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

Commit 8159668a authored by Mayank Rana's avatar Mayank Rana
Browse files

dwc3-msm: Check USB Endpoint status before queueing endless request



TRB Pool is allocated and de-allocated per endpoint when USB endpoint
is enabled and disabled respectively. In some instance, it has been
observed that usb_ep_disable() (for rmnet case, (u_bam.c) it is called
from set_alt or resume context i.e. interrupt context) and usb_ep_queue()
(for rmnet case, (u_bam.c) it is called from work queue context) are
racing for USB endless endpoint when USB bus suspend and resume is
happening quickly. It is causing NULL pointer dereference while accessing
TRB pool. Fix this issue by moving check if USB endpoint is enable or not
after acquiring dwc3->lock and before calling __dwc3_msm_ep_queue() which
prepares endless TRB.

CRs-Fixed: 986071
Change-Id: I842f6a82f3c454111ba68661cf835e86022e3e18
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent d5809484
Loading
Loading
Loading
Loading
+36 −28
Original line number Diff line number Diff line
@@ -668,32 +668,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
								gfp_flags);
	}

	if (!dep->endpoint.desc) {
		dev_err(mdwc->dev,
			"%s: trying to queue request %p to disabled ep %s\n",
			__func__, request, ep->name);
		return -EPERM;
	}

	if (dep->number == 0 || dep->number == 1) {
		dev_err(mdwc->dev,
			"%s: trying to queue dbm request %p to control ep %s\n",
			__func__, request, ep->name);
		return -EPERM;
	}


	if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
					 || !list_empty(&dep->req_queued)) {
		dev_err(mdwc->dev,
			"%s: trying to queue dbm request %p tp ep %s\n",
			__func__, request, ep->name);
		return -EPERM;
	} else {
		dep->busy_slot = 0;
		dep->free_slot = 0;
	}

	/* HW restriction regarding TRB size (8KB) */
	if (req->request.length < 0x2000) {
		dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__);
@@ -730,18 +704,52 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
	 * as soon as possible so we will release back the lock.
	 */
	spin_lock_irqsave(&dwc->lock, flags);
	if (!dep->endpoint.desc) {
		dev_err(mdwc->dev,
			"%s: trying to queue request %p to disabled ep %s\n",
			__func__, request, ep->name);
		ret = -EPERM;
		goto err;
	}

	if (dep->number == 0 || dep->number == 1) {
		dev_err(mdwc->dev,
			"%s: trying to queue dbm request %p to control ep %s\n",
			__func__, request, ep->name);
		ret = -EPERM;
		goto err;
	}


	if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
					 || !list_empty(&dep->req_queued)) {
		dev_err(mdwc->dev,
			"%s: trying to queue dbm request %p tp ep %s\n",
			__func__, request, ep->name);
		ret = -EPERM;
		goto err;
	} else {
		dep->busy_slot = 0;
		dep->free_slot = 0;
	}

	ret = __dwc3_msm_ep_queue(dep, req);
	spin_unlock_irqrestore(&dwc->lock, flags);
	if (ret < 0) {
		dev_err(mdwc->dev,
			"error %d after calling __dwc3_msm_ep_queue\n", ret);
		return ret;
		goto err;
	}

	spin_unlock_irqrestore(&dwc->lock, flags);
	superspeed = dwc3_msm_is_dev_superspeed(mdwc);
	dbm_set_speed(mdwc->dbm, (u8)superspeed);

	return 0;

err:
	spin_unlock_irqrestore(&dwc->lock, flags);
	kfree(req_complete);
	return ret;
}

/*