Re: [PATCH v3 1/2] USB host: Move AMD PLL quirk to pci-quirks.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux