* [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy
@ 2025-01-03 21:12 Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
` (27 more replies)
0 siblings, 28 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent, Kalesh AP
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This series brings support for budget evaluation strategy in the PSE
subsystem. PSE controllers can set priorities to decide which ports should
be turned off in case of special events like over-current.
I have added regulator maintainers to have their opinion on adding power
budget regulator constraint see patches 17 and 18.
There are also a core regulator change along the way patch 16.
I suppose I will need to merge them through the regulator tree.
Will it be possible to create an immutable tag to have this PSE series
based on them?
This patch series adds support for two budget evaluation strategy.
1. Static Method:
This method involves distributing power based on PD classification.
It’s straightforward and stable, the PSE core keeping track of the
budget and subtracting the power requested by each PD’s class.
Advantages: Every PD gets its promised power at any time, which
guarantees reliability.
Disadvantages: PD classification steps are large, meaning devices
request much more power than they actually need. As a result, the power
supply may only operate at, say, 50% capacity, which is inefficient and
wastes money.
2. Dynamic Method:
To address the inefficiencies of the static method, vendors like
Microchip have introduced dynamic power budgeting, as seen in the
PD692x0 firmware. This method monitors the current consumption per port
and subtracts it from the available power budget. When the budget is
exceeded, lower-priority ports are shut down.
Advantages: This method optimizes resource utilization, saving costs.
Disadvantages: Low-priority devices may experience instability.
The UAPI allows adding support for software port priority mode managed from
userspace later if needed.
The patch series is based on this fix merged in net:
https://lore.kernel.org/netdev/20241220170400.291705-1-kory.maincent@bootlin.com/
Several Reviewed-by have been removed due to the changes.
Thanks Oleksij for your pointers.
Patches 1-9: Cosmetics.
Patch 10: Adds support for last supported features in the TPS23881 drivers.
Patches 11,12: Add support for PSE index in PSE core and ethtool.
Patches 12-14: Add support for interrupt event report in PSE core, ethtool
and ethtool specs.
Patch 15: Adds support for interrupt and event report in TPS23881 driver.
Patch 16: Fix regulator resolve supply
Patches 17,18: Add support for power budget in regulator framework.
Patch 19: Cosmetic.
Patches 20,21: Add support for PSE power domain in PSE core and ethtool.
Patches 22,23: Add support for port priority in PSE core, ethtool and
ethtool specs.
Patches 24,25: Add support for port priority in PD692x0 drivers.
Patches 26,27: Add support for port priority in TPS23881 drivers.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v4:
- Remove disconnection policy.
- Rename port priority mode to budget evaluation strategy.
- Add cosmetic changes in PSE core.
- Add support for port priority in PD692x0 driver.
- Link to v3: https://lore.kernel.org/r/20241121-feature_poe_port_prio-v3-0-83299fa6967c@bootlin.com
Changes in v3:
- Move power budget to regulator core.
- Add disconnection policies with PIs using the same priority.
- Several fixes on the TPS23881 drivers.
- Several new cosmetic patches.
- Link to v2: https://lore.kernel.org/r/20241030-feature_poe_port_prio-v2-0-9559622ee47a@bootlin.com
Changes in v2:
- Rethink the port priority management.
- Add PSE id.
- Add support for PSE power domains.
- Add get power budget regulator constraint.
- Link to v1: https://lore.kernel.org/r/20241002-feature_poe_port_prio-v1-0-787054f74ed5@bootlin.com
---
Kory Maincent (27):
net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration
net: pse-pd: Avoid setting max_uA in regulator constraints
net: pse-pd: Add power limit check
net: pse-pd: tps23881: Simplify function returns by removing redundant checks
net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel
net: pse-pd: tps23881: Add missing configuration register after disable
net: pse-pd: Use power limit at driver side instead of current limit
net: pse-pd: Split ethtool_get_status into multiple callbacks
net: pse-pd: Remove is_enabled callback from drivers
net: pse-pd: tps23881: Add support for power limit and measurement features
net: pse-pd: Add support for PSE device index
net: ethtool: Add support for new PSE device index description
net: ethtool: Add support for ethnl_info_init_ntf helper function
net: pse-pd: Add support for reporting events
net: pse-pd: tps23881: Add support for PSE events and interrupts
regulator: core: Resolve supply using of_node from regulator_config
regulator: Add support for power budget description
regulator: dt-bindings: Add regulator-power-budget property
net: pse-pd: Fix missing PI of_node description
net: pse-pd: Add support for PSE power domains
net: ethtool: Add support for new power domains index description
net: pse-pd: Add support for getting budget evaluation strategies
net: ethtool: Add PSE new budget evaluation strategy support feature
net: pse-pd: pd692x0: Add support for PSE PI priority feature
dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
net: pse-pd: tps23881: Add support for static port priority feature
dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
.../bindings/net/pse-pd/microchip,pd692x0.yaml | 12 +-
.../bindings/net/pse-pd/ti,tps23881.yaml | 6 +
.../devicetree/bindings/regulator/regulator.yaml | 5 +
Documentation/netlink/specs/ethtool.yaml | 52 +
Documentation/networking/ethtool-netlink.rst | 94 ++
drivers/net/mdio/fwnode_mdio.c | 26 +-
drivers/net/pse-pd/pd692x0.c | 423 ++++++--
drivers/net/pse-pd/pse_core.c | 1029 ++++++++++++++++++--
drivers/net/pse-pd/pse_regulator.c | 23 +-
drivers/net/pse-pd/tps23881.c | 799 +++++++++++++--
drivers/regulator/core.c | 128 ++-
drivers/regulator/of_regulator.c | 3 +
include/linux/ethtool.h | 47 +
include/linux/ethtool_netlink.h | 9 +
include/linux/pse-pd/pse.h | 171 +++-
include/linux/regulator/consumer.h | 21 +
include/linux/regulator/driver.h | 2 +
include/linux/regulator/machine.h | 2 +
include/uapi/linux/ethtool.h | 54 +
include/uapi/linux/ethtool_netlink.h | 1 -
include/uapi/linux/ethtool_netlink_generated.h | 15 +
net/ethtool/common.c | 12 +
net/ethtool/common.h | 2 +
net/ethtool/netlink.c | 7 +-
net/ethtool/netlink.h | 2 +
net/ethtool/pse-pd.c | 98 +-
net/ethtool/strset.c | 5 +
27 files changed, 2698 insertions(+), 350 deletions(-)
---
base-commit: 2e22297376fe1aa562799c774c3baac9b6db238b
change-id: 20240913-feature_poe_port_prio-a51aed7332ec
Best regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH net-next v4 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 02/27] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
` (26 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent, Kalesh AP
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Removed the unused pse_ethtool_get_pw_limit() function declaration from
pse.h. This function was declared but never implemented or used,
making the declaration unnecessary.
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Kyle Swenson <kyle.swenson@est.tech>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
include/linux/pse-pd/pse.h | 8 --------
1 file changed, 8 deletions(-)
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 591a53e082e6..85a08c349256 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -184,8 +184,6 @@ int pse_ethtool_set_config(struct pse_control *psec,
int pse_ethtool_set_pw_limit(struct pse_control *psec,
struct netlink_ext_ack *extack,
const unsigned int pw_limit);
-int pse_ethtool_get_pw_limit(struct pse_control *psec,
- struct netlink_ext_ack *extack);
bool pse_has_podl(struct pse_control *psec);
bool pse_has_c33(struct pse_control *psec);
@@ -222,12 +220,6 @@ static inline int pse_ethtool_set_pw_limit(struct pse_control *psec,
return -EOPNOTSUPP;
}
-static inline int pse_ethtool_get_pw_limit(struct pse_control *psec,
- struct netlink_ext_ack *extack)
-{
- return -EOPNOTSUPP;
-}
-
static inline bool pse_has_podl(struct pse_control *psec)
{
return false;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 02/27] net: pse-pd: Avoid setting max_uA in regulator constraints
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 03/27] net: pse-pd: Add power limit check Kory Maincent
` (25 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Setting the max_uA constraint in the regulator API imposes a current
limit during the regulator registration process. This behavior conflicts
with preserving the maximum PI power budget configuration across reboots.
Instead, compare the desired current limit to MAX_PI_CURRENT in the
pse_pi_set_current_limit() function to ensure proper handling of the
power budget.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change ni v3:
- New patch
---
drivers/net/pse-pd/pse_core.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 2906ce173f66..9fee4dd53515 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -357,6 +357,9 @@ static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
if (!ops->pi_set_current_limit)
return -EOPNOTSUPP;
+ if (max_uA > MAX_PI_CURRENT)
+ return -ERANGE;
+
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
ret = ops->pi_set_current_limit(pcdev, id, max_uA);
@@ -403,11 +406,9 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
- if (pcdev->ops->pi_set_current_limit) {
+ if (pcdev->ops->pi_set_current_limit)
rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_CURRENT;
- rinit_data->constraints.max_uA = MAX_PI_CURRENT;
- }
rinit_data->supply_regulator = "vpwr";
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 03/27] net: pse-pd: Add power limit check
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 02/27] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 04/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
` (24 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Checking only the current limit is not sufficient. According to the
standard, voltage can reach up to 57V and current up to 1.92A, which
exceeds the power limit described in the standard (99.9W). Add a power
limit check to prevent this.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change ni v3:
- New patch
---
drivers/net/pse-pd/pse_core.c | 3 +++
include/linux/pse-pd/pse.h | 2 ++
2 files changed, 5 insertions(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 9fee4dd53515..432b6c2c04f8 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -877,6 +877,9 @@ int pse_ethtool_set_pw_limit(struct pse_control *psec,
int uV, uA, ret;
s64 tmp_64;
+ if (pw_limit > MAX_PI_PW)
+ return -ERANGE;
+
ret = regulator_get_voltage(psec->ps);
if (!ret) {
NL_SET_ERR_MSG(extack,
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 85a08c349256..bc5addccbf32 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -11,6 +11,8 @@
/* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
#define MAX_PI_CURRENT 1920000
+/* Maximum power in mW according to IEEE 802.3-2022 Table 145-16 */
+#define MAX_PI_PW 99900
struct phy_device;
struct pse_controller_dev;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 04/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (2 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 03/27] net: pse-pd: Add power limit check Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 05/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent
` (23 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Cleaned up several functions in tps23881 by removing redundant checks on
return values at the end of functions. These check has been removed, and
the return statement now directly returns the function result, reducing
the code's complexity and making it more concise.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Kyle Swenson <kyle.swenson@est.tech>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- Removed unused ret variable.
---
drivers/net/pse-pd/tps23881.c | 34 ++++++----------------------------
1 file changed, 6 insertions(+), 28 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 8797ca1a8a21..a3507520ff87 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -59,7 +59,6 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
- int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -78,11 +77,7 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
val |= BIT(chan + 4);
}
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
}
static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
@@ -91,7 +86,6 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
- int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -110,11 +104,7 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
val |= BIT(chan + 8);
}
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
}
static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
@@ -480,7 +470,7 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
struct i2c_client *client = priv->client;
u8 pi_id, lgcl_chan, hw_chan;
u16 val = 0;
- int i, ret;
+ int i;
for (i = 0; i < port_cnt; i++) {
pi_id = port_matrix[i].pi_id;
@@ -511,11 +501,7 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
}
/* Write hardware ports matrix */
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_PORT_MAP, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_PORT_MAP, val);
}
static int
@@ -564,11 +550,7 @@ tps23881_set_ports_conf(struct tps23881_priv *priv,
val |= BIT(port_matrix[i].lgcl_chan[1]) |
BIT(port_matrix[i].lgcl_chan[1] + 4);
}
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
}
static int
@@ -594,11 +576,7 @@ tps23881_set_ports_matrix(struct tps23881_priv *priv,
if (ret)
return ret;
- ret = tps23881_set_ports_conf(priv, port_matrix);
- if (ret)
- return ret;
-
- return 0;
+ return tps23881_set_ports_conf(priv, port_matrix);
}
static int tps23881_setup_pi_matrix(struct pse_controller_dev *pcdev)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 05/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (3 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 04/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 06/27] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
` (22 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This driver frequently follows a pattern where two registers are read or
written in a single operation, followed by calculating the bit offset for
a specific channel.
Introduce helpers to streamline this process and reduce code redundancy,
making the codebase cleaner and more maintainable.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Thanks to Oleksij for the design of the helpers functions.
Change in v3:
- Small fix: use chan >= 4 instead of chan > 4;
Change in v2:
- New patch
---
drivers/net/pse-pd/tps23881.c | 107 +++++++++++++++++++++++++++---------------
1 file changed, 69 insertions(+), 38 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index a3507520ff87..4a75206b2de6 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -53,6 +53,55 @@ static struct tps23881_priv *to_tps23881_priv(struct pse_controller_dev *pcdev)
return container_of(pcdev, struct tps23881_priv, pcdev);
}
+/*
+ * Helper to extract a value from a u16 register value, which is made of two
+ * u8 registers. The function calculates the bit offset based on the channel
+ * and extracts the relevant bits using a provided field mask.
+ *
+ * @param reg_val: The u16 register value (composed of two u8 registers).
+ * @param chan: The channel number (0-7).
+ * @param field_offset: The base bit offset to apply (e.g., 0 or 4).
+ * @param field_mask: The mask to apply to extract the required bits.
+ * @return: The extracted value for the specific channel.
+ */
+static u16 tps23881_calc_val(u16 reg_val, u8 chan, u8 field_offset,
+ u16 field_mask)
+{
+ if (chan >= 4)
+ reg_val >>= 8;
+
+ return (reg_val >> field_offset) & field_mask;
+}
+
+/*
+ * Helper to combine individual channel values into a u16 register value.
+ * The function sets the value for a specific channel in the appropriate
+ * position.
+ *
+ * @param reg_val: The current u16 register value.
+ * @param chan: The channel number (0-7).
+ * @param field_offset: The base bit offset to apply (e.g., 0 or 4).
+ * @param field_mask: The mask to apply for the field (e.g., 0x0F).
+ * @param field_val: The value to set for the specific channel (masked by
+ * field_mask).
+ * @return: The updated u16 register value with the channel value set.
+ */
+static u16 tps23881_set_val(u16 reg_val, u8 chan, u8 field_offset,
+ u16 field_mask, u16 field_val)
+{
+ field_val &= field_mask;
+
+ if (chan < 4) {
+ reg_val &= ~(field_mask << field_offset);
+ reg_val |= (field_val << field_offset);
+ } else {
+ reg_val &= ~(field_mask << (field_offset + 8));
+ reg_val |= (field_val << (field_offset + 8));
+ }
+
+ return reg_val;
+}
+
static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
@@ -64,17 +113,12 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
return -ERANGE;
chan = priv->port[id].chan[0];
- if (chan < 4)
- val = BIT(chan);
- else
- val = BIT(chan + 4);
+ val = tps23881_set_val(0, chan, 0, BIT(chan % 4), BIT(chan % 4));
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4)
- val |= BIT(chan);
- else
- val |= BIT(chan + 4);
+ val = tps23881_set_val(val, chan, 0, BIT(chan % 4),
+ BIT(chan % 4));
}
return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
@@ -91,17 +135,12 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
return -ERANGE;
chan = priv->port[id].chan[0];
- if (chan < 4)
- val = BIT(chan + 4);
- else
- val = BIT(chan + 8);
+ val = tps23881_set_val(0, chan, 4, BIT(chan % 4), BIT(chan % 4));
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4)
- val |= BIT(chan + 4);
- else
- val |= BIT(chan + 8);
+ val = tps23881_set_val(val, chan, 4, BIT(chan % 4),
+ BIT(chan % 4));
}
return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
@@ -113,6 +152,7 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
bool enabled;
u8 chan;
+ u16 val;
int ret;
ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
@@ -120,17 +160,13 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
return ret;
chan = priv->port[id].chan[0];
- if (chan < 4)
- enabled = ret & BIT(chan);
- else
- enabled = ret & BIT(chan + 4);
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled = !!(val);
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4)
- enabled &= !!(ret & BIT(chan));
- else
- enabled &= !!(ret & BIT(chan + 4));
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled &= !!(val);
}
/* Return enabled status only if both channel are on this state */
@@ -146,6 +182,7 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
struct i2c_client *client = priv->client;
bool enabled, delivering;
u8 chan;
+ u16 val;
int ret;
ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
@@ -153,23 +190,17 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
return ret;
chan = priv->port[id].chan[0];
- if (chan < 4) {
- enabled = ret & BIT(chan);
- delivering = ret & BIT(chan + 4);
- } else {
- enabled = ret & BIT(chan + 4);
- delivering = ret & BIT(chan + 8);
- }
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled = !!(val);
+ val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
+ delivering = !!(val);
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4) {
- enabled &= !!(ret & BIT(chan));
- delivering &= !!(ret & BIT(chan + 4));
- } else {
- enabled &= !!(ret & BIT(chan + 4));
- delivering &= !!(ret & BIT(chan + 8));
- }
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled &= !!(val);
+ val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
+ delivering &= !!(val);
}
/* Return delivering status only if both channel are on this state */
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 06/27] net: pse-pd: tps23881: Add missing configuration register after disable
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (4 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 05/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 07/27] net: pse-pd: Use power limit at driver side instead of current limit Kory Maincent
` (21 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
When setting the PWOFF register, the controller resets multiple
configuration registers. This patch ensures these registers are
reconfigured as needed following a disable operation.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v3:
- New patch
---
drivers/net/pse-pd/tps23881.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 4a75206b2de6..b87c391ae0f5 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -130,6 +130,7 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
+ int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -143,7 +144,34 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
BIT(chan % 4));
}
- return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
+ if (ret)
+ return ret;
+
+ /* PWOFF command resets lots of register which need to be
+ * configured again. According to the datasheet "It may take upwards
+ * of 5ms after PWOFFn command for all register values to be updated"
+ */
+ mdelay(5);
+
+ /* Enable detection and classification */
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_DET_CLA_EN);
+ if (ret < 0)
+ return ret;
+
+ chan = priv->port[id].chan[0];
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ val = tps23881_set_val(val, chan, 4, BIT(chan % 4), BIT(chan % 4));
+
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4),
+ BIT(chan % 4));
+ val = tps23881_set_val(val, chan, 4, BIT(chan % 4),
+ BIT(chan % 4));
+ }
+
+ return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
}
static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 07/27] net: pse-pd: Use power limit at driver side instead of current limit
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (5 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 06/27] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 08/27] net: pse-pd: Split ethtool_get_status into multiple callbacks Kory Maincent
` (20 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
The regulator framework uses current limits, but the PSE standard and
known PSE controllers rely on power limits. Instead of converting
current to power within each driver, perform the conversion in the PSE
core. This avoids redundancy in driver implementation and aligns better
with the standard, simplifying driver development.
Remove at the same time the _pse_ethtool_get_status() function which is
not needed anymore.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- New patch
---
drivers/net/pse-pd/pd692x0.c | 45 +++++----------------
drivers/net/pse-pd/pse_core.c | 91 +++++++++++++++++++------------------------
include/linux/pse-pd/pse.h | 16 +++-----
3 files changed, 57 insertions(+), 95 deletions(-)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index 0af7db80b2f8..9f00538f7e45 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -999,13 +999,12 @@ static int pd692x0_pi_get_voltage(struct pse_controller_dev *pcdev, int id)
return (buf.sub[0] << 8 | buf.sub[1]) * 100000;
}
-static int pd692x0_pi_get_current_limit(struct pse_controller_dev *pcdev,
- int id)
+static int pd692x0_pi_get_pw_limit(struct pse_controller_dev *pcdev,
+ int id)
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct pd692x0_msg msg, buf = {0};
- int mW, uV, uA, ret;
- s64 tmp_64;
+ int ret;
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
msg.sub[2] = id;
@@ -1013,48 +1012,24 @@ static int pd692x0_pi_get_current_limit(struct pse_controller_dev *pcdev,
if (ret < 0)
return ret;
- ret = pd692x0_pi_get_pw_from_table(buf.data[2], buf.data[3]);
- if (ret < 0)
- return ret;
- mW = ret;
-
- ret = pd692x0_pi_get_voltage(pcdev, id);
- if (ret < 0)
- return ret;
- uV = ret;
-
- tmp_64 = mW;
- tmp_64 *= 1000000000ull;
- /* uA = mW * 1000000000 / uV */
- uA = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
- return uA;
+ return pd692x0_pi_get_pw_from_table(buf.data[2], buf.data[3]);
}
-static int pd692x0_pi_set_current_limit(struct pse_controller_dev *pcdev,
- int id, int max_uA)
+static int pd692x0_pi_set_pw_limit(struct pse_controller_dev *pcdev,
+ int id, int max_mW)
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct device *dev = &priv->client->dev;
struct pd692x0_msg msg, buf = {0};
- int uV, ret, mW;
- s64 tmp_64;
+ int ret;
ret = pd692x0_fw_unavailable(priv);
if (ret)
return ret;
- ret = pd692x0_pi_get_voltage(pcdev, id);
- if (ret < 0)
- return ret;
- uV = ret;
-
msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
msg.sub[2] = id;
- tmp_64 = uV;
- tmp_64 *= max_uA;
- /* mW = uV * uA / 1000000000 */
- mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
- ret = pd692x0_pi_set_pw_from_table(dev, &msg, mW);
+ ret = pd692x0_pi_set_pw_from_table(dev, &msg, max_mW);
if (ret)
return ret;
@@ -1068,8 +1043,8 @@ static const struct pse_controller_ops pd692x0_ops = {
.pi_disable = pd692x0_pi_disable,
.pi_is_enabled = pd692x0_pi_is_enabled,
.pi_get_voltage = pd692x0_pi_get_voltage,
- .pi_get_current_limit = pd692x0_pi_get_current_limit,
- .pi_set_current_limit = pd692x0_pi_set_current_limit,
+ .pi_get_pw_limit = pd692x0_pi_get_pw_limit,
+ .pi_set_pw_limit = pd692x0_pi_set_pw_limit,
};
#define PD692X0_FW_LINE_MAX_SZ 0xff
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 432b6c2c04f8..ae819bfed1b1 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -291,33 +291,25 @@ static int pse_pi_get_voltage(struct regulator_dev *rdev)
return ret;
}
-static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
- int id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status);
-
static int pse_pi_get_current_limit(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
const struct pse_controller_ops *ops;
- struct netlink_ext_ack extack = {};
- struct pse_control_status st = {};
- int id, uV, ret;
+ int id, uV, mW, ret;
s64 tmp_64;
ops = pcdev->ops;
id = rdev_get_id(rdev);
+ if (!ops->pi_get_pw_limit || !ops->pi_get_voltage)
+ return -EOPNOTSUPP;
+
mutex_lock(&pcdev->lock);
- if (ops->pi_get_current_limit) {
- ret = ops->pi_get_current_limit(pcdev, id);
+ ret = ops->pi_get_pw_limit(pcdev, id);
+ if (ret < 0)
goto out;
- }
+ mW = ret;
- /* If pi_get_current_limit() callback not populated get voltage
- * from pi_get_voltage() and power limit from ethtool_get_status()
- * to calculate current limit.
- */
- ret = _pse_pi_get_voltage(rdev);
+ ret = pse_pi_get_voltage(rdev);
if (!ret) {
dev_err(pcdev->dev, "Voltage null\n");
ret = -ERANGE;
@@ -327,16 +319,7 @@ static int pse_pi_get_current_limit(struct regulator_dev *rdev)
goto out;
uV = ret;
- ret = _pse_ethtool_get_status(pcdev, id, &extack, &st);
- if (ret)
- goto out;
-
- if (!st.c33_avail_pw_limit) {
- ret = -ENODATA;
- goto out;
- }
-
- tmp_64 = st.c33_avail_pw_limit;
+ tmp_64 = mW;
tmp_64 *= 1000000000ull;
/* uA = mW * 1000000000 / uV */
ret = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
@@ -351,10 +334,11 @@ static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
const struct pse_controller_ops *ops;
- int id, ret;
+ int id, mW, ret;
+ s64 tmp_64;
ops = pcdev->ops;
- if (!ops->pi_set_current_limit)
+ if (!ops->pi_set_pw_limit || !ops->pi_get_voltage)
return -EOPNOTSUPP;
if (max_uA > MAX_PI_CURRENT)
@@ -362,7 +346,21 @@ static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
- ret = ops->pi_set_current_limit(pcdev, id, max_uA);
+ ret = pse_pi_get_voltage(rdev);
+ if (!ret) {
+ dev_err(pcdev->dev, "Voltage null\n");
+ ret = -ERANGE;
+ goto out;
+ }
+ if (ret < 0)
+ goto out;
+
+ tmp_64 = ret;
+ tmp_64 *= max_uA;
+ /* mW = uA * uV / 1000000000 */
+ mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
+ ret = ops->pi_set_pw_limit(pcdev, id, mW);
+out:
mutex_unlock(&pcdev->lock);
return ret;
@@ -406,7 +404,7 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
- if (pcdev->ops->pi_set_current_limit)
+ if (pcdev->ops->pi_set_pw_limit)
rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_CURRENT;
@@ -737,23 +735,6 @@ struct pse_control *of_pse_control_get(struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_pse_control_get);
-static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
- int id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
-{
- const struct pse_controller_ops *ops;
-
- ops = pcdev->ops;
- if (!ops->ethtool_get_status) {
- NL_SET_ERR_MSG(extack,
- "PSE driver does not support status report");
- return -EOPNOTSUPP;
- }
-
- return ops->ethtool_get_status(pcdev, id, extack, status);
-}
-
/**
* pse_ethtool_get_status - get status of PSE control
* @psec: PSE control pointer
@@ -766,11 +747,21 @@ int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
struct pse_control_status *status)
{
+ const struct pse_controller_ops *ops;
+ struct pse_controller_dev *pcdev;
int err;
- mutex_lock(&psec->pcdev->lock);
- err = _pse_ethtool_get_status(psec->pcdev, psec->id, extack, status);
- mutex_unlock(&psec->pcdev->lock);
+ pcdev = psec->pcdev;
+ ops = pcdev->ops;
+ if (!ops->ethtool_get_status) {
+ NL_SET_ERR_MSG(extack,
+ "PSE driver does not support status report");
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&pcdev->lock);
+ err = ops->ethtool_get_status(pcdev, psec->id, extack, status);
+ mutex_unlock(&pcdev->lock);
return err;
}
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index bc5addccbf32..a721651cd1e0 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -77,12 +77,8 @@ struct pse_control_status {
* @pi_disable: Configure the PSE PI as disabled.
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
* callback.
- * @pi_get_current_limit: Get the configured current limit similarly to
- * get_current_limit regulator callback.
- * @pi_set_current_limit: Configure the current limit similarly to
- * set_current_limit regulator callback.
- * Should not return an error in case of MAX_PI_CURRENT
- * current value set.
+ * @pi_get_pw_limit: Get the configured power limit of the PSE PI.
+ * @pi_set_pw_limit: Configure the power limit of the PSE PI.
*/
struct pse_controller_ops {
int (*ethtool_get_status)(struct pse_controller_dev *pcdev,
@@ -93,10 +89,10 @@ struct pse_controller_ops {
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
int (*pi_get_voltage)(struct pse_controller_dev *pcdev, int id);
- int (*pi_get_current_limit)(struct pse_controller_dev *pcdev,
- int id);
- int (*pi_set_current_limit)(struct pse_controller_dev *pcdev,
- int id, int max_uA);
+ int (*pi_get_pw_limit)(struct pse_controller_dev *pcdev,
+ int id);
+ int (*pi_set_pw_limit)(struct pse_controller_dev *pcdev,
+ int id, int max_mW);
};
struct module;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 08/27] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (6 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 07/27] net: pse-pd: Use power limit at driver side instead of current limit Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 09/27] net: pse-pd: Remove is_enabled callback from drivers Kory Maincent
` (19 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
The ethtool_get_status callback currently handles all status and PSE
information within a single function. This approach has two key
drawbacks:
1. If the core requires some information for purposes other than
ethtool_get_status, redundant code will be needed to fetch the same
data from the driver (like is_enabled).
2. Drivers currently have access to all information passed to ethtool.
New variables will soon be added to ethtool status, such as PSE ID,
power domain IDs, and budget evaluation strategies, which are meant
to be managed solely by the core. Drivers should not have the ability
to modify these variables.
To resolve these issues, ethtool_get_status has been split into multiple
callbacks, with each handling a specific piece of information required
by ethtool or the core.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- New patch
---
drivers/net/pse-pd/pd692x0.c | 153 ++++++++++++++++++++++++++-----------
drivers/net/pse-pd/pse_core.c | 83 +++++++++++++++++---
drivers/net/pse-pd/pse_regulator.c | 26 +++++--
drivers/net/pse-pd/tps23881.c | 60 +++++++++++----
include/linux/ethtool.h | 36 +++++++++
include/linux/pse-pd/pse.h | 87 +++++++++++++--------
net/ethtool/pse-pd.c | 8 +-
7 files changed, 341 insertions(+), 112 deletions(-)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index 9f00538f7e45..da5d09ed628a 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -517,21 +517,38 @@ pd692x0_pse_ext_state_map[] = {
{ /* sentinel */ }
};
-static void
-pd692x0_get_ext_state(struct ethtool_c33_pse_ext_state_info *c33_ext_state_info,
- u32 status_code)
+static int
+pd692x0_pi_get_ext_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_ext_state_info *ext_state_info)
{
+ struct ethtool_c33_pse_ext_state_info *c33_ext_state_info;
const struct pd692x0_pse_ext_state_mapping *ext_state_map;
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
+ msg.sub[2] = id;
+ ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
+ if (ret < 0)
+ return ret;
+
+ c33_ext_state_info = &ext_state_info->c33_ext_state_info;
ext_state_map = pd692x0_pse_ext_state_map;
while (ext_state_map->status_code) {
- if (ext_state_map->status_code == status_code) {
+ if (ext_state_map->status_code == buf.sub[0]) {
c33_ext_state_info->c33_pse_ext_state = ext_state_map->pse_ext_state;
c33_ext_state_info->__c33_pse_ext_substate = ext_state_map->pse_ext_substate;
- return;
+ return 0;
}
ext_state_map++;
}
+
+ return 0;
}
struct pd692x0_class_pw {
@@ -613,35 +630,36 @@ static int pd692x0_pi_set_pw_from_table(struct device *dev,
}
static int
-pd692x0_pi_get_pw_ranges(struct pse_control_status *st)
+pd692x0_pi_get_pw_limit_ranges(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_limit_ranges *pw_limit_ranges)
{
+ struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
const struct pd692x0_class_pw *pw_table;
int i;
pw_table = pd692x0_class_pw_table;
- st->c33_pw_limit_ranges = kcalloc(PD692X0_CLASS_PW_TABLE_SIZE,
- sizeof(struct ethtool_c33_pse_pw_limit_range),
- GFP_KERNEL);
- if (!st->c33_pw_limit_ranges)
+ c33_pw_limit_ranges = kcalloc(PD692X0_CLASS_PW_TABLE_SIZE,
+ sizeof(*c33_pw_limit_ranges),
+ GFP_KERNEL);
+ if (!c33_pw_limit_ranges)
return -ENOMEM;
for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
- st->c33_pw_limit_ranges[i].min = pw_table->class_pw;
- st->c33_pw_limit_ranges[i].max = pw_table->class_pw + pw_table->max_added_class_pw;
+ c33_pw_limit_ranges[i].min = pw_table->class_pw;
+ c33_pw_limit_ranges[i].max = pw_table->class_pw +
+ pw_table->max_added_class_pw;
}
- st->c33_pw_limit_nb_ranges = i;
- return 0;
+ pw_limit_ranges->c33_pw_limit_ranges = c33_pw_limit_ranges;
+ return i;
}
-static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
- unsigned long id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+static int
+pd692x0_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state)
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct pd692x0_msg msg, buf = {0};
- u32 class;
int ret;
ret = pd692x0_fw_unavailable(priv);
@@ -654,39 +672,65 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
if (ret < 0)
return ret;
- /* Compare Port Status (Communication Protocol Document par. 7.1) */
- if ((buf.sub[0] & 0xf0) == 0x80 || (buf.sub[0] & 0xf0) == 0x90)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
- else if (buf.sub[0] == 0x1b || buf.sub[0] == 0x22)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING;
- else if (buf.sub[0] == 0x12)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_FAULT;
- else
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
-
if (buf.sub[1])
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
else
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
- priv->admin_state[id] = status->c33_admin_state;
+ priv->admin_state[id] = admin_state->c33_admin_state;
- pd692x0_get_ext_state(&status->c33_ext_state_info, buf.sub[0]);
- status->c33_actual_pw = (buf.data[0] << 4 | buf.data[1]) * 100;
+ return 0;
+}
- msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
+static int
+pd692x0_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
+
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
msg.sub[2] = id;
- memset(&buf, 0, sizeof(buf));
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
if (ret < 0)
return ret;
- ret = pd692x0_pi_get_pw_from_table(buf.data[0], buf.data[1]);
- if (ret < 0)
+ /* Compare Port Status (Communication Protocol Document par. 7.1) */
+ if ((buf.sub[0] & 0xf0) == 0x80 || (buf.sub[0] & 0xf0) == 0x90)
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
+ else if (buf.sub[0] == 0x1b || buf.sub[0] == 0x22)
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING;
+ else if (buf.sub[0] == 0x12)
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_FAULT;
+ else
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
+
+ return 0;
+}
+
+static int
+pd692x0_pi_get_pw_class(struct pse_controller_dev *pcdev, int id)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ u32 class;
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
return ret;
- status->c33_avail_pw_limit = ret;
- memset(&buf, 0, sizeof(buf));
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_CLASS];
msg.sub[2] = id;
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
@@ -695,13 +739,29 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
class = buf.data[3] >> 4;
if (class <= 8)
- status->c33_pw_class = class;
+ return class;
+
+ return 0;
+}
+
+static int
+pd692x0_pi_get_actual_pw(struct pse_controller_dev *pcdev, int id)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
- ret = pd692x0_pi_get_pw_ranges(status);
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
+ msg.sub[2] = id;
+ ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
if (ret < 0)
return ret;
- return 0;
+ return (buf.data[0] << 4 | buf.data[1]) * 100;
}
static struct pd692x0_msg_ver pd692x0_get_sw_version(struct pd692x0_priv *priv)
@@ -1038,13 +1098,18 @@ static int pd692x0_pi_set_pw_limit(struct pse_controller_dev *pcdev,
static const struct pse_controller_ops pd692x0_ops = {
.setup_pi_matrix = pd692x0_setup_pi_matrix,
- .ethtool_get_status = pd692x0_ethtool_get_status,
+ .pi_get_admin_state = pd692x0_pi_get_admin_state,
+ .pi_get_pw_status = pd692x0_pi_get_pw_status,
+ .pi_get_ext_state = pd692x0_pi_get_ext_state,
+ .pi_get_pw_class = pd692x0_pi_get_pw_class,
+ .pi_get_actual_pw = pd692x0_pi_get_actual_pw,
.pi_enable = pd692x0_pi_enable,
.pi_disable = pd692x0_pi_disable,
.pi_is_enabled = pd692x0_pi_is_enabled,
.pi_get_voltage = pd692x0_pi_get_voltage,
.pi_get_pw_limit = pd692x0_pi_get_pw_limit,
.pi_set_pw_limit = pd692x0_pi_set_pw_limit,
+ .pi_get_pw_limit_ranges = pd692x0_pi_get_pw_limit_ranges,
};
#define PD692X0_FW_LINE_MAX_SZ 0xff
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index ae819bfed1b1..5f2a9f36e4ed 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -443,6 +443,13 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
if (!pcdev->nr_lines)
pcdev->nr_lines = 1;
+ if (!pcdev->ops->pi_get_admin_state ||
+ !pcdev->ops->pi_get_pw_status) {
+ dev_err(pcdev->dev,
+ "Mandatory status report callbacks are missing");
+ return -EINVAL;
+ }
+
ret = of_load_pse_pis(pcdev);
if (ret)
return ret;
@@ -745,25 +752,81 @@ EXPORT_SYMBOL_GPL(of_pse_control_get);
*/
int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+ struct ethtool_pse_control_status *status)
{
+ struct pse_admin_state admin_state = {0};
+ struct pse_pw_status pw_status = {0};
const struct pse_controller_ops *ops;
struct pse_controller_dev *pcdev;
- int err;
+ int ret;
pcdev = psec->pcdev;
ops = pcdev->ops;
- if (!ops->ethtool_get_status) {
- NL_SET_ERR_MSG(extack,
- "PSE driver does not support status report");
- return -EOPNOTSUPP;
+ mutex_lock(&pcdev->lock);
+ ret = ops->pi_get_admin_state(pcdev, psec->id, &admin_state);
+ if (ret)
+ goto out;
+ status->podl_admin_state = admin_state.podl_admin_state;
+ status->c33_admin_state = admin_state.c33_admin_state;
+
+ ret = ops->pi_get_pw_status(pcdev, psec->id, &pw_status);
+ if (ret)
+ goto out;
+ status->podl_pw_status = pw_status.podl_pw_status;
+ status->c33_pw_status = pw_status.c33_pw_status;
+
+ if (ops->pi_get_ext_state) {
+ struct pse_ext_state_info ext_state_info = {0};
+
+ ret = ops->pi_get_ext_state(pcdev, psec->id,
+ &ext_state_info);
+ if (ret)
+ goto out;
+
+ memcpy(&status->c33_ext_state_info,
+ &ext_state_info.c33_ext_state_info,
+ sizeof(status->c33_ext_state_info));
}
- mutex_lock(&pcdev->lock);
- err = ops->ethtool_get_status(pcdev, psec->id, extack, status);
- mutex_unlock(&pcdev->lock);
+ if (ops->pi_get_pw_class) {
+ ret = ops->pi_get_pw_class(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
- return err;
+ status->c33_pw_class = ret;
+ }
+
+ if (ops->pi_get_actual_pw) {
+ ret = ops->pi_get_actual_pw(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
+
+ status->c33_actual_pw = ret;
+ }
+
+ if (ops->pi_get_pw_limit) {
+ ret = ops->pi_get_pw_limit(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
+
+ status->c33_avail_pw_limit = ret;
+ }
+
+ if (ops->pi_get_pw_limit_ranges) {
+ struct pse_pw_limit_ranges pw_limit_ranges = {0};
+
+ ret = ops->pi_get_pw_limit_ranges(pcdev, psec->id,
+ &pw_limit_ranges);
+ if (ret < 0)
+ goto out;
+
+ status->c33_pw_limit_ranges =
+ pw_limit_ranges.c33_pw_limit_ranges;
+ status->c33_pw_limit_nb_ranges = ret;
+ }
+out:
+ mutex_unlock(&psec->pcdev->lock);
+ return ret;
}
EXPORT_SYMBOL_GPL(pse_ethtool_get_status);
diff --git a/drivers/net/pse-pd/pse_regulator.c b/drivers/net/pse-pd/pse_regulator.c
index 64ab36974fe0..86360056b2f5 100644
--- a/drivers/net/pse-pd/pse_regulator.c
+++ b/drivers/net/pse-pd/pse_regulator.c
@@ -60,9 +60,19 @@ pse_reg_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
}
static int
-pse_reg_ethtool_get_status(struct pse_controller_dev *pcdev, unsigned long id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+pse_reg_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state)
+{
+ struct pse_reg_priv *priv = to_pse_reg(pcdev);
+
+ admin_state->podl_admin_state = priv->admin_state;
+
+ return 0;
+}
+
+static int
+pse_reg_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status)
{
struct pse_reg_priv *priv = to_pse_reg(pcdev);
int ret;
@@ -72,18 +82,18 @@ pse_reg_ethtool_get_status(struct pse_controller_dev *pcdev, unsigned long id,
return ret;
if (!ret)
- status->podl_pw_status = ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED;
+ pw_status->podl_pw_status =
+ ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED;
else
- status->podl_pw_status =
+ pw_status->podl_pw_status =
ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING;
- status->podl_admin_state = priv->admin_state;
-
return 0;
}
static const struct pse_controller_ops pse_reg_ops = {
- .ethtool_get_status = pse_reg_ethtool_get_status,
+ .pi_get_admin_state = pse_reg_pi_get_admin_state,
+ .pi_get_pw_status = pse_reg_pi_get_pw_status,
.pi_enable = pse_reg_pi_enable,
.pi_is_enabled = pse_reg_pi_is_enabled,
.pi_disable = pse_reg_pi_disable,
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index b87c391ae0f5..f735b6917f8b 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -201,14 +201,13 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
return enabled;
}
-static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
- unsigned long id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+static int
+tps23881_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
struct i2c_client *client = priv->client;
- bool enabled, delivering;
+ bool enabled;
u8 chan;
u16 val;
int ret;
@@ -220,28 +219,56 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
chan = priv->port[id].chan[0];
val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
enabled = !!(val);
- val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
- delivering = !!(val);
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
enabled &= !!(val);
+ }
+
+ /* Return enabled status only if both channel are on this state */
+ if (enabled)
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ else
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+
+ return 0;
+}
+
+static int
+tps23881_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ bool delivering;
+ u8 chan;
+ u16 val;
+ int ret;
+
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
+ if (ret < 0)
+ return ret;
+
+ chan = priv->port[id].chan[0];
+ val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
+ delivering = !!(val);
+
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
delivering &= !!(val);
}
/* Return delivering status only if both channel are on this state */
if (delivering)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
- else
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
-
- /* Return enabled status only if both channel are on this state */
- if (enabled)
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
else
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
return 0;
}
@@ -664,7 +691,8 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_enable = tps23881_pi_enable,
.pi_disable = tps23881_pi_disable,
.pi_is_enabled = tps23881_pi_is_enabled,
- .ethtool_get_status = tps23881_ethtool_get_status,
+ .pi_get_admin_state = tps23881_pi_get_admin_state,
+ .pi_get_pw_status = tps23881_pi_get_pw_status,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index f711bfd75c4d..2bdf7e72ee50 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1323,4 +1323,40 @@ struct ethtool_c33_pse_pw_limit_range {
u32 min;
u32 max;
};
+
+/**
+ * struct ethtool_pse_control_status - PSE control/channel status.
+ *
+ * @podl_admin_state: operational state of the PoDL PSE
+ * functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
+ * @podl_pw_status: power detection status of the PoDL PSE.
+ * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
+ * @c33_admin_state: operational state of the PSE
+ * functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
+ * @c33_pw_status: power detection status of the PSE.
+ * IEEE 802.3-2022 30.9.1.1.5 aPSEPowerDetectionStatus:
+ * @c33_pw_class: detected class of a powered PD
+ * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification
+ * @c33_actual_pw: power currently delivered by the PSE in mW
+ * IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
+ * @c33_ext_state_info: extended state information of the PSE
+ * @c33_avail_pw_limit: available power limit of the PSE in mW
+ * IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
+ * @c33_pw_limit_ranges: supported power limit configuration range. The driver
+ * is in charge of the memory allocation
+ * @c33_pw_limit_nb_ranges: number of supported power limit configuration
+ * ranges
+ */
+struct ethtool_pse_control_status {
+ enum ethtool_podl_pse_admin_state podl_admin_state;
+ enum ethtool_podl_pse_pw_d_status podl_pw_status;
+ enum ethtool_c33_pse_admin_state c33_admin_state;
+ enum ethtool_c33_pse_pw_d_status c33_pw_status;
+ u32 c33_pw_class;
+ u32 c33_actual_pw;
+ struct ethtool_c33_pse_ext_state_info c33_ext_state_info;
+ u32 c33_avail_pw_limit;
+ struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
+ u32 c33_pw_limit_nb_ranges;
+};
#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index a721651cd1e0..db8b3db7b849 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -31,60 +31,84 @@ struct pse_control_config {
};
/**
- * struct pse_control_status - PSE control/channel status.
+ * struct pse_admin_state - PSE operational state
*
* @podl_admin_state: operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
- * @podl_pw_status: power detection status of the PoDL PSE.
- * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
* @c33_admin_state: operational state of the PSE
* functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
+ */
+struct pse_admin_state {
+ enum ethtool_podl_pse_admin_state podl_admin_state;
+ enum ethtool_c33_pse_admin_state c33_admin_state;
+};
+
+/**
+ * struct pse_pw_status - PSE power detection status
+ *
+ * @podl_pw_status: power detection status of the PoDL PSE.
+ * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
* @c33_pw_status: power detection status of the PSE.
* IEEE 802.3-2022 30.9.1.1.5 aPSEPowerDetectionStatus:
- * @c33_pw_class: detected class of a powered PD
- * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification
- * @c33_actual_pw: power currently delivered by the PSE in mW
- * IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
- * @c33_ext_state_info: extended state information of the PSE
- * @c33_avail_pw_limit: available power limit of the PSE in mW
- * IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
- * @c33_pw_limit_ranges: supported power limit configuration range. The driver
- * is in charge of the memory allocation.
- * @c33_pw_limit_nb_ranges: number of supported power limit configuration
- * ranges
*/
-struct pse_control_status {
- enum ethtool_podl_pse_admin_state podl_admin_state;
+struct pse_pw_status {
enum ethtool_podl_pse_pw_d_status podl_pw_status;
- enum ethtool_c33_pse_admin_state c33_admin_state;
enum ethtool_c33_pse_pw_d_status c33_pw_status;
- u32 c33_pw_class;
- u32 c33_actual_pw;
+};
+
+/**
+ * struct pse_ext_state_info - PSE extended state information
+ *
+ * @c33_ext_state_info: extended state information of the PSE
+ */
+struct pse_ext_state_info {
struct ethtool_c33_pse_ext_state_info c33_ext_state_info;
- u32 c33_avail_pw_limit;
+};
+
+/**
+ * struct pse_pw_limit_ranges - PSE power limit configuration range
+ *
+ * @c33_pw_limit_ranges: supported power limit configuration range. The driver
+ * is in charge of the memory allocation.
+ */
+struct pse_pw_limit_ranges {
struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
- u32 c33_pw_limit_nb_ranges;
};
/**
* struct pse_controller_ops - PSE controller driver callbacks
*
- * @ethtool_get_status: get PSE control status for ethtool interface
* @setup_pi_matrix: setup PI matrix of the PSE controller
+ * @pi_get_admin_state: Get the operational state of the PSE PI. This ops
+ * is mandatory.
+ * @pi_get_pw_status: Get the power detection status of the PSE PI. This
+ * ops is mandatory.
+ * @pi_get_ext_state: Get the extended state of the PSE PI.
+ * @pi_get_pw_class: Get the power class of the PSE PI.
+ * @pi_get_actual_pw: Get actual power of the PSE PI in mW.
* @pi_is_enabled: Return 1 if the PSE PI is enabled, 0 if not.
* May also return negative errno.
* @pi_enable: Configure the PSE PI as enabled.
* @pi_disable: Configure the PSE PI as disabled.
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
- * callback.
- * @pi_get_pw_limit: Get the configured power limit of the PSE PI.
- * @pi_set_pw_limit: Configure the power limit of the PSE PI.
+ * callback in uV.
+ * @pi_get_pw_limit: Get the configured power limit of the PSE PI in mW.
+ * @pi_set_pw_limit: Configure the power limit of the PSE PI in mW.
+ * @pi_get_pw_limit_ranges: Get the supported power limit configuration
+ * range. The driver is in charge of the memory
+ * allocation and should return the number of
+ * ranges.
*/
struct pse_controller_ops {
- int (*ethtool_get_status)(struct pse_controller_dev *pcdev,
- unsigned long id, struct netlink_ext_ack *extack,
- struct pse_control_status *status);
int (*setup_pi_matrix)(struct pse_controller_dev *pcdev);
+ int (*pi_get_admin_state)(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state);
+ int (*pi_get_pw_status)(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status);
+ int (*pi_get_ext_state)(struct pse_controller_dev *pcdev, int id,
+ struct pse_ext_state_info *ext_state_info);
+ int (*pi_get_pw_class)(struct pse_controller_dev *pcdev, int id);
+ int (*pi_get_actual_pw)(struct pse_controller_dev *pcdev, int id);
int (*pi_is_enabled)(struct pse_controller_dev *pcdev, int id);
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
@@ -93,12 +117,15 @@ struct pse_controller_ops {
int id);
int (*pi_set_pw_limit)(struct pse_controller_dev *pcdev,
int id, int max_mW);
+ int (*pi_get_pw_limit_ranges)(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_limit_ranges *pw_limit_ranges);
};
struct module;
struct device_node;
struct of_phandle_args;
struct pse_control;
+struct ethtool_pse_control_status;
/* PSE PI pairset pinout can either be Alternative A or Alternative B */
enum pse_pi_pairset_pinout {
@@ -175,7 +202,7 @@ void pse_control_put(struct pse_control *psec);
int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
- struct pse_control_status *status);
+ struct ethtool_pse_control_status *status);
int pse_ethtool_set_config(struct pse_control *psec,
struct netlink_ext_ack *extack,
const struct pse_control_config *config);
@@ -199,7 +226,7 @@ static inline void pse_control_put(struct pse_control *psec)
static inline int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+ struct ethtool_pse_control_status *status)
{
return -EOPNOTSUPP;
}
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index a0705edca22a..2819e2ba6be2 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -19,7 +19,7 @@ struct pse_req_info {
struct pse_reply_data {
struct ethnl_reply_data base;
- struct pse_control_status status;
+ struct ethtool_pse_control_status status;
};
#define PSE_REPDATA(__reply_base) \
@@ -80,7 +80,7 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
const struct pse_reply_data *data = PSE_REPDATA(reply_base);
- const struct pse_control_status *st = &data->status;
+ const struct ethtool_pse_control_status *st = &data->status;
int len = 0;
if (st->podl_admin_state > 0)
@@ -114,7 +114,7 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
}
static int pse_put_pw_limit_ranges(struct sk_buff *skb,
- const struct pse_control_status *st)
+ const struct ethtool_pse_control_status *st)
{
const struct ethtool_c33_pse_pw_limit_range *pw_limit_ranges;
int i;
@@ -146,7 +146,7 @@ static int pse_fill_reply(struct sk_buff *skb,
const struct ethnl_reply_data *reply_base)
{
const struct pse_reply_data *data = PSE_REPDATA(reply_base);
- const struct pse_control_status *st = &data->status;
+ const struct ethtool_pse_control_status *st = &data->status;
if (st->podl_admin_state > 0 &&
nla_put_u32(skb, ETHTOOL_A_PODL_PSE_ADMIN_STATE,
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 09/27] net: pse-pd: Remove is_enabled callback from drivers
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (7 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 08/27] net: pse-pd: Split ethtool_get_status into multiple callbacks Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 10/27] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
` (18 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
The is_enabled callback is now redundant as the admin_state can be obtained
directly from the driver and provides the same information.
To simplify functionality, the core will handle this internally, making
the is_enabled callback unnecessary at the driver level. This patch
removes the callback from all drivers.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- New patch
---
drivers/net/pse-pd/pd692x0.c | 26 --------------------------
drivers/net/pse-pd/pse_core.c | 13 +++++++++++--
drivers/net/pse-pd/pse_regulator.c | 9 ---------
drivers/net/pse-pd/tps23881.c | 28 ----------------------------
include/linux/pse-pd/pse.h | 3 ---
5 files changed, 11 insertions(+), 68 deletions(-)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index da5d09ed628a..fc9e23927b3b 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -431,31 +431,6 @@ static int pd692x0_pi_disable(struct pse_controller_dev *pcdev, int id)
return 0;
}
-static int pd692x0_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
-{
- struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
- struct pd692x0_msg msg, buf = {0};
- int ret;
-
- ret = pd692x0_fw_unavailable(priv);
- if (ret)
- return ret;
-
- msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
- msg.sub[2] = id;
- ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
- if (ret < 0)
- return ret;
-
- if (buf.sub[1]) {
- priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
- return 1;
- } else {
- priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
- return 0;
- }
-}
-
struct pd692x0_pse_ext_state_mapping {
u32 status_code;
enum ethtool_c33_pse_ext_state pse_ext_state;
@@ -1105,7 +1080,6 @@ static const struct pse_controller_ops pd692x0_ops = {
.pi_get_actual_pw = pd692x0_pi_get_actual_pw,
.pi_enable = pd692x0_pi_enable,
.pi_disable = pd692x0_pi_disable,
- .pi_is_enabled = pd692x0_pi_is_enabled,
.pi_get_voltage = pd692x0_pi_get_voltage,
.pi_get_pw_limit = pd692x0_pi_get_pw_limit,
.pi_set_pw_limit = pd692x0_pi_set_pw_limit,
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 5f2a9f36e4ed..887a477197a6 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -210,16 +210,25 @@ static int of_load_pse_pis(struct pse_controller_dev *pcdev)
static int pse_pi_is_enabled(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
+ struct pse_admin_state admin_state = {0};
const struct pse_controller_ops *ops;
int id, ret;
ops = pcdev->ops;
- if (!ops->pi_is_enabled)
+ if (!ops->pi_get_admin_state)
return -EOPNOTSUPP;
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
- ret = ops->pi_is_enabled(pcdev, id);
+ ret = ops->pi_get_admin_state(pcdev, id, &admin_state);
+ if (ret)
+ goto out;
+
+ if (admin_state.podl_admin_state == ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED ||
+ admin_state.c33_admin_state == ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED)
+ ret = 1;
+
+out:
mutex_unlock(&pcdev->lock);
return ret;
diff --git a/drivers/net/pse-pd/pse_regulator.c b/drivers/net/pse-pd/pse_regulator.c
index 86360056b2f5..6ce6773fff31 100644
--- a/drivers/net/pse-pd/pse_regulator.c
+++ b/drivers/net/pse-pd/pse_regulator.c
@@ -51,14 +51,6 @@ pse_reg_pi_disable(struct pse_controller_dev *pcdev, int id)
return 0;
}
-static int
-pse_reg_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
-{
- struct pse_reg_priv *priv = to_pse_reg(pcdev);
-
- return regulator_is_enabled(priv->ps);
-}
-
static int
pse_reg_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
struct pse_admin_state *admin_state)
@@ -95,7 +87,6 @@ static const struct pse_controller_ops pse_reg_ops = {
.pi_get_admin_state = pse_reg_pi_get_admin_state,
.pi_get_pw_status = pse_reg_pi_get_pw_status,
.pi_enable = pse_reg_pi_enable,
- .pi_is_enabled = pse_reg_pi_is_enabled,
.pi_disable = pse_reg_pi_disable,
};
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index f735b6917f8b..340d70ee37fe 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -174,33 +174,6 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
}
-static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
-{
- struct tps23881_priv *priv = to_tps23881_priv(pcdev);
- struct i2c_client *client = priv->client;
- bool enabled;
- u8 chan;
- u16 val;
- int ret;
-
- ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
- if (ret < 0)
- return ret;
-
- chan = priv->port[id].chan[0];
- val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
- enabled = !!(val);
-
- if (priv->port[id].is_4p) {
- chan = priv->port[id].chan[1];
- val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
- enabled &= !!(val);
- }
-
- /* Return enabled status only if both channel are on this state */
- return enabled;
-}
-
static int
tps23881_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
struct pse_admin_state *admin_state)
@@ -690,7 +663,6 @@ static const struct pse_controller_ops tps23881_ops = {
.setup_pi_matrix = tps23881_setup_pi_matrix,
.pi_enable = tps23881_pi_enable,
.pi_disable = tps23881_pi_disable,
- .pi_is_enabled = tps23881_pi_is_enabled,
.pi_get_admin_state = tps23881_pi_get_admin_state,
.pi_get_pw_status = tps23881_pi_get_pw_status,
};
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index db8b3db7b849..09e62d8c3271 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -86,8 +86,6 @@ struct pse_pw_limit_ranges {
* @pi_get_ext_state: Get the extended state of the PSE PI.
* @pi_get_pw_class: Get the power class of the PSE PI.
* @pi_get_actual_pw: Get actual power of the PSE PI in mW.
- * @pi_is_enabled: Return 1 if the PSE PI is enabled, 0 if not.
- * May also return negative errno.
* @pi_enable: Configure the PSE PI as enabled.
* @pi_disable: Configure the PSE PI as disabled.
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
@@ -109,7 +107,6 @@ struct pse_controller_ops {
struct pse_ext_state_info *ext_state_info);
int (*pi_get_pw_class)(struct pse_controller_dev *pcdev, int id);
int (*pi_get_actual_pw)(struct pse_controller_dev *pcdev, int id);
- int (*pi_is_enabled)(struct pse_controller_dev *pcdev, int id);
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
int (*pi_get_voltage)(struct pse_controller_dev *pcdev, int id);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 10/27] net: pse-pd: tps23881: Add support for power limit and measurement features
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (8 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 09/27] net: pse-pd: Remove is_enabled callback from drivers Kory Maincent
@ 2025-01-03 21:12 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 11/27] net: pse-pd: Add support for PSE device index Kory Maincent
` (17 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:12 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Expand PSE callbacks to support the newly introduced
pi_get/set_pw_limit() and pi_get_voltage() functions. These callbacks
allow for power limit configuration in the TPS23881 controller.
Additionally, the patch includes the pi_get_pw_class() the
pi_get_actual_pw(), and the pi_get_pw_limit_ranges') callbacks providing
more comprehensive PoE status reporting.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- Several changes for better readibility and to avoid code duplicate.
- Move on to the new callbacks.
Change in v3:
- NIT change, use tps23881_set_val helper to set the power limit
register value.
- Add policy varaible internally to being able to reconfigure it after a
PWOFF call.
Change in v2:
- Use newly introduced helpers.
---
drivers/net/pse-pd/tps23881.c | 258 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 256 insertions(+), 2 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 340d70ee37fe..5e9dda2c0eac 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -25,20 +25,32 @@
#define TPS23881_REG_GEN_MASK 0x17
#define TPS23881_REG_NBITACC BIT(5)
#define TPS23881_REG_PW_EN 0x19
+#define TPS23881_REG_2PAIR_POL1 0x1e
#define TPS23881_REG_PORT_MAP 0x26
#define TPS23881_REG_PORT_POWER 0x29
-#define TPS23881_REG_POEPLUS 0x40
+#define TPS23881_REG_4PAIR_POL1 0x2a
+#define TPS23881_REG_INPUT_V 0x2e
+#define TPS23881_REG_CHAN1_A 0x30
+#define TPS23881_REG_CHAN1_V 0x32
+#define TPS23881_REG_FOLDBACK 0x40
#define TPS23881_REG_TPON BIT(0)
#define TPS23881_REG_FWREV 0x41
#define TPS23881_REG_DEVID 0x43
#define TPS23881_REG_DEVID_MASK 0xF0
#define TPS23881_DEVICE_ID 0x02
+#define TPS23881_REG_CHAN1_CLASS 0x4c
#define TPS23881_REG_SRAM_CTRL 0x60
#define TPS23881_REG_SRAM_DATA 0x61
+#define TPS23881_UV_STEP 3662
+#define TPS23881_NA_STEP 70190
+#define TPS23881_MW_STEP 500
+#define TPS23881_MIN_PI_PW_LIMIT_MW 2000
+
struct tps23881_port_desc {
u8 chan[2];
bool is_4p;
+ int pw_pol;
};
struct tps23881_priv {
@@ -102,6 +114,54 @@ static u16 tps23881_set_val(u16 reg_val, u8 chan, u8 field_offset,
return reg_val;
}
+static int
+tps23881_pi_set_pw_pol_limit(struct tps23881_priv *priv, int id, u8 pw_pol,
+ bool is_4p)
+{
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u16 val;
+ u8 chan;
+
+ chan = priv->port[id].chan[0];
+ if (!is_4p) {
+ reg = TPS23881_REG_2PAIR_POL1 + (chan % 4);
+ } else {
+ /* One chan is enough to configure the 4p PI power limit */
+ if ((chan % 4) < 2)
+ reg = TPS23881_REG_4PAIR_POL1;
+ else
+ reg = TPS23881_REG_4PAIR_POL1 + 1;
+ }
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_set_val(ret, chan, 0, 0xff, pw_pol);
+ return i2c_smbus_write_word_data(client, reg, val);
+}
+
+static int tps23881_pi_enable_manual_pol(struct tps23881_priv *priv, int id)
+{
+ struct i2c_client *client = priv->client;
+ int ret;
+ u8 chan;
+ u16 val;
+
+ ret = i2c_smbus_read_byte_data(client, TPS23881_REG_FOLDBACK);
+ if (ret < 0)
+ return ret;
+
+ /* No need to test if the chan is PoE4 as setting either bit for a
+ * 4P configured port disables the automatic configuration on both
+ * channels.
+ */
+ chan = priv->port[id].chan[0];
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ return i2c_smbus_write_byte_data(client, TPS23881_REG_FOLDBACK, val);
+}
+
static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
@@ -171,7 +231,21 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
BIT(chan % 4));
}
- return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
+ if (ret)
+ return ret;
+
+ /* No power policy */
+ if (priv->port[id].pw_pol < 0)
+ return 0;
+
+ ret = tps23881_pi_enable_manual_pol(priv, id);
+ if (ret < 0)
+ return ret;
+
+ /* Set power policy */
+ return tps23881_pi_set_pw_pol_limit(priv, id, priv->port[id].pw_pol,
+ priv->port[id].is_4p);
}
static int
@@ -246,6 +320,177 @@ tps23881_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
return 0;
}
+static int tps23881_pi_get_voltage(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ int ret;
+ u64 uV;
+
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_INPUT_V);
+ if (ret < 0)
+ return ret;
+
+ uV = ret & 0x3fff;
+ uV *= TPS23881_UV_STEP;
+
+ return (int)uV;
+}
+
+static int
+tps23881_pi_get_chan_current(struct tps23881_priv *priv, u8 chan)
+{
+ struct i2c_client *client = priv->client;
+ int reg, ret;
+ u64 tmp_64;
+
+ /* Registers 0x30 to 0x3d */
+ reg = TPS23881_REG_CHAN1_A + (chan % 4) * 4 + (chan >= 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ tmp_64 = ret & 0x3fff;
+ tmp_64 *= TPS23881_NA_STEP;
+ /* uA = nA / 1000 */
+ tmp_64 = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000);
+ return (int)tmp_64;
+}
+
+static int tps23881_pi_get_pw_class(struct pse_controller_dev *pcdev,
+ int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u8 chan;
+
+ chan = priv->port[id].chan[0];
+ reg = TPS23881_REG_CHAN1_CLASS + (chan % 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ return tps23881_calc_val(ret, chan, 4, 0x0f);
+}
+
+static int
+tps23881_pi_get_actual_pw(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ int ret, uV, uA;
+ u64 tmp_64;
+ u8 chan;
+
+ ret = tps23881_pi_get_voltage(&priv->pcdev, id);
+ if (ret < 0)
+ return ret;
+ uV = ret;
+
+ chan = priv->port[id].chan[0];
+ ret = tps23881_pi_get_chan_current(priv, chan);
+ if (ret < 0)
+ return ret;
+ uA = ret;
+
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
+ ret = tps23881_pi_get_chan_current(priv, chan);
+ if (ret < 0)
+ return ret;
+ uA += ret;
+ }
+
+ tmp_64 = uV;
+ tmp_64 *= uA;
+ /* mW = uV * uA / 1000000000 */
+ return DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
+}
+
+static int
+tps23881_pi_get_pw_limit_chan(struct tps23881_priv *priv, u8 chan)
+{
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u16 val;
+
+ reg = TPS23881_REG_2PAIR_POL1 + (chan % 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_calc_val(ret, chan, 0, 0xff);
+ return val * TPS23881_MW_STEP;
+}
+
+static int tps23881_pi_get_pw_limit(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ int ret, mW;
+ u8 chan;
+
+ chan = priv->port[id].chan[0];
+ ret = tps23881_pi_get_pw_limit_chan(priv, chan);
+ if (ret < 0)
+ return ret;
+
+ mW = ret;
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
+ ret = tps23881_pi_get_pw_limit_chan(priv, chan);
+ if (ret < 0)
+ return ret;
+ mW += ret;
+ }
+
+ return mW;
+}
+
+static int tps23881_pi_set_pw_limit(struct pse_controller_dev *pcdev,
+ int id, int max_mW)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ u8 pw_pol;
+ int ret;
+
+ if (max_mW < TPS23881_MIN_PI_PW_LIMIT_MW || MAX_PI_PW < max_mW) {
+ dev_err(&priv->client->dev,
+ "power limit %d out of ranges [%d,%d]",
+ max_mW, TPS23881_MIN_PI_PW_LIMIT_MW, MAX_PI_PW);
+ return -ERANGE;
+ }
+
+ ret = tps23881_pi_enable_manual_pol(priv, id);
+ if (ret < 0)
+ return ret;
+
+ pw_pol = DIV_ROUND_CLOSEST_ULL(max_mW, TPS23881_MW_STEP);
+
+ /* Save power policy to reconfigure it after a disabled call */
+ priv->port[id].pw_pol = pw_pol;
+ return tps23881_pi_set_pw_pol_limit(priv, id, pw_pol,
+ priv->port[id].is_4p);
+}
+
+static int
+tps23881_pi_get_pw_limit_ranges(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_limit_ranges *pw_limit_ranges)
+{
+ struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
+
+ c33_pw_limit_ranges = kzalloc(sizeof(*c33_pw_limit_ranges),
+ GFP_KERNEL);
+ if (!c33_pw_limit_ranges)
+ return -ENOMEM;
+
+ c33_pw_limit_ranges->min = TPS23881_MIN_PI_PW_LIMIT_MW;
+ c33_pw_limit_ranges->max = MAX_PI_PW;
+ pw_limit_ranges->c33_pw_limit_ranges = c33_pw_limit_ranges;
+
+ /* Return the number of ranges */
+ return 1;
+}
+
/* Parse managers subnode into a array of device node */
static int
tps23881_get_of_channels(struct tps23881_priv *priv,
@@ -540,6 +785,9 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
if (port_matrix[i].exist)
priv->port[pi_id].chan[0] = lgcl_chan;
+ /* Initialize power policy internal value */
+ priv->port[pi_id].pw_pol = -1;
+
/* Set hardware port matrix for all ports */
val |= hw_chan << (lgcl_chan * 2);
@@ -665,6 +913,12 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_disable = tps23881_pi_disable,
.pi_get_admin_state = tps23881_pi_get_admin_state,
.pi_get_pw_status = tps23881_pi_get_pw_status,
+ .pi_get_pw_class = tps23881_pi_get_pw_class,
+ .pi_get_actual_pw = tps23881_pi_get_actual_pw,
+ .pi_get_voltage = tps23881_pi_get_voltage,
+ .pi_get_pw_limit = tps23881_pi_get_pw_limit,
+ .pi_set_pw_limit = tps23881_pi_set_pw_limit,
+ .pi_get_pw_limit_ranges = tps23881_pi_get_pw_limit_ranges,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 11/27] net: pse-pd: Add support for PSE device index
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (9 preceding siblings ...)
2025-01-03 21:12 ` [PATCH net-next v4 10/27] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 12/27] net: ethtool: Add support for new PSE device index description Kory Maincent
` (16 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Add support for a PSE device index to report the PSE controller index to
the user through ethtool. This will be useful for future support of power
domains and port priority management.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- Use u32 for all variables.
Changes in v2:
- new patch.
---
drivers/net/pse-pd/pse_core.c | 24 +++++++++++++++++++-----
include/linux/ethtool.h | 2 ++
include/linux/pse-pd/pse.h | 2 ++
3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 887a477197a6..830e8d567d4d 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -13,6 +13,7 @@
static DEFINE_MUTEX(pse_list_mutex);
static LIST_HEAD(pse_controller_list);
+static DEFINE_IDA(pse_ida);
/**
* struct pse_control - a PSE control
@@ -448,6 +449,10 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
mutex_init(&pcdev->lock);
INIT_LIST_HEAD(&pcdev->pse_control_head);
+ ret = ida_alloc_max(&pse_ida, INT_MAX, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+ pcdev->id = ret;
if (!pcdev->nr_lines)
pcdev->nr_lines = 1;
@@ -461,12 +466,12 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
ret = of_load_pse_pis(pcdev);
if (ret)
- return ret;
+ goto free_pse_ida;
if (pcdev->ops->setup_pi_matrix) {
ret = pcdev->ops->setup_pi_matrix(pcdev);
if (ret)
- return ret;
+ goto free_pse_ida;
}
/* Each regulator name len is pcdev dev name + 7 char +
@@ -483,15 +488,17 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
continue;
reg_name = devm_kzalloc(pcdev->dev, reg_name_len, GFP_KERNEL);
- if (!reg_name)
- return -ENOMEM;
+ if (!reg_name) {
+ ret = -ENOMEM;
+ goto free_pse_ida;
+ }
snprintf(reg_name, reg_name_len, "pse-%s_pi%d",
dev_name(pcdev->dev), i);
ret = devm_pse_pi_regulator_register(pcdev, reg_name, i);
if (ret)
- return ret;
+ goto free_pse_ida;
}
mutex_lock(&pse_list_mutex);
@@ -499,6 +506,10 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
mutex_unlock(&pse_list_mutex);
return 0;
+
+free_pse_ida:
+ ida_free(&pse_ida, pcdev->id);
+ return ret;
}
EXPORT_SYMBOL_GPL(pse_controller_register);
@@ -509,6 +520,7 @@ EXPORT_SYMBOL_GPL(pse_controller_register);
void pse_controller_unregister(struct pse_controller_dev *pcdev)
{
pse_release_pis(pcdev);
+ ida_free(&pse_ida, pcdev->id);
mutex_lock(&pse_list_mutex);
list_del(&pcdev->list);
mutex_unlock(&pse_list_mutex);
@@ -771,6 +783,8 @@ int pse_ethtool_get_status(struct pse_control *psec,
pcdev = psec->pcdev;
ops = pcdev->ops;
+ status->pse_id = pcdev->id;
+
mutex_lock(&pcdev->lock);
ret = ops->pi_get_admin_state(pcdev, psec->id, &admin_state);
if (ret)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 2bdf7e72ee50..d5d13a3d4447 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1327,6 +1327,7 @@ struct ethtool_c33_pse_pw_limit_range {
/**
* struct ethtool_pse_control_status - PSE control/channel status.
*
+ * @pse_id: index number of the PSE.
* @podl_admin_state: operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
* @podl_pw_status: power detection status of the PoDL PSE.
@@ -1348,6 +1349,7 @@ struct ethtool_c33_pse_pw_limit_range {
* ranges
*/
struct ethtool_pse_control_status {
+ u32 pse_id;
enum ethtool_podl_pse_admin_state podl_admin_state;
enum ethtool_podl_pse_pw_d_status podl_pw_status;
enum ethtool_c33_pse_admin_state c33_admin_state;
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 09e62d8c3271..8780a4160d3c 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -172,6 +172,7 @@ struct pse_pi {
* @types: types of the PSE controller
* @pi: table of PSE PIs described in this controller device
* @no_of_pse_pi: flag set if the pse_pis devicetree node is not used
+ * @id: Index of the PSE
*/
struct pse_controller_dev {
const struct pse_controller_ops *ops;
@@ -185,6 +186,7 @@ struct pse_controller_dev {
enum ethtool_pse_types types;
struct pse_pi *pi;
bool no_of_pse_pi;
+ u32 id;
};
#if IS_ENABLED(CONFIG_PSE_CONTROLLER)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 12/27] net: ethtool: Add support for new PSE device index description
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (10 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 11/27] net: pse-pd: Add support for PSE device index Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 13/27] net: ethtool: Add support for ethnl_info_init_ntf helper function Kory Maincent
` (15 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Add functionality to report the newly introduced PSE device index to
the user, enabling better identification and management of PSE devices.
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v2:
- new patch.
---
Documentation/netlink/specs/ethtool.yaml | 5 +++++
Documentation/networking/ethtool-netlink.rst | 4 ++++
include/uapi/linux/ethtool_netlink.h | 1 -
include/uapi/linux/ethtool_netlink_generated.h | 1 +
net/ethtool/pse-pd.c | 4 ++++
5 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 60f85fbf4156..cc26a9dfa8f7 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1357,6 +1357,10 @@ attribute-sets:
type: nest
multi-attr: true
nested-attributes: c33-pse-pw-limit
+ -
+ name: pse-id
+ type: u32
+ name-prefix: ethtool-a-
-
name: rss
attr-cnt-name: __ethtool-a-rss-cnt
@@ -2162,6 +2166,7 @@ operations:
- c33-pse-ext-substate
- c33-pse-avail-pw-limit
- c33-pse-pw-limit-ranges
+ - pse-id
dump: *pse-get-op
-
name: pse-set
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index a7ba6368a4d5..6f5a880d8df2 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1771,6 +1771,7 @@ Kernel response contents:
limit of the PoE PSE.
``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested Supported power limit
configuration ranges.
+ ``ETHTOOL_A_PSE_ID`` u32 Index of the PSE
========================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
@@ -1844,6 +1845,9 @@ identifies the C33 PSE power limit ranges through
If the controller works with fixed classes, the min and max values will be
equal.
+The ``ETHTOOL_A_PSE_ID`` attribute identifies the index of the PSE
+controller.
+
PSE_SET
=======
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 9c909ce733a5..335127b895fe 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -193,7 +193,6 @@ enum {
ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1)
};
-
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index 43993a2d68e5..b3c928c71ca3 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -630,6 +630,7 @@ enum {
ETHTOOL_A_C33_PSE_EXT_SUBSTATE,
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT,
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES,
+ ETHTOOL_A_PSE_ID,
__ETHTOOL_A_PSE_CNT,
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 2819e2ba6be2..6cfdfaa47c1c 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -83,6 +83,7 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
const struct ethtool_pse_control_status *st = &data->status;
int len = 0;
+ len += nla_total_size(sizeof(u32)); /* _PSE_ID */
if (st->podl_admin_state > 0)
len += nla_total_size(sizeof(u32)); /* _PODL_PSE_ADMIN_STATE */
if (st->podl_pw_status > 0)
@@ -148,6 +149,9 @@ static int pse_fill_reply(struct sk_buff *skb,
const struct pse_reply_data *data = PSE_REPDATA(reply_base);
const struct ethtool_pse_control_status *st = &data->status;
+ if (nla_put_u32(skb, ETHTOOL_A_PSE_ID, st->pse_id))
+ return -EMSGSIZE;
+
if (st->podl_admin_state > 0 &&
nla_put_u32(skb, ETHTOOL_A_PODL_PSE_ADMIN_STATE,
st->podl_admin_state))
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 13/27] net: ethtool: Add support for ethnl_info_init_ntf helper function
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (11 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 12/27] net: ethtool: Add support for new PSE device index description Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 14/27] net: pse-pd: Add support for reporting events Kory Maincent
` (14 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Introduce support for the ethnl_info_init_ntf helper function to enable
initialization of ethtool notifications outside of the netlink.c file.
This change allows for more flexible notification handling.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v4:
- Use the new helper in ethnl_default_notify function.
Changes in v2:
- new patch.
---
net/ethtool/netlink.c | 7 ++++++-
net/ethtool/netlink.h | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 849c98e637c6..334c98fada49 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -740,7 +740,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
int reply_len;
int ret;
- genl_info_init_ntf(&info, ðtool_genl_family, cmd);
+ ethnl_info_init_ntf(&info, cmd);
if (WARN_ONCE(cmd > ETHTOOL_MSG_KERNEL_MAX ||
!ethnl_default_notify_ops[cmd],
@@ -807,6 +807,11 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
typedef void (*ethnl_notify_handler_t)(struct net_device *dev, unsigned int cmd,
const void *data);
+void ethnl_info_init_ntf(struct genl_info *info, u8 cmd)
+{
+ genl_info_init_ntf(info, ðtool_genl_family, cmd);
+}
+
static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
[ETHTOOL_MSG_LINKINFO_NTF] = ethnl_default_notify,
[ETHTOOL_MSG_LINKMODES_NTF] = ethnl_default_notify,
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 0a09298fff92..1177d84d4eb7 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -322,6 +322,8 @@ struct ethnl_sock_priv {
int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
enum ethnl_sock_type type);
+void ethnl_info_init_ntf(struct genl_info *info, u8 cmd);
+
/**
* struct ethnl_request_ops - unified handling of GET and SET requests
* @request_cmd: command id for request (GET)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 14/27] net: pse-pd: Add support for reporting events
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (12 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 13/27] net: ethtool: Add support for ethnl_info_init_ntf helper function Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 15/27] net: pse-pd: tps23881: Add support for PSE events and interrupts Kory Maincent
` (13 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Add support for devm_pse_irq_helper() to register PSE interrupts. This aims
to report events such as over-current or over-temperature conditions
similarly to how the regulator API handles them but using a specific PSE
ethtool netlink socket.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- Fix netlink notification message issues.
- Use netlink bitset in ethtool_pse_send_ntf.
- Add kdoc.
Change in v3:
- Remove C33 prefix when it is not in the standards.
- Fix pse_to_regulator_notifs which could not report regulator events
together.
- Fix deadlock issue.
- Save interrupt in pcdev structure for later use.
Change in v2:
- Add support for PSE ethtool notification.
- Saved the attached phy_device in the pse_control structure to know which
interface should have the notification.
- Rethink devm_pse_irq_helper() without devm_regulator_irq_helper() call.
---
Documentation/netlink/specs/ethtool.yaml | 26 ++++
Documentation/networking/ethtool-netlink.rst | 19 +++
drivers/net/mdio/fwnode_mdio.c | 26 ++--
drivers/net/pse-pd/pse_core.c | 157 ++++++++++++++++++++++++-
include/linux/ethtool_netlink.h | 9 ++
include/linux/pse-pd/pse.h | 24 +++-
include/uapi/linux/ethtool.h | 17 +++
include/uapi/linux/ethtool_netlink_generated.h | 10 ++
net/ethtool/common.c | 6 +
net/ethtool/common.h | 2 +
net/ethtool/pse-pd.c | 53 +++++++++
net/ethtool/strset.c | 5 +
12 files changed, 337 insertions(+), 17 deletions(-)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index cc26a9dfa8f7..9aa62137166a 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1520,6 +1520,22 @@ attribute-sets:
-
name: hwtstamp-flags
type: u32
+ -
+ name: pse-ntf
+ attr-cnt-name: __ethtool-a-pse-ntf-cnt
+ attributes:
+ -
+ name: unspec
+ type: unused
+ value: 0
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: events
+ type: nest
+ nested-attributes: bitset
operations:
enum-model: directional
@@ -2375,3 +2391,13 @@ operations:
attributes: *tsconfig
reply:
attributes: *tsconfig
+ -
+ name: pse-ntf
+ doc: Notification for pse events.
+
+ attribute-set: pse-ntf
+
+ event:
+ attributes:
+ - header
+ - events
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index 6f5a880d8df2..9d836fa670df 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -290,6 +290,7 @@ Kernel to userspace:
``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change
``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration
``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configuration
+ ``ETHTOOL_MSG_PSE_NTF`` PSE events notification
======================================== =================================
``GET`` requests are sent by userspace applications to retrieve device
@@ -1883,6 +1884,24 @@ various existing products that document power consumption in watts rather than
classes. If power limit configuration based on classes is needed, the
conversion can be done in user space, for example by ethtool.
+PSE_NTF
+=======
+
+Notify PSE events.
+
+Notification contents:
+
+ =============================== ====== ========================
+ ``ETHTOOL_A_PSE_HEADER`` nested request header
+ ``ETHTOOL_A_PSE_EVENTS`` bitset PSE events
+ =============================== ====== ========================
+
+When set, the optional ``ETHTOOL_A_PSE_EVENTS`` attribute identifies the
+PSE events.
+
+.. kernel-doc:: include/uapi/linux/ethtool.h
+ :identifiers: ethtool_pse_events
+
RSS_GET
=======
diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c
index aea0f0357568..9b41d4697a40 100644
--- a/drivers/net/mdio/fwnode_mdio.c
+++ b/drivers/net/mdio/fwnode_mdio.c
@@ -18,7 +18,8 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("FWNODE MDIO bus (Ethernet PHY) accessors");
static struct pse_control *
-fwnode_find_pse_control(struct fwnode_handle *fwnode)
+fwnode_find_pse_control(struct fwnode_handle *fwnode,
+ struct phy_device *phydev)
{
struct pse_control *psec;
struct device_node *np;
@@ -30,7 +31,7 @@ fwnode_find_pse_control(struct fwnode_handle *fwnode)
if (!np)
return NULL;
- psec = of_pse_control_get(np);
+ psec = of_pse_control_get(np, phydev);
if (PTR_ERR(psec) == -ENOENT)
return NULL;
@@ -128,15 +129,9 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
u32 phy_id;
int rc;
- psec = fwnode_find_pse_control(child);
- if (IS_ERR(psec))
- return PTR_ERR(psec);
-
mii_ts = fwnode_find_mii_timestamper(child);
- if (IS_ERR(mii_ts)) {
- rc = PTR_ERR(mii_ts);
- goto clean_pse;
- }
+ if (IS_ERR(mii_ts))
+ return PTR_ERR(mii_ts);
is_c45 = fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45");
if (is_c45 || fwnode_get_phy_id(child, &phy_id))
@@ -169,6 +164,12 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
goto clean_phy;
}
+ psec = fwnode_find_pse_control(child, phy);
+ if (IS_ERR(psec)) {
+ rc = PTR_ERR(psec);
+ goto unregister_phy;
+ }
+
phy->psec = psec;
/* phy->mii_ts may already be defined by the PHY driver. A
@@ -180,12 +181,13 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
return 0;
+unregister_phy:
+ if (is_acpi_node(child) || is_of_node(child))
+ phy_device_remove(phy);
clean_phy:
phy_device_free(phy);
clean_mii_ts:
unregister_mii_timestamper(mii_ts);
-clean_pse:
- pse_control_put(psec);
return rc;
}
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 830e8d567d4d..83689de4a5ab 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -6,6 +6,7 @@
//
#include <linux/device.h>
+#include <linux/ethtool_netlink.h>
#include <linux/of.h>
#include <linux/pse-pd/pse.h>
#include <linux/regulator/driver.h>
@@ -23,6 +24,7 @@ static DEFINE_IDA(pse_ida);
* @list: list entry for the pcdev's PSE controller list
* @id: ID of the PSE line in the PSE controller device
* @refcnt: Number of gets of this pse_control
+ * @attached_phydev: PHY device pointer attached by the PSE control
*/
struct pse_control {
struct pse_controller_dev *pcdev;
@@ -30,6 +32,7 @@ struct pse_control {
struct list_head list;
unsigned int id;
struct kref refcnt;
+ struct phy_device *attached_phydev;
};
static int of_load_single_pse_pi_pairset(struct device_node *node,
@@ -567,6 +570,151 @@ int devm_pse_controller_register(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_pse_controller_register);
+struct pse_irq {
+ struct pse_controller_dev *pcdev;
+ struct pse_irq_desc desc;
+ unsigned long *notifs;
+};
+
+/**
+ * pse_to_regulator_notifs - Convert PSE notifications to Regulator
+ * notifications
+ * @notifs: PSE notifications
+ *
+ * Return: Regulator notifications
+ */
+static unsigned long pse_to_regulator_notifs(unsigned long notifs)
+{
+ unsigned long rnotifs = 0;
+
+ if (notifs & ETHTOOL_PSE_EVENT_OVER_CURRENT)
+ rnotifs |= REGULATOR_EVENT_OVER_CURRENT;
+ if (notifs & ETHTOOL_PSE_EVENT_OVER_TEMP)
+ rnotifs |= REGULATOR_EVENT_OVER_TEMP;
+
+ return rnotifs;
+}
+
+/**
+ * pse_control_find_phy_by_id - Find PHY attached to the a pse control id
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE control
+ *
+ * Return: PHY device pointer or NULL
+ */
+static struct phy_device *
+pse_control_find_phy_by_id(struct pse_controller_dev *pcdev, int id)
+{
+ struct pse_control *psec;
+
+ mutex_lock(&pse_list_mutex);
+ list_for_each_entry(psec, &pcdev->pse_control_head, list) {
+ if (psec->id == id) {
+ mutex_unlock(&pse_list_mutex);
+ return psec->attached_phydev;
+ }
+ }
+ mutex_unlock(&pse_list_mutex);
+
+ return NULL;
+}
+
+/**
+ * pse_isr - IRQ handler for PSE
+ * @irq: irq number
+ * @data: pointer to user interrupt structure
+ *
+ * Return: irqreturn_t - status of IRQ
+ */
+static irqreturn_t pse_isr(int irq, void *data)
+{
+ struct netlink_ext_ack extack = {};
+ struct pse_controller_dev *pcdev;
+ unsigned long notifs_mask = 0;
+ struct pse_irq_desc *desc;
+ struct pse_irq *h = data;
+ int ret, i;
+
+ desc = &h->desc;
+ pcdev = h->pcdev;
+
+ /* Clear notifs mask */
+ memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
+ mutex_lock(&pcdev->lock);
+ ret = desc->map_event(irq, pcdev, h->notifs, ¬ifs_mask);
+ mutex_unlock(&pcdev->lock);
+ if (ret || !notifs_mask)
+ return IRQ_NONE;
+
+ for_each_set_bit(i, ¬ifs_mask, pcdev->nr_lines) {
+ struct phy_device *phydev;
+ unsigned long notifs, rnotifs;
+
+ /* Do nothing PI not described */
+ if (!pcdev->pi[i].rdev)
+ continue;
+
+ notifs = h->notifs[i];
+ dev_dbg(h->pcdev->dev,
+ "Sending PSE notification EVT 0x%lx\n", notifs);
+
+ phydev = pse_control_find_phy_by_id(pcdev, i);
+ if (phydev)
+ ethnl_pse_send_ntf(phydev, notifs, &extack);
+ rnotifs = pse_to_regulator_notifs(notifs);
+ regulator_notifier_call_chain(pcdev->pi[i].rdev, rnotifs,
+ NULL);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * devm_pse_irq_helper - Register IRQ based PSE event notifier
+ *
+ * @pcdev: a pointer to the PSE
+ * @irq: the irq value to be passed to request_irq
+ * @irq_flags: the flags to be passed to request_irq
+ * @d: PSE interrupt description
+ *
+ * Return: 0 on success and failure value on error
+ */
+int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
+ int irq_flags, const struct pse_irq_desc *d)
+{
+ struct device *dev = pcdev->dev;
+ struct pse_irq *h;
+ int ret;
+
+ if (!d || !d->map_event || !d->name)
+ return -EINVAL;
+
+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ h->pcdev = pcdev;
+ h->desc = *d;
+ h->desc.name = devm_kstrdup(dev, d->name, GFP_KERNEL);
+ if (!h->desc.name)
+ return -ENOMEM;
+
+ h->notifs = devm_kcalloc(pcdev->dev, pcdev->nr_lines,
+ sizeof(*h->notifs), GFP_KERNEL);
+ if (!h->notifs)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, pse_isr,
+ IRQF_ONESHOT | irq_flags,
+ h->desc.name, h);
+ if (ret)
+ dev_err(pcdev->dev, "Failed to request IRQ %d\n", irq);
+
+ pcdev->irq = irq;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_pse_irq_helper);
+
/* PSE control section */
static void __pse_control_release(struct kref *kref)
@@ -609,7 +757,8 @@ void pse_control_put(struct pse_control *psec)
EXPORT_SYMBOL_GPL(pse_control_put);
static struct pse_control *
-pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index)
+pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
+ struct phy_device *phydev)
{
struct pse_control *psec;
int ret;
@@ -648,6 +797,7 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index)
psec->pcdev = pcdev;
list_add(&psec->list, &pcdev->pse_control_head);
psec->id = index;
+ psec->attached_phydev = phydev;
kref_init(&psec->refcnt);
return psec;
@@ -703,7 +853,8 @@ static int psec_id_xlate(struct pse_controller_dev *pcdev,
return pse_spec->args[0];
}
-struct pse_control *of_pse_control_get(struct device_node *node)
+struct pse_control *of_pse_control_get(struct device_node *node,
+ struct phy_device *phydev)
{
struct pse_controller_dev *r, *pcdev;
struct of_phandle_args args;
@@ -753,7 +904,7 @@ struct pse_control *of_pse_control_get(struct device_node *node)
}
/* pse_list_mutex also protects the pcdev's pse_control list */
- psec = pse_control_get_internal(pcdev, psec_id);
+ psec = pse_control_get_internal(pcdev, psec_id, phydev);
out:
mutex_unlock(&pse_list_mutex);
diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
index aba91335273a..0fa1d8f59cf2 100644
--- a/include/linux/ethtool_netlink.h
+++ b/include/linux/ethtool_netlink.h
@@ -43,6 +43,9 @@ void ethtool_aggregate_rmon_stats(struct net_device *dev,
struct ethtool_rmon_stats *rmon_stats);
bool ethtool_dev_mm_supported(struct net_device *dev);
+void ethnl_pse_send_ntf(struct phy_device *phydev, unsigned long notif,
+ struct netlink_ext_ack *extack);
+
#else
static inline int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
{
@@ -120,6 +123,12 @@ static inline bool ethtool_dev_mm_supported(struct net_device *dev)
return false;
}
+static inline void ethnl_pse_send_ntf(struct phy_device *phydev,
+ unsigned long notif,
+ struct netlink_ext_ack *extack)
+{
+}
+
#endif /* IS_ENABLED(CONFIG_ETHTOOL_NETLINK) */
static inline int ethnl_cable_test_result(struct phy_device *phydev, u8 pair,
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 8780a4160d3c..b3f8d198c5a7 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -8,6 +8,7 @@
#include <linux/ethtool.h>
#include <linux/list.h>
#include <uapi/linux/ethtool.h>
+#include <linux/regulator/driver.h>
/* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
#define MAX_PI_CURRENT 1920000
@@ -17,6 +18,19 @@
struct phy_device;
struct pse_controller_dev;
+/**
+ * struct pse_irq_desc - notification sender description for IRQ based events.
+ *
+ * @name: the visible name for the IRQ
+ * @map_event: driver callback to map IRQ status into PSE devices with events.
+ */
+struct pse_irq_desc {
+ const char *name;
+ int (*map_event)(int irq, struct pse_controller_dev *pcdev,
+ unsigned long *notifs,
+ unsigned long *notifs_mask);
+};
+
/**
* struct pse_control_config - PSE control/channel configuration.
*
@@ -173,6 +187,7 @@ struct pse_pi {
* @pi: table of PSE PIs described in this controller device
* @no_of_pse_pi: flag set if the pse_pis devicetree node is not used
* @id: Index of the PSE
+ * @irq: PSE interrupt
*/
struct pse_controller_dev {
const struct pse_controller_ops *ops;
@@ -187,6 +202,7 @@ struct pse_controller_dev {
struct pse_pi *pi;
bool no_of_pse_pi;
u32 id;
+ int irq;
};
#if IS_ENABLED(CONFIG_PSE_CONTROLLER)
@@ -195,8 +211,11 @@ void pse_controller_unregister(struct pse_controller_dev *pcdev);
struct device;
int devm_pse_controller_register(struct device *dev,
struct pse_controller_dev *pcdev);
+int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
+ int irq_flags, const struct pse_irq_desc *d);
-struct pse_control *of_pse_control_get(struct device_node *node);
+struct pse_control *of_pse_control_get(struct device_node *node,
+ struct phy_device *phydev);
void pse_control_put(struct pse_control *psec);
int pse_ethtool_get_status(struct pse_control *psec,
@@ -214,7 +233,8 @@ bool pse_has_c33(struct pse_control *psec);
#else
-static inline struct pse_control *of_pse_control_get(struct device_node *node)
+static inline struct pse_control *of_pse_control_get(struct device_node *node,
+ struct phy_device *phydev)
{
return ERR_PTR(-ENOENT);
}
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 7e1b3820f91f..33c8dc6c9ef6 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -681,6 +681,7 @@ enum ethtool_link_ext_substate_module {
* @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
* @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
* @ETH_SS_STATS_RMON: names of RMON statistics
+ * @ETH_SS_PSE_EVENTS: names of PSE events
*
* @ETH_SS_COUNT: number of defined string sets
*/
@@ -706,6 +707,7 @@ enum ethtool_stringset {
ETH_SS_STATS_ETH_MAC,
ETH_SS_STATS_ETH_CTRL,
ETH_SS_STATS_RMON,
+ ETH_SS_PSE_EVENTS,
/* add new constants above here */
ETH_SS_COUNT
@@ -998,6 +1000,21 @@ enum ethtool_c33_pse_pw_d_status {
ETHTOOL_C33_PSE_PW_D_STATUS_OTHERFAULT,
};
+/**
+ * enum ethtool_pse_events - event list of the PSE controller.
+ * @ETHTOOL_PSE_EVENT_OVER_CURRENT: PSE output current is too high.
+ * @ETHTOOL_PSE_EVENT_OVER_TEMP: PSE in over temperature state.
+ *
+ * @ETHTOOL_PSE_EVENT_LAST: Last PSE event of the enum.
+ */
+
+enum ethtool_pse_events {
+ ETHTOOL_PSE_EVENT_OVER_CURRENT = 1 << 0,
+ ETHTOOL_PSE_EVENT_OVER_TEMP = 1 << 1,
+
+ ETHTOOL_PSE_EVENT_LAST = ETHTOOL_PSE_EVENT_OVER_TEMP,
+};
+
/**
* enum ethtool_podl_pse_admin_state - operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index b3c928c71ca3..7293592fd689 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -707,6 +707,15 @@ enum {
ETHTOOL_A_TSCONFIG_MAX = (__ETHTOOL_A_TSCONFIG_CNT - 1)
};
+enum {
+ ETHTOOL_A_PSE_NTF_UNSPEC,
+ ETHTOOL_A_PSE_NTF_HEADER,
+ ETHTOOL_A_PSE_NTF_EVENTS,
+
+ __ETHTOOL_A_PSE_NTF_CNT,
+ ETHTOOL_A_PSE_NTF_MAX = (__ETHTOOL_A_PSE_NTF_CNT - 1)
+};
+
enum {
ETHTOOL_MSG_USER_NONE = 0,
ETHTOOL_MSG_STRSET_GET = 1,
@@ -811,6 +820,7 @@ enum {
ETHTOOL_MSG_PHY_NTF,
ETHTOOL_MSG_TSCONFIG_GET_REPLY,
ETHTOOL_MSG_TSCONFIG_SET_REPLY,
+ ETHTOOL_MSG_PSE_NTF,
__ETHTOOL_MSG_KERNEL_CNT,
ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 2607aea1fbfb..d50b8292debd 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -470,6 +470,12 @@ const char udp_tunnel_type_names[][ETH_GSTRING_LEN] = {
static_assert(ARRAY_SIZE(udp_tunnel_type_names) ==
__ETHTOOL_UDP_TUNNEL_TYPE_CNT);
+const char pse_event_names[][ETH_GSTRING_LEN] = {
+ [const_ilog2(ETHTOOL_PSE_EVENT_OVER_CURRENT)] = "over-current",
+ [const_ilog2(ETHTOOL_PSE_EVENT_OVER_TEMP)] = "over-temperature",
+};
+static_assert(ARRAY_SIZE(pse_event_names) == __PSE_EVENT_CNT);
+
/* return false if legacy contained non-0 deprecated fields
* maxtxpkt/maxrxpkt. rest of ksettings always updated
*/
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 850eadde4bfc..9f28e55a5040 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -13,6 +13,7 @@
ETHTOOL_LINK_MODE_ ## speed ## base ## type ## _ ## duplex ## _BIT
#define __SOF_TIMESTAMPING_CNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1)
+#define __PSE_EVENT_CNT (const_ilog2(ETHTOOL_PSE_EVENT_LAST) + 1)
struct link_mode_info {
int speed;
@@ -39,6 +40,7 @@ extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
extern const char ts_tx_type_names[][ETH_GSTRING_LEN];
extern const char ts_rx_filter_names[][ETH_GSTRING_LEN];
extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN];
+extern const char pse_event_names[][ETH_GSTRING_LEN];
int __ethtool_get_link(struct net_device *dev);
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 6cfdfaa47c1c..bbc9ae910e02 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -12,6 +12,7 @@
#include <linux/ethtool_netlink.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
+#include "bitset.h"
struct pse_req_info {
struct ethnl_req_info base;
@@ -319,3 +320,55 @@ const struct ethnl_request_ops ethnl_pse_request_ops = {
.set = ethnl_set_pse,
/* PSE has no notification */
};
+
+void ethnl_pse_send_ntf(struct phy_device *phydev, unsigned long notifs,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *netdev = phydev->attached_dev;
+ struct genl_info info;
+ void *reply_payload;
+ struct sk_buff *skb;
+ int reply_len;
+ int ret;
+
+ if (!netdev || !notifs)
+ return;
+
+ ethnl_info_init_ntf(&info, ETHTOOL_MSG_PSE_NTF);
+ info.extack = extack;
+
+ reply_len = ethnl_reply_header_size();
+ /* _C33_PSE_NTF_EVENTS */
+ ret = ethnl_bitset_size(¬ifs, NULL, __PSE_EVENT_CNT,
+ pse_event_names, 0);
+ if (ret < 0)
+ return;
+
+ reply_len += ret;
+ skb = genlmsg_new(reply_len, GFP_KERNEL);
+ reply_payload = ethnl_bcastmsg_put(skb, ETHTOOL_MSG_PSE_NTF);
+ if (!reply_payload)
+ goto err_skb;
+
+ ret = ethnl_fill_reply_header(skb, netdev,
+ ETHTOOL_A_PSE_NTF_HEADER);
+ if (ret < 0)
+ goto err_skb;
+
+ ret = ethnl_put_bitset(skb, ETHTOOL_A_PSE_NTF_EVENTS, ¬ifs,
+ NULL, __PSE_EVENT_CNT, pse_event_names, 0);
+ if (ret) {
+ WARN_ONCE(ret == -EMSGSIZE,
+ "calculated message payload length (%d) not sufficient\n",
+ reply_len);
+ goto err_skb;
+ }
+
+ genlmsg_end(skb, reply_payload);
+ ethnl_multicast(skb, netdev);
+ return;
+
+err_skb:
+ nlmsg_free(skb);
+}
+EXPORT_SYMBOL_GPL(ethnl_pse_send_ntf);
diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c
index b3382b3cf325..8f81e05107f3 100644
--- a/net/ethtool/strset.c
+++ b/net/ethtool/strset.c
@@ -105,6 +105,11 @@ static const struct strset_info info_template[] = {
.count = __ETHTOOL_A_STATS_RMON_CNT,
.strings = stats_rmon_names,
},
+ [ETH_SS_PSE_EVENTS] = {
+ .per_dev = false,
+ .count = __PSE_EVENT_CNT,
+ .strings = pse_event_names,
+ },
};
struct strset_req_info {
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 15/27] net: pse-pd: tps23881: Add support for PSE events and interrupts
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (13 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 14/27] net: pse-pd: Add support for reporting events Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 16/27] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
` (12 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Add support for PSE event reporting through interrupts. Set up the newly
introduced devm_pse_irq_helper helper to register the interrupt. Events are
reported for over-current and over-temperature conditions.
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- Small rename of a function.
Change in v3:
- Loop over interruption register to be sure the interruption pin is
freed before exiting the interrupt handler function.
- Add exist variable to not report event for undescribed PIs.
- Used helpers to convert the chan number to the PI port number.
Change in v2:
- Remove support for OSS pin and TPC23881 specific port priority management
---
drivers/net/pse-pd/tps23881.c | 178 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 1 deletion(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 5e9dda2c0eac..122666719297 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -17,6 +17,13 @@
#define TPS23881_MAX_CHANS 8
+#define TPS23881_REG_IT 0x0
+#define TPS23881_REG_IT_MASK 0x1
+#define TPS23881_REG_IT_IFAULT BIT(5)
+#define TPS23881_REG_IT_SUPF BIT(7)
+#define TPS23881_REG_FAULT 0x7
+#define TPS23881_REG_SUPF_EVENT 0xb
+#define TPS23881_REG_TSD BIT(7)
#define TPS23881_REG_PW_STATUS 0x10
#define TPS23881_REG_OP_MODE 0x12
#define TPS23881_OP_MODE_SEMIAUTO 0xaaaa
@@ -24,6 +31,7 @@
#define TPS23881_REG_DET_CLA_EN 0x14
#define TPS23881_REG_GEN_MASK 0x17
#define TPS23881_REG_NBITACC BIT(5)
+#define TPS23881_REG_INTEN BIT(7)
#define TPS23881_REG_PW_EN 0x19
#define TPS23881_REG_2PAIR_POL1 0x1e
#define TPS23881_REG_PORT_MAP 0x26
@@ -51,6 +59,7 @@ struct tps23881_port_desc {
u8 chan[2];
bool is_4p;
int pw_pol;
+ bool exist;
};
struct tps23881_priv {
@@ -782,8 +791,10 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
hw_chan = port_matrix[i].hw_chan[0] % 4;
/* Set software port matrix for existing ports */
- if (port_matrix[i].exist)
+ if (port_matrix[i].exist) {
priv->port[pi_id].chan[0] = lgcl_chan;
+ priv->port[pi_id].exist = true;
+ }
/* Initialize power policy internal value */
priv->port[pi_id].pw_pol = -1;
@@ -1017,6 +1028,165 @@ static int tps23881_flash_sram_fw(struct i2c_client *client)
return 0;
}
+/* Convert interrupt events to 0xff to be aligned with the chan
+ * number.
+ */
+static u8 tps23881_irq_export_chans_helper(u16 reg_val, u8 field_offset)
+{
+ u8 val;
+
+ val = (reg_val >> (4 + field_offset) & 0xf0) |
+ (reg_val >> field_offset & 0x0f);
+
+ return val;
+}
+
+/* Convert chan number to port number */
+static void tps23881_set_notifs_helper(struct tps23881_priv *priv,
+ u8 chans,
+ unsigned long *notifs,
+ unsigned long *notifs_mask,
+ enum ethtool_pse_events event)
+{
+ u8 chan;
+ int i;
+
+ if (!chans)
+ return;
+
+ for (i = 0; i < TPS23881_MAX_CHANS; i++) {
+ if (!priv->port[i].exist)
+ continue;
+ /* No need to look at the 2nd channel in case of PoE4 as
+ * both registers are set.
+ */
+ chan = priv->port[i].chan[0];
+
+ if (BIT(chan) & chans) {
+ *notifs_mask |= BIT(i);
+ notifs[i] |= event;
+ }
+ }
+}
+
+static void tps23881_irq_event_over_temp(struct tps23881_priv *priv,
+ u16 reg_val,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ int i;
+
+ if (reg_val & TPS23881_REG_TSD) {
+ for (i = 0; i < TPS23881_MAX_CHANS; i++) {
+ if (!priv->port[i].exist)
+ continue;
+
+ *notifs_mask |= BIT(i);
+ notifs[i] |= ETHTOOL_PSE_EVENT_OVER_TEMP;
+ }
+ }
+}
+
+static void tps23881_irq_event_over_current(struct tps23881_priv *priv,
+ u16 reg_val,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ u8 chans;
+
+ chans = tps23881_irq_export_chans_helper(reg_val, 0);
+ if (chans)
+ tps23881_set_notifs_helper(priv, chans, notifs, notifs_mask,
+ ETHTOOL_PSE_EVENT_OVER_CURRENT);
+}
+
+static int tps23881_irq_event_handler(struct tps23881_priv *priv, u16 reg,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ struct i2c_client *client = priv->client;
+ int ret;
+
+ /* The Supply event bit is repeated twice so we only need to read
+ * the one from the first byte.
+ */
+ if (reg & TPS23881_REG_IT_SUPF) {
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_SUPF_EVENT);
+ if (ret < 0)
+ return ret;
+ tps23881_irq_event_over_temp(priv, ret, notifs, notifs_mask);
+ }
+
+ if (reg & (TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_IFAULT << 8)) {
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_FAULT);
+ if (ret < 0)
+ return ret;
+ tps23881_irq_event_over_current(priv, ret, notifs, notifs_mask);
+ }
+
+ return 0;
+}
+
+static int tps23881_irq_handler(int irq, struct pse_controller_dev *pcdev,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ int ret, it_mask;
+
+ /* Get interruption mask */
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_IT_MASK);
+ if (ret < 0)
+ return ret;
+ it_mask = ret;
+
+ /* Read interrupt register until it frees the interruption pin. */
+ while (true) {
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_IT);
+ if (ret < 0)
+ return ret;
+
+ /* No more relevant interruption */
+ if (!(ret & it_mask))
+ return 0;
+
+ ret = tps23881_irq_event_handler(priv, (u16)ret, notifs,
+ notifs_mask);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int tps23881_setup_irq(struct tps23881_priv *priv, int irq)
+{
+ struct i2c_client *client = priv->client;
+ struct pse_irq_desc irq_desc = {
+ .name = "tps23881-irq",
+ .map_event = tps23881_irq_handler,
+ };
+ int ret;
+ u16 val;
+
+ val = TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_SUPF;
+ val |= val << 8;
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_IT_MASK, val);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_GEN_MASK);
+ if (ret < 0)
+ return ret;
+
+ val = (u16)(ret | TPS23881_REG_INTEN | TPS23881_REG_INTEN << 8);
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_GEN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return devm_pse_irq_helper(&priv->pcdev, irq, 0, &irq_desc);
+}
+
static int tps23881_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -1097,6 +1267,12 @@ static int tps23881_i2c_probe(struct i2c_client *client)
"failed to register PSE controller\n");
}
+ if (client->irq) {
+ ret = tps23881_setup_irq(priv, client->irq);
+ if (ret)
+ return ret;
+ }
+
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 16/27] regulator: core: Resolve supply using of_node from regulator_config
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (14 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 15/27] net: pse-pd: tps23881: Add support for PSE events and interrupts Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 17/27] regulator: Add support for power budget description Kory Maincent
` (11 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Previously, the regulator core resolved its supply only from the parent
device or its children, ignoring the of_node specified in the
regulator_config structure.
This behavior causes issues in scenarios where multiple regulator devices
are registered for components described as children of a controller, each
with their own specific regulator supply.
For instance, in a PSE controller with multiple PIs (Power Interfaces),
each PI may have a distinct regulator supply. However, the regulator core
would incorrectly use the PSE controller node or its first child to look up
the regulator supply, rather than the node specified by the
regulator_config->of_node for the PI.
This update modifies the behavior to prioritize the of_node in
regulator_config for resolving the supply. This ensures correct resolution
of the power supply for each device. If no supply is found in the provided
of_node, the core falls back to searching within the parent device as
before.
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
It is weird that it wasn't seen before, maybe there was not any case
were it can't find the supply_name from the parent device.
Changes in v4:
- Remove dev.of_node double check.
Changes in v3:
- New patch
---
drivers/regulator/core.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8cb948a91e60..c092b78c5f12 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1936,6 +1936,20 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
return dev ? dev_to_rdev(dev) : NULL;
}
+static struct regulator_dev *regulator_dt_lookup(struct device *dev,
+ const char *supply)
+{
+ struct regulator_dev *r = NULL;
+
+ if (dev_of_node(dev)) {
+ r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
+ if (PTR_ERR(r) == -ENODEV)
+ r = NULL;
+ }
+
+ return r;
+}
+
/**
* regulator_dev_lookup - lookup a regulator device.
* @dev: device for regulator "consumer".
@@ -1960,16 +1974,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
regulator_supply_alias(&dev, &supply);
/* first do a dt based lookup */
- if (dev_of_node(dev)) {
- r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
- if (!IS_ERR(r))
- return r;
- if (PTR_ERR(r) == -EPROBE_DEFER)
- return r;
-
- if (PTR_ERR(r) == -ENODEV)
- r = NULL;
- }
+ r = regulator_dt_lookup(dev, supply);
+ if (r)
+ return r;
/* if not found, try doing it non-dt way */
if (dev)
@@ -2015,7 +2022,17 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (rdev->supply)
return 0;
- r = regulator_dev_lookup(dev, rdev->supply_name);
+ /* first do a dt based lookup on the node described in the virtual
+ * device.
+ */
+ r = regulator_dt_lookup(&rdev->dev, rdev->supply_name);
+
+ /* If regulator not found use usual search path in the parent
+ * device.
+ */
+ if (!r)
+ r = regulator_dev_lookup(dev, rdev->supply_name);
+
if (IS_ERR(r)) {
ret = PTR_ERR(r);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 17/27] regulator: Add support for power budget description
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (15 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 16/27] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
` (10 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
In preparation for future support of PSE port priority and power
management, we need the power budget value of the power supply.
This addition allows the regulator to track the available power
capacity, which will be essential for prioritizing ports when
making power allocation decisions.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v4:
- Add mW unit at the end of power variables.
Changes in v3:
- Add management of available power.
Changes in v2:
- new patch.
---
drivers/regulator/core.c | 89 ++++++++++++++++++++++++++++++++++++++
drivers/regulator/of_regulator.c | 3 ++
include/linux/regulator/consumer.h | 21 +++++++++
include/linux/regulator/driver.h | 2 +
include/linux/regulator/machine.h | 2 +
5 files changed, 117 insertions(+)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c092b78c5f12..c86092220b70 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -917,6 +917,15 @@ static ssize_t bypass_show(struct device *dev,
}
static DEVICE_ATTR_RO(bypass);
+static ssize_t power_budget_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", rdev->pw_available_mW);
+}
+static DEVICE_ATTR_RO(power_budget);
+
#define REGULATOR_ERROR_ATTR(name, bit) \
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -1149,6 +1158,10 @@ static void print_constraints_debug(struct regulator_dev *rdev)
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
count += scnprintf(buf + count, len - count, "standby ");
+ if (constraints->pw_budget_mW)
+ count += scnprintf(buf + count, len - count, "%d mW budget",
+ constraints->pw_budget_mW);
+
if (!count)
count = scnprintf(buf, len, "no parameters");
else
@@ -1627,6 +1640,13 @@ static int set_machine_constraints(struct regulator_dev *rdev)
rdev->last_off = ktime_get();
}
+ if (rdev->constraints->pw_budget_mW)
+ rdev->pw_available_mW = rdev->constraints->pw_budget_mW;
+ else if (rdev->supply)
+ rdev->pw_available_mW = regulator_get_power_budget(rdev->supply);
+ else
+ rdev->pw_available_mW = INT_MAX;
+
print_constraints(rdev);
return 0;
}
@@ -4601,6 +4621,71 @@ int regulator_get_current_limit(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(regulator_get_current_limit);
+/**
+ * regulator_get_power_budget - get regulator total power budget
+ * @regulator: regulator source
+ *
+ * Return: Power budget of the regulator in mW.
+ */
+int regulator_get_power_budget(struct regulator *regulator)
+{
+ return regulator->rdev->pw_available_mW;
+}
+EXPORT_SYMBOL_GPL(regulator_get_power_budget);
+
+/**
+ * regulator_request_power_budget - request power budget on a regulator
+ * @regulator: regulator source
+ * @pw_req: Power requested
+ *
+ * Return: 0 on success or a negative error number on failure.
+ */
+int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret = 0;
+
+ regulator_lock(rdev);
+ if (rdev->supply) {
+ ret = regulator_request_power_budget(rdev->supply, pw_req);
+ if (ret < 0)
+ goto out;
+ }
+ if (pw_req > rdev->pw_available_mW) {
+ rdev_dbg(rdev, "power requested %d mW out of budget %d mW",
+ pw_req, rdev->pw_available_mW);
+ ret = -ERANGE;
+ goto out;
+ }
+
+ rdev->pw_available_mW -= pw_req;
+out:
+ regulator_unlock(rdev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_request_power_budget);
+
+/**
+ * regulator_free_power_budget - free power budget on a regulator
+ * @regulator: regulator source
+ * @pw: Power to be released.
+ *
+ * Return: Power budget of the regulator in mW.
+ */
+void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+
+ regulator_lock(rdev);
+ if (rdev->supply)
+ regulator_free_power_budget(rdev->supply, pw);
+ rdev->pw_available_mW += pw;
+ regulator_unlock(rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_free_power_budget);
+
/**
* regulator_set_mode - set regulator operating mode
* @regulator: regulator source
@@ -5239,6 +5324,7 @@ static struct attribute *regulator_dev_attrs[] = {
&dev_attr_suspend_standby_mode.attr,
&dev_attr_suspend_mem_mode.attr,
&dev_attr_suspend_disk_mode.attr,
+ &dev_attr_power_budget.attr,
NULL
};
@@ -5320,6 +5406,9 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
attr == &dev_attr_suspend_disk_mode.attr)
return ops->set_suspend_mode ? mode : 0;
+ if (attr == &dev_attr_power_budget.attr)
+ return rdev->pw_available_mW != INT_MAX ? mode : 0;
+
return mode;
}
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 3d85762beda6..129a8c4ff62a 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev,
if (constraints->min_uA != constraints->max_uA)
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
+ if (!of_property_read_u32(np, "regulator-power-budget-miniwatt", &pval))
+ constraints->pw_budget_mW = pval;
+
constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
constraints->always_on = of_property_read_bool(np, "regulator-always-on");
if (!constraints->always_on) /* status change should be possible. */
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 8c3c372ad735..8598078c36d1 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -258,6 +258,11 @@ int regulator_sync_voltage(struct regulator *regulator);
int regulator_set_current_limit(struct regulator *regulator,
int min_uA, int max_uA);
int regulator_get_current_limit(struct regulator *regulator);
+int regulator_get_power_budget(struct regulator *regulator);
+int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req);
+void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw);
int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator);
@@ -571,6 +576,22 @@ static inline int regulator_get_current_limit(struct regulator *regulator)
return 0;
}
+static inline int regulator_get_power_budget(struct regulator *regulator)
+{
+ return INT_MAX;
+}
+
+static inline int regulator_request_power_budget(struct regulator *regulator,
+ unsigned int pw_req)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void regulator_free_power_budget(struct regulator *regulator,
+ unsigned int pw)
+{
+}
+
static inline int regulator_set_mode(struct regulator *regulator,
unsigned int mode)
{
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 5b66caf1695d..9e436b4d7c4c 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -656,6 +656,8 @@ struct regulator_dev {
int cached_err;
bool use_cached_err;
spinlock_t err_lock;
+
+ int pw_available_mW;
};
/*
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index b3db09a7429b..1fc440c5c4c7 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -113,6 +113,7 @@ struct notification_limit {
* @min_uA: Smallest current consumers may set.
* @max_uA: Largest current consumers may set.
* @ilim_uA: Maximum input current.
+ * @pw_budget_mW: Power budget for the regulator in mW.
* @system_load: Load that isn't captured by any consumer requests.
*
* @over_curr_limits: Limits for acting on over current.
@@ -185,6 +186,7 @@ struct regulation_constraints {
int max_uA;
int ilim_uA;
+ int pw_budget_mW;
int system_load;
/* used for coupled regulators */
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (16 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 17/27] regulator: Add support for power budget description Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-04 9:42 ` Krzysztof Kozlowski
2025-01-04 9:43 ` Krzysztof Kozlowski
2025-01-03 21:13 ` [PATCH net-next v4 19/27] net: pse-pd: Fix missing PI of_node description Kory Maincent
` (9 subsequent siblings)
27 siblings, 2 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Introduce a new property to describe the power budget of the regulator.
This property will allow power management support for regulator consumers
like PSE controllers, enabling them to make decisions based on the
available power capacity.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- Add type.
- Add unit in the name.
Changes in v2:
- new patch.
---
Documentation/devicetree/bindings/regulator/regulator.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 1ef380d1515e..c5a6b24ebe7b 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -34,6 +34,11 @@ properties:
regulator-input-current-limit-microamp:
description: maximum input current regulator allows
+ regulator-power-budget-miniwatt:
+ description: power budget of the regulator
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+
regulator-always-on:
description: boolean, regulator should never be disabled
type: boolean
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 19/27] net: pse-pd: Fix missing PI of_node description
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (17 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 20/27] net: pse-pd: Add support for PSE power domains Kory Maincent
` (8 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
The PI of_node was not assigned in the regulator_config structure, leading
to failures in resolving the correct supply when different power supplies
are assigned to multiple PIs of a PSE controller. This fix ensures that the
of_node is properly set in the regulator_config, allowing accurate supply
resolution for each PI.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- New patch
---
drivers/net/pse-pd/pse_core.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 83689de4a5ab..1da974fb83a2 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -426,6 +426,7 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
rconfig.dev = pcdev->dev;
rconfig.driver_data = pcdev;
rconfig.init_data = rinit_data;
+ rconfig.of_node = pcdev->pi[id].np;
rdev = devm_regulator_register(pcdev->dev, rdesc, &rconfig);
if (IS_ERR(rdev)) {
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 20/27] net: pse-pd: Add support for PSE power domains
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (18 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 19/27] net: pse-pd: Fix missing PI of_node description Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 21/27] net: ethtool: Add support for new power domains index description Kory Maincent
` (7 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Introduce PSE power domain support as groundwork for upcoming port
priority features. Multiple PSE PIs can now be grouped under a single
PSE power domain, enabling future enhancements like defining available
power budgets, port priority modes, and disconnection policies. This
setup will allow the system to assess whether activating a port would
exceed the available power budget, preventing over-budget states
proactively.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v4:
- Add kdoc.
- Fix null dereference in pse_flush_pw_ds function.
Changes in v3:
- Remove pw_budget variable.
Changes in v2:
- new patch.
---
drivers/net/pse-pd/pse_core.c | 114 ++++++++++++++++++++++++++++++++++++++++++
include/linux/pse-pd/pse.h | 2 +
2 files changed, 116 insertions(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 1da974fb83a2..6bfe0fca90b4 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -15,6 +15,7 @@
static DEFINE_MUTEX(pse_list_mutex);
static LIST_HEAD(pse_controller_list);
static DEFINE_IDA(pse_ida);
+static DEFINE_XARRAY_ALLOC(pse_pw_d_map);
/**
* struct pse_control - a PSE control
@@ -35,6 +36,16 @@ struct pse_control {
struct phy_device *attached_phydev;
};
+/**
+ * struct pse_power_domain - a PSE power domain
+ * @id: ID of the power domain
+ * @supply: Power supply the Power Domain
+ */
+struct pse_power_domain {
+ int id;
+ struct regulator *supply;
+};
+
static int of_load_single_pse_pi_pairset(struct device_node *node,
struct pse_pi *pi,
int pairset_num)
@@ -440,6 +451,103 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
return 0;
}
+/**
+ * pse_flush_pw_ds - flush all PSE power domains of a PSE
+ * @pcdev: a pointer to the initialized PSE controller device
+ */
+static void pse_flush_pw_ds(struct pse_controller_dev *pcdev)
+{
+ struct pse_power_domain *pw_d;
+ int i;
+
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ if (!pcdev->pi[i].pw_d)
+ continue;
+
+ pw_d = xa_load(&pse_pw_d_map, pcdev->pi[i].pw_d->id);
+ if (pw_d) {
+ regulator_put(pw_d->supply);
+ xa_erase(&pse_pw_d_map, pw_d->id);
+ }
+ }
+}
+
+/**
+ * devm_pse_alloc_pw_d - allocate a new PSE power domain for a device
+ * @dev: device that is registering this PSE power domain
+ *
+ * Return: Pointer to the newly allocated PSE power domain or error pointers
+ */
+static struct pse_power_domain *devm_pse_alloc_pw_d(struct device *dev)
+{
+ struct pse_power_domain *pw_d;
+ int index, ret;
+
+ pw_d = devm_kzalloc(dev, sizeof(*pw_d), GFP_KERNEL);
+ if (!pw_d)
+ return ERR_PTR(-ENOMEM);
+
+ ret = xa_alloc(&pse_pw_d_map, &index, pw_d, XA_LIMIT(1, INT_MAX), GFP_KERNEL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ pw_d->id = index;
+ return pw_d;
+}
+
+/**
+ * pse_register_pw_ds - register the PSE power domains for a PSE
+ * @pcdev: a pointer to the PSE controller device
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int pse_register_pw_ds(struct pse_controller_dev *pcdev)
+{
+ int i;
+
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ struct regulator_dev *rdev = pcdev->pi[i].rdev;
+ struct pse_power_domain *pw_d;
+ struct regulator *supply;
+ bool present = false;
+ unsigned long index;
+
+ /* No regulator or regulator parent supply registered.
+ * We need a regulator parent to register a PSE power domain
+ */
+ if (!rdev || !rdev->supply)
+ continue;
+
+ xa_for_each(&pse_pw_d_map, index, pw_d) {
+ /* Power supply already registered as a PSE power
+ * domain.
+ */
+ if (regulator_is_equal(pw_d->supply, rdev->supply)) {
+ present = true;
+ pcdev->pi[i].pw_d = pw_d;
+ break;
+ }
+ }
+ if (present)
+ continue;
+
+ pw_d = devm_pse_alloc_pw_d(pcdev->dev);
+ if (IS_ERR_OR_NULL(pw_d))
+ return PTR_ERR(pw_d);
+
+ supply = regulator_get(&rdev->dev, rdev->supply_name);
+ if (IS_ERR(supply)) {
+ xa_erase(&pse_pw_d_map, pw_d->id);
+ return PTR_ERR(supply);
+ }
+
+ pw_d->supply = supply;
+ pcdev->pi[i].pw_d = pw_d;
+ }
+
+ return 0;
+}
+
/**
* pse_controller_register - register a PSE controller device
* @pcdev: a pointer to the initialized PSE controller device
@@ -505,6 +613,11 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
goto free_pse_ida;
}
+ ret = pse_register_pw_ds(pcdev);
+
+ if (ret)
+ goto free_pse_ida;
+
mutex_lock(&pse_list_mutex);
list_add(&pcdev->list, &pse_controller_list);
mutex_unlock(&pse_list_mutex);
@@ -523,6 +636,7 @@ EXPORT_SYMBOL_GPL(pse_controller_register);
*/
void pse_controller_unregister(struct pse_controller_dev *pcdev)
{
+ pse_flush_pw_ds(pcdev);
pse_release_pis(pcdev);
ida_free(&pse_ida, pcdev->id);
mutex_lock(&pse_list_mutex);
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index b3f8d198c5a7..54b88cce5cf5 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -164,12 +164,14 @@ struct pse_pi_pairset {
* @np: device node pointer of the PSE PI node
* @rdev: regulator represented by the PSE PI
* @admin_state_enabled: PI enabled state
+ * @pw_d: Power domain of the PSE PI
*/
struct pse_pi {
struct pse_pi_pairset pairset[2];
struct device_node *np;
struct regulator_dev *rdev;
bool admin_state_enabled;
+ struct pse_power_domain *pw_d;
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 21/27] net: ethtool: Add support for new power domains index description
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (19 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 20/27] net: pse-pd: Add support for PSE power domains Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 22/27] net: pse-pd: Add support for getting budget evaluation strategies Kory Maincent
` (6 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Report the index of the newly introduced PSE power domain to the user,
enabling improved management of the power budget for PSE devices.
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- Do not support power domain id = 0 because we can't differentiate with
no PSE power domain.
Changes in v2:
- new patch.
---
Documentation/netlink/specs/ethtool.yaml | 5 +++++
Documentation/networking/ethtool-netlink.rst | 4 ++++
drivers/net/pse-pd/pse_core.c | 3 +++
include/linux/ethtool.h | 2 ++
include/uapi/linux/ethtool_netlink_generated.h | 1 +
net/ethtool/pse-pd.c | 7 +++++++
6 files changed, 22 insertions(+)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 9aa62137166a..686181440d58 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1361,6 +1361,10 @@ attribute-sets:
name: pse-id
type: u32
name-prefix: ethtool-a-
+ -
+ name: pse-pw-d-id
+ type: u32
+ name-prefix: ethtool-a-
-
name: rss
attr-cnt-name: __ethtool-a-rss-cnt
@@ -2183,6 +2187,7 @@ operations:
- c33-pse-avail-pw-limit
- c33-pse-pw-limit-ranges
- pse-id
+ - pse-pw-d-id
dump: *pse-get-op
-
name: pse-set
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index 9d836fa670df..68c0cfcea127 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1773,6 +1773,7 @@ Kernel response contents:
``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested Supported power limit
configuration ranges.
``ETHTOOL_A_PSE_ID`` u32 Index of the PSE
+ ``ETHTOOL_A_PSE_PW_D_ID`` u32 Index of the PSE power domain
========================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
@@ -1849,6 +1850,9 @@ equal.
The ``ETHTOOL_A_PSE_ID`` attribute identifies the index of the PSE
controller.
+The ``ETHTOOL_A_PSE_PW_D_ID`` attribute identifies the index of PSE power
+domain.
+
PSE_SET
=======
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 6bfe0fca90b4..9c482d341b9c 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -1052,6 +1052,9 @@ int pse_ethtool_get_status(struct pse_control *psec,
status->pse_id = pcdev->id;
mutex_lock(&pcdev->lock);
+ if (pcdev->pi[psec->id].pw_d)
+ status->pw_d_id = pcdev->pi[psec->id].pw_d->id;
+
ret = ops->pi_get_admin_state(pcdev, psec->id, &admin_state);
if (ret)
goto out;
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index d5d13a3d4447..1ae0651b2ebd 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1328,6 +1328,7 @@ struct ethtool_c33_pse_pw_limit_range {
* struct ethtool_pse_control_status - PSE control/channel status.
*
* @pse_id: index number of the PSE.
+ * @pw_d_id: PSE power domain index.
* @podl_admin_state: operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
* @podl_pw_status: power detection status of the PoDL PSE.
@@ -1350,6 +1351,7 @@ struct ethtool_c33_pse_pw_limit_range {
*/
struct ethtool_pse_control_status {
u32 pse_id;
+ u32 pw_d_id;
enum ethtool_podl_pse_admin_state podl_admin_state;
enum ethtool_podl_pse_pw_d_status podl_pw_status;
enum ethtool_c33_pse_admin_state c33_admin_state;
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index 7293592fd689..1ec5a0838f50 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -631,6 +631,7 @@ enum {
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT,
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES,
ETHTOOL_A_PSE_ID,
+ ETHTOOL_A_PSE_PW_D_ID,
__ETHTOOL_A_PSE_CNT,
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index bbc9ae910e02..00b97712767d 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -85,6 +85,8 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
int len = 0;
len += nla_total_size(sizeof(u32)); /* _PSE_ID */
+ if (st->pw_d_id > 0)
+ len += nla_total_size(sizeof(u32)); /* _PSE_PW_D_ID */
if (st->podl_admin_state > 0)
len += nla_total_size(sizeof(u32)); /* _PODL_PSE_ADMIN_STATE */
if (st->podl_pw_status > 0)
@@ -153,6 +155,11 @@ static int pse_fill_reply(struct sk_buff *skb,
if (nla_put_u32(skb, ETHTOOL_A_PSE_ID, st->pse_id))
return -EMSGSIZE;
+ if (st->pw_d_id > 0 &&
+ nla_put_u32(skb, ETHTOOL_A_PSE_PW_D_ID,
+ st->pw_d_id))
+ return -EMSGSIZE;
+
if (st->podl_admin_state > 0 &&
nla_put_u32(skb, ETHTOOL_A_PODL_PSE_ADMIN_STATE,
st->podl_admin_state))
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 22/27] net: pse-pd: Add support for getting budget evaluation strategies
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (20 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 21/27] net: ethtool: Add support for new power domains index description Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 23/27] net: ethtool: Add PSE new budget evaluation strategy support feature Kory Maincent
` (5 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This patch introduces the ability to configure the PSE PI budget evaluation
strategies. Budget evaluation strategies is utilized by PSE controllers to
determine which ports to turn off first in scenarios such as power budget
exceedance.
The pis_prio_max value is used to define the maximum priority level
supported by the controller. Both the current priority and the maximum
priority are exposed to the user through the pse_ethtool_get_status call.
This patch add support for two mode of budget evaluation strategies.
1. Static Method:
This method involves distributing power based on PD classification.
It’s straightforward and stable, the PSE core keeping track of the
budget and subtracting the power requested by each PD’s class.
Advantages: Every PD gets its promised power at any time, which
guarantees reliability.
Disadvantages: PD classification steps are large, meaning devices
request much more power than they actually need. As a result, the power
supply may only operate at, say, 50% capacity, which is inefficient and
wastes money.
Priority max value is matching the number of PSE PIs within the PSE.
2. Dynamic Method:
To address the inefficiencies of the static method, vendors like
Microchip have introduced dynamic power budgeting, as seen in the
PD692x0 firmware. This method monitors the current consumption per port
and subtracts it from the available power budget. When the budget is
exceeded, lower-priority ports are shut down.
Advantages: This method optimizes resource utilization, saving costs.
Disadvantages: Low-priority devices may experience instability.
Priority max value is set by the PSE controller driver.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- Remove disconnection policy features.
- Rename port priority to budget evaluation strategy.
- Add kdoc
Change in v3:
- Add disconnection policy.
- Add management of disabled port priority in the interrupt handler.
- Move port prio mode in the power domain instead of the PSE.
Change in v2:
- Rethink the port priority support.
---
drivers/net/pse-pd/pse_core.c | 601 ++++++++++++++++++++++++++++++++++++++----
include/linux/ethtool.h | 7 +
include/linux/pse-pd/pse.h | 39 +++
include/uapi/linux/ethtool.h | 39 ++-
net/ethtool/common.c | 6 +
5 files changed, 647 insertions(+), 45 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 9c482d341b9c..1ab6edaf9707 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -40,10 +40,13 @@ struct pse_control {
* struct pse_power_domain - a PSE power domain
* @id: ID of the power domain
* @supply: Power supply the Power Domain
+ * @budget_eval_strategy: Current power budget evaluation strategy of the
+ * power domain
*/
struct pse_power_domain {
int id;
struct regulator *supply;
+ u32 budget_eval_strategy;
};
static int of_load_single_pse_pi_pairset(struct device_node *node,
@@ -222,6 +225,30 @@ static int of_load_pse_pis(struct pse_controller_dev *pcdev)
return ret;
}
+/**
+ * pse_pw_d_is_sw_pw_control - Is power control software managed
+ * @pcdev: a pointer to the PSE controller device
+ * @pw_d: a pointer to the PSE power domain
+ *
+ * Return: true if the power control of the power domain is managed from
+ * the software in the interrupt handler
+ */
+static bool pse_pw_d_is_sw_pw_control(struct pse_controller_dev *pcdev,
+ struct pse_power_domain *pw_d)
+{
+ if (!pw_d)
+ return false;
+
+ if (pw_d->budget_eval_strategy == ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC)
+ return true;
+ if (pw_d->budget_eval_strategy == ETHTOOL_PSE_BUDGET_EVAL_STRAT_DISABLED &&
+ pcdev->ops->pi_enable && pcdev->ops->pi_get_pw_req &&
+ pcdev->irq)
+ return true;
+
+ return false;
+}
+
static int pse_pi_is_enabled(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
@@ -235,6 +262,11 @@ static int pse_pi_is_enabled(struct regulator_dev *rdev)
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
+ if (pse_pw_d_is_sw_pw_control(pcdev, pcdev->pi[id].pw_d)) {
+ ret = pcdev->pi[id].admin_state_enabled;
+ goto out;
+ }
+
ret = ops->pi_get_admin_state(pcdev, id, &admin_state);
if (ret)
goto out;
@@ -249,11 +281,256 @@ static int pse_pi_is_enabled(struct regulator_dev *rdev)
return ret;
}
+/**
+ * pse_pi_deallocate_pw_budget - Deallocate power budget of the PI
+ * @pi: a pointer to the PSE PI
+ */
+static void pse_pi_deallocate_pw_budget(struct pse_pi *pi)
+{
+ if (!pi->pw_d)
+ return;
+
+ regulator_free_power_budget(pi->pw_d->supply, pi->pw_allocated_mW);
+ pi->pw_allocated_mW = 0;
+}
+
+/**
+ * _pse_pi_disable - Call disable operation. Assumes the PSE lock has been
+ * acquired.
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE control
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int _pse_pi_disable(struct pse_controller_dev *pcdev, int id)
+{
+ const struct pse_controller_ops *ops = pcdev->ops;
+ int ret;
+
+ if (!ops->pi_disable)
+ return -EOPNOTSUPP;
+
+ ret = ops->pi_disable(pcdev, id);
+ if (ret)
+ return ret;
+
+ pse_pi_deallocate_pw_budget(&pcdev->pi[id]);
+
+ return 0;
+}
+
+/**
+ * pse_control_find_phy_by_id - Find PHY attached to the a pse control id
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE control
+ *
+ * Return: PHY device pointer or NULL
+ */
+static struct phy_device *
+pse_control_find_phy_by_id(struct pse_controller_dev *pcdev, int id)
+{
+ struct pse_control *psec;
+
+ mutex_lock(&pse_list_mutex);
+ list_for_each_entry(psec, &pcdev->pse_control_head, list) {
+ if (psec->id == id) {
+ mutex_unlock(&pse_list_mutex);
+ return psec->attached_phydev;
+ }
+ }
+ mutex_unlock(&pse_list_mutex);
+ return NULL;
+}
+
+/**
+ * pse_disable_pi_pol - Disable a PI on a power budget policy
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE PI
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int pse_disable_pi_pol(struct pse_controller_dev *pcdev, int id)
+{
+ unsigned long notifs = ETHTOOL_PSE_EVENT_OVER_BUDGET;
+ struct netlink_ext_ack extack = {};
+ struct phy_device *phydev;
+ int ret;
+
+ dev_dbg(pcdev->dev, "Disabling PI %d to free power budget\n", id);
+
+ NL_SET_ERR_MSG_FMT(&extack,
+ "Disabling PI %d to free power budget", id);
+
+ ret = _pse_pi_disable(pcdev, id);
+ if (ret) {
+ notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
+ } else {
+ pcdev->pi[id].admin_state_enabled = 0;
+ pcdev->pi[id]._isr_counter_mismatch = 1;
+ }
+
+ phydev = pse_control_find_phy_by_id(pcdev, id);
+ if (phydev)
+ ethnl_pse_send_ntf(phydev, notifs, &extack);
+
+ return ret;
+}
+
+/**
+ * pse_disable_pi_prio - Disable all PIs of a given priority inside a PSE
+ * power domain
+ * @pcdev: a pointer to the PSE
+ * @pw_d: a pointer to the PSE power domain
+ * @prio: priority
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int pse_disable_pi_prio(struct pse_controller_dev *pcdev,
+ struct pse_power_domain *pw_d,
+ int prio)
+{
+ int i;
+
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ int ret;
+
+ if (pcdev->pi[i].prio != prio ||
+ pcdev->pi[i].pw_d != pw_d ||
+ !pcdev->pi[i].admin_state_enabled)
+ continue;
+
+ ret = pse_disable_pi_pol(pcdev, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * pse_pi_allocate_pw_budget_static_prio - Allocate power budget for the PI
+ * when the budget eval strategy is
+ * static
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE control
+ * @pw_req: power requested in mW
+ * @extack: extack for error reporting
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int
+pse_pi_allocate_pw_budget_static_prio(struct pse_controller_dev *pcdev, int id,
+ int pw_req, struct netlink_ext_ack *extack)
+{
+ struct pse_pi *pi = &pcdev->pi[id];
+ int ret, _prio;
+
+ _prio = pcdev->nr_lines;
+ while (regulator_request_power_budget(pi->pw_d->supply, pw_req) == -ERANGE) {
+ if (_prio <= pi->prio) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: not enough power budget available",
+ id);
+ return -ERANGE;
+ }
+
+ ret = pse_disable_pi_prio(pcdev, pi->pw_d, _prio);
+ if (ret < 0)
+ return ret;
+
+ _prio--;
+ }
+
+ pi->pw_allocated_mW = pw_req;
+ return 0;
+}
+
+/**
+ * pse_pi_allocate_pw_budget - Allocate power budget for the PI
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE control
+ * @pw_req: power requested in mW
+ * @extack: extack for error reporting
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int pse_pi_allocate_pw_budget(struct pse_controller_dev *pcdev, int id,
+ int pw_req, struct netlink_ext_ack *extack)
+{
+ struct pse_pi *pi = &pcdev->pi[id];
+
+ if (!pi->pw_d)
+ return 0;
+
+ /* ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC */
+ if (pi->pw_d->budget_eval_strategy == ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC)
+ return pse_pi_allocate_pw_budget_static_prio(pcdev, id, pw_req,
+ extack);
+
+ return 0;
+}
+
+/**
+ * _pse_pi_enable_sw_pw_ctrl - Enable PSE PI in case of software power control.
+ * Assumes the PSE lock has been acquired
+ * @pcdev: a pointer to the PSE
+ * @id: index of the PSE control
+ * @extack: extack for error reporting
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int _pse_pi_enable_sw_pw_ctrl(struct pse_controller_dev *pcdev, int id,
+ struct netlink_ext_ack *extack)
+{
+ const struct pse_controller_ops *ops = pcdev->ops;
+ struct pse_pi *pi = &pcdev->pi[id];
+ int ret, pw_req;
+
+ if (!ops->pi_get_pw_req) {
+ NL_SET_ERR_MSG(extack,
+ "PSE does not support get power request");
+ return -EOPNOTSUPP;
+ }
+
+ ret = ops->pi_get_pw_req(pcdev, id);
+ if (ret < 0)
+ return ret;
+
+ pw_req = ret;
+
+ /* Compare requested power with port power limit and use the lowest
+ * one.
+ */
+ if (ops->pi_get_pw_limit) {
+ ret = ops->pi_get_pw_limit(pcdev, id);
+ if (ret < 0)
+ return ret;
+
+ if (ret < pw_req)
+ pw_req = ret;
+ }
+
+ ret = pse_pi_allocate_pw_budget(pcdev, id, pw_req, extack);
+ if (ret)
+ return ret;
+
+ ret = ops->pi_enable(pcdev, id);
+ if (ret) {
+ pse_pi_deallocate_pw_budget(pi);
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: enable error %d",
+ id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int pse_pi_enable(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
const struct pse_controller_ops *ops;
- int id, ret;
+ int id, ret = 0;
ops = pcdev->ops;
if (!ops->pi_enable)
@@ -261,6 +538,23 @@ static int pse_pi_enable(struct regulator_dev *rdev)
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
+ if (pse_pw_d_is_sw_pw_control(pcdev, pcdev->pi[id].pw_d)) {
+ /* Manage enabled status by software.
+ * Real enable process will happen if a port is connected.
+ */
+ if (pcdev->pi[id].isr_pd_detected) {
+ struct netlink_ext_ack extack;
+
+ ret = _pse_pi_enable_sw_pw_ctrl(pcdev, id, &extack);
+ if (!ret)
+ pcdev->pi[id].admin_state_enabled = 1;
+ } else {
+ pcdev->pi[id].admin_state_enabled = 1;
+ }
+ mutex_unlock(&pcdev->lock);
+ return ret;
+ }
+
ret = ops->pi_enable(pcdev, id);
if (!ret)
pcdev->pi[id].admin_state_enabled = 1;
@@ -272,21 +566,20 @@ static int pse_pi_enable(struct regulator_dev *rdev)
static int pse_pi_disable(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
- const struct pse_controller_ops *ops;
+ struct pse_pi *pi;
int id, ret;
- ops = pcdev->ops;
- if (!ops->pi_disable)
- return -EOPNOTSUPP;
-
id = rdev_get_id(rdev);
+ pi = &pcdev->pi[id];
mutex_lock(&pcdev->lock);
- ret = ops->pi_disable(pcdev, id);
- if (!ret)
- pcdev->pi[id].admin_state_enabled = 0;
- mutex_unlock(&pcdev->lock);
+ ret = _pse_pi_disable(pcdev, id);
+ if (!ret) {
+ pi->admin_state_enabled = 0;
+ pcdev->pi[id]._isr_counter_mismatch = 0;
+ }
- return ret;
+ mutex_unlock(&pcdev->lock);
+ return 0;
}
static int _pse_pi_get_voltage(struct regulator_dev *rdev)
@@ -542,6 +835,10 @@ static int pse_register_pw_ds(struct pse_controller_dev *pcdev)
}
pw_d->supply = supply;
+ if (pcdev->supp_budget_eval_strategies)
+ pw_d->budget_eval_strategy = pcdev->supp_budget_eval_strategies;
+ else
+ pw_d->budget_eval_strategy = ETHTOOL_PSE_BUDGET_EVAL_STRAT_DISABLED;
pcdev->pi[i].pw_d = pw_d;
}
@@ -711,27 +1008,45 @@ static unsigned long pse_to_regulator_notifs(unsigned long notifs)
}
/**
- * pse_control_find_phy_by_id - Find PHY attached to the a pse control id
+ * pse_set_config_isr - Set PSE control config according to the PSE
+ * notifications
* @pcdev: a pointer to the PSE
* @id: index of the PSE control
+ * @notifs: PSE event notifications
+ * @extack: extack for error reporting
*
- * Return: PHY device pointer or NULL
+ * Return: 0 on success and failure value on error
*/
-static struct phy_device *
-pse_control_find_phy_by_id(struct pse_controller_dev *pcdev, int id)
+static int pse_set_config_isr(struct pse_controller_dev *pcdev, int id,
+ unsigned long notifs,
+ struct netlink_ext_ack *extack)
{
- struct pse_control *psec;
+ int ret = 0;
- mutex_lock(&pse_list_mutex);
- list_for_each_entry(psec, &pcdev->pse_control_head, list) {
- if (psec->id == id) {
- mutex_unlock(&pse_list_mutex);
- return psec->attached_phydev;
- }
+ if (notifs & ETHTOOL_PSE_BUDGET_EVAL_STRAT_DYNAMIC)
+ return 0;
+
+ if ((notifs & ETHTOOL_C33_PSE_EVENT_DISCONNECTION) &&
+ ((notifs & ETHTOOL_C33_PSE_EVENT_DETECTION) ||
+ (notifs & ETHTOOL_C33_PSE_EVENT_CLASSIFICATION))) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: error, connection and disconnection reported simultaneously",
+ id);
+ return -EINVAL;
}
- mutex_unlock(&pse_list_mutex);
- return NULL;
+ if (notifs & ETHTOOL_C33_PSE_EVENT_CLASSIFICATION) {
+ pcdev->pi[id].isr_pd_detected = true;
+ if (pcdev->pi[id].admin_state_enabled)
+ ret = _pse_pi_enable_sw_pw_ctrl(pcdev, id, extack);
+ } else if (notifs & ETHTOOL_C33_PSE_EVENT_DISCONNECTION) {
+ if (pcdev->pi[id].admin_state_enabled &&
+ pcdev->pi[id].isr_pd_detected)
+ ret = _pse_pi_disable(pcdev, id);
+ pcdev->pi[id].isr_pd_detected = false;
+ }
+
+ return ret;
}
/**
@@ -757,9 +1072,10 @@ static irqreturn_t pse_isr(int irq, void *data)
memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
mutex_lock(&pcdev->lock);
ret = desc->map_event(irq, pcdev, h->notifs, ¬ifs_mask);
- mutex_unlock(&pcdev->lock);
- if (ret || !notifs_mask)
+ if (ret || !notifs_mask) {
+ mutex_unlock(&pcdev->lock);
return IRQ_NONE;
+ }
for_each_set_bit(i, ¬ifs_mask, pcdev->nr_lines) {
struct phy_device *phydev;
@@ -770,6 +1086,12 @@ static irqreturn_t pse_isr(int irq, void *data)
continue;
notifs = h->notifs[i];
+ if (pse_pw_d_is_sw_pw_control(pcdev, pcdev->pi[i].pw_d)) {
+ ret = pse_set_config_isr(pcdev, i, notifs, &extack);
+ if (ret)
+ notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
+ }
+
dev_dbg(h->pcdev->dev,
"Sending PSE notification EVT 0x%lx\n", notifs);
@@ -781,6 +1103,8 @@ static irqreturn_t pse_isr(int irq, void *data)
NULL);
}
+ mutex_unlock(&pcdev->lock);
+
return IRQ_HANDLED;
}
@@ -875,6 +1199,7 @@ static struct pse_control *
pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
struct phy_device *phydev)
{
+ struct pse_admin_state admin_state = {0};
struct pse_control *psec;
int ret;
@@ -896,6 +1221,23 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
goto free_psec;
}
+ if (!pcdev->ops->pi_get_admin_state) {
+ ret = -EOPNOTSUPP;
+ goto free_psec;
+ }
+
+ /* Initialize admin_state_enabled before the regulator_get. This
+ * aims to have the right value reported in the first is_enabled
+ * call in case of control managed by software.
+ */
+ ret = pcdev->ops->pi_get_admin_state(pcdev, index, &admin_state);
+ if (ret)
+ goto free_psec;
+
+ if (admin_state.podl_admin_state == ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED ||
+ admin_state.c33_admin_state == ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED)
+ pcdev->pi[index].admin_state_enabled = 1;
+
psec->ps = devm_regulator_get_exclusive(pcdev->dev,
rdev_get_name(pcdev->pi[index].rdev));
if (IS_ERR(psec->ps)) {
@@ -903,12 +1245,6 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
goto put_module;
}
- ret = regulator_is_enabled(psec->ps);
- if (ret < 0)
- goto regulator_put;
-
- pcdev->pi[index].admin_state_enabled = ret;
-
psec->pcdev = pcdev;
list_add(&psec->list, &pcdev->pse_control_head);
psec->id = index;
@@ -917,8 +1253,6 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
return psec;
-regulator_put:
- devm_regulator_put(psec->ps);
put_module:
module_put(pcdev->owner);
free_psec:
@@ -1029,6 +1363,35 @@ struct pse_control *of_pse_control_get(struct device_node *node,
}
EXPORT_SYMBOL_GPL(of_pse_control_get);
+/**
+ * pse_get_sw_admin_state - Convert the software admin state to c33 or podl
+ * admin state value used in the standard
+ * @psec: PSE control pointer
+ * @admin_state: a pointer to the admin_state structure
+ */
+static void pse_get_sw_admin_state(struct pse_control *psec,
+ struct pse_admin_state *admin_state)
+{
+ struct pse_pi *pi = &psec->pcdev->pi[psec->id];
+
+ if (pse_has_podl(psec)) {
+ if (pi->admin_state_enabled)
+ admin_state->podl_admin_state =
+ ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED;
+ else
+ admin_state->podl_admin_state =
+ ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED;
+ }
+ if (pse_has_c33(psec)) {
+ if (pi->admin_state_enabled)
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ else
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+ }
+}
+
/**
* pse_ethtool_get_status - get status of PSE control
* @psec: PSE control pointer
@@ -1045,21 +1408,48 @@ int pse_ethtool_get_status(struct pse_control *psec,
struct pse_pw_status pw_status = {0};
const struct pse_controller_ops *ops;
struct pse_controller_dev *pcdev;
+ struct pse_pi *pi;
int ret;
pcdev = psec->pcdev;
ops = pcdev->ops;
status->pse_id = pcdev->id;
+ pi = &pcdev->pi[psec->id];
mutex_lock(&pcdev->lock);
- if (pcdev->pi[psec->id].pw_d)
- status->pw_d_id = pcdev->pi[psec->id].pw_d->id;
+ if (pi->pw_d) {
+ status->pw_d_id = pi->pw_d->id;
+ status->budget_eval_strategy = pi->pw_d->budget_eval_strategy;
+ if (pse_pw_d_is_sw_pw_control(pcdev, pi->pw_d)) {
+ pse_get_sw_admin_state(psec, &admin_state);
+ } else {
+ ret = ops->pi_get_admin_state(pcdev, psec->id,
+ &admin_state);
+ if (ret)
+ goto out;
+ }
+ status->podl_admin_state = admin_state.podl_admin_state;
+ status->c33_admin_state = admin_state.c33_admin_state;
- ret = ops->pi_get_admin_state(pcdev, psec->id, &admin_state);
- if (ret)
- goto out;
- status->podl_admin_state = admin_state.podl_admin_state;
- status->c33_admin_state = admin_state.c33_admin_state;
+ switch (pi->pw_d->budget_eval_strategy) {
+ case ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC:
+ status->prio_max = pcdev->nr_lines;
+ status->prio = pi->prio;
+ break;
+ case ETHTOOL_PSE_BUDGET_EVAL_STRAT_DYNAMIC:
+ status->prio_max = pcdev->pis_prio_max;
+ if (ops->pi_get_prio) {
+ ret = ops->pi_get_prio(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
+
+ status->prio = ret;
+ }
+ break;
+ default:
+ break;
+ }
+ }
ret = ops->pi_get_pw_status(pcdev, psec->id, &pw_status);
if (ret)
@@ -1134,11 +1524,15 @@ static int pse_ethtool_c33_set_config(struct pse_control *psec,
case ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED:
/* We could have mismatch between admin_state_enabled and
* state reported by regulator_is_enabled. This can occur when
- * the PI is forcibly turn off by the controller. Call
+ * the PI is forcibly turn off by the controller or in power
+ * off case in the interrupt context. Call
* regulator_disable on that case to fix the counters state.
+ * disable action might be called two times consecutively
+ * but that is not a real issue.
*/
- if (psec->pcdev->pi[psec->id].admin_state_enabled &&
- !regulator_is_enabled(psec->ps)) {
+ if ((psec->pcdev->pi[psec->id].admin_state_enabled &&
+ !regulator_is_enabled(psec->ps)) ||
+ psec->pcdev->pi[psec->id]._isr_counter_mismatch) {
err = regulator_disable(psec->ps);
if (err)
break;
@@ -1208,6 +1602,49 @@ int pse_ethtool_set_config(struct pse_control *psec,
}
EXPORT_SYMBOL_GPL(pse_ethtool_set_config);
+/**
+ * pse_pi_update_pw_budget - Update PSE power budget allocated with new
+ * power in mW
+ * @pcdev: a pointer to the PSE controller device
+ * @id: index of the PSE PI
+ * @pw_req: power requested
+ * @extack: extack for reporting useful error messages
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int pse_pi_update_pw_budget(struct pse_controller_dev *pcdev, int id,
+ const unsigned int pw_req,
+ struct netlink_ext_ack *extack)
+{
+ struct pse_pi *pi = &pcdev->pi[id];
+ int pw_diff, ret = 0;
+
+ /* We don't want pw_allocated_mW value change in the middle of an
+ * power budget update
+ */
+ mutex_lock(&pcdev->lock);
+ pw_diff = pw_req - pi->pw_allocated_mW;
+ if (!pw_diff) {
+ goto out;
+ } else if (pw_diff > 0) {
+ ret = regulator_request_power_budget(pi->pw_d->supply, pw_diff);
+ if (ret) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: not enough power budget available",
+ id);
+ goto out;
+ }
+
+ } else {
+ regulator_free_power_budget(pi->pw_d->supply, -pw_diff);
+ }
+ pi->pw_allocated_mW = pw_req;
+
+out:
+ mutex_unlock(&pcdev->lock);
+ return ret;
+}
+
/**
* pse_ethtool_set_pw_limit - set PSE control power limit
* @psec: PSE control pointer
@@ -1244,10 +1681,86 @@ int pse_ethtool_set_pw_limit(struct pse_control *psec,
/* uA = mW * 1000000000 / uV */
uA = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
+ if (psec->pcdev->pi[psec->id].pw_d) {
+ ret = pse_pi_update_pw_budget(psec->pcdev, psec->id,
+ pw_limit, extack);
+ if (ret)
+ return ret;
+ }
+
return regulator_set_current_limit(psec->ps, 0, uA);
}
EXPORT_SYMBOL_GPL(pse_ethtool_set_pw_limit);
+/**
+ * pse_ethtool_set_prio - Set PSE PI priority according to the budget
+ * evaluation strategy
+ * @psec: PSE control pointer
+ * @extack: extack for reporting useful error messages
+ * @prio: priovity value
+ *
+ * Return: 0 on success and failure value on error
+ */
+int pse_ethtool_set_prio(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ unsigned int prio)
+{
+ struct pse_controller_dev *pcdev = psec->pcdev;
+ const struct pse_controller_ops *ops;
+ int ret = 0;
+
+ if (!pcdev->pi[psec->id].pw_d) {
+ NL_SET_ERR_MSG(extack, "no power domain attached");
+ return -EOPNOTSUPP;
+ }
+
+ /* We don't want priority change in the middle of an
+ * enable/disable call or a priority mode change
+ */
+ mutex_lock(&pcdev->lock);
+ switch (pcdev->pi[psec->id].pw_d->budget_eval_strategy) {
+ case ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC:
+ if (prio > pcdev->nr_lines) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "priority %d exceed priority max %d",
+ prio, pcdev->nr_lines);
+ ret = -ERANGE;
+ goto out;
+ }
+
+ pcdev->pi[psec->id].prio = prio;
+ break;
+
+ case ETHTOOL_PSE_BUDGET_EVAL_STRAT_DYNAMIC:
+ ops = psec->pcdev->ops;
+ if (!ops->pi_set_prio) {
+ NL_SET_ERR_MSG(extack,
+ "pse driver does not support setting port priority");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (prio > pcdev->pis_prio_max) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "priority %d exceed priority max %d",
+ prio, pcdev->pis_prio_max);
+ ret = -ERANGE;
+ goto out;
+ }
+
+ ret = ops->pi_set_prio(pcdev, psec->id, prio);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+out:
+ mutex_unlock(&pcdev->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pse_ethtool_set_prio);
+
bool pse_has_podl(struct pse_control *psec)
{
return psec->pcdev->types & ETHTOOL_PSE_PODL;
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 1ae0651b2ebd..bf5145cc83d2 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1348,6 +1348,10 @@ struct ethtool_c33_pse_pw_limit_range {
* is in charge of the memory allocation
* @c33_pw_limit_nb_ranges: number of supported power limit configuration
* ranges
+ * @budget_eval_strategy: PSE budget evaluation strategy selected.
+ * @prio_max: max priority allowed for the c33_prio variable value.
+ * @prio: priority of the PSE. Managed by PSE core in case of static budget
+ * evaluation strategy.
*/
struct ethtool_pse_control_status {
u32 pse_id;
@@ -1362,5 +1366,8 @@ struct ethtool_pse_control_status {
u32 c33_avail_pw_limit;
struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
u32 c33_pw_limit_nb_ranges;
+ enum ethtool_pse_budget_eval_strategies budget_eval_strategy;
+ u32 prio_max;
+ u32 prio;
};
#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 54b88cce5cf5..8ddea690eb76 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -110,6 +110,11 @@ struct pse_pw_limit_ranges {
* range. The driver is in charge of the memory
* allocation and should return the number of
* ranges.
+ * @pi_get_prio: Get the PSE PI priority.
+ * @pi_set_prio: Configure the PSE PI priority.
+ * @pi_get_pw_req: Get the power requested by a PD before enabling the PSE PI.
+ * This is only relevant when an interrupt is registered using
+ * devm_pse_irq_helper helper.
*/
struct pse_controller_ops {
int (*setup_pi_matrix)(struct pse_controller_dev *pcdev);
@@ -130,6 +135,10 @@ struct pse_controller_ops {
int id, int max_mW);
int (*pi_get_pw_limit_ranges)(struct pse_controller_dev *pcdev, int id,
struct pse_pw_limit_ranges *pw_limit_ranges);
+ int (*pi_get_prio)(struct pse_controller_dev *pcdev, int id);
+ int (*pi_set_prio)(struct pse_controller_dev *pcdev, int id,
+ unsigned int prio);
+ int (*pi_get_pw_req)(struct pse_controller_dev *pcdev, int id);
};
struct module;
@@ -165,6 +174,17 @@ struct pse_pi_pairset {
* @rdev: regulator represented by the PSE PI
* @admin_state_enabled: PI enabled state
* @pw_d: Power domain of the PSE PI
+ * @prio: Priority of the PSE PI. Used in static budget evaluation strategy
+ * @isr_pd_detected: PSE PI detection status managed by the interruption
+ * handler. This variable is relevant when the power enabled
+ * management is managed in software like the static
+ * budget evaluation strategy.
+ * @pw_allocated_mW: Power allocated to a PSE PI to manage power budget in
+ * static budget evaluation strategy.
+ * @_isr_counter_mismatch: Internal flag used in PSE core in case of a
+ * counter mismatch between regulator and PSE API.
+ * This is caused by a disable call in the interrupt
+ * context handler.
*/
struct pse_pi {
struct pse_pi_pairset pairset[2];
@@ -172,6 +192,10 @@ struct pse_pi {
struct regulator_dev *rdev;
bool admin_state_enabled;
struct pse_power_domain *pw_d;
+ int prio;
+ bool isr_pd_detected;
+ int pw_allocated_mW;
+ bool _isr_counter_mismatch;
};
/**
@@ -190,6 +214,9 @@ struct pse_pi {
* @no_of_pse_pi: flag set if the pse_pis devicetree node is not used
* @id: Index of the PSE
* @irq: PSE interrupt
+ * @pis_prio_max: Maximum value allowed for the PSE PIs priority
+ * @supp_budget_eval_strategies: budget evaluation strategies supported
+ * by the PSE
*/
struct pse_controller_dev {
const struct pse_controller_ops *ops;
@@ -205,6 +232,8 @@ struct pse_controller_dev {
bool no_of_pse_pi;
u32 id;
int irq;
+ unsigned int pis_prio_max;
+ u32 supp_budget_eval_strategies;
};
#if IS_ENABLED(CONFIG_PSE_CONTROLLER)
@@ -229,6 +258,9 @@ int pse_ethtool_set_config(struct pse_control *psec,
int pse_ethtool_set_pw_limit(struct pse_control *psec,
struct netlink_ext_ack *extack,
const unsigned int pw_limit);
+int pse_ethtool_set_prio(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ unsigned int prio);
bool pse_has_podl(struct pse_control *psec);
bool pse_has_c33(struct pse_control *psec);
@@ -266,6 +298,13 @@ static inline int pse_ethtool_set_pw_limit(struct pse_control *psec,
return -EOPNOTSUPP;
}
+static inline int pse_ethtool_set_prio(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ unsigned int prio)
+{
+ return -EOPNOTSUPP;
+}
+
static inline bool pse_has_podl(struct pse_control *psec)
{
return false;
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 33c8dc6c9ef6..cd11d3e6e5bc 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1004,6 +1004,20 @@ enum ethtool_c33_pse_pw_d_status {
* enum ethtool_pse_events - event list of the PSE controller.
* @ETHTOOL_PSE_EVENT_OVER_CURRENT: PSE output current is too high.
* @ETHTOOL_PSE_EVENT_OVER_TEMP: PSE in over temperature state.
+ * @ETHTOOL_C33_PSE_EVENT_DETECTION: detection process occur on the PSE.
+ * IEEE 802.3-2022 33.2.5 and 145.2.6 PSE detection of PDs.
+ * IEEE 802.3-202 30.9.1.1.5 aPSEPowerDetectionStatus.
+ * @ETHTOOL_C33_PSE_EVENT_CLASSIFICATION: classification process occur on
+ * the PSE. IEEE 802.3-2022 33.2.6 and 145.2.8 classification of PDs and
+ * mutual identification.
+ * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification.
+ * @ETHTOOL_C33_PSE_EVENT_DISCONNECTION: PD has been disconnected on the PSE.
+ * IEEE 802.3-2022 33.3.8 and 145.3.9 PD Maintain Power Signature.
+ * IEEE 802.3-2022 33.5.1.2.9 MPS Absent.
+ * IEEE 802.3-2022 30.9.1.1.20 aPSEMPSAbsentCounter.
+ * @ETHTOOL_PSE_EVENT_OVER_BUDGET: PSE turned off due to over budget situation.
+ * @ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR: PSE faced an error managing the
+ * power control from software.
*
* @ETHTOOL_PSE_EVENT_LAST: Last PSE event of the enum.
*/
@@ -1011,8 +1025,31 @@ enum ethtool_c33_pse_pw_d_status {
enum ethtool_pse_events {
ETHTOOL_PSE_EVENT_OVER_CURRENT = 1 << 0,
ETHTOOL_PSE_EVENT_OVER_TEMP = 1 << 1,
+ ETHTOOL_C33_PSE_EVENT_DETECTION = 1 << 2,
+ ETHTOOL_C33_PSE_EVENT_CLASSIFICATION = 1 << 3,
+ ETHTOOL_C33_PSE_EVENT_DISCONNECTION = 1 << 4,
+ ETHTOOL_PSE_EVENT_OVER_BUDGET = 1 << 5,
+ ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR = 1 << 6,
- ETHTOOL_PSE_EVENT_LAST = ETHTOOL_PSE_EVENT_OVER_TEMP,
+ ETHTOOL_PSE_EVENT_LAST = ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR,
+};
+
+/**
+ * enum ethtool_pse_budget_eval_strategies - PSE budget evaluation strategies.
+ * @ETHTOOL_PSE_BUDGET_EVAL_STRAT_DISABLED: Budget evaluation strategy disabled.
+ * @ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC: PSE static budget evaluation strategy.
+ * Budget evaluation strategy based on the power requested during PD
+ * classification. This strategy is managed by the PSE core.
+ * @ETHTOOL_PSE_BUDGET_EVAL_STRAT_DYNAMIC: PSE dynamic budget evaluation
+ * strategy. Budget evaluation strategy based on the current consumption
+ * per ports compared to the total power budget. This mode is managed by
+ * the PSE controller.
+ */
+
+enum ethtool_pse_budget_eval_strategies {
+ ETHTOOL_PSE_BUDGET_EVAL_STRAT_DISABLED = 1 << 0,
+ ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC = 1 << 1,
+ ETHTOOL_PSE_BUDGET_EVAL_STRAT_DYNAMIC = 1 << 2,
};
/**
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index d50b8292debd..304c91f6c7e6 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -473,6 +473,12 @@ static_assert(ARRAY_SIZE(udp_tunnel_type_names) ==
const char pse_event_names[][ETH_GSTRING_LEN] = {
[const_ilog2(ETHTOOL_PSE_EVENT_OVER_CURRENT)] = "over-current",
[const_ilog2(ETHTOOL_PSE_EVENT_OVER_TEMP)] = "over-temperature",
+ [const_ilog2(ETHTOOL_C33_PSE_EVENT_DETECTION)] = "detection",
+ [const_ilog2(ETHTOOL_C33_PSE_EVENT_CLASSIFICATION)] = "classification",
+ [const_ilog2(ETHTOOL_C33_PSE_EVENT_DISCONNECTION)] = "disconnection",
+ [const_ilog2(ETHTOOL_PSE_EVENT_OVER_BUDGET)] = "over-budget",
+ [const_ilog2(ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR)] =
+ "software-pw-control-error",
};
static_assert(ARRAY_SIZE(pse_event_names) == __PSE_EVENT_CNT);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 23/27] net: ethtool: Add PSE new budget evaluation strategy support feature
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (21 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 22/27] net: pse-pd: Add support for getting budget evaluation strategies Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature Kory Maincent
` (4 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This patch expands the status information provided by ethtool for PSE c33
with current port priority and max port priority. It also adds a call to
pse_ethtool_set_prio() to configure the PSE port priority.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v4:
- Remove disconnection policy features.
- Rename port priority to budget evaluation strategy.
Change in v3:
- Add disconnection policy.
Change in v2:
- Improve port priority documentation.
- Add port priority modes.
---
Documentation/netlink/specs/ethtool.yaml | 16 ++++++
Documentation/networking/ethtool-netlink.rst | 67 ++++++++++++++++++++++++++
include/uapi/linux/ethtool_netlink_generated.h | 3 ++
net/ethtool/pse-pd.c | 26 ++++++++++
4 files changed, 112 insertions(+)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 686181440d58..22913f6857d9 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1365,6 +1365,18 @@ attribute-sets:
name: pse-pw-d-id
type: u32
name-prefix: ethtool-a-
+ -
+ name: pse-budget-eval-strat
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: pse-prio-max
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: pse-prio
+ type: u32
+ name-prefix: ethtool-a-
-
name: rss
attr-cnt-name: __ethtool-a-rss-cnt
@@ -2188,6 +2200,9 @@ operations:
- c33-pse-pw-limit-ranges
- pse-id
- pse-pw-d-id
+ - pse-budget-eval-strat
+ - pse-prio-max
+ - pse-prio
dump: *pse-get-op
-
name: pse-set
@@ -2202,6 +2217,7 @@ operations:
- podl-pse-admin-control
- c33-pse-admin-control
- c33-pse-avail-pw-limit
+ - pse-prio
-
name: rss-get
doc: Get RSS params.
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index 68c0cfcea127..102a173764de 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1774,6 +1774,12 @@ Kernel response contents:
configuration ranges.
``ETHTOOL_A_PSE_ID`` u32 Index of the PSE
``ETHTOOL_A_PSE_PW_D_ID`` u32 Index of the PSE power domain
+ ``ETHTOOL_A_C33_PSE_BUDGET_EVAL_STRAT`` u32 Budget evaluation strategy
+ of the PSE
+ ``ETHTOOL_A_C33_PSE_PRIO_MAX`` u32 Priority maximum configurable
+ on the PoE PSE
+ ``ETHTOOL_A_C33_PSE_PRIO`` u32 Priority of the PoE PSE
+ currently configured
========================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
@@ -1853,6 +1859,51 @@ controller.
The ``ETHTOOL_A_PSE_PW_D_ID`` attribute identifies the index of PSE power
domain.
+When set, the optional ``ETHTOOL_A_C33_PSE_PRIO_SUPP_MODES`` attribute
+identifies the priority mode supported by the C33 PSE.
+When set, the optional ``ETHTOOL_A_C33_PSE_BUDGET_EVAL_STRAT`` attributes is used to
+identifies the currently configured C33 PSE budget evaluation strategy.
+The available strategies are:
+
+1. Disabled:
+
+ In this mode, the port is excluded from active budget evaluation. It
+ allows the port to violate the budget and is intended primarily for testing
+ purposes.
+
+2. Static Method:
+
+ This method involves distributing power based on PD classification. It’s
+ straightforward and stable, with the PSE core keeping track of the budget
+ and subtracting the power requested by each PD’s class. This is the
+ safest option and should be used by default.
+
+ Advantages: Every PD gets its promised power at any time, which guarantees
+ reliability.
+
+ Disadvantages: PD classification steps are large, meaning devices request
+ much more power than they actually need. As a result, the power supply may
+ only operate at, say, 50% capacity, which is inefficient and wastes money.
+
+3. Dynamic Method:
+
+ This method monitors the current consumption per port and subtracts it from
+ the available power budget. When the budget is exceeded, lower-priority
+ ports are shut down. This method is managed by the PSE controller itself.
+
+ Advantages: This method optimizes resource utilization, saving costs.
+
+ Disadvantages: Low-priority devices may experience instability.
+
+.. kernel-doc:: include/uapi/linux/ethtool.h
+ :identifiers: ethtool_pse_budget_eval_strategies
+
+When set, the optional ``ETHTOOL_A_C33_PSE_PRIO_MAX`` attribute identifies
+the C33 PSE maximum priority value.
+When set, the optional ``ETHTOOL_A_C33_PSE_PRIO`` attributes is used to
+identifies the currently configured C33 PSE priority.
+For a description of PSE priority attributes, see ``PSE_SET``.
+
PSE_SET
=======
@@ -1866,6 +1917,8 @@ Request contents:
``ETHTOOL_A_C33_PSE_ADMIN_CONTROL`` u32 Control PSE Admin state
``ETHTOOL_A_C33_PSE_AVAIL_PWR_LIMIT`` u32 Control PoE PSE available
power limit
+ ``ETHTOOL_A_C33_PSE_PRIO`` u32 Control priority of the
+ PoE PSE
====================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_CONTROL`` attribute is used
@@ -1888,6 +1941,20 @@ various existing products that document power consumption in watts rather than
classes. If power limit configuration based on classes is needed, the
conversion can be done in user space, for example by ethtool.
+When set, the optional ``ETHTOOL_A_C33_PSE_PRIO`` attributes is used to
+control the C33 PSE priority. Allowed priority value are between zero
+and the value of ``ETHTOOL_A_C33_PSE_PRIO_MAX`` attribute.
+
+A lower value indicates a higher priority, meaning that a priority value
+of 0 corresponds to the highest port priority.
+Port priority serves two functions:
+
+ - Power-up Order: After a reset, ports are powered up in order of their
+ priority from highest to lowest. Ports with higher priority
+ (lower values) power up first.
+ - Shutdown Order: When the power budget is exceeded, ports with lower
+ priority (higher values) are turned off first.
+
PSE_NTF
=======
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index 1ec5a0838f50..120d88e245b8 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -632,6 +632,9 @@ enum {
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES,
ETHTOOL_A_PSE_ID,
ETHTOOL_A_PSE_PW_D_ID,
+ ETHTOOL_A_PSE_BUDGET_EVAL_STRAT,
+ ETHTOOL_A_PSE_PRIO_MAX,
+ ETHTOOL_A_PSE_PRIO,
__ETHTOOL_A_PSE_CNT,
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 00b97712767d..7f9a8515659a 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -113,6 +113,12 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
len += st->c33_pw_limit_nb_ranges *
(nla_total_size(0) +
nla_total_size(sizeof(u32)) * 2);
+ if (st->budget_eval_strategy)
+ /* _PSE_BUDGET_EVAL_STRAT */
+ len += nla_total_size(sizeof(u32));
+ if (st->prio_max)
+ /* _PSE_PRIO_MAX + _PSE_PRIO */
+ len += nla_total_size(sizeof(u32)) * 2;
return len;
}
@@ -210,6 +216,16 @@ static int pse_fill_reply(struct sk_buff *skb,
pse_put_pw_limit_ranges(skb, st))
return -EMSGSIZE;
+ if (st->budget_eval_strategy > 0 &&
+ nla_put_u32(skb, ETHTOOL_A_PSE_BUDGET_EVAL_STRAT,
+ st->budget_eval_strategy))
+ return -EMSGSIZE;
+
+ if (st->prio_max > 0 &&
+ (nla_put_u32(skb, ETHTOOL_A_PSE_PRIO_MAX, st->prio_max) ||
+ nla_put_u32(skb, ETHTOOL_A_PSE_PRIO, st->prio)))
+ return -EMSGSIZE;
+
return 0;
}
@@ -231,6 +247,7 @@ const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1] = {
NLA_POLICY_RANGE(NLA_U32, ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED,
ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED),
[ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT] = { .type = NLA_U32 },
+ [ETHTOOL_A_PSE_PRIO] = { .type = NLA_U32 },
};
static int
@@ -279,6 +296,15 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
if (ret)
return ret;
+ if (tb[ETHTOOL_A_PSE_PRIO]) {
+ unsigned int prio;
+
+ prio = nla_get_u32(tb[ETHTOOL_A_PSE_PRIO]);
+ ret = pse_ethtool_set_prio(phydev->psec, info->extack, prio);
+ if (ret)
+ return ret;
+ }
+
if (tb[ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT]) {
unsigned int pw_limit;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (22 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 23/27] net: ethtool: Add PSE new budget evaluation strategy support feature Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
` (3 subsequent siblings)
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This patch extends the PSE callbacks by adding support for the newly
introduced pi_set_prio() callback, enabling the configuration of PSE PI
priorities. The current port priority is now also included in the status
information returned to users.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- New patch
---
drivers/net/pse-pd/pd692x0.c | 205 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 205 insertions(+)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index fc9e23927b3b..360c92354908 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pse-pd/pse.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
#define PD692X0_PSE_NAME "pd692x0_pse"
@@ -76,6 +78,8 @@ enum {
PD692X0_MSG_GET_PORT_CLASS,
PD692X0_MSG_GET_PORT_MEAS,
PD692X0_MSG_GET_PORT_PARAM,
+ PD692X0_MSG_GET_POWER_BANK,
+ PD692X0_MSG_SET_POWER_BANK,
/* add new message above here */
PD692X0_MSG_CNT
@@ -95,6 +99,8 @@ struct pd692x0_priv {
unsigned long last_cmd_key_time;
enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS];
+ struct regulator_dev *manager_reg[PD692X0_MAX_MANAGERS];
+ int manager_pw_budget[PD692X0_MAX_MANAGERS];
};
/* Template list of communication messages. The non-null bytes defined here
@@ -170,6 +176,16 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
.data = {0x4e, 0x4e, 0x4e, 0x4e,
0x4e, 0x4e, 0x4e, 0x4e},
},
+ [PD692X0_MSG_GET_POWER_BANK] = {
+ .key = PD692X0_KEY_REQ,
+ .sub = {0x07, 0x0b, 0x57},
+ .data = { 0, 0x4e, 0x4e, 0x4e,
+ 0x4e, 0x4e, 0x4e, 0x4e},
+ },
+ [PD692X0_MSG_SET_POWER_BANK] = {
+ .key = PD692X0_KEY_CMD,
+ .sub = {0x07, 0x0b, 0x57},
+ },
};
static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo)
@@ -739,6 +755,29 @@ pd692x0_pi_get_actual_pw(struct pse_controller_dev *pcdev, int id)
return (buf.data[0] << 4 | buf.data[1]) * 100;
}
+static int
+pd692x0_pi_get_prio(struct pse_controller_dev *pcdev, int id)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
+
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
+ msg.sub[2] = id;
+ ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -ERANGE;
+
+ /* PSE core priority start at 0 */
+ return buf.data[2] - 1;
+}
+
static struct pd692x0_msg_ver pd692x0_get_sw_version(struct pd692x0_priv *priv)
{
struct device *dev = &priv->client->dev;
@@ -766,6 +805,7 @@ static struct pd692x0_msg_ver pd692x0_get_sw_version(struct pd692x0_priv *priv)
struct pd692x0_manager {
struct device_node *port_node[PD692X0_MAX_MANAGER_PORTS];
+ struct device_node *node;
int nports;
};
@@ -857,6 +897,8 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv,
if (ret)
goto out;
+ of_node_get(node);
+ manager[manager_id].node = node;
nmanagers++;
}
@@ -869,6 +911,8 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv,
of_node_put(manager[i].port_node[j]);
manager[i].port_node[j] = NULL;
}
+ of_node_put(manager[i].node);
+ manager[i].node = NULL;
}
of_node_put(node);
@@ -876,6 +920,130 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv,
return ret;
}
+static const struct regulator_ops dummy_ops;
+
+static struct regulator_dev *
+pd692x0_register_manager_regulator(struct device *dev, char *reg_name,
+ struct device_node *node)
+{
+ struct regulator_init_data *rinit_data;
+ struct regulator_config rconfig = {0};
+ struct regulator_desc *rdesc;
+ struct regulator_dev *rdev;
+
+ rinit_data = devm_kzalloc(dev, sizeof(*rinit_data),
+ GFP_KERNEL);
+ if (!rinit_data)
+ return ERR_PTR(-ENOMEM);
+
+ rdesc = devm_kzalloc(dev, sizeof(*rdesc), GFP_KERNEL);
+ if (!rdesc)
+ return ERR_PTR(-ENOMEM);
+
+ rdesc->name = reg_name;
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->ops = &dummy_ops;
+ rdesc->owner = THIS_MODULE;
+
+ rinit_data->supply_regulator = "vmain";
+
+ rconfig.dev = dev;
+ rconfig.init_data = rinit_data;
+ rconfig.of_node = node;
+
+ rdev = devm_regulator_register(dev, rdesc, &rconfig);
+ if (IS_ERR(rdev)) {
+ dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to register regulator\n");
+ return rdev;
+ }
+
+ return rdev;
+}
+
+static int
+pd692x0_register_managers_regulator(struct pd692x0_priv *priv,
+ const struct pd692x0_manager *manager,
+ int nmanagers)
+{
+ struct device *dev = &priv->client->dev;
+ size_t reg_name_len;
+ int i;
+
+ /* Each regulator name len is dev name + 12 char +
+ * int max digit number (10) + 1
+ */
+ reg_name_len = strlen(dev_name(dev)) + 23;
+
+ for (i = 0; i < nmanagers; i++) {
+ struct regulator_dev *rdev;
+ char *reg_name;
+
+ reg_name = devm_kzalloc(dev, reg_name_len, GFP_KERNEL);
+ if (!reg_name)
+ return -ENOMEM;
+ snprintf(reg_name, 26, "pse-%s-manager%d", dev_name(dev), i);
+ rdev = pd692x0_register_manager_regulator(dev, reg_name,
+ manager[i].node);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ priv->manager_reg[i] = rdev;
+ }
+
+ return 0;
+}
+
+static int
+pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int pw)
+{
+ struct pd692x0_msg msg, buf;
+ int ret, pw_mW = pw / 1000;
+
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_POWER_BANK];
+ msg.data[0] = id;
+ ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
+ if (ret < 0)
+ return ret;
+
+ msg = pd692x0_msg_template_list[PD692X0_MSG_SET_POWER_BANK];
+ msg.data[0] = id;
+ msg.data[1] = pw_mW >> 8;
+ msg.data[2] = pw_mW & 0xff;
+ msg.data[3] = buf.sub[2];
+ msg.data[4] = buf.data[0];
+ msg.data[5] = buf.data[1];
+ msg.data[6] = buf.data[2];
+ msg.data[7] = buf.data[3];
+ return pd692x0_sendrecv_msg(priv, &msg, &buf);
+}
+
+static int
+pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers)
+{
+ int i, ret;
+
+ for (i = 0; i < nmanagers; i++) {
+ struct regulator *supply = priv->manager_reg[i]->supply;
+ int pw_budget;
+
+ pw_budget = regulator_get_power_budget(supply);
+ /* Max power budget per manager */
+ if (pw_budget > 6000000)
+ pw_budget = 6000000;
+ ret = regulator_request_power_budget(supply, pw_budget);
+ if (ret < 0)
+ return ret;
+
+ priv->manager_pw_budget[i] = pw_budget;
+ ret = pd692x0_conf_manager_power_budget(priv, i, pw_budget);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int
pd692x0_set_port_matrix(const struct pse_pi_pairset *pairset,
const struct pd692x0_manager *manager,
@@ -998,6 +1166,14 @@ static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
return ret;
nmanagers = ret;
+ ret = pd692x0_register_managers_regulator(priv, manager, nmanagers);
+ if (ret)
+ goto out;
+
+ ret = pd692x0_configure_managers(priv, nmanagers);
+ if (ret)
+ goto out;
+
ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix);
if (ret)
goto out;
@@ -1008,8 +1184,14 @@ static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
out:
for (i = 0; i < nmanagers; i++) {
+ struct regulator *supply = priv->manager_reg[i]->supply;
+
+ regulator_free_power_budget(supply,
+ priv->manager_pw_budget[i]);
+
for (j = 0; j < manager[i].nports; j++)
of_node_put(manager[i].port_node[j]);
+ of_node_put(manager[i].node);
}
return ret;
}
@@ -1071,6 +1253,25 @@ static int pd692x0_pi_set_pw_limit(struct pse_controller_dev *pcdev,
return pd692x0_sendrecv_msg(priv, &msg, &buf);
}
+static int pd692x0_pi_set_prio(struct pse_controller_dev *pcdev, int id,
+ unsigned int prio)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
+
+ msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
+ msg.sub[2] = id;
+ /* Controller priority from 1 to 3 */
+ msg.data[4] = prio + 1;
+
+ return pd692x0_sendrecv_msg(priv, &msg, &buf);
+}
+
static const struct pse_controller_ops pd692x0_ops = {
.setup_pi_matrix = pd692x0_setup_pi_matrix,
.pi_get_admin_state = pd692x0_pi_get_admin_state,
@@ -1084,6 +1285,8 @@ static const struct pse_controller_ops pd692x0_ops = {
.pi_get_pw_limit = pd692x0_pi_get_pw_limit,
.pi_set_pw_limit = pd692x0_pi_set_pw_limit,
.pi_get_pw_limit_ranges = pd692x0_pi_get_pw_limit_ranges,
+ .pi_get_prio = pd692x0_pi_get_prio,
+ .pi_set_prio = pd692x0_pi_set_prio,
};
#define PD692X0_FW_LINE_MAX_SZ 0xff
@@ -1500,6 +1703,8 @@ static int pd692x0_i2c_probe(struct i2c_client *client)
priv->pcdev.ops = &pd692x0_ops;
priv->pcdev.dev = dev;
priv->pcdev.types = ETHTOOL_PSE_C33;
+ priv->pcdev.supp_budget_eval_strategies = ETHTOOL_PSE_BUDGET_EVAL_STRAT_DYNAMIC;
+ priv->pcdev.pis_prio_max = 2;
ret = devm_pse_controller_register(dev, &priv->pcdev);
if (ret)
return dev_err_probe(dev, ret,
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (23 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-04 9:52 ` Krzysztof Kozlowski
2025-01-03 21:13 ` [PATCH net-next v4 26/27] net: pse-pd: tps23881: Add support for static port priority feature Kory Maincent
` (2 subsequent siblings)
27 siblings, 1 reply; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This patch adds the regulator supply parameter of the managers.
It updates also the example as the regulator supply of the PSE PIs
should be the managers itself and not an external regulator.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- New patch
---
.../devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml b/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml
index fd4244fceced..0dc0da32576b 100644
--- a/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml
+++ b/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml
@@ -68,6 +68,9 @@ properties:
"#size-cells":
const: 0
+ vmain-supply:
+ description: Regulator power supply for the PD69208X manager.
+
patternProperties:
'^port@[0-7]$':
type: object
@@ -106,10 +109,11 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
- manager@0 {
+ manager0: manager@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
+ vmain-supply = <&pse1_supply>;
phys0: port@0 {
reg = <0>;
@@ -128,7 +132,7 @@ examples:
};
};
- manager@1 {
+ manager1: manager@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -161,7 +165,7 @@ examples:
pairset-names = "alternative-a", "alternative-b";
pairsets = <&phys0>, <&phys1>;
polarity-supported = "MDI", "S";
- vpwr-supply = <&vpwr1>;
+ vpwr-supply = <&manager0>;
};
pse_pi1: pse-pi@1 {
reg = <1>;
@@ -169,7 +173,7 @@ examples:
pairset-names = "alternative-a";
pairsets = <&phys2>;
polarity-supported = "MDI";
- vpwr-supply = <&vpwr2>;
+ vpwr-supply = <&manager0>;
};
};
};
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 26/27] net: pse-pd: tps23881: Add support for static port priority feature
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (24 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description Kory Maincent
2025-01-04 11:37 ` [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Oleksij Rempel
27 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This patch enhances PSE callbacks by introducing support for the static
port priority feature. It extends interrupt management to handle and report
detection, classification, and disconnection events. Additionally, it
introduces the pi_get_pw_req() callback, which provides information about
the power requested by the Powered Devices.
Interrupt support is essential for the proper functioning of the TPS23881
controller. Without it, after a power-on (PWON), the controller will
no longer perform detection and classification. This could lead to
potential hazards, such as connecting a non-PoE device after a PoE device,
which might result in magic smoke.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
We may need a fix for the interrupt support in old version of Linux.
Change in v4:
- Fix variable type nit.
Change in v3:
- New patch
---
drivers/net/pse-pd/tps23881.c | 204 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 194 insertions(+), 10 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 122666719297..6012c58b47e8 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -19,20 +19,30 @@
#define TPS23881_REG_IT 0x0
#define TPS23881_REG_IT_MASK 0x1
+#define TPS23881_REG_IT_DISF BIT(2)
+#define TPS23881_REG_IT_DETC BIT(3)
+#define TPS23881_REG_IT_CLASC BIT(4)
#define TPS23881_REG_IT_IFAULT BIT(5)
#define TPS23881_REG_IT_SUPF BIT(7)
+#define TPS23881_REG_DET_EVENT 0x5
#define TPS23881_REG_FAULT 0x7
#define TPS23881_REG_SUPF_EVENT 0xb
#define TPS23881_REG_TSD BIT(7)
+#define TPS23881_REG_DISC 0xc
#define TPS23881_REG_PW_STATUS 0x10
#define TPS23881_REG_OP_MODE 0x12
+#define TPS23881_REG_DISC_EN 0x13
#define TPS23881_OP_MODE_SEMIAUTO 0xaaaa
#define TPS23881_REG_DIS_EN 0x13
#define TPS23881_REG_DET_CLA_EN 0x14
#define TPS23881_REG_GEN_MASK 0x17
+#define TPS23881_REG_CLCHE BIT(2)
+#define TPS23881_REG_DECHE BIT(3)
#define TPS23881_REG_NBITACC BIT(5)
#define TPS23881_REG_INTEN BIT(7)
#define TPS23881_REG_PW_EN 0x19
+#define TPS23881_REG_RESET 0x1a
+#define TPS23881_REG_CLRAIN BIT(7)
#define TPS23881_REG_2PAIR_POL1 0x1e
#define TPS23881_REG_PORT_MAP 0x26
#define TPS23881_REG_PORT_POWER 0x29
@@ -177,6 +187,7 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
+ int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -190,7 +201,22 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
BIT(chan % 4));
}
- return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
+ if (ret)
+ return ret;
+
+ /* Enable DC disconnect*/
+ chan = priv->port[id].chan[0];
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_DISC_EN);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_DISC_EN, val);
+ if (ret)
+ return ret;
+
+ return 0;
}
static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
@@ -223,6 +249,17 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
*/
mdelay(5);
+ /* Disable DC disconnect*/
+ chan = priv->port[id].chan[0];
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_DISC_EN);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_set_val(ret, chan, 0, 0, BIT(chan % 4));
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_DISC_EN, val);
+ if (ret)
+ return ret;
+
/* Enable detection and classification */
ret = i2c_smbus_read_word_data(client, TPS23881_REG_DET_CLA_EN);
if (ret < 0)
@@ -918,6 +955,47 @@ static int tps23881_setup_pi_matrix(struct pse_controller_dev *pcdev)
return ret;
}
+static int tps23881_power_class_table[] = {
+ -ERANGE,
+ 4000,
+ 7000,
+ 15500,
+ 30000,
+ 15500,
+ 15500,
+ -ERANGE,
+ 45000,
+ 60000,
+ 75000,
+ 90000,
+ 15500,
+ 45000,
+ -ERANGE,
+ -ERANGE,
+};
+
+static int tps23881_pi_get_pw_req(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ u8 reg, chan;
+ int ret;
+ u16 val;
+
+ /* For a 4-pair the classification need 5ms to be completed */
+ if (priv->port[id].is_4p)
+ mdelay(5);
+
+ chan = priv->port[id].chan[0];
+ reg = TPS23881_REG_DISC + (chan % 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_calc_val(ret, chan, 4, 0xf);
+ return tps23881_power_class_table[val];
+}
+
static const struct pse_controller_ops tps23881_ops = {
.setup_pi_matrix = tps23881_setup_pi_matrix,
.pi_enable = tps23881_pi_enable,
@@ -930,6 +1008,7 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_get_pw_limit = tps23881_pi_get_pw_limit,
.pi_set_pw_limit = tps23881_pi_set_pw_limit,
.pi_get_pw_limit_ranges = tps23881_pi_get_pw_limit_ranges,
+ .pi_get_pw_req = tps23881_pi_get_pw_req,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
@@ -1100,12 +1179,83 @@ static void tps23881_irq_event_over_current(struct tps23881_priv *priv,
ETHTOOL_PSE_EVENT_OVER_CURRENT);
}
+static void tps23881_irq_event_disconnection(struct tps23881_priv *priv,
+ u16 reg_val,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ u8 chans;
+
+ chans = tps23881_irq_export_chans_helper(reg_val, 4);
+ if (chans)
+ tps23881_set_notifs_helper(priv, chans, notifs, notifs_mask,
+ ETHTOOL_C33_PSE_EVENT_DISCONNECTION);
+}
+
+static int tps23881_irq_event_detection(struct tps23881_priv *priv,
+ u16 reg_val,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ enum ethtool_pse_events event;
+ int reg, ret, i, val;
+ unsigned long chans;
+
+ chans = tps23881_irq_export_chans_helper(reg_val, 0);
+ for_each_set_bit(i, &chans, TPS23881_MAX_CHANS) {
+ reg = TPS23881_REG_DISC + (i % 4);
+ ret = i2c_smbus_read_word_data(priv->client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_calc_val(ret, i, 0, 0xf);
+ /* If detection valid */
+ if (val == 0x4)
+ event = ETHTOOL_C33_PSE_EVENT_DETECTION;
+ else
+ event = ETHTOOL_C33_PSE_EVENT_DISCONNECTION;
+
+ tps23881_set_notifs_helper(priv, BIT(i), notifs,
+ notifs_mask, event);
+ }
+
+ return 0;
+}
+
+static int tps23881_irq_event_classification(struct tps23881_priv *priv,
+ u16 reg_val,
+ unsigned long *notifs,
+ unsigned long *notifs_mask)
+{
+ int reg, ret, val, i;
+ unsigned long chans;
+
+ chans = tps23881_irq_export_chans_helper(reg_val, 4);
+ for_each_set_bit(i, &chans, TPS23881_MAX_CHANS) {
+ reg = TPS23881_REG_DISC + (i % 4);
+ ret = i2c_smbus_read_word_data(priv->client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_calc_val(ret, i, 4, 0xf);
+ /* Do not report classification event for unknown class */
+ if (!val || val == 0x8 || val == 0xf)
+ continue;
+
+ tps23881_set_notifs_helper(priv, BIT(i), notifs,
+ notifs_mask,
+ ETHTOOL_C33_PSE_EVENT_CLASSIFICATION);
+ }
+
+ return 0;
+}
+
static int tps23881_irq_event_handler(struct tps23881_priv *priv, u16 reg,
unsigned long *notifs,
unsigned long *notifs_mask)
{
struct i2c_client *client = priv->client;
- int ret;
+ int ret, val;
/* The Supply event bit is repeated twice so we only need to read
* the one from the first byte.
@@ -1117,13 +1267,33 @@ static int tps23881_irq_event_handler(struct tps23881_priv *priv, u16 reg,
tps23881_irq_event_over_temp(priv, ret, notifs, notifs_mask);
}
- if (reg & (TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_IFAULT << 8)) {
+ if (reg & (TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_IFAULT << 8 |
+ TPS23881_REG_IT_DISF | TPS23881_REG_IT_DISF << 8)) {
ret = i2c_smbus_read_word_data(client, TPS23881_REG_FAULT);
if (ret < 0)
return ret;
tps23881_irq_event_over_current(priv, ret, notifs, notifs_mask);
+
+ tps23881_irq_event_disconnection(priv, ret, notifs, notifs_mask);
}
+ if (reg & (TPS23881_REG_IT_DETC | TPS23881_REG_IT_DETC << 8 |
+ TPS23881_REG_IT_CLASC | TPS23881_REG_IT_CLASC << 8)) {
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_DET_EVENT);
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+ ret = tps23881_irq_event_detection(priv, val, notifs,
+ notifs_mask);
+ if (ret)
+ return ret;
+
+ ret = tps23881_irq_event_classification(priv, val, notifs,
+ notifs_mask);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -1169,7 +1339,14 @@ static int tps23881_setup_irq(struct tps23881_priv *priv, int irq)
int ret;
u16 val;
- val = TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_SUPF;
+ if (!irq) {
+ dev_err(&client->dev, "interrupt is missing");
+ return -EINVAL;
+ }
+
+ val = TPS23881_REG_IT_IFAULT | TPS23881_REG_IT_SUPF |
+ TPS23881_REG_IT_DETC | TPS23881_REG_IT_CLASC |
+ TPS23881_REG_IT_DISF;
val |= val << 8;
ret = i2c_smbus_write_word_data(client, TPS23881_REG_IT_MASK, val);
if (ret)
@@ -1179,11 +1356,19 @@ static int tps23881_setup_irq(struct tps23881_priv *priv, int irq)
if (ret < 0)
return ret;
- val = (u16)(ret | TPS23881_REG_INTEN | TPS23881_REG_INTEN << 8);
+ val = TPS23881_REG_INTEN | TPS23881_REG_CLCHE | TPS23881_REG_DECHE;
+ val |= val << 8;
+ val |= (u16)ret;
ret = i2c_smbus_write_word_data(client, TPS23881_REG_GEN_MASK, val);
if (ret < 0)
return ret;
+ /* Reset interrupts registers */
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_RESET,
+ TPS23881_REG_CLRAIN);
+ if (ret < 0)
+ return ret;
+
return devm_pse_irq_helper(&priv->pcdev, irq, 0, &irq_desc);
}
@@ -1261,17 +1446,16 @@ static int tps23881_i2c_probe(struct i2c_client *client)
priv->pcdev.dev = dev;
priv->pcdev.types = ETHTOOL_PSE_C33;
priv->pcdev.nr_lines = TPS23881_MAX_CHANS;
+ priv->pcdev.supp_budget_eval_strategies = ETHTOOL_PSE_BUDGET_EVAL_STRAT_STATIC;
ret = devm_pse_controller_register(dev, &priv->pcdev);
if (ret) {
return dev_err_probe(dev, ret,
"failed to register PSE controller\n");
}
- if (client->irq) {
- ret = tps23881_setup_irq(priv, client->irq);
- if (ret)
- return ret;
- }
+ ret = tps23881_setup_irq(priv, client->irq);
+ if (ret)
+ return ret;
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (25 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 26/27] net: pse-pd: tps23881: Add support for static port priority feature Kory Maincent
@ 2025-01-03 21:13 ` Kory Maincent
2025-01-04 9:44 ` Krzysztof Kozlowski
2025-01-04 11:37 ` [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Oleksij Rempel
27 siblings, 1 reply; 41+ messages in thread
From: Kory Maincent @ 2025-01-03 21:13 UTC (permalink / raw)
To: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree,
Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Add an interrupt property to the device tree bindings for the TI TPS23881
PSE controller. The interrupt is primarily used to detect classification
and disconnection events, which are essential for managing the PSE
controller in compliance with the PoE standard.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v3:
- New patch
---
Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml b/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml
index d08abcb01211..19d25ded4e58 100644
--- a/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml
+++ b/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml
@@ -20,6 +20,9 @@ properties:
reg:
maxItems: 1
+ interrupts:
+ maxItems: 1
+
'#pse-cells':
const: 1
@@ -62,6 +65,7 @@ unevaluatedProperties: false
required:
- compatible
- reg
+ - interrupts
examples:
- |
@@ -72,6 +76,8 @@ examples:
ethernet-pse@20 {
compatible = "ti,tps23881";
reg = <0x20>;
+ interrupts = <8 0>;
+ interrupt-parent = <&gpiog>;
channels {
#address-cells = <1>;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-03 21:13 ` [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
@ 2025-01-04 9:42 ` Krzysztof Kozlowski
2025-01-04 15:50 ` Kory Maincent
2025-01-04 9:43 ` Krzysztof Kozlowski
1 sibling, 1 reply; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-04 9:42 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On Fri, Jan 03, 2025 at 10:13:07PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> Introduce a new property to describe the power budget of the regulator.
> This property will allow power management support for regulator consumers
> like PSE controllers, enabling them to make decisions based on the
> available power capacity.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> ---
>
> Changes in v3:
> - Add type.
> - Add unit in the name.
>
> Changes in v2:
> - new patch.
> ---
> Documentation/devicetree/bindings/regulator/regulator.yaml | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml
> index 1ef380d1515e..c5a6b24ebe7b 100644
> --- a/Documentation/devicetree/bindings/regulator/regulator.yaml
> +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
> @@ -34,6 +34,11 @@ properties:
> regulator-input-current-limit-microamp:
> description: maximum input current regulator allows
>
> + regulator-power-budget-miniwatt:
What sort of quantity prefix is a "mini"? How much is a mini?
> + description: power budget of the regulator
> + $ref: /schemas/types.yaml#/definitions/uint32
This should not be needed. Use proper unit from dtschema.
> +
> +
Just one blank line.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-03 21:13 ` [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
2025-01-04 9:42 ` Krzysztof Kozlowski
@ 2025-01-04 9:43 ` Krzysztof Kozlowski
2025-01-04 15:37 ` Kory Maincent
1 sibling, 1 reply; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-04 9:43 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On Fri, Jan 03, 2025 at 10:13:07PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> Introduce a new property to describe the power budget of the regulator.
> This property will allow power management support for regulator consumers
> like PSE controllers, enabling them to make decisions based on the
> available power capacity.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Please use same SoB as From. You might need to configure your Git
correctly, first of all.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
2025-01-03 21:13 ` [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description Kory Maincent
@ 2025-01-04 9:44 ` Krzysztof Kozlowski
2025-02-05 14:18 ` Kory Maincent
0 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-04 9:44 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On Fri, Jan 03, 2025 at 10:13:16PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> Add an interrupt property to the device tree bindings for the TI TPS23881
> PSE controller. The interrupt is primarily used to detect classification
> and disconnection events, which are essential for managing the PSE
> controller in compliance with the PoE standard.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> ---
>
> Change in v3:
> - New patch
> ---
> Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml b/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml
> index d08abcb01211..19d25ded4e58 100644
> --- a/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml
> +++ b/Documentation/devicetree/bindings/net/pse-pd/ti,tps23881.yaml
> @@ -20,6 +20,9 @@ properties:
> reg:
> maxItems: 1
>
> + interrupts:
> + maxItems: 1
> +
> '#pse-cells':
> const: 1
>
> @@ -62,6 +65,7 @@ unevaluatedProperties: false
> required:
> - compatible
> - reg
> + - interrupts
Why? That's an ABI change. Commit msg mentions something like "essential
for standard" so are you saying nothing here was working according to
standard before?
>
> examples:
> - |
> @@ -72,6 +76,8 @@ examples:
> ethernet-pse@20 {
> compatible = "ti,tps23881";
> reg = <0x20>;
> + interrupts = <8 0>;
This looks like standard flag, so use standard define and then note that
NONE is usually not a correct interrupt type.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2025-01-03 21:13 ` [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
@ 2025-01-04 9:52 ` Krzysztof Kozlowski
2025-02-05 14:05 ` Kory Maincent
0 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-04 9:52 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On Fri, Jan 03, 2025 at 10:13:14PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> This patch adds the regulator supply parameter of the managers.
Please do not use "This commit/patch/change", but imperative mood. See
longer explanation here:
https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
> It updates also the example as the regulator supply of the PSE PIs
> should be the managers itself and not an external regulator.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> ---
>
> Changes in v3:
> - New patch
> ---
> .../devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml b/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml
> index fd4244fceced..0dc0da32576b 100644
> --- a/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml
> +++ b/Documentation/devicetree/bindings/net/pse-pd/microchip,pd692x0.yaml
> @@ -68,6 +68,9 @@ properties:
> "#size-cells":
> const: 0
>
> + vmain-supply:
> + description: Regulator power supply for the PD69208X manager.
s/Regulator//
Keep it simple, no need to state obvious. What is not obvious here is
why there are no main device supplies (VDD, VDDA).
And what about VAUX5 and VAUX3P3? So basically the description is not
only redundant but actually incorrect because it suggests it is entire
supply, while there are others.
> +
> patternProperties:
> '^port@[0-7]$':
> type: object
> @@ -106,10 +109,11 @@ examples:
> #address-cells = <1>;
> #size-cells = <0>;
>
> - manager@0 {
> + manager0: manager@0 {
> reg = <0>;
> #address-cells = <1>;
> #size-cells = <0>;
> + vmain-supply = <&pse1_supply>;
>
> phys0: port@0 {
> reg = <0>;
> @@ -128,7 +132,7 @@ examples:
> };
> };
>
> - manager@1 {
> + manager1: manager@1 {
Not used.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
` (26 preceding siblings ...)
2025-01-03 21:13 ` [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description Kory Maincent
@ 2025-01-04 11:37 ` Oleksij Rempel
2025-01-04 15:16 ` Kory Maincent
27 siblings, 1 reply; 41+ messages in thread
From: Oleksij Rempel @ 2025-01-04 11:37 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Jonathan Corbet, Donald Hunter, Rob Herring,
Andrew Lunn, Simon Horman, Heiner Kallweit, Russell King,
Liam Girdwood, Mark Brown, Krzysztof Kozlowski, Conor Dooley,
Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree, Kalesh AP
Hi Kory,
please, split this patch set. Some of them can be already taken. The
upper limit for the patch set is 15 patches.
Regards,
Oleksij
On Fri, Jan 03, 2025 at 10:12:49PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> This series brings support for budget evaluation strategy in the PSE
> subsystem. PSE controllers can set priorities to decide which ports should
> be turned off in case of special events like over-current.
>
> I have added regulator maintainers to have their opinion on adding power
> budget regulator constraint see patches 17 and 18.
> There are also a core regulator change along the way patch 16.
> I suppose I will need to merge them through the regulator tree.
> Will it be possible to create an immutable tag to have this PSE series
> based on them?
>
> This patch series adds support for two budget evaluation strategy.
> 1. Static Method:
>
> This method involves distributing power based on PD classification.
> It’s straightforward and stable, the PSE core keeping track of the
> budget and subtracting the power requested by each PD’s class.
>
> Advantages: Every PD gets its promised power at any time, which
> guarantees reliability.
>
> Disadvantages: PD classification steps are large, meaning devices
> request much more power than they actually need. As a result, the power
> supply may only operate at, say, 50% capacity, which is inefficient and
> wastes money.
>
> 2. Dynamic Method:
>
> To address the inefficiencies of the static method, vendors like
> Microchip have introduced dynamic power budgeting, as seen in the
> PD692x0 firmware. This method monitors the current consumption per port
> and subtracts it from the available power budget. When the budget is
> exceeded, lower-priority ports are shut down.
>
> Advantages: This method optimizes resource utilization, saving costs.
>
> Disadvantages: Low-priority devices may experience instability.
>
> The UAPI allows adding support for software port priority mode managed from
> userspace later if needed.
>
> The patch series is based on this fix merged in net:
> https://lore.kernel.org/netdev/20241220170400.291705-1-kory.maincent@bootlin.com/
>
> Several Reviewed-by have been removed due to the changes.
>
> Thanks Oleksij for your pointers.
>
> Patches 1-9: Cosmetics.
> Patch 10: Adds support for last supported features in the TPS23881 drivers.
> Patches 11,12: Add support for PSE index in PSE core and ethtool.
> Patches 12-14: Add support for interrupt event report in PSE core, ethtool
> and ethtool specs.
> Patch 15: Adds support for interrupt and event report in TPS23881 driver.
> Patch 16: Fix regulator resolve supply
> Patches 17,18: Add support for power budget in regulator framework.
> Patch 19: Cosmetic.
> Patches 20,21: Add support for PSE power domain in PSE core and ethtool.
> Patches 22,23: Add support for port priority in PSE core, ethtool and
> ethtool specs.
> Patches 24,25: Add support for port priority in PD692x0 drivers.
> Patches 26,27: Add support for port priority in TPS23881 drivers.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> ---
> Changes in v4:
> - Remove disconnection policy.
> - Rename port priority mode to budget evaluation strategy.
> - Add cosmetic changes in PSE core.
> - Add support for port priority in PD692x0 driver.
> - Link to v3: https://lore.kernel.org/r/20241121-feature_poe_port_prio-v3-0-83299fa6967c@bootlin.com
>
> Changes in v3:
> - Move power budget to regulator core.
> - Add disconnection policies with PIs using the same priority.
> - Several fixes on the TPS23881 drivers.
> - Several new cosmetic patches.
> - Link to v2: https://lore.kernel.org/r/20241030-feature_poe_port_prio-v2-0-9559622ee47a@bootlin.com
>
> Changes in v2:
> - Rethink the port priority management.
> - Add PSE id.
> - Add support for PSE power domains.
> - Add get power budget regulator constraint.
> - Link to v1: https://lore.kernel.org/r/20241002-feature_poe_port_prio-v1-0-787054f74ed5@bootlin.com
>
> ---
> Kory Maincent (27):
> net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration
> net: pse-pd: Avoid setting max_uA in regulator constraints
> net: pse-pd: Add power limit check
> net: pse-pd: tps23881: Simplify function returns by removing redundant checks
> net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel
> net: pse-pd: tps23881: Add missing configuration register after disable
> net: pse-pd: Use power limit at driver side instead of current limit
> net: pse-pd: Split ethtool_get_status into multiple callbacks
> net: pse-pd: Remove is_enabled callback from drivers
> net: pse-pd: tps23881: Add support for power limit and measurement features
> net: pse-pd: Add support for PSE device index
> net: ethtool: Add support for new PSE device index description
> net: ethtool: Add support for ethnl_info_init_ntf helper function
> net: pse-pd: Add support for reporting events
> net: pse-pd: tps23881: Add support for PSE events and interrupts
> regulator: core: Resolve supply using of_node from regulator_config
> regulator: Add support for power budget description
> regulator: dt-bindings: Add regulator-power-budget property
> net: pse-pd: Fix missing PI of_node description
> net: pse-pd: Add support for PSE power domains
> net: ethtool: Add support for new power domains index description
> net: pse-pd: Add support for getting budget evaluation strategies
> net: ethtool: Add PSE new budget evaluation strategy support feature
> net: pse-pd: pd692x0: Add support for PSE PI priority feature
> dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
> net: pse-pd: tps23881: Add support for static port priority feature
> dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
>
> .../bindings/net/pse-pd/microchip,pd692x0.yaml | 12 +-
> .../bindings/net/pse-pd/ti,tps23881.yaml | 6 +
> .../devicetree/bindings/regulator/regulator.yaml | 5 +
> Documentation/netlink/specs/ethtool.yaml | 52 +
> Documentation/networking/ethtool-netlink.rst | 94 ++
> drivers/net/mdio/fwnode_mdio.c | 26 +-
> drivers/net/pse-pd/pd692x0.c | 423 ++++++--
> drivers/net/pse-pd/pse_core.c | 1029 ++++++++++++++++++--
> drivers/net/pse-pd/pse_regulator.c | 23 +-
> drivers/net/pse-pd/tps23881.c | 799 +++++++++++++--
> drivers/regulator/core.c | 128 ++-
> drivers/regulator/of_regulator.c | 3 +
> include/linux/ethtool.h | 47 +
> include/linux/ethtool_netlink.h | 9 +
> include/linux/pse-pd/pse.h | 171 +++-
> include/linux/regulator/consumer.h | 21 +
> include/linux/regulator/driver.h | 2 +
> include/linux/regulator/machine.h | 2 +
> include/uapi/linux/ethtool.h | 54 +
> include/uapi/linux/ethtool_netlink.h | 1 -
> include/uapi/linux/ethtool_netlink_generated.h | 15 +
> net/ethtool/common.c | 12 +
> net/ethtool/common.h | 2 +
> net/ethtool/netlink.c | 7 +-
> net/ethtool/netlink.h | 2 +
> net/ethtool/pse-pd.c | 98 +-
> net/ethtool/strset.c | 5 +
> 27 files changed, 2698 insertions(+), 350 deletions(-)
> ---
> base-commit: 2e22297376fe1aa562799c774c3baac9b6db238b
> change-id: 20240913-feature_poe_port_prio-a51aed7332ec
>
> Best regards,
> --
> Köry Maincent, Bootlin
> Embedded Linux and kernel engineering
> https://bootlin.com
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy
2025-01-04 11:37 ` [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Oleksij Rempel
@ 2025-01-04 15:16 ` Kory Maincent
0 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-01-04 15:16 UTC (permalink / raw)
To: Oleksij Rempel
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Jonathan Corbet, Donald Hunter, Rob Herring,
Andrew Lunn, Simon Horman, Heiner Kallweit, Russell King,
Liam Girdwood, Mark Brown, Krzysztof Kozlowski, Conor Dooley,
Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, devicetree, Kalesh AP
On Sat, 4 Jan 2025 12:37:00 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> Hi Kory,
>
> please, split this patch set. Some of them can be already taken. The
> upper limit for the patch set is 15 patches.
Ack, I will!
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-04 9:43 ` Krzysztof Kozlowski
@ 2025-01-04 15:37 ` Kory Maincent
2025-01-05 9:04 ` Krzysztof Kozlowski
0 siblings, 1 reply; 41+ messages in thread
From: Kory Maincent @ 2025-01-04 15:37 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On Sat, 4 Jan 2025 10:43:25 +0100
Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On Fri, Jan 03, 2025 at 10:13:07PM +0100, Kory Maincent wrote:
> > From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
> >
> > Introduce a new property to describe the power budget of the regulator.
> > This property will allow power management support for regulator consumers
> > like PSE controllers, enabling them to make decisions based on the
> > available power capacity.
> >
> > Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
>
> Please use same SoB as From. You might need to configure your Git
> correctly, first of all.
That was not an issue in the previous series. Net maintainers and you were ok
with this:
https://lore.kernel.org/linux-doc/20240417-feature_poe-v9-11-242293fd1900@bootlin.com/
Does it bother you now?
If so I will fix it.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-04 9:42 ` Krzysztof Kozlowski
@ 2025-01-04 15:50 ` Kory Maincent
2025-01-05 9:06 ` Krzysztof Kozlowski
0 siblings, 1 reply; 41+ messages in thread
From: Kory Maincent @ 2025-01-04 15:50 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On Sat, 4 Jan 2025 10:42:32 +0100
Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On Fri, Jan 03, 2025 at 10:13:07PM +0100, Kory Maincent wrote:
> > From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
> >
> > Introduce a new property to describe the power budget of the regulator.
> > This property will allow power management support for regulator consumers
> > like PSE controllers, enabling them to make decisions based on the
> > available power capacity.
> >
> > Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> > ---
> >
> > Changes in v3:
> > - Add type.
> > - Add unit in the name.
> >
> > Changes in v2:
> > - new patch.
> > ---
> > Documentation/devicetree/bindings/regulator/regulator.yaml | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml
> > b/Documentation/devicetree/bindings/regulator/regulator.yaml index
> > 1ef380d1515e..c5a6b24ebe7b 100644 ---
> > a/Documentation/devicetree/bindings/regulator/regulator.yaml +++
> > b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -34,6
> > +34,11 @@ properties: regulator-input-current-limit-microamp:
> > description: maximum input current regulator allows
> >
> > + regulator-power-budget-miniwatt:
>
> What sort of quantity prefix is a "mini"? How much is a mini?
Oops, that is a brain fart sorry for this. Of course it is milliwatt.
>
> > + description: power budget of the regulator
> > + $ref: /schemas/types.yaml#/definitions/uint32
>
> This should not be needed. Use proper unit from dtschema.
Ok, I was mistaken. There are bindings with this ref in this file, so I thought
it was needed. I will remove it.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-04 15:37 ` Kory Maincent
@ 2025-01-05 9:04 ` Krzysztof Kozlowski
0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-05 9:04 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On 04/01/2025 16:37, Kory Maincent wrote:
> On Sat, 4 Jan 2025 10:43:25 +0100
> Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
>> On Fri, Jan 03, 2025 at 10:13:07PM +0100, Kory Maincent wrote:
>>> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>>>
>>> Introduce a new property to describe the power budget of the regulator.
>>> This property will allow power management support for regulator consumers
>>> like PSE controllers, enabling them to make decisions based on the
>>> available power capacity.
>>>
>>> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
>>
>> Please use same SoB as From. You might need to configure your Git
>> correctly, first of all.
>
> That was not an issue in the previous series. Net maintainers and you were ok
> with this:
> https://lore.kernel.org/linux-doc/20240417-feature_poe-v9-11-242293fd1900@bootlin.com/
>
> Does it bother you now?
> If so I will fix it.
I don't think I paid attention to it before and I am not sure whether it
matters, but I just don't want to wonder about it in the first place. I
am not a lawyer and my knowledge on this topic is rather amateurish, so
why would we even need to consider legal implications of different SoB
from "From", if you could just fix it and make it
simple/obvious/explicit/un-doubtful?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property
2025-01-04 15:50 ` Kory Maincent
@ 2025-01-05 9:06 ` Krzysztof Kozlowski
0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-05 9:06 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On 04/01/2025 16:50, Kory Maincent wrote:
> On Sat, 4 Jan 2025 10:42:32 +0100
> Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
>> On Fri, Jan 03, 2025 at 10:13:07PM +0100, Kory Maincent wrote:
>>> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>>>
>>> Introduce a new property to describe the power budget of the regulator.
>>> This property will allow power management support for regulator consumers
>>> like PSE controllers, enabling them to make decisions based on the
>>> available power capacity.
>>>
>>> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
>>> ---
>>>
>>> Changes in v3:
>>> - Add type.
>>> - Add unit in the name.
>>>
>>> Changes in v2:
>>> - new patch.
>>> ---
>>> Documentation/devicetree/bindings/regulator/regulator.yaml | 5 +++++
>>> 1 file changed, 5 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml
>>> b/Documentation/devicetree/bindings/regulator/regulator.yaml index
>>> 1ef380d1515e..c5a6b24ebe7b 100644 ---
>>> a/Documentation/devicetree/bindings/regulator/regulator.yaml +++
>>> b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -34,6
>>> +34,11 @@ properties: regulator-input-current-limit-microamp:
>>> description: maximum input current regulator allows
>>>
>>> + regulator-power-budget-miniwatt:
>>
>> What sort of quantity prefix is a "mini"? How much is a mini?
>
> Oops, that is a brain fart sorry for this. Of course it is milliwatt.
>
>>
>>> + description: power budget of the regulator
>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>
>> This should not be needed. Use proper unit from dtschema.
>
> Ok, I was mistaken. There are bindings with this ref in this file, so I thought
> it was needed. I will remove it.
If the unit is not in the property-units of dtschema, you will have a
warning, but then please send a pull request (patch could work as well
probably) to dtschema adding it... but I am sure that milliwatt is there.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2025-01-04 9:52 ` Krzysztof Kozlowski
@ 2025-02-05 14:05 ` Kory Maincent
0 siblings, 0 replies; 41+ messages in thread
From: Kory Maincent @ 2025-02-05 14:05 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
Hello Krzysztof,
On Sat, 4 Jan 2025 10:52:55 +0100
Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On Fri, Jan 03, 2025 at 10:13:14PM +0100, Kory Maincent wrote:
> > From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
> >
> > This patch adds the regulator supply parameter of the managers.
>
> > + vmain-supply:
> > + description: Regulator power supply for the PD69208X manager.
>
> s/Regulator//
> Keep it simple, no need to state obvious. What is not obvious here is
> why there are no main device supplies (VDD, VDDA).
>
> And what about VAUX5 and VAUX3P3? So basically the description is not
> only redundant but actually incorrect because it suggests it is entire
> supply, while there are others.
VMAIN can be the only power supply, with VAUX5 and VAUX3P3 derived internally
from VMAIN. However having the descriptions of all the regulator supplies is
indeed maybe better. I will update the patch accordingly.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
2025-01-04 9:44 ` Krzysztof Kozlowski
@ 2025-02-05 14:18 ` Kory Maincent
2025-02-05 16:35 ` Krzysztof Kozlowski
0 siblings, 1 reply; 41+ messages in thread
From: Kory Maincent @ 2025-02-05 14:18 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
Hello Krzysztof,
On Sat, 4 Jan 2025 10:44:49 +0100
Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On Fri, Jan 03, 2025 at 10:13:16PM +0100, Kory Maincent wrote:
> > From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
> >
> > Add an interrupt property to the device tree bindings for the TI TPS23881
> > PSE controller. The interrupt is primarily used to detect classification
> > and disconnection events, which are essential for managing the PSE
> > controller in compliance with the PoE standard.
> >
> > @@ -62,6 +65,7 @@ unevaluatedProperties: false
> > required:
> > - compatible
> > - reg
> > + - interrupts
>
> Why? That's an ABI change. Commit msg mentions something like "essential
> for standard" so are you saying nothing here was working according to
> standard before?
Yes indeed, the disconnection management did not follow the standard. Without
this series, the power on the ports of this controller is not shut down after a
Powered Device disconnection. Unfortunately, I did not noticed this before.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
2025-02-05 14:18 ` Kory Maincent
@ 2025-02-05 16:35 ` Krzysztof Kozlowski
0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-05 16:35 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Simon Horman, Heiner Kallweit,
Russell King, Liam Girdwood, Mark Brown, Krzysztof Kozlowski,
Conor Dooley, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier, devicetree
On 05/02/2025 15:18, Kory Maincent wrote:
>>> Add an interrupt property to the device tree bindings for the TI TPS23881
>>> PSE controller. The interrupt is primarily used to detect classification
>>> and disconnection events, which are essential for managing the PSE
>>> controller in compliance with the PoE standard.
>>>
>>> @@ -62,6 +65,7 @@ unevaluatedProperties: false
>>> required:
>>> - compatible
>>> - reg
>>> + - interrupts
>>
>> Why? That's an ABI change. Commit msg mentions something like "essential
>> for standard" so are you saying nothing here was working according to
>> standard before?
>
> Yes indeed, the disconnection management did not follow the standard. Without
> this series, the power on the ports of this controller is not shut down after a
> Powered Device disconnection. Unfortunately, I did not noticed this before.
This would be useful part of commit msg.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2025-02-05 16:35 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-03 21:12 [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 02/27] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 03/27] net: pse-pd: Add power limit check Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 04/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 05/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 06/27] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 07/27] net: pse-pd: Use power limit at driver side instead of current limit Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 08/27] net: pse-pd: Split ethtool_get_status into multiple callbacks Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 09/27] net: pse-pd: Remove is_enabled callback from drivers Kory Maincent
2025-01-03 21:12 ` [PATCH net-next v4 10/27] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 11/27] net: pse-pd: Add support for PSE device index Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 12/27] net: ethtool: Add support for new PSE device index description Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 13/27] net: ethtool: Add support for ethnl_info_init_ntf helper function Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 14/27] net: pse-pd: Add support for reporting events Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 15/27] net: pse-pd: tps23881: Add support for PSE events and interrupts Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 16/27] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 17/27] regulator: Add support for power budget description Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 18/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
2025-01-04 9:42 ` Krzysztof Kozlowski
2025-01-04 15:50 ` Kory Maincent
2025-01-05 9:06 ` Krzysztof Kozlowski
2025-01-04 9:43 ` Krzysztof Kozlowski
2025-01-04 15:37 ` Kory Maincent
2025-01-05 9:04 ` Krzysztof Kozlowski
2025-01-03 21:13 ` [PATCH net-next v4 19/27] net: pse-pd: Fix missing PI of_node description Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 20/27] net: pse-pd: Add support for PSE power domains Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 21/27] net: ethtool: Add support for new power domains index description Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 22/27] net: pse-pd: Add support for getting budget evaluation strategies Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 23/27] net: ethtool: Add PSE new budget evaluation strategy support feature Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
2025-01-04 9:52 ` Krzysztof Kozlowski
2025-02-05 14:05 ` Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 26/27] net: pse-pd: tps23881: Add support for static port priority feature Kory Maincent
2025-01-03 21:13 ` [PATCH net-next v4 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description Kory Maincent
2025-01-04 9:44 ` Krzysztof Kozlowski
2025-02-05 14:18 ` Kory Maincent
2025-02-05 16:35 ` Krzysztof Kozlowski
2025-01-04 11:37 ` [PATCH net-next v4 00/27] Add support for PSE budget evaluation strategy Oleksij Rempel
2025-01-04 15:16 ` Kory Maincent
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).