From e3020f3887dbd1f4443e5012942f6ec72e3fe9e9 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Fri, 19 Feb 2016 15:14:07 -0800 Subject: [PATCH] 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: Mayank Rana --- drivers/usb/host/xhci-hub.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index f980c239eded..0f51d078416e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -395,11 +395,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); @@ -410,6 +419,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; }