USB: new flag for resume-from-hibernation
This patch (as1237) changes the way the PCI host controller drivers avoid retaining bogus hardware states during resume-from-hibernation. Previously we had reset the hardware as part of preparing to reinstate the memory image. But we can do better now with the new PM framework, since we know exactly which resume operations are from hibernation. The pci_resume method is changed to accept a flag indicating whether the system is resuming from hibernation. When this flag is set, the drivers will reset the hardware to get rid of any existing state. Similarly, the pci_suspend method is changed to remove the pm_message_t argument. It's no longer needed, since no special action has to be taken when preparing to reinstate the memory image. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
abb306416a
commit
6ec4beb5c7
|
@ -237,7 +237,7 @@ static int hcd_pci_suspend(struct device *dev)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (hcd->driver->pci_suspend) {
|
if (hcd->driver->pci_suspend) {
|
||||||
retval = hcd->driver->pci_suspend(hcd, PMSG_SUSPEND);
|
retval = hcd->driver->pci_suspend(hcd);
|
||||||
suspend_report_result(hcd->driver->pci_suspend, retval);
|
suspend_report_result(hcd->driver->pci_suspend, retval);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -344,7 +344,7 @@ static int resume_common(struct device *dev, bool hibernated)
|
||||||
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||||
|
|
||||||
if (hcd->driver->pci_resume) {
|
if (hcd->driver->pci_resume) {
|
||||||
retval = hcd->driver->pci_resume(hcd);
|
retval = hcd->driver->pci_resume(hcd, hibernated);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
dev_err(dev, "PCI post-resume error %d!\n", retval);
|
dev_err(dev, "PCI post-resume error %d!\n", retval);
|
||||||
usb_hc_died(hcd);
|
usb_hc_died(hcd);
|
||||||
|
|
|
@ -182,10 +182,10 @@ struct hc_driver {
|
||||||
* a whole, not just the root hub; they're for PCI bus glue.
|
* a whole, not just the root hub; they're for PCI bus glue.
|
||||||
*/
|
*/
|
||||||
/* called after suspending the hub, before entering D3 etc */
|
/* called after suspending the hub, before entering D3 etc */
|
||||||
int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message);
|
int (*pci_suspend)(struct usb_hcd *hcd);
|
||||||
|
|
||||||
/* called after entering D0 (etc), before resuming the hub */
|
/* called after entering D0 (etc), before resuming the hub */
|
||||||
int (*pci_resume) (struct usb_hcd *hcd);
|
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
|
||||||
|
|
||||||
/* cleanly make HCD stop writing memory and doing I/O */
|
/* cleanly make HCD stop writing memory and doing I/O */
|
||||||
void (*stop) (struct usb_hcd *hcd);
|
void (*stop) (struct usb_hcd *hcd);
|
||||||
|
|
|
@ -268,7 +268,7 @@ done:
|
||||||
* Also they depend on separate root hub suspend/resume.
|
* Also they depend on separate root hub suspend/resume.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
static int ehci_pci_suspend(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -293,12 +293,6 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||||
|
|
||||||
/* make sure snapshot being resumed re-enumerates everything */
|
|
||||||
if (message.event == PM_EVENT_PRETHAW) {
|
|
||||||
ehci_halt(ehci);
|
|
||||||
ehci_reset(ehci);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
bail:
|
bail:
|
||||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||||
|
@ -309,7 +303,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ehci_pci_resume(struct usb_hcd *hcd)
|
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||||
{
|
{
|
||||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||||
|
@ -322,10 +316,12 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
|
|
||||||
/* If CF is still set, we maintained PCI Vaux power.
|
/* If CF is still set and we aren't resuming from hibernation
|
||||||
|
* then we maintained PCI Vaux power.
|
||||||
* Just undo the effect of ehci_pci_suspend().
|
* Just undo the effect of ehci_pci_suspend().
|
||||||
*/
|
*/
|
||||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
|
||||||
|
!hibernated) {
|
||||||
int mask = INTR_MASK;
|
int mask = INTR_MASK;
|
||||||
|
|
||||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||||
|
@ -335,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ehci_dbg(ehci, "lost power, restarting\n");
|
|
||||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||||
|
|
||||||
/* Else reset, to cope with power loss or flush-to-storage
|
/* Else reset, to cope with power loss or flush-to-storage
|
||||||
|
|
|
@ -372,7 +372,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
static int ohci_pci_suspend(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -394,10 +394,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
||||||
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
||||||
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
|
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
|
||||||
|
|
||||||
/* make sure snapshot being resumed re-enumerates everything */
|
|
||||||
if (message.event == PM_EVENT_PRETHAW)
|
|
||||||
ohci_usb_reset(ohci);
|
|
||||||
|
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
bail:
|
bail:
|
||||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||||
|
@ -406,9 +402,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ohci_pci_resume (struct usb_hcd *hcd)
|
static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||||
{
|
{
|
||||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
|
|
||||||
|
/* Make sure resume from hibernation re-enumerates everything */
|
||||||
|
if (hibernated)
|
||||||
|
ohci_usb_reset(hcd_to_ohci(hcd));
|
||||||
|
|
||||||
ohci_finish_controller_resume(hcd);
|
ohci_finish_controller_resume(hcd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -769,7 +769,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
static int uhci_pci_suspend(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -795,10 +795,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||||
|
|
||||||
/* FIXME: Enable non-PME# remote wakeup? */
|
/* FIXME: Enable non-PME# remote wakeup? */
|
||||||
|
|
||||||
/* make sure snapshot being resumed re-enumerates everything */
|
|
||||||
if (message.event == PM_EVENT_PRETHAW)
|
|
||||||
uhci_hc_died(uhci);
|
|
||||||
|
|
||||||
done_okay:
|
done_okay:
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
done:
|
done:
|
||||||
|
@ -806,7 +802,7 @@ done:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uhci_pci_resume(struct usb_hcd *hcd)
|
static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||||
{
|
{
|
||||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||||
|
|
||||||
|
@ -820,6 +816,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
|
||||||
|
|
||||||
spin_lock_irq(&uhci->lock);
|
spin_lock_irq(&uhci->lock);
|
||||||
|
|
||||||
|
/* Make sure resume from hibernation re-enumerates everything */
|
||||||
|
if (hibernated)
|
||||||
|
uhci_hc_died(uhci);
|
||||||
|
|
||||||
/* FIXME: Disable non-PME# remote wakeup? */
|
/* FIXME: Disable non-PME# remote wakeup? */
|
||||||
|
|
||||||
/* The firmware or a boot kernel may have changed the controller
|
/* The firmware or a boot kernel may have changed the controller
|
||||||
|
|
Loading…
Reference in New Issue