diff options
author | David Brownell <david-b@pacbell.net> | 2006-01-23 18:28:07 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-20 17:49:56 -0500 |
commit | 6a9062f393fa48125df23c5491543828a21e1ae0 (patch) | |
tree | ca79e036f5a00253af790b45da6a6102b58ff97c | |
parent | b1e8f0a6a8805c971857cd10a65cf8caa4c1a672 (diff) |
[PATCH] USB: ohci uses driver model wakeup flags
This makes OHCI use the driver model wakeup control bits for its root hub
(e.g. disable on amd756, because of chip erratum) and for the controller
itself. It no longer uses the hcd glue bits with those roles, and depends
on the previous patch making the root hub available earlier.
Note that on most platforms (boot code properly setting the RWC bit) this
gives a partial workaround for the way PCI isn't currently flagging devices
that support PME# signals. (Because of odd PCI init sequencing on PPC.)
That's because many OHCI controllers support "legacy PCI PM" ... without
involving any PCI PM capability.
USB wakeup from STR, if it works on your system, may still involve
tweaking things by hand in /proc/acpi/wakeup.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 49 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 12 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 15 |
3 files changed, 46 insertions, 30 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2990be269000..544f7589912f 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -443,11 +443,16 @@ ohci_reboot (struct notifier_block *block, unsigned long code, void *null) | |||
443 | static int ohci_init (struct ohci_hcd *ohci) | 443 | static int ohci_init (struct ohci_hcd *ohci) |
444 | { | 444 | { |
445 | int ret; | 445 | int ret; |
446 | struct usb_hcd *hcd = ohci_to_hcd(ohci); | ||
446 | 447 | ||
447 | disable (ohci); | 448 | disable (ohci); |
448 | ohci->regs = ohci_to_hcd(ohci)->regs; | 449 | ohci->regs = hcd->regs; |
449 | ohci->next_statechange = jiffies; | 450 | ohci->next_statechange = jiffies; |
450 | 451 | ||
452 | /* REVISIT this BIOS handshake is now moved into PCI "quirks", and | ||
453 | * was never needed for most non-PCI systems ... remove the code? | ||
454 | */ | ||
455 | |||
451 | #ifndef IR_DISABLE | 456 | #ifndef IR_DISABLE |
452 | /* SMM owns the HC? not for long! */ | 457 | /* SMM owns the HC? not for long! */ |
453 | if (!no_handshake && ohci_readl (ohci, | 458 | if (!no_handshake && ohci_readl (ohci, |
@@ -478,8 +483,10 @@ static int ohci_init (struct ohci_hcd *ohci) | |||
478 | 483 | ||
479 | /* Disable HC interrupts */ | 484 | /* Disable HC interrupts */ |
480 | ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); | 485 | ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); |
481 | // flush the writes | 486 | |
482 | (void) ohci_readl (ohci, &ohci->regs->control); | 487 | /* flush the writes, and save key bits like RWC */ |
488 | if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC) | ||
489 | ohci->hc_control |= OHCI_CTRL_RWC; | ||
483 | 490 | ||
484 | /* Read the number of ports unless overridden */ | 491 | /* Read the number of ports unless overridden */ |
485 | if (ohci->num_ports == 0) | 492 | if (ohci->num_ports == 0) |
@@ -488,16 +495,19 @@ static int ohci_init (struct ohci_hcd *ohci) | |||
488 | if (ohci->hcca) | 495 | if (ohci->hcca) |
489 | return 0; | 496 | return 0; |
490 | 497 | ||
491 | ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller, | 498 | ohci->hcca = dma_alloc_coherent (hcd->self.controller, |
492 | sizeof *ohci->hcca, &ohci->hcca_dma, 0); | 499 | sizeof *ohci->hcca, &ohci->hcca_dma, 0); |
493 | if (!ohci->hcca) | 500 | if (!ohci->hcca) |
494 | return -ENOMEM; | 501 | return -ENOMEM; |
495 | 502 | ||
496 | if ((ret = ohci_mem_init (ohci)) < 0) | 503 | if ((ret = ohci_mem_init (ohci)) < 0) |
497 | ohci_stop (ohci_to_hcd(ohci)); | 504 | ohci_stop (hcd); |
505 | else { | ||
506 | register_reboot_notifier (&ohci->reboot_notifier); | ||
507 | create_debug_files (ohci); | ||
508 | } | ||
498 | 509 | ||
499 | return ret; | 510 | return ret; |
500 | |||
501 | } | 511 | } |
502 | 512 | ||
503 | /*-------------------------------------------------------------------------*/ | 513 | /*-------------------------------------------------------------------------*/ |
@@ -510,6 +520,7 @@ static int ohci_run (struct ohci_hcd *ohci) | |||
510 | { | 520 | { |
511 | u32 mask, temp; | 521 | u32 mask, temp; |
512 | int first = ohci->fminterval == 0; | 522 | int first = ohci->fminterval == 0; |
523 | struct usb_hcd *hcd = ohci_to_hcd(ohci); | ||
513 | 524 | ||
514 | disable (ohci); | 525 | disable (ohci); |
515 | 526 | ||
@@ -525,18 +536,17 @@ static int ohci_run (struct ohci_hcd *ohci) | |||
525 | /* also: power/overcurrent flags in roothub.a */ | 536 | /* also: power/overcurrent flags in roothub.a */ |
526 | } | 537 | } |
527 | 538 | ||
528 | /* Reset USB nearly "by the book". RemoteWakeupConnected | 539 | /* Reset USB nearly "by the book". RemoteWakeupConnected was |
529 | * saved if boot firmware (BIOS/SMM/...) told us it's connected | 540 | * saved if boot firmware (BIOS/SMM/...) told us it's connected, |
530 | * (for OHCI integrated on mainboard, it normally is) | 541 | * or if bus glue did the same (e.g. for PCI add-in cards with |
542 | * PCI PM support). | ||
531 | */ | 543 | */ |
532 | ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); | ||
533 | ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n", | 544 | ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n", |
534 | hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), | 545 | hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), |
535 | ohci->hc_control); | 546 | ohci_readl (ohci, &ohci->regs->control)); |
536 | 547 | if ((ohci->hc_control & OHCI_CTRL_RWC) != 0 | |
537 | if (ohci->hc_control & OHCI_CTRL_RWC | 548 | && !device_may_wakeup(hcd->self.controller)) |
538 | && !(ohci->flags & OHCI_QUIRK_AMD756)) | 549 | device_init_wakeup(hcd->self.controller, 1); |
539 | ohci_to_hcd(ohci)->can_wakeup = 1; | ||
540 | 550 | ||
541 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { | 551 | switch (ohci->hc_control & OHCI_CTRL_HCFS) { |
542 | case OHCI_USB_OPER: | 552 | case OHCI_USB_OPER: |
@@ -632,7 +642,7 @@ retry: | |||
632 | ohci->hc_control &= OHCI_CTRL_RWC; | 642 | ohci->hc_control &= OHCI_CTRL_RWC; |
633 | ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; | 643 | ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; |
634 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); | 644 | ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); |
635 | ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; | 645 | hcd->state = HC_STATE_RUNNING; |
636 | 646 | ||
637 | /* wake on ConnectStatusChange, matching external hubs */ | 647 | /* wake on ConnectStatusChange, matching external hubs */ |
638 | ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); | 648 | ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); |
@@ -667,15 +677,10 @@ retry: | |||
667 | 677 | ||
668 | // POTPGT delay is bits 24-31, in 2 ms units. | 678 | // POTPGT delay is bits 24-31, in 2 ms units. |
669 | mdelay ((temp >> 23) & 0x1fe); | 679 | mdelay ((temp >> 23) & 0x1fe); |
670 | ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; | 680 | hcd->state = HC_STATE_RUNNING; |
671 | 681 | ||
672 | ohci_dump (ohci, 1); | 682 | ohci_dump (ohci, 1); |
673 | 683 | ||
674 | if (ohci_to_hcd(ohci)->self.root_hub == NULL) { | ||
675 | register_reboot_notifier (&ohci->reboot_notifier); | ||
676 | create_debug_files (ohci); | ||
677 | } | ||
678 | |||
679 | return 0; | 684 | return 0; |
680 | } | 685 | } |
681 | 686 | ||
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 4b2226d77b34..0bb972b58336 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -107,7 +107,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) | |||
107 | &ohci->regs->intrstatus); | 107 | &ohci->regs->intrstatus); |
108 | 108 | ||
109 | /* maybe resume can wake root hub */ | 109 | /* maybe resume can wake root hub */ |
110 | if (hcd->remote_wakeup) | 110 | if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) |
111 | ohci->hc_control |= OHCI_CTRL_RWE; | 111 | ohci->hc_control |= OHCI_CTRL_RWE; |
112 | else | 112 | else |
113 | ohci->hc_control &= ~OHCI_CTRL_RWE; | 113 | ohci->hc_control &= ~OHCI_CTRL_RWE; |
@@ -246,9 +246,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd) | |||
246 | (void) ohci_readl (ohci, &ohci->regs->control); | 246 | (void) ohci_readl (ohci, &ohci->regs->control); |
247 | msleep (3); | 247 | msleep (3); |
248 | 248 | ||
249 | temp = OHCI_CONTROL_INIT | OHCI_USB_OPER; | 249 | temp = ohci->hc_control; |
250 | if (hcd->can_wakeup) | 250 | temp &= OHCI_CTRL_RWC; |
251 | temp |= OHCI_CTRL_RWC; | 251 | temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER; |
252 | ohci->hc_control = temp; | 252 | ohci->hc_control = temp; |
253 | ohci_writel (ohci, temp, &ohci->regs->control); | 253 | ohci_writel (ohci, temp, &ohci->regs->control); |
254 | (void) ohci_readl (ohci, &ohci->regs->control); | 254 | (void) ohci_readl (ohci, &ohci->regs->control); |
@@ -302,7 +302,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
302 | { | 302 | { |
303 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 303 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
304 | int i, changed = 0, length = 1; | 304 | int i, changed = 0, length = 1; |
305 | int can_suspend = hcd->can_wakeup; | 305 | int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); |
306 | unsigned long flags; | 306 | unsigned long flags; |
307 | 307 | ||
308 | spin_lock_irqsave (&ohci->lock, flags); | 308 | spin_lock_irqsave (&ohci->lock, flags); |
@@ -354,7 +354,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
354 | */ | 354 | */ |
355 | if (!(status & RH_PS_CCS)) | 355 | if (!(status & RH_PS_CCS)) |
356 | continue; | 356 | continue; |
357 | if ((status & RH_PS_PSS) && hcd->remote_wakeup) | 357 | if ((status & RH_PS_PSS) && can_suspend) |
358 | continue; | 358 | continue; |
359 | can_suspend = 0; | 359 | can_suspend = 0; |
360 | } | 360 | } |
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 1b09dde068e1..1bfe96f4d045 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c | |||
@@ -35,7 +35,10 @@ ohci_pci_start (struct usb_hcd *hcd) | |||
35 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 35 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
36 | int ret; | 36 | int ret; |
37 | 37 | ||
38 | if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) { | 38 | /* REVISIT this whole block should move to reset(), which handles |
39 | * all the other one-time init. | ||
40 | */ | ||
41 | if (hcd->self.controller) { | ||
39 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | 42 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); |
40 | 43 | ||
41 | /* AMD 756, for most chips (early revs), corrupts register | 44 | /* AMD 756, for most chips (early revs), corrupts register |
@@ -45,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd) | |||
45 | && pdev->device == 0x740c) { | 48 | && pdev->device == 0x740c) { |
46 | ohci->flags = OHCI_QUIRK_AMD756; | 49 | ohci->flags = OHCI_QUIRK_AMD756; |
47 | ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); | 50 | ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); |
48 | // also somewhat erratum 10 (suspend/resume issues) | 51 | /* also erratum 10 (suspend/resume issues) */ |
52 | device_init_wakeup(&hcd->self.root_hub->dev, 0); | ||
49 | } | 53 | } |
50 | 54 | ||
51 | /* FIXME for some of the early AMD 760 southbridges, OHCI | 55 | /* FIXME for some of the early AMD 760 southbridges, OHCI |
@@ -88,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd) | |||
88 | ohci_dbg (ohci, | 92 | ohci_dbg (ohci, |
89 | "enabled Compaq ZFMicro chipset quirk\n"); | 93 | "enabled Compaq ZFMicro chipset quirk\n"); |
90 | } | 94 | } |
95 | |||
96 | /* RWC may not be set for add-in PCI cards, since boot | ||
97 | * firmware probably ignored them. This transfers PCI | ||
98 | * PM wakeup capabilities (once the PCI layer is fixed). | ||
99 | */ | ||
100 | if (device_may_wakeup(&pdev->dev)) | ||
101 | ohci->hc_control |= OHCI_CTRL_RWC; | ||
91 | } | 102 | } |
92 | 103 | ||
93 | /* NOTE: there may have already been a first reset, to | 104 | /* NOTE: there may have already been a first reset, to |