aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pci-driver.c134
1 files changed, 81 insertions, 53 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8395206d1aee..3c1831c82f5b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -352,53 +352,60 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
352{ 352{
353 struct pci_dev * pci_dev = to_pci_dev(dev); 353 struct pci_dev * pci_dev = to_pci_dev(dev);
354 struct pci_driver * drv = pci_dev->driver; 354 struct pci_driver * drv = pci_dev->driver;
355 int error = 0; 355
356 pci_dev->state_saved = false;
356 357
357 if (drv && drv->suspend) { 358 if (drv && drv->suspend) {
358 pci_power_t prev = pci_dev->current_state; 359 pci_power_t prev = pci_dev->current_state;
359 360 int error;
360 pci_dev->state_saved = false;
361 361
362 error = drv->suspend(pci_dev, state); 362 error = drv->suspend(pci_dev, state);
363 suspend_report_result(drv->suspend, error); 363 suspend_report_result(drv->suspend, error);
364 if (error) 364 if (error)
365 return error; 365 return error;
366 366
367 if (pci_dev->state_saved) 367 if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
368 goto Fixup;
369
370 if (pci_dev->current_state != PCI_D0
371 && pci_dev->current_state != PCI_UNKNOWN) { 368 && pci_dev->current_state != PCI_UNKNOWN) {
372 WARN_ONCE(pci_dev->current_state != prev, 369 WARN_ONCE(pci_dev->current_state != prev,
373 "PCI PM: Device state not saved by %pF\n", 370 "PCI PM: Device state not saved by %pF\n",
374 drv->suspend); 371 drv->suspend);
375 goto Fixup;
376 } 372 }
377 } 373 }
378 374
379 pci_save_state(pci_dev);
380 /*
381 * This is for compatibility with existing code with legacy PM support.
382 */
383 pci_pm_set_unknown_state(pci_dev);
384
385 Fixup:
386 pci_fixup_device(pci_fixup_suspend, pci_dev); 375 pci_fixup_device(pci_fixup_suspend, pci_dev);
387 376
388 return error; 377 return 0;
389} 378}
390 379
391static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) 380static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
392{ 381{
393 struct pci_dev * pci_dev = to_pci_dev(dev); 382 struct pci_dev * pci_dev = to_pci_dev(dev);
394 struct pci_driver * drv = pci_dev->driver; 383 struct pci_driver * drv = pci_dev->driver;
395 int error = 0;
396 384
397 if (drv && drv->suspend_late) { 385 if (drv && drv->suspend_late) {
386 pci_power_t prev = pci_dev->current_state;
387 int error;
388
398 error = drv->suspend_late(pci_dev, state); 389 error = drv->suspend_late(pci_dev, state);
399 suspend_report_result(drv->suspend_late, error); 390 suspend_report_result(drv->suspend_late, error);
391 if (error)
392 return error;
393
394 if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
395 && pci_dev->current_state != PCI_UNKNOWN) {
396 WARN_ONCE(pci_dev->current_state != prev,
397 "PCI PM: Device state not saved by %pF\n",
398 drv->suspend_late);
399 return 0;
400 }
400 } 401 }
401 return error; 402
403 if (!pci_dev->state_saved)
404 pci_save_state(pci_dev);
405
406 pci_pm_set_unknown_state(pci_dev);
407
408 return 0;
402} 409}
403 410
404static int pci_legacy_resume_early(struct device *dev) 411static int pci_legacy_resume_early(struct device *dev)
@@ -460,7 +467,6 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev)
460 /* Disable non-bridge devices without PM support */ 467 /* Disable non-bridge devices without PM support */
461 if (!pci_is_bridge(pci_dev)) 468 if (!pci_is_bridge(pci_dev))
462 pci_disable_enabled_device(pci_dev); 469 pci_disable_enabled_device(pci_dev);
463 pci_save_state(pci_dev);
464} 470}
465 471
466static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) 472static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
@@ -526,24 +532,14 @@ static int pci_pm_suspend(struct device *dev)
526 if (error) 532 if (error)
527 return error; 533 return error;
528 534
529 if (pci_dev->state_saved) 535 if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
530 goto Fixup;
531
532 if (pci_dev->current_state != PCI_D0
533 && pci_dev->current_state != PCI_UNKNOWN) { 536 && pci_dev->current_state != PCI_UNKNOWN) {
534 WARN_ONCE(pci_dev->current_state != prev, 537 WARN_ONCE(pci_dev->current_state != prev,
535 "PCI PM: State of device not saved by %pF\n", 538 "PCI PM: State of device not saved by %pF\n",
536 pm->suspend); 539 pm->suspend);
537 goto Fixup;
538 } 540 }
539 } 541 }
540 542
541 if (!pci_dev->state_saved) {
542 pci_save_state(pci_dev);
543 if (!pci_is_bridge(pci_dev))
544 pci_prepare_to_sleep(pci_dev);
545 }
546
547 Fixup: 543 Fixup:
548 pci_fixup_device(pci_fixup_suspend, pci_dev); 544 pci_fixup_device(pci_fixup_suspend, pci_dev);
549 545
@@ -553,21 +549,41 @@ static int pci_pm_suspend(struct device *dev)
553static int pci_pm_suspend_noirq(struct device *dev) 549static int pci_pm_suspend_noirq(struct device *dev)
554{ 550{
555 struct pci_dev *pci_dev = to_pci_dev(dev); 551 struct pci_dev *pci_dev = to_pci_dev(dev);
556 struct device_driver *drv = dev->driver; 552 struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
557 int error = 0;
558 553
559 if (pci_has_legacy_pm_support(pci_dev)) 554 if (pci_has_legacy_pm_support(pci_dev))
560 return pci_legacy_suspend_late(dev, PMSG_SUSPEND); 555 return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
561 556
562 if (drv && drv->pm && drv->pm->suspend_noirq) { 557 if (!pm)
563 error = drv->pm->suspend_noirq(dev); 558 return 0;
564 suspend_report_result(drv->pm->suspend_noirq, error); 559
560 if (pm->suspend_noirq) {
561 pci_power_t prev = pci_dev->current_state;
562 int error;
563
564 error = pm->suspend_noirq(dev);
565 suspend_report_result(pm->suspend_noirq, error);
566 if (error)
567 return error;
568
569 if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
570 && pci_dev->current_state != PCI_UNKNOWN) {
571 WARN_ONCE(pci_dev->current_state != prev,
572 "PCI PM: State of device not saved by %pF\n",
573 pm->suspend_noirq);
574 return 0;
575 }
565 } 576 }
566 577
567 if (!error) 578 if (!pci_dev->state_saved) {
568 pci_pm_set_unknown_state(pci_dev); 579 pci_save_state(pci_dev);
580 if (!pci_is_bridge(pci_dev))
581 pci_prepare_to_sleep(pci_dev);
582 }
569 583
570 return error; 584 pci_pm_set_unknown_state(pci_dev);
585
586 return 0;
571} 587}
572 588
573static int pci_pm_resume_noirq(struct device *dev) 589static int pci_pm_resume_noirq(struct device *dev)
@@ -650,9 +666,6 @@ static int pci_pm_freeze(struct device *dev)
650 return error; 666 return error;
651 } 667 }
652 668
653 if (!pci_dev->state_saved)
654 pci_save_state(pci_dev);
655
656 return 0; 669 return 0;
657} 670}
658 671
@@ -660,20 +673,25 @@ static int pci_pm_freeze_noirq(struct device *dev)
660{ 673{
661 struct pci_dev *pci_dev = to_pci_dev(dev); 674 struct pci_dev *pci_dev = to_pci_dev(dev);
662 struct device_driver *drv = dev->driver; 675 struct device_driver *drv = dev->driver;
663 int error = 0;
664 676
665 if (pci_has_legacy_pm_support(pci_dev)) 677 if (pci_has_legacy_pm_support(pci_dev))
666 return pci_legacy_suspend_late(dev, PMSG_FREEZE); 678 return pci_legacy_suspend_late(dev, PMSG_FREEZE);
667 679
668 if (drv && drv->pm && drv->pm->freeze_noirq) { 680 if (drv && drv->pm && drv->pm->freeze_noirq) {
681 int error;
682
669 error = drv->pm->freeze_noirq(dev); 683 error = drv->pm->freeze_noirq(dev);
670 suspend_report_result(drv->pm->freeze_noirq, error); 684 suspend_report_result(drv->pm->freeze_noirq, error);
685 if (error)
686 return error;
671 } 687 }
672 688
673 if (!error) 689 if (!pci_dev->state_saved)
674 pci_pm_set_unknown_state(pci_dev); 690 pci_save_state(pci_dev);
675 691
676 return error; 692 pci_pm_set_unknown_state(pci_dev);
693
694 return 0;
677} 695}
678 696
679static int pci_pm_thaw_noirq(struct device *dev) 697static int pci_pm_thaw_noirq(struct device *dev)
@@ -716,7 +734,6 @@ static int pci_pm_poweroff(struct device *dev)
716{ 734{
717 struct pci_dev *pci_dev = to_pci_dev(dev); 735 struct pci_dev *pci_dev = to_pci_dev(dev);
718 struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 736 struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
719 int error = 0;
720 737
721 if (pci_has_legacy_pm_support(pci_dev)) 738 if (pci_has_legacy_pm_support(pci_dev))
722 return pci_legacy_suspend(dev, PMSG_HIBERNATE); 739 return pci_legacy_suspend(dev, PMSG_HIBERNATE);
@@ -729,33 +746,44 @@ static int pci_pm_poweroff(struct device *dev)
729 pci_dev->state_saved = false; 746 pci_dev->state_saved = false;
730 747
731 if (pm->poweroff) { 748 if (pm->poweroff) {
749 int error;
750
732 error = pm->poweroff(dev); 751 error = pm->poweroff(dev);
733 suspend_report_result(pm->poweroff, error); 752 suspend_report_result(pm->poweroff, error);
753 if (error)
754 return error;
734 } 755 }
735 756
736 if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
737 pci_prepare_to_sleep(pci_dev);
738
739 Fixup: 757 Fixup:
740 pci_fixup_device(pci_fixup_suspend, pci_dev); 758 pci_fixup_device(pci_fixup_suspend, pci_dev);
741 759
742 return error; 760 return 0;
743} 761}
744 762
745static int pci_pm_poweroff_noirq(struct device *dev) 763static int pci_pm_poweroff_noirq(struct device *dev)
746{ 764{
765 struct pci_dev *pci_dev = to_pci_dev(dev);
747 struct device_driver *drv = dev->driver; 766 struct device_driver *drv = dev->driver;
748 int error = 0;
749 767
750 if (pci_has_legacy_pm_support(to_pci_dev(dev))) 768 if (pci_has_legacy_pm_support(to_pci_dev(dev)))
751 return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); 769 return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
752 770
753 if (drv && drv->pm && drv->pm->poweroff_noirq) { 771 if (!drv || !drv->pm)
772 return 0;
773
774 if (drv->pm->poweroff_noirq) {
775 int error;
776
754 error = drv->pm->poweroff_noirq(dev); 777 error = drv->pm->poweroff_noirq(dev);
755 suspend_report_result(drv->pm->poweroff_noirq, error); 778 suspend_report_result(drv->pm->poweroff_noirq, error);
779 if (error)
780 return error;
756 } 781 }
757 782
758 return error; 783 if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
784 pci_prepare_to_sleep(pci_dev);
785
786 return 0;
759} 787}
760 788
761static int pci_pm_restore_noirq(struct device *dev) 789static int pci_pm_restore_noirq(struct device *dev)