diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index a6101f095db81bbcee04389d57984f0dfba1aa3b..b7ed214b757c7770a1899e57010e8d600dd2ceb6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2123,7 +2123,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, { u32 temp, port_offset, port_count; int i; - u8 major_revision, minor_revision; + u8 major_revision, minor_revision, tmp_minor_revision; struct xhci_hub *rhub; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; struct xhci_port_cap *port_cap; @@ -2134,6 +2134,14 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, if (major_revision == 0x03) { rhub = &xhci->usb3_rhub; + /* + * Some zhaoxin's xHCI controller that follow usb3.1 spec + * but only support Gen1. + */ + if (xhci->quirks & XHCI_ZHAOXIN_HOST) { + tmp_minor_revision = minor_revision; + minor_revision = 0; + } } else if (major_revision <= 0x02) { rhub = &xhci->usb2_rhub; } else { @@ -2143,10 +2151,6 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, /* Ignoring port protocol we can't understand. FIXME */ return; } - rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp); - - if (rhub->min_rev < minor_revision) - rhub->min_rev = minor_revision; /* Port offset and count in the third dword, see section 7.2 */ temp = readl(addr + 2); @@ -2165,8 +2169,6 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, if (xhci->num_port_caps > max_caps) return; - port_cap->maj_rev = major_revision; - port_cap->min_rev = minor_revision; port_cap->psi_count = XHCI_EXT_PORT_PSIC(temp); if (port_cap->psi_count) { @@ -2187,6 +2189,11 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, XHCI_EXT_PORT_PSIV(port_cap->psi[i - 1]))) port_cap->psi_uid_count++; + if (xhci->quirks & XHCI_ZHAOXIN_HOST && + major_revision == 0x03 && + XHCI_EXT_PORT_PSIV(port_cap->psi[i]) >= 5) + minor_revision = tmp_minor_revision; + xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d PSIM:%d\n", XHCI_EXT_PORT_PSIV(port_cap->psi[i]), XHCI_EXT_PORT_PSIE(port_cap->psi[i]), @@ -2196,6 +2203,15 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, XHCI_EXT_PORT_PSIM(port_cap->psi[i])); } } + + rhub->maj_rev = major_revision; + + if (rhub->min_rev < minor_revision) + rhub->min_rev = minor_revision; + + port_cap->maj_rev = major_revision; + port_cap->min_rev = minor_revision; + /* cache usb2 port capabilities */ if (major_revision < 0x03 && xhci->num_ext_caps < max_caps) xhci->ext_caps[xhci->num_ext_caps++] = temp; @@ -2450,15 +2466,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * and our use of dma addresses in the trb_address_map radix tree needs * TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need. */ - /* With xHCI TRB prefetch patch:To fix cross page boundry access issue - * in IOV environment */ - if (xhci->quirks & XHCI_ZHAOXIN_TRB_FETCH) { + if (xhci->quirks & XHCI_ZHAOXIN_TRB_FETCH) xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, - TRB_SEGMENT_SIZE*2, TRB_SEGMENT_SIZE*2, xhci->page_size*2); - } else { + TRB_SEGMENT_SIZE * 2, TRB_SEGMENT_SIZE * 2, xhci->page_size * 2); + else xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, - TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size); - } + TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size); /* See Table 46 and Note on Figure 55 */ xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 4c2376a4c1d6b2eb0a5e14b9f08275fd06430ea0..8eb049c4e65c6c52323e90bec9fc202817221290 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -218,10 +218,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) } if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; - if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) { - xhci->quirks |= XHCI_LPM_SUPPORT; - xhci->quirks |= XHCI_ZHAOXIN_HOST; - } if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) xhci->quirks |= XHCI_SUSPEND_DELAY; @@ -231,11 +227,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == 0x3432) xhci->quirks |= XHCI_BROKEN_STREAMS; - if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN && - (pdev->device == 0x9202 || - pdev->device == 0x9203)) - xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH; - if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1042) xhci->quirks |= XHCI_BROKEN_STREAMS; @@ -250,14 +241,24 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241) xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7; - if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN && pdev->device == 0x9202) - xhci->quirks |= XHCI_RESET_ON_RESUME; - if ((pdev->vendor == PCI_VENDOR_ID_BROADCOM || pdev->vendor == PCI_VENDOR_ID_CAVIUM) && pdev->device == 0x9026) xhci->quirks |= XHCI_RESET_PLL_ON_DISCONNECT; + if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) { + xhci->quirks |= XHCI_ZHAOXIN_HOST; + xhci->quirks |= XHCI_LPM_SUPPORT; + + if (pdev->device == 0x9202) { + xhci->quirks |= XHCI_RESET_ON_RESUME; + xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH; + } + + if (pdev->device == 0x9203) + xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH; + } + if (xhci->quirks & XHCI_RESET_ON_RESUME) xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "QUIRK: Resetting on resume"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1cb66cbe648799898e869174488bcb8e778a19cc..d4b86aa2a5eb706605585c15f06c0cebf74328b5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4704,70 +4704,33 @@ static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci, return 0; } -static int xhci_check_intel_tier_policy(struct usb_device *udev, +static int xhci_check_tier_policy(struct xhci_hcd *xhci, + struct usb_device *udev, enum usb3_link_state state) { - struct usb_device *parent; - unsigned int num_hubs; + struct usb_device *parent = udev->parent; + int tier = 1; /* roothub is tier1 */ if (state == USB3_LPM_U2) return 0; - /* Don't enable U1 if the device is on a 2nd tier hub or lower. */ - for (parent = udev->parent, num_hubs = 0; parent->parent; - parent = parent->parent) - num_hubs++; - - if (num_hubs < 2) - return 0; - - dev_dbg(&udev->dev, "Disabling U1 link state for device" - " below second-tier hub.\n"); - dev_dbg(&udev->dev, "Plug device into first-tier hub " - "to decrease power consumption.\n"); - return -E2BIG; -} - -static int xhci_check_zhaoxin_tier_policy(struct usb_device *udev, - enum usb3_link_state state) -{ - struct usb_device *parent; - unsigned int num_hubs; - char *state_name; - - if (state == USB3_LPM_U1) - state_name = "U1"; - else if (state == USB3_LPM_U2) - state_name = "U2"; - else - state_name = "Unknown"; - /* Don't enable U1/U2 if the device is on an external hub*/ - for (parent = udev->parent, num_hubs = 0; parent->parent; - parent = parent->parent) - num_hubs++; + while (parent) { + parent = parent->parent; + tier++; + } - if (num_hubs < 1) - return 0; + if (xhci->quirks & XHCI_INTEL_HOST && tier > 3) + goto fail; + if (xhci->quirks & XHCI_ZHAOXIN_HOST && tier > 2) + goto fail; - dev_dbg(&udev->dev, "Disabling %s link state for device" \ - " below external hub.\n", state_name); - dev_dbg(&udev->dev, "Plug device into root port " \ - "to decrease power consumption.\n"); + return 0; +fail: + dev_dbg(&udev->dev, "Tier policy prevents U1/U2 LPM states for devices at tier %d\n", + tier); return -E2BIG; } -static int xhci_check_tier_policy(struct xhci_hcd *xhci, - struct usb_device *udev, - enum usb3_link_state state) -{ - if (xhci->quirks & XHCI_INTEL_HOST) - return xhci_check_intel_tier_policy(udev, state); - else if (xhci->quirks & XHCI_ZHAOXIN_HOST) - return xhci_check_zhaoxin_tier_policy(udev, state); - else - return 0; -} - /* Returns the U1 or U2 timeout that should be enabled. * If the tier check or timeout setting functions return with a non-zero exit * code, that means the timeout value has been finalized and we shouldn't look @@ -5079,7 +5042,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) */ struct device *dev = hcd->self.sysdev; unsigned int minor_rev; - u8 i, j; int retval; /* Accept arbitrarily long scatter-gather lists */ @@ -5134,24 +5096,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; break; } - - /* usb3.1 has gen1 and gen2, Some zx's xHCI controller that follow usb3.1 spec - * but only support gen1 - */ - if (xhci->quirks & XHCI_ZHAOXIN_HOST) { - minor_rev = 0; - for (j = 0; j < xhci->num_port_caps; j++) { - for (i = 0; i < xhci->port_caps[j].psi_count; i++) { - if (XHCI_EXT_PORT_PSIV(xhci->port_caps[j].psi[i]) >= 5) - minor_rev = 1; - } - } - if (minor_rev != 1) { - hcd->speed = HCD_USB3; - hcd->self.root_hub->speed = USB_SPEED_SUPER; - } - } - xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n", minor_rev, minor_rev ? "Enhanced " : ""); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 485ba36b566caff7d33a82903fe00bd2df95c47c..4f91bd3194c7374fc76b23d68616fb786740e245 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1873,7 +1873,8 @@ struct xhci_hcd { #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) #define XHCI_ZHAOXIN_HOST BIT_ULL(36) -#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(39) +#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45) +#define XHCI_ZHAOXIN_HOST BIT_ULL(46) unsigned int num_active_eps; unsigned int limit_active_eps;