Skip to content

Commit b5364e6

Browse files
hkallweitSeth Forshee
authored andcommitted
PCI/ASPM: Add sysfs attributes for controlling ASPM link states
BugLink: https://bugs.launchpad.net/ubuntu/bugs/1836030 Add sysfs attributes to Endpoints and other Upstream Ports to control ASPM, Clock PM, and L1 PM Substates. The new attributes are: /sys/devices/pci*/.../link/clkpm /sys/devices/pci*/.../link/l0s_aspm /sys/devices/pci*/.../link/l1_aspm /sys/devices/pci*/.../link/l1_1_aspm /sys/devices/pci*/.../link/l1_2_aspm /sys/devices/pci*/.../link/l1_1_pcipm /sys/devices/pci*/.../link/l1_2_pcipm An attribute is only visible if both ends of the Link leading to the device support the state. Writing y/1/on to the file enables the state; n/0/off disables it. These attributes can be used to tune the power/performance tradeoff for individual devices. [bhelgaas: commit log, rename directory to "link"] Link: https://lore.kernel.org/r/b1c83f8a-9bf6-eac5-82d0-cf5b90128fbf@gmail.com Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> (cherry picked from commit 72ea91a) Signed-off-by: AceLan Kao <acelan.kao@canonical.com> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
1 parent 0a5cfbe commit b5364e6

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed

Documentation/ABI/testing/sysfs-bus-pci

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,16 @@ Description:
347347
If the device has any Peer-to-Peer memory registered, this
348348
file contains a '1' if the memory has been published for
349349
use outside the driver that owns the device.
350+
351+
What: /sys/bus/pci/devices/.../link/clkpm
352+
/sys/bus/pci/devices/.../link/l0s_aspm
353+
/sys/bus/pci/devices/.../link/l1_aspm
354+
/sys/bus/pci/devices/.../link/l1_1_aspm
355+
/sys/bus/pci/devices/.../link/l1_2_aspm
356+
/sys/bus/pci/devices/.../link/l1_1_pcipm
357+
/sys/bus/pci/devices/.../link/l1_2_pcipm
358+
Date: October 2019
359+
Contact: Heiner Kallweit <hkallweit1@gmail.com>
360+
Description: If ASPM is supported for an endpoint, these files can be
361+
used to disable or enable the individual power management
362+
states. Write y/1/on to enable, n/0/off to disable.

drivers/pci/pci-sysfs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,9 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
15871587
&pcie_dev_attr_group,
15881588
#ifdef CONFIG_PCIEAER
15891589
&aer_stats_attr_group,
1590+
#endif
1591+
#ifdef CONFIG_PCIEASPM
1592+
&aspm_ctrl_attr_group,
15901593
#endif
15911594
NULL,
15921595
};

drivers/pci/pci.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,4 +671,8 @@ static inline int pci_acpi_program_hp_params(struct pci_dev *dev)
671671
}
672672
#endif
673673

674+
#ifdef CONFIG_PCIEASPM
675+
extern const struct attribute_group aspm_ctrl_attr_group;
676+
#endif
677+
674678
#endif /* DRIVERS_PCI_H */

drivers/pci/pcie/aspm.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,14 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
899899
return link;
900900
}
901901

902+
static void pcie_aspm_update_sysfs_visibility(struct pci_dev *pdev)
903+
{
904+
struct pci_dev *child;
905+
906+
list_for_each_entry(child, &pdev->subordinate->devices, bus_list)
907+
sysfs_update_group(&child->dev.kobj, &aspm_ctrl_attr_group);
908+
}
909+
902910
/*
903911
* pcie_aspm_init_link_state: Initiate PCI express link state.
904912
* It is called after the pcie and its children devices are scanned.
@@ -960,6 +968,8 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
960968
pcie_set_clkpm(link, policy_to_clkpm_state(link));
961969
}
962970

971+
pcie_aspm_update_sysfs_visibility(pdev);
972+
963973
unlock:
964974
mutex_unlock(&aspm_lock);
965975
out:
@@ -1313,6 +1323,145 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
13131323
}
13141324
#endif
13151325

1326+
static ssize_t aspm_attr_show_common(struct device *dev,
1327+
struct device_attribute *attr,
1328+
char *buf, u8 state)
1329+
{
1330+
struct pci_dev *pdev = to_pci_dev(dev);
1331+
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1332+
1333+
return sprintf(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
1334+
}
1335+
1336+
static ssize_t aspm_attr_store_common(struct device *dev,
1337+
struct device_attribute *attr,
1338+
const char *buf, size_t len, u8 state)
1339+
{
1340+
struct pci_dev *pdev = to_pci_dev(dev);
1341+
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1342+
bool state_enable;
1343+
1344+
if (strtobool(buf, &state_enable) < 0)
1345+
return -EINVAL;
1346+
1347+
down_read(&pci_bus_sem);
1348+
mutex_lock(&aspm_lock);
1349+
1350+
if (state_enable) {
1351+
link->aspm_disable &= ~state;
1352+
/* need to enable L1 for substates */
1353+
if (state & ASPM_STATE_L1SS)
1354+
link->aspm_disable &= ~ASPM_STATE_L1;
1355+
} else {
1356+
link->aspm_disable |= state;
1357+
}
1358+
1359+
pcie_config_aspm_link(link, policy_to_aspm_state(link));
1360+
1361+
mutex_unlock(&aspm_lock);
1362+
up_read(&pci_bus_sem);
1363+
1364+
return len;
1365+
}
1366+
1367+
#define ASPM_ATTR(_f, _s) \
1368+
static ssize_t _f##_show(struct device *dev, \
1369+
struct device_attribute *attr, char *buf) \
1370+
{ return aspm_attr_show_common(dev, attr, buf, ASPM_STATE_##_s); } \
1371+
\
1372+
static ssize_t _f##_store(struct device *dev, \
1373+
struct device_attribute *attr, \
1374+
const char *buf, size_t len) \
1375+
{ return aspm_attr_store_common(dev, attr, buf, len, ASPM_STATE_##_s); }
1376+
1377+
ASPM_ATTR(l0s_aspm, L0S)
1378+
ASPM_ATTR(l1_aspm, L1)
1379+
ASPM_ATTR(l1_1_aspm, L1_1)
1380+
ASPM_ATTR(l1_2_aspm, L1_2)
1381+
ASPM_ATTR(l1_1_pcipm, L1_1_PCIPM)
1382+
ASPM_ATTR(l1_2_pcipm, L1_2_PCIPM)
1383+
1384+
static ssize_t clkpm_show(struct device *dev,
1385+
struct device_attribute *attr, char *buf)
1386+
{
1387+
struct pci_dev *pdev = to_pci_dev(dev);
1388+
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1389+
1390+
return sprintf(buf, "%d\n", link->clkpm_enabled);
1391+
}
1392+
1393+
static ssize_t clkpm_store(struct device *dev,
1394+
struct device_attribute *attr,
1395+
const char *buf, size_t len)
1396+
{
1397+
struct pci_dev *pdev = to_pci_dev(dev);
1398+
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1399+
bool state_enable;
1400+
1401+
if (strtobool(buf, &state_enable) < 0)
1402+
return -EINVAL;
1403+
1404+
down_read(&pci_bus_sem);
1405+
mutex_lock(&aspm_lock);
1406+
1407+
link->clkpm_disable = !state_enable;
1408+
pcie_set_clkpm(link, policy_to_clkpm_state(link));
1409+
1410+
mutex_unlock(&aspm_lock);
1411+
up_read(&pci_bus_sem);
1412+
1413+
return len;
1414+
}
1415+
1416+
static DEVICE_ATTR_RW(clkpm);
1417+
static DEVICE_ATTR_RW(l0s_aspm);
1418+
static DEVICE_ATTR_RW(l1_aspm);
1419+
static DEVICE_ATTR_RW(l1_1_aspm);
1420+
static DEVICE_ATTR_RW(l1_2_aspm);
1421+
static DEVICE_ATTR_RW(l1_1_pcipm);
1422+
static DEVICE_ATTR_RW(l1_2_pcipm);
1423+
1424+
static struct attribute *aspm_ctrl_attrs[] = {
1425+
&dev_attr_clkpm.attr,
1426+
&dev_attr_l0s_aspm.attr,
1427+
&dev_attr_l1_aspm.attr,
1428+
&dev_attr_l1_1_aspm.attr,
1429+
&dev_attr_l1_2_aspm.attr,
1430+
&dev_attr_l1_1_pcipm.attr,
1431+
&dev_attr_l1_2_pcipm.attr,
1432+
NULL
1433+
};
1434+
1435+
static umode_t aspm_ctrl_attrs_are_visible(struct kobject *kobj,
1436+
struct attribute *a, int n)
1437+
{
1438+
struct device *dev = kobj_to_dev(kobj);
1439+
struct pci_dev *pdev = to_pci_dev(dev);
1440+
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1441+
static const u8 aspm_state_map[] = {
1442+
ASPM_STATE_L0S,
1443+
ASPM_STATE_L1,
1444+
ASPM_STATE_L1_1,
1445+
ASPM_STATE_L1_2,
1446+
ASPM_STATE_L1_1_PCIPM,
1447+
ASPM_STATE_L1_2_PCIPM,
1448+
};
1449+
1450+
if (aspm_disabled || !link)
1451+
return 0;
1452+
1453+
if (n == 0)
1454+
return link->clkpm_capable ? a->mode : 0;
1455+
1456+
return link->aspm_capable & aspm_state_map[n - 1] ? a->mode : 0;
1457+
}
1458+
1459+
const struct attribute_group aspm_ctrl_attr_group = {
1460+
.name = "link",
1461+
.attrs = aspm_ctrl_attrs,
1462+
.is_visible = aspm_ctrl_attrs_are_visible,
1463+
};
1464+
13161465
static int __init pcie_aspm_disable(char *str)
13171466
{
13181467
if (!strcmp(str, "off")) {

0 commit comments

Comments
 (0)