diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-driver.c | 177 | ||||
-rw-r--r-- | drivers/pci/pci.c | 142 | ||||
-rw-r--r-- | drivers/pci/pci.h | 1 |
3 files changed, 177 insertions, 143 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b522f883d674..16240390bcde 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -351,53 +351,60 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state) | |||
351 | { | 351 | { |
352 | struct pci_dev * pci_dev = to_pci_dev(dev); | 352 | struct pci_dev * pci_dev = to_pci_dev(dev); |
353 | struct pci_driver * drv = pci_dev->driver; | 353 | struct pci_driver * drv = pci_dev->driver; |
354 | int i = 0; | 354 | |
355 | pci_dev->state_saved = false; | ||
355 | 356 | ||
356 | if (drv && drv->suspend) { | 357 | if (drv && drv->suspend) { |
357 | pci_power_t prev = pci_dev->current_state; | 358 | pci_power_t prev = pci_dev->current_state; |
359 | int error; | ||
358 | 360 | ||
359 | pci_dev->state_saved = false; | 361 | error = drv->suspend(pci_dev, state); |
360 | 362 | suspend_report_result(drv->suspend, error); | |
361 | i = drv->suspend(pci_dev, state); | 363 | if (error) |
362 | suspend_report_result(drv->suspend, i); | 364 | return error; |
363 | if (i) | ||
364 | return i; | ||
365 | |||
366 | if (pci_dev->state_saved) | ||
367 | goto Fixup; | ||
368 | 365 | ||
369 | if (pci_dev->current_state != PCI_D0 | 366 | if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 |
370 | && pci_dev->current_state != PCI_UNKNOWN) { | 367 | && pci_dev->current_state != PCI_UNKNOWN) { |
371 | WARN_ONCE(pci_dev->current_state != prev, | 368 | WARN_ONCE(pci_dev->current_state != prev, |
372 | "PCI PM: Device state not saved by %pF\n", | 369 | "PCI PM: Device state not saved by %pF\n", |
373 | drv->suspend); | 370 | drv->suspend); |
374 | goto Fixup; | ||
375 | } | 371 | } |
376 | } | 372 | } |
377 | 373 | ||
378 | pci_save_state(pci_dev); | ||
379 | /* | ||
380 | * This is for compatibility with existing code with legacy PM support. | ||
381 | */ | ||
382 | pci_pm_set_unknown_state(pci_dev); | ||
383 | |||
384 | Fixup: | ||
385 | pci_fixup_device(pci_fixup_suspend, pci_dev); | 374 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
386 | 375 | ||
387 | return i; | 376 | return 0; |
388 | } | 377 | } |
389 | 378 | ||
390 | static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) | 379 | static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) |
391 | { | 380 | { |
392 | struct pci_dev * pci_dev = to_pci_dev(dev); | 381 | struct pci_dev * pci_dev = to_pci_dev(dev); |
393 | struct pci_driver * drv = pci_dev->driver; | 382 | struct pci_driver * drv = pci_dev->driver; |
394 | int i = 0; | ||
395 | 383 | ||
396 | if (drv && drv->suspend_late) { | 384 | if (drv && drv->suspend_late) { |
397 | i = drv->suspend_late(pci_dev, state); | 385 | pci_power_t prev = pci_dev->current_state; |
398 | suspend_report_result(drv->suspend_late, i); | 386 | int error; |
387 | |||
388 | error = drv->suspend_late(pci_dev, state); | ||
389 | suspend_report_result(drv->suspend_late, error); | ||
390 | if (error) | ||
391 | return error; | ||
392 | |||
393 | if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 | ||
394 | && pci_dev->current_state != PCI_UNKNOWN) { | ||
395 | WARN_ONCE(pci_dev->current_state != prev, | ||
396 | "PCI PM: Device state not saved by %pF\n", | ||
397 | drv->suspend_late); | ||
398 | return 0; | ||
399 | } | ||
399 | } | 400 | } |
400 | return i; | 401 | |
402 | if (!pci_dev->state_saved) | ||
403 | pci_save_state(pci_dev); | ||
404 | |||
405 | pci_pm_set_unknown_state(pci_dev); | ||
406 | |||
407 | return 0; | ||
401 | } | 408 | } |
402 | 409 | ||
403 | static int pci_legacy_resume_early(struct device *dev) | 410 | static int pci_legacy_resume_early(struct device *dev) |
@@ -422,6 +429,23 @@ static int pci_legacy_resume(struct device *dev) | |||
422 | 429 | ||
423 | /* Auxiliary functions used by the new power management framework */ | 430 | /* Auxiliary functions used by the new power management framework */ |
424 | 431 | ||
432 | /** | ||
433 | * pci_restore_standard_config - restore standard config registers of PCI device | ||
434 | * @pci_dev: PCI device to handle | ||
435 | */ | ||
436 | static int pci_restore_standard_config(struct pci_dev *pci_dev) | ||
437 | { | ||
438 | pci_update_current_state(pci_dev, PCI_UNKNOWN); | ||
439 | |||
440 | if (pci_dev->current_state != PCI_D0) { | ||
441 | int error = pci_set_power_state(pci_dev, PCI_D0); | ||
442 | if (error) | ||
443 | return error; | ||
444 | } | ||
445 | |||
446 | return pci_dev->state_saved ? pci_restore_state(pci_dev) : 0; | ||
447 | } | ||
448 | |||
425 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) | 449 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) |
426 | { | 450 | { |
427 | pci_restore_standard_config(pci_dev); | 451 | pci_restore_standard_config(pci_dev); |
@@ -442,7 +466,6 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev) | |||
442 | /* Disable non-bridge devices without PM support */ | 466 | /* Disable non-bridge devices without PM support */ |
443 | if (!pci_is_bridge(pci_dev)) | 467 | if (!pci_is_bridge(pci_dev)) |
444 | pci_disable_enabled_device(pci_dev); | 468 | pci_disable_enabled_device(pci_dev); |
445 | pci_save_state(pci_dev); | ||
446 | } | 469 | } |
447 | 470 | ||
448 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) | 471 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) |
@@ -492,13 +515,13 @@ static int pci_pm_suspend(struct device *dev) | |||
492 | if (pci_has_legacy_pm_support(pci_dev)) | 515 | if (pci_has_legacy_pm_support(pci_dev)) |
493 | return pci_legacy_suspend(dev, PMSG_SUSPEND); | 516 | return pci_legacy_suspend(dev, PMSG_SUSPEND); |
494 | 517 | ||
518 | pci_dev->state_saved = false; | ||
519 | |||
495 | if (!pm) { | 520 | if (!pm) { |
496 | pci_pm_default_suspend(pci_dev); | 521 | pci_pm_default_suspend(pci_dev); |
497 | goto Fixup; | 522 | goto Fixup; |
498 | } | 523 | } |
499 | 524 | ||
500 | pci_dev->state_saved = false; | ||
501 | |||
502 | if (pm->suspend) { | 525 | if (pm->suspend) { |
503 | pci_power_t prev = pci_dev->current_state; | 526 | pci_power_t prev = pci_dev->current_state; |
504 | int error; | 527 | int error; |
@@ -508,24 +531,14 @@ static int pci_pm_suspend(struct device *dev) | |||
508 | if (error) | 531 | if (error) |
509 | return error; | 532 | return error; |
510 | 533 | ||
511 | if (pci_dev->state_saved) | 534 | if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 |
512 | goto Fixup; | ||
513 | |||
514 | if (pci_dev->current_state != PCI_D0 | ||
515 | && pci_dev->current_state != PCI_UNKNOWN) { | 535 | && pci_dev->current_state != PCI_UNKNOWN) { |
516 | WARN_ONCE(pci_dev->current_state != prev, | 536 | WARN_ONCE(pci_dev->current_state != prev, |
517 | "PCI PM: State of device not saved by %pF\n", | 537 | "PCI PM: State of device not saved by %pF\n", |
518 | pm->suspend); | 538 | pm->suspend); |
519 | goto Fixup; | ||
520 | } | 539 | } |
521 | } | 540 | } |
522 | 541 | ||
523 | if (!pci_dev->state_saved) { | ||
524 | pci_save_state(pci_dev); | ||
525 | if (!pci_is_bridge(pci_dev)) | ||
526 | pci_prepare_to_sleep(pci_dev); | ||
527 | } | ||
528 | |||
529 | Fixup: | 542 | Fixup: |
530 | pci_fixup_device(pci_fixup_suspend, pci_dev); | 543 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
531 | 544 | ||
@@ -535,21 +548,43 @@ static int pci_pm_suspend(struct device *dev) | |||
535 | static int pci_pm_suspend_noirq(struct device *dev) | 548 | static int pci_pm_suspend_noirq(struct device *dev) |
536 | { | 549 | { |
537 | struct pci_dev *pci_dev = to_pci_dev(dev); | 550 | struct pci_dev *pci_dev = to_pci_dev(dev); |
538 | struct device_driver *drv = dev->driver; | 551 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
539 | int error = 0; | ||
540 | 552 | ||
541 | if (pci_has_legacy_pm_support(pci_dev)) | 553 | if (pci_has_legacy_pm_support(pci_dev)) |
542 | return pci_legacy_suspend_late(dev, PMSG_SUSPEND); | 554 | return pci_legacy_suspend_late(dev, PMSG_SUSPEND); |
543 | 555 | ||
544 | if (drv && drv->pm && drv->pm->suspend_noirq) { | 556 | if (!pm) { |
545 | error = drv->pm->suspend_noirq(dev); | 557 | pci_save_state(pci_dev); |
546 | suspend_report_result(drv->pm->suspend_noirq, error); | 558 | return 0; |
547 | } | 559 | } |
548 | 560 | ||
549 | if (!error) | 561 | if (pm->suspend_noirq) { |
550 | pci_pm_set_unknown_state(pci_dev); | 562 | pci_power_t prev = pci_dev->current_state; |
563 | int error; | ||
551 | 564 | ||
552 | return error; | 565 | error = pm->suspend_noirq(dev); |
566 | suspend_report_result(pm->suspend_noirq, error); | ||
567 | if (error) | ||
568 | return error; | ||
569 | |||
570 | if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 | ||
571 | && pci_dev->current_state != PCI_UNKNOWN) { | ||
572 | WARN_ONCE(pci_dev->current_state != prev, | ||
573 | "PCI PM: State of device not saved by %pF\n", | ||
574 | pm->suspend_noirq); | ||
575 | return 0; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | if (!pci_dev->state_saved) { | ||
580 | pci_save_state(pci_dev); | ||
581 | if (!pci_is_bridge(pci_dev)) | ||
582 | pci_prepare_to_sleep(pci_dev); | ||
583 | } | ||
584 | |||
585 | pci_pm_set_unknown_state(pci_dev); | ||
586 | |||
587 | return 0; | ||
553 | } | 588 | } |
554 | 589 | ||
555 | static int pci_pm_resume_noirq(struct device *dev) | 590 | static int pci_pm_resume_noirq(struct device *dev) |
@@ -616,13 +651,13 @@ static int pci_pm_freeze(struct device *dev) | |||
616 | if (pci_has_legacy_pm_support(pci_dev)) | 651 | if (pci_has_legacy_pm_support(pci_dev)) |
617 | return pci_legacy_suspend(dev, PMSG_FREEZE); | 652 | return pci_legacy_suspend(dev, PMSG_FREEZE); |
618 | 653 | ||
654 | pci_dev->state_saved = false; | ||
655 | |||
619 | if (!pm) { | 656 | if (!pm) { |
620 | pci_pm_default_suspend(pci_dev); | 657 | pci_pm_default_suspend(pci_dev); |
621 | return 0; | 658 | return 0; |
622 | } | 659 | } |
623 | 660 | ||
624 | pci_dev->state_saved = false; | ||
625 | |||
626 | if (pm->freeze) { | 661 | if (pm->freeze) { |
627 | int error; | 662 | int error; |
628 | 663 | ||
@@ -632,9 +667,6 @@ static int pci_pm_freeze(struct device *dev) | |||
632 | return error; | 667 | return error; |
633 | } | 668 | } |
634 | 669 | ||
635 | if (!pci_dev->state_saved) | ||
636 | pci_save_state(pci_dev); | ||
637 | |||
638 | return 0; | 670 | return 0; |
639 | } | 671 | } |
640 | 672 | ||
@@ -642,20 +674,25 @@ static int pci_pm_freeze_noirq(struct device *dev) | |||
642 | { | 674 | { |
643 | struct pci_dev *pci_dev = to_pci_dev(dev); | 675 | struct pci_dev *pci_dev = to_pci_dev(dev); |
644 | struct device_driver *drv = dev->driver; | 676 | struct device_driver *drv = dev->driver; |
645 | int error = 0; | ||
646 | 677 | ||
647 | if (pci_has_legacy_pm_support(pci_dev)) | 678 | if (pci_has_legacy_pm_support(pci_dev)) |
648 | return pci_legacy_suspend_late(dev, PMSG_FREEZE); | 679 | return pci_legacy_suspend_late(dev, PMSG_FREEZE); |
649 | 680 | ||
650 | if (drv && drv->pm && drv->pm->freeze_noirq) { | 681 | if (drv && drv->pm && drv->pm->freeze_noirq) { |
682 | int error; | ||
683 | |||
651 | error = drv->pm->freeze_noirq(dev); | 684 | error = drv->pm->freeze_noirq(dev); |
652 | suspend_report_result(drv->pm->freeze_noirq, error); | 685 | suspend_report_result(drv->pm->freeze_noirq, error); |
686 | if (error) | ||
687 | return error; | ||
653 | } | 688 | } |
654 | 689 | ||
655 | if (!error) | 690 | if (!pci_dev->state_saved) |
656 | pci_pm_set_unknown_state(pci_dev); | 691 | pci_save_state(pci_dev); |
657 | 692 | ||
658 | return error; | 693 | pci_pm_set_unknown_state(pci_dev); |
694 | |||
695 | return 0; | ||
659 | } | 696 | } |
660 | 697 | ||
661 | static int pci_pm_thaw_noirq(struct device *dev) | 698 | static int pci_pm_thaw_noirq(struct device *dev) |
@@ -698,46 +735,56 @@ static int pci_pm_poweroff(struct device *dev) | |||
698 | { | 735 | { |
699 | struct pci_dev *pci_dev = to_pci_dev(dev); | 736 | struct pci_dev *pci_dev = to_pci_dev(dev); |
700 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | 737 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
701 | int error = 0; | ||
702 | 738 | ||
703 | if (pci_has_legacy_pm_support(pci_dev)) | 739 | if (pci_has_legacy_pm_support(pci_dev)) |
704 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); | 740 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); |
705 | 741 | ||
742 | pci_dev->state_saved = false; | ||
743 | |||
706 | if (!pm) { | 744 | if (!pm) { |
707 | pci_pm_default_suspend(pci_dev); | 745 | pci_pm_default_suspend(pci_dev); |
708 | goto Fixup; | 746 | goto Fixup; |
709 | } | 747 | } |
710 | 748 | ||
711 | pci_dev->state_saved = false; | ||
712 | |||
713 | if (pm->poweroff) { | 749 | if (pm->poweroff) { |
750 | int error; | ||
751 | |||
714 | error = pm->poweroff(dev); | 752 | error = pm->poweroff(dev); |
715 | suspend_report_result(pm->poweroff, error); | 753 | suspend_report_result(pm->poweroff, error); |
754 | if (error) | ||
755 | return error; | ||
716 | } | 756 | } |
717 | 757 | ||
718 | if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) | ||
719 | pci_prepare_to_sleep(pci_dev); | ||
720 | |||
721 | Fixup: | 758 | Fixup: |
722 | pci_fixup_device(pci_fixup_suspend, pci_dev); | 759 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
723 | 760 | ||
724 | return error; | 761 | return 0; |
725 | } | 762 | } |
726 | 763 | ||
727 | static int pci_pm_poweroff_noirq(struct device *dev) | 764 | static int pci_pm_poweroff_noirq(struct device *dev) |
728 | { | 765 | { |
766 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
729 | struct device_driver *drv = dev->driver; | 767 | struct device_driver *drv = dev->driver; |
730 | int error = 0; | ||
731 | 768 | ||
732 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) | 769 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) |
733 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); | 770 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); |
734 | 771 | ||
735 | if (drv && drv->pm && drv->pm->poweroff_noirq) { | 772 | if (!drv || !drv->pm) |
773 | return 0; | ||
774 | |||
775 | if (drv->pm->poweroff_noirq) { | ||
776 | int error; | ||
777 | |||
736 | error = drv->pm->poweroff_noirq(dev); | 778 | error = drv->pm->poweroff_noirq(dev); |
737 | suspend_report_result(drv->pm->poweroff_noirq, error); | 779 | suspend_report_result(drv->pm->poweroff_noirq, error); |
780 | if (error) | ||
781 | return error; | ||
738 | } | 782 | } |
739 | 783 | ||
740 | return error; | 784 | if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) |
785 | pci_prepare_to_sleep(pci_dev); | ||
786 | |||
787 | return 0; | ||
741 | } | 788 | } |
742 | 789 | ||
743 | static int pci_pm_restore_noirq(struct device *dev) | 790 | static int pci_pm_restore_noirq(struct device *dev) |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6d6120007af4..0195066251e5 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -426,7 +426,6 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) | |||
426 | * given PCI device | 426 | * given PCI device |
427 | * @dev: PCI device to handle. | 427 | * @dev: PCI device to handle. |
428 | * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. | 428 | * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. |
429 | * @wait: If 'true', wait for the device to change its power state | ||
430 | * | 429 | * |
431 | * RETURN VALUE: | 430 | * RETURN VALUE: |
432 | * -EINVAL if the requested state is invalid. | 431 | * -EINVAL if the requested state is invalid. |
@@ -435,12 +434,15 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) | |||
435 | * 0 if device already is in the requested state. | 434 | * 0 if device already is in the requested state. |
436 | * 0 if device's power state has been successfully changed. | 435 | * 0 if device's power state has been successfully changed. |
437 | */ | 436 | */ |
438 | static int | 437 | static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) |
439 | pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait) | ||
440 | { | 438 | { |
441 | u16 pmcsr; | 439 | u16 pmcsr; |
442 | bool need_restore = false; | 440 | bool need_restore = false; |
443 | 441 | ||
442 | /* Check if we're already there */ | ||
443 | if (dev->current_state == state) | ||
444 | return 0; | ||
445 | |||
444 | if (!dev->pm_cap) | 446 | if (!dev->pm_cap) |
445 | return -EIO; | 447 | return -EIO; |
446 | 448 | ||
@@ -451,10 +453,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait) | |||
451 | * Can enter D0 from any state, but if we can only go deeper | 453 | * Can enter D0 from any state, but if we can only go deeper |
452 | * to sleep if we're already in a low power state | 454 | * to sleep if we're already in a low power state |
453 | */ | 455 | */ |
454 | if (dev->current_state == state) { | 456 | if (state != PCI_D0 && dev->current_state <= PCI_D3cold |
455 | /* we're already there */ | ||
456 | return 0; | ||
457 | } else if (state != PCI_D0 && dev->current_state <= PCI_D3cold | ||
458 | && dev->current_state > state) { | 457 | && dev->current_state > state) { |
459 | dev_err(&dev->dev, "invalid power transition " | 458 | dev_err(&dev->dev, "invalid power transition " |
460 | "(from state %d to %d)\n", dev->current_state, state); | 459 | "(from state %d to %d)\n", dev->current_state, state); |
@@ -481,10 +480,8 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait) | |||
481 | break; | 480 | break; |
482 | case PCI_UNKNOWN: /* Boot-up */ | 481 | case PCI_UNKNOWN: /* Boot-up */ |
483 | if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot | 482 | if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot |
484 | && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) { | 483 | && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) |
485 | need_restore = true; | 484 | need_restore = true; |
486 | wait = true; | ||
487 | } | ||
488 | /* Fall-through: force to D0 */ | 485 | /* Fall-through: force to D0 */ |
489 | default: | 486 | default: |
490 | pmcsr = 0; | 487 | pmcsr = 0; |
@@ -494,9 +491,6 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait) | |||
494 | /* enter specified state */ | 491 | /* enter specified state */ |
495 | pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); | 492 | pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); |
496 | 493 | ||
497 | if (!wait) | ||
498 | return 0; | ||
499 | |||
500 | /* Mandatory power management transition delays */ | 494 | /* Mandatory power management transition delays */ |
501 | /* see PCI PM 1.1 5.6.1 table 18 */ | 495 | /* see PCI PM 1.1 5.6.1 table 18 */ |
502 | if (state == PCI_D3hot || dev->current_state == PCI_D3hot) | 496 | if (state == PCI_D3hot || dev->current_state == PCI_D3hot) |
@@ -521,7 +515,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait) | |||
521 | if (need_restore) | 515 | if (need_restore) |
522 | pci_restore_bars(dev); | 516 | pci_restore_bars(dev); |
523 | 517 | ||
524 | if (wait && dev->bus->self) | 518 | if (dev->bus->self) |
525 | pcie_aspm_pm_state_change(dev->bus->self); | 519 | pcie_aspm_pm_state_change(dev->bus->self); |
526 | 520 | ||
527 | return 0; | 521 | return 0; |
@@ -546,6 +540,53 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state) | |||
546 | } | 540 | } |
547 | 541 | ||
548 | /** | 542 | /** |
543 | * pci_platform_power_transition - Use platform to change device power state | ||
544 | * @dev: PCI device to handle. | ||
545 | * @state: State to put the device into. | ||
546 | */ | ||
547 | static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) | ||
548 | { | ||
549 | int error; | ||
550 | |||
551 | if (platform_pci_power_manageable(dev)) { | ||
552 | error = platform_pci_set_power_state(dev, state); | ||
553 | if (!error) | ||
554 | pci_update_current_state(dev, state); | ||
555 | } else { | ||
556 | error = -ENODEV; | ||
557 | /* Fall back to PCI_D0 if native PM is not supported */ | ||
558 | pci_update_current_state(dev, PCI_D0); | ||
559 | } | ||
560 | |||
561 | return error; | ||
562 | } | ||
563 | |||
564 | /** | ||
565 | * __pci_start_power_transition - Start power transition of a PCI device | ||
566 | * @dev: PCI device to handle. | ||
567 | * @state: State to put the device into. | ||
568 | */ | ||
569 | static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) | ||
570 | { | ||
571 | if (state == PCI_D0) | ||
572 | pci_platform_power_transition(dev, PCI_D0); | ||
573 | } | ||
574 | |||
575 | /** | ||
576 | * __pci_complete_power_transition - Complete power transition of a PCI device | ||
577 | * @dev: PCI device to handle. | ||
578 | * @state: State to put the device into. | ||
579 | * | ||
580 | * This function should not be called directly by device drivers. | ||
581 | */ | ||
582 | int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state) | ||
583 | { | ||
584 | return state > PCI_D0 ? | ||
585 | pci_platform_power_transition(dev, state) : -EINVAL; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(__pci_complete_power_transition); | ||
588 | |||
589 | /** | ||
549 | * pci_set_power_state - Set the power state of a PCI device | 590 | * pci_set_power_state - Set the power state of a PCI device |
550 | * @dev: PCI device to handle. | 591 | * @dev: PCI device to handle. |
551 | * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. | 592 | * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. |
@@ -577,30 +618,21 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
577 | */ | 618 | */ |
578 | return 0; | 619 | return 0; |
579 | 620 | ||
580 | if (state == PCI_D0 && platform_pci_power_manageable(dev)) { | 621 | /* Check if we're already there */ |
581 | /* | 622 | if (dev->current_state == state) |
582 | * Allow the platform to change the state, for example via ACPI | 623 | return 0; |
583 | * _PR0, _PS0 and some such, but do not trust it. | 624 | |
584 | */ | 625 | __pci_start_power_transition(dev, state); |
585 | int ret = platform_pci_set_power_state(dev, PCI_D0); | 626 | |
586 | if (!ret) | ||
587 | pci_update_current_state(dev, PCI_D0); | ||
588 | } | ||
589 | /* This device is quirked not to be put into D3, so | 627 | /* This device is quirked not to be put into D3, so |
590 | don't put it in D3 */ | 628 | don't put it in D3 */ |
591 | if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) | 629 | if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) |
592 | return 0; | 630 | return 0; |
593 | 631 | ||
594 | error = pci_raw_set_power_state(dev, state, true); | 632 | error = pci_raw_set_power_state(dev, state); |
595 | 633 | ||
596 | if (state > PCI_D0 && platform_pci_power_manageable(dev)) { | 634 | if (!__pci_complete_power_transition(dev, state)) |
597 | /* Allow the platform to finalize the transition */ | 635 | error = 0; |
598 | int ret = platform_pci_set_power_state(dev, state); | ||
599 | if (!ret) { | ||
600 | pci_update_current_state(dev, state); | ||
601 | error = 0; | ||
602 | } | ||
603 | } | ||
604 | 636 | ||
605 | return error; | 637 | return error; |
606 | } | 638 | } |
@@ -1231,7 +1263,7 @@ int pci_prepare_to_sleep(struct pci_dev *dev) | |||
1231 | if (target_state == PCI_POWER_ERROR) | 1263 | if (target_state == PCI_POWER_ERROR) |
1232 | return -EIO; | 1264 | return -EIO; |
1233 | 1265 | ||
1234 | pci_enable_wake(dev, target_state, true); | 1266 | pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); |
1235 | 1267 | ||
1236 | error = pci_set_power_state(dev, target_state); | 1268 | error = pci_set_power_state(dev, target_state); |
1237 | 1269 | ||
@@ -1381,50 +1413,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev) | |||
1381 | } | 1413 | } |
1382 | 1414 | ||
1383 | /** | 1415 | /** |
1384 | * pci_restore_standard_config - restore standard config registers of PCI device | ||
1385 | * @dev: PCI device to handle | ||
1386 | * | ||
1387 | * This function assumes that the device's configuration space is accessible. | ||
1388 | * If the device needs to be powered up, the function will wait for it to | ||
1389 | * change the state. | ||
1390 | */ | ||
1391 | int pci_restore_standard_config(struct pci_dev *dev) | ||
1392 | { | ||
1393 | pci_power_t prev_state; | ||
1394 | int error; | ||
1395 | |||
1396 | pci_update_current_state(dev, PCI_D0); | ||
1397 | |||
1398 | prev_state = dev->current_state; | ||
1399 | if (prev_state == PCI_D0) | ||
1400 | goto Restore; | ||
1401 | |||
1402 | error = pci_raw_set_power_state(dev, PCI_D0, false); | ||
1403 | if (error) | ||
1404 | return error; | ||
1405 | |||
1406 | /* | ||
1407 | * This assumes that we won't get a bus in B2 or B3 from the BIOS, but | ||
1408 | * we've made this assumption forever and it appears to be universally | ||
1409 | * satisfied. | ||
1410 | */ | ||
1411 | switch(prev_state) { | ||
1412 | case PCI_D3cold: | ||
1413 | case PCI_D3hot: | ||
1414 | mdelay(pci_pm_d3_delay); | ||
1415 | break; | ||
1416 | case PCI_D2: | ||
1417 | udelay(PCI_PM_D2_DELAY); | ||
1418 | break; | ||
1419 | } | ||
1420 | |||
1421 | pci_update_current_state(dev, PCI_D0); | ||
1422 | |||
1423 | Restore: | ||
1424 | return dev->state_saved ? pci_restore_state(dev) : 0; | ||
1425 | } | ||
1426 | |||
1427 | /** | ||
1428 | * pci_enable_ari - enable ARI forwarding if hardware support it | 1416 | * pci_enable_ari - enable ARI forwarding if hardware support it |
1429 | * @dev: the PCI device | 1417 | * @dev: the PCI device |
1430 | */ | 1418 | */ |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 07c0aa5275e6..149fff65891f 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -49,7 +49,6 @@ extern void pci_disable_enabled_device(struct pci_dev *dev); | |||
49 | extern void pci_pm_init(struct pci_dev *dev); | 49 | extern void pci_pm_init(struct pci_dev *dev); |
50 | extern void platform_pci_wakeup_init(struct pci_dev *dev); | 50 | extern void platform_pci_wakeup_init(struct pci_dev *dev); |
51 | extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); | 51 | extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); |
52 | extern int pci_restore_standard_config(struct pci_dev *dev); | ||
53 | 52 | ||
54 | static inline bool pci_is_bridge(struct pci_dev *pci_dev) | 53 | static inline bool pci_is_bridge(struct pci_dev *pci_dev) |
55 | { | 54 | { |