diff options
Diffstat (limited to 'drivers/usb/core/hcd-pci.c')
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 214 |
1 files changed, 129 insertions, 85 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 2b487d4797bd..caeb8d6d39fb 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c | |||
@@ -37,119 +37,123 @@ | |||
37 | 37 | ||
38 | /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ | 38 | /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ |
39 | 39 | ||
40 | #ifdef CONFIG_PM_SLEEP | 40 | /* |
41 | 41 | * Coordinate handoffs between EHCI and companion controllers | |
42 | /* Coordinate handoffs between EHCI and companion controllers | 42 | * during EHCI probing and system resume. |
43 | * during system resume | ||
44 | */ | 43 | */ |
45 | 44 | ||
46 | static DEFINE_MUTEX(companions_mutex); | 45 | static DECLARE_RWSEM(companions_rwsem); |
47 | 46 | ||
48 | #define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI | 47 | #define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI |
49 | #define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI | 48 | #define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI |
50 | #define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI | 49 | #define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI |
51 | 50 | ||
52 | enum companion_action { | 51 | static inline int is_ohci_or_uhci(struct pci_dev *pdev) |
53 | SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS | 52 | { |
54 | }; | 53 | return pdev->class == CL_OHCI || pdev->class == CL_UHCI; |
54 | } | ||
55 | |||
56 | typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd, | ||
57 | struct pci_dev *companion, struct usb_hcd *companion_hcd); | ||
55 | 58 | ||
56 | static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, | 59 | /* Iterate over PCI devices in the same slot as pdev and call fn for each */ |
57 | enum companion_action action) | 60 | static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, |
61 | companion_fn fn) | ||
58 | { | 62 | { |
59 | struct pci_dev *companion; | 63 | struct pci_dev *companion; |
60 | struct usb_hcd *companion_hcd; | 64 | struct usb_hcd *companion_hcd; |
61 | unsigned int slot = PCI_SLOT(pdev->devfn); | 65 | unsigned int slot = PCI_SLOT(pdev->devfn); |
62 | 66 | ||
63 | /* Iterate through other PCI functions in the same slot. | 67 | /* |
64 | * If pdev is OHCI or UHCI then we are looking for EHCI, and | 68 | * Iterate through other PCI functions in the same slot. |
65 | * vice versa. | 69 | * If the function's drvdata isn't set then it isn't bound to |
70 | * a USB host controller driver, so skip it. | ||
66 | */ | 71 | */ |
67 | companion = NULL; | 72 | companion = NULL; |
68 | for_each_pci_dev(companion) { | 73 | for_each_pci_dev(companion) { |
69 | if (companion->bus != pdev->bus || | 74 | if (companion->bus != pdev->bus || |
70 | PCI_SLOT(companion->devfn) != slot) | 75 | PCI_SLOT(companion->devfn) != slot) |
71 | continue; | 76 | continue; |
72 | |||
73 | companion_hcd = pci_get_drvdata(companion); | 77 | companion_hcd = pci_get_drvdata(companion); |
74 | if (!companion_hcd) | 78 | if (!companion_hcd) |
75 | continue; | 79 | continue; |
76 | 80 | fn(pdev, hcd, companion, companion_hcd); | |
77 | /* For SET_HS_COMPANION, store a pointer to the EHCI bus in | ||
78 | * the OHCI/UHCI companion bus structure. | ||
79 | * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus | ||
80 | * in the OHCI/UHCI companion bus structure. | ||
81 | * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI | ||
82 | * companion controllers have fully resumed. | ||
83 | */ | ||
84 | |||
85 | if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) && | ||
86 | companion->class == CL_EHCI) { | ||
87 | /* action must be SET_HS_COMPANION */ | ||
88 | dev_dbg(&companion->dev, "HS companion for %s\n", | ||
89 | dev_name(&pdev->dev)); | ||
90 | hcd->self.hs_companion = &companion_hcd->self; | ||
91 | |||
92 | } else if (pdev->class == CL_EHCI && | ||
93 | (companion->class == CL_OHCI || | ||
94 | companion->class == CL_UHCI)) { | ||
95 | switch (action) { | ||
96 | case SET_HS_COMPANION: | ||
97 | dev_dbg(&pdev->dev, "HS companion for %s\n", | ||
98 | dev_name(&companion->dev)); | ||
99 | companion_hcd->self.hs_companion = &hcd->self; | ||
100 | break; | ||
101 | case CLEAR_HS_COMPANION: | ||
102 | companion_hcd->self.hs_companion = NULL; | ||
103 | break; | ||
104 | case WAIT_FOR_COMPANIONS: | ||
105 | device_pm_wait_for_dev(&pdev->dev, | ||
106 | &companion->dev); | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | } | 81 | } |
111 | } | 82 | } |
112 | 83 | ||
113 | static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) | 84 | /* |
85 | * We're about to add an EHCI controller, which will unceremoniously grab | ||
86 | * all the port connections away from its companions. To prevent annoying | ||
87 | * error messages, lock the companion's root hub and gracefully unconfigure | ||
88 | * it beforehand. Leave it locked until the EHCI controller is all set. | ||
89 | */ | ||
90 | static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd, | ||
91 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | ||
114 | { | 92 | { |
115 | mutex_lock(&companions_mutex); | 93 | struct usb_device *udev; |
116 | dev_set_drvdata(&pdev->dev, hcd); | 94 | |
117 | companion_common(pdev, hcd, SET_HS_COMPANION); | 95 | if (is_ohci_or_uhci(companion)) { |
118 | mutex_unlock(&companions_mutex); | 96 | udev = companion_hcd->self.root_hub; |
97 | usb_lock_device(udev); | ||
98 | usb_set_configuration(udev, 0); | ||
99 | } | ||
119 | } | 100 | } |
120 | 101 | ||
121 | static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) | 102 | /* |
103 | * Adding the EHCI controller has either succeeded or failed. Set the | ||
104 | * companion pointer accordingly, and in either case, reconfigure and | ||
105 | * unlock the root hub. | ||
106 | */ | ||
107 | static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd, | ||
108 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | ||
122 | { | 109 | { |
123 | mutex_lock(&companions_mutex); | 110 | struct usb_device *udev; |
124 | dev_set_drvdata(&pdev->dev, NULL); | ||
125 | 111 | ||
126 | /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */ | 112 | if (is_ohci_or_uhci(companion)) { |
127 | if (pdev->class == CL_OHCI || pdev->class == CL_UHCI) | 113 | if (dev_get_drvdata(&pdev->dev)) { /* Succeeded */ |
128 | hcd->self.hs_companion = NULL; | 114 | dev_dbg(&pdev->dev, "HS companion for %s\n", |
115 | dev_name(&companion->dev)); | ||
116 | companion_hcd->self.hs_companion = &hcd->self; | ||
117 | } | ||
118 | udev = companion_hcd->self.root_hub; | ||
119 | usb_set_configuration(udev, 1); | ||
120 | usb_unlock_device(udev); | ||
121 | } | ||
122 | } | ||
129 | 123 | ||
130 | /* Otherwise search for companion buses and clear their pointers */ | 124 | /* |
131 | else | 125 | * We just added a non-EHCI controller. Find the EHCI controller to |
132 | companion_common(pdev, hcd, CLEAR_HS_COMPANION); | 126 | * which it is a companion, and store a pointer to the bus structure. |
133 | mutex_unlock(&companions_mutex); | 127 | */ |
128 | static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd, | ||
129 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | ||
130 | { | ||
131 | if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) { | ||
132 | dev_dbg(&pdev->dev, "FS/LS companion for %s\n", | ||
133 | dev_name(&companion->dev)); | ||
134 | hcd->self.hs_companion = &companion_hcd->self; | ||
135 | } | ||
134 | } | 136 | } |
135 | 137 | ||
136 | static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) | 138 | /* We are removing an EHCI controller. Clear the companions' pointers. */ |
139 | static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd, | ||
140 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | ||
137 | { | 141 | { |
138 | /* Only EHCI controllers need to wait. | 142 | if (is_ohci_or_uhci(companion)) |
139 | * No locking is needed because a controller cannot be resumed | 143 | companion_hcd->self.hs_companion = NULL; |
140 | * while one of its companions is getting unbound. | ||
141 | */ | ||
142 | if (pdev->class == CL_EHCI) | ||
143 | companion_common(pdev, hcd, WAIT_FOR_COMPANIONS); | ||
144 | } | 144 | } |
145 | 145 | ||
146 | #else /* !CONFIG_PM_SLEEP */ | 146 | #ifdef CONFIG_PM |
147 | 147 | ||
148 | static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} | 148 | /* An EHCI controller must wait for its companions before resuming. */ |
149 | static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} | 149 | static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, |
150 | static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {} | 150 | struct pci_dev *companion, struct usb_hcd *companion_hcd) |
151 | { | ||
152 | if (is_ohci_or_uhci(companion)) | ||
153 | device_pm_wait_for_dev(&pdev->dev, &companion->dev); | ||
154 | } | ||
151 | 155 | ||
152 | #endif /* !CONFIG_PM_SLEEP */ | 156 | #endif /* CONFIG_PM */ |
153 | 157 | ||
154 | /*-------------------------------------------------------------------------*/ | 158 | /*-------------------------------------------------------------------------*/ |
155 | 159 | ||
@@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
217 | driver->description)) { | 221 | driver->description)) { |
218 | dev_dbg(&dev->dev, "controller already in use\n"); | 222 | dev_dbg(&dev->dev, "controller already in use\n"); |
219 | retval = -EBUSY; | 223 | retval = -EBUSY; |
220 | goto clear_companion; | 224 | goto put_hcd; |
221 | } | 225 | } |
222 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); | 226 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
223 | if (hcd->regs == NULL) { | 227 | if (hcd->regs == NULL) { |
@@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
244 | if (region == PCI_ROM_RESOURCE) { | 248 | if (region == PCI_ROM_RESOURCE) { |
245 | dev_dbg(&dev->dev, "no i/o regions available\n"); | 249 | dev_dbg(&dev->dev, "no i/o regions available\n"); |
246 | retval = -EBUSY; | 250 | retval = -EBUSY; |
247 | goto clear_companion; | 251 | goto put_hcd; |
248 | } | 252 | } |
249 | } | 253 | } |
250 | 254 | ||
251 | pci_set_master(dev); | 255 | pci_set_master(dev); |
252 | 256 | ||
253 | retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); | 257 | /* Note: dev_set_drvdata must be called while holding the rwsem */ |
258 | if (dev->class == CL_EHCI) { | ||
259 | down_write(&companions_rwsem); | ||
260 | dev_set_drvdata(&dev->dev, hcd); | ||
261 | for_each_companion(dev, hcd, ehci_pre_add); | ||
262 | retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); | ||
263 | if (retval != 0) | ||
264 | dev_set_drvdata(&dev->dev, NULL); | ||
265 | for_each_companion(dev, hcd, ehci_post_add); | ||
266 | up_write(&companions_rwsem); | ||
267 | } else { | ||
268 | down_read(&companions_rwsem); | ||
269 | dev_set_drvdata(&dev->dev, hcd); | ||
270 | retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); | ||
271 | if (retval != 0) | ||
272 | dev_set_drvdata(&dev->dev, NULL); | ||
273 | else | ||
274 | for_each_companion(dev, hcd, non_ehci_add); | ||
275 | up_read(&companions_rwsem); | ||
276 | } | ||
277 | |||
254 | if (retval != 0) | 278 | if (retval != 0) |
255 | goto unmap_registers; | 279 | goto unmap_registers; |
256 | set_hs_companion(dev, hcd); | ||
257 | 280 | ||
258 | if (pci_dev_run_wake(dev)) | 281 | if (pci_dev_run_wake(dev)) |
259 | pm_runtime_put_noidle(&dev->dev); | 282 | pm_runtime_put_noidle(&dev->dev); |
@@ -266,8 +289,7 @@ release_mem_region: | |||
266 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 289 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
267 | } else | 290 | } else |
268 | release_region(hcd->rsrc_start, hcd->rsrc_len); | 291 | release_region(hcd->rsrc_start, hcd->rsrc_len); |
269 | clear_companion: | 292 | put_hcd: |
270 | clear_hs_companion(dev, hcd); | ||
271 | usb_put_hcd(hcd); | 293 | usb_put_hcd(hcd); |
272 | disable_pci: | 294 | disable_pci: |
273 | pci_disable_device(dev); | 295 | pci_disable_device(dev); |
@@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev) | |||
310 | usb_hcd_irq(0, hcd); | 332 | usb_hcd_irq(0, hcd); |
311 | local_irq_enable(); | 333 | local_irq_enable(); |
312 | 334 | ||
313 | usb_remove_hcd(hcd); | 335 | /* Note: dev_set_drvdata must be called while holding the rwsem */ |
336 | if (dev->class == CL_EHCI) { | ||
337 | down_write(&companions_rwsem); | ||
338 | for_each_companion(dev, hcd, ehci_remove); | ||
339 | usb_remove_hcd(hcd); | ||
340 | dev_set_drvdata(&dev->dev, NULL); | ||
341 | up_write(&companions_rwsem); | ||
342 | } else { | ||
343 | /* Not EHCI; just clear the companion pointer */ | ||
344 | down_read(&companions_rwsem); | ||
345 | hcd->self.hs_companion = NULL; | ||
346 | usb_remove_hcd(hcd); | ||
347 | dev_set_drvdata(&dev->dev, NULL); | ||
348 | up_read(&companions_rwsem); | ||
349 | } | ||
350 | |||
314 | if (hcd->driver->flags & HCD_MEMORY) { | 351 | if (hcd->driver->flags & HCD_MEMORY) { |
315 | iounmap(hcd->regs); | 352 | iounmap(hcd->regs); |
316 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 353 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
317 | } else { | 354 | } else { |
318 | release_region(hcd->rsrc_start, hcd->rsrc_len); | 355 | release_region(hcd->rsrc_start, hcd->rsrc_len); |
319 | } | 356 | } |
320 | clear_hs_companion(dev, hcd); | 357 | |
321 | usb_put_hcd(hcd); | 358 | usb_put_hcd(hcd); |
322 | pci_disable_device(dev); | 359 | pci_disable_device(dev); |
323 | } | 360 | } |
@@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event) | |||
463 | pci_set_master(pci_dev); | 500 | pci_set_master(pci_dev); |
464 | 501 | ||
465 | if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { | 502 | if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { |
466 | if (event != PM_EVENT_AUTO_RESUME) | 503 | |
467 | wait_for_companions(pci_dev, hcd); | 504 | /* |
505 | * Only EHCI controllers have to wait for their companions. | ||
506 | * No locking is needed because PCI controller drivers do not | ||
507 | * get unbound during system resume. | ||
508 | */ | ||
509 | if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME) | ||
510 | for_each_companion(pci_dev, hcd, | ||
511 | ehci_wait_for_companions); | ||
468 | 512 | ||
469 | retval = hcd->driver->pci_resume(hcd, | 513 | retval = hcd->driver->pci_resume(hcd, |
470 | event == PM_EVENT_RESTORE); | 514 | event == PM_EVENT_RESTORE); |