aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-04-27 13:33:41 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:44 -0400
commit6ec4beb5c701f728548b587082c83ef62eb36035 (patch)
treec5450f6e40f3656b5e27a0ca30adda2a16ad303f /drivers/usb
parentabb306416a7ec2386678de0da6b632a6cb068af0 (diff)
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/hcd-pci.c4
-rw-r--r--drivers/usb/core/hcd.h4
-rw-r--r--drivers/usb/host/ehci-pci.c17
-rw-r--r--drivers/usb/host/ohci-pci.c13
-rw-r--r--drivers/usb/host/uhci-hcd.c12
5 files changed, 23 insertions, 27 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 5db4d40db832..91f2885b6ee1 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -237,7 +237,7 @@ static int hcd_pci_suspend(struct device *dev)
237 return retval; 237 return retval;
238 238
239 if (hcd->driver->pci_suspend) { 239 if (hcd->driver->pci_suspend) {
240 retval = hcd->driver->pci_suspend(hcd, PMSG_SUSPEND); 240 retval = hcd->driver->pci_suspend(hcd);
241 suspend_report_result(hcd->driver->pci_suspend, retval); 241 suspend_report_result(hcd->driver->pci_suspend, retval);
242 if (retval) 242 if (retval)
243 return retval; 243 return retval;
@@ -344,7 +344,7 @@ static int resume_common(struct device *dev, bool hibernated)
344 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 344 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
345 345
346 if (hcd->driver->pci_resume) { 346 if (hcd->driver->pci_resume) {
347 retval = hcd->driver->pci_resume(hcd); 347 retval = hcd->driver->pci_resume(hcd, hibernated);
348 if (retval) { 348 if (retval) {
349 dev_err(dev, "PCI post-resume error %d!\n", retval); 349 dev_err(dev, "PCI post-resume error %d!\n", retval);
350 usb_hc_died(hcd); 350 usb_hc_died(hcd);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 7f068d6e6940..174170f14f06 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -182,10 +182,10 @@ struct hc_driver {
182 * a whole, not just the root hub; they're for PCI bus glue. 182 * a whole, not just the root hub; they're for PCI bus glue.
183 */ 183 */
184 /* called after suspending the hub, before entering D3 etc */ 184 /* called after suspending the hub, before entering D3 etc */
185 int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message); 185 int (*pci_suspend)(struct usb_hcd *hcd);
186 186
187 /* called after entering D0 (etc), before resuming the hub */ 187 /* called after entering D0 (etc), before resuming the hub */
188 int (*pci_resume) (struct usb_hcd *hcd); 188 int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
189 189
190 /* cleanly make HCD stop writing memory and doing I/O */ 190 /* cleanly make HCD stop writing memory and doing I/O */
191 void (*stop) (struct usb_hcd *hcd); 191 void (*stop) (struct usb_hcd *hcd);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 8172383e8908..e74948898f76 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -268,7 +268,7 @@ done:
268 * Also they depend on separate root hub suspend/resume. 268 * Also they depend on separate root hub suspend/resume.
269 */ 269 */
270 270
271static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) 271static int ehci_pci_suspend(struct usb_hcd *hcd)
272{ 272{
273 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 273 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
274 unsigned long flags; 274 unsigned long flags;
@@ -293,12 +293,6 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
293 ehci_writel(ehci, 0, &ehci->regs->intr_enable); 293 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
294 (void)ehci_readl(ehci, &ehci->regs->intr_enable); 294 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
295 295
296 /* make sure snapshot being resumed re-enumerates everything */
297 if (message.event == PM_EVENT_PRETHAW) {
298 ehci_halt(ehci);
299 ehci_reset(ehci);
300 }
301
302 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 296 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
303 bail: 297 bail:
304 spin_unlock_irqrestore (&ehci->lock, flags); 298 spin_unlock_irqrestore (&ehci->lock, flags);
@@ -309,7 +303,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
309 return rc; 303 return rc;
310} 304}
311 305
312static int ehci_pci_resume(struct usb_hcd *hcd) 306static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
313{ 307{
314 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 308 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
315 struct pci_dev *pdev = to_pci_dev(hcd->self.controller); 309 struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
@@ -322,10 +316,12 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
322 /* Mark hardware accessible again as we are out of D3 state by now */ 316 /* Mark hardware accessible again as we are out of D3 state by now */
323 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 317 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
324 318
325 /* If CF is still set, we maintained PCI Vaux power. 319 /* If CF is still set and we aren't resuming from hibernation
320 * then we maintained PCI Vaux power.
326 * Just undo the effect of ehci_pci_suspend(). 321 * Just undo the effect of ehci_pci_suspend().
327 */ 322 */
328 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { 323 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
324 !hibernated) {
329 int mask = INTR_MASK; 325 int mask = INTR_MASK;
330 326
331 if (!hcd->self.root_hub->do_remote_wakeup) 327 if (!hcd->self.root_hub->do_remote_wakeup)
@@ -335,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
335 return 0; 331 return 0;
336 } 332 }
337 333
338 ehci_dbg(ehci, "lost power, restarting\n");
339 usb_root_hub_lost_power(hcd->self.root_hub); 334 usb_root_hub_lost_power(hcd->self.root_hub);
340 335
341 /* Else reset, to cope with power loss or flush-to-storage 336 /* Else reset, to cope with power loss or flush-to-storage
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index ee0a68ca5fda..d2ba04dd785e 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -372,7 +372,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
372 372
373#ifdef CONFIG_PM 373#ifdef CONFIG_PM
374 374
375static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) 375static int ohci_pci_suspend(struct usb_hcd *hcd)
376{ 376{
377 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 377 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
378 unsigned long flags; 378 unsigned long flags;
@@ -394,10 +394,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
394 ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); 394 ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
395 (void)ohci_readl(ohci, &ohci->regs->intrdisable); 395 (void)ohci_readl(ohci, &ohci->regs->intrdisable);
396 396
397 /* make sure snapshot being resumed re-enumerates everything */
398 if (message.event == PM_EVENT_PRETHAW)
399 ohci_usb_reset(ohci);
400
401 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 397 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
402 bail: 398 bail:
403 spin_unlock_irqrestore (&ohci->lock, flags); 399 spin_unlock_irqrestore (&ohci->lock, flags);
@@ -406,9 +402,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
406} 402}
407 403
408 404
409static int ohci_pci_resume (struct usb_hcd *hcd) 405static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated)
410{ 406{
411 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 407 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
408
409 /* Make sure resume from hibernation re-enumerates everything */
410 if (hibernated)
411 ohci_usb_reset(hcd_to_ohci(hcd));
412
412 ohci_finish_controller_resume(hcd); 413 ohci_finish_controller_resume(hcd);
413 return 0; 414 return 0;
414} 415}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index c0133211e3ec..274751b4409c 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -769,7 +769,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
769 return rc; 769 return rc;
770} 770}
771 771
772static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) 772static int uhci_pci_suspend(struct usb_hcd *hcd)
773{ 773{
774 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 774 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
775 int rc = 0; 775 int rc = 0;
@@ -795,10 +795,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
795 795
796 /* FIXME: Enable non-PME# remote wakeup? */ 796 /* FIXME: Enable non-PME# remote wakeup? */
797 797
798 /* make sure snapshot being resumed re-enumerates everything */
799 if (message.event == PM_EVENT_PRETHAW)
800 uhci_hc_died(uhci);
801
802done_okay: 798done_okay:
803 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 799 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
804done: 800done:
@@ -806,7 +802,7 @@ done:
806 return rc; 802 return rc;
807} 803}
808 804
809static int uhci_pci_resume(struct usb_hcd *hcd) 805static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
810{ 806{
811 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 807 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
812 808
@@ -820,6 +816,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
820 816
821 spin_lock_irq(&uhci->lock); 817 spin_lock_irq(&uhci->lock);
822 818
819 /* Make sure resume from hibernation re-enumerates everything */
820 if (hibernated)
821 uhci_hc_died(uhci);
822
823 /* FIXME: Disable non-PME# remote wakeup? */ 823 /* FIXME: Disable non-PME# remote wakeup? */
824 824
825 /* The firmware or a boot kernel may have changed the controller 825 /* The firmware or a boot kernel may have changed the controller