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

Commit 97882a07 authored by Udipto Goswami's avatar Udipto Goswami
Browse files

usb: f_qdss: Fix race between usb_connect_work and qdss_disable



Currently in the HW path implementation of qdss, if
set_qdss_data_connection is executing & within that timeframe a
composition switch was issued, it will start executing
qdss_disable where the disconnect_work is queued. But as
set_qdss_data_connection was still executing which is part of
connect_work, it will go ahead as try to do usb_ep_queue. This
is because we never cleared connect_work which is why it would
still be executing in workqueue context. This will lead the
controller to access invalid addresses which would lead to SMMU
fault.

Fix this by doing ep_queue only after checking usb_connected
is set & doing this under spinlock protection.

Change-Id: Ib39040ec381a464854640145e2bf0b5bc8e1ef7a
Signed-off-by: default avatarUdipto Goswami <ugoswami@codeaurora.org>
parent 74809ce2
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -776,6 +776,12 @@ 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 (!dwc->pullups_connected) {
		dev_err(mdwc->dev, "%s: No Pullup\n", __func__);
		spin_unlock_irqrestore(&dwc->lock, flags);
		return -ESHUTDOWN;
	}

	if (!dep->endpoint.desc) {
		dev_err(mdwc->dev,
			"%s: trying to queue request %pK to disabled ep %s\n",
+6 −1
Original line number Diff line number Diff line
@@ -607,17 +607,22 @@ static void usb_qdss_connect_work(struct work_struct *work)
	qdss = container_of(work, struct f_qdss, connect_w);

	/* If cable is already removed, discard connect_work */
	spin_lock_irqsave(&qdss->lock, flags);
	if (qdss->usb_connected == 0) {
		qdss_log("%s: discard connect_work\n", __func__);
		spin_unlock_irqrestore(&qdss->lock, flags);
		cancel_work_sync(&qdss->disconnect_w);
		return;
	}

	qdss_log("%s: channel name = %s\n", __func__, qdss->ch.name);

	if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM))
	if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) {
		spin_unlock_irqrestore(&qdss->lock, flags);
		goto notify;
	}

	spin_unlock_irqrestore(&qdss->lock, flags);
	status = set_qdss_data_connection(qdss, 1);
	if (status) {
		pr_err("set_qdss_data_connection error(%d)\n", status);