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

Commit f7e7f483 authored by Mayank Rana's avatar Mayank Rana
Browse files

xhci-hub: Handle error condition with xhci_stop_device



xhci_stop_device() is calling xhci_queue_stop_endpoint() multiple time
and doesn't check return value. xhci_queue_stop_endpoint() can return
error if xhci is already halted or not able to queue command.
xhci_stop_device() waits for stop command completion using
wait_for_completion which wouldn't be interrupted or completed if
queueing of command fails. It results into possible deadlock condition
where usb_disconnect() waits for this udev->lock which is already
acquired by caller of xhci_stop_device() which is set_port_feature().

Fix this issue by handling error condition and making sure that
xhci_stop_device() doesn't wait if queueing of command is failed.

Change-Id: Ica4db17afcd39a7e89fcf985f41760efd2756653
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 79d42bd7
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -407,11 +407,20 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
				return -ENOMEM;

			}
			xhci_queue_stop_endpoint(xhci, command, slot_id, i,
						 suspend);

			ret = xhci_queue_stop_endpoint(xhci, command, slot_id,
					i, suspend);
			if (ret) {
				spin_unlock_irqrestore(&xhci->lock, flags);
				goto err_cmd_queue;
			}
		}
	}
	xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
	ret = xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
	if (ret) {
		spin_unlock_irqrestore(&xhci->lock, flags);
		goto err_cmd_queue;
	}
	xhci_ring_cmd_db(xhci);
	spin_unlock_irqrestore(&xhci->lock, flags);

@@ -422,6 +431,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
		xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
		ret = -ETIME;
	}

err_cmd_queue:
	xhci_free_command(xhci, cmd);
	return ret;
}