Re: xhci deadlock warning from lockdep

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Oct 18, 2011 at 05:11:37PM -0400, Don Zickus wrote:
> Hi Sarah,
> 
> While trying to debug why a usb3 harddrive doesn't show when a usb3 hub is
> plugged into another port, I stumbled upon this deadlock warning from
> lockdep.

<snip>

> This was found using gregkh's usb-next (fa3ae0c1).
> 
> Basically what is happening is in xhci_stop_endpoint_command_watchdog()
> the xhci->lock is grabbed with just spin_lock.  What lockdep deduces is
> that if an interrupt occurred while in this function it would deadlock
> with xhci_irq because that function also grabs the xhci->lock.

The watchdog timer only runs when the hardware is seriously hosed (i.e.
has stopped giving back events for the stop endpoint command).  It's
possible, I suppose, for the host controller to interrupt with a
different event, so your patch is probably necessary.

> Fixing it is trivial by using spin_lock_irqsave instead.  However, I am
> not sure if that is really the right thing to do.  The patch below fixes
> the lockdep warning, but I am open to other suggestions (and willing to test
> them).

I think your patch is fine, and I'll get it off to Greg.

Sarah

> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index e4b7f00..3339ec3 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -816,23 +816,24 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
>  	struct xhci_ring *ring;
>  	struct xhci_td *cur_td;
>  	int ret, i, j;
> +	unsigned long flags;
>  
>  	ep = (struct xhci_virt_ep *) arg;
>  	xhci = ep->xhci;
>  
> -	spin_lock(&xhci->lock);
> +	spin_lock_irqsave(&xhci->lock, flags);
>  
>  	ep->stop_cmds_pending--;
>  	if (xhci->xhc_state & XHCI_STATE_DYING) {
>  		xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
>  				"xHCI as DYING, exiting.\n");
> -		spin_unlock(&xhci->lock);
> +		spin_unlock_irqrestore(&xhci->lock, flags);
>  		return;
>  	}
>  	if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
>  		xhci_dbg(xhci, "Stop EP timer ran, but no command pending, "
>  				"exiting.\n");
> -		spin_unlock(&xhci->lock);
> +		spin_unlock_irqrestore(&xhci->lock, flags);
>  		return;
>  	}
>  
> @@ -844,11 +845,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
>  	xhci->xhc_state |= XHCI_STATE_DYING;
>  	/* Disable interrupts from the host controller and start halting it */
>  	xhci_quiesce(xhci);
> -	spin_unlock(&xhci->lock);
> +	spin_unlock_irqrestore(&xhci->lock, flags);
>  
>  	ret = xhci_halt(xhci);
>  
> -	spin_lock(&xhci->lock);
> +	spin_lock_irqsave(&xhci->lock, flags);
>  	if (ret < 0) {
>  		/* This is bad; the host is not responding to commands and it's
>  		 * not allowing itself to be halted.  At least interrupts are
> @@ -896,7 +897,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
>  			}
>  		}
>  	}
> -	spin_unlock(&xhci->lock);
> +	spin_unlock_irqrestore(&xhci->lock, flags);
>  	xhci_dbg(xhci, "Calling usb_hc_died()\n");
>  	usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
>  	xhci_dbg(xhci, "xHCI host controller is dead.\n");
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux