diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c928dbbff881..dae3be1b9c8f 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) { |
@@ -4496,6 +4514,14 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci, | |||
4496 | { | 4514 | { |
4497 | unsigned long long timeout_ns; | 4515 | unsigned long long timeout_ns; |
4498 | 4516 | ||
4517 | /* Prevent U1 if service interval is shorter than U1 exit latency */ | ||
4518 | if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) { | ||
4519 | if (xhci_service_interval_to_ns(desc) <= udev->u1_params.mel) { | ||
4520 | dev_dbg(&udev->dev, "Disable U1, ESIT shorter than exit latency\n"); | ||
4521 | return USB3_LPM_DISABLED; | ||
4522 | } | ||
4523 | } | ||
4524 | |||
4499 | if (xhci->quirks & XHCI_INTEL_HOST) | 4525 | if (xhci->quirks & XHCI_INTEL_HOST) |
4500 | timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc); | 4526 | timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc); |
4501 | else | 4527 | else |
@@ -4552,6 +4578,14 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci, | |||
4552 | { | 4578 | { |
4553 | unsigned long long timeout_ns; | 4579 | unsigned long long timeout_ns; |
4554 | 4580 | ||
4581 | /* Prevent U2 if service interval is shorter than U2 exit latency */ | ||
4582 | if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) { | ||
4583 | if (xhci_service_interval_to_ns(desc) <= udev->u2_params.mel) { | ||
4584 | dev_dbg(&udev->dev, "Disable U2, ESIT shorter than exit latency\n"); | ||
4585 | return USB3_LPM_DISABLED; | ||
4586 | } | ||
4587 | } | ||
4588 | |||
4555 | if (xhci->quirks & XHCI_INTEL_HOST) | 4589 | if (xhci->quirks & XHCI_INTEL_HOST) |
4556 | timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc); | 4590 | timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc); |
4557 | else | 4591 | else |