aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hcd-pci.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2013-03-28 15:04:45 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-28 17:45:57 -0400
commit05768918b9a122ce21bd55950df5054ff6c57f28 (patch)
tree5acd91bdea7290599050fac5de27f06cf61d41bc /drivers/usb/core/hcd-pci.c
parent4e9c8e5c5883c910926296e699c2f4e4d9f847cb (diff)
USB: improve port transitions when EHCI starts up
It seems to be getting more common recently for EHCI host controllers to be probed after their companion UHCI or OHCI controllers. This may be caused partly by splitting the ehci-pci driver out from ehci-hcd, or it may be caused by changes in the way the kernel does driver probing. Regardless, it has a tendency to cause problems. When an EHCI controller is initialized, it takes ownership of all the ports away from the companions. In effect, it forcefully disconnects all the USB devices that may already be using a companion controller. This patch (as1672b) tries to make the transition more orderly by deconfiguring the root hubs for all the companion controllers before initializing the EHCI controller, and reconfiguring them afterward. The result is a soft disconnect rather than a hard one. Internally, the patch refactors the code involved in associating EHCI controllers with their companions. The old approach, in which a single function is called with an argument telling it what to do (the companion_action enum), has been replaced with a scheme using multiple callback functions, each performing a single task. This patch won't solve all the problems people encounter when their EHCI controllers start up, but it will at least reduce the number of error messages generated by the unexpected disconnections. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Jenya Y <jy.gerstmaier@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/hcd-pci.c')
-rw-r--r--drivers/usb/core/hcd-pci.c214
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
46static DEFINE_MUTEX(companions_mutex); 45static 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
52enum companion_action { 51static 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
56typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd,
57 struct pci_dev *companion, struct usb_hcd *companion_hcd);
55 58
56static 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) 60static 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
113static 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 */
90static 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
121static 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 */
107static 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 */
128static 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
136static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) 138/* We are removing an EHCI controller. Clear the companions' pointers. */
139static 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
148static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} 148/* An EHCI controller must wait for its companions before resuming. */
149static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} 149static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
150static 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);
269clear_companion: 292put_hcd:
270 clear_hs_companion(dev, hcd);
271 usb_put_hcd(hcd); 293 usb_put_hcd(hcd);
272disable_pci: 294disable_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);