aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-pci.c24
-rw-r--r--drivers/usb/host/ehci.h12
2 files changed, 29 insertions, 7 deletions
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index c46a58f9181d..36864f958444 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -66,6 +66,8 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
66{ 66{
67 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 67 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
68 struct pci_dev *pdev = to_pci_dev(hcd->self.controller); 68 struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
69 struct pci_dev *p_smbus;
70 u8 rev;
69 u32 temp; 71 u32 temp;
70 int retval; 72 int retval;
71 73
@@ -166,6 +168,28 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
166 pci_write_config_byte(pdev, 0x4b, tmp | 0x20); 168 pci_write_config_byte(pdev, 0x4b, tmp | 0x20);
167 } 169 }
168 break; 170 break;
171 case PCI_VENDOR_ID_ATI:
172 /* SB600 and old version of SB700 have a bug in EHCI controller,
173 * which causes usb devices lose response in some cases.
174 */
175 if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) {
176 p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
177 PCI_DEVICE_ID_ATI_SBX00_SMBUS,
178 NULL);
179 if (!p_smbus)
180 break;
181 rev = p_smbus->revision;
182 if ((pdev->device == 0x4386) || (rev == 0x3a)
183 || (rev == 0x3b)) {
184 u8 tmp;
185 ehci_info(ehci, "applying AMD SB600/SB700 USB "
186 "freeze workaround\n");
187 pci_read_config_byte(pdev, 0x53, &tmp);
188 pci_write_config_byte(pdev, 0x53, tmp | (1<<3));
189 }
190 pci_dev_put(p_smbus);
191 }
192 break;
169 } 193 }
170 194
171 ehci_reset(ehci); 195 ehci_reset(ehci);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index b11798d17ae5..c7d4b5a06bdb 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -183,16 +183,14 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
183 * the async ring; just the I/O watchdog. Note that if a 183 * the async ring; just the I/O watchdog. Note that if a
184 * SHRINK were pending, OFF would never be requested. 184 * SHRINK were pending, OFF would never be requested.
185 */ 185 */
186 enum ehci_timer_action oldactions = ehci->actions; 186 if (timer_pending(&ehci->watchdog)
187 && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
188 & ehci->actions))
189 return;
187 190
188 if (!test_and_set_bit (action, &ehci->actions)) { 191 if (!test_and_set_bit (action, &ehci->actions)) {
189 unsigned long t; 192 unsigned long t;
190 193
191 if (timer_pending(&ehci->watchdog)
192 && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
193 & oldactions))
194 return;
195
196 switch (action) { 194 switch (action) {
197 case TIMER_IO_WATCHDOG: 195 case TIMER_IO_WATCHDOG:
198 t = EHCI_IO_JIFFIES; 196 t = EHCI_IO_JIFFIES;
@@ -208,7 +206,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
208 t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1; 206 t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
209 break; 207 break;
210 } 208 }
211 mod_timer(&ehci->watchdog, round_jiffies(t + jiffies)); 209 mod_timer(&ehci->watchdog, t + jiffies);
212 } 210 }
213} 211}
214 212