| From c2e1abb35b37a2b46220ea0af7c8d70d8c09edf6 Mon Sep 17 00:00:00 2001 |
| From: Joel Stanley <joel@jms.id.au> |
| Date: Fri, 7 Apr 2017 17:57:00 +0300 |
| Subject: [PATCH 186/286] xhci: Do not halt the host until both HCD have |
| disconnected their devices. |
| |
| We can't halt the host controller immediately when first HCD is removed as |
| it will cause problems if we have devices attached to the second (primary) |
| HCD, like a keyboard. |
| |
| We've been carrying this in our Linux-as-a-bootloader environment for a |
| little while now. The machines all have the same TI TUSB73x0 part, |
| and when we kexec the devices don't come back until a system power cycle. |
| |
| [minor adjustments, code comments and remove HALT check -Mathias] |
| Signed-off-by: Joel Stanley <joel@jms.id.au> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| (cherry picked from commit fe190ed0d60260e44f48d8b0b04f26a8c8898a02) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/usb/host/xhci.c | 20 ++++++++++---------- |
| 1 file changed, 10 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/usb/host/xhci.c |
| +++ b/drivers/usb/host/xhci.c |
| @@ -692,21 +692,21 @@ void xhci_stop(struct usb_hcd *hcd) |
| |
| mutex_lock(&xhci->mutex); |
| |
| - if (!(xhci->xhc_state & XHCI_STATE_HALTED)) { |
| - spin_lock_irq(&xhci->lock); |
| - |
| - xhci->xhc_state |= XHCI_STATE_HALTED; |
| - xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; |
| - xhci_halt(xhci); |
| - xhci_reset(xhci); |
| - spin_unlock_irq(&xhci->lock); |
| - } |
| - |
| + /* Only halt host and free memory after both hcds are removed */ |
| if (!usb_hcd_is_primary_hcd(hcd)) { |
| + /* usb core will free this hcd shortly, unset pointer */ |
| + xhci->shared_hcd = NULL; |
| mutex_unlock(&xhci->mutex); |
| return; |
| } |
| |
| + spin_lock_irq(&xhci->lock); |
| + xhci->xhc_state |= XHCI_STATE_HALTED; |
| + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; |
| + xhci_halt(xhci); |
| + xhci_reset(xhci); |
| + spin_unlock_irq(&xhci->lock); |
| + |
| xhci_cleanup_msix(xhci); |
| |
| /* Deleting Compliance Mode Recovery Timer */ |