Skip to content
Permalink
Browse files
PCI: vmd: Override ASPM on TGL/ADL VMD devices
On Tiger Lake and Alder Lake platforms, VMD controllers do not have ASPM
enabled nor LTR values set by BIOS. This leads high power consumption on
these platforms when VMD is enabled as reported in bugzilla [1].  Enable
these features in the VMD driver using pcie_aspm_policy_override() to set
the ASPM policy for the root ports.

To do this, add an additional flag in VMD features to specify devices that
must have their respective policies overridden.

[1] https://bugzilla.kernel.org/show_bug.cgi?id=213717

Signed-off-by: Michael Bottini <michael.a.bottini@linux.intel.com>
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
  • Loading branch information
Michael Bottini authored and intel-lab-lkp committed Nov 20, 2021
1 parent 43c71b2 commit d0452407e2d5bf22bd1094654d7e868311b7c94e
Showing 1 changed file with 37 additions and 3 deletions.
@@ -20,6 +20,8 @@

#include <asm/irqdomain.h>

#include "../pci.h"

#define VMD_CFGBAR 0
#define VMD_MEMBAR1 2
#define VMD_MEMBAR2 4
@@ -67,6 +69,12 @@ enum vmd_features {
* interrupt handling.
*/
VMD_FEAT_CAN_BYPASS_MSI_REMAP = (1 << 4),

/*
* Device must have ASPM policy overridden, as its default policy is
* incorrect.
*/
VMD_FEAT_QUIRK_OVERRIDE_ASPM = (1 << 5),
};

static DEFINE_IDA(vmd_instance_ida);
@@ -661,6 +669,27 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd)
return 0;
}

/*
* Override the BIOS ASPM policy and set the LTR value for PCI storage
* devices on the VMD bride.
*/
int vmd_enable_aspm(struct pci_dev *pdev, void *userdata)
{
int features = *(int *)userdata;

if (features & VMD_FEAT_QUIRK_OVERRIDE_ASPM &&
pdev->class == PCI_CLASS_STORAGE_EXPRESS) {
int pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);

if (pos) {
pci_write_config_word(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, 0x1003);
pci_write_config_word(pdev, pos + PCI_LTR_MAX_NOSNOOP_LAT, 0x1003);
pcie_aspm_policy_override(pdev);
}
}
return 0;
}

static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
{
struct pci_sysdata *sd = &vmd->sysdata;
@@ -807,6 +836,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
pci_scan_child_bus(vmd->bus);
pci_assign_unassigned_bus_resources(vmd->bus);

pci_walk_bus(vmd->bus, vmd_enable_aspm, &features);

/*
* VMD root buses are virtual and don't return true on pci_is_pcie()
* and will fail pcie_bus_configure_settings() early. It can instead be
@@ -948,15 +979,18 @@ static const struct pci_device_id vmd_ids[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
VMD_FEAT_OFFSET_FIRST_VECTOR |
VMD_FEAT_QUIRK_OVERRIDE_ASPM,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
VMD_FEAT_OFFSET_FIRST_VECTOR |
VMD_FEAT_QUIRK_OVERRIDE_ASPM,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
VMD_FEAT_OFFSET_FIRST_VECTOR |
VMD_FEAT_QUIRK_OVERRIDE_ASPM,},
{0,}
};
MODULE_DEVICE_TABLE(pci, vmd_ids);

0 comments on commit d045240

Please sign in to comment.