Skip to content

Commit 2afbbc6

Browse files
committed
Merge branch 'pci/pm'
- Protect driver's D3cold preference from being overwritten by user space via sysfs (Lukas Wunner) - Avoid PME from D3hot/D3cold for AMD Rembrandt and Phoenix USB4 to fix wakeup by USB4-attached devices (Mario Limonciello) * pci/pm: x86/PCI: Avoid PME from D3hot/D3cold for AMD Rembrandt and Phoenix USB4 PCI/sysfs: Protect driver's D3cold preference from user space
2 parents 2094918 + 7d08f21 commit 2afbbc6

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

arch/x86/pci/fixup.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
44
*/
55

6+
#include <linux/bitfield.h>
67
#include <linux/delay.h>
78
#include <linux/dmi.h>
89
#include <linux/pci.h>
10+
#include <linux/suspend.h>
911
#include <linux/vgaarb.h>
1012
#include <asm/amd_nb.h>
1113
#include <asm/hpet.h>
@@ -904,3 +906,60 @@ static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev)
904906
}
905907
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
906908
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
909+
910+
#ifdef CONFIG_SUSPEND
911+
/*
912+
* Root Ports on some AMD SoCs advertise PME_Support for D3hot and D3cold, but
913+
* if the SoC is put into a hardware sleep state by the amd-pmc driver, the
914+
* Root Ports don't generate wakeup interrupts for USB devices.
915+
*
916+
* When suspending, remove D3hot and D3cold from the PME_Support advertised
917+
* by the Root Port so we don't use those states if we're expecting wakeup
918+
* interrupts. Restore the advertised PME_Support when resuming.
919+
*/
920+
static void amd_rp_pme_suspend(struct pci_dev *dev)
921+
{
922+
struct pci_dev *rp;
923+
924+
/*
925+
* PM_SUSPEND_ON means we're doing runtime suspend, which means
926+
* amd-pmc will not be involved so PMEs during D3 work as advertised.
927+
*
928+
* The PMEs *do* work if amd-pmc doesn't put the SoC in the hardware
929+
* sleep state, but we assume amd-pmc is always present.
930+
*/
931+
if (pm_suspend_target_state == PM_SUSPEND_ON)
932+
return;
933+
934+
rp = pcie_find_root_port(dev);
935+
if (!rp->pm_cap)
936+
return;
937+
938+
rp->pme_support &= ~((PCI_PM_CAP_PME_D3hot|PCI_PM_CAP_PME_D3cold) >>
939+
PCI_PM_CAP_PME_SHIFT);
940+
dev_info_once(&rp->dev, "quirk: disabling D3cold for suspend\n");
941+
}
942+
943+
static void amd_rp_pme_resume(struct pci_dev *dev)
944+
{
945+
struct pci_dev *rp;
946+
u16 pmc;
947+
948+
rp = pcie_find_root_port(dev);
949+
if (!rp->pm_cap)
950+
return;
951+
952+
pci_read_config_word(rp, rp->pm_cap + PCI_PM_PMC, &pmc);
953+
rp->pme_support = FIELD_GET(PCI_PM_CAP_PME_MASK, pmc);
954+
}
955+
/* Rembrandt (yellow_carp) */
956+
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_suspend);
957+
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_resume);
958+
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_suspend);
959+
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_resume);
960+
/* Phoenix (pink_sardine) */
961+
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_suspend);
962+
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_resume);
963+
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_suspend);
964+
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_resume);
965+
#endif /* CONFIG_SUSPEND */

drivers/pci/pci-acpi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
911911
{
912912
int acpi_state, d_max;
913913

914-
if (pdev->no_d3cold)
914+
if (pdev->no_d3cold || !pdev->d3cold_allowed)
915915
d_max = ACPI_STATE_D3_HOT;
916916
else
917917
d_max = ACPI_STATE_D3_COLD;

drivers/pci/pci-sysfs.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -530,10 +530,7 @@ static ssize_t d3cold_allowed_store(struct device *dev,
530530
return -EINVAL;
531531

532532
pdev->d3cold_allowed = !!val;
533-
if (pdev->d3cold_allowed)
534-
pci_d3cold_enable(pdev);
535-
else
536-
pci_d3cold_disable(pdev);
533+
pci_bridge_d3_update(pdev);
537534

538535
pm_runtime_resume(dev);
539536

0 commit comments

Comments
 (0)