diff options
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 10 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-pci.c | 45 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 73 | ||||
| -rw-r--r-- | drivers/usb/host/ehci.h | 2 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 13 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-pci.c | 110 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-q.c | 4 | ||||
| -rw-r--r-- | drivers/usb/host/ohci.h | 4 | ||||
| -rw-r--r-- | drivers/usb/host/pci-quirks.c | 258 | ||||
| -rw-r--r-- | drivers/usb/host/pci-quirks.h | 10 | 
10 files changed, 300 insertions, 229 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index f69305d3a9b..e6277536f39 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -114,13 +114,11 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");  #define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) -/* for ASPM quirk of ISOC on AMD SB800 */ -static struct pci_dev *amd_nb_dev; -  /*-------------------------------------------------------------------------*/  #include "ehci.h"  #include "ehci-dbg.c" +#include "pci-quirks.h"  /*-------------------------------------------------------------------------*/ @@ -532,10 +530,8 @@ static void ehci_stop (struct usb_hcd *hcd)  	spin_unlock_irq (&ehci->lock);  	ehci_mem_cleanup (ehci); -	if (amd_nb_dev) { -		pci_dev_put(amd_nb_dev); -		amd_nb_dev = NULL; -	} +	if (ehci->amd_pll_fix == 1) +		usb_amd_dev_put();  #ifdef	EHCI_STATS  	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 07bb982e59f..d5eaea7caf8 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -44,42 +44,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)  	return 0;  } -static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci) -{ -	struct pci_dev *amd_smbus_dev; -	u8 rev = 0; - -	amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); -	if (amd_smbus_dev) { -		pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); -		if (rev < 0x40) { -			pci_dev_put(amd_smbus_dev); -			amd_smbus_dev = NULL; -			return 0; -		} -	} else { -		amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL); -		if (!amd_smbus_dev) -			return 0; -		pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); -		if (rev < 0x11 || rev > 0x18) { -			pci_dev_put(amd_smbus_dev); -			amd_smbus_dev = NULL; -			return 0; -		} -	} - -	if (!amd_nb_dev) -		amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL); - -	ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n"); - -	pci_dev_put(amd_smbus_dev); -	amd_smbus_dev = NULL; - -	return 1; -} -  /* called during probe() after chip reset completes */  static int ehci_pci_setup(struct usb_hcd *hcd)  { @@ -138,9 +102,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)  	/* cache this readonly data; minimize chip reads */  	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); -	if (ehci_quirk_amd_hudson(ehci)) -		ehci->amd_l1_fix = 1; -  	retval = ehci_halt(ehci);  	if (retval)  		return retval; @@ -191,6 +152,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)  		}  		break;  	case PCI_VENDOR_ID_AMD: +		/* AMD PLL quirk */ +		if (usb_amd_find_chipset_info()) +			ehci->amd_pll_fix = 1;  		/* AMD8111 EHCI doesn't work, according to AMD errata */  		if (pdev->device == 0x7463) {  			ehci_info(ehci, "ignoring AMD8111 (errata)\n"); @@ -236,6 +200,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)  		}  		break;  	case PCI_VENDOR_ID_ATI: +		/* AMD PLL quirk */ +		if (usb_amd_find_chipset_info()) +			ehci->amd_pll_fix = 1;  		/* SB600 and old version of SB700 have a bug in EHCI controller,  		 * which causes usb devices lose response in some cases.  		 */ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 30fbdbe1cf1..1543c838b3d 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1587,63 +1587,6 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)  	*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);  } -#define AB_REG_BAR_LOW 0xe0 -#define AB_REG_BAR_HIGH 0xe1 -#define AB_INDX(addr) ((addr) + 0x00) -#define AB_DATA(addr) ((addr) + 0x04) -#define NB_PCIE_INDX_ADDR 0xe0 -#define NB_PCIE_INDX_DATA 0xe4 -#define NB_PIF0_PWRDOWN_0 0x01100012 -#define NB_PIF0_PWRDOWN_1 0x01100013 - -static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable) -{ -	u32 addr, addr_low, addr_high, val; - -	outb_p(AB_REG_BAR_LOW, 0xcd6); -	addr_low = inb_p(0xcd7); -	outb_p(AB_REG_BAR_HIGH, 0xcd6); -	addr_high = inb_p(0xcd7); -	addr = addr_high << 8 | addr_low; -	outl_p(0x30, AB_INDX(addr)); -	outl_p(0x40, AB_DATA(addr)); -	outl_p(0x34, AB_INDX(addr)); -	val = inl_p(AB_DATA(addr)); - -	if (disable) { -		val &= ~0x8; -		val |= (1 << 4) | (1 << 9); -	} else { -		val |= 0x8; -		val &= ~((1 << 4) | (1 << 9)); -	} -	outl_p(val, AB_DATA(addr)); - -	if (amd_nb_dev) { -		addr = NB_PIF0_PWRDOWN_0; -		pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr); -		pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val); -		if (disable) -			val &= ~(0x3f << 7); -		else -			val |= 0x3f << 7; - -		pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val); - -		addr = NB_PIF0_PWRDOWN_1; -		pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr); -		pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val); -		if (disable) -			val &= ~(0x3f << 7); -		else -			val |= 0x3f << 7; - -		pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val); -	} - -	return; -} -  /* fit urb's itds into the selected schedule slot; activate as needed */  static int  itd_link_urb ( @@ -1672,8 +1615,8 @@ itd_link_urb (  	}  	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { -		if (ehci->amd_l1_fix == 1) -			ehci_quirk_amd_L1(ehci, 1); +		if (ehci->amd_pll_fix == 1) +			usb_amd_quirk_pll_disable();  	}  	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; @@ -1801,8 +1744,8 @@ itd_complete (  	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;  	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { -		if (ehci->amd_l1_fix == 1) -			ehci_quirk_amd_L1(ehci, 0); +		if (ehci->amd_pll_fix == 1) +			usb_amd_quirk_pll_enable();  	}  	if (unlikely(list_is_singular(&stream->td_list))) { @@ -2092,8 +2035,8 @@ sitd_link_urb (  	}  	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { -		if (ehci->amd_l1_fix == 1) -			ehci_quirk_amd_L1(ehci, 1); +		if (ehci->amd_pll_fix == 1) +			usb_amd_quirk_pll_disable();  	}  	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; @@ -2197,8 +2140,8 @@ sitd_complete (  	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;  	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { -		if (ehci->amd_l1_fix == 1) -			ehci_quirk_amd_L1(ehci, 0); +		if (ehci->amd_pll_fix == 1) +			usb_amd_quirk_pll_enable();  	}  	if (list_is_singular(&stream->td_list)) { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 799ac16a54b..f86d3fa2021 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -131,7 +131,7 @@ struct ehci_hcd {			/* one per controller */  	unsigned		has_amcc_usb23:1;  	unsigned		need_io_watchdog:1;  	unsigned		broken_periodic:1; -	unsigned		amd_l1_fix:1; +	unsigned		amd_pll_fix:1;  	unsigned		fs_i_thresh:1;	/* Intel iso scheduling */  	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/ diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 759a12ff804..7b791bf1e7b 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -75,6 +75,7 @@ static const char	hcd_name [] = "ohci_hcd";  #define	STATECHANGE_DELAY	msecs_to_jiffies(300)  #include "ohci.h" +#include "pci-quirks.h"  static void ohci_dump (struct ohci_hcd *ohci, int verbose);  static int ohci_init (struct ohci_hcd *ohci); @@ -85,18 +86,8 @@ static int ohci_restart (struct ohci_hcd *ohci);  #endif  #ifdef CONFIG_PCI -static void quirk_amd_pll(int state); -static void amd_iso_dev_put(void);  static void sb800_prefetch(struct ohci_hcd *ohci, int on);  #else -static inline void quirk_amd_pll(int state) -{ -	return; -} -static inline void amd_iso_dev_put(void) -{ -	return; -}  static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)  {  	return; @@ -912,7 +903,7 @@ static void ohci_stop (struct usb_hcd *hcd)  	if (quirk_zfmicro(ohci))  		del_timer(&ohci->unlink_watchdog);  	if (quirk_amdiso(ohci)) -		amd_iso_dev_put(); +		usb_amd_dev_put();  	remove_debug_files (ohci);  	ohci_mem_cleanup (ohci); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 36ee9a666e9..9816a2870d0 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -22,24 +22,6 @@  #include <linux/io.h> -/* constants used to work around PM-related transfer - * glitches in some AMD 700 series southbridges - */ -#define AB_REG_BAR	0xf0 -#define AB_INDX(addr)	((addr) + 0x00) -#define AB_DATA(addr)	((addr) + 0x04) -#define AX_INDXC	0X30 -#define AX_DATAC	0x34 - -#define NB_PCIE_INDX_ADDR	0xe0 -#define NB_PCIE_INDX_DATA	0xe4 -#define PCIE_P_CNTL		0x10040 -#define BIF_NB			0x10002 - -static struct pci_dev *amd_smbus_dev; -static struct pci_dev *amd_hb_dev; -static int amd_ohci_iso_count; -  /*-------------------------------------------------------------------------*/  static int broken_suspend(struct usb_hcd *hcd) @@ -168,11 +150,14 @@ static int ohci_quirk_nec(struct usb_hcd *hcd)  static int ohci_quirk_amd700(struct usb_hcd *hcd)  {  	struct ohci_hcd *ohci = hcd_to_ohci(hcd); +	struct pci_dev *amd_smbus_dev;  	u8 rev = 0; -	if (!amd_smbus_dev) -		amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, -				PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); +	if (usb_amd_find_chipset_info()) +		ohci->flags |= OHCI_QUIRK_AMD_PLL; + +	amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, +			PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);  	if (!amd_smbus_dev)  		return 0; @@ -184,19 +169,8 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)  		ohci_dbg(ohci, "enabled AMD prefetch quirk\n");  	} -	if ((rev > 0x3b) || (rev < 0x30)) { -		pci_dev_put(amd_smbus_dev); -		amd_smbus_dev = NULL; -		return 0; -	} - -	amd_ohci_iso_count++; - -	if (!amd_hb_dev) -		amd_hb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9600, NULL); - -	ohci->flags |= OHCI_QUIRK_AMD_ISO; -	ohci_dbg(ohci, "enabled AMD ISO transfers quirk\n"); +	pci_dev_put(amd_smbus_dev); +	amd_smbus_dev = NULL;  	return 0;  } @@ -215,74 +189,6 @@ static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)  	return 0;  } -/* - * The hardware normally enables the A-link power management feature, which - * lets the system lower the power consumption in idle states. - * - * Assume the system is configured to have USB 1.1 ISO transfers going - * to or from a USB device.  Without this quirk, that stream may stutter - * or have breaks occasionally.  For transfers going to speakers, this - * makes a very audible mess... - * - * That audio playback corruption is due to the audio stream getting - * interrupted occasionally when the link goes in lower power state - * This USB quirk prevents the link going into that lower power state - * during audio playback or other ISO operations. - */ -static void quirk_amd_pll(int on) -{ -	u32 addr; -	u32 val; -	u32 bit = (on > 0) ? 1 : 0; - -	pci_read_config_dword(amd_smbus_dev, AB_REG_BAR, &addr); - -	/* BIT names/meanings are NDA-protected, sorry ... */ - -	outl(AX_INDXC, AB_INDX(addr)); -	outl(0x40, AB_DATA(addr)); -	outl(AX_DATAC, AB_INDX(addr)); -	val = inl(AB_DATA(addr)); -	val &= ~((1 << 3) | (1 << 4) | (1 << 9)); -	val |= (bit << 3) | ((!bit) << 4) | ((!bit) << 9); -	outl(val, AB_DATA(addr)); - -	if (amd_hb_dev) { -		addr = PCIE_P_CNTL; -		pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr); - -		pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val); -		val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12)); -		val |= bit | (bit << 3) | (bit << 12); -		val |= ((!bit) << 4) | ((!bit) << 9); -		pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val); - -		addr = BIF_NB; -		pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_ADDR, addr); - -		pci_read_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, &val); -		val &= ~(1 << 8); -		val |= bit << 8; -		pci_write_config_dword(amd_hb_dev, NB_PCIE_INDX_DATA, val); -	} -} - -static void amd_iso_dev_put(void) -{ -	amd_ohci_iso_count--; -	if (amd_ohci_iso_count == 0) { -		if (amd_smbus_dev) { -			pci_dev_put(amd_smbus_dev); -			amd_smbus_dev = NULL; -		} -		if (amd_hb_dev) { -			pci_dev_put(amd_hb_dev); -			amd_hb_dev = NULL; -		} -	} - -} -  static void sb800_prefetch(struct ohci_hcd *ohci, int on)  {  	struct pci_dev *pdev; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 83094d067e0..dd24fc115e4 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -52,7 +52,7 @@ __acquires(ohci->lock)  		ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;  		if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {  			if (quirk_amdiso(ohci)) -				quirk_amd_pll(1); +				usb_amd_quirk_pll_enable();  			if (quirk_amdprefetch(ohci))  				sb800_prefetch(ohci, 0);  		} @@ -686,7 +686,7 @@ static void td_submit_urb (  		}  		if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {  			if (quirk_amdiso(ohci)) -				quirk_amd_pll(0); +				usb_amd_quirk_pll_disable();  			if (quirk_amdprefetch(ohci))  				sb800_prefetch(ohci, 1);  		} diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 51facb985c8..bad11a72c20 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -401,7 +401,7 @@ struct ohci_hcd {  #define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */  #define	OHCI_QUIRK_FRAME_NO	0x80			/* no big endian frame_no shift */  #define	OHCI_QUIRK_HUB_POWER	0x100			/* distrust firmware power/oc setup */ -#define	OHCI_QUIRK_AMD_ISO	0x200			/* ISO transfers*/ +#define	OHCI_QUIRK_AMD_PLL	0x200			/* AMD PLL quirk*/  #define	OHCI_QUIRK_AMD_PREFETCH	0x400			/* pre-fetch for ISO transfer */  #define	OHCI_QUIRK_SHUTDOWN	0x800			/* nVidia power bug */  	// there are also chip quirks/bugs in init logic @@ -433,7 +433,7 @@ static inline int quirk_zfmicro(struct ohci_hcd *ohci)  }  static inline int quirk_amdiso(struct ohci_hcd *ohci)  { -	return ohci->flags & OHCI_QUIRK_AMD_ISO; +	return ohci->flags & OHCI_QUIRK_AMD_PLL;  }  static inline int quirk_amdprefetch(struct ohci_hcd *ohci)  { diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 4c502c890eb..1d586d4f7b5 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -52,6 +52,264 @@  #define EHCI_USBLEGCTLSTS	4		/* legacy control/status */  #define EHCI_USBLEGCTLSTS_SOOE	(1 << 13)	/* SMI on ownership change */ +/* AMD quirk use */ +#define	AB_REG_BAR_LOW		0xe0 +#define	AB_REG_BAR_HIGH		0xe1 +#define	AB_REG_BAR_SB700	0xf0 +#define	AB_INDX(addr)		((addr) + 0x00) +#define	AB_DATA(addr)		((addr) + 0x04) +#define	AX_INDXC		0x30 +#define	AX_DATAC		0x34 + +#define	NB_PCIE_INDX_ADDR	0xe0 +#define	NB_PCIE_INDX_DATA	0xe4 +#define	PCIE_P_CNTL		0x10040 +#define	BIF_NB			0x10002 +#define	NB_PIF0_PWRDOWN_0	0x01100012 +#define	NB_PIF0_PWRDOWN_1	0x01100013 + +static struct amd_chipset_info { +	struct pci_dev	*nb_dev; +	struct pci_dev	*smbus_dev; +	int nb_type; +	int sb_type; +	int isoc_reqs; +	int probe_count; +	int probe_result; +} amd_chipset; + +static DEFINE_SPINLOCK(amd_lock); + +int usb_amd_find_chipset_info(void) +{ +	u8 rev = 0; +	unsigned long flags; + +	spin_lock_irqsave(&amd_lock, flags); + +	amd_chipset.probe_count++; +	/* probe only once */ +	if (amd_chipset.probe_count > 1) { +		spin_unlock_irqrestore(&amd_lock, flags); +		return amd_chipset.probe_result; +	} + +	amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); +	if (amd_chipset.smbus_dev) { +		rev = amd_chipset.smbus_dev->revision; +		if (rev >= 0x40) +			amd_chipset.sb_type = 1; +		else if (rev >= 0x30 && rev <= 0x3b) +			amd_chipset.sb_type = 3; +	} else { +		amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, +							0x780b, NULL); +		if (!amd_chipset.smbus_dev) { +			spin_unlock_irqrestore(&amd_lock, flags); +			return 0; +		} +		rev = amd_chipset.smbus_dev->revision; +		if (rev >= 0x11 && rev <= 0x18) +			amd_chipset.sb_type = 2; +	} + +	if (amd_chipset.sb_type == 0) { +		if (amd_chipset.smbus_dev) { +			pci_dev_put(amd_chipset.smbus_dev); +			amd_chipset.smbus_dev = NULL; +		} +		spin_unlock_irqrestore(&amd_lock, flags); +		return 0; +	} + +	amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL); +	if (amd_chipset.nb_dev) { +		amd_chipset.nb_type = 1; +	} else { +		amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, +							0x1510, NULL); +		if (amd_chipset.nb_dev) { +			amd_chipset.nb_type = 2; +		} else  { +			amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, +								0x9600, NULL); +			if (amd_chipset.nb_dev) +				amd_chipset.nb_type = 3; +		} +	} + +	amd_chipset.probe_result = 1; +	printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n"); + +	spin_unlock_irqrestore(&amd_lock, flags); +	return amd_chipset.probe_result; +} +EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); + +/* + * The hardware normally enables the A-link power management feature, which + * lets the system lower the power consumption in idle states. + * + * This USB quirk prevents the link going into that lower power state + * during isochronous transfers. + * + * Without this quirk, isochronous stream on OHCI/EHCI/xHCI controllers of + * some AMD platforms may stutter or have breaks occasionally. + */ +static void usb_amd_quirk_pll(int disable) +{ +	u32 addr, addr_low, addr_high, val; +	u32 bit = disable ? 0 : 1; +	unsigned long flags; + +	spin_lock_irqsave(&amd_lock, flags); + +	if (disable) { +		amd_chipset.isoc_reqs++; +		if (amd_chipset.isoc_reqs > 1) { +			spin_unlock_irqrestore(&amd_lock, flags); +			return; +		} +	} else { +		amd_chipset.isoc_reqs--; +		if (amd_chipset.isoc_reqs > 0) { +			spin_unlock_irqrestore(&amd_lock, flags); +			return; +		} +	} + +	if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) { +		outb_p(AB_REG_BAR_LOW, 0xcd6); +		addr_low = inb_p(0xcd7); +		outb_p(AB_REG_BAR_HIGH, 0xcd6); +		addr_high = inb_p(0xcd7); +		addr = addr_high << 8 | addr_low; + +		outl_p(0x30, AB_INDX(addr)); +		outl_p(0x40, AB_DATA(addr)); +		outl_p(0x34, AB_INDX(addr)); +		val = inl_p(AB_DATA(addr)); +	} else if (amd_chipset.sb_type == 3) { +		pci_read_config_dword(amd_chipset.smbus_dev, +					AB_REG_BAR_SB700, &addr); +		outl(AX_INDXC, AB_INDX(addr)); +		outl(0x40, AB_DATA(addr)); +		outl(AX_DATAC, AB_INDX(addr)); +		val = inl(AB_DATA(addr)); +	} else { +		spin_unlock_irqrestore(&amd_lock, flags); +		return; +	} + +	if (disable) { +		val &= ~0x08; +		val |= (1 << 4) | (1 << 9); +	} else { +		val |= 0x08; +		val &= ~((1 << 4) | (1 << 9)); +	} +	outl_p(val, AB_DATA(addr)); + +	if (!amd_chipset.nb_dev) { +		spin_unlock_irqrestore(&amd_lock, flags); +		return; +	} + +	if (amd_chipset.nb_type == 1 || amd_chipset.nb_type == 3) { +		addr = PCIE_P_CNTL; +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_ADDR, addr); +		pci_read_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, &val); + +		val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12)); +		val |= bit | (bit << 3) | (bit << 12); +		val |= ((!bit) << 4) | ((!bit) << 9); +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, val); + +		addr = BIF_NB; +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_ADDR, addr); +		pci_read_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, &val); +		val &= ~(1 << 8); +		val |= bit << 8; + +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, val); +	} else if (amd_chipset.nb_type == 2) { +		addr = NB_PIF0_PWRDOWN_0; +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_ADDR, addr); +		pci_read_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, &val); +		if (disable) +			val &= ~(0x3f << 7); +		else +			val |= 0x3f << 7; + +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, val); + +		addr = NB_PIF0_PWRDOWN_1; +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_ADDR, addr); +		pci_read_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, &val); +		if (disable) +			val &= ~(0x3f << 7); +		else +			val |= 0x3f << 7; + +		pci_write_config_dword(amd_chipset.nb_dev, +					NB_PCIE_INDX_DATA, val); +	} + +	spin_unlock_irqrestore(&amd_lock, flags); +	return; +} + +void usb_amd_quirk_pll_disable(void) +{ +	usb_amd_quirk_pll(1); +} +EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable); + +void usb_amd_quirk_pll_enable(void) +{ +	usb_amd_quirk_pll(0); +} +EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable); + +void usb_amd_dev_put(void) +{ +	unsigned long flags; + +	spin_lock_irqsave(&amd_lock, flags); + +	amd_chipset.probe_count--; +	if (amd_chipset.probe_count > 0) { +		spin_unlock_irqrestore(&amd_lock, flags); +		return; +	} + +	if (amd_chipset.nb_dev) { +		pci_dev_put(amd_chipset.nb_dev); +		amd_chipset.nb_dev = NULL; +	} +	if (amd_chipset.smbus_dev) { +		pci_dev_put(amd_chipset.smbus_dev); +		amd_chipset.smbus_dev = NULL; +	} +	amd_chipset.nb_type = 0; +	amd_chipset.sb_type = 0; +	amd_chipset.isoc_reqs = 0; +	amd_chipset.probe_result = 0; + +	spin_unlock_irqrestore(&amd_lock, flags); +} +EXPORT_SYMBOL_GPL(usb_amd_dev_put);  /*   * Make sure the controller is completely inactive, unable to diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 1564edfff6f..6ae9f78e993 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -1,7 +1,17 @@  #ifndef __LINUX_USB_PCI_QUIRKS_H  #define __LINUX_USB_PCI_QUIRKS_H +#ifdef CONFIG_PCI  void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);  int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); +int usb_amd_find_chipset_info(void); +void usb_amd_dev_put(void); +void usb_amd_quirk_pll_disable(void); +void usb_amd_quirk_pll_enable(void); +#else +static inline void usb_amd_quirk_pll_disable(void) {} +static inline void usb_amd_quirk_pll_enable(void) {} +static inline void usb_amd_dev_put(void) {} +#endif  /* CONFIG_PCI */  #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */  |