diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-02-13 03:44:22 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-13 03:44:22 -0500 |
commit | f8a6b2b9cee298a9663cbe38ce1eb5240987cb62 (patch) | |
tree | b356490269c9e77d164dcc1477792b882fbb8bdb /drivers/pci | |
parent | ba1511bf7fbda452138e4096bf10d5a382710f4f (diff) | |
parent | 071a0bc2ceace31266836801510879407a3701fa (diff) |
Merge branch 'linus' into x86/apic
Conflicts:
arch/x86/kernel/acpi/boot.c
arch/x86/mm/fault.c
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-driver.c | 164 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 4 | ||||
-rw-r--r-- | drivers/pci/pci.c | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 16 | ||||
-rw-r--r-- | drivers/pci/rom.c | 8 |
6 files changed, 117 insertions, 83 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index ab1d615425a8..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,12 +367,16 @@ 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); |
373 | pci_dev->state_saved = true; | ||
374 | /* | 380 | /* |
375 | * This is for compatibility with existing code with legacy PM support. | 381 | * This is for compatibility with existing code with legacy PM support. |
376 | */ | 382 | */ |
@@ -424,35 +430,20 @@ static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) | |||
424 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 430 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
425 | } | 431 | } |
426 | 432 | ||
427 | static int pci_pm_default_resume(struct pci_dev *pci_dev) | 433 | static void pci_pm_default_resume(struct pci_dev *pci_dev) |
428 | { | 434 | { |
429 | pci_fixup_device(pci_fixup_resume, pci_dev); | 435 | pci_fixup_device(pci_fixup_resume, pci_dev); |
430 | 436 | ||
431 | if (!pci_is_bridge(pci_dev)) | 437 | if (!pci_is_bridge(pci_dev)) |
432 | pci_enable_wake(pci_dev, PCI_D0, false); | 438 | pci_enable_wake(pci_dev, PCI_D0, false); |
433 | |||
434 | return pci_pm_reenable_device(pci_dev); | ||
435 | } | ||
436 | |||
437 | static void pci_pm_default_suspend_generic(struct pci_dev *pci_dev) | ||
438 | { | ||
439 | /* If device is enabled at this point, disable it */ | ||
440 | pci_disable_enabled_device(pci_dev); | ||
441 | /* | ||
442 | * Save state with interrupts enabled, because in principle the bus the | ||
443 | * device is on may be put into a low power state after this code runs. | ||
444 | */ | ||
445 | pci_save_state(pci_dev); | ||
446 | } | 439 | } |
447 | 440 | ||
448 | static void pci_pm_default_suspend(struct pci_dev *pci_dev) | 441 | static void pci_pm_default_suspend(struct pci_dev *pci_dev) |
449 | { | 442 | { |
450 | pci_pm_default_suspend_generic(pci_dev); | 443 | /* Disable non-bridge devices without PM support */ |
451 | |||
452 | if (!pci_is_bridge(pci_dev)) | 444 | if (!pci_is_bridge(pci_dev)) |
453 | pci_prepare_to_sleep(pci_dev); | 445 | pci_disable_enabled_device(pci_dev); |
454 | 446 | pci_save_state(pci_dev); | |
455 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
456 | } | 447 | } |
457 | 448 | ||
458 | 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) |
@@ -497,21 +488,49 @@ static void pci_pm_complete(struct device *dev) | |||
497 | static int pci_pm_suspend(struct device *dev) | 488 | static int pci_pm_suspend(struct device *dev) |
498 | { | 489 | { |
499 | struct pci_dev *pci_dev = to_pci_dev(dev); | 490 | struct pci_dev *pci_dev = to_pci_dev(dev); |
500 | struct device_driver *drv = dev->driver; | 491 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
501 | int error = 0; | ||
502 | 492 | ||
503 | if (pci_has_legacy_pm_support(pci_dev)) | 493 | if (pci_has_legacy_pm_support(pci_dev)) |
504 | return pci_legacy_suspend(dev, PMSG_SUSPEND); | 494 | return pci_legacy_suspend(dev, PMSG_SUSPEND); |
505 | 495 | ||
506 | if (drv && drv->pm && drv->pm->suspend) { | 496 | if (!pm) { |
507 | error = drv->pm->suspend(dev); | 497 | pci_pm_default_suspend(pci_dev); |
508 | suspend_report_result(drv->pm->suspend, error); | 498 | goto Fixup; |
509 | } | 499 | } |
510 | 500 | ||
511 | if (!error) | 501 | pci_dev->state_saved = false; |
512 | pci_pm_default_suspend(pci_dev); | ||
513 | 502 | ||
514 | 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; | ||
515 | } | 534 | } |
516 | 535 | ||
517 | static int pci_pm_suspend_noirq(struct device *dev) | 536 | static int pci_pm_suspend_noirq(struct device *dev) |
@@ -554,7 +573,7 @@ static int pci_pm_resume_noirq(struct device *dev) | |||
554 | static int pci_pm_resume(struct device *dev) | 573 | static int pci_pm_resume(struct device *dev) |
555 | { | 574 | { |
556 | struct pci_dev *pci_dev = to_pci_dev(dev); | 575 | struct pci_dev *pci_dev = to_pci_dev(dev); |
557 | struct device_driver *drv = dev->driver; | 576 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
558 | int error = 0; | 577 | int error = 0; |
559 | 578 | ||
560 | /* | 579 | /* |
@@ -567,12 +586,16 @@ static int pci_pm_resume(struct device *dev) | |||
567 | if (pci_has_legacy_pm_support(pci_dev)) | 586 | if (pci_has_legacy_pm_support(pci_dev)) |
568 | return pci_legacy_resume(dev); | 587 | return pci_legacy_resume(dev); |
569 | 588 | ||
570 | error = pci_pm_default_resume(pci_dev); | 589 | pci_pm_default_resume(pci_dev); |
571 | 590 | ||
572 | if (!error && drv && drv->pm && drv->pm->resume) | 591 | if (pm) { |
573 | error = drv->pm->resume(dev); | 592 | if (pm->resume) |
593 | error = pm->resume(dev); | ||
594 | } else { | ||
595 | pci_pm_reenable_device(pci_dev); | ||
596 | } | ||
574 | 597 | ||
575 | return error; | 598 | return 0; |
576 | } | 599 | } |
577 | 600 | ||
578 | #else /* !CONFIG_SUSPEND */ | 601 | #else /* !CONFIG_SUSPEND */ |
@@ -589,21 +612,31 @@ static int pci_pm_resume(struct device *dev) | |||
589 | static int pci_pm_freeze(struct device *dev) | 612 | static int pci_pm_freeze(struct device *dev) |
590 | { | 613 | { |
591 | struct pci_dev *pci_dev = to_pci_dev(dev); | 614 | struct pci_dev *pci_dev = to_pci_dev(dev); |
592 | struct device_driver *drv = dev->driver; | 615 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
593 | int error = 0; | ||
594 | 616 | ||
595 | if (pci_has_legacy_pm_support(pci_dev)) | 617 | if (pci_has_legacy_pm_support(pci_dev)) |
596 | return pci_legacy_suspend(dev, PMSG_FREEZE); | 618 | return pci_legacy_suspend(dev, PMSG_FREEZE); |
597 | 619 | ||
598 | if (drv && drv->pm && drv->pm->freeze) { | 620 | if (!pm) { |
599 | error = drv->pm->freeze(dev); | 621 | pci_pm_default_suspend(pci_dev); |
600 | suspend_report_result(drv->pm->freeze, error); | 622 | return 0; |
601 | } | 623 | } |
602 | 624 | ||
603 | if (!error) | 625 | pci_dev->state_saved = false; |
604 | pci_pm_default_suspend_generic(pci_dev); | ||
605 | 626 | ||
606 | return error; | 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; | ||
634 | } | ||
635 | |||
636 | if (!pci_dev->state_saved) | ||
637 | pci_save_state(pci_dev); | ||
638 | |||
639 | return 0; | ||
607 | } | 640 | } |
608 | 641 | ||
609 | static int pci_pm_freeze_noirq(struct device *dev) | 642 | static int pci_pm_freeze_noirq(struct device *dev) |
@@ -646,16 +679,18 @@ static int pci_pm_thaw_noirq(struct device *dev) | |||
646 | static int pci_pm_thaw(struct device *dev) | 679 | static int pci_pm_thaw(struct device *dev) |
647 | { | 680 | { |
648 | struct pci_dev *pci_dev = to_pci_dev(dev); | 681 | struct pci_dev *pci_dev = to_pci_dev(dev); |
649 | struct device_driver *drv = dev->driver; | 682 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
650 | int error = 0; | 683 | int error = 0; |
651 | 684 | ||
652 | if (pci_has_legacy_pm_support(pci_dev)) | 685 | if (pci_has_legacy_pm_support(pci_dev)) |
653 | return pci_legacy_resume(dev); | 686 | return pci_legacy_resume(dev); |
654 | 687 | ||
655 | pci_pm_reenable_device(pci_dev); | 688 | if (pm) { |
656 | 689 | if (pm->thaw) | |
657 | if (drv && drv->pm && drv->pm->thaw) | 690 | error = pm->thaw(dev); |
658 | error = drv->pm->thaw(dev); | 691 | } else { |
692 | pci_pm_reenable_device(pci_dev); | ||
693 | } | ||
659 | 694 | ||
660 | return error; | 695 | return error; |
661 | } | 696 | } |
@@ -663,22 +698,29 @@ static int pci_pm_thaw(struct device *dev) | |||
663 | static int pci_pm_poweroff(struct device *dev) | 698 | static int pci_pm_poweroff(struct device *dev) |
664 | { | 699 | { |
665 | struct pci_dev *pci_dev = to_pci_dev(dev); | 700 | struct pci_dev *pci_dev = to_pci_dev(dev); |
666 | struct device_driver *drv = dev->driver; | 701 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
667 | int error = 0; | 702 | int error = 0; |
668 | 703 | ||
669 | if (pci_has_legacy_pm_support(pci_dev)) | 704 | if (pci_has_legacy_pm_support(pci_dev)) |
670 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); | 705 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); |
671 | 706 | ||
672 | if (!drv || !drv->pm) | 707 | if (!pm) { |
673 | return 0; | 708 | pci_pm_default_suspend(pci_dev); |
709 | goto Fixup; | ||
710 | } | ||
711 | |||
712 | pci_dev->state_saved = false; | ||
674 | 713 | ||
675 | if (drv->pm->poweroff) { | 714 | if (pm->poweroff) { |
676 | error = drv->pm->poweroff(dev); | 715 | error = pm->poweroff(dev); |
677 | suspend_report_result(drv->pm->poweroff, error); | 716 | suspend_report_result(pm->poweroff, error); |
678 | } | 717 | } |
679 | 718 | ||
680 | if (!error) | 719 | if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) |
681 | pci_pm_default_suspend(pci_dev); | 720 | pci_prepare_to_sleep(pci_dev); |
721 | |||
722 | Fixup: | ||
723 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
682 | 724 | ||
683 | return error; | 725 | return error; |
684 | } | 726 | } |
@@ -719,7 +761,7 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
719 | static int pci_pm_restore(struct device *dev) | 761 | static int pci_pm_restore(struct device *dev) |
720 | { | 762 | { |
721 | struct pci_dev *pci_dev = to_pci_dev(dev); | 763 | struct pci_dev *pci_dev = to_pci_dev(dev); |
722 | struct device_driver *drv = dev->driver; | 764 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
723 | int error = 0; | 765 | int error = 0; |
724 | 766 | ||
725 | /* | 767 | /* |
@@ -732,10 +774,14 @@ static int pci_pm_restore(struct device *dev) | |||
732 | if (pci_has_legacy_pm_support(pci_dev)) | 774 | if (pci_has_legacy_pm_support(pci_dev)) |
733 | return pci_legacy_resume(dev); | 775 | return pci_legacy_resume(dev); |
734 | 776 | ||
735 | error = pci_pm_default_resume(pci_dev); | 777 | pci_pm_default_resume(pci_dev); |
736 | 778 | ||
737 | if (!error && drv && drv->pm && drv->pm->restore) | 779 | if (pm) { |
738 | error = drv->pm->restore(dev); | 780 | if (pm->restore) |
781 | error = pm->restore(dev); | ||
782 | } else { | ||
783 | pci_pm_reenable_device(pci_dev); | ||
784 | } | ||
739 | 785 | ||
740 | return error; | 786 | return error; |
741 | } | 787 | } |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index db7ec14fa719..dfc4e0ddf241 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -768,8 +768,8 @@ pci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
768 | return -EINVAL; | 768 | return -EINVAL; |
769 | 769 | ||
770 | rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ | 770 | rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ |
771 | if (!rom) | 771 | if (!rom || !size) |
772 | return 0; | 772 | return -EIO; |
773 | 773 | ||
774 | if (off >= size) | 774 | if (off >= size) |
775 | count = 0; | 775 | count = 0; |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 48807556b47a..e3efe6b19ee7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1418,10 +1418,10 @@ int pci_restore_standard_config(struct pci_dev *dev) | |||
1418 | break; | 1418 | break; |
1419 | } | 1419 | } |
1420 | 1420 | ||
1421 | dev->current_state = PCI_D0; | 1421 | pci_update_current_state(dev, PCI_D0); |
1422 | 1422 | ||
1423 | Restore: | 1423 | Restore: |
1424 | return pci_restore_state(dev); | 1424 | return dev->state_saved ? pci_restore_state(dev) : 0; |
1425 | } | 1425 | } |
1426 | 1426 | ||
1427 | /** | 1427 | /** |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 586b6f75910d..b0367f168af4 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -718,9 +718,9 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
718 | 718 | ||
719 | /* | 719 | /* |
720 | * All PCIe functions are in one slot, remove one function will remove | 720 | * All PCIe functions are in one slot, remove one function will remove |
721 | * the the whole slot, so just wait | 721 | * the whole slot, so just wait until we are the last function left. |
722 | */ | 722 | */ |
723 | if (!list_empty(&parent->subordinate->devices)) | 723 | if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices)) |
724 | goto out; | 724 | goto out; |
725 | 725 | ||
726 | /* All functions are removed, so just disable ASPM for the link */ | 726 | /* All functions are removed, so just disable ASPM for the link */ |
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 99a914a027f8..f9b874eaeb9f 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -55,25 +55,13 @@ static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) | |||
55 | 55 | ||
56 | } | 56 | } |
57 | 57 | ||
58 | static int pcie_portdrv_suspend_late(struct pci_dev *dev, pm_message_t state) | ||
59 | { | ||
60 | return pci_save_state(dev); | ||
61 | } | ||
62 | |||
63 | static int pcie_portdrv_resume_early(struct pci_dev *dev) | ||
64 | { | ||
65 | return pci_restore_state(dev); | ||
66 | } | ||
67 | |||
68 | static int pcie_portdrv_resume(struct pci_dev *dev) | 58 | static int pcie_portdrv_resume(struct pci_dev *dev) |
69 | { | 59 | { |
70 | pcie_portdrv_restore_config(dev); | 60 | pci_set_master(dev); |
71 | return pcie_port_device_resume(dev); | 61 | return pcie_port_device_resume(dev); |
72 | } | 62 | } |
73 | #else | 63 | #else |
74 | #define pcie_portdrv_suspend NULL | 64 | #define pcie_portdrv_suspend NULL |
75 | #define pcie_portdrv_suspend_late NULL | ||
76 | #define pcie_portdrv_resume_early NULL | ||
77 | #define pcie_portdrv_resume NULL | 65 | #define pcie_portdrv_resume NULL |
78 | #endif | 66 | #endif |
79 | 67 | ||
@@ -292,8 +280,6 @@ static struct pci_driver pcie_portdriver = { | |||
292 | .remove = pcie_portdrv_remove, | 280 | .remove = pcie_portdrv_remove, |
293 | 281 | ||
294 | .suspend = pcie_portdrv_suspend, | 282 | .suspend = pcie_portdrv_suspend, |
295 | .suspend_late = pcie_portdrv_suspend_late, | ||
296 | .resume_early = pcie_portdrv_resume_early, | ||
297 | .resume = pcie_portdrv_resume, | 283 | .resume = pcie_portdrv_resume, |
298 | 284 | ||
299 | .err_handler = &pcie_portdrv_err_handler, | 285 | .err_handler = &pcie_portdrv_err_handler, |
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 132a78159b60..29cbe47f219f 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c | |||
@@ -63,7 +63,7 @@ void pci_disable_rom(struct pci_dev *pdev) | |||
63 | * The PCI window size could be much larger than the | 63 | * The PCI window size could be much larger than the |
64 | * actual image size. | 64 | * actual image size. |
65 | */ | 65 | */ |
66 | size_t pci_get_rom_size(void __iomem *rom, size_t size) | 66 | size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) |
67 | { | 67 | { |
68 | void __iomem *image; | 68 | void __iomem *image; |
69 | int last_image; | 69 | int last_image; |
@@ -72,8 +72,10 @@ size_t pci_get_rom_size(void __iomem *rom, size_t size) | |||
72 | do { | 72 | do { |
73 | void __iomem *pds; | 73 | void __iomem *pds; |
74 | /* Standard PCI ROMs start out with these bytes 55 AA */ | 74 | /* Standard PCI ROMs start out with these bytes 55 AA */ |
75 | if (readb(image) != 0x55) | 75 | if (readb(image) != 0x55) { |
76 | dev_err(&pdev->dev, "Invalid ROM contents\n"); | ||
76 | break; | 77 | break; |
78 | } | ||
77 | if (readb(image + 1) != 0xAA) | 79 | if (readb(image + 1) != 0xAA) |
78 | break; | 80 | break; |
79 | /* get the PCI data structure and check its signature */ | 81 | /* get the PCI data structure and check its signature */ |
@@ -159,7 +161,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) | |||
159 | * size is much larger than the actual size of the ROM. | 161 | * size is much larger than the actual size of the ROM. |
160 | * True size is important if the ROM is going to be copied. | 162 | * True size is important if the ROM is going to be copied. |
161 | */ | 163 | */ |
162 | *size = pci_get_rom_size(rom, *size); | 164 | *size = pci_get_rom_size(pdev, rom, *size); |
163 | return rom; | 165 | return rom; |
164 | } | 166 | } |
165 | 167 | ||