Re: [PATCH] EHCI: ASPM quirk of ISOC on AMD SB800

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

 



I don't see any reason to hold off on this,
so ACK.  Finding the northbridge is a bit
ugly, but there's likely no way around that.
Greg?)

--- On Mon, 12/6/10, Alex He <alex.he@xxxxxxx> wrote:

> From: Alex He <alex.he@xxxxxxx>
> Subject: [PATCH] EHCI: ASPM quirk of ISOC on AMD SB800
> To: dbrownell@xxxxxxxxxxxxxxxxxxxxx
> Cc: linux-usb@xxxxxxxxxxxxxxx, "Xu, Andiry" <Andiry.Xu@xxxxxxx>, gregkh@xxxxxxx
> Date: Monday, December 6, 2010, 6:10 PM
> When ASPM PM Feature is enabled on
> UMI link, devices that use ISOC stream of
> data transfer may be exposed to longer latency causing less
> than optimal per-
> formance of the device. The longer latencies are normal and
> are due to link
> wake time coming out of low power state which happens
> frequently to save
> power when the link is not active.
> The following code will make exception for certain features
> of ASPM to be by
> passed and keep the logic normal state only when the ISOC
> device is connected
> and active. This change will allow the device to run at
> optimal performance
> yet minimize the impact on overall power savings.
> 
> Signed-off-by: Alex He <alex.he@xxxxxxx>

Acked-by: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx>


> ---
>  drivers/usb/host/ehci-hcd.c   | 
>   8 ++++
> 
> drivers/usb/host/ehci-pci.c   |   32
> ++++++++++++++++
>  drivers/usb/host/ehci-sched.c |   79
> +++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/ehci.h   
>    |    1 +
>  4 files changed, 120 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/host/ehci-hcd.c
> b/drivers/usb/host/ehci-hcd.c
> index 13ead00..cae4695 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -103,6 +103,9 @@ MODULE_PARM_DESC (ignore_oc, "ignore
> bogus hardware overcurrent indications");
>  
>  #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"
> @@ -502,6 +505,11 @@ 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;
> +    }
> +
>  #ifdef    EHCI_STATS
>      ehci_dbg (ehci, "irq normal %ld err %ld
> reclaim %ld (lost %ld)\n",
>         
> ehci->stats.normal, ehci->stats.error,
> ehci->stats.reclaim,
> diff --git a/drivers/usb/host/ehci-pci.c
> b/drivers/usb/host/ehci-pci.c
> index ead5f4f..b2da9a2 100644
> --- a/drivers/usb/host/ehci-pci.c
> +++ b/drivers/usb/host/ehci-pci.c
> @@ -41,6 +41,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)
>  {
> @@ -99,6 +128,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;
> diff --git a/drivers/usb/host/ehci-sched.c
> b/drivers/usb/host/ehci-sched.c
> index 805ec63..f80c506 100644
> --- a/drivers/usb/host/ehci-sched.c
> +++ b/drivers/usb/host/ehci-sched.c
> @@ -1588,6 +1588,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,6 +1672,12 @@ itd_link_urb (
>             
> next_uframe >> 3, next_uframe & 0x7);
>          stream->start =
> jiffies;
>      }
> +
> +    if
> (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
> +        if
> (ehci->amd_l1_fix == 1)
> +           
> ehci_quirk_amd_L1(ehci, 1);
> +    }
> +
>     
> ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
>  
>      /* fill iTDs uframe by uframe */
> @@ -1741,6 +1804,11 @@ itd_complete (
>      (void) disable_periodic(ehci);
>     
> 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
> (unlikely(list_is_singular(&stream->td_list))) {
>         
> ehci_to_hcd(ehci)->self.bandwidth_allocated
>             
>     -= stream->bandwidth;
> @@ -2028,6 +2096,12 @@ sitd_link_urb (
>             
> stream->interval, hc32_to_cpu(ehci, stream->splits));
>          stream->start =
> jiffies;
>      }
> +
> +    if
> (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
> +        if
> (ehci->amd_l1_fix == 1)
> +           
> ehci_quirk_amd_L1(ehci, 1);
> +    }
> +
>     
> ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
>  
>      /* fill sITDs frame by frame */
> @@ -2130,6 +2204,11 @@ sitd_complete (
>      (void) disable_periodic(ehci);
>     
> 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
> (list_is_singular(&stream->td_list)) {
>         
> ehci_to_hcd(ehci)->self.bandwidth_allocated
>             
>     -= stream->bandwidth;
> diff --git a/drivers/usb/host/ehci.h
> b/drivers/usb/host/ehci.h
> index 4ebe9ad..2649925 100644
> --- a/drivers/usb/host/ehci.h
> +++ b/drivers/usb/host/ehci.h
> @@ -130,6 +130,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;
>  
>      /* required for usb32 quirk */
>      #define OHCI_CTRL_HCFS   
>       (3 << 6)
> -- 
> 1.7.0.4
> 
> 
> 
> 
--
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