diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2017-03-01 02:22:44 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-03-01 02:22:44 -0800 |
| commit | 8e3beda4812f54fa3461e34c38cd7f688faf5433 (patch) | |
| tree | 85d37afbde986ec7d1fdae1bbce484725268e872 /drivers/usb | |
| parent | bb35e1ed7889e631ffcc241f6864049dafeb8ab6 (diff) | |
| parent | 82e6740d7f3c556fa84166874661f184eaec0c30 (diff) | |
Merge "f_gsi: Don't send end xfer command when USB is into U3 state"
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/gadget/function/f_gsi.c | 187 |
1 files changed, 70 insertions, 117 deletions
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 9473e7e31eaa..d3845b4f82c6 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -40,7 +40,6 @@ MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); static struct workqueue_struct *ipa_usb_wq; -static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis); 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); @@ -48,6 +47,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; @@ -477,16 +490,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 - */ - usb_gsi_ep_op(d_port->in_ep, (void *)&block_db, + 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_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE); + } - usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE); - - if (gsi->d_port.out_ep) + if (gsi->d_port.out_ep) { + gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc; usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_DISABLE); + } + gsi->d_port.net_ready_trigger = false; } @@ -523,19 +542,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; log_event_dbg("%s: STATE SUSPENDED", __func__); @@ -553,10 +574,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; } @@ -591,7 +610,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); @@ -653,6 +671,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; @@ -714,15 +753,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(gsi); - 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); @@ -1345,26 +1376,6 @@ static void gsi_rndis_open(struct f_gsi *rndis) rndis_signal_connect(rndis->params); } -static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis) -{ - unsigned long flags; - - if (!rndis) { - log_event_err("%s: gsi prot ctx is %pK", __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 rndis_params *param) { struct f_gsi *rndis = param->v; @@ -2115,7 +2126,6 @@ static void gsi_suspend(struct usb_function *f) { bool block_db; struct f_gsi *gsi = func_to_gsi(f); - bool remote_wakeup_allowed; /* Check if function is already suspended in gsi_func_suspend() */ if (f->func_is_suspended) { @@ -2123,49 +2133,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->params, 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); - } - + 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__); @@ -2178,49 +2156,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) - rndis_flow_control(gsi->params, false); - } else - post_event(&gsi->d_port, EVT_RESUMED); + /* + * 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 && + !usb_gsi_remote_wakeup_allowed(f)) + rndis_flow_control(gsi->params, false); + 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__); } |
