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>
This commit is contained in:
parent
3364f0c127
commit
7d2a01b87f
|
@ -582,7 +582,7 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
|
||||||
WARN_ONCE(pci_dev->current_state != prev,
|
WARN_ONCE(pci_dev->current_state != prev,
|
||||||
"PCI PM: Device state not saved by %pF\n",
|
"PCI PM: Device state not saved by %pF\n",
|
||||||
drv->suspend_late);
|
drv->suspend_late);
|
||||||
return 0;
|
goto Fixup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,6 +591,9 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
|
||||||
|
|
||||||
pci_pm_set_unknown_state(pci_dev);
|
pci_pm_set_unknown_state(pci_dev);
|
||||||
|
|
||||||
|
Fixup:
|
||||||
|
pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,7 +737,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
|
||||||
|
|
||||||
if (!pm) {
|
if (!pm) {
|
||||||
pci_save_state(pci_dev);
|
pci_save_state(pci_dev);
|
||||||
return 0;
|
goto Fixup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pm->suspend_noirq) {
|
if (pm->suspend_noirq) {
|
||||||
|
@ -751,7 +754,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
|
||||||
WARN_ONCE(pci_dev->current_state != prev,
|
WARN_ONCE(pci_dev->current_state != prev,
|
||||||
"PCI PM: State of device not saved by %pF\n",
|
"PCI PM: State of device not saved by %pF\n",
|
||||||
pm->suspend_noirq);
|
pm->suspend_noirq);
|
||||||
return 0;
|
goto Fixup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,6 +778,9 @@ static int pci_pm_suspend_noirq(struct device *dev)
|
||||||
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
||||||
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
|
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
|
||||||
|
|
||||||
|
Fixup:
|
||||||
|
pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,8 +1005,10 @@ static int pci_pm_poweroff_noirq(struct device *dev)
|
||||||
if (pci_has_legacy_pm_support(to_pci_dev(dev)))
|
if (pci_has_legacy_pm_support(to_pci_dev(dev)))
|
||||||
return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
|
return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
|
||||||
|
|
||||||
if (!drv || !drv->pm)
|
if (!drv || !drv->pm) {
|
||||||
|
pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (drv->pm->poweroff_noirq) {
|
if (drv->pm->poweroff_noirq) {
|
||||||
int error;
|
int error;
|
||||||
|
@ -1021,6 +1029,8 @@ static int pci_pm_poweroff_noirq(struct device *dev)
|
||||||
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
||||||
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
|
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
|
||||||
|
|
||||||
|
pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||||
|
|
||||||
if (pcibios_pm_ops.poweroff_noirq)
|
if (pcibios_pm_ops.poweroff_noirq)
|
||||||
return pcibios_pm_ops.poweroff_noirq(dev);
|
return pcibios_pm_ops.poweroff_noirq(dev);
|
||||||
|
|
||||||
|
|
|
@ -3018,6 +3018,8 @@ extern struct pci_fixup __start_pci_fixups_resume_early[];
|
||||||
extern struct pci_fixup __end_pci_fixups_resume_early[];
|
extern struct pci_fixup __end_pci_fixups_resume_early[];
|
||||||
extern struct pci_fixup __start_pci_fixups_suspend[];
|
extern struct pci_fixup __start_pci_fixups_suspend[];
|
||||||
extern struct pci_fixup __end_pci_fixups_suspend[];
|
extern struct pci_fixup __end_pci_fixups_suspend[];
|
||||||
|
extern struct pci_fixup __start_pci_fixups_suspend_late[];
|
||||||
|
extern struct pci_fixup __end_pci_fixups_suspend_late[];
|
||||||
|
|
||||||
static bool pci_apply_fixup_final_quirks;
|
static bool pci_apply_fixup_final_quirks;
|
||||||
|
|
||||||
|
@ -3063,6 +3065,11 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
|
||||||
end = __end_pci_fixups_suspend;
|
end = __end_pci_fixups_suspend;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case pci_fixup_suspend_late:
|
||||||
|
start = __start_pci_fixups_suspend_late;
|
||||||
|
end = __end_pci_fixups_suspend_late;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* stupid compiler warning, you would think with an enum... */
|
/* stupid compiler warning, you would think with an enum... */
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -268,6 +268,9 @@
|
||||||
VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \
|
VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \
|
||||||
*(.pci_fixup_suspend) \
|
*(.pci_fixup_suspend) \
|
||||||
VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \
|
VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \
|
||||||
|
*(.pci_fixup_suspend_late) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Built-in firmware blobs */ \
|
/* Built-in firmware blobs */ \
|
||||||
|
|
|
@ -1477,8 +1477,9 @@ enum pci_fixup_pass {
|
||||||
pci_fixup_final, /* Final phase of device fixups */
|
pci_fixup_final, /* Final phase of device fixups */
|
||||||
pci_fixup_enable, /* pci_enable_device() time */
|
pci_fixup_enable, /* pci_enable_device() time */
|
||||||
pci_fixup_resume, /* pci_device_resume() */
|
pci_fixup_resume, /* pci_device_resume() */
|
||||||
pci_fixup_suspend, /* pci_device_suspend */
|
pci_fixup_suspend, /* pci_device_suspend() */
|
||||||
pci_fixup_resume_early, /* pci_device_resume_early() */
|
pci_fixup_resume_early, /* pci_device_resume_early() */
|
||||||
|
pci_fixup_suspend_late, /* pci_device_suspend_late() */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Anonymous variables would be nice... */
|
/* Anonymous variables would be nice... */
|
||||||
|
@ -1519,6 +1520,11 @@ enum pci_fixup_pass {
|
||||||
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
|
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
|
||||||
suspend##hook, vendor, device, class, \
|
suspend##hook, vendor, device, class, \
|
||||||
class_shift, hook)
|
class_shift, hook)
|
||||||
|
#define DECLARE_PCI_FIXUP_CLASS_SUSPEND_LATE(vendor, device, class, \
|
||||||
|
class_shift, hook) \
|
||||||
|
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \
|
||||||
|
suspend_late##hook, vendor, device, \
|
||||||
|
class, class_shift, hook)
|
||||||
|
|
||||||
#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \
|
#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \
|
||||||
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
|
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
|
||||||
|
@ -1544,6 +1550,10 @@ enum pci_fixup_pass {
|
||||||
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
|
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
|
||||||
suspend##hook, vendor, device, \
|
suspend##hook, vendor, device, \
|
||||||
PCI_ANY_ID, 0, hook)
|
PCI_ANY_ID, 0, hook)
|
||||||
|
#define DECLARE_PCI_FIXUP_SUSPEND_LATE(vendor, device, hook) \
|
||||||
|
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \
|
||||||
|
suspend_late##hook, vendor, device, \
|
||||||
|
PCI_ANY_ID, 0, hook)
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_QUIRKS
|
#ifdef CONFIG_PCI_QUIRKS
|
||||||
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
|
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
|
||||||
|
|
Loading…
Reference in New Issue