Dear all, I ran into a regression with an ExpressCard/54 USB 3.0 expansion card that uses the Renesas uPD72020x chipset on a Lenovo X220i Laptop (the described behavior has been reproduced with kernel versions 4.12.8, 4.12.13, 4.13.1 and 4.13.2). Once booting such a kernel, the system becomes very sluggish with considerable mouse pointer delays that are followed by display driver errors such as - pipe A vblank wait timed out - pipe B vblank wait timed out after some minutes. Please refer to https://weichselbraun.net/tmp/dmesg-pipe-a-vblank-timeout.log https://weichselbraun.net/tmp/dmesg-pipe-b-vblank-timeout.log for the corresponding log messages. Removing the expansion card or booting with a pre 4.12.8 kernel resolves the issue. I traced the problem back to the following patch that has been introduced in 4.12.8 and seems to force a PCI reset on the device. <snip url="https://patchwork.ozlabs.org/patch/786253/">;;; diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci- quirks.c index a9a1e4c40480..5bed002c7dd3 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -1096,3 +1096,23 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); + +bool usb_xhci_needs_pci_reset(struct pci_dev *pdev) +{ + /* + * Our dear uPD72020{1,2} friend only partially resets when + * asked to via the XHCI interface, and may end-up doing DMA + * at the wrong addresses, as it keeps the top 32bit of some + * addresses from its previous programming under obscure + * circumstances. + * Give it a good wack at probe time. Unfortunately, this + * needs to happen before we've had a chance to discover any + * quirk, or the system will be in a rather bad state. + */ + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + (pdev->device == 0x0014 || pdev->device == 0x0015)) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(usb_xhci_needs_pci_reset); diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci- quirks.h index 0222195bd5b0..dcbe4b097b33 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -14,6 +14,7 @@ void usb_amd_quirk_pll_enable(void); void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); void sb800_prefetch(struct device *dev, int on); +bool usb_xhci_needs_pci_reset(struct pci_dev *pdev); #else struct pci_dev; static inline void usb_amd_quirk_pll_disable(void) {} diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1bcf971141c0..3831705c2817 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -267,6 +267,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) driver = (struct hc_driver *)id->driver_data; + /* For some HW implementation, a XHCI reset is just not enough... */ + if (usb_xhci_needs_pci_reset(dev)) { + dev_info(&dev->dev, "Resetting\n"); + if (pci_reset_function_locked(dev)) + dev_warn(&dev->dev, "Reset failed"); + } + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev); </snip> What seems to happen on my machine is that the reset fails leaving the device in an undefined state: <snip> Sep 17 08:35:19 trinity kernel: [ 2.874329] xhci_hcd 0000:05:00.0: xHCI host controller not responding, assume dead Sep 17 08:35:19 trinity kernel: [ 2.874341] xhci_hcd 0000:05:00.0: remove, state 1 Sep 17 08:35:19 trinity kernel: [ 2.874350] usb usb4: USB disconnect, device number 1 Sep 17 08:35:19 trinity kernel: [ 2.874608] xhci_hcd 0000:05:00.0: USB bus 4 deregistered Sep 17 08:35:19 trinity kernel: [ 2.875433] xhci_hcd 0000:05:00.0: remove, state 1 Sep 17 08:35:19 trinity kernel: [ 2.875440] usb usb3: USB disconnect, device number 1 Sep 17 08:35:19 trinity kernel: [ 2.875535] clocksource: Switched to clocksource tsc Sep 17 08:35:19 trinity kernel: [ 2.875769] xhci_hcd 0000:05:00.0: Host halt failed, -19 Sep 17 08:35:19 trinity kernel: [ 2.875777] xhci_hcd 0000:05:00.0: Host not accessible, reset failed. Sep 17 08:35:19 trinity kernel: [ 2.876148] xhci_hcd 0000:05:00.0: USB bus 3 deregistered </snip> The full dmesg output is available at https://weichselbraun.net/tmp/dmesg-4.13.2-unpatched Reverting the changes (tested on 4.12.8, 4.13.1 and 4.13.2) solves this issue on my system. https://weichselbraun.net/tmp/dmesg-4.13.2-patched lspci: 05:00.0 USB controller: Renesas Technology Corp. uPD720202 USB 3.0 Host Controller (rev 02) Please let me know if there is any additional information I can provide to help narrowing this down. Cheers, albert :)
Attachment:
signature.asc
Description: This is a digitally signed message part