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

Commit 8a78fc9c authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa
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>
parent b2b64139
Loading
Loading
Loading
Loading
+30 −10
Original line number Diff line number Diff line
@@ -675,6 +675,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);
@@ -682,14 +690,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) */
@@ -1352,8 +1357,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;
@@ -1365,23 +1369,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);
@@ -1389,8 +1397,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.
@@ -1406,9 +1416,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);
@@ -1428,12 +1441,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_dbg(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;
@@ -1445,8 +1461,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)) {
@@ -1467,6 +1485,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
@@ -2373,7 +2373,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 */
	}

@@ -2383,7 +2383,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 */
	}

+2 −2
Original line number Diff line number Diff line
@@ -1404,7 +1404,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,
@@ -1412,7 +1412,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 */
+2 −2
Original line number Diff line number Diff line
@@ -937,7 +937,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,
@@ -947,7 +947,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 */
+2 −4
Original line number Diff line number Diff line
@@ -362,8 +362,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,
@@ -387,8 +386,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;
Loading