linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v2 0/3] PCI/ASPM: add sysfs attribute for controlling ASPM
@ 2019-05-11 15:30 Heiner Kallweit
  2019-05-11 15:31 ` [PATCH RFC v2 1/3] PCI/ASPM: add L1 sub-state support to pci_disable_link_state Heiner Kallweit
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-11 15:30 UTC (permalink / raw)
  To: Frederick Lawler, Bjorn Helgaas; +Cc: linux-pci

Background of this extension is a problem with the r8169 network driver.
Several combinations of board chipsets and network chip versions have
problems if ASPM is enabled, therefore we have to disable ASPM per
default. However especially on notebooks ASPM can provide significant
power-saving, therefore we want to give users the option to enable
ASPM. With the new sysfs attribute users can control which ASPM
link-states are disabled.

This is a RFC version, therefore documentation of attribute is
still missing. The attribute handling was inspired by the protocol
attribute handling in drivers/media/rc/rc-main.c.
Attribute syntax in a few words:
none: allow all supported ASPM states
all: disable all ASPM states
+<state>: add state to list of disabled ASPM states
-<state>: re-enable ASPM state if supported

v2:
- bind attribute to the endpoint

Heiner Kallweit (3):
  PCI/ASPM: add L1 sub-state support to pci_disable_link_state
  PCI/ASPM: allow to re-enable Clock PM
  PCI/ASPM: add sysfs attribute for controlling ASPM

 drivers/pci/pci.h        |   8 +-
 drivers/pci/pcie/aspm.c  | 204 ++++++++++++++++++++++++++++++++++++---
 include/linux/pci-aspm.h |   8 +-
 3 files changed, 199 insertions(+), 21 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC v2 1/3] PCI/ASPM: add L1 sub-state support to pci_disable_link_state
  2019-05-11 15:30 [PATCH RFC v2 0/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
@ 2019-05-11 15:31 ` Heiner Kallweit
  2019-05-11 15:32 ` [PATCH RFC v2 2/3] PCI/ASPM: allow to re-enable Clock PM Heiner Kallweit
  2019-05-11 15:33 ` [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
  2 siblings, 0 replies; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-11 15:31 UTC (permalink / raw)
  To: Frederick Lawler, Bjorn Helgaas; +Cc: linux-pci

Add support for disabling states L1.1 and L1.2 to pci_disable_link_state.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- no change
---
 drivers/pci/pcie/aspm.c  | 13 ++++++++++---
 include/linux/pci-aspm.h |  8 +++++---
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index fd4cb7508..511f3e018 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -35,9 +35,9 @@
 #define ASPM_STATE_L1_1_PCIPM	(0x20)	/* PCI PM L1.1 state */
 #define ASPM_STATE_L1_2_PCIPM	(0x40)	/* PCI PM L1.2 state */
 #define ASPM_STATE_L1_SS_PCIPM	(ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1_2_PCIPM)
+#define ASPM_STATE_L1_1_MASK	(ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM)
 #define ASPM_STATE_L1_2_MASK	(ASPM_STATE_L1_2 | ASPM_STATE_L1_2_PCIPM)
-#define ASPM_STATE_L1SS		(ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM |\
-				 ASPM_STATE_L1_2_MASK)
+#define ASPM_STATE_L1SS		(ASPM_STATE_L1_1_MASK | ASPM_STATE_L1_2_MASK)
 #define ASPM_STATE_L0S		(ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
 #define ASPM_STATE_ALL		(ASPM_STATE_L0S | ASPM_STATE_L1 |	\
 				 ASPM_STATE_L1SS)
@@ -1094,8 +1094,15 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
 	link = parent->link_state;
 	if (state & PCIE_LINK_STATE_L0S)
 		link->aspm_disable |= ASPM_STATE_L0S;
-	if (state & PCIE_LINK_STATE_L1)
+	if (state & PCIE_LINK_STATE_L1) {
 		link->aspm_disable |= ASPM_STATE_L1;
+		/* sub-states require L1 */
+		link->aspm_disable |= ASPM_STATE_L1SS;
+	}
+	if (state & PCIE_LINK_STATE_L1_1)
+		link->aspm_disable |= ASPM_STATE_L1_1_MASK;
+	if (state & PCIE_LINK_STATE_L1_2)
+		link->aspm_disable |= ASPM_STATE_L1_2_MASK;
 	pcie_config_aspm_link(link, policy_to_aspm_state(link));
 
 	if (state & PCIE_LINK_STATE_CLKPM) {
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index df28af5ce..e66c3e3d8 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -19,9 +19,11 @@
 
 #include <linux/pci.h>
 
-#define PCIE_LINK_STATE_L0S	1
-#define PCIE_LINK_STATE_L1	2
-#define PCIE_LINK_STATE_CLKPM	4
+#define PCIE_LINK_STATE_L0S	BIT(0)
+#define PCIE_LINK_STATE_L1	BIT(1)
+#define PCIE_LINK_STATE_CLKPM	BIT(2)
+#define PCIE_LINK_STATE_L1_1	BIT(3)
+#define PCIE_LINK_STATE_L1_2	BIT(4)
 
 #ifdef CONFIG_PCIEASPM
 void pci_disable_link_state(struct pci_dev *pdev, int state);
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC v2 2/3] PCI/ASPM: allow to re-enable Clock PM
  2019-05-11 15:30 [PATCH RFC v2 0/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
  2019-05-11 15:31 ` [PATCH RFC v2 1/3] PCI/ASPM: add L1 sub-state support to pci_disable_link_state Heiner Kallweit
@ 2019-05-11 15:32 ` Heiner Kallweit
  2019-05-11 15:33 ` [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
  2 siblings, 0 replies; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-11 15:32 UTC (permalink / raw)
  To: Frederick Lawler, Bjorn Helgaas; +Cc: linux-pci

So far Clock PM can't be re-enabled once it has been disabled with a
call to pci_disable_link_state(). Reason is that clkpm_capable is
reset. Change this by adding a clkpm_disable field similar to
aspm_disable.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
v2:
- no change
---
 drivers/pci/pcie/aspm.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 511f3e018..7847be38e 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -65,6 +65,7 @@ struct pcie_link_state {
 	u32 clkpm_capable:1;		/* Clock PM capable? */
 	u32 clkpm_enabled:1;		/* Current Clock PM state */
 	u32 clkpm_default:1;		/* Default Clock PM state by BIOS */
+	u32 clkpm_disable:1;		/* Clock PM disabled */
 
 	/* Exit latencies */
 	struct aspm_latency latency_up;	/* Upstream direction exit latency */
@@ -162,8 +163,11 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
 
 static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
 {
-	/* Don't enable Clock PM if the link is not Clock PM capable */
-	if (!link->clkpm_capable)
+	/*
+	 * Don't enable Clock PM if the link is not Clock PM capable
+	 * or Clock PM is disabled
+	 */
+	if (!link->clkpm_capable || link->clkpm_disable)
 		enable = 0;
 	/* Need nothing if the specified equals to current state */
 	if (link->clkpm_enabled == enable)
@@ -193,7 +197,8 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
 	}
 	link->clkpm_enabled = enabled;
 	link->clkpm_default = enabled;
-	link->clkpm_capable = (blacklist) ? 0 : capable;
+	link->clkpm_capable = capable;
+	link->clkpm_disable = blacklist ? 1 : 0;
 }
 
 static bool pcie_retrain_link(struct pcie_link_state *link)
@@ -1105,10 +1110,9 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
 		link->aspm_disable |= ASPM_STATE_L1_2_MASK;
 	pcie_config_aspm_link(link, policy_to_aspm_state(link));
 
-	if (state & PCIE_LINK_STATE_CLKPM) {
-		link->clkpm_capable = 0;
-		pcie_set_clkpm(link, 0);
-	}
+	if (state & PCIE_LINK_STATE_CLKPM)
+		link->clkpm_disable = 1;
+	pcie_set_clkpm(link, policy_to_clkpm_state(link));
 	mutex_unlock(&aspm_lock);
 	if (sem)
 		up_read(&pci_bus_sem);
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM
  2019-05-11 15:30 [PATCH RFC v2 0/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
  2019-05-11 15:31 ` [PATCH RFC v2 1/3] PCI/ASPM: add L1 sub-state support to pci_disable_link_state Heiner Kallweit
  2019-05-11 15:32 ` [PATCH RFC v2 2/3] PCI/ASPM: allow to re-enable Clock PM Heiner Kallweit
@ 2019-05-11 15:33 ` Heiner Kallweit
  2019-05-12  1:02   ` Frederick Lawler
  2 siblings, 1 reply; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-11 15:33 UTC (permalink / raw)
  To: Frederick Lawler, Bjorn Helgaas; +Cc: linux-pci

Background of this extension is a problem with the r8169 network driver.
Several combinations of board chipsets and network chip versions have
problems if ASPM is enabled, therefore we have to disable ASPM per
default. However especially on notebooks ASPM can provide significant
power-saving, therefore we want to give users the option to enable
ASPM. With the new sysfs attribute users can control which ASPM
link-states are disabled.

This is a RFC version, therefore documentation of attribute is
still missing. The attribute handling was inspired by the protocol
attribute handling in drivers/media/rc/rc-main.c.
Attribute syntax in a few words:
none: allow all supported ASPM states
all: disable all ASPM states
+<state>: add state to list of disabled ASPM states
-<state>: re-enable ASPM state if supported

v2:
- bind attribute to the endpoint

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
 drivers/pci/pci.h       |   8 +-
 drivers/pci/pcie/aspm.c | 181 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 181 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9cb99380c..06642b7de 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -499,17 +499,13 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 void pcie_aspm_pm_state_change(struct pci_dev *pdev);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
+void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
+void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
-#endif
-
-#ifdef CONFIG_PCIEASPM_DEBUG
-void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
-void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
-#else
 static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { }
 static inline void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { }
 #endif
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 7847be38e..530a2fbf0 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -42,6 +42,8 @@
 #define ASPM_STATE_ALL		(ASPM_STATE_L0S | ASPM_STATE_L1 |	\
 				 ASPM_STATE_L1SS)
 
+static const char power_group[] = "power";
+
 struct aspm_latency {
 	u32 l0s;			/* L0s latency (nsec) */
 	u32 l1;				/* L1 latency (nsec) */
@@ -1251,38 +1253,213 @@ static ssize_t clk_ctl_store(struct device *dev,
 
 static DEVICE_ATTR_RW(link_state);
 static DEVICE_ATTR_RW(clk_ctl);
+#endif
+
+struct aspm_sysfs_state {
+	const char *name;
+	int disable_mask;
+};
+
+static const struct aspm_sysfs_state aspm_sysfs_states[] = {
+	{ "L0S",	ASPM_STATE_L0S		},
+	{ "L1",		ASPM_STATE_L1		},
+	{ "L1.1",	ASPM_STATE_L1_1_MASK	},
+	{ "L1.2",	ASPM_STATE_L1_2_MASK	},
+};
+
+static struct pcie_link_state *aspm_get_parent_link(struct pci_dev *pdev)
+{
+	struct pci_dev *parent = pdev->bus->self;
+
+	if (pdev->has_secondary_link)
+		parent = pdev;
+
+	return parent ? parent->link_state : NULL;
+}
+
+static bool pcie_check_aspm_endpoint(struct pci_dev *pdev)
+{
+	struct pcie_link_state *link;
+
+	if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT)
+		return false;
+
+	link = aspm_get_parent_link(pdev);
+
+	return link && link->aspm_support;
+}
+
+static ssize_t aspm_disable_link_state_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pcie_link_state *link;
+	int len = 0, i;
+
+	link = aspm_get_parent_link(pdev);
+	if (!link)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&aspm_lock);
+
+	for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
+		const struct aspm_sysfs_state *st = aspm_sysfs_states + i;
+
+		if (link->aspm_disable & st->disable_mask)
+			len += scnprintf(buf + len, PAGE_SIZE - len, "[%s] ",
+					 st->name);
+		else
+			len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
+					 st->name);
+	}
+
+	if (link->clkpm_disable)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "[CLKPM] ");
+	else
+		len += scnprintf(buf + len, PAGE_SIZE - len, "CLKPM ");
+
+	mutex_unlock(&aspm_lock);
+
+	len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+
+	return len;
+}
+
+static ssize_t aspm_disable_link_state_store(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t len)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pcie_link_state *link;
+	char *buftmp = (char *)buf, *tok;
+	unsigned int disable_aspm, disable_clkpm;
+	bool first = true, add;
+	int err = 0, i;
+
+	if (aspm_disabled)
+		return -EPERM;
+
+	link = aspm_get_parent_link(pdev);
+	if (!link)
+		return -EOPNOTSUPP;
+
+	down_read(&pci_bus_sem);
+	mutex_lock(&aspm_lock);
+
+	disable_aspm = link->aspm_disable;
+	disable_clkpm = link->clkpm_disable;
+
+	while ((tok = strsep(&buftmp, " \n")) != NULL) {
+		bool found = false;
+
+		if (!*tok)
+			continue;
+
+		if (first) {
+			if (!strcasecmp(tok, "none")) {
+				disable_aspm = 0;
+				disable_clkpm = 0;
+				break;
+			}
+			if (!strcasecmp(tok, "all")) {
+				disable_aspm = ASPM_STATE_ALL;
+				disable_clkpm = 1;
+				break;
+			}
+			first = false;
+		}
+
+		if (*tok != '+' && *tok != '-') {
+			err = -EINVAL;
+			goto out;
+		}
+
+		add = *tok++ == '+';
+
+		for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
+			const struct aspm_sysfs_state *st =
+						aspm_sysfs_states + i;
+
+			if (!strcasecmp(tok, st->name)) {
+				if (add)
+					disable_aspm |= st->disable_mask;
+				else
+					disable_aspm &= ~st->disable_mask;
+				found = true;
+				break;
+			}
+		}
+
+		if (!found && !strcasecmp(tok, "clkpm")) {
+			disable_clkpm = add ? 1 : 0;
+			found = true;
+		}
+
+		if (!found) {
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (disable_aspm & ASPM_STATE_L1)
+		disable_aspm |= ASPM_STATE_L1SS;
+
+	link->aspm_disable = disable_aspm;
+	link->clkpm_disable = disable_clkpm;
+
+	pcie_config_aspm_link(link, policy_to_aspm_state(link));
+	pcie_set_clkpm(link, policy_to_clkpm_state(link));
+out:
+	mutex_unlock(&aspm_lock);
+	up_read(&pci_bus_sem);
+
+	return err ?: len;
+}
+
+static DEVICE_ATTR_RW(aspm_disable_link_state);
 
-static char power_group[] = "power";
 void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
 {
 	struct pcie_link_state *link_state = pdev->link_state;
 
+	if (pcie_check_aspm_endpoint(pdev))
+		sysfs_add_file_to_group(&pdev->dev.kobj,
+			&dev_attr_aspm_disable_link_state.attr, power_group);
+
 	if (!link_state)
 		return;
 
+#ifdef CONFIG_PCIEASPM_DEBUG
 	if (link_state->aspm_support)
 		sysfs_add_file_to_group(&pdev->dev.kobj,
 			&dev_attr_link_state.attr, power_group);
 	if (link_state->clkpm_capable)
 		sysfs_add_file_to_group(&pdev->dev.kobj,
 			&dev_attr_clk_ctl.attr, power_group);
+#endif
 }
 
 void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
 {
 	struct pcie_link_state *link_state = pdev->link_state;
 
+	if (pcie_check_aspm_endpoint(pdev))
+		sysfs_remove_file_from_group(&pdev->dev.kobj,
+			&dev_attr_aspm_disable_link_state.attr, power_group);
+
 	if (!link_state)
 		return;
 
+#ifdef CONFIG_PCIEASPM_DEBUG
 	if (link_state->aspm_support)
 		sysfs_remove_file_from_group(&pdev->dev.kobj,
 			&dev_attr_link_state.attr, power_group);
 	if (link_state->clkpm_capable)
 		sysfs_remove_file_from_group(&pdev->dev.kobj,
 			&dev_attr_clk_ctl.attr, power_group);
-}
 #endif
+}
 
 static int __init pcie_aspm_disable(char *str)
 {
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM
  2019-05-11 15:33 ` [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
@ 2019-05-12  1:02   ` Frederick Lawler
  2019-05-12  8:47     ` Heiner Kallweit
                       ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Frederick Lawler @ 2019-05-12  1:02 UTC (permalink / raw)
  To: Heiner Kallweit; +Cc: Bjorn Helgaas, linux-pci

Evening,

Heiner Kallweit wrote on 5/11/19 10:33 AM:> +static ssize_t 
aspm_disable_link_state_show(struct device *dev,
> +					    struct device_attribute *attr,
> +					    char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct pcie_link_state *link;
> +	int len = 0, i;
> +
> +	link = aspm_get_parent_link(pdev);
> +	if (!link)
> +		return -EOPNOTSUPP;
> +
> +	mutex_lock(&aspm_lock);
> +
> +	for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
> +		const struct aspm_sysfs_state *st = aspm_sysfs_states + i;
> +
> +		if (link->aspm_disable & st->disable_mask)
> +			len += scnprintf(buf + len, PAGE_SIZE - len, "[%s] ",
> +					 st->name);
> +		else
> +			len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
> +					 st->name);
> +	}
> +
> +	if (link->clkpm_disable)
> +		len += scnprintf(buf + len, PAGE_SIZE - len, "[CLKPM] ");
> +	else
> +		len += scnprintf(buf + len, PAGE_SIZE - len, "CLKPM ");
> +
> +	mutex_unlock(&aspm_lock);
> +
> +	len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
> +
> +	return len;
> +}

I think it would be better to model the output to something similar to 
what lspci would do:

L1.1- L1.2- L0S+ ClockPM+, etc...

This better conveys the message that these states are enabled vs disabled.

I'd be interested to know if the use of [STATE]/STATE pattern is used 
elsewhere in the kernel. If so, then I'm cool with it :)

> +
> +static ssize_t aspm_disable_link_state_store(struct device *dev,
> +					     struct device_attribute *attr,
> +					     const char *buf, size_t len)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct pcie_link_state *link;
> +	char *buftmp = (char *)buf, *tok;
> +	unsigned int disable_aspm, disable_clkpm;
> +	bool first = true, add;
> +	int err = 0, i;
> +
> +	if (aspm_disabled)
> +		return -EPERM;
> +
> +	link = aspm_get_parent_link(pdev);
> +	if (!link)
> +		return -EOPNOTSUPP;
> +
> +	down_read(&pci_bus_sem);
> +	mutex_lock(&aspm_lock);
> +
> +	disable_aspm = link->aspm_disable;
> +	disable_clkpm = link->clkpm_disable;
> +
> +	while ((tok = strsep(&buftmp, " \n")) != NULL) {
> +		bool found = false;
> +
> +		if (!*tok)
> +			continue;
> +
> +		if (first) {
> +			if (!strcasecmp(tok, "none")) {
> +				disable_aspm = 0;
> +				disable_clkpm = 0;
> +				break;
> +			}
> +			if (!strcasecmp(tok, "all")) {
> +				disable_aspm = ASPM_STATE_ALL;
> +				disable_clkpm = 1;
> +				break;
> +			}
> +			first = false;
> +		}
> +
> +		if (*tok != '+' && *tok != '-') {
> +			err = -EINVAL;
> +			goto out;
> +		}
> +
> +		add = *tok++ == '+';
> +
> +		for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
> +			const struct aspm_sysfs_state *st =
> +						aspm_sysfs_states + i;
> +
> +			if (!strcasecmp(tok, st->name)) {
> +				if (add)
> +					disable_aspm |= st->disable_mask;
> +				else
> +					disable_aspm &= ~st->disable_mask;
> +				found = true;
> +				break;
> +			}
> +		}
> +
> +		if (!found && !strcasecmp(tok, "clkpm")) {
> +			disable_clkpm = add ? 1 : 0;
> +			found = true;
> +		}
> +
> +		if (!found) {
> +			err = -EINVAL;
> +			goto out;
> +		}
> +	}
> +
> +	if (disable_aspm & ASPM_STATE_L1)
> +		disable_aspm |= ASPM_STATE_L1SS;
> +
> +	link->aspm_disable = disable_aspm;
> +	link->clkpm_disable = disable_clkpm;
> +
> +	pcie_config_aspm_link(link, policy_to_aspm_state(link));
> +	pcie_set_clkpm(link, policy_to_clkpm_state(link));
> +out:
> +	mutex_unlock(&aspm_lock);
> +	up_read(&pci_bus_sem);
> +
> +	return err ?: len;
> +}
> +
> +static DEVICE_ATTR_RW(aspm_disable_link_state);
>   

Since we're introducing a new sysfs interface, would it be more 
appropriate to rename the sysfs files to aspm_set_link_state (or 
something to that effect)?

The syntax as it stands, means that to enable a state, a double negative 
must be used:

echo "-L1.1" > ./aspm_disable_link_state"
vs
echo "+L1.1" > ./aspm_set_link_state

If we avoid the double negative, the documentation about to be written 
will be more clear and use of the sysfs file will be more intuitive.

Thanks,
Frederick Lawler


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM
  2019-05-12  1:02   ` Frederick Lawler
@ 2019-05-12  8:47     ` Heiner Kallweit
  2019-05-12 13:59     ` Heiner Kallweit
  2019-05-12 14:03     ` Heiner Kallweit
  2 siblings, 0 replies; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-12  8:47 UTC (permalink / raw)
  To: Frederick Lawler; +Cc: Bjorn Helgaas, linux-pci

On 12.05.2019 03:02, Frederick Lawler wrote:
> Evening,
> 
> Heiner Kallweit wrote on 5/11/19 10:33 AM:> +static ssize_t aspm_disable_link_state_show(struct device *dev,
>> +                        struct device_attribute *attr,
>> +                        char *buf)
>> +{
>> +    struct pci_dev *pdev = to_pci_dev(dev);
>> +    struct pcie_link_state *link;
>> +    int len = 0, i;
>> +
>> +    link = aspm_get_parent_link(pdev);
>> +    if (!link)
>> +        return -EOPNOTSUPP;
>> +
>> +    mutex_lock(&aspm_lock);
>> +
>> +    for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
>> +        const struct aspm_sysfs_state *st = aspm_sysfs_states + i;
>> +
>> +        if (link->aspm_disable & st->disable_mask)
>> +            len += scnprintf(buf + len, PAGE_SIZE - len, "[%s] ",
>> +                     st->name);
>> +        else
>> +            len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
>> +                     st->name);
>> +    }
>> +
>> +    if (link->clkpm_disable)
>> +        len += scnprintf(buf + len, PAGE_SIZE - len, "[CLKPM] ");
>> +    else
>> +        len += scnprintf(buf + len, PAGE_SIZE - len, "CLKPM ");
>> +
>> +    mutex_unlock(&aspm_lock);
>> +
>> +    len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
>> +
>> +    return len;
>> +}
> 
> I think it would be better to model the output to something similar to what lspci would do:
> 
> L1.1- L1.2- L0S+ ClockPM+, etc...
> 
> This better conveys the message that these states are enabled vs disabled.
> 
> I'd be interested to know if the use of [STATE]/STATE pattern is used elsewhere in the kernel. If so, then I'm cool with it :)
> 
This pattern is used in several places in sysfs. At first for "1 of n" selections like
in /sys/module/pcie_aspm/parameters/policy. But also for "m of n" selections,
examples would be LED triggers or active remote control protocols (drivers/media/rc).

>> +
>> +static ssize_t aspm_disable_link_state_store(struct device *dev,
>> +                         struct device_attribute *attr,
>> +                         const char *buf, size_t len)
>> +{
>> +    struct pci_dev *pdev = to_pci_dev(dev);
>> +    struct pcie_link_state *link;
>> +    char *buftmp = (char *)buf, *tok;
>> +    unsigned int disable_aspm, disable_clkpm;
>> +    bool first = true, add;
>> +    int err = 0, i;
>> +
>> +    if (aspm_disabled)
>> +        return -EPERM;
>> +
>> +    link = aspm_get_parent_link(pdev);
>> +    if (!link)
>> +        return -EOPNOTSUPP;
>> +
>> +    down_read(&pci_bus_sem);
>> +    mutex_lock(&aspm_lock);
>> +
>> +    disable_aspm = link->aspm_disable;
>> +    disable_clkpm = link->clkpm_disable;
>> +
>> +    while ((tok = strsep(&buftmp, " \n")) != NULL) {
>> +        bool found = false;
>> +
>> +        if (!*tok)
>> +            continue;
>> +
>> +        if (first) {
>> +            if (!strcasecmp(tok, "none")) {
>> +                disable_aspm = 0;
>> +                disable_clkpm = 0;
>> +                break;
>> +            }
>> +            if (!strcasecmp(tok, "all")) {
>> +                disable_aspm = ASPM_STATE_ALL;
>> +                disable_clkpm = 1;
>> +                break;
>> +            }
>> +            first = false;
>> +        }
>> +
>> +        if (*tok != '+' && *tok != '-') {
>> +            err = -EINVAL;
>> +            goto out;
>> +        }
>> +
>> +        add = *tok++ == '+';
>> +
>> +        for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
>> +            const struct aspm_sysfs_state *st =
>> +                        aspm_sysfs_states + i;
>> +
>> +            if (!strcasecmp(tok, st->name)) {
>> +                if (add)
>> +                    disable_aspm |= st->disable_mask;
>> +                else
>> +                    disable_aspm &= ~st->disable_mask;
>> +                found = true;
>> +                break;
>> +            }
>> +        }
>> +
>> +        if (!found && !strcasecmp(tok, "clkpm")) {
>> +            disable_clkpm = add ? 1 : 0;
>> +            found = true;
>> +        }
>> +
>> +        if (!found) {
>> +            err = -EINVAL;
>> +            goto out;
>> +        }
>> +    }
>> +
>> +    if (disable_aspm & ASPM_STATE_L1)
>> +        disable_aspm |= ASPM_STATE_L1SS;
>> +
>> +    link->aspm_disable = disable_aspm;
>> +    link->clkpm_disable = disable_clkpm;
>> +
>> +    pcie_config_aspm_link(link, policy_to_aspm_state(link));
>> +    pcie_set_clkpm(link, policy_to_clkpm_state(link));
>> +out:
>> +    mutex_unlock(&aspm_lock);
>> +    up_read(&pci_bus_sem);
>> +
>> +    return err ?: len;
>> +}
>> +
>> +static DEVICE_ATTR_RW(aspm_disable_link_state);
>>   
> 
> Since we're introducing a new sysfs interface, would it be more appropriate to rename the sysfs files to aspm_set_link_state (or something to that effect)?
> 
> The syntax as it stands, means that to enable a state, a double negative must be used:
> 
> echo "-L1.1" > ./aspm_disable_link_state"
> vs
> echo "+L1.1" > ./aspm_set_link_state
> 
> If we avoid the double negative, the documentation about to be written will be more clear and use of the sysfs file will be more intuitive.
> 
I think this is a valid point. Let me check and come up with a proposal.

> Thanks,
> Frederick Lawler
> 
> 
Heiner

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM
  2019-05-12  1:02   ` Frederick Lawler
  2019-05-12  8:47     ` Heiner Kallweit
@ 2019-05-12 13:59     ` Heiner Kallweit
  2019-05-12 14:03     ` Heiner Kallweit
  2 siblings, 0 replies; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-12 13:59 UTC (permalink / raw)
  To: Frederick Lawler; +Cc: Bjorn Helgaas, linux-pci

On 12.05.2019 03:02, Frederick Lawler wrote:
> Evening,
> 
> Heiner Kallweit wrote on 5/11/19 10:33 AM:> +static ssize_t aspm_disable_link_state_show(struct device *dev,
>> +                        struct device_attribute *attr,
>> +                        char *buf)
>> +{
>> +    struct pci_dev *pdev = to_pci_dev(dev);
>> +    struct pcie_link_state *link;
>> +    int len = 0, i;
>> +
>> +    link = aspm_get_parent_link(pdev);
>> +    if (!link)
>> +        return -EOPNOTSUPP;
>> +
>> +    mutex_lock(&aspm_lock);
>> +
>> +    for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
>> +        const struct aspm_sysfs_state *st = aspm_sysfs_states + i;
>> +
>> +        if (link->aspm_disable & st->disable_mask)
>> +            len += scnprintf(buf + len, PAGE_SIZE - len, "[%s] ",
>> +                     st->name);
>> +        else
>> +            len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
>> +                     st->name);
>> +    }
>> +
>> +    if (link->clkpm_disable)
>> +        len += scnprintf(buf + len, PAGE_SIZE - len, "[CLKPM] ");
>> +    else
>> +        len += scnprintf(buf + len, PAGE_SIZE - len, "CLKPM ");
>> +
>> +    mutex_unlock(&aspm_lock);
>> +
>> +    len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
>> +
>> +    return len;
>> +}
> 
> I think it would be better to model the output to something similar to what lspci would do:
> 
> L1.1- L1.2- L0S+ ClockPM+, etc...
> 
> This better conveys the message that these states are enabled vs disabled.
> 
> I'd be interested to know if the use of [STATE]/STATE pattern is used elsewhere in the kernel. If so, then I'm cool with it :)
> 
>> +
>> +static ssize_t aspm_disable_link_state_store(struct device *dev,
>> +                         struct device_attribute *attr,
>> +                         const char *buf, size_t len)
>> +{
>> +    struct pci_dev *pdev = to_pci_dev(dev);
>> +    struct pcie_link_state *link;
>> +    char *buftmp = (char *)buf, *tok;
>> +    unsigned int disable_aspm, disable_clkpm;
>> +    bool first = true, add;
>> +    int err = 0, i;
>> +
>> +    if (aspm_disabled)
>> +        return -EPERM;
>> +
>> +    link = aspm_get_parent_link(pdev);
>> +    if (!link)
>> +        return -EOPNOTSUPP;
>> +
>> +    down_read(&pci_bus_sem);
>> +    mutex_lock(&aspm_lock);
>> +
>> +    disable_aspm = link->aspm_disable;
>> +    disable_clkpm = link->clkpm_disable;
>> +
>> +    while ((tok = strsep(&buftmp, " \n")) != NULL) {
>> +        bool found = false;
>> +
>> +        if (!*tok)
>> +            continue;
>> +
>> +        if (first) {
>> +            if (!strcasecmp(tok, "none")) {
>> +                disable_aspm = 0;
>> +                disable_clkpm = 0;
>> +                break;
>> +            }
>> +            if (!strcasecmp(tok, "all")) {
>> +                disable_aspm = ASPM_STATE_ALL;
>> +                disable_clkpm = 1;
>> +                break;
>> +            }
>> +            first = false;
>> +        }
>> +
>> +        if (*tok != '+' && *tok != '-') {
>> +            err = -EINVAL;
>> +            goto out;
>> +        }
>> +
>> +        add = *tok++ == '+';
>> +
>> +        for (i = 0; i < ARRAY_SIZE(aspm_sysfs_states); i++) {
>> +            const struct aspm_sysfs_state *st =
>> +                        aspm_sysfs_states + i;
>> +
>> +            if (!strcasecmp(tok, st->name)) {
>> +                if (add)
>> +                    disable_aspm |= st->disable_mask;
>> +                else
>> +                    disable_aspm &= ~st->disable_mask;
>> +                found = true;
>> +                break;
>> +            }
>> +        }
>> +
>> +        if (!found && !strcasecmp(tok, "clkpm")) {
>> +            disable_clkpm = add ? 1 : 0;
>> +            found = true;
>> +        }
>> +
>> +        if (!found) {
>> +            err = -EINVAL;
>> +            goto out;
>> +        }
>> +    }
>> +
>> +    if (disable_aspm & ASPM_STATE_L1)
>> +        disable_aspm |= ASPM_STATE_L1SS;
>> +
>> +    link->aspm_disable = disable_aspm;
>> +    link->clkpm_disable = disable_clkpm;
>> +
>> +    pcie_config_aspm_link(link, policy_to_aspm_state(link));
>> +    pcie_set_clkpm(link, policy_to_clkpm_state(link));
>> +out:
>> +    mutex_unlock(&aspm_lock);
>> +    up_read(&pci_bus_sem);
>> +
>> +    return err ?: len;
>> +}
>> +
>> +static DEVICE_ATTR_RW(aspm_disable_link_state);
>>   
> 
> Since we're introducing a new sysfs interface, would it be more appropriate to rename the sysfs files to aspm_set_link_state (or something to that effect)?
> 
I changed the attribute to aspm_link_states. The "set" isn't needed IMO. It's a RW attribute and that should make
clear it can be used to change the state.

> The syntax as it stands, means that to enable a state, a double negative must be used:
> 
> echo "-L1.1" > ./aspm_disable_link_state"
> vs
> echo "+L1.1" > ./aspm_set_link_state
> 
> If we avoid the double negative, the documentation about to be written will be more clear and use of the sysfs file will be more intuitive.
> 
> Thanks,
> Frederick Lawler
> 
> 
Heiner

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM
  2019-05-12  1:02   ` Frederick Lawler
  2019-05-12  8:47     ` Heiner Kallweit
  2019-05-12 13:59     ` Heiner Kallweit
@ 2019-05-12 14:03     ` Heiner Kallweit
  2019-05-12 20:18       ` Frederick Lawler
  2 siblings, 1 reply; 9+ messages in thread
From: Heiner Kallweit @ 2019-05-12 14:03 UTC (permalink / raw)
  To: Frederick Lawler; +Cc: Bjorn Helgaas, linux-pci

On 12.05.2019 03:02, Frederick Lawler wrote:
> Evening,
> 
> Heiner Kallweit wrote on 5/11/19 10:33 AM:> +static ssize_t aspm_disable_link_state_show(struct device *dev,
[..]
> 
> Since we're introducing a new sysfs interface, would it be more appropriate to rename the sysfs files to aspm_set_link_state (or something to that effect)?
> 
> The syntax as it stands, means that to enable a state, a double negative must be used:
> 
> echo "-L1.1" > ./aspm_disable_link_state"
> vs
> echo "+L1.1" > ./aspm_set_link_state
> 
> If we avoid the double negative, the documentation about to be written will be more clear and use of the sysfs file will be more intuitive.
> 
In addition to these more formal parts: Can you test the functionality?

> Thanks,
> Frederick Lawler
> 
> 
Heiner

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM
  2019-05-12 14:03     ` Heiner Kallweit
@ 2019-05-12 20:18       ` Frederick Lawler
  0 siblings, 0 replies; 9+ messages in thread
From: Frederick Lawler @ 2019-05-12 20:18 UTC (permalink / raw)
  To: Heiner Kallweit; +Cc: Bjorn Helgaas, linux-pci

Heiner Kallweit wrote on 5/12/19 9:03 AM:
> On 12.05.2019 03:02, Frederick Lawler wrote:
>> Evening,
>>
>> Heiner Kallweit wrote on 5/11/19 10:33 AM:> +static ssize_t aspm_disable_link_state_show(struct device *dev,
> [..]
>>
>> Since we're introducing a new sysfs interface, would it be more appropriate to rename the sysfs files to aspm_set_link_state (or something to that effect)?
>>
>> The syntax as it stands, means that to enable a state, a double negative must be used:
>>
>> echo "-L1.1" > ./aspm_disable_link_state"
>> vs
>> echo "+L1.1" > ./aspm_set_link_state
>>
>> If we avoid the double negative, the documentation about to be written will be more clear and use of the sysfs file will be more intuitive.
>>
> In addition to these more formal parts: Can you test the functionality?

I don't have enough hardware to fully test things out. I just have 1 
device with ASPM support and no switches.

I'll have a go tonight with the v3 patches and report back.

> 
>> Thanks,
>> Frederick Lawler
>>
>>
> Heiner
> 

Frederick Lawler


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-05-12 20:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-11 15:30 [PATCH RFC v2 0/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
2019-05-11 15:31 ` [PATCH RFC v2 1/3] PCI/ASPM: add L1 sub-state support to pci_disable_link_state Heiner Kallweit
2019-05-11 15:32 ` [PATCH RFC v2 2/3] PCI/ASPM: allow to re-enable Clock PM Heiner Kallweit
2019-05-11 15:33 ` [PATCH RFC v2 3/3] PCI/ASPM: add sysfs attribute for controlling ASPM Heiner Kallweit
2019-05-12  1:02   ` Frederick Lawler
2019-05-12  8:47     ` Heiner Kallweit
2019-05-12 13:59     ` Heiner Kallweit
2019-05-12 14:03     ` Heiner Kallweit
2019-05-12 20:18       ` Frederick Lawler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).