diff options
| -rw-r--r-- | drivers/usb/host/xhci-pci.c | 4 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 26 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 3 |
3 files changed, 29 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a9515265db4d..a9ec7051f286 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
| @@ -139,6 +139,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
| 139 | pdev->device == 0x43bb)) | 139 | pdev->device == 0x43bb)) |
| 140 | xhci->quirks |= XHCI_SUSPEND_DELAY; | 140 | xhci->quirks |= XHCI_SUSPEND_DELAY; |
| 141 | 141 | ||
| 142 | if (pdev->vendor == PCI_VENDOR_ID_AMD && | ||
| 143 | (pdev->device == 0x15e0 || pdev->device == 0x15e1)) | ||
| 144 | xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND; | ||
| 145 | |||
| 142 | if (pdev->vendor == PCI_VENDOR_ID_AMD) | 146 | if (pdev->vendor == PCI_VENDOR_ID_AMD) |
| 143 | xhci->quirks |= XHCI_TRUST_TX_LENGTH; | 147 | xhci->quirks |= XHCI_TRUST_TX_LENGTH; |
| 144 | 148 | ||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c928dbbff881..c20b85e28d81 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
| @@ -968,6 +968,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) | |||
| 968 | unsigned int delay = XHCI_MAX_HALT_USEC; | 968 | unsigned int delay = XHCI_MAX_HALT_USEC; |
| 969 | struct usb_hcd *hcd = xhci_to_hcd(xhci); | 969 | struct usb_hcd *hcd = xhci_to_hcd(xhci); |
| 970 | u32 command; | 970 | u32 command; |
| 971 | u32 res; | ||
| 971 | 972 | ||
| 972 | if (!hcd->state) | 973 | if (!hcd->state) |
| 973 | return 0; | 974 | return 0; |
| @@ -1021,11 +1022,28 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) | |||
| 1021 | command = readl(&xhci->op_regs->command); | 1022 | command = readl(&xhci->op_regs->command); |
| 1022 | command |= CMD_CSS; | 1023 | command |= CMD_CSS; |
| 1023 | writel(command, &xhci->op_regs->command); | 1024 | writel(command, &xhci->op_regs->command); |
| 1025 | xhci->broken_suspend = 0; | ||
| 1024 | if (xhci_handshake(&xhci->op_regs->status, | 1026 | if (xhci_handshake(&xhci->op_regs->status, |
| 1025 | STS_SAVE, 0, 10 * 1000)) { | 1027 | STS_SAVE, 0, 10 * 1000)) { |
| 1026 | xhci_warn(xhci, "WARN: xHC save state timeout\n"); | 1028 | /* |
| 1027 | spin_unlock_irq(&xhci->lock); | 1029 | * AMD SNPS xHC 3.0 occasionally does not clear the |
| 1028 | return -ETIMEDOUT; | 1030 | * SSS bit of USBSTS and when driver tries to poll |
| 1031 | * to see if the xHC clears BIT(8) which never happens | ||
| 1032 | * and driver assumes that controller is not responding | ||
| 1033 | * and times out. To workaround this, its good to check | ||
| 1034 | * if SRE and HCE bits are not set (as per xhci | ||
| 1035 | * Section 5.4.2) and bypass the timeout. | ||
| 1036 | */ | ||
| 1037 | res = readl(&xhci->op_regs->status); | ||
| 1038 | if ((xhci->quirks & XHCI_SNPS_BROKEN_SUSPEND) && | ||
| 1039 | (((res & STS_SRE) == 0) && | ||
| 1040 | ((res & STS_HCE) == 0))) { | ||
| 1041 | xhci->broken_suspend = 1; | ||
| 1042 | } else { | ||
| 1043 | xhci_warn(xhci, "WARN: xHC save state timeout\n"); | ||
| 1044 | spin_unlock_irq(&xhci->lock); | ||
| 1045 | return -ETIMEDOUT; | ||
| 1046 | } | ||
| 1029 | } | 1047 | } |
| 1030 | spin_unlock_irq(&xhci->lock); | 1048 | spin_unlock_irq(&xhci->lock); |
| 1031 | 1049 | ||
| @@ -1078,7 +1096,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) | |||
| 1078 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); | 1096 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); |
| 1079 | 1097 | ||
| 1080 | spin_lock_irq(&xhci->lock); | 1098 | spin_lock_irq(&xhci->lock); |
| 1081 | if (xhci->quirks & XHCI_RESET_ON_RESUME) | 1099 | if ((xhci->quirks & XHCI_RESET_ON_RESUME) || xhci->broken_suspend) |
| 1082 | hibernated = true; | 1100 | hibernated = true; |
| 1083 | 1101 | ||
| 1084 | if (!hibernated) { | 1102 | if (!hibernated) { |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 260b259b72bc..c3515bad5dbb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
| @@ -1850,6 +1850,7 @@ struct xhci_hcd { | |||
| 1850 | #define XHCI_ZERO_64B_REGS BIT_ULL(32) | 1850 | #define XHCI_ZERO_64B_REGS BIT_ULL(32) |
| 1851 | #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) | 1851 | #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) |
| 1852 | #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) | 1852 | #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) |
| 1853 | #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) | ||
| 1853 | 1854 | ||
| 1854 | unsigned int num_active_eps; | 1855 | unsigned int num_active_eps; |
| 1855 | unsigned int limit_active_eps; | 1856 | unsigned int limit_active_eps; |
| @@ -1879,6 +1880,8 @@ struct xhci_hcd { | |||
| 1879 | void *dbc; | 1880 | void *dbc; |
| 1880 | /* platform-specific data -- must come last */ | 1881 | /* platform-specific data -- must come last */ |
| 1881 | unsigned long priv[0] __aligned(sizeof(s64)); | 1882 | unsigned long priv[0] __aligned(sizeof(s64)); |
| 1883 | /* Broken Suspend flag for SNPS Suspend resume issue */ | ||
| 1884 | u8 broken_suspend; | ||
| 1882 | }; | 1885 | }; |
| 1883 | 1886 | ||
| 1884 | /* Platform specific overrides to generic XHCI hc_driver ops */ | 1887 | /* Platform specific overrides to generic XHCI hc_driver ops */ |
