diff options
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
| -rw-r--r-- | drivers/usb/host/pci-quirks.c | 42 | 
1 files changed, 35 insertions, 7 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c5e9e4a76f1..966d1484ee7 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -75,7 +75,9 @@  #define	NB_PIF0_PWRDOWN_1	0x01100013  #define USB_INTEL_XUSB2PR      0xD0 +#define USB_INTEL_USB2PRM      0xD4  #define USB_INTEL_USB3_PSSEN   0xD8 +#define USB_INTEL_USB3PRM      0xDC  static struct amd_chipset_info {  	struct pci_dev	*nb_dev; @@ -772,10 +774,18 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)  		return;  	} -	ports_available = 0xffffffff; +	/* Read USB3PRM, the USB 3.0 Port Routing Mask Register +	 * Indicate the ports that can be changed from OS. +	 */ +	pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM, +			&ports_available); + +	dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n", +			ports_available); +  	/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable -	 * Register, to turn on SuperSpeed terminations for all -	 * available ports. +	 * Register, to turn on SuperSpeed terminations for the +	 * switchable ports.  	 */  	pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,  			cpu_to_le32(ports_available)); @@ -785,7 +795,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)  	dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "  			"under xHCI: 0x%x\n", ports_available); -	ports_available = 0xffffffff; +	/* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register +	 * Indicate the USB 2.0 ports to be controlled by the xHCI host. +	 */ + +	pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM, +			&ports_available); + +	dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n", +			ports_available); +  	/* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to  	 * switch the USB 2.0 power and data lines over to the xHCI  	 * host. @@ -822,12 +841,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)  	void __iomem *op_reg_base;  	u32 val;  	int timeout; +	int len = pci_resource_len(pdev, 0);  	if (!mmio_resource_enabled(pdev, 0))  		return; -	base = ioremap_nocache(pci_resource_start(pdev, 0), -				pci_resource_len(pdev, 0)); +	base = ioremap_nocache(pci_resource_start(pdev, 0), len);  	if (base == NULL)  		return; @@ -837,9 +856,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)  	 */  	ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);  	do { +		if ((ext_cap_offset + sizeof(val)) > len) { +			/* We're reading garbage from the controller */ +			dev_warn(&pdev->dev, +				 "xHCI controller failing to respond"); +			return; +		} +  		if (!ext_cap_offset)  			/* We've reached the end of the extended capabilities */  			goto hc_init; +  		val = readl(base + ext_cap_offset);  		if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)  			break; @@ -870,9 +897,10 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)  	/* Disable any BIOS SMIs and clear all SMI events*/  	writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); +hc_init:  	if (usb_is_intel_switchable_xhci(pdev))  		usb_enable_xhci_ports(pdev); -hc_init: +  	op_reg_base = base + XHCI_HC_LENGTH(readl(base));  	/* Wait for the host controller to be ready before writing any  |