aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2010-12-02 22:10:02 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-03-13 21:23:33 -0400
commitff9d78b36f76687c91c67b9f4c5c33bc888ed2f9 (patch)
treec269f0ec7f830a478ab5738f7579221d7caecf5d /drivers/usb/core
parentc56354378426e550aaf6ddf3983f502a8fddeab5 (diff)
USB: Set usb_hcd->state and flags for shared roothubs.
The hcd->flags are in a sorry state. Some of them are clearly specific to the particular roothub (HCD_POLL_RH, HCD_POLL_PENDING, and HCD_WAKEUP_PENDING), but some flags are related to PCI device state (HCD_HW_ACCESSIBLE and HCD_SAW_IRQ). This is an issue when one PCI device can have two roothubs that share the same IRQ line and hardware. Make sure to set HCD_FLAG_SAW_IRQ for both roothubs when an interrupt is serviced, or an URB is unlinked without an interrupt. (We can't tell if the host actually serviced an interrupt for a particular bus, but we can tell it serviced some interrupt.) HCD_HW_ACCESSIBLE is set once by usb_add_hcd(), which is set for both roothubs as they are added, so it doesn't need to be modified. HCD_POLL_RH and HCD_POLL_PENDING are only checked by the USB core, and they are never set by the xHCI driver, since the roothub never needs to be polled. The usb_hcd's state field is a similar mess. Sometimes the state applies to the underlying hardware: HC_STATE_HALT, HC_STATE_RUNNING, and HC_STATE_QUIESCING. But sometimes the state refers to the roothub state: HC_STATE_RESUMING and HC_STATE_SUSPENDED. Alan Stern recently made the USB core not rely on the hcd->state variable. Internally, the xHCI driver still checks for HC_STATE_SUSPENDED, so leave that code in. Remove all references to HC_STATE_HALT, since the xHCI driver only sets and doesn't test those variables. We still have to set HC_STATE_RUNNING, since Alan's patch has a bug that means the roothub won't get registered if we don't set that. Alan's patch made the USB core check a different variable when trying to determine whether to suspend a roothub. The xHCI host has a split roothub, where two buses are registered for one PCI device. Each bus in the xHCI split roothub can be suspended separately, but both buses must be suspended before the PCI device can be suspended. Therefore, make sure that the USB core checks HCD_RH_RUNNING() for both roothubs before suspending the PCI host. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hcd-pci.c27
-rw-r--r--drivers/usb/core/hcd.c4
2 files changed, 27 insertions, 4 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 88d9109b4b4..b992a886f05 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -367,6 +367,13 @@ static int check_root_hub_suspended(struct device *dev)
367 dev_warn(dev, "Root hub is not suspended\n"); 367 dev_warn(dev, "Root hub is not suspended\n");
368 return -EBUSY; 368 return -EBUSY;
369 } 369 }
370 if (hcd->shared_hcd) {
371 hcd = hcd->shared_hcd;
372 if (HCD_RH_RUNNING(hcd)) {
373 dev_warn(dev, "Secondary root hub is not suspended\n");
374 return -EBUSY;
375 }
376 }
370 return 0; 377 return 0;
371} 378}
372 379
@@ -391,11 +398,16 @@ static int suspend_common(struct device *dev, bool do_wakeup)
391 */ 398 */
392 if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) 399 if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
393 return -EBUSY; 400 return -EBUSY;
401 if (do_wakeup && hcd->shared_hcd &&
402 HCD_WAKEUP_PENDING(hcd->shared_hcd))
403 return -EBUSY;
394 retval = hcd->driver->pci_suspend(hcd, do_wakeup); 404 retval = hcd->driver->pci_suspend(hcd, do_wakeup);
395 suspend_report_result(hcd->driver->pci_suspend, retval); 405 suspend_report_result(hcd->driver->pci_suspend, retval);
396 406
397 /* Check again in case wakeup raced with pci_suspend */ 407 /* Check again in case wakeup raced with pci_suspend */
398 if (retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) { 408 if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) ||
409 (retval == 0 && do_wakeup && hcd->shared_hcd &&
410 HCD_WAKEUP_PENDING(hcd->shared_hcd))) {
399 if (hcd->driver->pci_resume) 411 if (hcd->driver->pci_resume)
400 hcd->driver->pci_resume(hcd, false); 412 hcd->driver->pci_resume(hcd, false);
401 retval = -EBUSY; 413 retval = -EBUSY;
@@ -426,7 +438,9 @@ static int resume_common(struct device *dev, int event)
426 struct usb_hcd *hcd = pci_get_drvdata(pci_dev); 438 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
427 int retval; 439 int retval;
428 440
429 if (HCD_RH_RUNNING(hcd)) { 441 if (HCD_RH_RUNNING(hcd) ||
442 (hcd->shared_hcd &&
443 HCD_RH_RUNNING(hcd->shared_hcd))) {
430 dev_dbg(dev, "can't resume, not suspended!\n"); 444 dev_dbg(dev, "can't resume, not suspended!\n");
431 return 0; 445 return 0;
432 } 446 }
@@ -440,6 +454,8 @@ static int resume_common(struct device *dev, int event)
440 pci_set_master(pci_dev); 454 pci_set_master(pci_dev);
441 455
442 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 456 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
457 if (hcd->shared_hcd)
458 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
443 459
444 if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { 460 if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
445 if (event != PM_EVENT_AUTO_RESUME) 461 if (event != PM_EVENT_AUTO_RESUME)
@@ -449,6 +465,8 @@ static int resume_common(struct device *dev, int event)
449 event == PM_EVENT_RESTORE); 465 event == PM_EVENT_RESTORE);
450 if (retval) { 466 if (retval) {
451 dev_err(dev, "PCI post-resume error %d!\n", retval); 467 dev_err(dev, "PCI post-resume error %d!\n", retval);
468 if (hcd->shared_hcd)
469 usb_hc_died(hcd->shared_hcd);
452 usb_hc_died(hcd); 470 usb_hc_died(hcd);
453 } 471 }
454 } 472 }
@@ -474,8 +492,9 @@ static int hcd_pci_suspend_noirq(struct device *dev)
474 492
475 pci_save_state(pci_dev); 493 pci_save_state(pci_dev);
476 494
477 /* If the root hub is dead rather than suspended, 495 /* If the root hub is dead rather than suspended, disallow remote
478 * disallow remote wakeup. 496 * wakeup. usb_hc_died() should ensure that both hosts are marked as
497 * dying, so we only need to check the primary roothub.
479 */ 498 */
480 if (HCD_DEAD(hcd)) 499 if (HCD_DEAD(hcd))
481 device_set_wakeup_enable(dev, 0); 500 device_set_wakeup_enable(dev, 0);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index ba15eeab824..02b4dbfa488 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1153,6 +1153,8 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
1153 dev_warn(hcd->self.controller, "Unlink after no-IRQ? " 1153 dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
1154 "Controller is probably using the wrong IRQ.\n"); 1154 "Controller is probably using the wrong IRQ.\n");
1155 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 1155 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
1156 if (hcd->shared_hcd)
1157 set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
1156 } 1158 }
1157 1159
1158 return 0; 1160 return 0;
@@ -2124,6 +2126,8 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
2124 rc = IRQ_NONE; 2126 rc = IRQ_NONE;
2125 } else { 2127 } else {
2126 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 2128 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
2129 if (hcd->shared_hcd)
2130 set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
2127 2131
2128 if (unlikely(hcd->state == HC_STATE_HALT)) 2132 if (unlikely(hcd->state == HC_STATE_HALT))
2129 usb_hc_died(hcd); 2133 usb_hc_died(hcd);