aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/atm/cxacru.c3
-rw-r--r--drivers/usb/core/hcd-pci.c3
-rw-r--r--drivers/usb/core/hcd.c15
-rw-r--r--drivers/usb/core/hcd.h7
-rw-r--r--drivers/usb/host/ehci-pci.c46
-rw-r--r--drivers/usb/host/ehci-q.c24
-rw-r--r--drivers/usb/host/ehci-sched.c18
-rw-r--r--drivers/usb/host/ohci-hcd.c6
-rw-r--r--drivers/usb/host/ohci-hub.c24
-rw-r--r--drivers/usb/host/ohci-pci.c27
-rw-r--r--drivers/usb/host/uhci-hcd.c6
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 */
125static int ehci_pci_reset(struct usb_hcd *hcd) 125static 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 216done:
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)
228static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) 233static 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
241static int ehci_pci_resume(struct usb_hcd *hcd) 268static 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
106static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) 106static 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
113static int ohci_pci_resume (struct usb_hcd *hcd) 135static 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);