summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-03-01 02:22:44 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-03-01 02:22:44 -0800
commit8e3beda4812f54fa3461e34c38cd7f688faf5433 (patch)
tree85d37afbde986ec7d1fdae1bbce484725268e872 /drivers/usb
parentbb35e1ed7889e631ffcc241f6864049dafeb8ab6 (diff)
parent82e6740d7f3c556fa84166874661f184eaec0c30 (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.c187
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__);
}