Skip to content

Commit 90fb1a3

Browse files
committed
Merge branch 'pci/controller/vmd'
- Add pci_enable_link_state() to allow drivers to enable ASPM link state (Michael Bottini) - Add quirk to enable all ASPM link states and program LTR for devices below VMD (David E. Box) * pci/controller/vmd: PCI: vmd: Add quirk to configure PCIe ASPM and LTR PCI: vmd: Create feature grouping for client products PCI: vmd: Use PCI_VDEVICE in device list PCI/ASPM: Add pci_enable_link_state()
2 parents 69ed52b + f492edb commit 90fb1a3

File tree

3 files changed

+132
-26
lines changed

3 files changed

+132
-26
lines changed

drivers/pci/controller/vmd.c

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,23 @@ enum vmd_features {
6666
* interrupt handling.
6767
*/
6868
VMD_FEAT_CAN_BYPASS_MSI_REMAP = (1 << 4),
69+
70+
/*
71+
* Enable ASPM on the PCIE root ports and set the default LTR of the
72+
* storage devices on platforms where these values are not configured by
73+
* BIOS. This is needed for laptops, which require these settings for
74+
* proper power management of the SoC.
75+
*/
76+
VMD_FEAT_BIOS_PM_QUIRK = (1 << 5),
6977
};
7078

79+
#define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */
80+
81+
#define VMD_FEATS_CLIENT (VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | \
82+
VMD_FEAT_HAS_BUS_RESTRICTIONS | \
83+
VMD_FEAT_OFFSET_FIRST_VECTOR | \
84+
VMD_FEAT_BIOS_PM_QUIRK)
85+
7186
static DEFINE_IDA(vmd_instance_ida);
7287

7388
/*
@@ -709,6 +724,46 @@ static void vmd_copy_host_bridge_flags(struct pci_host_bridge *root_bridge,
709724
vmd_bridge->native_dpc = root_bridge->native_dpc;
710725
}
711726

727+
/*
728+
* Enable ASPM and LTR settings on devices that aren't configured by BIOS.
729+
*/
730+
static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
731+
{
732+
unsigned long features = *(unsigned long *)userdata;
733+
u16 ltr = VMD_BIOS_PM_QUIRK_LTR;
734+
u32 ltr_reg;
735+
int pos;
736+
737+
if (!(features & VMD_FEAT_BIOS_PM_QUIRK))
738+
return 0;
739+
740+
pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
741+
742+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
743+
if (!pos)
744+
return 0;
745+
746+
/*
747+
* Skip if the max snoop LTR is non-zero, indicating BIOS has set it
748+
* so the LTR quirk is not needed.
749+
*/
750+
pci_read_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, &ltr_reg);
751+
if (!!(ltr_reg & (PCI_LTR_VALUE_MASK | PCI_LTR_SCALE_MASK)))
752+
return 0;
753+
754+
/*
755+
* Set the default values to the maximum required by the platform to
756+
* allow the deepest power management savings. Write as a DWORD where
757+
* the lower word is the max snoop latency and the upper word is the
758+
* max non-snoop latency.
759+
*/
760+
ltr_reg = (ltr << 16) | ltr;
761+
pci_write_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, ltr_reg);
762+
pci_info(pdev, "VMD: Default LTR value set by driver\n");
763+
764+
return 0;
765+
}
766+
712767
static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
713768
{
714769
struct pci_sysdata *sd = &vmd->sysdata;
@@ -881,6 +936,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
881936

882937
pci_assign_unassigned_bus_resources(vmd->bus);
883938

939+
pci_walk_bus(vmd->bus, vmd_pm_enable_quirk, &features);
940+
884941
/*
885942
* VMD root buses are virtual and don't return true on pci_is_pcie()
886943
* and will fail pcie_bus_configure_settings() early. It can instead be
@@ -1017,36 +1074,24 @@ static int vmd_resume(struct device *dev)
10171074
static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);
10181075

10191076
static const struct pci_device_id vmd_ids[] = {
1020-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
1077+
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
10211078
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},
1022-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
1079+
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
10231080
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
10241081
VMD_FEAT_HAS_BUS_RESTRICTIONS |
10251082
VMD_FEAT_CAN_BYPASS_MSI_REMAP,},
1026-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
1027-
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
1028-
VMD_FEAT_HAS_BUS_RESTRICTIONS |
1029-
VMD_FEAT_OFFSET_FIRST_VECTOR,},
1030-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
1031-
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
1032-
VMD_FEAT_HAS_BUS_RESTRICTIONS |
1033-
VMD_FEAT_OFFSET_FIRST_VECTOR,},
1034-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa77f),
1035-
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
1036-
VMD_FEAT_HAS_BUS_RESTRICTIONS |
1037-
VMD_FEAT_OFFSET_FIRST_VECTOR,},
1038-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7d0b),
1039-
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
1040-
VMD_FEAT_HAS_BUS_RESTRICTIONS |
1041-
VMD_FEAT_OFFSET_FIRST_VECTOR,},
1042-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xad0b),
1043-
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
1044-
VMD_FEAT_HAS_BUS_RESTRICTIONS |
1045-
VMD_FEAT_OFFSET_FIRST_VECTOR,},
1046-
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
1047-
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
1048-
VMD_FEAT_HAS_BUS_RESTRICTIONS |
1049-
VMD_FEAT_OFFSET_FIRST_VECTOR,},
1083+
{PCI_VDEVICE(INTEL, 0x467f),
1084+
.driver_data = VMD_FEATS_CLIENT,},
1085+
{PCI_VDEVICE(INTEL, 0x4c3d),
1086+
.driver_data = VMD_FEATS_CLIENT,},
1087+
{PCI_VDEVICE(INTEL, 0xa77f),
1088+
.driver_data = VMD_FEATS_CLIENT,},
1089+
{PCI_VDEVICE(INTEL, 0x7d0b),
1090+
.driver_data = VMD_FEATS_CLIENT,},
1091+
{PCI_VDEVICE(INTEL, 0xad0b),
1092+
.driver_data = VMD_FEATS_CLIENT,},
1093+
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
1094+
.driver_data = VMD_FEATS_CLIENT,},
10501095
{0,}
10511096
};
10521097
MODULE_DEVICE_TABLE(pci, vmd_ids);

drivers/pci/pcie/aspm.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,60 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
11811181
}
11821182
EXPORT_SYMBOL(pci_disable_link_state);
11831183

1184+
/**
1185+
* pci_enable_link_state - Clear and set the default device link state so that
1186+
* the link may be allowed to enter the specified states. Note that if the
1187+
* BIOS didn't grant ASPM control to the OS, this does nothing because we can't
1188+
* touch the LNKCTL register. Also note that this does not enable states
1189+
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
1190+
*
1191+
* @pdev: PCI device
1192+
* @state: Mask of ASPM link states to enable
1193+
*/
1194+
int pci_enable_link_state(struct pci_dev *pdev, int state)
1195+
{
1196+
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1197+
1198+
if (!link)
1199+
return -EINVAL;
1200+
/*
1201+
* A driver requested that ASPM be enabled on this device, but
1202+
* if we don't have permission to manage ASPM (e.g., on ACPI
1203+
* systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
1204+
* the _OSC method), we can't honor that request.
1205+
*/
1206+
if (aspm_disabled) {
1207+
pci_warn(pdev, "can't override BIOS ASPM; OS doesn't have ASPM control\n");
1208+
return -EPERM;
1209+
}
1210+
1211+
down_read(&pci_bus_sem);
1212+
mutex_lock(&aspm_lock);
1213+
link->aspm_default = 0;
1214+
if (state & PCIE_LINK_STATE_L0S)
1215+
link->aspm_default |= ASPM_STATE_L0S;
1216+
if (state & PCIE_LINK_STATE_L1)
1217+
/* L1 PM substates require L1 */
1218+
link->aspm_default |= ASPM_STATE_L1 | ASPM_STATE_L1SS;
1219+
if (state & PCIE_LINK_STATE_L1_1)
1220+
link->aspm_default |= ASPM_STATE_L1_1;
1221+
if (state & PCIE_LINK_STATE_L1_2)
1222+
link->aspm_default |= ASPM_STATE_L1_2;
1223+
if (state & PCIE_LINK_STATE_L1_1_PCIPM)
1224+
link->aspm_default |= ASPM_STATE_L1_1_PCIPM;
1225+
if (state & PCIE_LINK_STATE_L1_2_PCIPM)
1226+
link->aspm_default |= ASPM_STATE_L1_2_PCIPM;
1227+
pcie_config_aspm_link(link, policy_to_aspm_state(link));
1228+
1229+
link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
1230+
pcie_set_clkpm(link, policy_to_clkpm_state(link));
1231+
mutex_unlock(&aspm_lock);
1232+
up_read(&pci_bus_sem);
1233+
1234+
return 0;
1235+
}
1236+
EXPORT_SYMBOL(pci_enable_link_state);
1237+
11841238
static int pcie_aspm_set_policy(const char *val,
11851239
const struct kernel_param *kp)
11861240
{

include/linux/pci.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,10 +1686,15 @@ extern bool pcie_ports_native;
16861686
#define PCIE_LINK_STATE_L1_2 BIT(4)
16871687
#define PCIE_LINK_STATE_L1_1_PCIPM BIT(5)
16881688
#define PCIE_LINK_STATE_L1_2_PCIPM BIT(6)
1689+
#define PCIE_LINK_STATE_ALL (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |\
1690+
PCIE_LINK_STATE_CLKPM | PCIE_LINK_STATE_L1_1 |\
1691+
PCIE_LINK_STATE_L1_2 | PCIE_LINK_STATE_L1_1_PCIPM |\
1692+
PCIE_LINK_STATE_L1_2_PCIPM)
16891693

16901694
#ifdef CONFIG_PCIEASPM
16911695
int pci_disable_link_state(struct pci_dev *pdev, int state);
16921696
int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
1697+
int pci_enable_link_state(struct pci_dev *pdev, int state);
16931698
void pcie_no_aspm(void);
16941699
bool pcie_aspm_support_enabled(void);
16951700
bool pcie_aspm_enabled(struct pci_dev *pdev);
@@ -1698,6 +1703,8 @@ static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
16981703
{ return 0; }
16991704
static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
17001705
{ return 0; }
1706+
static inline int pci_enable_link_state(struct pci_dev *pdev, int state)
1707+
{ return 0; }
17011708
static inline void pcie_no_aspm(void) { }
17021709
static inline bool pcie_aspm_support_enabled(void) { return false; }
17031710
static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; }

0 commit comments

Comments
 (0)