Loading drivers/usb/gadget/u_bam_data.c +72 −128 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ struct rndis_data_ch_info { u32 prod_clnt_hdl; u32 cons_clnt_hdl; void *priv; bool adaptor_disable; }; struct sys2ipa_sw_data { Loading Loading @@ -127,18 +126,8 @@ enum u_bam_data_event_type { U_BAM_DATA_RESUME_E }; /* * Used exclusively for RNDIS adpator enable/disable * operation performed on host machine. */ enum u_bam_rndis_state { RNDIS_DISCONNECT = 0, RNDIS_SOFT_DISABLE, RNDIS_SOFT_ENABLE }; struct bam_data_port { bool is_connected; bool is_ipa_connected; enum u_bam_data_event_type last_event; unsigned port_num; spinlock_t port_lock; Loading @@ -150,7 +139,6 @@ struct bam_data_port { struct work_struct disconnect_w; struct work_struct suspend_w; struct work_struct resume_w; enum u_bam_rndis_state rndis_s; }; struct usb_bam_data_connect_info { u32 usb_bam_pipe_idx; Loading Loading @@ -797,17 +785,12 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) spin_lock_irqsave(&port->port_lock, flags); if (!port->is_connected) { if (!port->is_ipa_connected) { pr_debug("%s: Already disconnected. Bailing out.\n", __func__); spin_unlock_irqrestore(&port->port_lock, flags); return; } /* * Mark port as disconnected, to maintaine this driver state, * even if there gonna be errors down in this function. */ port->is_connected = false; d = &port->data_ch; /* Loading @@ -828,6 +811,10 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret); } spin_lock_irqsave(&port->port_lock, flags); port->is_ipa_connected = false; spin_unlock_irqrestore(&port->port_lock, flags); pr_debug("Disconnect workqueue done (port %p)\n", port); } /* Loading Loading @@ -878,7 +865,6 @@ static void bam2bam_data_connect_work(struct work_struct *w) u32 sps_params; int ret; unsigned long flags; bool enable_eps = true; pr_debug("%s: Connect workqueue started", __func__); Loading @@ -887,8 +873,7 @@ static void bam2bam_data_connect_work(struct work_struct *w) d = &port->data_ch; d_port = port->port_usb; if (port->rndis_s == RNDIS_DISCONNECT && port->last_event == U_BAM_DATA_DISCONNECT_E) { if (port->last_event == U_BAM_DATA_DISCONNECT_E) { pr_debug("%s: Port is about to disconnect. Bail out.\n", __func__); spin_unlock_irqrestore(&port->port_lock, flags); Loading Loading @@ -916,70 +901,6 @@ static void bam2bam_data_connect_work(struct work_struct *w) return; } /* * Disabling RNDIS network adaptor disable/enable performs * USB IPA disconect and connect respectively. This particular * check makes sure that when we re-enable USB eps are not * re-renabled. */ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS && port->rndis_s == RNDIS_SOFT_ENABLE) enable_eps = false; if (enable_eps) { if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { /* UL workaround requirements */ skb_queue_head_init(&d->rx_skb_q); skb_queue_head_init(&d->rx_skb_idle); INIT_LIST_HEAD(&d->rx_idle); ret = bam_data_sys2bam_alloc_req(port, false); if (ret) { spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s: sys2bam_alloc_req failed(%d)", __func__, ret); return; } } d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC); if (!d->rx_req) { bam_data_free_reqs(port); spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s: failed to allocate rx_req\n", __func__); return; } d->rx_req->context = port; d->rx_req->complete = bam_data_endless_rx_complete; d->rx_req->length = 0; d->rx_req->no_interrupt = 1; d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC); if (!d->tx_req) { usb_ep_free_request(port->port_usb->out, d->rx_req); bam_data_free_reqs(port); spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s: failed to allocate tx_req\n", __func__); return; } d->tx_req->context = port; d->tx_req->complete = bam_data_endless_tx_complete; d->tx_req->length = 0; d->tx_req->no_interrupt = 1; } /* * Mark port as connected, to maintaine this driver state, * even if there gonna be errors down in this function. */ port->is_connected = true; if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { d->ipa_params.usb_connection_speed = gadget->speed; Loading Loading @@ -1045,8 +966,7 @@ static void bam2bam_data_connect_work(struct work_struct *w) } spin_lock_irqsave(&port->port_lock, flags); if (port->rndis_s == RNDIS_DISCONNECT && port->last_event == U_BAM_DATA_DISCONNECT_E) { if (port->last_event == U_BAM_DATA_DISCONNECT_E) { spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s:%d: Port is being disconnected.\n", __func__, __LINE__); Loading Loading @@ -1109,14 +1029,15 @@ static void bam2bam_data_connect_work(struct work_struct *w) * spinlock and re-enabling IRQs. Hence check again. */ spin_lock_irqsave(&port->port_lock, flags); if (port->rndis_s == RNDIS_DISCONNECT && port->last_event == U_BAM_DATA_DISCONNECT_E) { if (port->last_event == U_BAM_DATA_DISCONNECT_E) { spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s:%d: port is beind disconnected.\n", __func__, __LINE__); goto disconnect_ipa; } port->is_ipa_connected = true; d_port->ipa_producer_ep = d->ipa_params.ipa_prod_ep_idx; pr_debug("%s(): ipa_producer_ep:%d ipa_consumer_ep:%d\n", __func__, d_port->ipa_producer_ep, Loading Loading @@ -1309,7 +1230,7 @@ void bam_data_start_rx_tx(u8 port_num) d->rx_req, d->tx_req); goto out; } if (!port->is_connected) { if (!port->is_ipa_connected) { pr_debug("%s: pipes are disconnected", __func__); goto out; } Loading Loading @@ -1365,8 +1286,7 @@ int bam2bam_data_port_select(int portno) port = bam2bam_data_ports[portno]; port->port_num = portno; port->is_connected = false; port->rndis_s = RNDIS_DISCONNECT; port->is_ipa_connected = false; spin_lock_init(&port->port_lock); Loading Loading @@ -1401,18 +1321,11 @@ void u_bam_data_start_rndis_ipa(void) { pr_debug("%s\n", __func__); if (!is_ipa_rndis_net_on) { int port_num = u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT); struct bam_data_port *port = bam2bam_data_ports[port_num]; if (port->rndis_s == RNDIS_SOFT_DISABLE) port->rndis_s = RNDIS_SOFT_ENABLE; if (!is_ipa_rndis_net_on) queue_work(bam_data_wq, rndis_conn_w); } else { else pr_debug("%s: Transfers already started?\n", __func__); } } void u_bam_data_stop_rndis_ipa(void) { Loading @@ -1425,9 +1338,8 @@ void u_bam_data_stop_rndis_ipa(void) rndis_ipa_reset_trigger(); bam_data_stop_endless_tx(port); port->rndis_s = RNDIS_SOFT_DISABLE; rndis_data.adaptor_disable = true; bam_data_disconnect(port->port_usb, port_num); if (port->is_ipa_connected) queue_work(bam_data_wq, &port->disconnect_w); } } Loading Loading @@ -1456,7 +1368,6 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num) struct bam_data_ch_info *d; struct sk_buff *skb = NULL; unsigned long flags; bool disable_eps = true; pr_debug("dev:%p port number:%d\n", gr, port_num); Loading @@ -1481,25 +1392,7 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num) d = &port->data_ch; /* * Flag disable_eps and rndis_s state as RNDIS_SOFT_DISABLE are * being used to detect that this API is being called due to * performing RNDIS adaptor disable on host. In normal case, * disable_eps would be always false, which would make sure to * perform disconnect sequeunce. */ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS) { if (rndis_data.adaptor_disable && port->rndis_s == RNDIS_SOFT_DISABLE) { disable_eps = false; rndis_data.adaptor_disable = false; } else { port->rndis_s = RNDIS_DISCONNECT; } } if (port->port_usb && disable_eps) { if (port->port_usb) { if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { port->port_usb->ipa_consumer_ep = -1; port->port_usb->ipa_producer_ep = -1; Loading Loading @@ -1686,10 +1579,50 @@ int bam_data_connect(struct data_port *gr, u8 port_num, ret = usb_ep_enable(gr->out); if (ret) { pr_err("usb_ep_enable failed eptype:OUT ep:%p", gr->out); gr->in->driver_data = 0; goto exit; goto disable_in_ep; } gr->out->driver_data = port; if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { /* UL workaround requirements */ skb_queue_head_init(&d->rx_skb_q); skb_queue_head_init(&d->rx_skb_idle); INIT_LIST_HEAD(&d->rx_idle); ret = bam_data_sys2bam_alloc_req(port, false); if (ret) { pr_err("%s: sys2bam_alloc_req failed(%d)", __func__, ret); goto disable_out_ep; } } d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC); if (!d->rx_req) { pr_err("%s: failed to allocate rx_req\n", __func__); goto bam_data_free; } d->rx_req->context = port; d->rx_req->complete = bam_data_endless_rx_complete; d->rx_req->length = 0; d->rx_req->no_interrupt = 1; d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC); if (!d->tx_req) { pr_err("%s: failed to allocate tx_req\n", __func__); goto ep_out_req_free; } d->tx_req->context = port; d->tx_req->complete = bam_data_endless_tx_complete; d->tx_req->length = 0; d->tx_req->no_interrupt = 1; gr->out->driver_data = port; if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS) { Loading @@ -1701,8 +1634,19 @@ int bam_data_connect(struct data_port *gr, u8 port_num, port->last_event = U_BAM_DATA_CONNECT_E; queue_work(bam_data_wq, &port->connect_w); ret = 0; spin_unlock_irqrestore(&port->port_lock, flags); return 0; ep_out_req_free: usb_ep_free_request(port->port_usb->out, d->rx_req); bam_data_free: bam_data_free_reqs(port); disable_out_ep: gr->out->driver_data = 0; usb_ep_disable(gr->out); disable_in_ep: gr->in->driver_data = 0; usb_ep_disable(gr->in); exit: spin_unlock_irqrestore(&port->port_lock, flags); return ret; Loading Loading
drivers/usb/gadget/u_bam_data.c +72 −128 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ struct rndis_data_ch_info { u32 prod_clnt_hdl; u32 cons_clnt_hdl; void *priv; bool adaptor_disable; }; struct sys2ipa_sw_data { Loading Loading @@ -127,18 +126,8 @@ enum u_bam_data_event_type { U_BAM_DATA_RESUME_E }; /* * Used exclusively for RNDIS adpator enable/disable * operation performed on host machine. */ enum u_bam_rndis_state { RNDIS_DISCONNECT = 0, RNDIS_SOFT_DISABLE, RNDIS_SOFT_ENABLE }; struct bam_data_port { bool is_connected; bool is_ipa_connected; enum u_bam_data_event_type last_event; unsigned port_num; spinlock_t port_lock; Loading @@ -150,7 +139,6 @@ struct bam_data_port { struct work_struct disconnect_w; struct work_struct suspend_w; struct work_struct resume_w; enum u_bam_rndis_state rndis_s; }; struct usb_bam_data_connect_info { u32 usb_bam_pipe_idx; Loading Loading @@ -797,17 +785,12 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) spin_lock_irqsave(&port->port_lock, flags); if (!port->is_connected) { if (!port->is_ipa_connected) { pr_debug("%s: Already disconnected. Bailing out.\n", __func__); spin_unlock_irqrestore(&port->port_lock, flags); return; } /* * Mark port as disconnected, to maintaine this driver state, * even if there gonna be errors down in this function. */ port->is_connected = false; d = &port->data_ch; /* Loading @@ -828,6 +811,10 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret); } spin_lock_irqsave(&port->port_lock, flags); port->is_ipa_connected = false; spin_unlock_irqrestore(&port->port_lock, flags); pr_debug("Disconnect workqueue done (port %p)\n", port); } /* Loading Loading @@ -878,7 +865,6 @@ static void bam2bam_data_connect_work(struct work_struct *w) u32 sps_params; int ret; unsigned long flags; bool enable_eps = true; pr_debug("%s: Connect workqueue started", __func__); Loading @@ -887,8 +873,7 @@ static void bam2bam_data_connect_work(struct work_struct *w) d = &port->data_ch; d_port = port->port_usb; if (port->rndis_s == RNDIS_DISCONNECT && port->last_event == U_BAM_DATA_DISCONNECT_E) { if (port->last_event == U_BAM_DATA_DISCONNECT_E) { pr_debug("%s: Port is about to disconnect. Bail out.\n", __func__); spin_unlock_irqrestore(&port->port_lock, flags); Loading Loading @@ -916,70 +901,6 @@ static void bam2bam_data_connect_work(struct work_struct *w) return; } /* * Disabling RNDIS network adaptor disable/enable performs * USB IPA disconect and connect respectively. This particular * check makes sure that when we re-enable USB eps are not * re-renabled. */ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS && port->rndis_s == RNDIS_SOFT_ENABLE) enable_eps = false; if (enable_eps) { if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { /* UL workaround requirements */ skb_queue_head_init(&d->rx_skb_q); skb_queue_head_init(&d->rx_skb_idle); INIT_LIST_HEAD(&d->rx_idle); ret = bam_data_sys2bam_alloc_req(port, false); if (ret) { spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s: sys2bam_alloc_req failed(%d)", __func__, ret); return; } } d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC); if (!d->rx_req) { bam_data_free_reqs(port); spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s: failed to allocate rx_req\n", __func__); return; } d->rx_req->context = port; d->rx_req->complete = bam_data_endless_rx_complete; d->rx_req->length = 0; d->rx_req->no_interrupt = 1; d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC); if (!d->tx_req) { usb_ep_free_request(port->port_usb->out, d->rx_req); bam_data_free_reqs(port); spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s: failed to allocate tx_req\n", __func__); return; } d->tx_req->context = port; d->tx_req->complete = bam_data_endless_tx_complete; d->tx_req->length = 0; d->tx_req->no_interrupt = 1; } /* * Mark port as connected, to maintaine this driver state, * even if there gonna be errors down in this function. */ port->is_connected = true; if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { d->ipa_params.usb_connection_speed = gadget->speed; Loading Loading @@ -1045,8 +966,7 @@ static void bam2bam_data_connect_work(struct work_struct *w) } spin_lock_irqsave(&port->port_lock, flags); if (port->rndis_s == RNDIS_DISCONNECT && port->last_event == U_BAM_DATA_DISCONNECT_E) { if (port->last_event == U_BAM_DATA_DISCONNECT_E) { spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s:%d: Port is being disconnected.\n", __func__, __LINE__); Loading Loading @@ -1109,14 +1029,15 @@ static void bam2bam_data_connect_work(struct work_struct *w) * spinlock and re-enabling IRQs. Hence check again. */ spin_lock_irqsave(&port->port_lock, flags); if (port->rndis_s == RNDIS_DISCONNECT && port->last_event == U_BAM_DATA_DISCONNECT_E) { if (port->last_event == U_BAM_DATA_DISCONNECT_E) { spin_unlock_irqrestore(&port->port_lock, flags); pr_err("%s:%d: port is beind disconnected.\n", __func__, __LINE__); goto disconnect_ipa; } port->is_ipa_connected = true; d_port->ipa_producer_ep = d->ipa_params.ipa_prod_ep_idx; pr_debug("%s(): ipa_producer_ep:%d ipa_consumer_ep:%d\n", __func__, d_port->ipa_producer_ep, Loading Loading @@ -1309,7 +1230,7 @@ void bam_data_start_rx_tx(u8 port_num) d->rx_req, d->tx_req); goto out; } if (!port->is_connected) { if (!port->is_ipa_connected) { pr_debug("%s: pipes are disconnected", __func__); goto out; } Loading Loading @@ -1365,8 +1286,7 @@ int bam2bam_data_port_select(int portno) port = bam2bam_data_ports[portno]; port->port_num = portno; port->is_connected = false; port->rndis_s = RNDIS_DISCONNECT; port->is_ipa_connected = false; spin_lock_init(&port->port_lock); Loading Loading @@ -1401,18 +1321,11 @@ void u_bam_data_start_rndis_ipa(void) { pr_debug("%s\n", __func__); if (!is_ipa_rndis_net_on) { int port_num = u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT); struct bam_data_port *port = bam2bam_data_ports[port_num]; if (port->rndis_s == RNDIS_SOFT_DISABLE) port->rndis_s = RNDIS_SOFT_ENABLE; if (!is_ipa_rndis_net_on) queue_work(bam_data_wq, rndis_conn_w); } else { else pr_debug("%s: Transfers already started?\n", __func__); } } void u_bam_data_stop_rndis_ipa(void) { Loading @@ -1425,9 +1338,8 @@ void u_bam_data_stop_rndis_ipa(void) rndis_ipa_reset_trigger(); bam_data_stop_endless_tx(port); port->rndis_s = RNDIS_SOFT_DISABLE; rndis_data.adaptor_disable = true; bam_data_disconnect(port->port_usb, port_num); if (port->is_ipa_connected) queue_work(bam_data_wq, &port->disconnect_w); } } Loading Loading @@ -1456,7 +1368,6 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num) struct bam_data_ch_info *d; struct sk_buff *skb = NULL; unsigned long flags; bool disable_eps = true; pr_debug("dev:%p port number:%d\n", gr, port_num); Loading @@ -1481,25 +1392,7 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num) d = &port->data_ch; /* * Flag disable_eps and rndis_s state as RNDIS_SOFT_DISABLE are * being used to detect that this API is being called due to * performing RNDIS adaptor disable on host. In normal case, * disable_eps would be always false, which would make sure to * perform disconnect sequeunce. */ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS) { if (rndis_data.adaptor_disable && port->rndis_s == RNDIS_SOFT_DISABLE) { disable_eps = false; rndis_data.adaptor_disable = false; } else { port->rndis_s = RNDIS_DISCONNECT; } } if (port->port_usb && disable_eps) { if (port->port_usb) { if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { port->port_usb->ipa_consumer_ep = -1; port->port_usb->ipa_producer_ep = -1; Loading Loading @@ -1686,10 +1579,50 @@ int bam_data_connect(struct data_port *gr, u8 port_num, ret = usb_ep_enable(gr->out); if (ret) { pr_err("usb_ep_enable failed eptype:OUT ep:%p", gr->out); gr->in->driver_data = 0; goto exit; goto disable_in_ep; } gr->out->driver_data = port; if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { /* UL workaround requirements */ skb_queue_head_init(&d->rx_skb_q); skb_queue_head_init(&d->rx_skb_idle); INIT_LIST_HEAD(&d->rx_idle); ret = bam_data_sys2bam_alloc_req(port, false); if (ret) { pr_err("%s: sys2bam_alloc_req failed(%d)", __func__, ret); goto disable_out_ep; } } d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC); if (!d->rx_req) { pr_err("%s: failed to allocate rx_req\n", __func__); goto bam_data_free; } d->rx_req->context = port; d->rx_req->complete = bam_data_endless_rx_complete; d->rx_req->length = 0; d->rx_req->no_interrupt = 1; d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC); if (!d->tx_req) { pr_err("%s: failed to allocate tx_req\n", __func__); goto ep_out_req_free; } d->tx_req->context = port; d->tx_req->complete = bam_data_endless_tx_complete; d->tx_req->length = 0; d->tx_req->no_interrupt = 1; gr->out->driver_data = port; if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS) { Loading @@ -1701,8 +1634,19 @@ int bam_data_connect(struct data_port *gr, u8 port_num, port->last_event = U_BAM_DATA_CONNECT_E; queue_work(bam_data_wq, &port->connect_w); ret = 0; spin_unlock_irqrestore(&port->port_lock, flags); return 0; ep_out_req_free: usb_ep_free_request(port->port_usb->out, d->rx_req); bam_data_free: bam_data_free_reqs(port); disable_out_ep: gr->out->driver_data = 0; usb_ep_disable(gr->out); disable_in_ep: gr->in->driver_data = 0; usb_ep_disable(gr->in); exit: spin_unlock_irqrestore(&port->port_lock, flags); return ret; Loading