diff options
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 32 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 79 | ||||
-rw-r--r-- | 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 abe8336ebffa..6778fbcf2416 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -114,6 +114,9 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n"); | |||
114 | 114 | ||
115 | #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) | 115 | #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) |
116 | 116 | ||
117 | /* for ASPM quirk of ISOC on AMD SB800 */ | ||
118 | static struct pci_dev *amd_nb_dev; | ||
119 | |||
117 | /*-------------------------------------------------------------------------*/ | 120 | /*-------------------------------------------------------------------------*/ |
118 | 121 | ||
119 | #include "ehci.h" | 122 | #include "ehci.h" |
@@ -529,6 +532,11 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
529 | spin_unlock_irq (&ehci->lock); | 532 | spin_unlock_irq (&ehci->lock); |
530 | ehci_mem_cleanup (ehci); | 533 | ehci_mem_cleanup (ehci); |
531 | 534 | ||
535 | if (amd_nb_dev) { | ||
536 | pci_dev_put(amd_nb_dev); | ||
537 | amd_nb_dev = NULL; | ||
538 | } | ||
539 | |||
532 | #ifdef EHCI_STATS | 540 | #ifdef EHCI_STATS |
533 | ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", | 541 | ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", |
534 | ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, | 542 | 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 56c78e93440f..35a533e4c01d 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) | |||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | static int ehci_quirk_amd_SB800(struct ehci_hcd *ehci) | ||
48 | { | ||
49 | struct pci_dev *amd_smbus_dev; | ||
50 | u8 rev = 0; | ||
51 | |||
52 | amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); | ||
53 | if (!amd_smbus_dev) | ||
54 | return 0; | ||
55 | |||
56 | pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); | ||
57 | if (rev < 0x40) { | ||
58 | pci_dev_put(amd_smbus_dev); | ||
59 | amd_smbus_dev = NULL; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | if (!amd_nb_dev) | ||
64 | amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL); | ||
65 | if (!amd_nb_dev) | ||
66 | ehci_err(ehci, "QUIRK: unable to get AMD NB device\n"); | ||
67 | |||
68 | ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n"); | ||
69 | |||
70 | pci_dev_put(amd_smbus_dev); | ||
71 | amd_smbus_dev = NULL; | ||
72 | |||
73 | return 1; | ||
74 | } | ||
75 | |||
47 | /* called during probe() after chip reset completes */ | 76 | /* called during probe() after chip reset completes */ |
48 | static int ehci_pci_setup(struct usb_hcd *hcd) | 77 | static int ehci_pci_setup(struct usb_hcd *hcd) |
49 | { | 78 | { |
@@ -102,6 +131,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
102 | /* cache this readonly data; minimize chip reads */ | 131 | /* cache this readonly data; minimize chip reads */ |
103 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); | 132 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
104 | 133 | ||
134 | if (ehci_quirk_amd_SB800(ehci)) | ||
135 | ehci->amd_l1_fix = 1; | ||
136 | |||
105 | retval = ehci_halt(ehci); | 137 | retval = ehci_halt(ehci); |
106 | if (retval) | 138 | if (retval) |
107 | return retval; | 139 | return retval; |
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a92526d6e5ae..724ba7133c4f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -1583,6 +1583,63 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) | |||
1583 | *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); | 1583 | *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); |
1584 | } | 1584 | } |
1585 | 1585 | ||
1586 | #define AB_REG_BAR_LOW 0xe0 | ||
1587 | #define AB_REG_BAR_HIGH 0xe1 | ||
1588 | #define AB_INDX(addr) ((addr) + 0x00) | ||
1589 | #define AB_DATA(addr) ((addr) + 0x04) | ||
1590 | #define NB_PCIE_INDX_ADDR 0xe0 | ||
1591 | #define NB_PCIE_INDX_DATA 0xe4 | ||
1592 | #define NB_PIF0_PWRDOWN_0 0x01100012 | ||
1593 | #define NB_PIF0_PWRDOWN_1 0x01100013 | ||
1594 | |||
1595 | static void ehci_quirk_amd_L1(struct ehci_hcd *ehci, int disable) | ||
1596 | { | ||
1597 | u32 addr, addr_low, addr_high, val; | ||
1598 | |||
1599 | outb_p(AB_REG_BAR_LOW, 0xcd6); | ||
1600 | addr_low = inb_p(0xcd7); | ||
1601 | outb_p(AB_REG_BAR_HIGH, 0xcd6); | ||
1602 | addr_high = inb_p(0xcd7); | ||
1603 | addr = addr_high << 8 | addr_low; | ||
1604 | outl_p(0x30, AB_INDX(addr)); | ||
1605 | outl_p(0x40, AB_DATA(addr)); | ||
1606 | outl_p(0x34, AB_INDX(addr)); | ||
1607 | val = inl_p(AB_DATA(addr)); | ||
1608 | |||
1609 | if (disable) { | ||
1610 | val &= ~0x8; | ||
1611 | val |= (1 << 4) | (1 << 9); | ||
1612 | } else { | ||
1613 | val |= 0x8; | ||
1614 | val &= ~((1 << 4) | (1 << 9)); | ||
1615 | } | ||
1616 | outl_p(val, AB_DATA(addr)); | ||
1617 | |||
1618 | if (amd_nb_dev) { | ||
1619 | addr = NB_PIF0_PWRDOWN_0; | ||
1620 | pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr); | ||
1621 | pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val); | ||
1622 | if (disable) | ||
1623 | val &= ~(0x3f << 7); | ||
1624 | else | ||
1625 | val |= 0x3f << 7; | ||
1626 | |||
1627 | pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val); | ||
1628 | |||
1629 | addr = NB_PIF0_PWRDOWN_1; | ||
1630 | pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_ADDR, addr); | ||
1631 | pci_read_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, &val); | ||
1632 | if (disable) | ||
1633 | val &= ~(0x3f << 7); | ||
1634 | else | ||
1635 | val |= 0x3f << 7; | ||
1636 | |||
1637 | pci_write_config_dword(amd_nb_dev, NB_PCIE_INDX_DATA, val); | ||
1638 | } | ||
1639 | |||
1640 | return; | ||
1641 | } | ||
1642 | |||
1586 | /* fit urb's itds into the selected schedule slot; activate as needed */ | 1643 | /* fit urb's itds into the selected schedule slot; activate as needed */ |
1587 | static int | 1644 | static int |
1588 | itd_link_urb ( | 1645 | itd_link_urb ( |
@@ -1609,6 +1666,12 @@ itd_link_urb ( | |||
1609 | urb->interval, | 1666 | urb->interval, |
1610 | next_uframe >> 3, next_uframe & 0x7); | 1667 | next_uframe >> 3, next_uframe & 0x7); |
1611 | } | 1668 | } |
1669 | |||
1670 | if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { | ||
1671 | if (ehci->amd_l1_fix == 1) | ||
1672 | ehci_quirk_amd_L1(ehci, 1); | ||
1673 | } | ||
1674 | |||
1612 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; | 1675 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; |
1613 | 1676 | ||
1614 | /* fill iTDs uframe by uframe */ | 1677 | /* fill iTDs uframe by uframe */ |
@@ -1733,6 +1796,11 @@ itd_complete ( | |||
1733 | (void) disable_periodic(ehci); | 1796 | (void) disable_periodic(ehci); |
1734 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; | 1797 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; |
1735 | 1798 | ||
1799 | if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { | ||
1800 | if (ehci->amd_l1_fix == 1) | ||
1801 | ehci_quirk_amd_L1(ehci, 0); | ||
1802 | } | ||
1803 | |||
1736 | if (unlikely(list_is_singular(&stream->td_list))) { | 1804 | if (unlikely(list_is_singular(&stream->td_list))) { |
1737 | ehci_to_hcd(ehci)->self.bandwidth_allocated | 1805 | ehci_to_hcd(ehci)->self.bandwidth_allocated |
1738 | -= stream->bandwidth; | 1806 | -= stream->bandwidth; |
@@ -2018,6 +2086,12 @@ sitd_link_urb ( | |||
2018 | (next_uframe >> 3) & (ehci->periodic_size - 1), | 2086 | (next_uframe >> 3) & (ehci->periodic_size - 1), |
2019 | stream->interval, hc32_to_cpu(ehci, stream->splits)); | 2087 | stream->interval, hc32_to_cpu(ehci, stream->splits)); |
2020 | } | 2088 | } |
2089 | |||
2090 | if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { | ||
2091 | if (ehci->amd_l1_fix == 1) | ||
2092 | ehci_quirk_amd_L1(ehci, 1); | ||
2093 | } | ||
2094 | |||
2021 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; | 2095 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; |
2022 | 2096 | ||
2023 | /* fill sITDs frame by frame */ | 2097 | /* fill sITDs frame by frame */ |
@@ -2118,6 +2192,11 @@ sitd_complete ( | |||
2118 | (void) disable_periodic(ehci); | 2192 | (void) disable_periodic(ehci); |
2119 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; | 2193 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; |
2120 | 2194 | ||
2195 | if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { | ||
2196 | if (ehci->amd_l1_fix == 1) | ||
2197 | ehci_quirk_amd_L1(ehci, 0); | ||
2198 | } | ||
2199 | |||
2121 | if (list_is_singular(&stream->td_list)) { | 2200 | if (list_is_singular(&stream->td_list)) { |
2122 | ehci_to_hcd(ehci)->self.bandwidth_allocated | 2201 | ehci_to_hcd(ehci)->self.bandwidth_allocated |
2123 | -= stream->bandwidth; | 2202 | -= stream->bandwidth; |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bde823f704e9..fd1c53da89e4 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -130,6 +130,7 @@ struct ehci_hcd { /* one per controller */ | |||
130 | unsigned has_amcc_usb23:1; | 130 | unsigned has_amcc_usb23:1; |
131 | unsigned need_io_watchdog:1; | 131 | unsigned need_io_watchdog:1; |
132 | unsigned broken_periodic:1; | 132 | unsigned broken_periodic:1; |
133 | unsigned amd_l1_fix:1; | ||
133 | unsigned fs_i_thresh:1; /* Intel iso scheduling */ | 134 | unsigned fs_i_thresh:1; /* Intel iso scheduling */ |
134 | 135 | ||
135 | /* required for usb32 quirk */ | 136 | /* required for usb32 quirk */ |