diff options
author | Andreas Noever <andreas.noever@gmail.com> | 2014-06-03 16:04:09 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-06-19 17:08:41 -0400 |
commit | 7d2a01b87f1682fde87461864e6682031bfaa0a9 (patch) | |
tree | 071da51f78bd9b2091ea9663be6d0dde4069492e | |
parent | 3364f0c12795713e89ae1209081c60d64bfb4ca1 (diff) |
PCI: Add pci_fixup_suspend_late quirk pass
Add pci_fixup_suspend_late as a new pci_fixup_pass. The pass is called
from suspend_noirq and poweroff_noirq. Using the same pass for suspend
and hibernate is consistent with resume_early which is called by
resume_noirq and restore_noirq.
The new quirk pass is required for Thunderbolt support on Apple
hardware.
Signed-off-by: Andreas Noever <andreas.noever@gmail.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/pci/pci-driver.c | 18 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 7 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 3 | ||||
-rw-r--r-- | include/linux/pci.h | 12 |
4 files changed, 35 insertions, 5 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 3f8e3dbcaa7c..d04c5adafc16 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -582,7 +582,7 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) | |||
582 | WARN_ONCE(pci_dev->current_state != prev, | 582 | WARN_ONCE(pci_dev->current_state != prev, |
583 | "PCI PM: Device state not saved by %pF\n", | 583 | "PCI PM: Device state not saved by %pF\n", |
584 | drv->suspend_late); | 584 | drv->suspend_late); |
585 | return 0; | 585 | goto Fixup; |
586 | } | 586 | } |
587 | } | 587 | } |
588 | 588 | ||
@@ -591,6 +591,9 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) | |||
591 | 591 | ||
592 | pci_pm_set_unknown_state(pci_dev); | 592 | pci_pm_set_unknown_state(pci_dev); |
593 | 593 | ||
594 | Fixup: | ||
595 | pci_fixup_device(pci_fixup_suspend_late, pci_dev); | ||
596 | |||
594 | return 0; | 597 | return 0; |
595 | } | 598 | } |
596 | 599 | ||
@@ -734,7 +737,7 @@ static int pci_pm_suspend_noirq(struct device *dev) | |||
734 | 737 | ||
735 | if (!pm) { | 738 | if (!pm) { |
736 | pci_save_state(pci_dev); | 739 | pci_save_state(pci_dev); |
737 | return 0; | 740 | goto Fixup; |
738 | } | 741 | } |
739 | 742 | ||
740 | if (pm->suspend_noirq) { | 743 | if (pm->suspend_noirq) { |
@@ -751,7 +754,7 @@ static int pci_pm_suspend_noirq(struct device *dev) | |||
751 | WARN_ONCE(pci_dev->current_state != prev, | 754 | WARN_ONCE(pci_dev->current_state != prev, |
752 | "PCI PM: State of device not saved by %pF\n", | 755 | "PCI PM: State of device not saved by %pF\n", |
753 | pm->suspend_noirq); | 756 | pm->suspend_noirq); |
754 | return 0; | 757 | goto Fixup; |
755 | } | 758 | } |
756 | } | 759 | } |
757 | 760 | ||
@@ -775,6 +778,9 @@ static int pci_pm_suspend_noirq(struct device *dev) | |||
775 | if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) | 778 | if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) |
776 | pci_write_config_word(pci_dev, PCI_COMMAND, 0); | 779 | pci_write_config_word(pci_dev, PCI_COMMAND, 0); |
777 | 780 | ||
781 | Fixup: | ||
782 | pci_fixup_device(pci_fixup_suspend_late, pci_dev); | ||
783 | |||
778 | return 0; | 784 | return 0; |
779 | } | 785 | } |
780 | 786 | ||
@@ -999,8 +1005,10 @@ static int pci_pm_poweroff_noirq(struct device *dev) | |||
999 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) | 1005 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) |
1000 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); | 1006 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); |
1001 | 1007 | ||
1002 | if (!drv || !drv->pm) | 1008 | if (!drv || !drv->pm) { |
1009 | pci_fixup_device(pci_fixup_suspend_late, pci_dev); | ||
1003 | return 0; | 1010 | return 0; |
1011 | } | ||
1004 | 1012 | ||
1005 | if (drv->pm->poweroff_noirq) { | 1013 | if (drv->pm->poweroff_noirq) { |
1006 | int error; | 1014 | int error; |
@@ -1021,6 +1029,8 @@ static int pci_pm_poweroff_noirq(struct device *dev) | |||
1021 | if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) | 1029 | if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI) |
1022 | pci_write_config_word(pci_dev, PCI_COMMAND, 0); | 1030 | pci_write_config_word(pci_dev, PCI_COMMAND, 0); |
1023 | 1031 | ||
1032 | pci_fixup_device(pci_fixup_suspend_late, pci_dev); | ||
1033 | |||
1024 | if (pcibios_pm_ops.poweroff_noirq) | 1034 | if (pcibios_pm_ops.poweroff_noirq) |
1025 | return pcibios_pm_ops.poweroff_noirq(dev); | 1035 | return pcibios_pm_ops.poweroff_noirq(dev); |
1026 | 1036 | ||
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d0f69269eb6c..03266af20d5f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -3018,6 +3018,8 @@ extern struct pci_fixup __start_pci_fixups_resume_early[]; | |||
3018 | extern struct pci_fixup __end_pci_fixups_resume_early[]; | 3018 | extern struct pci_fixup __end_pci_fixups_resume_early[]; |
3019 | extern struct pci_fixup __start_pci_fixups_suspend[]; | 3019 | extern struct pci_fixup __start_pci_fixups_suspend[]; |
3020 | extern struct pci_fixup __end_pci_fixups_suspend[]; | 3020 | extern struct pci_fixup __end_pci_fixups_suspend[]; |
3021 | extern struct pci_fixup __start_pci_fixups_suspend_late[]; | ||
3022 | extern struct pci_fixup __end_pci_fixups_suspend_late[]; | ||
3021 | 3023 | ||
3022 | static bool pci_apply_fixup_final_quirks; | 3024 | static bool pci_apply_fixup_final_quirks; |
3023 | 3025 | ||
@@ -3063,6 +3065,11 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) | |||
3063 | end = __end_pci_fixups_suspend; | 3065 | end = __end_pci_fixups_suspend; |
3064 | break; | 3066 | break; |
3065 | 3067 | ||
3068 | case pci_fixup_suspend_late: | ||
3069 | start = __start_pci_fixups_suspend_late; | ||
3070 | end = __end_pci_fixups_suspend_late; | ||
3071 | break; | ||
3072 | |||
3066 | default: | 3073 | default: |
3067 | /* stupid compiler warning, you would think with an enum... */ | 3074 | /* stupid compiler warning, you would think with an enum... */ |
3068 | return; | 3075 | return; |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 471ba48c7ae4..47cd98656f9d 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -268,6 +268,9 @@ | |||
268 | VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ | 268 | VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ |
269 | *(.pci_fixup_suspend) \ | 269 | *(.pci_fixup_suspend) \ |
270 | VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ | 270 | VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ |
271 | VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \ | ||
272 | *(.pci_fixup_suspend_late) \ | ||
273 | VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ | ||
271 | } \ | 274 | } \ |
272 | \ | 275 | \ |
273 | /* Built-in firmware blobs */ \ | 276 | /* Built-in firmware blobs */ \ |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 466bcd111d85..295d3a9d8ffe 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1477,8 +1477,9 @@ enum pci_fixup_pass { | |||
1477 | pci_fixup_final, /* Final phase of device fixups */ | 1477 | pci_fixup_final, /* Final phase of device fixups */ |
1478 | pci_fixup_enable, /* pci_enable_device() time */ | 1478 | pci_fixup_enable, /* pci_enable_device() time */ |
1479 | pci_fixup_resume, /* pci_device_resume() */ | 1479 | pci_fixup_resume, /* pci_device_resume() */ |
1480 | pci_fixup_suspend, /* pci_device_suspend */ | 1480 | pci_fixup_suspend, /* pci_device_suspend() */ |
1481 | pci_fixup_resume_early, /* pci_device_resume_early() */ | 1481 | pci_fixup_resume_early, /* pci_device_resume_early() */ |
1482 | pci_fixup_suspend_late, /* pci_device_suspend_late() */ | ||
1482 | }; | 1483 | }; |
1483 | 1484 | ||
1484 | /* Anonymous variables would be nice... */ | 1485 | /* Anonymous variables would be nice... */ |
@@ -1519,6 +1520,11 @@ enum pci_fixup_pass { | |||
1519 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \ | 1520 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \ |
1520 | suspend##hook, vendor, device, class, \ | 1521 | suspend##hook, vendor, device, class, \ |
1521 | class_shift, hook) | 1522 | class_shift, hook) |
1523 | #define DECLARE_PCI_FIXUP_CLASS_SUSPEND_LATE(vendor, device, class, \ | ||
1524 | class_shift, hook) \ | ||
1525 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \ | ||
1526 | suspend_late##hook, vendor, device, \ | ||
1527 | class, class_shift, hook) | ||
1522 | 1528 | ||
1523 | #define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \ | 1529 | #define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \ |
1524 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \ | 1530 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \ |
@@ -1544,6 +1550,10 @@ enum pci_fixup_pass { | |||
1544 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \ | 1550 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \ |
1545 | suspend##hook, vendor, device, \ | 1551 | suspend##hook, vendor, device, \ |
1546 | PCI_ANY_ID, 0, hook) | 1552 | PCI_ANY_ID, 0, hook) |
1553 | #define DECLARE_PCI_FIXUP_SUSPEND_LATE(vendor, device, hook) \ | ||
1554 | DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \ | ||
1555 | suspend_late##hook, vendor, device, \ | ||
1556 | PCI_ANY_ID, 0, hook) | ||
1547 | 1557 | ||
1548 | #ifdef CONFIG_PCI_QUIRKS | 1558 | #ifdef CONFIG_PCI_QUIRKS |
1549 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); | 1559 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); |