aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-driver.c
diff options
context:
space:
mode:
authorEric Miao <eric.miao@marvell.com>2009-03-09 09:21:07 -0400
committerEric Miao <eric.miao@marvell.com>2009-03-09 09:21:07 -0400
commitabcea2c322cef559ef2f108b4763d107a5ccc37f (patch)
tree5fec7fec372f9bdb70703f6c77bfc49cda945442 /drivers/pci/pci-driver.c
parent8118aea23c328fd4913b325af53fda9d530b1d56 (diff)
parent6d831c6554e4f95083919914955a1a3a4a6acfa9 (diff)
Merge branch 'devel' of ssh://master.kernel.org/home/rmk/linux-2.6-arm into devel
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r--drivers/pci/pci-driver.c112
1 files changed, 47 insertions, 65 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index c697f2680856..ab1d615425a8 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -355,17 +355,28 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
355 int i = 0; 355 int i = 0;
356 356
357 if (drv && drv->suspend) { 357 if (drv && drv->suspend) {
358 pci_dev->state_saved = false;
359
358 i = drv->suspend(pci_dev, state); 360 i = drv->suspend(pci_dev, state);
359 suspend_report_result(drv->suspend, i); 361 suspend_report_result(drv->suspend, i);
360 } else { 362 if (i)
361 pci_save_state(pci_dev); 363 return i;
362 /* 364
363 * This is for compatibility with existing code with legacy PM 365 if (pci_dev->state_saved)
364 * support. 366 goto Fixup;
365 */ 367
366 pci_pm_set_unknown_state(pci_dev); 368 if (WARN_ON_ONCE(pci_dev->current_state != PCI_D0))
369 goto Fixup;
367 } 370 }
368 371
372 pci_save_state(pci_dev);
373 pci_dev->state_saved = true;
374 /*
375 * This is for compatibility with existing code with legacy PM support.
376 */
377 pci_pm_set_unknown_state(pci_dev);
378
379 Fixup:
369 pci_fixup_device(pci_fixup_suspend, pci_dev); 380 pci_fixup_device(pci_fixup_suspend, pci_dev);
370 381
371 return i; 382 return i;
@@ -386,81 +397,35 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
386 397
387static int pci_legacy_resume_early(struct device *dev) 398static int pci_legacy_resume_early(struct device *dev)
388{ 399{
389 int error = 0;
390 struct pci_dev * pci_dev = to_pci_dev(dev); 400 struct pci_dev * pci_dev = to_pci_dev(dev);
391 struct pci_driver * drv = pci_dev->driver; 401 struct pci_driver * drv = pci_dev->driver;
392 402
393 pci_fixup_device(pci_fixup_resume_early, pci_dev); 403 return drv && drv->resume_early ?
394 404 drv->resume_early(pci_dev) : 0;
395 if (drv && drv->resume_early)
396 error = drv->resume_early(pci_dev);
397 return error;
398} 405}
399 406
400static int pci_legacy_resume(struct device *dev) 407static int pci_legacy_resume(struct device *dev)
401{ 408{
402 int error;
403 struct pci_dev * pci_dev = to_pci_dev(dev); 409 struct pci_dev * pci_dev = to_pci_dev(dev);
404 struct pci_driver * drv = pci_dev->driver; 410 struct pci_driver * drv = pci_dev->driver;
405 411
406 pci_fixup_device(pci_fixup_resume, pci_dev); 412 pci_fixup_device(pci_fixup_resume, pci_dev);
407 413
408 if (drv && drv->resume) { 414 return drv && drv->resume ?
409 error = drv->resume(pci_dev); 415 drv->resume(pci_dev) : pci_pm_reenable_device(pci_dev);
410 } else {
411 /* restore the PCI config space */
412 pci_restore_state(pci_dev);
413 error = pci_pm_reenable_device(pci_dev);
414 }
415 return error;
416} 416}
417 417
418/* Auxiliary functions used by the new power management framework */ 418/* Auxiliary functions used by the new power management framework */
419 419
420static int pci_restore_standard_config(struct pci_dev *pci_dev)
421{
422 struct pci_dev *parent = pci_dev->bus->self;
423 int error = 0;
424
425 /* Check if the device's bus is operational */
426 if (!parent || parent->current_state == PCI_D0) {
427 pci_restore_state(pci_dev);
428 pci_update_current_state(pci_dev, PCI_D0);
429 } else {
430 dev_warn(&pci_dev->dev, "unable to restore config, "
431 "bridge %s in low power state D%d\n", pci_name(parent),
432 parent->current_state);
433 pci_dev->current_state = PCI_UNKNOWN;
434 error = -EAGAIN;
435 }
436
437 return error;
438}
439
440static bool pci_is_bridge(struct pci_dev *pci_dev)
441{
442 return !!(pci_dev->subordinate);
443}
444
445static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) 420static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
446{ 421{
447 if (pci_restore_standard_config(pci_dev)) 422 pci_restore_standard_config(pci_dev);
448 pci_fixup_device(pci_fixup_resume_early, pci_dev); 423 pci_dev->state_saved = false;
424 pci_fixup_device(pci_fixup_resume_early, pci_dev);
449} 425}
450 426
451static int pci_pm_default_resume(struct pci_dev *pci_dev) 427static int pci_pm_default_resume(struct pci_dev *pci_dev)
452{ 428{
453 /*
454 * pci_restore_standard_config() should have been called once already,
455 * but it would have failed if the device's parent bridge had not been
456 * in power state D0 at that time. Check it and try again if necessary.
457 */
458 if (pci_dev->current_state == PCI_UNKNOWN) {
459 int error = pci_restore_standard_config(pci_dev);
460 if (error)
461 return error;
462 }
463
464 pci_fixup_device(pci_fixup_resume, pci_dev); 429 pci_fixup_device(pci_fixup_resume, pci_dev);
465 430
466 if (!pci_is_bridge(pci_dev)) 431 if (!pci_is_bridge(pci_dev))
@@ -575,11 +540,11 @@ static int pci_pm_resume_noirq(struct device *dev)
575 struct device_driver *drv = dev->driver; 540 struct device_driver *drv = dev->driver;
576 int error = 0; 541 int error = 0;
577 542
543 pci_pm_default_resume_noirq(pci_dev);
544
578 if (pci_has_legacy_pm_support(pci_dev)) 545 if (pci_has_legacy_pm_support(pci_dev))
579 return pci_legacy_resume_early(dev); 546 return pci_legacy_resume_early(dev);
580 547
581 pci_pm_default_resume_noirq(pci_dev);
582
583 if (drv && drv->pm && drv->pm->resume_noirq) 548 if (drv && drv->pm && drv->pm->resume_noirq)
584 error = drv->pm->resume_noirq(dev); 549 error = drv->pm->resume_noirq(dev);
585 550
@@ -592,6 +557,13 @@ static int pci_pm_resume(struct device *dev)
592 struct device_driver *drv = dev->driver; 557 struct device_driver *drv = dev->driver;
593 int error = 0; 558 int error = 0;
594 559
560 /*
561 * This is necessary for the suspend error path in which resume is
562 * called without restoring the standard config registers of the device.
563 */
564 if (pci_dev->state_saved)
565 pci_restore_standard_config(pci_dev);
566
595 if (pci_has_legacy_pm_support(pci_dev)) 567 if (pci_has_legacy_pm_support(pci_dev))
596 return pci_legacy_resume(dev); 568 return pci_legacy_resume(dev);
597 569
@@ -697,7 +669,10 @@ static int pci_pm_poweroff(struct device *dev)
697 if (pci_has_legacy_pm_support(pci_dev)) 669 if (pci_has_legacy_pm_support(pci_dev))
698 return pci_legacy_suspend(dev, PMSG_HIBERNATE); 670 return pci_legacy_suspend(dev, PMSG_HIBERNATE);
699 671
700 if (drv && drv->pm && drv->pm->poweroff) { 672 if (!drv || !drv->pm)
673 return 0;
674
675 if (drv->pm->poweroff) {
701 error = drv->pm->poweroff(dev); 676 error = drv->pm->poweroff(dev);
702 suspend_report_result(drv->pm->poweroff, error); 677 suspend_report_result(drv->pm->poweroff, error);
703 } 678 }
@@ -730,11 +705,11 @@ static int pci_pm_restore_noirq(struct device *dev)
730 struct device_driver *drv = dev->driver; 705 struct device_driver *drv = dev->driver;
731 int error = 0; 706 int error = 0;
732 707
708 pci_pm_default_resume_noirq(pci_dev);
709
733 if (pci_has_legacy_pm_support(pci_dev)) 710 if (pci_has_legacy_pm_support(pci_dev))
734 return pci_legacy_resume_early(dev); 711 return pci_legacy_resume_early(dev);
735 712
736 pci_pm_default_resume_noirq(pci_dev);
737
738 if (drv && drv->pm && drv->pm->restore_noirq) 713 if (drv && drv->pm && drv->pm->restore_noirq)
739 error = drv->pm->restore_noirq(dev); 714 error = drv->pm->restore_noirq(dev);
740 715
@@ -747,6 +722,13 @@ static int pci_pm_restore(struct device *dev)
747 struct device_driver *drv = dev->driver; 722 struct device_driver *drv = dev->driver;
748 int error = 0; 723 int error = 0;
749 724
725 /*
726 * This is necessary for the hibernation error path in which restore is
727 * called without restoring the standard config registers of the device.
728 */
729 if (pci_dev->state_saved)
730 pci_restore_standard_config(pci_dev);
731
750 if (pci_has_legacy_pm_support(pci_dev)) 732 if (pci_has_legacy_pm_support(pci_dev))
751 return pci_legacy_resume(dev); 733 return pci_legacy_resume(dev);
752 734