diff options
Diffstat (limited to 'drivers/usb/core')
-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 |
3 files changed, 18 insertions, 7 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5131d88e8c5..29b5b2a6e18 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) goto done; } } + synchronize_irq(dev->irq); /* FIXME until the generic PM interfaces change a lot more, this * 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) dev->dev.power.power_state = PMSG_ON; - hcd->saw_irq = 0; + clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); if (hcd->driver->resume) { retval = hcd->driver->resume(hcd); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 5e5f65a475a..da24c31ee00 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) * finish unlinking the initial failed usb_set_address() * or device descriptor fetch. */ - if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) { + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) + && hcd->self.root_hub != urb->dev) { dev_warn (hcd->self.controller, "Unlink after no-IRQ? " "Controller is probably using the wrong IRQ." "\n"); - hcd->saw_irq = 1; + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } urb->status = status; @@ -1649,13 +1650,15 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) struct usb_hcd *hcd = __hcd; int start = hcd->state; - if (start == HC_STATE_HALT) + if (unlikely(start == HC_STATE_HALT || + !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) return IRQ_NONE; if (hcd->driver->irq (hcd, r) == IRQ_NONE) return IRQ_NONE; - hcd->saw_irq = 1; - if (hcd->state == HC_STATE_HALT) + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + + if (unlikely(hcd->state == HC_STATE_HALT)) usb_hc_died (hcd); return IRQ_HANDLED; } @@ -1768,6 +1771,8 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* till now HC has been in an indeterminate state ... */ if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { dev_err(hcd->self.controller, "can't reset\n"); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 24a62a2ff86..c8a1b350e2c 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 */ * hardware info/state */ const struct hc_driver *driver; /* hw-specific hooks */ - unsigned saw_irq : 1; + + /* Flags that need to be manipulated atomically */ + unsigned long flags; +#define HCD_FLAG_HW_ACCESSIBLE 0x00000001 +#define HCD_FLAG_SAW_IRQ 0x00000002 + unsigned can_wakeup:1; /* hw supports wakeup? */ unsigned remote_wakeup:1;/* sw should use wakeup? */ unsigned rh_registered:1;/* is root hub registered? */ |