mirror of
https://github.com/torvalds/linux.git
synced 2025-11-03 01:59:51 +02:00
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
This commit is contained in:
commit
2afbbc65be
3 changed files with 61 additions and 5 deletions
|
|
@ -3,9 +3,11 @@
|
||||||
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
|
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
#include <linux/vgaarb.h>
|
#include <linux/vgaarb.h>
|
||||||
#include <asm/amd_nb.h>
|
#include <asm/amd_nb.h>
|
||||||
#include <asm/hpet.h>
|
#include <asm/hpet.h>
|
||||||
|
|
@ -904,3 +906,60 @@ static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev)
|
||||||
}
|
}
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
|
||||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUSPEND
|
||||||
|
/*
|
||||||
|
* Root Ports on some AMD SoCs advertise PME_Support for D3hot and D3cold, but
|
||||||
|
* if the SoC is put into a hardware sleep state by the amd-pmc driver, the
|
||||||
|
* Root Ports don't generate wakeup interrupts for USB devices.
|
||||||
|
*
|
||||||
|
* When suspending, remove D3hot and D3cold from the PME_Support advertised
|
||||||
|
* by the Root Port so we don't use those states if we're expecting wakeup
|
||||||
|
* interrupts. Restore the advertised PME_Support when resuming.
|
||||||
|
*/
|
||||||
|
static void amd_rp_pme_suspend(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct pci_dev *rp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PM_SUSPEND_ON means we're doing runtime suspend, which means
|
||||||
|
* amd-pmc will not be involved so PMEs during D3 work as advertised.
|
||||||
|
*
|
||||||
|
* The PMEs *do* work if amd-pmc doesn't put the SoC in the hardware
|
||||||
|
* sleep state, but we assume amd-pmc is always present.
|
||||||
|
*/
|
||||||
|
if (pm_suspend_target_state == PM_SUSPEND_ON)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rp = pcie_find_root_port(dev);
|
||||||
|
if (!rp->pm_cap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rp->pme_support &= ~((PCI_PM_CAP_PME_D3hot|PCI_PM_CAP_PME_D3cold) >>
|
||||||
|
PCI_PM_CAP_PME_SHIFT);
|
||||||
|
dev_info_once(&rp->dev, "quirk: disabling D3cold for suspend\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amd_rp_pme_resume(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct pci_dev *rp;
|
||||||
|
u16 pmc;
|
||||||
|
|
||||||
|
rp = pcie_find_root_port(dev);
|
||||||
|
if (!rp->pm_cap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_read_config_word(rp, rp->pm_cap + PCI_PM_PMC, &pmc);
|
||||||
|
rp->pme_support = FIELD_GET(PCI_PM_CAP_PME_MASK, pmc);
|
||||||
|
}
|
||||||
|
/* Rembrandt (yellow_carp) */
|
||||||
|
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_suspend);
|
||||||
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_resume);
|
||||||
|
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_suspend);
|
||||||
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_resume);
|
||||||
|
/* Phoenix (pink_sardine) */
|
||||||
|
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_suspend);
|
||||||
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_resume);
|
||||||
|
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_suspend);
|
||||||
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_resume);
|
||||||
|
#endif /* CONFIG_SUSPEND */
|
||||||
|
|
|
||||||
|
|
@ -911,7 +911,7 @@ pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
int acpi_state, d_max;
|
int acpi_state, d_max;
|
||||||
|
|
||||||
if (pdev->no_d3cold)
|
if (pdev->no_d3cold || !pdev->d3cold_allowed)
|
||||||
d_max = ACPI_STATE_D3_HOT;
|
d_max = ACPI_STATE_D3_HOT;
|
||||||
else
|
else
|
||||||
d_max = ACPI_STATE_D3_COLD;
|
d_max = ACPI_STATE_D3_COLD;
|
||||||
|
|
|
||||||
|
|
@ -530,10 +530,7 @@ static ssize_t d3cold_allowed_store(struct device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
pdev->d3cold_allowed = !!val;
|
pdev->d3cold_allowed = !!val;
|
||||||
if (pdev->d3cold_allowed)
|
pci_bridge_d3_update(pdev);
|
||||||
pci_d3cold_enable(pdev);
|
|
||||||
else
|
|
||||||
pci_d3cold_disable(pdev);
|
|
||||||
|
|
||||||
pm_runtime_resume(dev);
|
pm_runtime_resume(dev);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue