Loading drivers/usb/gadget/function/f_gsi.c +70 −117 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ struct usb_gsi_debugfs { static struct usb_gsi_debugfs debugfs; static void gsi_rndis_ipa_reset_trigger(void); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi); static int gsi_alloc_trb_buffer(struct f_gsi *gsi); Loading @@ -66,6 +65,20 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi); static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned len, gfp_t flags); static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt); static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f) { bool remote_wakeup_allowed; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; log_event_dbg("%s: remote_wakeup_allowed:%s", __func__, remote_wakeup_allowed ? "true" : "false"); return remote_wakeup_allowed; } void post_event(struct gsi_data_port *port, u8 event) { unsigned long flags; Loading Loading @@ -884,16 +897,22 @@ static void ipa_disconnect_handler(struct gsi_data_port *d_port) log_event_dbg("%s: EP Disable for data", __func__); /* Block doorbell to GSI to avoid USB wrapper from * ringing doorbell in case IPA clocks are OFF if (gsi->d_port.in_ep) { /* * Block doorbell to GSI to avoid USB wrapper from * ringing doorbell in case IPA clocks are OFF. */ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc; usb_ep_disable(gsi->d_port.in_ep); } if (gsi->d_port.out_ep) if (gsi->d_port.out_ep) { gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; usb_ep_disable(gsi->d_port.out_ep); } gsi->d_port.net_ready_trigger = false; } Loading Loading @@ -930,18 +949,21 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) int ret = 0; bool block_db, f_suspend; struct f_gsi *gsi = d_port_to_gsi(d_port); struct usb_function *f = &gsi->function; f_suspend = f->func_wakeup_allowed; log_event_dbg("%s: f_suspend:%d", __func__, f_suspend); f_suspend = gsi->function.func_wakeup_allowed; if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend, GSI_EP_OP_CHECK_FOR_SUSPEND)) { ret = -EFAULT; goto done; } log_event_dbg("%s: Calling xdci_suspend", __func__); log_event_dbg("%s: Calling xdci_suspend", __func__); ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id, true); usb_gsi_remote_wakeup_allowed(f)); if (!ret) { d_port->sm_state = STATE_SUSPENDED; Loading @@ -960,10 +982,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) log_event_err("%s: Error %d for %d", __func__, ret, gsi->prot_id); } log_event_dbg("%s: xdci_suspend ret %d", __func__, ret); done: log_event_dbg("%s: xdci_suspend ret %d", __func__, ret); return ret; } Loading Loading @@ -998,7 +1018,6 @@ static void ipa_work_handler(struct work_struct *w) struct device *dev; struct device *gad_dev; struct f_gsi *gsi; bool block_db; event = read_event(d_port); Loading Loading @@ -1060,6 +1079,27 @@ static void ipa_work_handler(struct work_struct *w) __func__); break; } if (d_port->out_ep && !d_port->out_ep->desc && gsi->out_ep_desc_backup) { d_port->out_ep->desc = gsi->out_ep_desc_backup; d_port->out_ep->ep_intr_num = 1; } if (d_port->in_ep && !d_port->in_ep->desc && gsi->in_ep_desc_backup) { d_port->in_ep->desc = gsi->in_ep_desc_backup; d_port->in_ep->ep_intr_num = 2; } if (d_port->out_ep) usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, GSI_EP_OP_CONFIG); if (d_port->in_ep) usb_gsi_ep_op(d_port->in_ep, &d_port->in_request, GSI_EP_OP_CONFIG); ipa_connect_channels(d_port); ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; Loading Loading @@ -1121,15 +1161,7 @@ static void ipa_work_handler(struct work_struct *w) if (event == EVT_HOST_NRDY) { log_event_dbg("%s: ST_CON_HOST_NRDY\n", __func__); block_db = true; /* stop USB ringing doorbell to GSI(OUT_EP) */ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); gsi_rndis_ipa_reset_trigger(); usb_gsi_ep_op(d_port->in_ep, NULL, GSI_EP_OP_ENDXFER); usb_gsi_ep_op(d_port->out_ep, NULL, GSI_EP_OP_ENDXFER); ipa_disconnect_handler(d_port); } ipa_disconnect_work_handler(d_port); Loading Loading @@ -1743,27 +1775,6 @@ static void gsi_rndis_open(struct f_gsi *rndis) rndis_signal_connect(rndis->config); } static void gsi_rndis_ipa_reset_trigger(void) { struct f_gsi *rndis = gsi_prot_ctx[IPA_USB_RNDIS]; unsigned long flags; if (!rndis) { log_event_err("%s: gsi prot ctx is %p", __func__, rndis); return; } spin_lock_irqsave(&rndis->d_port.lock, flags); if (!rndis) { log_event_err("%s: No RNDIS instance", __func__); spin_unlock_irqrestore(&rndis->d_port.lock, flags); return; } rndis->d_port.net_ready_trigger = false; spin_unlock_irqrestore(&rndis->d_port.lock, flags); } void gsi_rndis_flow_ctrl_enable(bool enable) { struct f_gsi *rndis = gsi_prot_ctx[IPA_USB_RNDIS]; Loading Loading @@ -2573,7 +2584,6 @@ static void gsi_suspend(struct usb_function *f) { bool block_db; struct f_gsi *gsi = func_to_gsi(f); bool remote_wakeup_allowed; if (!gsi->data_interface_up) { log_event_dbg("%s: Data interface not up\n", __func__); Loading @@ -2586,49 +2596,17 @@ static void gsi_suspend(struct usb_function *f) return; } if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; log_event_info("%s: remote_wakeup_allowed %d", __func__, remote_wakeup_allowed); if (!remote_wakeup_allowed) { if (gsi->prot_id == IPA_USB_RNDIS) rndis_flow_control(gsi->config, true); /* * When remote wakeup is disabled, IPA is disconnected * because it cannot send new data until the USB bus is * resumed. Endpoint descriptors info is saved before it * gets reset by the BAM disconnect API. This lets us * restore this info when the USB bus is resumed. */ if (gsi->d_port.in_ep) gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc; if (gsi->d_port.out_ep) gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; ipa_disconnect_handler(&gsi->d_port); post_event(&gsi->d_port, EVT_DISCONNECTED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("%s: Disconnecting", __func__); } else { block_db = true; usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); post_event(&gsi->d_port, EVT_SUSPEND); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); } log_event_dbg("gsi suspended"); } static void gsi_resume(struct usb_function *f) { struct f_gsi *gsi = func_to_gsi(f); bool remote_wakeup_allowed; struct usb_composite_dev *cdev = f->config->cdev; log_event_dbg("%s", __func__); Loading @@ -2646,49 +2624,24 @@ static void gsi_resume(struct usb_function *f) f->func_is_suspended) return; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); if (!remote_wakeup_allowed) { /* Configure EPs for GSI */ if (gsi->d_port.out_ep) { gsi->d_port.out_ep->desc = gsi->out_ep_desc_backup; gsi->d_port.out_ep->ep_intr_num = 1; usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request, GSI_EP_OP_CONFIG); } gsi->d_port.in_ep->desc = gsi->in_ep_desc_backup; if (gsi->prot_id != IPA_USB_DIAG) gsi->d_port.in_ep->ep_intr_num = 2; else gsi->d_port.in_ep->ep_intr_num = 3; usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request, GSI_EP_OP_CONFIG); post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS); /* * Linux host does not send RNDIS_MSG_INIT or non-zero * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume. * Trigger state machine explicitly on resume. */ if (gsi->prot_id == IPA_USB_RNDIS) if (gsi->prot_id == IPA_USB_RNDIS && !usb_gsi_remote_wakeup_allowed(f)) rndis_flow_control(gsi->config, false); } else post_event(&gsi->d_port, EVT_RESUMED); post_event(&gsi->d_port, EVT_RESUMED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("%s: completed", __func__); } Loading Loading
drivers/usb/gadget/function/f_gsi.c +70 −117 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ struct usb_gsi_debugfs { static struct usb_gsi_debugfs debugfs; static void gsi_rndis_ipa_reset_trigger(void); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi); static int gsi_alloc_trb_buffer(struct f_gsi *gsi); Loading @@ -66,6 +65,20 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi); static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned len, gfp_t flags); static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt); static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f) { bool remote_wakeup_allowed; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; log_event_dbg("%s: remote_wakeup_allowed:%s", __func__, remote_wakeup_allowed ? "true" : "false"); return remote_wakeup_allowed; } void post_event(struct gsi_data_port *port, u8 event) { unsigned long flags; Loading Loading @@ -884,16 +897,22 @@ static void ipa_disconnect_handler(struct gsi_data_port *d_port) log_event_dbg("%s: EP Disable for data", __func__); /* Block doorbell to GSI to avoid USB wrapper from * ringing doorbell in case IPA clocks are OFF if (gsi->d_port.in_ep) { /* * Block doorbell to GSI to avoid USB wrapper from * ringing doorbell in case IPA clocks are OFF. */ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc; usb_ep_disable(gsi->d_port.in_ep); } if (gsi->d_port.out_ep) if (gsi->d_port.out_ep) { gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; usb_ep_disable(gsi->d_port.out_ep); } gsi->d_port.net_ready_trigger = false; } Loading Loading @@ -930,18 +949,21 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) int ret = 0; bool block_db, f_suspend; struct f_gsi *gsi = d_port_to_gsi(d_port); struct usb_function *f = &gsi->function; f_suspend = f->func_wakeup_allowed; log_event_dbg("%s: f_suspend:%d", __func__, f_suspend); f_suspend = gsi->function.func_wakeup_allowed; if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend, GSI_EP_OP_CHECK_FOR_SUSPEND)) { ret = -EFAULT; goto done; } log_event_dbg("%s: Calling xdci_suspend", __func__); log_event_dbg("%s: Calling xdci_suspend", __func__); ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id, true); usb_gsi_remote_wakeup_allowed(f)); if (!ret) { d_port->sm_state = STATE_SUSPENDED; Loading @@ -960,10 +982,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) log_event_err("%s: Error %d for %d", __func__, ret, gsi->prot_id); } log_event_dbg("%s: xdci_suspend ret %d", __func__, ret); done: log_event_dbg("%s: xdci_suspend ret %d", __func__, ret); return ret; } Loading Loading @@ -998,7 +1018,6 @@ static void ipa_work_handler(struct work_struct *w) struct device *dev; struct device *gad_dev; struct f_gsi *gsi; bool block_db; event = read_event(d_port); Loading Loading @@ -1060,6 +1079,27 @@ static void ipa_work_handler(struct work_struct *w) __func__); break; } if (d_port->out_ep && !d_port->out_ep->desc && gsi->out_ep_desc_backup) { d_port->out_ep->desc = gsi->out_ep_desc_backup; d_port->out_ep->ep_intr_num = 1; } if (d_port->in_ep && !d_port->in_ep->desc && gsi->in_ep_desc_backup) { d_port->in_ep->desc = gsi->in_ep_desc_backup; d_port->in_ep->ep_intr_num = 2; } if (d_port->out_ep) usb_gsi_ep_op(d_port->out_ep, &d_port->out_request, GSI_EP_OP_CONFIG); if (d_port->in_ep) usb_gsi_ep_op(d_port->in_ep, &d_port->in_request, GSI_EP_OP_CONFIG); ipa_connect_channels(d_port); ipa_data_path_enable(d_port); d_port->sm_state = STATE_CONNECTED; Loading Loading @@ -1121,15 +1161,7 @@ static void ipa_work_handler(struct work_struct *w) if (event == EVT_HOST_NRDY) { log_event_dbg("%s: ST_CON_HOST_NRDY\n", __func__); block_db = true; /* stop USB ringing doorbell to GSI(OUT_EP) */ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); gsi_rndis_ipa_reset_trigger(); usb_gsi_ep_op(d_port->in_ep, NULL, GSI_EP_OP_ENDXFER); usb_gsi_ep_op(d_port->out_ep, NULL, GSI_EP_OP_ENDXFER); ipa_disconnect_handler(d_port); } ipa_disconnect_work_handler(d_port); Loading Loading @@ -1743,27 +1775,6 @@ static void gsi_rndis_open(struct f_gsi *rndis) rndis_signal_connect(rndis->config); } static void gsi_rndis_ipa_reset_trigger(void) { struct f_gsi *rndis = gsi_prot_ctx[IPA_USB_RNDIS]; unsigned long flags; if (!rndis) { log_event_err("%s: gsi prot ctx is %p", __func__, rndis); return; } spin_lock_irqsave(&rndis->d_port.lock, flags); if (!rndis) { log_event_err("%s: No RNDIS instance", __func__); spin_unlock_irqrestore(&rndis->d_port.lock, flags); return; } rndis->d_port.net_ready_trigger = false; spin_unlock_irqrestore(&rndis->d_port.lock, flags); } void gsi_rndis_flow_ctrl_enable(bool enable) { struct f_gsi *rndis = gsi_prot_ctx[IPA_USB_RNDIS]; Loading Loading @@ -2573,7 +2584,6 @@ static void gsi_suspend(struct usb_function *f) { bool block_db; struct f_gsi *gsi = func_to_gsi(f); bool remote_wakeup_allowed; if (!gsi->data_interface_up) { log_event_dbg("%s: Data interface not up\n", __func__); Loading @@ -2586,49 +2596,17 @@ static void gsi_suspend(struct usb_function *f) return; } if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; log_event_info("%s: remote_wakeup_allowed %d", __func__, remote_wakeup_allowed); if (!remote_wakeup_allowed) { if (gsi->prot_id == IPA_USB_RNDIS) rndis_flow_control(gsi->config, true); /* * When remote wakeup is disabled, IPA is disconnected * because it cannot send new data until the USB bus is * resumed. Endpoint descriptors info is saved before it * gets reset by the BAM disconnect API. This lets us * restore this info when the USB bus is resumed. */ if (gsi->d_port.in_ep) gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc; if (gsi->d_port.out_ep) gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; ipa_disconnect_handler(&gsi->d_port); post_event(&gsi->d_port, EVT_DISCONNECTED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("%s: Disconnecting", __func__); } else { block_db = true; usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); post_event(&gsi->d_port, EVT_SUSPEND); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); } log_event_dbg("gsi suspended"); } static void gsi_resume(struct usb_function *f) { struct f_gsi *gsi = func_to_gsi(f); bool remote_wakeup_allowed; struct usb_composite_dev *cdev = f->config->cdev; log_event_dbg("%s", __func__); Loading @@ -2646,49 +2624,24 @@ static void gsi_resume(struct usb_function *f) f->func_is_suspended) return; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); if (!remote_wakeup_allowed) { /* Configure EPs for GSI */ if (gsi->d_port.out_ep) { gsi->d_port.out_ep->desc = gsi->out_ep_desc_backup; gsi->d_port.out_ep->ep_intr_num = 1; usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request, GSI_EP_OP_CONFIG); } gsi->d_port.in_ep->desc = gsi->in_ep_desc_backup; if (gsi->prot_id != IPA_USB_DIAG) gsi->d_port.in_ep->ep_intr_num = 2; else gsi->d_port.in_ep->ep_intr_num = 3; usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request, GSI_EP_OP_CONFIG); post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS); /* * Linux host does not send RNDIS_MSG_INIT or non-zero * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume. * Trigger state machine explicitly on resume. */ if (gsi->prot_id == IPA_USB_RNDIS) if (gsi->prot_id == IPA_USB_RNDIS && !usb_gsi_remote_wakeup_allowed(f)) rndis_flow_control(gsi->config, false); } else post_event(&gsi->d_port, EVT_RESUMED); post_event(&gsi->d_port, EVT_RESUMED); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("%s: completed", __func__); } Loading