diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 24 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 12 |
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 | ||