diff options
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 177 |
1 files changed, 121 insertions, 56 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 9de07b75b993..93eac1423585 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -355,6 +355,8 @@ 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_power_t prev = pci_dev->current_state; | ||
359 | |||
358 | pci_dev->state_saved = false; | 360 | pci_dev->state_saved = false; |
359 | 361 | ||
360 | i = drv->suspend(pci_dev, state); | 362 | i = drv->suspend(pci_dev, state); |
@@ -365,8 +367,13 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state) | |||
365 | if (pci_dev->state_saved) | 367 | if (pci_dev->state_saved) |
366 | goto Fixup; | 368 | goto Fixup; |
367 | 369 | ||
368 | if (WARN_ON_ONCE(pci_dev->current_state != PCI_D0)) | 370 | if (pci_dev->current_state != PCI_D0 |
371 | && pci_dev->current_state != PCI_UNKNOWN) { | ||
372 | WARN_ONCE(pci_dev->current_state != prev, | ||
373 | "PCI PM: Device state not saved by %pF\n", | ||
374 | drv->suspend); | ||
369 | goto Fixup; | 375 | goto Fixup; |
376 | } | ||
370 | } | 377 | } |
371 | 378 | ||
372 | pci_save_state(pci_dev); | 379 | pci_save_state(pci_dev); |
@@ -419,38 +426,24 @@ static int pci_legacy_resume(struct device *dev) | |||
419 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) | 426 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) |
420 | { | 427 | { |
421 | pci_restore_standard_config(pci_dev); | 428 | pci_restore_standard_config(pci_dev); |
429 | pci_dev->state_saved = false; | ||
422 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 430 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
423 | } | 431 | } |
424 | 432 | ||
425 | static int pci_pm_default_resume(struct pci_dev *pci_dev) | 433 | static void pci_pm_default_resume(struct pci_dev *pci_dev) |
426 | { | 434 | { |
427 | pci_fixup_device(pci_fixup_resume, pci_dev); | 435 | pci_fixup_device(pci_fixup_resume, pci_dev); |
428 | 436 | ||
429 | if (!pci_is_bridge(pci_dev)) | 437 | if (!pci_is_bridge(pci_dev)) |
430 | pci_enable_wake(pci_dev, PCI_D0, false); | 438 | pci_enable_wake(pci_dev, PCI_D0, false); |
431 | |||
432 | return pci_pm_reenable_device(pci_dev); | ||
433 | } | ||
434 | |||
435 | static void pci_pm_default_suspend_generic(struct pci_dev *pci_dev) | ||
436 | { | ||
437 | /* If device is enabled at this point, disable it */ | ||
438 | pci_disable_enabled_device(pci_dev); | ||
439 | /* | ||
440 | * Save state with interrupts enabled, because in principle the bus the | ||
441 | * device is on may be put into a low power state after this code runs. | ||
442 | */ | ||
443 | pci_save_state(pci_dev); | ||
444 | } | 439 | } |
445 | 440 | ||
446 | static void pci_pm_default_suspend(struct pci_dev *pci_dev) | 441 | static void pci_pm_default_suspend(struct pci_dev *pci_dev) |
447 | { | 442 | { |
448 | pci_pm_default_suspend_generic(pci_dev); | 443 | /* Disable non-bridge devices without PM support */ |
449 | |||
450 | if (!pci_is_bridge(pci_dev)) | 444 | if (!pci_is_bridge(pci_dev)) |
451 | pci_prepare_to_sleep(pci_dev); | 445 | pci_disable_enabled_device(pci_dev); |
452 | 446 | pci_save_state(pci_dev); | |
453 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
454 | } | 447 | } |
455 | 448 | ||
456 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) | 449 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) |
@@ -495,21 +488,49 @@ static void pci_pm_complete(struct device *dev) | |||
495 | static int pci_pm_suspend(struct device *dev) | 488 | static int pci_pm_suspend(struct device *dev) |
496 | { | 489 | { |
497 | struct pci_dev *pci_dev = to_pci_dev(dev); | 490 | struct pci_dev *pci_dev = to_pci_dev(dev); |
498 | struct device_driver *drv = dev->driver; | 491 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
499 | int error = 0; | ||
500 | 492 | ||
501 | if (pci_has_legacy_pm_support(pci_dev)) | 493 | if (pci_has_legacy_pm_support(pci_dev)) |
502 | return pci_legacy_suspend(dev, PMSG_SUSPEND); | 494 | return pci_legacy_suspend(dev, PMSG_SUSPEND); |
503 | 495 | ||
504 | if (drv && drv->pm && drv->pm->suspend) { | 496 | if (!pm) { |
505 | error = drv->pm->suspend(dev); | 497 | pci_pm_default_suspend(pci_dev); |
506 | suspend_report_result(drv->pm->suspend, error); | 498 | goto Fixup; |
507 | } | 499 | } |
508 | 500 | ||
509 | if (!error) | 501 | pci_dev->state_saved = false; |
510 | pci_pm_default_suspend(pci_dev); | ||
511 | 502 | ||
512 | return error; | 503 | if (pm->suspend) { |
504 | pci_power_t prev = pci_dev->current_state; | ||
505 | int error; | ||
506 | |||
507 | error = pm->suspend(dev); | ||
508 | suspend_report_result(pm->suspend, error); | ||
509 | if (error) | ||
510 | return error; | ||
511 | |||
512 | if (pci_dev->state_saved) | ||
513 | goto Fixup; | ||
514 | |||
515 | if (pci_dev->current_state != PCI_D0 | ||
516 | && pci_dev->current_state != PCI_UNKNOWN) { | ||
517 | WARN_ONCE(pci_dev->current_state != prev, | ||
518 | "PCI PM: State of device not saved by %pF\n", | ||
519 | pm->suspend); | ||
520 | goto Fixup; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | if (!pci_dev->state_saved) { | ||
525 | pci_save_state(pci_dev); | ||
526 | if (!pci_is_bridge(pci_dev)) | ||
527 | pci_prepare_to_sleep(pci_dev); | ||
528 | } | ||
529 | |||
530 | Fixup: | ||
531 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
532 | |||
533 | return 0; | ||
513 | } | 534 | } |
514 | 535 | ||
515 | static int pci_pm_suspend_noirq(struct device *dev) | 536 | static int pci_pm_suspend_noirq(struct device *dev) |
@@ -552,18 +573,29 @@ static int pci_pm_resume_noirq(struct device *dev) | |||
552 | static int pci_pm_resume(struct device *dev) | 573 | static int pci_pm_resume(struct device *dev) |
553 | { | 574 | { |
554 | struct pci_dev *pci_dev = to_pci_dev(dev); | 575 | struct pci_dev *pci_dev = to_pci_dev(dev); |
555 | struct device_driver *drv = dev->driver; | 576 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
556 | int error = 0; | 577 | int error = 0; |
557 | 578 | ||
579 | /* | ||
580 | * This is necessary for the suspend error path in which resume is | ||
581 | * called without restoring the standard config registers of the device. | ||
582 | */ | ||
583 | if (pci_dev->state_saved) | ||
584 | pci_restore_standard_config(pci_dev); | ||
585 | |||
558 | if (pci_has_legacy_pm_support(pci_dev)) | 586 | if (pci_has_legacy_pm_support(pci_dev)) |
559 | return pci_legacy_resume(dev); | 587 | return pci_legacy_resume(dev); |
560 | 588 | ||
561 | error = pci_pm_default_resume(pci_dev); | 589 | pci_pm_default_resume(pci_dev); |
562 | 590 | ||
563 | if (!error && drv && drv->pm && drv->pm->resume) | 591 | if (pm) { |
564 | error = drv->pm->resume(dev); | 592 | if (pm->resume) |
593 | error = pm->resume(dev); | ||
594 | } else { | ||
595 | pci_pm_reenable_device(pci_dev); | ||
596 | } | ||
565 | 597 | ||
566 | return error; | 598 | return 0; |
567 | } | 599 | } |
568 | 600 | ||
569 | #else /* !CONFIG_SUSPEND */ | 601 | #else /* !CONFIG_SUSPEND */ |
@@ -580,21 +612,31 @@ static int pci_pm_resume(struct device *dev) | |||
580 | static int pci_pm_freeze(struct device *dev) | 612 | static int pci_pm_freeze(struct device *dev) |
581 | { | 613 | { |
582 | struct pci_dev *pci_dev = to_pci_dev(dev); | 614 | struct pci_dev *pci_dev = to_pci_dev(dev); |
583 | struct device_driver *drv = dev->driver; | 615 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
584 | int error = 0; | ||
585 | 616 | ||
586 | if (pci_has_legacy_pm_support(pci_dev)) | 617 | if (pci_has_legacy_pm_support(pci_dev)) |
587 | return pci_legacy_suspend(dev, PMSG_FREEZE); | 618 | return pci_legacy_suspend(dev, PMSG_FREEZE); |
588 | 619 | ||
589 | if (drv && drv->pm && drv->pm->freeze) { | 620 | if (!pm) { |
590 | error = drv->pm->freeze(dev); | 621 | pci_pm_default_suspend(pci_dev); |
591 | suspend_report_result(drv->pm->freeze, error); | 622 | return 0; |
623 | } | ||
624 | |||
625 | pci_dev->state_saved = false; | ||
626 | |||
627 | if (pm->freeze) { | ||
628 | int error; | ||
629 | |||
630 | error = pm->freeze(dev); | ||
631 | suspend_report_result(pm->freeze, error); | ||
632 | if (error) | ||
633 | return error; | ||
592 | } | 634 | } |
593 | 635 | ||
594 | if (!error) | 636 | if (!pci_dev->state_saved) |
595 | pci_pm_default_suspend_generic(pci_dev); | 637 | pci_save_state(pci_dev); |
596 | 638 | ||
597 | return error; | 639 | return 0; |
598 | } | 640 | } |
599 | 641 | ||
600 | static int pci_pm_freeze_noirq(struct device *dev) | 642 | static int pci_pm_freeze_noirq(struct device *dev) |
@@ -637,16 +679,18 @@ static int pci_pm_thaw_noirq(struct device *dev) | |||
637 | static int pci_pm_thaw(struct device *dev) | 679 | static int pci_pm_thaw(struct device *dev) |
638 | { | 680 | { |
639 | struct pci_dev *pci_dev = to_pci_dev(dev); | 681 | struct pci_dev *pci_dev = to_pci_dev(dev); |
640 | struct device_driver *drv = dev->driver; | 682 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
641 | int error = 0; | 683 | int error = 0; |
642 | 684 | ||
643 | if (pci_has_legacy_pm_support(pci_dev)) | 685 | if (pci_has_legacy_pm_support(pci_dev)) |
644 | return pci_legacy_resume(dev); | 686 | return pci_legacy_resume(dev); |
645 | 687 | ||
646 | pci_pm_reenable_device(pci_dev); | 688 | if (pm) { |
647 | 689 | if (pm->thaw) | |
648 | if (drv && drv->pm && drv->pm->thaw) | 690 | error = pm->thaw(dev); |
649 | error = drv->pm->thaw(dev); | 691 | } else { |
692 | pci_pm_reenable_device(pci_dev); | ||
693 | } | ||
650 | 694 | ||
651 | return error; | 695 | return error; |
652 | } | 696 | } |
@@ -654,19 +698,29 @@ static int pci_pm_thaw(struct device *dev) | |||
654 | static int pci_pm_poweroff(struct device *dev) | 698 | static int pci_pm_poweroff(struct device *dev) |
655 | { | 699 | { |
656 | struct pci_dev *pci_dev = to_pci_dev(dev); | 700 | struct pci_dev *pci_dev = to_pci_dev(dev); |
657 | struct device_driver *drv = dev->driver; | 701 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
658 | int error = 0; | 702 | int error = 0; |
659 | 703 | ||
660 | if (pci_has_legacy_pm_support(pci_dev)) | 704 | if (pci_has_legacy_pm_support(pci_dev)) |
661 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); | 705 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); |
662 | 706 | ||
663 | if (drv && drv->pm && drv->pm->poweroff) { | 707 | if (!pm) { |
664 | error = drv->pm->poweroff(dev); | 708 | pci_pm_default_suspend(pci_dev); |
665 | suspend_report_result(drv->pm->poweroff, error); | 709 | goto Fixup; |
666 | } | 710 | } |
667 | 711 | ||
668 | if (!error) | 712 | pci_dev->state_saved = false; |
669 | pci_pm_default_suspend(pci_dev); | 713 | |
714 | if (pm->poweroff) { | ||
715 | error = pm->poweroff(dev); | ||
716 | suspend_report_result(pm->poweroff, error); | ||
717 | } | ||
718 | |||
719 | if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) | ||
720 | pci_prepare_to_sleep(pci_dev); | ||
721 | |||
722 | Fixup: | ||
723 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
670 | 724 | ||
671 | return error; | 725 | return error; |
672 | } | 726 | } |
@@ -707,16 +761,27 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
707 | static int pci_pm_restore(struct device *dev) | 761 | static int pci_pm_restore(struct device *dev) |
708 | { | 762 | { |
709 | struct pci_dev *pci_dev = to_pci_dev(dev); | 763 | struct pci_dev *pci_dev = to_pci_dev(dev); |
710 | struct device_driver *drv = dev->driver; | 764 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
711 | int error = 0; | 765 | int error = 0; |
712 | 766 | ||
767 | /* | ||
768 | * This is necessary for the hibernation error path in which restore is | ||
769 | * called without restoring the standard config registers of the device. | ||
770 | */ | ||
771 | if (pci_dev->state_saved) | ||
772 | pci_restore_standard_config(pci_dev); | ||
773 | |||
713 | if (pci_has_legacy_pm_support(pci_dev)) | 774 | if (pci_has_legacy_pm_support(pci_dev)) |
714 | return pci_legacy_resume(dev); | 775 | return pci_legacy_resume(dev); |
715 | 776 | ||
716 | error = pci_pm_default_resume(pci_dev); | 777 | pci_pm_default_resume(pci_dev); |
717 | 778 | ||
718 | if (!error && drv && drv->pm && drv->pm->restore) | 779 | if (pm) { |
719 | error = drv->pm->restore(dev); | 780 | if (pm->restore) |
781 | error = pm->restore(dev); | ||
782 | } else { | ||
783 | pci_pm_reenable_device(pci_dev); | ||
784 | } | ||
720 | 785 | ||
721 | return error; | 786 | return error; |
722 | } | 787 | } |