diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/uhci-pci.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 12 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 29 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
4 files changed, 45 insertions, 8 deletions
diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 3592f757fe05..7bd2fddde770 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -119,11 +119,13 @@ static int uhci_pci_init(struct usb_hcd *hcd) uhci->rh_numports = uhci_count_ports(hcd); - /* Intel controllers report the OverCurrent bit active on. - * VIA controllers report it active off, so we'll adjust the - * bit value. (It's not standardized in the UHCI spec.) + /* + * Intel controllers report the OverCurrent bit active on. VIA + * and ZHAOXIN controllers report it active off, so we'll adjust + * the bit value. (It's not standardized in the UHCI spec.) */ - if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA) + if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA || + to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_ZHAOXIN) uhci->oc_low = 1; /* HP's server management chip requires a longer port reset delay. */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index ddb79f23fb3b..79b3691f373f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/acpi.h> #include <linux/reset.h> +#include <linux/suspend.h> #include "xhci.h" #include "xhci-trace.h" @@ -387,7 +388,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_RENOIR_XHCI) - xhci->quirks |= XHCI_BROKEN_D3COLD; + xhci->quirks |= XHCI_BROKEN_D3COLD_S2I; if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; @@ -801,9 +802,16 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) * Systems with the TI redriver that loses port status change events * need to have the registers polled during D3, so avoid D3cold. */ - if (xhci->quirks & (XHCI_COMP_MODE_QUIRK | XHCI_BROKEN_D3COLD)) + if (xhci->quirks & XHCI_COMP_MODE_QUIRK) pci_d3cold_disable(pdev); +#ifdef CONFIG_SUSPEND + /* d3cold is broken, but only when s2idle is used */ + if (pm_suspend_target_state == PM_SUSPEND_TO_IDLE && + xhci->quirks & (XHCI_BROKEN_D3COLD_S2I)) + pci_d3cold_disable(pdev); +#endif + if (xhci->quirks & XHCI_PME_STUCK_QUIRK) xhci_pme_quirk(hcd); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 1ad12d5a4857..2bc82b3a2f98 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -276,6 +276,26 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, trace_xhci_inc_enq(ring); } +static int xhci_num_trbs_to(struct xhci_segment *start_seg, union xhci_trb *start, + struct xhci_segment *end_seg, union xhci_trb *end, + unsigned int num_segs) +{ + union xhci_trb *last_on_seg; + int num = 0; + int i = 0; + + do { + if (start_seg == end_seg && end >= start) + return num + (end - start); + last_on_seg = &start_seg->trbs[TRBS_PER_SEGMENT - 1]; + num += last_on_seg - start; + start_seg = start_seg->next; + start = start_seg->trbs; + } while (i++ <= num_segs); + + return -EINVAL; +} + /* * Check to see if there's room to enqueue num_trbs on the ring and make sure * enqueue pointer will not advance into dequeue segment. See rules above. @@ -2140,6 +2160,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, u32 trb_comp_code) { struct xhci_ep_ctx *ep_ctx; + int trbs_freed; ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); @@ -2209,9 +2230,15 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, } /* Update ring dequeue pointer */ + trbs_freed = xhci_num_trbs_to(ep_ring->deq_seg, ep_ring->dequeue, + td->last_trb_seg, td->last_trb, + ep_ring->num_segs); + if (trbs_freed < 0) + xhci_dbg(xhci, "Failed to count freed trbs at TD finish\n"); + else + ep_ring->num_trbs_free += trbs_freed; ep_ring->dequeue = td->last_trb; ep_ring->deq_seg = td->last_trb_seg; - ep_ring->num_trbs_free += td->num_trbs - 1; inc_deq(xhci, ep_ring); return xhci_td_cleanup(xhci, td, ep_ring, td->status); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 08d721921b7b..6b690ec91ff3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1901,7 +1901,7 @@ struct xhci_hcd { #define XHCI_DISABLE_SPARSE BIT_ULL(38) #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39) #define XHCI_NO_SOFT_RETRY BIT_ULL(40) -#define XHCI_BROKEN_D3COLD BIT_ULL(41) +#define XHCI_BROKEN_D3COLD_S2I BIT_ULL(41) #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42) #define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43) #define XHCI_RESET_TO_DEFAULT BIT_ULL(44) |