diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/atm/cxacru.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/hcd.h | 7 | ||||
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 46 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 24 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 24 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 27 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 6 |
11 files changed, 147 insertions, 32 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 79861ee12a29..9d59dc62e6d2 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c | |||
@@ -787,6 +787,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { | |||
787 | { /* V = Conexant P = ADSL modem (Hasbani project) */ | 787 | { /* V = Conexant P = ADSL modem (Hasbani project) */ |
788 | USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00 | 788 | USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00 |
789 | }, | 789 | }, |
790 | { /* V = Conexant P = ADSL modem (Well PTI-800 */ | ||
791 | USB_DEVICE(0x0572, 0xcb02), .driver_info = (unsigned long) &cxacru_cb00 | ||
792 | }, | ||
790 | { /* V = Conexant P = ADSL modem */ | 793 | { /* V = Conexant P = ADSL modem */ |
791 | USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 | 794 | USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 |
792 | }, | 795 | }, |
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5131d88e8c5b..29b5b2a6e183 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c | |||
@@ -219,6 +219,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) | |||
219 | goto done; | 219 | goto done; |
220 | } | 220 | } |
221 | } | 221 | } |
222 | synchronize_irq(dev->irq); | ||
222 | 223 | ||
223 | /* FIXME until the generic PM interfaces change a lot more, this | 224 | /* FIXME until the generic PM interfaces change a lot more, this |
224 | * can't use PCI D1 and D2 states. For example, the confusion | 225 | * can't use PCI D1 and D2 states. For example, the confusion |
@@ -392,7 +393,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) | |||
392 | 393 | ||
393 | dev->dev.power.power_state = PMSG_ON; | 394 | dev->dev.power.power_state = PMSG_ON; |
394 | 395 | ||
395 | hcd->saw_irq = 0; | 396 | clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); |
396 | 397 | ||
397 | if (hcd->driver->resume) { | 398 | if (hcd->driver->resume) { |
398 | retval = hcd->driver->resume(hcd); | 399 | retval = hcd->driver->resume(hcd); |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 5e5f65a475ab..da24c31ee00d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1315,11 +1315,12 @@ static int hcd_unlink_urb (struct urb *urb, int status) | |||
1315 | * finish unlinking the initial failed usb_set_address() | 1315 | * finish unlinking the initial failed usb_set_address() |
1316 | * or device descriptor fetch. | 1316 | * or device descriptor fetch. |
1317 | */ | 1317 | */ |
1318 | if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) { | 1318 | if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) |
1319 | && hcd->self.root_hub != urb->dev) { | ||
1319 | dev_warn (hcd->self.controller, "Unlink after no-IRQ? " | 1320 | dev_warn (hcd->self.controller, "Unlink after no-IRQ? " |
1320 | "Controller is probably using the wrong IRQ." | 1321 | "Controller is probably using the wrong IRQ." |
1321 | "\n"); | 1322 | "\n"); |
1322 | hcd->saw_irq = 1; | 1323 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); |
1323 | } | 1324 | } |
1324 | 1325 | ||
1325 | urb->status = status; | 1326 | urb->status = status; |
@@ -1649,13 +1650,15 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) | |||
1649 | struct usb_hcd *hcd = __hcd; | 1650 | struct usb_hcd *hcd = __hcd; |
1650 | int start = hcd->state; | 1651 | int start = hcd->state; |
1651 | 1652 | ||
1652 | if (start == HC_STATE_HALT) | 1653 | if (unlikely(start == HC_STATE_HALT || |
1654 | !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) | ||
1653 | return IRQ_NONE; | 1655 | return IRQ_NONE; |
1654 | if (hcd->driver->irq (hcd, r) == IRQ_NONE) | 1656 | if (hcd->driver->irq (hcd, r) == IRQ_NONE) |
1655 | return IRQ_NONE; | 1657 | return IRQ_NONE; |
1656 | 1658 | ||
1657 | hcd->saw_irq = 1; | 1659 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); |
1658 | if (hcd->state == HC_STATE_HALT) | 1660 | |
1661 | if (unlikely(hcd->state == HC_STATE_HALT)) | ||
1659 | usb_hc_died (hcd); | 1662 | usb_hc_died (hcd); |
1660 | return IRQ_HANDLED; | 1663 | return IRQ_HANDLED; |
1661 | } | 1664 | } |
@@ -1768,6 +1771,8 @@ int usb_add_hcd(struct usb_hcd *hcd, | |||
1768 | 1771 | ||
1769 | dev_info(hcd->self.controller, "%s\n", hcd->product_desc); | 1772 | dev_info(hcd->self.controller, "%s\n", hcd->product_desc); |
1770 | 1773 | ||
1774 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
1775 | |||
1771 | /* till now HC has been in an indeterminate state ... */ | 1776 | /* till now HC has been in an indeterminate state ... */ |
1772 | if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { | 1777 | if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { |
1773 | dev_err(hcd->self.controller, "can't reset\n"); | 1778 | dev_err(hcd->self.controller, "can't reset\n"); |
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 24a62a2ff86d..c8a1b350e2cf 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h | |||
@@ -72,7 +72,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ | |||
72 | * hardware info/state | 72 | * hardware info/state |
73 | */ | 73 | */ |
74 | const struct hc_driver *driver; /* hw-specific hooks */ | 74 | const struct hc_driver *driver; /* hw-specific hooks */ |
75 | unsigned saw_irq : 1; | 75 | |
76 | /* Flags that need to be manipulated atomically */ | ||
77 | unsigned long flags; | ||
78 | #define HCD_FLAG_HW_ACCESSIBLE 0x00000001 | ||
79 | #define HCD_FLAG_SAW_IRQ 0x00000002 | ||
80 | |||
76 | unsigned can_wakeup:1; /* hw supports wakeup? */ | 81 | unsigned can_wakeup:1; /* hw supports wakeup? */ |
77 | unsigned remote_wakeup:1;/* sw should use wakeup? */ | 82 | unsigned remote_wakeup:1;/* sw should use wakeup? */ |
78 | unsigned rh_registered:1;/* is root hub registered? */ | 83 | unsigned rh_registered:1;/* is root hub registered? */ |
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 441c26064b44..13f73a836e45 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
@@ -121,8 +121,8 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) | |||
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
123 | 123 | ||
124 | /* called by khubd or root hub (re)init threads; leaves HC in halt state */ | 124 | /* called during probe() after chip reset completes */ |
125 | static int ehci_pci_reset(struct usb_hcd *hcd) | 125 | static int ehci_pci_setup(struct usb_hcd *hcd) |
126 | { | 126 | { |
127 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 127 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
128 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | 128 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); |
@@ -141,6 +141,11 @@ static int ehci_pci_reset(struct usb_hcd *hcd) | |||
141 | if (retval) | 141 | if (retval) |
142 | return retval; | 142 | return retval; |
143 | 143 | ||
144 | /* data structure init */ | ||
145 | retval = ehci_init(hcd); | ||
146 | if (retval) | ||
147 | return retval; | ||
148 | |||
144 | /* NOTE: only the parts below this line are PCI-specific */ | 149 | /* NOTE: only the parts below this line are PCI-specific */ |
145 | 150 | ||
146 | switch (pdev->vendor) { | 151 | switch (pdev->vendor) { |
@@ -154,7 +159,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd) | |||
154 | /* AMD8111 EHCI doesn't work, according to AMD errata */ | 159 | /* AMD8111 EHCI doesn't work, according to AMD errata */ |
155 | if (pdev->device == 0x7463) { | 160 | if (pdev->device == 0x7463) { |
156 | ehci_info(ehci, "ignoring AMD8111 (errata)\n"); | 161 | ehci_info(ehci, "ignoring AMD8111 (errata)\n"); |
157 | return -EIO; | 162 | retval = -EIO; |
163 | goto done; | ||
158 | } | 164 | } |
159 | break; | 165 | break; |
160 | case PCI_VENDOR_ID_NVIDIA: | 166 | case PCI_VENDOR_ID_NVIDIA: |
@@ -207,9 +213,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd) | |||
207 | /* REVISIT: per-port wake capability (PCI 0x62) currently unused */ | 213 | /* REVISIT: per-port wake capability (PCI 0x62) currently unused */ |
208 | 214 | ||
209 | retval = ehci_pci_reinit(ehci, pdev); | 215 | retval = ehci_pci_reinit(ehci, pdev); |
210 | 216 | done: | |
211 | /* finish init */ | 217 | return retval; |
212 | return ehci_init(hcd); | ||
213 | } | 218 | } |
214 | 219 | ||
215 | /*-------------------------------------------------------------------------*/ | 220 | /*-------------------------------------------------------------------------*/ |
@@ -228,14 +233,36 @@ static int ehci_pci_reset(struct usb_hcd *hcd) | |||
228 | static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) | 233 | static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) |
229 | { | 234 | { |
230 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 235 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
236 | unsigned long flags; | ||
237 | int rc = 0; | ||
231 | 238 | ||
232 | if (time_before(jiffies, ehci->next_statechange)) | 239 | if (time_before(jiffies, ehci->next_statechange)) |
233 | msleep(10); | 240 | msleep(10); |
234 | 241 | ||
242 | /* Root hub was already suspended. Disable irq emission and | ||
243 | * mark HW unaccessible, bail out if RH has been resumed. Use | ||
244 | * the spinlock to properly synchronize with possible pending | ||
245 | * RH suspend or resume activity. | ||
246 | * | ||
247 | * This is still racy as hcd->state is manipulated outside of | ||
248 | * any locks =P But that will be a different fix. | ||
249 | */ | ||
250 | spin_lock_irqsave (&ehci->lock, flags); | ||
251 | if (hcd->state != HC_STATE_SUSPENDED) { | ||
252 | rc = -EINVAL; | ||
253 | goto bail; | ||
254 | } | ||
255 | writel (0, &ehci->regs->intr_enable); | ||
256 | (void)readl(&ehci->regs->intr_enable); | ||
257 | |||
258 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
259 | bail: | ||
260 | spin_unlock_irqrestore (&ehci->lock, flags); | ||
261 | |||
235 | // could save FLADJ in case of Vaux power loss | 262 | // could save FLADJ in case of Vaux power loss |
236 | // ... we'd only use it to handle clock skew | 263 | // ... we'd only use it to handle clock skew |
237 | 264 | ||
238 | return 0; | 265 | return rc; |
239 | } | 266 | } |
240 | 267 | ||
241 | static int ehci_pci_resume(struct usb_hcd *hcd) | 268 | static int ehci_pci_resume(struct usb_hcd *hcd) |
@@ -251,6 +278,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd) | |||
251 | if (time_before(jiffies, ehci->next_statechange)) | 278 | if (time_before(jiffies, ehci->next_statechange)) |
252 | msleep(100); | 279 | msleep(100); |
253 | 280 | ||
281 | /* Mark hardware accessible again as we are out of D3 state by now */ | ||
282 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
283 | |||
254 | /* If CF is clear, we lost PCI Vaux power and need to restart. */ | 284 | /* If CF is clear, we lost PCI Vaux power and need to restart. */ |
255 | if (readl(&ehci->regs->configured_flag) != FLAG_CF) | 285 | if (readl(&ehci->regs->configured_flag) != FLAG_CF) |
256 | goto restart; | 286 | goto restart; |
@@ -319,7 +349,7 @@ static const struct hc_driver ehci_pci_hc_driver = { | |||
319 | /* | 349 | /* |
320 | * basic lifecycle operations | 350 | * basic lifecycle operations |
321 | */ | 351 | */ |
322 | .reset = ehci_pci_reset, | 352 | .reset = ehci_pci_setup, |
323 | .start = ehci_run, | 353 | .start = ehci_run, |
324 | #ifdef CONFIG_PM | 354 | #ifdef CONFIG_PM |
325 | .suspend = ehci_pci_suspend, | 355 | .suspend = ehci_pci_suspend, |
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5bb872c3496d..bf03ec0d8ee2 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -912,6 +912,7 @@ submit_async ( | |||
912 | int epnum; | 912 | int epnum; |
913 | unsigned long flags; | 913 | unsigned long flags; |
914 | struct ehci_qh *qh = NULL; | 914 | struct ehci_qh *qh = NULL; |
915 | int rc = 0; | ||
915 | 916 | ||
916 | qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); | 917 | qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); |
917 | epnum = ep->desc.bEndpointAddress; | 918 | epnum = ep->desc.bEndpointAddress; |
@@ -926,21 +927,28 @@ submit_async ( | |||
926 | #endif | 927 | #endif |
927 | 928 | ||
928 | spin_lock_irqsave (&ehci->lock, flags); | 929 | spin_lock_irqsave (&ehci->lock, flags); |
930 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, | ||
931 | &ehci_to_hcd(ehci)->flags))) { | ||
932 | rc = -ESHUTDOWN; | ||
933 | goto done; | ||
934 | } | ||
935 | |||
929 | qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); | 936 | qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); |
937 | if (unlikely(qh == NULL)) { | ||
938 | rc = -ENOMEM; | ||
939 | goto done; | ||
940 | } | ||
930 | 941 | ||
931 | /* Control/bulk operations through TTs don't need scheduling, | 942 | /* Control/bulk operations through TTs don't need scheduling, |
932 | * the HC and TT handle it when the TT has a buffer ready. | 943 | * the HC and TT handle it when the TT has a buffer ready. |
933 | */ | 944 | */ |
934 | if (likely (qh != NULL)) { | 945 | if (likely (qh->qh_state == QH_STATE_IDLE)) |
935 | if (likely (qh->qh_state == QH_STATE_IDLE)) | 946 | qh_link_async (ehci, qh_get (qh)); |
936 | qh_link_async (ehci, qh_get (qh)); | 947 | done: |
937 | } | ||
938 | spin_unlock_irqrestore (&ehci->lock, flags); | 948 | spin_unlock_irqrestore (&ehci->lock, flags); |
939 | if (unlikely (qh == NULL)) { | 949 | if (unlikely (qh == NULL)) |
940 | qtd_list_free (ehci, urb, qtd_list); | 950 | qtd_list_free (ehci, urb, qtd_list); |
941 | return -ENOMEM; | 951 | return rc; |
942 | } | ||
943 | return 0; | ||
944 | } | 952 | } |
945 | 953 | ||
946 | /*-------------------------------------------------------------------------*/ | 954 | /*-------------------------------------------------------------------------*/ |
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index f0c8aa1ccd5d..57e77374d228 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -602,6 +602,12 @@ static int intr_submit ( | |||
602 | 602 | ||
603 | spin_lock_irqsave (&ehci->lock, flags); | 603 | spin_lock_irqsave (&ehci->lock, flags); |
604 | 604 | ||
605 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, | ||
606 | &ehci_to_hcd(ehci)->flags))) { | ||
607 | status = -ESHUTDOWN; | ||
608 | goto done; | ||
609 | } | ||
610 | |||
605 | /* get qh and force any scheduling errors */ | 611 | /* get qh and force any scheduling errors */ |
606 | INIT_LIST_HEAD (&empty); | 612 | INIT_LIST_HEAD (&empty); |
607 | qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); | 613 | qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); |
@@ -1456,7 +1462,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, | |||
1456 | 1462 | ||
1457 | /* schedule ... need to lock */ | 1463 | /* schedule ... need to lock */ |
1458 | spin_lock_irqsave (&ehci->lock, flags); | 1464 | spin_lock_irqsave (&ehci->lock, flags); |
1459 | status = iso_stream_schedule (ehci, urb, stream); | 1465 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, |
1466 | &ehci_to_hcd(ehci)->flags))) | ||
1467 | status = -ESHUTDOWN; | ||
1468 | else | ||
1469 | status = iso_stream_schedule (ehci, urb, stream); | ||
1460 | if (likely (status == 0)) | 1470 | if (likely (status == 0)) |
1461 | itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); | 1471 | itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); |
1462 | spin_unlock_irqrestore (&ehci->lock, flags); | 1472 | spin_unlock_irqrestore (&ehci->lock, flags); |
@@ -1815,7 +1825,11 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, | |||
1815 | 1825 | ||
1816 | /* schedule ... need to lock */ | 1826 | /* schedule ... need to lock */ |
1817 | spin_lock_irqsave (&ehci->lock, flags); | 1827 | spin_lock_irqsave (&ehci->lock, flags); |
1818 | status = iso_stream_schedule (ehci, urb, stream); | 1828 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, |
1829 | &ehci_to_hcd(ehci)->flags))) | ||
1830 | status = -ESHUTDOWN; | ||
1831 | else | ||
1832 | status = iso_stream_schedule (ehci, urb, stream); | ||
1819 | if (status == 0) | 1833 | if (status == 0) |
1820 | sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); | 1834 | sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); |
1821 | spin_unlock_irqrestore (&ehci->lock, flags); | 1835 | spin_unlock_irqrestore (&ehci->lock, flags); |
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 5c0c6c8a7a82..bf1d9abc07ac 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -115,7 +115,7 @@ | |||
115 | 115 | ||
116 | /*-------------------------------------------------------------------------*/ | 116 | /*-------------------------------------------------------------------------*/ |
117 | 117 | ||
118 | // #define OHCI_VERBOSE_DEBUG /* not always helpful */ | 118 | #undef OHCI_VERBOSE_DEBUG /* not always helpful */ |
119 | 119 | ||
120 | /* For initializing controller (mask in an HCFS mode too) */ | 120 | /* For initializing controller (mask in an HCFS mode too) */ |
121 | #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR | 121 | #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR |
@@ -253,6 +253,10 @@ static int ohci_urb_enqueue ( | |||
253 | spin_lock_irqsave (&ohci->lock, flags); | 253 | spin_lock_irqsave (&ohci->lock, flags); |
254 | 254 | ||
255 | /* don't submit to a dead HC */ | 255 | /* don't submit to a dead HC */ |
256 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { | ||
257 | retval = -ENODEV; | ||
258 | goto fail; | ||
259 | } | ||
256 | if (!HC_IS_RUNNING(hcd->state)) { | 260 | if (!HC_IS_RUNNING(hcd->state)) { |
257 | retval = -ENODEV; | 261 | retval = -ENODEV; |
258 | goto fail; | 262 | goto fail; |
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index e01e77bc324b..72e3b12a1926 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -53,6 +53,11 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
53 | 53 | ||
54 | spin_lock_irqsave (&ohci->lock, flags); | 54 | spin_lock_irqsave (&ohci->lock, flags); |
55 | 55 | ||
56 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
57 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
58 | return -ESHUTDOWN; | ||
59 | } | ||
60 | |||
56 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 61 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
57 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | 62 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { |
58 | case OHCI_USB_RESUME: | 63 | case OHCI_USB_RESUME: |
@@ -140,11 +145,19 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
140 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 145 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
141 | u32 temp, enables; | 146 | u32 temp, enables; |
142 | int status = -EINPROGRESS; | 147 | int status = -EINPROGRESS; |
148 | unsigned long flags; | ||
143 | 149 | ||
144 | if (time_before (jiffies, ohci->next_statechange)) | 150 | if (time_before (jiffies, ohci->next_statechange)) |
145 | msleep(5); | 151 | msleep(5); |
146 | 152 | ||
147 | spin_lock_irq (&ohci->lock); | 153 | spin_lock_irqsave (&ohci->lock, flags); |
154 | |||
155 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { | ||
156 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
157 | return -ESHUTDOWN; | ||
158 | } | ||
159 | |||
160 | |||
148 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | 161 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); |
149 | 162 | ||
150 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { | 163 | if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { |
@@ -179,7 +192,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
179 | ohci_dbg (ohci, "lost power\n"); | 192 | ohci_dbg (ohci, "lost power\n"); |
180 | status = -EBUSY; | 193 | status = -EBUSY; |
181 | } | 194 | } |
182 | spin_unlock_irq (&ohci->lock); | 195 | spin_unlock_irqrestore (&ohci->lock, flags); |
183 | if (status == -EBUSY) { | 196 | if (status == -EBUSY) { |
184 | (void) ohci_init (ohci); | 197 | (void) ohci_init (ohci); |
185 | return ohci_restart (ohci); | 198 | return ohci_restart (ohci); |
@@ -297,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
297 | /* handle autosuspended root: finish resuming before | 310 | /* handle autosuspended root: finish resuming before |
298 | * letting khubd or root hub timer see state changes. | 311 | * letting khubd or root hub timer see state changes. |
299 | */ | 312 | */ |
300 | if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER | 313 | if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER |
301 | || !HC_IS_RUNNING(hcd->state)) { | 314 | || !HC_IS_RUNNING(hcd->state))) { |
302 | can_suspend = 0; | 315 | can_suspend = 0; |
303 | goto done; | 316 | goto done; |
304 | } | 317 | } |
@@ -508,6 +521,9 @@ static int ohci_hub_control ( | |||
508 | u32 temp; | 521 | u32 temp; |
509 | int retval = 0; | 522 | int retval = 0; |
510 | 523 | ||
524 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) | ||
525 | return -ESHUTDOWN; | ||
526 | |||
511 | switch (typeReq) { | 527 | switch (typeReq) { |
512 | case ClearHubFeature: | 528 | case ClearHubFeature: |
513 | switch (wValue) { | 529 | switch (wValue) { |
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 5f22e6590cd1..1b09dde068e1 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c | |||
@@ -105,13 +105,36 @@ ohci_pci_start (struct usb_hcd *hcd) | |||
105 | 105 | ||
106 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) | 106 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) |
107 | { | 107 | { |
108 | /* root hub was already suspended */ | 108 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
109 | return 0; | 109 | unsigned long flags; |
110 | int rc = 0; | ||
111 | |||
112 | /* Root hub was already suspended. Disable irq emission and | ||
113 | * mark HW unaccessible, bail out if RH has been resumed. Use | ||
114 | * the spinlock to properly synchronize with possible pending | ||
115 | * RH suspend or resume activity. | ||
116 | * | ||
117 | * This is still racy as hcd->state is manipulated outside of | ||
118 | * any locks =P But that will be a different fix. | ||
119 | */ | ||
120 | spin_lock_irqsave (&ohci->lock, flags); | ||
121 | if (hcd->state != HC_STATE_SUSPENDED) { | ||
122 | rc = -EINVAL; | ||
123 | goto bail; | ||
124 | } | ||
125 | ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); | ||
126 | (void)ohci_readl(ohci, &ohci->regs->intrdisable); | ||
127 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
128 | bail: | ||
129 | spin_unlock_irqrestore (&ohci->lock, flags); | ||
130 | |||
131 | return rc; | ||
110 | } | 132 | } |
111 | 133 | ||
112 | 134 | ||
113 | static int ohci_pci_resume (struct usb_hcd *hcd) | 135 | static int ohci_pci_resume (struct usb_hcd *hcd) |
114 | { | 136 | { |
137 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
115 | usb_hcd_resume_root_hub(hcd); | 138 | usb_hcd_resume_root_hub(hcd); |
116 | return 0; | 139 | return 0; |
117 | } | 140 | } |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d33ce3982a5f..ed550132db0b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -717,6 +717,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
717 | * at the source, so we must turn off PIRQ. | 717 | * at the source, so we must turn off PIRQ. |
718 | */ | 718 | */ |
719 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); | 719 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); |
720 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
720 | uhci->hc_inaccessible = 1; | 721 | uhci->hc_inaccessible = 1; |
721 | hcd->poll_rh = 0; | 722 | hcd->poll_rh = 0; |
722 | 723 | ||
@@ -733,6 +734,11 @@ static int uhci_resume(struct usb_hcd *hcd) | |||
733 | 734 | ||
734 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 735 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
735 | 736 | ||
737 | /* We aren't in D3 state anymore, we do that even if dead as I | ||
738 | * really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0 | ||
739 | */ | ||
740 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
741 | |||
736 | if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ | 742 | if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ |
737 | return 0; | 743 | return 0; |
738 | spin_lock_irq(&uhci->lock); | 744 | spin_lock_irq(&uhci->lock); |