Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a162cde authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
Signed-off-by: default avatarChandana Kishori Chiluveru <cchiluve@codeaurora.org>
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent 6f536528
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -715,6 +715,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);
@@ -722,14 +730,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) */
@@ -1459,8 +1464,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;
@@ -1472,29 +1476,36 @@ 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);
	if (!new_ep_ops)
	new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC);
	if (!new_ep_ops) {
		spin_unlock_irqrestore(&dwc->lock, flags);
		return -ENOMEM;
	}

	(*new_ep_ops) = (*ep->ops);
	new_ep_ops->queue = dwc3_msm_ep_queue;
	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.
@@ -1510,9 +1521,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);
@@ -1532,12 +1546,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;
@@ -1549,8 +1566,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->trb_dequeue == dep->trb_enqueue
					&& list_empty(&dep->pending_list)
@@ -1572,6 +1591,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);
+2 −2
Original line number Diff line number Diff line
@@ -2378,7 +2378,7 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi,
		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 */
	}

@@ -2388,7 +2388,7 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi,
		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 */
	}

+2 −2
Original line number Diff line number Diff line
@@ -478,7 +478,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");
			spin_unlock_irqrestore(&port->port_lock, flags);
@@ -503,7 +503,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");
			spin_unlock_irqrestore(&port->port_lock, flags);
+1 −1
Original line number Diff line number Diff line
@@ -136,7 +136,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");

+2 −4
Original line number Diff line number Diff line
@@ -1127,8 +1127,7 @@ extern struct usb_ep *usb_ep_autoconfig_by_name(struct usb_gadget *gadget,
			const char *ep_name);

#ifdef CONFIG_USB_DWC3_MSM
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);
int msm_ep_unconfig(struct usb_ep *ep);
void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable);
int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size,
@@ -1140,8 +1139,7 @@ static inline int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr,
	u32 size, u8 dst_pipe_idx)
{	return -ENODEV; }

static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
					gfp_t gfp_flags)
static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request)
{ return -ENODEV; }

static inline int msm_ep_unconfig(struct usb_ep *ep)