aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/driver.c8
-rw-r--r--drivers/usb/core/hcd-pci.c127
-rw-r--r--include/linux/usb.h1
3 files changed, 135 insertions, 1 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 60a45f1e3a67..f2f055eb6831 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1022,6 +1022,14 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
1022 goto done; 1022 goto done;
1023 } 1023 }
1024 1024
1025 /* Non-root devices on a full/low-speed bus must wait for their
1026 * companion high-speed root hub, in case a handoff is needed.
1027 */
1028 if (!(msg.event & PM_EVENT_AUTO) && udev->parent &&
1029 udev->bus->hs_companion)
1030 device_pm_wait_for_dev(&udev->dev,
1031 &udev->bus->hs_companion->root_hub->dev);
1032
1025 if (udev->quirks & USB_QUIRK_RESET_RESUME) 1033 if (udev->quirks & USB_QUIRK_RESET_RESUME)
1026 udev->reset_resume = 1; 1034 udev->reset_resume = 1;
1027 1035
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 2dcf906df569..15286533c15a 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -19,6 +19,7 @@
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/pci.h> 21#include <linux/pci.h>
22#include <linux/pm_runtime.h>
22#include <linux/usb.h> 23#include <linux/usb.h>
23 24
24#include <asm/io.h> 25#include <asm/io.h>
@@ -37,6 +38,122 @@
37 38
38/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ 39/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
39 40
41#ifdef CONFIG_PM_SLEEP
42
43/* Coordinate handoffs between EHCI and companion controllers
44 * during system resume
45 */
46
47static DEFINE_MUTEX(companions_mutex);
48
49#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
50#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
51#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
52
53enum companion_action {
54 SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
55};
56
57static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
58 enum companion_action action)
59{
60 struct pci_dev *companion;
61 struct usb_hcd *companion_hcd;
62 unsigned int slot = PCI_SLOT(pdev->devfn);
63
64 /* Iterate through other PCI functions in the same slot.
65 * If pdev is OHCI or UHCI then we are looking for EHCI, and
66 * vice versa.
67 */
68 companion = NULL;
69 for (;;) {
70 companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion);
71 if (!companion)
72 break;
73 if (companion->bus != pdev->bus ||
74 PCI_SLOT(companion->devfn) != slot)
75 continue;
76
77 companion_hcd = pci_get_drvdata(companion);
78 if (!companion_hcd)
79 continue;
80
81 /* For SET_HS_COMPANION, store a pointer to the EHCI bus in
82 * the OHCI/UHCI companion bus structure.
83 * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
84 * in the OHCI/UHCI companion bus structure.
85 * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
86 * companion controllers have fully resumed.
87 */
88
89 if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
90 companion->class == CL_EHCI) {
91 /* action must be SET_HS_COMPANION */
92 dev_dbg(&companion->dev, "HS companion for %s\n",
93 dev_name(&pdev->dev));
94 hcd->self.hs_companion = &companion_hcd->self;
95
96 } else if (pdev->class == CL_EHCI &&
97 (companion->class == CL_OHCI ||
98 companion->class == CL_UHCI)) {
99 switch (action) {
100 case SET_HS_COMPANION:
101 dev_dbg(&pdev->dev, "HS companion for %s\n",
102 dev_name(&companion->dev));
103 companion_hcd->self.hs_companion = &hcd->self;
104 break;
105 case CLEAR_HS_COMPANION:
106 companion_hcd->self.hs_companion = NULL;
107 break;
108 case WAIT_FOR_COMPANIONS:
109 device_pm_wait_for_dev(&pdev->dev,
110 &companion->dev);
111 break;
112 }
113 }
114 }
115}
116
117static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
118{
119 mutex_lock(&companions_mutex);
120 dev_set_drvdata(&pdev->dev, hcd);
121 companion_common(pdev, hcd, SET_HS_COMPANION);
122 mutex_unlock(&companions_mutex);
123}
124
125static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
126{
127 mutex_lock(&companions_mutex);
128 dev_set_drvdata(&pdev->dev, NULL);
129
130 /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
131 if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
132 hcd->self.hs_companion = NULL;
133
134 /* Otherwise search for companion buses and clear their pointers */
135 else
136 companion_common(pdev, hcd, CLEAR_HS_COMPANION);
137 mutex_unlock(&companions_mutex);
138}
139
140static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
141{
142 /* Only EHCI controllers need to wait.
143 * No locking is needed because a controller cannot be resumed
144 * while one of its companions is getting unbound.
145 */
146 if (pdev->class == CL_EHCI)
147 companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
148}
149
150#else /* !CONFIG_PM_SLEEP */
151
152static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
153static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
154static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
155
156#endif /* !CONFIG_PM_SLEEP */
40 157
41/*-------------------------------------------------------------------------*/ 158/*-------------------------------------------------------------------------*/
42 159
@@ -123,7 +240,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
123 if (region == PCI_ROM_RESOURCE) { 240 if (region == PCI_ROM_RESOURCE) {
124 dev_dbg(&dev->dev, "no i/o regions available\n"); 241 dev_dbg(&dev->dev, "no i/o regions available\n");
125 retval = -EBUSY; 242 retval = -EBUSY;
126 goto err1; 243 goto err2;
127 } 244 }
128 } 245 }
129 246
@@ -132,6 +249,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
132 retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); 249 retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
133 if (retval != 0) 250 if (retval != 0)
134 goto err4; 251 goto err4;
252 set_hs_companion(dev, hcd);
135 return retval; 253 return retval;
136 254
137 err4: 255 err4:
@@ -142,6 +260,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
142 } else 260 } else
143 release_region(hcd->rsrc_start, hcd->rsrc_len); 261 release_region(hcd->rsrc_start, hcd->rsrc_len);
144 err2: 262 err2:
263 clear_hs_companion(dev, hcd);
145 usb_put_hcd(hcd); 264 usb_put_hcd(hcd);
146 err1: 265 err1:
147 pci_disable_device(dev); 266 pci_disable_device(dev);
@@ -180,6 +299,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
180 } else { 299 } else {
181 release_region(hcd->rsrc_start, hcd->rsrc_len); 300 release_region(hcd->rsrc_start, hcd->rsrc_len);
182 } 301 }
302 clear_hs_companion(dev, hcd);
183 usb_put_hcd(hcd); 303 usb_put_hcd(hcd);
184 pci_disable_device(dev); 304 pci_disable_device(dev);
185} 305}
@@ -344,6 +464,11 @@ static int resume_common(struct device *dev, bool hibernated)
344 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 464 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
345 465
346 if (hcd->driver->pci_resume) { 466 if (hcd->driver->pci_resume) {
467 /* This call should be made only during system resume,
468 * not during runtime resume.
469 */
470 wait_for_companions(pci_dev, hcd);
471
347 retval = hcd->driver->pci_resume(hcd, hibernated); 472 retval = hcd->driver->pci_resume(hcd, hibernated);
348 if (retval) { 473 if (retval) {
349 dev_err(dev, "PCI post-resume error %d!\n", retval); 474 dev_err(dev, "PCI post-resume error %d!\n", retval);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index d7ace1b80f09..332eaea61021 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -339,6 +339,7 @@ struct usb_bus {
339 339
340 struct usb_devmap devmap; /* device address allocation map */ 340 struct usb_devmap devmap; /* device address allocation map */
341 struct usb_device *root_hub; /* Root hub */ 341 struct usb_device *root_hub; /* Root hub */
342 struct usb_bus *hs_companion; /* Companion EHCI bus, if any */
342 struct list_head bus_list; /* list of busses */ 343 struct list_head bus_list; /* list of busses */
343 344
344 int bandwidth_allocated; /* on this bus: how much of the time 345 int bandwidth_allocated; /* on this bus: how much of the time