diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-17 18:54:16 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-17 18:54:16 +0100 |
commit | 479b46b5599b1e610630d7332e168c1f9c4ee0b4 (patch) | |
tree | c5d7e48576f5b5b6a61a2a2e5f85abaa941b85ab /drivers/usb | |
parent | USB: gadget: f_fs: even zero-length packets require a buffer (diff) | |
download | linux-479b46b5599b1e610630d7332e168c1f9c4ee0b4.tar.xz linux-479b46b5599b1e610630d7332e168c1f9c4ee0b4.zip |
Revert "USB host: Move AMD PLL quirk to pci-quirks.c"
This reverts commit b7d5b439b7a40dd0a0202fe1c118615a3fcc3b25.
It conflicts with commit baab93afc2844b68d57b0dcca5e1d34c5d7cf411 "USB:
EHCI: ASPM quirk of ISOC on AMD Hudson" and merging the two just doesn't
work properly.
Cc: Andiry Xu <andiry.xu@amd.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alex He <alex.he@amd.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 38 | ||||
-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 | 260 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.h | 19 |
10 files changed, 222 insertions, 311 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 30515d362c4b..6fee3cd58efe 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -114,11 +114,13 @@ 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" /*-------------------------------------------------------------------------*/ @@ -530,8 +532,10 @@ static void ehci_stop (struct usb_hcd *hcd) spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); - if (ehci->amd_pll_fix == 1) - usb_amd_dev_put(); + if (amd_nb_dev) { + pci_dev_put(amd_nb_dev); + amd_nb_dev = NULL; + } #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 1ec8060e8cc4..76179c39c0e3 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -44,6 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) return 0; } +static int ehci_quirk_amd_SB800(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) + return 0; + + 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; + } + + if (!amd_nb_dev) + amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL); + if (!amd_nb_dev) + ehci_err(ehci, "QUIRK: unable to get AMD NB device\n"); + + ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\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) { @@ -102,6 +131,9 @@ 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_SB800(ehci)) + ehci->amd_l1_fix = 1; + retval = ehci_halt(ehci); if (retval) return retval; @@ -152,9 +184,6 @@ 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"); @@ -200,9 +229,6 @@ 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 1543c838b3d1..30fbdbe1cf1e 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1587,6 +1587,63 @@ 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 ( @@ -1615,8 +1672,8 @@ itd_link_urb ( } if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_disable(); + if (ehci->amd_l1_fix == 1) + ehci_quirk_amd_L1(ehci, 1); } ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; @@ -1744,8 +1801,8 @@ itd_complete ( ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_enable(); + if (ehci->amd_l1_fix == 1) + ehci_quirk_amd_L1(ehci, 0); } if (unlikely(list_is_singular(&stream->td_list))) { @@ -2035,8 +2092,8 @@ sitd_link_urb ( } if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_disable(); + if (ehci->amd_l1_fix == 1) + ehci_quirk_amd_L1(ehci, 1); } ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; @@ -2140,8 +2197,8 @@ sitd_complete ( ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_enable(); + if (ehci->amd_l1_fix == 1) + ehci_quirk_amd_L1(ehci, 0); } if (list_is_singular(&stream->td_list)) { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index f86d3fa20214..799ac16a54b4 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_pll_fix:1; + unsigned amd_l1_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 7b791bf1e7b4..759a12ff8048 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -75,7 +75,6 @@ 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); @@ -86,8 +85,18 @@ 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; @@ -903,7 +912,7 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_zfmicro(ohci)) del_timer(&ohci->unlink_watchdog); if (quirk_amdiso(ohci)) - usb_amd_dev_put(); + amd_iso_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 9816a2870d00..36ee9a666e93 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -22,6 +22,24 @@ #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) @@ -150,14 +168,11 @@ 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 (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) + amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); if (!amd_smbus_dev) return 0; @@ -169,8 +184,19 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) ohci_dbg(ohci, "enabled AMD prefetch quirk\n"); } - pci_dev_put(amd_smbus_dev); - amd_smbus_dev = NULL; + 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"); return 0; } @@ -189,6 +215,74 @@ 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 dd24fc115e48..83094d067e0f 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)) - usb_amd_quirk_pll_enable(); + quirk_amd_pll(1); 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)) - usb_amd_quirk_pll_disable(); + quirk_amd_pll(0); if (quirk_amdprefetch(ohci)) sb800_prefetch(ohci, 1); } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index bad11a72c202..51facb985c84 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_PLL 0x200 /* AMD PLL quirk*/ +#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/ #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_PLL; + return ohci->flags & OHCI_QUIRK_AMD_ISO; } 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 344b25a790e1..4c502c890ebd 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -52,266 +52,6 @@ #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) { - pci_read_config_byte(amd_chipset.smbus_dev, - PCI_REVISION_ID, &rev); - 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; - } - pci_read_config_byte(amd_chipset.smbus_dev, - PCI_REVISION_ID, &rev); - 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 4d2118cf1ff8..1564edfff6fe 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -1,26 +1,7 @@ #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) -{ - return; -} -static inline void usb_amd_quirk_pll_enable(void) -{ - return; -} -static inline void usb_amd_dev_put(void) -{ - return; -} -#endif /* CONFIG_PCI */ #endif /* __LINUX_USB_PCI_QUIRKS_H */ |