From d9f11ba9f107aa335091ab8d7ba5eea714e46e8b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 7 Apr 2017 17:57:01 +0300 Subject: xhci: Rework how we handle unresponsive or hoptlug removed hosts Introduce a new xhci_hc_died() function that takes care of handling pending commands and URBs if a host controller becomes unresponsive. This addresses issues on hotpluggable xhci controllers that disappear from the bus suddenly, often while the bus (PCI) remove function is still being processed. xhci_hc_died() sets a XHCI_STATUS_DYING flag to prevent new URBs and commands or to be queued. The flag also ensures xhci_hc_died() will give back pending commands and URBs once. Host is considered dead if register read returns 0xffffffff, or host fails to abort the command ring, or fails stopping an endpoint after trying for 5 seconds. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/usb/host/xhci-hub.c') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a0545fc367ca..0b88e76251eb 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1050,7 +1050,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; wIndex--; temp = readl(port_array[wIndex]); - if (temp == 0xffffffff) { + if (temp == ~(u32)0) { + xhci_hc_died(xhci); retval = -ENODEV; break; } @@ -1092,7 +1093,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; wIndex--; temp = readl(port_array[wIndex]); - if (temp == 0xffffffff) { + if (temp == ~(u32)0) { + xhci_hc_died(xhci); retval = -ENODEV; break; } @@ -1267,7 +1269,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; wIndex--; temp = readl(port_array[wIndex]); - if (temp == 0xffffffff) { + if (temp == ~(u32)0) { + xhci_hc_died(xhci); retval = -ENODEV; break; } @@ -1378,7 +1381,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < max_ports; i++) { temp = readl(port_array[i]); - if (temp == 0xffffffff) { + if (temp == ~(u32)0) { + xhci_hc_died(xhci); retval = -ENODEV; break; } -- cgit