summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorVijayavardhan Vennapusa <vvreddy@codeaurora.org>2016-05-11 13:06:37 +0530
committerChandana Kishori Chiluveru <cchiluve@codeaurora.org>2016-12-12 15:21:33 +0530
commite589cdf9015a48ce9515b0d8bb5d5a6f2413ee8e (patch)
treecff7fc74571f8b40c59fd2e8e1859020c3aaaef1 /drivers/usb
parentda1cf560c2f723612a5e0eba5d9f524c71076439 (diff)
USB: dwc3-msm: Perform DBM config/unconfig under spinlock protection
There is a possibility of dwc3_msm_ep_queue() and msm_ep_unconfig() racing each other if suspend happens right after configured. This scenario will result in NOC error if start_xfer command gets queued after msm_ep_unconfig(). Hence fix the issue by adding spinlock protection for DBM endpoint configuration and unconfiguration. Change-Id: I3fd007647370250017c97faebffadb35afb7fc4d Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org> Signed-off-by: Chandana Kishori Chiluveru <cchiluve@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c40
-rw-r--r--drivers/usb/gadget/function/f_gsi.c4
-rw-r--r--drivers/usb/gadget/function/u_bam.c4
-rw-r--r--drivers/usb/gadget/function/u_bam_data.c4
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.c4
-rw-r--r--drivers/usb/gadget/function/u_qdss.c2
6 files changed, 39 insertions, 19 deletions
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 7447efebed7a..beff34569392 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -640,6 +640,14 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
return -EPERM;
}
+ if (!mdwc->original_ep_ops[dep->number]) {
+ dev_err(mdwc->dev,
+ "ep [%s,%d] was unconfigured as msm endpoint\n",
+ ep->name, dep->number);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+
if (!request) {
dev_err(mdwc->dev, "%s: request is NULL\n", __func__);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -647,14 +655,11 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
}
if (!(request->udc_priv & MSM_SPS_MODE)) {
- /* Not SPS mode, call original queue */
- dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n",
+ dev_err(mdwc->dev, "%s: sps mode is not set\n",
__func__);
spin_unlock_irqrestore(&dwc->lock, flags);
- return (mdwc->original_ep_ops[dep->number])->queue(ep,
- request,
- gfp_flags);
+ return -EINVAL;
}
/* HW restriction regarding TRB size (8KB) */
@@ -1331,8 +1336,7 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
*
* @return int - 0 on success, negetive on error.
*/
-int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
- gfp_t gfp_flags)
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
@@ -1344,23 +1348,27 @@ int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
bool disable_wb;
bool internal_mem;
bool ioc;
+ unsigned long flags;
+ spin_lock_irqsave(&dwc->lock, flags);
/* Save original ep ops for future restore*/
if (mdwc->original_ep_ops[dep->number]) {
dev_err(mdwc->dev,
"ep [%s,%d] already configured as msm endpoint\n",
ep->name, dep->number);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -EPERM;
}
mdwc->original_ep_ops[dep->number] = ep->ops;
/* Set new usb ops as we like */
- new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), gfp_flags);
+ new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC);
if (!new_ep_ops) {
dev_err(mdwc->dev,
"%s: unable to allocate mem for new usb ep ops\n",
__func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -ENOMEM;
}
(*new_ep_ops) = (*ep->ops);
@@ -1368,8 +1376,10 @@ int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
new_ep_ops->gsi_ep_op = dwc3_msm_gsi_ep_op;
ep->ops = new_ep_ops;
- if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI))
+ if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI)) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
+ }
/*
* Configure the DBM endpoint if required.
@@ -1385,9 +1395,12 @@ int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
if (ret < 0) {
dev_err(mdwc->dev,
"error %d after calling dbm_ep_config\n", ret);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
return 0;
}
EXPORT_SYMBOL(msm_ep_config);
@@ -1407,12 +1420,15 @@ int msm_ep_unconfig(struct usb_ep *ep)
struct dwc3 *dwc = dep->dwc;
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct usb_ep_ops *old_ep_ops;
+ unsigned long flags;
+ spin_lock_irqsave(&dwc->lock, flags);
/* Restore original ep ops */
if (!mdwc->original_ep_ops[dep->number]) {
dev_err(mdwc->dev,
"ep [%s,%d] was not configured as msm endpoint\n",
ep->name, dep->number);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -EINVAL;
}
old_ep_ops = (struct usb_ep_ops *)ep->ops;
@@ -1424,8 +1440,10 @@ int msm_ep_unconfig(struct usb_ep *ep)
* Do HERE more usb endpoint un-configurations
* which are specific to MSM.
*/
- if (!mdwc->dbm || (dep->endpoint.ep_type == EP_TYPE_GSI))
+ if (!mdwc->dbm || (dep->endpoint.ep_type == EP_TYPE_GSI)) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
+ }
if (dep->busy_slot == dep->free_slot && list_empty(&dep->request_list)
&& list_empty(&dep->req_queued)) {
@@ -1446,6 +1464,8 @@ int msm_ep_unconfig(struct usb_ep *ep)
dbm_event_buffer_config(mdwc->dbm, 0, 0, 0);
}
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
return 0;
}
EXPORT_SYMBOL(msm_ep_unconfig);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 84b60ec771a4..d3e01f71fa2f 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -2245,7 +2245,7 @@ skip_string_id_alloc:
if (!ep)
goto fail;
gsi->d_port.in_ep = ep;
- msm_ep_config(gsi->d_port.in_ep, NULL, GFP_KERNEL);
+ msm_ep_config(gsi->d_port.in_ep, NULL);
ep->driver_data = cdev; /* claim */
}
@@ -2255,7 +2255,7 @@ skip_string_id_alloc:
if (!ep)
goto fail;
gsi->d_port.out_ep = ep;
- msm_ep_config(gsi->d_port.out_ep, NULL, GFP_KERNEL);
+ msm_ep_config(gsi->d_port.out_ep, NULL);
ep->driver_data = cdev; /* claim */
}
diff --git a/drivers/usb/gadget/function/u_bam.c b/drivers/usb/gadget/function/u_bam.c
index bc3dd69dcb00..bbb744b33c3a 100644
--- a/drivers/usb/gadget/function/u_bam.c
+++ b/drivers/usb/gadget/function/u_bam.c
@@ -1395,7 +1395,7 @@ static void gbam2bam_connect_work(struct work_struct *w)
d->src_pipe_idx;
d->rx_req->length = 32*1024;
d->rx_req->udc_priv = sps_params;
- msm_ep_config(port->port_usb->out, d->rx_req, GFP_ATOMIC);
+ msm_ep_config(port->port_usb->out, d->rx_req);
/* Configure for TX */
configure_data_fifo(d->usb_bam_type, d->dst_connection_idx,
@@ -1403,7 +1403,7 @@ static void gbam2bam_connect_work(struct work_struct *w)
sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | d->dst_pipe_idx;
d->tx_req->length = 32*1024;
d->tx_req->udc_priv = sps_params;
- msm_ep_config(port->port_usb->in, d->tx_req, GFP_ATOMIC);
+ msm_ep_config(port->port_usb->in, d->tx_req);
} else {
/* Configure for RX */
diff --git a/drivers/usb/gadget/function/u_bam_data.c b/drivers/usb/gadget/function/u_bam_data.c
index 226af4bf1595..e479907e93ef 100644
--- a/drivers/usb/gadget/function/u_bam_data.c
+++ b/drivers/usb/gadget/function/u_bam_data.c
@@ -935,7 +935,7 @@ static void bam2bam_data_connect_work(struct work_struct *w)
| MSM_PRODUCER | d->src_pipe_idx;
d->rx_req->length = 32*1024;
d->rx_req->udc_priv = sps_params;
- msm_ep_config(port->port_usb->out, d->rx_req, GFP_ATOMIC);
+ msm_ep_config(port->port_usb->out, d->rx_req);
/* Configure TX */
configure_usb_data_fifo(d->usb_bam_type,
@@ -945,7 +945,7 @@ static void bam2bam_data_connect_work(struct work_struct *w)
| d->dst_pipe_idx;
d->tx_req->length = 32*1024;
d->tx_req->udc_priv = sps_params;
- msm_ep_config(port->port_usb->in, d->tx_req, GFP_ATOMIC);
+ msm_ep_config(port->port_usb->in, d->tx_req);
} else {
/* Configure RX */
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index 1850aa6ea19d..51d95f6c01d4 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -457,7 +457,7 @@ static void ipa_data_connect_work(struct work_struct *w)
configure_fifo(port->usb_bam_type,
port->src_connection_idx,
port->port_usb->out);
- ret = msm_ep_config(gport->out, port->rx_req, GFP_ATOMIC);
+ ret = msm_ep_config(gport->out, port->rx_req);
if (ret) {
pr_err("msm_ep_config() failed for OUT EP\n");
usb_bam_free_fifos(port->usb_bam_type,
@@ -475,7 +475,7 @@ static void ipa_data_connect_work(struct work_struct *w)
port->tx_req->udc_priv = sps_params;
configure_fifo(port->usb_bam_type,
port->dst_connection_idx, gport->in);
- ret = msm_ep_config(gport->in, port->tx_req, GFP_ATOMIC);
+ ret = msm_ep_config(gport->in, port->tx_req);
if (ret) {
pr_err("msm_ep_config() failed for IN EP\n");
goto unconfig_msm_ep_out;
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
index e26f0977b9b7..42a9cda68659 100644
--- a/drivers/usb/gadget/function/u_qdss.c
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -99,7 +99,7 @@ static int init_data(struct usb_ep *ep)
pr_debug("init_data\n");
- res = msm_ep_config(ep, qdss->endless_req, GFP_ATOMIC);
+ res = msm_ep_config(ep, qdss->endless_req);
if (res)
pr_err("msm_ep_config failed\n");