diff options
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
| -rw-r--r-- | drivers/usb/host/pci-quirks.c | 57 | 
1 files changed, 25 insertions, 32 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 27a3dec32fa..caf87428ca4 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -37,6 +37,7 @@  #define OHCI_INTRENABLE		0x10  #define OHCI_INTRDISABLE	0x14  #define OHCI_FMINTERVAL		0x34 +#define OHCI_HCFS		(3 << 6)	/* hc functional state */  #define OHCI_HCR		(1 << 0)	/* host controller reset */  #define OHCI_OCR		(1 << 3)	/* ownership change request */  #define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */ @@ -466,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)  {  	void __iomem *base;  	u32 control; +	u32 fminterval; +	int cnt;  	if (!mmio_resource_enabled(pdev, 0))  		return; @@ -498,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)  	}  #endif -	/* reset controller, preserving RWC (and possibly IR) */ -	writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); -	readl(base + OHCI_CONTROL); +	/* disable interrupts */ +	writel((u32) ~0, base + OHCI_INTRDISABLE); -	/* Some NVIDIA controllers stop working if kept in RESET for too long */ -	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { -		u32 fminterval; -		int cnt; +	/* Reset the USB bus, if the controller isn't already in RESET */ +	if (control & OHCI_HCFS) { +		/* Go into RESET, preserving RWC (and possibly IR) */ +		writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); +		readl(base + OHCI_CONTROL); -		/* drive reset for at least 50 ms (7.1.7.5) */ +		/* drive bus reset for at least 50 ms (7.1.7.5) */  		msleep(50); +	} -		/* software reset of the controller, preserving HcFmInterval */ -		fminterval = readl(base + OHCI_FMINTERVAL); -		writel(OHCI_HCR, base + OHCI_CMDSTATUS); +	/* software reset of the controller, preserving HcFmInterval */ +	fminterval = readl(base + OHCI_FMINTERVAL); +	writel(OHCI_HCR, base + OHCI_CMDSTATUS); -		/* reset requires max 10 us delay */ -		for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */ -			if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) -				break; -			udelay(1); -		} -		writel(fminterval, base + OHCI_FMINTERVAL); - -		/* Now we're in the SUSPEND state with all devices reset -		 * and wakeups and interrupts disabled -		 */ +	/* reset requires max 10 us delay */ +	for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */ +		if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) +			break; +		udelay(1);  	} +	writel(fminterval, base + OHCI_FMINTERVAL); -	/* -	 * disable interrupts -	 */ -	writel(~(u32)0, base + OHCI_INTRDISABLE); -	writel(~(u32)0, base + OHCI_INTRSTATUS); - +	/* Now the controller is safely in SUSPEND and nothing can wake it up */  	iounmap(base);  } @@ -627,7 +621,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)  	void __iomem *base, *op_reg_base;  	u32	hcc_params, cap, val;  	u8	offset, cap_length; -	int	wait_time, delta, count = 256/4; +	int	wait_time, count = 256/4;  	if (!mmio_resource_enabled(pdev, 0))  		return; @@ -673,11 +667,10 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)  		writel(val, op_reg_base + EHCI_USBCMD);  		wait_time = 2000; -		delta = 100;  		do {  			writel(0x3f, op_reg_base + EHCI_USBSTS); -			udelay(delta); -			wait_time -= delta; +			udelay(100); +			wait_time -= 100;  			val = readl(op_reg_base + EHCI_USBSTS);  			if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {  				break;  |