On Wed, 19 Jan 2011, Andiry Xu wrote: > This patch moves the AMD PLL quirk code in OHCI/EHCI driver to pci-quirks.c, > and exports the functions to be used by xHCI driver later. > > AMD PLL quirk disable the optional PM feature inside specific > SB700/SB800/Hudson-2/3 platforms under the following conditions: > > 1. If an isochronous device is connected to OHCI/EHCI/xHCI port and is active; > 2. Optional PM feature that powers down the internal Bus PLL when the link is > in low power state is enabled. > > Without AMD PLL quirk, USB isochronous stream may stutter or have breaks > occasionally, which greatly impair the performance of audio/video streams. > > Currently AMD PLL quirk is implemented in OHCI and EHCI driver, and will be > added to xHCI driver too. They are doing similar things actually, so move > the quirk code to pci-quirks.c, which has several advantages: > > 1. Remove repeat defines and functions in OHCI/EHCI (and xHCI) driver and > make them cleaner; > 2. AMD chipset information will be probed only once and then stored. > Currently they're probed during every OHCI/EHCI initialization, move > the detect code to pci-quirks.c saves the repeat detect cost; > 3. Build up synchronization among OHCI/EHCI/xHCI driver. In current > code, every host controller enable/disable PLL only according to > its own status, and may enable PLL while there is still isoc transfer on > other HCs. Move the quirk to pci-quirks.c prevents this issue. ... > +/* > + * 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. > + */ > +void usb_amd_quirk_pll_disable(void) > +{ > + u32 addr, addr_low, addr_high, val; > + unsigned long flags; > + > + spin_lock_irqsave(&amd_lock, flags); > + > + amd_chipset.isoc_reqs++; > + if (amd_chipset.isoc_reqs > 1) { > + 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; > + } > + > + 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 << 12)); > + val |= (1 << 4) | (1 << 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); > + > + 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); > + 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); > + val &= ~(0x3f << 7); > + > + pci_write_config_dword(amd_chipset.nb_dev, > + NB_PCIE_INDX_DATA, val); > + } > + > + spin_unlock_irqrestore(&amd_lock, flags); > + return; > +} > +EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable); > + > +void usb_amd_quirk_pll_enable(void) > +{ > + u32 addr, addr_low, addr_high, val; > + unsigned long flags; > + > + spin_lock_irqsave(&amd_lock, flags); > + > + 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; > + } > + > + 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 << 4) | (1 << 9)); > + val |= (1 << 0) | (1 << 3) | (1 << 12); > + > + 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; > + > + 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); > + 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); > + val |= 0x3f << 7; > + > + pci_write_config_dword(amd_chipset.nb_dev, > + NB_PCIE_INDX_DATA, val); > + } > + > + spin_unlock_irqrestore(&amd_lock, flags); > + return; > +} > +EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable); Good grief! Don't duplicate so much code! Just have usb_amd_quirk_pll_disable() and usb_amd_quirk_pll_enable() call a common function to do the hard work. You could even write usb_amd_quirk_pll_disable() and usb_amd_quirk_pll_enable() as inlines, passing a 0 or 1 respectively to the common function. Alan Stern -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html