* [PATCH RFC net-next v3 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 02/27] regulator: core: Ignore unset max_uA constraints in current limit check Kory Maincent
` (26 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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] 60+ messages in thread* [PATCH RFC net-next v3 02/27] regulator: core: Ignore unset max_uA constraints in current limit check
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 03/27] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
` (25 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
We should only consider max_uA constraints if they are explicitly defined.
In cases where it is not set, we should assume the regulator has no current
limit.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v3:
- New patch
---
drivers/regulator/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 1179766811f5..2948a7eca734 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -497,7 +497,8 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
return -EPERM;
}
- if (*max_uA > rdev->constraints->max_uA)
+ if (*max_uA > rdev->constraints->max_uA &&
+ rdev->constraints->max_uA)
*max_uA = rdev->constraints->max_uA;
if (*min_uA < rdev->constraints->min_uA)
*min_uA = rdev->constraints->min_uA;
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* [PATCH RFC net-next v3 03/27] net: pse-pd: Avoid setting max_uA in regulator constraints
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 01/27] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 02/27] regulator: core: Ignore unset max_uA constraints in current limit check Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-23 6:29 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 04/27] net: pse-pd: Add power limit check Kory Maincent
` (24 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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] 60+ messages in thread* Re: [PATCH RFC net-next v3 03/27] net: pse-pd: Avoid setting max_uA in regulator constraints
2024-11-21 14:42 ` [PATCH RFC net-next v3 03/27] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
@ 2024-11-23 6:29 ` Oleksij Rempel
2024-11-24 11:47 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-23 6:29 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
Hi Kory,
On Thu, Nov 21, 2024 at 03:42:29PM +0100, Kory Maincent wrote:
> 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.
Not enough coffee :) I still didn't correctly understood the problem.
MAX_PI_CURRENT is the hard limit according to the standard, so it is the
intial limit anyway. Why it is bad to set it on registration? It feels
still better compared to have no limit on init. Or do i'm missing
things?
Regards,
Oleksij
--
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] 60+ messages in thread
* Re: [PATCH RFC net-next v3 03/27] net: pse-pd: Avoid setting max_uA in regulator constraints
2024-11-23 6:29 ` Oleksij Rempel
@ 2024-11-24 11:47 ` Kory Maincent
0 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-24 11:47 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
Hello Oleksij,
On Sat, 23 Nov 2024 07:29:29 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> Hi Kory,
>
> On Thu, Nov 21, 2024 at 03:42:29PM +0100, Kory Maincent wrote:
> > 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.
>
> Not enough coffee :) I still didn't correctly understood the problem.
Don't worry, if you don't understand as a PSE Maintainer no one will. The cause
is the commit message.
> MAX_PI_CURRENT is the hard limit according to the standard, so it is the
> intial limit anyway. Why it is bad to set it on registration? It feels
> still better compared to have no limit on init. Or do i'm missing
> things?
Using constraints.max_uA to set the max current limit will cause regulator core
to call the set_current_limit callback when registering a regulator. This call
will be done using MAX_PI_CURRENT (1,92A) limit.
Is see two issues to this:
- There is a chance the power budget of the supply will be not sufficient for
all the PIs configured to MAX_PI_CURRENT. On that case the power budget of
the supply is exceeded and the next PI of the PSE power domain can't probe
with success. It will have -ERANGE error returned from
devm_regulator_register() call. So the PSE driver can't probe with success.
- The PI current limit is reset at each boot. The next patch series will tackle
permanent configuration feature of the PD692x0. This will conflict as
we want to keep the PI current limit saved.
Another solution would be to add a no_apply_max_uA_constraint flag.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 04/27] net: pse-pd: Add power limit check
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (2 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 03/27] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-23 6:31 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 05/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
` (23 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
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] 60+ messages in thread* Re: [PATCH RFC net-next v3 04/27] net: pse-pd: Add power limit check
2024-11-21 14:42 ` [PATCH RFC net-next v3 04/27] net: pse-pd: Add power limit check Kory Maincent
@ 2024-11-23 6:31 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-23 6:31 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:30PM +0100, Kory Maincent wrote:
> 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.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Acled-by: Oleksij Rempel <o.rempel@pengutronix.de>
Thank you!
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 05/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (3 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 04/27] net: pse-pd: Add power limit check Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 06/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent (Dent Project)
` (22 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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>
---
drivers/net/pse-pd/tps23881.c | 26 +++++---------------------
1 file changed, 5 insertions(+), 21 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 5c4e88be46ee..20eab9857817 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -118,11 +118,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)
@@ -488,7 +484,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;
@@ -519,11 +515,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
@@ -572,11 +564,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
@@ -602,11 +590,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] 60+ messages in thread* [PATCH RFC net-next v3 06/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (4 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 05/27] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent (Dent Project)
2024-11-21 14:42 ` [PATCH RFC net-next v3 07/27] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
` (21 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent (Dent Project) @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 20eab9857817..6fd76ecb2961 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);
@@ -69,17 +118,12 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
return ret;
chan = priv->port[id].chan[0];
- if (chan < 4)
- val = (u16)(ret | BIT(chan));
- else
- val = (u16)(ret | BIT(chan + 4));
+ val = tps23881_set_val(ret, 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));
}
ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
@@ -105,17 +149,12 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
return ret;
chan = priv->port[id].chan[0];
- if (chan < 4)
- val = (u16)(ret | BIT(chan + 4));
- else
- val = (u16)(ret | BIT(chan + 8));
+ val = tps23881_set_val(ret, 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);
@@ -127,6 +166,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);
@@ -134,17 +174,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 */
@@ -160,6 +196,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);
@@ -167,23 +204,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] 60+ messages in thread* [PATCH RFC net-next v3 07/27] net: pse-pd: tps23881: Add missing configuration register after disable
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (5 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 06/27] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent (Dent Project)
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-23 6:35 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 08/27] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
` (20 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v3:
- New patch
---
drivers/net/pse-pd/tps23881.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 6fd76ecb2961..58864b7d28d2 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -157,7 +157,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] 60+ messages in thread* Re: [PATCH RFC net-next v3 07/27] net: pse-pd: tps23881: Add missing configuration register after disable
2024-11-21 14:42 ` [PATCH RFC net-next v3 07/27] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
@ 2024-11-23 6:35 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-23 6:35 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:33PM +0100, Kory Maincent wrote:
> 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.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Thank you!
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 08/27] net: pse-pd: tps23881: Add support for power limit and measurement features
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (6 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 07/27] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-23 7:31 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 09/27] net: pse-pd: Add support for PSE device index Kory Maincent
` (19 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Expand PSE callbacks to support the newly introduced
pi_get/set_current_limit() and pi_get_voltage() functions. These callbacks
allow for power limit configuration in the TPS23881 controller.
Additionally, the patch includes the detected class, the current power
delivered and the power limit ranges in the status returned, providing more
comprehensive PoE status reporting.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
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 | 326 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 324 insertions(+), 2 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 58864b7d28d2..b25561f95774 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -25,20 +25,34 @@
#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_MAX_UV 60000000
+#define TPS23881_NA_STEP 70190
+#define TPS23881_MAX_UA 1150000
+#define TPS23881_MW_STEP 500
+#define TPS23881_MIN_PI_PW_LIMIT 2000
+
struct tps23881_port_desc {
u8 chan[2];
bool is_4p;
+ int pw_pol;
};
struct tps23881_priv {
@@ -102,6 +116,42 @@ static u16 tps23881_set_val(u16 reg_val, u8 chan, u8 field_offset,
return reg_val;
}
+static int
+tps23881_pi_set_2p_pw_limit(struct tps23881_priv *priv, u8 chan, u8 pw_pol)
+{
+ 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_set_val(ret, chan, 0, 0xff, pw_pol);
+ return i2c_smbus_write_word_data(client, reg, val);
+}
+
+static int
+tps23881_pi_set_4p_pw_limit(struct tps23881_priv *priv, u8 chan, u8 pw_pol)
+{
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u16 val;
+
+ 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(struct pse_controller_dev *pcdev, int id)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
@@ -184,7 +234,38 @@ 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 set */
+ if (priv->port[id].pw_pol < 0)
+ return 0;
+
+ chan = priv->port[id].chan[0];
+ 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.
+ */
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ ret = i2c_smbus_write_byte_data(client, TPS23881_REG_FOLDBACK, val);
+ if (ret)
+ return ret;
+
+ /* Set power policy */
+ if (priv->port[id].is_4p)
+ /* One chan is enough to configure the PI power limit */
+ ret = tps23881_pi_set_4p_pw_limit(priv, chan,
+ priv->port[id].pw_pol);
+ else
+ ret = tps23881_pi_set_2p_pw_limit(priv, chan,
+ priv->port[id].pw_pol);
+
+ return ret;
}
static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
@@ -214,6 +295,141 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
return enabled;
}
+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;
+ if (uV > TPS23881_MAX_UV) {
+ dev_err(&client->dev, "voltage read out of range\n");
+ return -ERANGE;
+ }
+
+ 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;
+
+ if (chan < 4)
+ /* Registers 0x30 0x34 0x38 0x3c */
+ reg = TPS23881_REG_CHAN1_A + chan * 4;
+ else
+ /* Registers 0x31 0x35 0x39 0x3d */
+ reg = TPS23881_REG_CHAN1_A + 1 + (chan % 4) * 4;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ tmp_64 = ret;
+ tmp_64 *= TPS23881_NA_STEP;
+ /* uA = nA / 1000 */
+ tmp_64 = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000);
+ if (tmp_64 > TPS23881_MAX_UA) {
+ dev_err(&client->dev, "current read out of range\n");
+ return -ERANGE;
+ }
+ return (int)tmp_64;
+}
+
+static int
+tps23881_pi_get_power(struct tps23881_priv *priv, unsigned long id)
+{
+ 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 tps23881_priv *priv, int id)
+{
+ 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_get_class(struct tps23881_priv *priv, int id)
+{
+ 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_ethtool_get_status(struct pse_controller_dev *pcdev,
unsigned long id,
struct netlink_ext_ack *extack,
@@ -256,6 +472,31 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
else
status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+ ret = tps23881_pi_get_power(priv, id);
+ if (ret < 0)
+ return ret;
+ status->c33_actual_pw = ret;
+
+ status->c33_pw_limit_ranges = kzalloc(sizeof(*status->c33_pw_limit_ranges),
+ GFP_KERNEL);
+ if (!status->c33_pw_limit_ranges)
+ return -ENOMEM;
+
+ status->c33_actual_pw = ret;
+ status->c33_pw_limit_nb_ranges = 1;
+ status->c33_pw_limit_ranges->min = TPS23881_MIN_PI_PW_LIMIT;
+ status->c33_pw_limit_ranges->max = MAX_PI_PW;
+
+ ret = tps23881_pi_get_pw_limit(priv, id);
+ if (ret < 0)
+ return ret;
+ status->c33_avail_pw_limit = ret;
+
+ ret = tps23881_pi_get_class(priv, id);
+ if (ret < 0)
+ return ret;
+ status->c33_pw_class = ret;
+
return 0;
}
@@ -553,6 +794,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);
@@ -672,12 +916,90 @@ static int tps23881_setup_pi_matrix(struct pse_controller_dev *pcdev)
return ret;
}
+static int tps23881_pi_get_current_limit(struct pse_controller_dev *pcdev,
+ int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ int ret, mW, uV;
+ u64 tmp_64;
+
+ ret = tps23881_pi_get_pw_limit(priv, id);
+ if (ret < 0)
+ return ret;
+ mW = ret;
+
+ ret = tps23881_pi_get_voltage(pcdev, id);
+ if (ret < 0)
+ return ret;
+ uV = ret;
+
+ tmp_64 = mW;
+ tmp_64 *= 1000000000ull;
+ /* uA = mW * 1000000000 / uV */
+ return DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
+}
+
+static int tps23881_pi_set_current_limit(struct pse_controller_dev *pcdev,
+ int id, int max_uA)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ u8 chan, pw_pol;
+ int ret, mW;
+ u64 tmp_64;
+ u16 val;
+
+ ret = tps23881_pi_get_voltage(pcdev, id);
+ if (ret < 0)
+ return ret;
+
+ tmp_64 = ret;
+ tmp_64 *= max_uA;
+ /* mW = uV * uA / 1000000000 */
+ mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
+ if (mW < TPS23881_MIN_PI_PW_LIMIT || MAX_PI_PW < mW)
+ return -ERANGE;
+
+ chan = priv->port[id].chan[0];
+ ret = i2c_smbus_read_byte_data(priv->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.
+ */
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ ret = i2c_smbus_write_byte_data(priv->client, TPS23881_REG_FOLDBACK, val);
+ if (ret)
+ return ret;
+
+ pw_pol = DIV_ROUND_CLOSEST_ULL(mW, TPS23881_MW_STEP);
+
+ /* Save power policy to reconfigure it after a disabled call */
+ priv->port[id].pw_pol = pw_pol;
+ if (priv->port[id].is_4p) {
+ /* One chan is enough to configure the PI power limit */
+ ret = tps23881_pi_set_4p_pw_limit(priv, chan, pw_pol);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = tps23881_pi_set_2p_pw_limit(priv, chan, pw_pol);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
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,
.ethtool_get_status = tps23881_ethtool_get_status,
+ .pi_get_voltage = tps23881_pi_get_voltage,
+ .pi_get_current_limit = tps23881_pi_get_current_limit,
+ .pi_set_current_limit = tps23881_pi_set_current_limit,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 08/27] net: pse-pd: tps23881: Add support for power limit and measurement features
2024-11-21 14:42 ` [PATCH RFC net-next v3 08/27] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
@ 2024-11-23 7:31 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-23 7:31 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:34PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> Expand PSE callbacks to support the newly introduced
> pi_get/set_current_limit() and pi_get_voltage() functions. These callbacks
> allow for power limit configuration in the TPS23881 controller.
>
> Additionally, the patch includes the detected class, the current power
> delivered and the power limit ranges in the status returned, providing more
> comprehensive PoE status reporting.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> ---
>
> 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 | 326 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 324 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
> index 58864b7d28d2..b25561f95774 100644
> --- a/drivers/net/pse-pd/tps23881.c
> +++ b/drivers/net/pse-pd/tps23881.c
> @@ -25,20 +25,34 @@
> #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_MAX_UV 60000000
> +#define TPS23881_NA_STEP 70190
> +#define TPS23881_MAX_UA 1150000
> +#define TPS23881_MW_STEP 500
> +#define TPS23881_MIN_PI_PW_LIMIT 2000
please add units annotations to define names or comments.
> +
> struct tps23881_port_desc {
> u8 chan[2];
> bool is_4p;
> + int pw_pol;
> };
>
> struct tps23881_priv {
> @@ -102,6 +116,42 @@ static u16 tps23881_set_val(u16 reg_val, u8 chan, u8 field_offset,
> return reg_val;
> }
>
> +static int
> +tps23881_pi_set_2p_pw_limit(struct tps23881_priv *priv, u8 chan, u8 pw_pol)
> +{
> + 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_set_val(ret, chan, 0, 0xff, pw_pol);
> + return i2c_smbus_write_word_data(client, reg, val);
> +}
> +
> +static int
> +tps23881_pi_set_4p_pw_limit(struct tps23881_priv *priv, u8 chan, u8 pw_pol)
> +{
> + struct i2c_client *client = priv->client;
> + int ret, reg;
> + u16 val;
> +
> + if ((chan % 4) < 2)
> + reg = TPS23881_REG_4PAIR_POL1;
> + else
> + reg = TPS23881_REG_4PAIR_POL1 + 1;
tps23881_pi_set_4p_pw_limit and tps23881_pi_set_2p_pw_limit are
identical except of register offset calculation. Can you please move the
common code to a separate function and add comments on why it needs
different offset calculations.
> + 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(struct pse_controller_dev *pcdev, int id)
> {
> struct tps23881_priv *priv = to_tps23881_priv(pcdev);
> @@ -184,7 +234,38 @@ 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 set */
> + if (priv->port[id].pw_pol < 0)
> + return 0;
> +
> + chan = priv->port[id].chan[0];
> + 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 re-assignment can be moved here, it is easier to understand
together with this comment.
> + chan = priv->port[id].chan[0];
> + val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
> + ret = i2c_smbus_write_byte_data(client, TPS23881_REG_FOLDBACK, val);
> + if (ret)
> + return ret;
> +
> + /* Set power policy */
> + if (priv->port[id].is_4p)
> + /* One chan is enough to configure the PI power limit */
> + ret = tps23881_pi_set_4p_pw_limit(priv, chan,
> + priv->port[id].pw_pol);
> + else
> + ret = tps23881_pi_set_2p_pw_limit(priv, chan,
> + priv->port[id].pw_pol);
> +
> + return ret;
> }
>
> static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
> @@ -214,6 +295,141 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
> return enabled;
> }
>
> +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;
> + if (uV > TPS23881_MAX_UV) {
used 0x3fff * TPS23881_UV_STEP not exceed TPS23881_MAX_UV. This sanity
check can be removed.
> + dev_err(&client->dev, "voltage read out of range\n");
> + return -ERANGE;
> + }
> +
> + 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;
> +
> + if (chan < 4)
> + /* Registers 0x30 0x34 0x38 0x3c */
> + reg = TPS23881_REG_CHAN1_A + chan * 4;
> + else
> + /* Registers 0x31 0x35 0x39 0x3d */
> + reg = TPS23881_REG_CHAN1_A + 1 + (chan % 4) * 4;
Hm, may be:
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;
Here is missing the 0x3fff mask or FIELD_GET, same for get_voltage.
> + tmp_64 *= TPS23881_NA_STEP;
> + /* uA = nA / 1000 */
> + tmp_64 = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000);
This sanity check can be removed.
> + if (tmp_64 > TPS23881_MAX_UA) {
> + dev_err(&client->dev, "current read out of range\n");
> + return -ERANGE;
> + }
> + return (int)tmp_64;
> +}
> +
> +static int
> +tps23881_pi_get_power(struct tps23881_priv *priv, unsigned long id)
> +{
> + 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 tps23881_priv *priv, int id)
> +{
> + 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_get_class(struct tps23881_priv *priv, int id)
> +{
> + 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_ethtool_get_status(struct pse_controller_dev *pcdev,
> unsigned long id,
> struct netlink_ext_ack *extack,
> @@ -256,6 +472,31 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
> else
> status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
>
> + ret = tps23881_pi_get_power(priv, id);
> + if (ret < 0)
> + return ret;
> + status->c33_actual_pw = ret;
> +
> + status->c33_pw_limit_ranges = kzalloc(sizeof(*status->c33_pw_limit_ranges),
> + GFP_KERNEL);
> + if (!status->c33_pw_limit_ranges)
> + return -ENOMEM;
> +
> + status->c33_actual_pw = ret;
> + status->c33_pw_limit_nb_ranges = 1;
> + status->c33_pw_limit_ranges->min = TPS23881_MIN_PI_PW_LIMIT;
> + status->c33_pw_limit_ranges->max = MAX_PI_PW;
> +
> + ret = tps23881_pi_get_pw_limit(priv, id);
> + if (ret < 0)
> + return ret;
> + status->c33_avail_pw_limit = ret;
> +
> + ret = tps23881_pi_get_class(priv, id);
> + if (ret < 0)
> + return ret;
> + status->c33_pw_class = ret;
> +
> return 0;
> }
>
> @@ -553,6 +794,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);
>
> @@ -672,12 +916,90 @@ static int tps23881_setup_pi_matrix(struct pse_controller_dev *pcdev)
> return ret;
> }
>
> +static int tps23881_pi_get_current_limit(struct pse_controller_dev *pcdev,
> + int id)
> +{
> + struct tps23881_priv *priv = to_tps23881_priv(pcdev);
> + int ret, mW, uV;
> + u64 tmp_64;
> +
> + ret = tps23881_pi_get_pw_limit(priv, id);
> + if (ret < 0)
> + return ret;
> + mW = ret;
> +
> + ret = tps23881_pi_get_voltage(pcdev, id);
> + if (ret < 0)
> + return ret;
> + uV = ret;
> +
> + tmp_64 = mW;
> + tmp_64 *= 1000000000ull;
> + /* uA = mW * 1000000000 / uV */
> + return DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
> +}
> +
> +static int tps23881_pi_set_current_limit(struct pse_controller_dev *pcdev,
> + int id, int max_uA)
> +{
> + struct tps23881_priv *priv = to_tps23881_priv(pcdev);
> + u8 chan, pw_pol;
> + int ret, mW;
> + u64 tmp_64;
> + u16 val;
> +
> + ret = tps23881_pi_get_voltage(pcdev, id);
> + if (ret < 0)
> + return ret;
> +
> + tmp_64 = ret;
> + tmp_64 *= max_uA;
> + /* mW = uV * uA / 1000000000 */
> + mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
> + if (mW < TPS23881_MIN_PI_PW_LIMIT || MAX_PI_PW < mW)
May be add here some error message to let understand what limit did we
hit.
> + return -ERANGE;
> +
> + chan = priv->port[id].chan[0];
> + ret = i2c_smbus_read_byte_data(priv->client, TPS23881_REG_FOLDBACK);
> + if (ret < 0)
> + return ret;
I have seen this sequence in tps23881_pi_disable(), may be share this
code?
> + /* 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.
> + */
> + val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
> + ret = i2c_smbus_write_byte_data(priv->client, TPS23881_REG_FOLDBACK, val);
> + if (ret)
> + return ret;
> +
> + pw_pol = DIV_ROUND_CLOSEST_ULL(mW, TPS23881_MW_STEP);
> +
> + /* Save power policy to reconfigure it after a disabled call */
> + priv->port[id].pw_pol = pw_pol;
> + if (priv->port[id].is_4p) {
> + /* One chan is enough to configure the PI power limit */
> + ret = tps23881_pi_set_4p_pw_limit(priv, chan, pw_pol);
> + if (ret < 0)
> + return ret;
> + } else {
> + ret = tps23881_pi_set_2p_pw_limit(priv, chan, pw_pol);
> + if (ret < 0)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> 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,
> .ethtool_get_status = tps23881_ethtool_get_status,
> + .pi_get_voltage = tps23881_pi_get_voltage,
> + .pi_get_current_limit = tps23881_pi_get_current_limit,
> + .pi_set_current_limit = tps23881_pi_set_current_limit,
> };
>
> static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
>
> --
> 2.34.1
>
>
Regards,
Oleksij
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 09/27] net: pse-pd: Add support for PSE device index
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (7 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 08/27] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-23 7:34 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 10/27] net: ethtool: Add support for new PSE device index description Kory Maincent
` (18 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
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 | 23 ++++++++++++++++++-----
include/linux/pse-pd/pse.h | 4 ++++
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 432b6c2c04f8..411868bccbcc 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
@@ -441,18 +442,22 @@ 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;
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 +
@@ -469,15 +474,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);
@@ -485,6 +492,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);
@@ -495,6 +506,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);
@@ -751,6 +763,7 @@ static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
return -EOPNOTSUPP;
}
+ status->pse_id = pcdev->id;
return ops->ethtool_get_status(pcdev, id, extack, status);
}
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index bc5addccbf32..f2294a1d9b58 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -33,6 +33,7 @@ struct pse_control_config {
/**
* struct pse_control_status - PSE control/channel status.
*
+ * @pse_id: index number of the PSE. Set by PSE core.
* @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.
@@ -54,6 +55,7 @@ struct pse_control_config {
* ranges
*/
struct 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;
@@ -152,6 +154,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;
@@ -165,6 +168,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] 60+ messages in thread* Re: [PATCH RFC net-next v3 09/27] net: pse-pd: Add support for PSE device index
2024-11-21 14:42 ` [PATCH RFC net-next v3 09/27] net: pse-pd: Add support for PSE device index Kory Maincent
@ 2024-11-23 7:34 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-23 7:34 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:35PM +0100, Kory Maincent wrote:
> 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.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Thank you!
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 10/27] net: ethtool: Add support for new PSE device index description
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (8 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 09/27] net: pse-pd: Add support for PSE device index Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 11/27] net: ethtool: Add support for ethnl_info_init_ntf helper function Kory Maincent
` (17 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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/networking/ethtool-netlink.rst | 4 ++++
include/uapi/linux/ethtool_netlink.h | 1 +
net/ethtool/pse-pd.c | 4 ++++
3 files changed, 9 insertions(+)
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index b25926071ece..bd7173d1fa4d 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1766,6 +1766,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
@@ -1839,6 +1840,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 283305f6b063..9a4c293a9a82 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -970,6 +970,7 @@ enum {
ETHTOOL_A_C33_PSE_EXT_SUBSTATE, /* u32 */
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT, /* u32 */
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES, /* nest - _C33_PSE_PW_LIMIT_* */
+ ETHTOOL_A_PSE_ID, /* u32 */
/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index a0705edca22a..5edb8b0a669e 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 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 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] 60+ messages in thread* [PATCH RFC net-next v3 11/27] net: ethtool: Add support for ethnl_info_init_ntf helper function
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (9 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 10/27] net: ethtool: Add support for new PSE device index description Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 12/27] net: pse-pd: Add support for reporting events Kory Maincent
` (16 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 v2:
- new patch.
---
net/ethtool/netlink.c | 5 +++++
net/ethtool/netlink.h | 2 ++
2 files changed, 7 insertions(+)
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index e3f0ef6b851b..808cc8096f93 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -805,6 +805,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 203b08eb6c6f..d04a8e9d54db 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] 60+ messages in thread* [PATCH RFC net-next v3 12/27] net: pse-pd: Add support for reporting events
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (10 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 11/27] net: ethtool: Add support for ethnl_info_init_ntf helper function Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-24 9:26 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 13/27] netlink: specs: Add support for PSE netlink notifications Kory Maincent
` (15 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 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.
---
drivers/net/mdio/fwnode_mdio.c | 26 ++++----
drivers/net/pse-pd/pse_core.c | 126 ++++++++++++++++++++++++++++++++++-
include/linux/ethtool_netlink.h | 9 +++
include/linux/pse-pd/pse.h | 18 ++++-
include/uapi/linux/ethtool.h | 11 +++
include/uapi/linux/ethtool_netlink.h | 11 +++
net/ethtool/pse-pd.c | 46 +++++++++++++
7 files changed, 230 insertions(+), 17 deletions(-)
diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c
index b156493d7084..7d571895a8eb 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;
@@ -121,15 +122,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))
@@ -162,6 +157,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
@@ -173,12 +174,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 411868bccbcc..8b5a9e7fd9c5 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,
@@ -553,6 +556,120 @@ 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;
+};
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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)
@@ -595,7 +712,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;
@@ -634,6 +752,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;
@@ -689,7 +808,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;
@@ -739,7 +859,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 f2294a1d9b58..be6e967f9ac3 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,13 @@
struct phy_device;
struct pse_controller_dev;
+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.
*
@@ -155,6 +163,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;
@@ -169,6 +178,7 @@ struct pse_controller_dev {
struct pse_pi *pi;
bool no_of_pse_pi;
u32 id;
+ int irq;
};
#if IS_ENABLED(CONFIG_PSE_CONTROLLER)
@@ -177,8 +187,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,
@@ -196,7 +209,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 fc1f54b065f9..a4c93d6de218 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -998,6 +998,17 @@ 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.
+ */
+
+enum ethtool_pse_events {
+ ETHTOOL_PSE_EVENT_OVER_CURRENT = 1 << 0,
+ ETHTOOL_PSE_EVENT_OVER_TEMP = 1 << 1,
+};
+
/**
* 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.h b/include/uapi/linux/ethtool_netlink.h
index 9a4c293a9a82..91c1bd9349b0 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -114,6 +114,7 @@ enum {
ETHTOOL_MSG_MODULE_FW_FLASH_NTF,
ETHTOOL_MSG_PHY_GET_REPLY,
ETHTOOL_MSG_PHY_NTF,
+ ETHTOOL_MSG_PSE_NTF,
/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
@@ -977,6 +978,16 @@ enum {
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
};
+/* PSE NOTIFY */
+enum {
+ ETHTOOL_A_PSE_NTF_UNSPEC,
+ ETHTOOL_A_PSE_NTF_HEADER, /* nest - ETHTOOL_A_HEADER_* */
+ ETHTOOL_A_PSE_NTF_EVENTS, /* u32 */
+
+ __ETHTOOL_A_PSE_NTF_CNT,
+ ETHTOOL_A_PSE_NTF_MAX = (__ETHTOOL_A_PSE_NTF_CNT - 1)
+};
+
enum {
ETHTOOL_A_RSS_UNSPEC,
ETHTOOL_A_RSS_HEADER,
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 5edb8b0a669e..19ab6bd35ad4 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -319,3 +319,49 @@ 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_MM_NTF);
+ info.extack = extack;
+
+ reply_len = ethnl_reply_header_size();
+ /* _C33_PSE_NTF_EVENTS */
+ reply_len += nla_total_size(sizeof(u32));
+ skb = genlmsg_new(reply_len, GFP_KERNEL);
+ reply_payload = ethnl_bcastmsg_put(skb, ETHTOOL_MSG_MM_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 = nla_put_u32(skb, ETHTOOL_A_PSE_NTF_EVENTS, notifs);
+ 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);
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 12/27] net: pse-pd: Add support for reporting events
2024-11-21 14:42 ` [PATCH RFC net-next v3 12/27] net: pse-pd: Add support for reporting events Kory Maincent
@ 2024-11-24 9:26 ` Oleksij Rempel
2024-11-25 10:42 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 9:26 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:38PM +0100, Kory Maincent wrote:
> 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>
....
> @@ -634,6 +752,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;
Hm, i guess, here is missing some sort of phy_attach_pse.
Otherwise the phydev may be removed.
> kref_init(&psec->refcnt);
>
> return psec;
> @@ -689,7 +808,8 @@ static int psec_id_xlate(struct pse_controller_dev *pcdev,
> return pse_spec->args[0];
> }
It will be good if some one takes a look at netlink specific part of the
code.
--
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] 60+ messages in thread
* Re: [PATCH RFC net-next v3 12/27] net: pse-pd: Add support for reporting events
2024-11-24 9:26 ` Oleksij Rempel
@ 2024-11-25 10:42 ` Kory Maincent
0 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-25 10:42 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sun, 24 Nov 2024 10:26:34 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> On Thu, Nov 21, 2024 at 03:42:38PM +0100, Kory Maincent wrote:
> > 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>
>
> ....
>
> > @@ -634,6 +752,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;
>
> Hm, i guess, here is missing some sort of phy_attach_pse.
> Otherwise the phydev may be removed.
I don't think so as a phy_device remove call will also free the pse control
pointer through the pse_control_put() function.
https://elixir.bootlin.com/linux/v6.11.7/source/drivers/net/phy/phy_device.c#L1045
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 13/27] netlink: specs: Add support for PSE netlink notifications
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (11 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 12/27] net: pse-pd: Add support for reporting events Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 14/27] net: pse-pd: tps23881: Add support for PSE events and interrupts Kory Maincent
` (14 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Introduce support for PSE-specific netlink notifications, allowing for
the reporting of events related to c33 PSE (Power Sourcing Equipment).
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v2:
- new patch.
---
Documentation/netlink/specs/ethtool.yaml | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 93369f0eb816..f27c76d965d9 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1137,6 +1137,18 @@ attribute-sets:
-
name: downstream-sfp-name
type: string
+ -
+ name: pse-ntf
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: pse-ntf-events
+ type: nest
+ nested-attributes: bitset
+ name-prefix: ethtool-a-
operations:
enum-model: directional
@@ -1960,3 +1972,13 @@ operations:
name: phy-ntf
doc: Notification for change in PHY devices.
notify: phy-get
+ -
+ name: pse-ntf
+ doc: Notification for pse events.
+
+ attribute-set: pse-ntf
+
+ event:
+ attributes:
+ - header
+ - pse-ntf-events
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* [PATCH RFC net-next v3 14/27] net: pse-pd: tps23881: Add support for PSE events and interrupts
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (12 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 13/27] netlink: specs: Add support for PSE netlink notifications Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-24 9:34 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 15/27] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
` (13 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
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 b25561f95774..6fe8f150231f 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
@@ -53,6 +61,7 @@ struct tps23881_port_desc {
u8 chan[2];
bool is_4p;
int pw_pol;
+ bool exist;
};
struct tps23881_priv {
@@ -791,8 +800,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;
@@ -1098,6 +1109,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_it_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_it_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;
@@ -1178,6 +1348,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] 60+ messages in thread* Re: [PATCH RFC net-next v3 14/27] net: pse-pd: tps23881: Add support for PSE events and interrupts
2024-11-21 14:42 ` [PATCH RFC net-next v3 14/27] net: pse-pd: tps23881: Add support for PSE events and interrupts Kory Maincent
@ 2024-11-24 9:34 ` Oleksij Rempel
2024-11-25 11:39 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 9:34 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:40PM +0100, Kory Maincent wrote:
> 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.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> ---
>
> 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 b25561f95774..6fe8f150231f 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
> @@ -53,6 +61,7 @@ struct tps23881_port_desc {
> u8 chan[2];
> bool is_4p;
> int pw_pol;
> + bool exist;
> };
>
> struct tps23881_priv {
> @@ -791,8 +800,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;
> @@ -1098,6 +1109,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_it_export_chans_helper(u16 reg_val, u8 field_offset)
What is the meaning of _it_?
> +{
> + 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;
Hm, should it be bound to bound to therman zone frame work and start
cooling or something? I guess this can be done in a separate step..
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
--
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] 60+ messages in thread* Re: [PATCH RFC net-next v3 14/27] net: pse-pd: tps23881: Add support for PSE events and interrupts
2024-11-24 9:34 ` Oleksij Rempel
@ 2024-11-25 11:39 ` Kory Maincent
0 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-25 11:39 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sun, 24 Nov 2024 10:34:04 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> >
> > +/* Convert interrupt events to 0xff to be aligned with the chan
> > + * number.
> > + */
> > +static u8 tps23881_it_export_chans_helper(u16 reg_val, u8 field_offset)
>
> What is the meaning of _it_?
Interrupt. I will change it to irq ;)
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 15/27] regulator: core: Resolve supply using of_node from regulator_config
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (13 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 14/27] net: pse-pd: tps23881: Add support for PSE events and interrupts Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-24 9:39 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 16/27] regulator: Add support for power budget description Kory Maincent
` (12 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
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 v3:
- New patch
---
drivers/regulator/core.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2948a7eca734..b49f751893b9 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 && dev->of_node) {
+ r = of_regulator_dev_lookup(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 && dev->of_node) {
- r = of_regulator_dev_lookup(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)
@@ -2002,8 +2009,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
static int regulator_resolve_supply(struct regulator_dev *rdev)
{
- struct regulator_dev *r;
struct device *dev = rdev->dev.parent;
+ struct regulator_dev *r = NULL;
struct ww_acquire_ctx ww_ctx;
int ret = 0;
@@ -2015,7 +2022,18 @@ 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.
+ */
+ if (rdev->dev.of_node)
+ 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] 60+ messages in thread* Re: [PATCH RFC net-next v3 15/27] regulator: core: Resolve supply using of_node from regulator_config
2024-11-21 14:42 ` [PATCH RFC net-next v3 15/27] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
@ 2024-11-24 9:39 ` Oleksij Rempel
2024-11-24 9:44 ` Oleksij Rempel
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 9:39 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:41PM +0100, Kory Maincent wrote:
> 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.
>
> 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 v3:
> - New patch
> ---
> drivers/regulator/core.c | 42 ++++++++++++++++++++++++++++++------------
> 1 file changed, 30 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index 2948a7eca734..b49f751893b9 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 && dev->of_node) {
> + r = of_regulator_dev_lookup(dev, supply);
> + if (PTR_ERR(r) == -ENODEV)
> + r = NULL;
> + }
> +
> + return r;
> +}
...
> static int regulator_resolve_supply(struct regulator_dev *rdev)
> {
> - struct regulator_dev *r;
> struct device *dev = rdev->dev.parent;
> + struct regulator_dev *r = NULL;
> struct ww_acquire_ctx ww_ctx;
> int ret = 0;
>
> @@ -2015,7 +2022,18 @@ 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.
> + */
> + if (rdev->dev.of_node)
regulator_dt_lookup() is already doing dev.of_node check, this one can
be removed.
> + 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);
>
With remove dev.of_node check:
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
--
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] 60+ messages in thread* Re: [PATCH RFC net-next v3 15/27] regulator: core: Resolve supply using of_node from regulator_config
2024-11-24 9:39 ` Oleksij Rempel
@ 2024-11-24 9:44 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 9:44 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
> > diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> > index 2948a7eca734..b49f751893b9 100644
> > --- a/drivers/regulator/core.c
> > +++ b/drivers/regulator/core.c
...
> With remove dev.of_node check:
> Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Sorry, wrong framework :) I can do only Reviewed-by
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 16/27] regulator: Add support for power budget description
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (14 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 15/27] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-24 9:46 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
` (11 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 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 b49f751893b9..828b4dd10f68 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);
+}
+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)
+ count += scnprintf(buf + count, len - count, "%d mW budget",
+ constraints->pw_budget);
+
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)
+ rdev->pw_available = rdev->constraints->pw_budget;
+ else if (rdev->supply)
+ rdev->pw_available = regulator_get_power_budget(rdev->supply);
+ else
+ rdev->pw_available = INT_MAX;
+
print_constraints(rdev);
return 0;
}
@@ -4641,6 +4661,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;
+}
+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) {
+ rdev_dbg(rdev, "power requested %d mW out of budget %d mW",
+ pw_req, rdev->pw_available);
+ ret = -ERANGE;
+ goto out;
+ }
+
+ rdev->pw_available -= 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 += pw;
+ regulator_unlock(rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_free_power_budget);
+
/**
* regulator_set_mode - set regulator operating mode
* @regulator: regulator source
@@ -5279,6 +5364,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
};
@@ -5360,6 +5446,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 != INT_MAX ? mode : 0;
+
return mode;
}
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 3f490d81abc2..a8996e7597d4 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", &pval))
+ constraints->pw_budget = 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 b9ce521910a0..8f0a0e98d7ee 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -235,6 +235,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);
@@ -534,6 +539,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 f230a472ccd3..e006d0c19542 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -649,6 +649,8 @@ struct regulator_dev {
int cached_err;
bool use_cached_err;
spinlock_t err_lock;
+
+ int pw_available;
};
/*
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 0cd76d264727..3304cf8773b7 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: 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;
int system_load;
/* used for coupled regulators */
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 16/27] regulator: Add support for power budget description
2024-11-21 14:42 ` [PATCH RFC net-next v3 16/27] regulator: Add support for power budget description Kory Maincent
@ 2024-11-24 9:46 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 9:46 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:42PM +0100, Kory Maincent wrote:
> 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>
> --- 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: 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;
Unit name is missing. Should be: pw_budget_mW or something like this.
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (15 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 16/27] regulator: Add support for power budget description Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:58 ` Mark Brown
2024-11-22 6:57 ` Krzysztof Kozlowski
2024-11-21 14:42 ` [PATCH RFC net-next v3 18/27] net: pse-pd: Fix missing PI of_node description Kory Maincent
` (10 subsequent siblings)
27 siblings, 2 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 v2:
- new patch.
---
Documentation/devicetree/bindings/regulator/regulator.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 1ef380d1515e..52a410b51769 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -34,6 +34,9 @@ properties:
regulator-input-current-limit-microamp:
description: maximum input current regulator allows
+ regulator-power-budget:
+ description: power budget of the regulator in mW
+
regulator-always-on:
description: boolean, regulator should never be disabled
type: boolean
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property
2024-11-21 14:42 ` [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
@ 2024-11-21 14:58 ` Mark Brown
2024-11-21 15:27 ` Kory Maincent
2024-11-22 6:57 ` Krzysztof Kozlowski
1 sibling, 1 reply; 60+ messages in thread
From: Mark Brown @ 2024-11-21 14:58 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, Thomas Petazzoni, linux-kernel,
netdev, linux-doc, Kyle Swenson, Dent Project, kernel,
Maxime Chevallier
[-- Attachment #1: Type: text/plain, Size: 327 bytes --]
On Thu, Nov 21, 2024 at 03:42:43PM +0100, Kory Maincent wrote:
> regulator-input-current-limit-microamp:
> description: maximum input current regulator allows
>
> + regulator-power-budget:
> + description: power budget of the regulator in mW
> +
Properties are supposed to include the unit in the name.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property
2024-11-21 14:58 ` Mark Brown
@ 2024-11-21 15:27 ` Kory Maincent
0 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 15:27 UTC (permalink / raw)
To: Mark Brown
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, Thomas Petazzoni, linux-kernel,
netdev, linux-doc, Kyle Swenson, Dent Project, kernel,
Maxime Chevallier
On Thu, 21 Nov 2024 14:58:06 +0000
Mark Brown <broonie@kernel.org> wrote:
> On Thu, Nov 21, 2024 at 03:42:43PM +0100, Kory Maincent wrote:
> > regulator-input-current-limit-microamp:
> > description: maximum input current regulator allows
> >
> > + regulator-power-budget:
> > + description: power budget of the regulator in mW
> > +
>
> Properties are supposed to include the unit in the name.
Oh ok, thanks!
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property
2024-11-21 14:42 ` [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
2024-11-21 14:58 ` Mark Brown
@ 2024-11-22 6:57 ` Krzysztof Kozlowski
1 sibling, 0 replies; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-22 6:57 UTC (permalink / raw)
To: Kory Maincent, 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier
On 21/11/2024 15:42, 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>
> ---
>
Considering:
1. This was not tested,
2. You did not Cc DT folks
so I assume you do not expect review as indicated by RFC. It is fine,
but if that was not the intention, please kindly first test the patch
and then use get_maintainers.pl or b4.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 18/27] net: pse-pd: Fix missing PI of_node description
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (16 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 17/27] regulator: dt-bindings: Add regulator-power-budget property Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-24 9:49 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 19/27] net: pse-pd: Add support for PSE power domains Kory Maincent
` (9 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
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 8b5a9e7fd9c5..d4cf5523194d 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -419,6 +419,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] 60+ messages in thread* Re: [PATCH RFC net-next v3 18/27] net: pse-pd: Fix missing PI of_node description
2024-11-21 14:42 ` [PATCH RFC net-next v3 18/27] net: pse-pd: Fix missing PI of_node description Kory Maincent
@ 2024-11-24 9:49 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 9:49 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:44PM +0100, Kory Maincent wrote:
> 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.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>
> 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 8b5a9e7fd9c5..d4cf5523194d 100644
> --- a/drivers/net/pse-pd/pse_core.c
> +++ b/drivers/net/pse-pd/pse_core.c
> @@ -419,6 +419,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
>
>
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 19/27] net: pse-pd: Add support for PSE power domains
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (17 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 18/27] net: pse-pd: Fix missing PI of_node description Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-24 10:24 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 20/27] net: ethtool: Add support for new power domains index description Kory Maincent
` (8 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 v3:
- Remove pw_budget variable.
Changes in v2:
- new patch.
---
drivers/net/pse-pd/pse_core.c | 95 +++++++++++++++++++++++++++++++++++++++++++
include/linux/pse-pd/pse.h | 2 +
2 files changed, 97 insertions(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index d4cf5523194d..8b9ce8c6ecef 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)
@@ -433,6 +444,84 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
return 0;
}
+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++) {
+ 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);
+ }
+ }
+}
+
+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;
+}
+
+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
@@ -491,6 +580,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);
@@ -509,6 +603,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 be6e967f9ac3..9d06eb9ca663 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -140,12 +140,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] 60+ messages in thread* Re: [PATCH RFC net-next v3 19/27] net: pse-pd: Add support for PSE power domains
2024-11-21 14:42 ` [PATCH RFC net-next v3 19/27] net: pse-pd: Add support for PSE power domains Kory Maincent
@ 2024-11-24 10:24 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-24 10:24 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:45PM +0100, Kory Maincent wrote:
> 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>
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Thank you!
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 20/27] net: ethtool: Add support for new power domains index description
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (18 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 19/27] net: pse-pd: Add support for PSE power domains Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-26 5:53 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority Kory Maincent
` (7 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Changes in v3:
- Add support power domain id = 0 in ethtool.
Changes in v2:
- new patch.
---
Documentation/networking/ethtool-netlink.rst | 4 ++++
drivers/net/pse-pd/pse_core.c | 3 +++
include/linux/pse-pd/pse.h | 2 ++
include/uapi/linux/ethtool_netlink.h | 1 +
net/ethtool/pse-pd.c | 7 +++++++
5 files changed, 17 insertions(+)
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index bd7173d1fa4d..3573543ae5ad 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1767,6 +1767,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
@@ -1843,6 +1844,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 8b9ce8c6ecef..ff0ffbccf139 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -980,6 +980,9 @@ static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
}
status->pse_id = pcdev->id;
+ if (pcdev->pi[id].pw_d)
+ status->pw_d_id = pcdev->pi[id].pw_d->id;
+
return ops->ethtool_get_status(pcdev, id, extack, status);
}
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 9d06eb9ca663..bdf3e8c468fc 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -42,6 +42,7 @@ struct pse_control_config {
* struct pse_control_status - PSE control/channel status.
*
* @pse_id: index number of the PSE. Set by PSE core.
+ * @pw_d_id: PSE power domain index. Set by PSE core.
* @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.
@@ -64,6 +65,7 @@ struct pse_control_config {
*/
struct 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.h b/include/uapi/linux/ethtool_netlink.h
index 91c1bd9349b0..088ad7b956fb 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -972,6 +972,7 @@ enum {
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT, /* u32 */
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES, /* nest - _C33_PSE_PW_LIMIT_* */
ETHTOOL_A_PSE_ID, /* u32 */
+ ETHTOOL_A_PSE_PW_D_ID, /* u32 */
/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 19ab6bd35ad4..d67803b67e76 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -84,6 +84,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)
@@ -152,6 +154,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] 60+ messages in thread* Re: [PATCH RFC net-next v3 20/27] net: ethtool: Add support for new power domains index description
2024-11-21 14:42 ` [PATCH RFC net-next v3 20/27] net: ethtool: Add support for new power domains index description Kory Maincent
@ 2024-11-26 5:53 ` Oleksij Rempel
0 siblings, 0 replies; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-26 5:53 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:46PM +0100, Kory Maincent wrote:
> 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.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Thank you!
--
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] 60+ messages in thread
* [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (19 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 20/27] net: ethtool: Add support for new power domains index description Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-26 8:38 ` Oleksij Rempel
2024-11-21 14:42 ` [PATCH RFC net-next v3 22/27] net: ethtool: Add PSE new port priority support feature Kory Maincent
` (6 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
This patch introduces the ability to configure the PSE PI port priority.
Port priority 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 port priority modes.
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 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 | 550 +++++++++++++++++++++++++++++++++++++++++-
include/linux/pse-pd/pse.h | 63 +++++
include/uapi/linux/ethtool.h | 73 ++++++
3 files changed, 676 insertions(+), 10 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index ff0ffbccf139..f15a693692ae 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -40,10 +40,17 @@ struct pse_control {
* struct pse_power_domain - a PSE power domain
* @id: ID of the power domain
* @supply: Power supply the Power Domain
+ * @port_prio_mode: Current port priority mode of the power domain
+ * @discon_pol: Current disonnection policy of the power domain
+ * @pi_lrc_id: ID of the last recently connected PI. -1 if none. Relevant
+ * for static port priority mode.
*/
struct pse_power_domain {
int id;
struct regulator *supply;
+ u32 port_prio_mode;
+ u32 discon_pol;
+ int pi_lrc_id;
};
static int of_load_single_pse_pi_pairset(struct device_node *node,
@@ -222,6 +229,33 @@ static int of_load_pse_pis(struct pse_controller_dev *pcdev)
return ret;
}
+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);
+}
+
+/* Helper returning true if the power control 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->port_prio_mode & ETHTOOL_PSE_PORT_PRIO_STATIC)
+ return true;
+ if (pw_d->port_prio_mode == ETHTOOL_PSE_PORT_PRIO_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);
@@ -234,6 +268,13 @@ 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].isr_enabled &&
+ pcdev->pi[id].admin_state_enabled;
+ mutex_unlock(&pcdev->lock);
+ return ret;
+ }
+
ret = ops->pi_is_enabled(pcdev, id);
mutex_unlock(&pcdev->lock);
@@ -244,7 +285,7 @@ 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)
@@ -252,6 +293,21 @@ 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_enabled) {
+ ret = ops->pi_enable(pcdev, id);
+ 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;
@@ -264,6 +320,7 @@ 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;
@@ -272,9 +329,16 @@ static int pse_pi_disable(struct regulator_dev *rdev)
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
+
+ pi = &pcdev->pi[id];
ret = ops->pi_disable(pcdev, id);
- if (!ret)
- pcdev->pi[id].admin_state_enabled = 0;
+ if (!ret) {
+ pse_pi_deallocate_pw_budget(pi);
+ pi->admin_state_enabled = 0;
+ pi->isr_enabled = 0;
+ if (pi->pw_d && pi->pw_d->pi_lrc_id == id)
+ pi->pw_d->pi_lrc_id = -1;
+ }
mutex_unlock(&pcdev->lock);
return ret;
@@ -516,6 +580,8 @@ static int pse_register_pw_ds(struct pse_controller_dev *pcdev)
}
pw_d->supply = supply;
+ pw_d->port_prio_mode = ETHTOOL_PSE_PORT_PRIO_DISABLED;
+ pw_d->discon_pol = ETHTOOL_PSE_DISCON_ROUND_ROBIN_IDX_LOWEST_FIRST;
pcdev->pi[i].pw_d = pw_d;
}
@@ -539,6 +605,7 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
if (ret < 0)
return ret;
pcdev->id = ret;
+ pcdev->port_prio_supp_modes |= ETHTOOL_PSE_PORT_PRIO_DISABLED;
if (!pcdev->nr_lines)
pcdev->nr_lines = 1;
@@ -683,10 +750,279 @@ pse_control_find_phy_by_id(struct pse_controller_dev *pcdev, int id)
}
}
mutex_unlock(&pse_list_mutex);
-
return NULL;
}
+static int pse_pi_disable_isr(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;
+
+ if (!ops->pi_disable) {
+ NL_SET_ERR_MSG(extack, "PSE does not support disable control");
+ return -EOPNOTSUPP;
+ }
+
+ if (!pi->isr_enabled)
+ return 0;
+
+ if (pi->admin_state_enabled) {
+ ret = ops->pi_disable(pcdev, id);
+ if (ret) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: disable error %d",
+ id, ret);
+ return ret;
+ }
+ }
+
+ pse_pi_deallocate_pw_budget(pi);
+ pi->isr_enabled = 0;
+ if (pi->pw_d && pi->pw_d->pi_lrc_id == id)
+ pi->pw_d->pi_lrc_id = -1;
+
+ return 0;
+}
+
+static int _pse_disable_pi_pol(struct pse_controller_dev *pcdev, int id)
+{
+ unsigned long notifs = ETHTOOL_C33_PSE_EVENT_DISCONNECTION;
+ 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_isr(pcdev, id, &extack);
+ if (ret)
+ notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
+ phydev = pse_control_find_phy_by_id(pcdev, id);
+ if (phydev)
+ ethnl_pse_send_ntf(phydev, notifs, &extack);
+
+ return ret;
+}
+
+static int pse_disable_pi_prio_lrc(struct pse_controller_dev *pcdev,
+ struct pse_power_domain *pw_d,
+ int prio)
+{
+ int lrc_id = pw_d->pi_lrc_id;
+ int ret;
+
+ if (lrc_id < 0)
+ return 0;
+
+ if (pcdev->pi[lrc_id].prio != prio)
+ return 0;
+
+ ret = _pse_disable_pi_pol(pcdev, lrc_id);
+ if (ret)
+ return ret;
+
+ /* PI disabled */
+ return 1;
+}
+
+static int pse_disable_pi_prio_round_rob_low(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].isr_enabled)
+ continue;
+
+ ret = _pse_disable_pi_pol(pcdev, i);
+ if (ret)
+ return ret;
+
+ /* PI disabled */
+ return 1;
+ }
+
+ /* No PI disabled */
+ return 0;
+}
+
+static int pse_disable_pi_prio_pol(struct pse_controller_dev *pcdev,
+ struct pse_power_domain *pw_d,
+ int prio)
+{
+ int ret;
+
+ if (pw_d->discon_pol & ETHTOOL_PSE_DISCON_LRC) {
+ ret = pse_disable_pi_prio_lrc(pcdev, pw_d, prio);
+ if (ret)
+ return ret;
+ }
+
+ if (pw_d->discon_pol &
+ ETHTOOL_PSE_DISCON_ROUND_ROBIN_IDX_LOWEST_FIRST) {
+ ret = pse_disable_pi_prio_round_rob_low(pcdev, pw_d, prio);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+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) {
+ ret = pse_disable_pi_prio_pol(pcdev, pi->pw_d, _prio);
+ if (ret < 0)
+ return ret;
+ /* No pi disabled, decrease priority value */
+ if (!ret)
+ _prio--;
+
+ if (_prio <= pi->prio) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: not enough power budget available",
+ id);
+ return -ERANGE;
+ }
+ }
+
+ pi->pw_allocated = pw_req;
+ return 0;
+}
+
+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];
+ int ret;
+
+ if (!pi->pw_d)
+ return 0;
+
+ /* ETHTOOL_PSE_PORT_PRIO_STATIC */
+ if (pi->pw_d->port_prio_mode & ETHTOOL_PSE_PORT_PRIO_STATIC)
+ return pse_pi_allocate_pw_budget_static_prio(pcdev, id, pw_req,
+ extack);
+
+ /* ETHTOOL_PSE_PORT_PRIO_DISABLED */
+ ret = regulator_request_power_budget(pi->pw_d->supply, pw_req);
+ if (ret)
+ NL_SET_ERR_MSG_FMT(extack,
+ "PI %d: not enough power budget available",
+ id);
+ else
+ pi->pw_allocated = pw_req;
+
+ return ret;
+}
+
+static int pse_pi_enable_isr(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_enable || !ops->pi_get_pw_req) {
+ NL_SET_ERR_MSG(extack, "PSE does not support enable control");
+ return -EOPNOTSUPP;
+ }
+
+ if (pi->isr_enabled)
+ return 0;
+
+ 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_current_limit && ops->pi_get_voltage) {
+ int uV, mW;
+ s64 tmp_64;
+
+ ret = ops->pi_get_voltage(pcdev, id);
+ if (ret < 0)
+ return ret;
+ uV = ret;
+
+ ret = ops->pi_get_current_limit(pcdev, id);
+ if (ret < 0)
+ return ret;
+
+ tmp_64 = ret;
+ tmp_64 *= uV;
+ /* mW = uV * uA / 1000000000 */
+ mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
+ if (mW < pw_req)
+ pw_req = mW;
+ }
+
+ ret = pse_pi_allocate_pw_budget(pcdev, id, pw_req, extack);
+ if (ret)
+ return ret;
+
+ if (pi->admin_state_enabled) {
+ 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;
+ }
+ }
+
+ pi->isr_enabled = 1;
+ if (pi->pw_d)
+ pi->pw_d->pi_lrc_id = id;
+ return 0;
+}
+
+static int pse_set_config_isr(struct pse_controller_dev *pcdev, int id,
+ unsigned long notifs,
+ struct netlink_ext_ack *extack)
+{
+ int ret = 0;
+
+ if (notifs & ETHTOOL_PSE_PORT_PRIO_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;
+ }
+
+ if (notifs & ETHTOOL_C33_PSE_EVENT_CLASSIFICATION)
+ ret = pse_pi_enable_isr(pcdev, id, extack);
+ else if (notifs & ETHTOOL_C33_PSE_EVENT_DISCONNECTION)
+ ret = pse_pi_disable_isr(pcdev, id, extack);
+
+ return ret;
+}
+
static irqreturn_t pse_isr(int irq, void *data)
{
struct netlink_ext_ack extack = {};
@@ -703,9 +1039,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;
@@ -716,6 +1053,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);
@@ -727,6 +1070,8 @@ static irqreturn_t pse_isr(int irq, void *data)
NULL);
}
+ mutex_unlock(&pcdev->lock);
+
return IRQ_HANDLED;
}
@@ -971,6 +1316,7 @@ static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
struct pse_control_status *status)
{
const struct pse_controller_ops *ops;
+ struct pse_pi *pi = &pcdev->pi[id];
ops = pcdev->ops;
if (!ops->ethtool_get_status) {
@@ -980,8 +1326,23 @@ static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
}
status->pse_id = pcdev->id;
- if (pcdev->pi[id].pw_d)
- status->pw_d_id = pcdev->pi[id].pw_d->id;
+ if (pi->pw_d) {
+ status->pw_d_id = pi->pw_d->id;
+ status->c33_prio_mode = pi->pw_d->port_prio_mode;
+ status->c33_discon_pol = pi->pw_d->discon_pol;
+ switch (pi->pw_d->port_prio_mode) {
+ case ETHTOOL_PSE_PORT_PRIO_STATIC:
+ status->c33_prio_max = pcdev->nr_lines;
+ status->c33_prio = pi->prio;
+ break;
+ case ETHTOOL_PSE_PORT_PRIO_DYNAMIC:
+ status->c33_prio_max = pcdev->pis_prio_max;
+ break;
+ default:
+ break;
+ }
+ status->c33_prio_supp_modes = pcdev->port_prio_supp_modes;
+ }
return ops->ethtool_get_status(pcdev, id, extack, status);
}
@@ -1020,8 +1381,9 @@ 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
- * regulator_disable on that case to fix the counters state.
+ * the PI is forcibly turn off by the controller or by the
+ * interrupt context. Call regulator_disable on that case
+ * to fix the counters state.
*/
if (psec->pcdev->pi[psec->id].admin_state_enabled &&
!regulator_is_enabled(psec->ps)) {
@@ -1094,6 +1456,32 @@ int pse_ethtool_set_config(struct pse_control *psec,
}
EXPORT_SYMBOL_GPL(pse_ethtool_set_config);
+static int pse_pi_update_pw_budget(struct pse_pi *pi, int id,
+ const unsigned int pw_limit,
+ struct netlink_ext_ack *extack)
+{
+ int pw_diff, ret;
+
+ pw_diff = pw_limit - pi->pw_allocated;
+ if (!pw_diff) {
+ return 0;
+ } 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);
+ return ret;
+ }
+
+ } else {
+ regulator_free_power_budget(pi->pw_d->supply, -pw_diff);
+ }
+ pi->pw_allocated = pw_limit;
+
+ return 0;
+}
+
/**
* pse_ethtool_set_pw_limit - set PSE control power limit
* @psec: PSE control pointer
@@ -1130,10 +1518,152 @@ 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->pi[psec->id],
+ 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);
+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->port_prio_mode) {
+ case ETHTOOL_PSE_PORT_PRIO_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_PORT_PRIO_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);
+
+int pse_ethtool_set_prio_mode(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ u32 prio_mode)
+{
+ struct pse_controller_dev *pcdev = psec->pcdev;
+ const struct pse_controller_ops *ops;
+ int ret = 0, i;
+
+ if (!(prio_mode & pcdev->port_prio_supp_modes)) {
+ NL_SET_ERR_MSG(extack, "priority mode not supported");
+ return -EOPNOTSUPP;
+ }
+
+ if (!pcdev->pi[psec->id].pw_d) {
+ NL_SET_ERR_MSG(extack, "no power domain attached");
+ return -EOPNOTSUPP;
+ }
+
+ /* ETHTOOL_PSE_PORT_PRIO_DISABLED can't be ORed with another mode */
+ if (prio_mode & ETHTOOL_PSE_PORT_PRIO_DISABLED &&
+ prio_mode & ~ETHTOOL_PSE_PORT_PRIO_DISABLED) {
+ NL_SET_ERR_MSG(extack,
+ "port priority can't be enabled and disabled simultaneously");
+ return -EINVAL;
+ }
+
+ ops = psec->pcdev->ops;
+
+ /* We don't want priority mode change in the middle of an
+ * enable/disable call
+ */
+ mutex_lock(&pcdev->lock);
+ pcdev->pi[psec->id].pw_d->port_prio_mode = prio_mode;
+
+ /* Reset all priorities of the Power Domain */
+ for (i = 0; i < psec->pcdev->nr_lines; i++) {
+ if (!pcdev->pi[i].rdev ||
+ pcdev->pi[i].pw_d != pcdev->pi[psec->id].pw_d)
+ continue;
+
+ pcdev->pi[i].prio = 0;
+
+ if (!ops->pi_set_prio)
+ continue;
+
+ if (pcdev->port_prio_supp_modes &
+ ETHTOOL_PSE_PORT_PRIO_DYNAMIC)
+ ret = ops->pi_set_prio(pcdev, psec->id, 0);
+ }
+
+ mutex_unlock(&psec->pcdev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pse_ethtool_set_prio_mode);
+
+int pse_ethtool_set_discon_pol(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ u32 pol)
+{
+ struct pse_controller_dev *pcdev = psec->pcdev;
+
+ if (!pcdev->pi[psec->id].pw_d) {
+ NL_SET_ERR_MSG(extack, "no power domain attached");
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&pcdev->lock);
+ pcdev->pi[psec->id].pw_d->discon_pol = pol;
+ mutex_unlock(&psec->pcdev->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pse_ethtool_set_discon_pol);
+
bool pse_has_podl(struct pse_control *psec)
{
return psec->pcdev->types & ETHTOOL_PSE_PODL;
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index bdf3e8c468fc..e84eba710dc8 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -9,6 +9,7 @@
#include <linux/list.h>
#include <uapi/linux/ethtool.h>
#include <linux/regulator/driver.h>
+#include <linux/workqueue.h>
/* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
#define MAX_PI_CURRENT 1920000
@@ -62,6 +63,13 @@ struct pse_control_config {
* is in charge of the memory allocation.
* @c33_pw_limit_nb_ranges: number of supported power limit configuration
* ranges
+ * @c33_prio_supp_modes: PSE port priority modes supported. Set by PSE core.
+ * @c33_prio_mode: PSE port priority mode selected. Set by PSE core.
+ * @c33_prio_max: max priority allowed for the c33_prio variable value. Set
+ * by PSE core.
+ * @c33_prio: priority of the PSE. Set by PSE core in case of static port
+ * priority mode.
+ * @c33_discon_pol: PSE disconnection policy selected. Set by PSE core.
*/
struct pse_control_status {
u32 pse_id;
@@ -76,6 +84,11 @@ struct 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;
+ u32 c33_prio_supp_modes;
+ enum pse_port_prio_modes c33_prio_mode;
+ u32 c33_prio_max;
+ u32 c33_prio;
+ u32 c33_discon_pol;
};
/**
@@ -95,6 +108,10 @@ struct pse_control_status {
* set_current_limit regulator callback.
* Should not return an error in case of MAX_PI_CURRENT
* current value set.
+ * @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 (*ethtool_get_status)(struct pse_controller_dev *pcdev,
@@ -109,6 +126,9 @@ struct pse_controller_ops {
int id);
int (*pi_set_current_limit)(struct pse_controller_dev *pcdev,
int id, int max_uA);
+ 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;
@@ -143,6 +163,12 @@ 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 port priority mode
+ * @isr_enabled: PSE PI power status managed by the interruption handler.
+ * This variable is relevant when the power enabled management
+ * is a managed in software like the static port priority mode.
+ * @pw_allocated: Power allocated to a PSE PI to manage power budget in
+ * static port priority mode
*/
struct pse_pi {
struct pse_pi_pairset pairset[2];
@@ -150,6 +176,9 @@ struct pse_pi {
struct regulator_dev *rdev;
bool admin_state_enabled;
struct pse_power_domain *pw_d;
+ int prio;
+ bool isr_enabled;
+ int pw_allocated;
};
/**
@@ -168,6 +197,8 @@ 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
+ * @port_prio_supp_modes: Bitfield of port priority mode supported by the PSE
*/
struct pse_controller_dev {
const struct pse_controller_ops *ops;
@@ -183,6 +214,8 @@ struct pse_controller_dev {
bool no_of_pse_pi;
u32 id;
int irq;
+ unsigned int pis_prio_max;
+ u32 port_prio_supp_modes;
};
#if IS_ENABLED(CONFIG_PSE_CONTROLLER)
@@ -207,6 +240,15 @@ 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);
+int pse_ethtool_set_prio_mode(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ u32 prio_mode);
+int pse_ethtool_set_discon_pol(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ u32 pol);
bool pse_has_podl(struct pse_control *psec);
bool pse_has_c33(struct pse_control *psec);
@@ -244,6 +286,27 @@ 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 int pse_ethtool_set_prio_mode(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ u32 prio_mode)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int pse_ethtool_set_discon_pol(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ u32 pol)
+{
+ 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 a4c93d6de218..b6727049840c 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1002,11 +1002,84 @@ 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 145.2.6 PSE detection of PDs
+ * @ETHTOOL_C33_PSE_EVENT_CLASSIFICATION: classification process occur on
+ * the PSE. IEEE 802.3-2022 145.2.8 PSE classification of PDs and
+ * mutual identification
+ * @ETHTOOL_C33_PSE_EVENT_DISCONNECTION: PD has been disconnected on the PSE.
+ * @ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR: PSE faced an error managing the
+ * power control from software.
*/
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_SW_PW_CONTROL_ERROR = 1 << 5,
+};
+
+/**
+ * enum pse_port_prio_modes - PSE port priority modes.
+ * @ETHTOOL_PSE_PORT_PRIO_DISABLED: Port priority disabled.
+ * @ETHTOOL_PSE_PORT_PRIO_STATIC: PSE static port priority. Port priority
+ * based on the power requested during PD classification. This mode
+ * is managed by the PSE core.
+ * @ETHTOOL_PSE_PORT_PRIO_DYNAMIC: PSE dynamic port priority. Port priority
+ * based on the current consumption per ports compared to the total
+ * power budget. This mode is managed by the PSE controller.
+ */
+
+enum pse_port_prio_modes {
+ ETHTOOL_PSE_PORT_PRIO_DISABLED = 1 << 0,
+ ETHTOOL_PSE_PORT_PRIO_STATIC = 1 << 1,
+ ETHTOOL_PSE_PORT_PRIO_DYNAMIC = 1 << 2,
+};
+
+/**
+ * enum ethtool_pse_disconnection_policy - Disconnection strategies for
+ * same-priority devices when power budget is exceeded, tailored to
+ * specific priority modes.
+ *
+ * @ETHTOOL_PSE_DISCON_LRC: Disconnect least recently connected device.
+ * Relevant for: ETHTOOL_PSE_PORT_PRIO_STATIC
+ * Behavior: When multiple devices share the same priority level, the
+ * system disconnects the device that was most recently connected.
+ * Rationale: This strategy favors stability for longer-standing
+ * connections, assuming that established devices may be more critical.
+ * Use Case: Suitable for systems prioritizing stable power allocation for
+ * existing static-priority connections, making newer devices suitable
+ * candidates for disconnection if limits are exceeded.
+ * @ETHTOOL_PSE_DISCON_ROUND_ROBIN_IDX_LOWEST_FIRST: Disconnect based on port
+ * index in a round-robin manner, starting with the lowest index.
+ * Relevant for: ETHTOOL_PSE_PORT_PRIO_STATIC
+ * Behavior: Disconnects devices sequentially based on port index, starting
+ * with the lowest. If multiple disconnections are required, the process
+ * continues in ascending order.
+ * Rationale: Provides a predictable, systematic approach for
+ * static-priority devices, making it clear which device will be
+ * disconnected next if power limits are reached.
+ * Use Case: Appropriate for systems where static-priority devices are
+ * equal in role, and fairness in disconnections is prioritized.
+ *
+ * Each device can have multiple disconnection policies set as an array of
+ * priorities. When the power budget is exceeded, the policies are executed
+ * in the order defined by the user. This allows for a more nuanced and
+ * flexible approach to handling power constraints across a range of devices
+ * with similar priorities or attributes.
+ *
+ * Example Usage:
+ * Users can specify an ordered list of policies, such as starting with
+ * `PSE_DISCON_STATIC_CLASS_HIGHEST_FIRST` to prioritize based on class,
+ * followed by `PSE_DISCON_LRC` to break ties based on connection time.
+ * This ordered execution ensures that power disconnections align closely
+ * with the system’s operational requirements and priorities.
+ */
+enum ethtool_pse_disconnection_policy {
+ ETHTOOL_PSE_DISCON_LRC = 1 << 0,
+ ETHTOOL_PSE_DISCON_ROUND_ROBIN_IDX_LOWEST_FIRST = 1 << 1,
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-21 14:42 ` [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority Kory Maincent
@ 2024-11-26 8:38 ` Oleksij Rempel
2024-11-26 15:31 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-26 8:38 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:47PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> This patch introduces the ability to configure the PSE PI port priority.
> Port priority 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 port priority modes.
Priorit mode is too abstract for me, in this case we are talking about
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.
>
> 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 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 | 550 +++++++++++++++++++++++++++++++++++++++++-
> include/linux/pse-pd/pse.h | 63 +++++
> include/uapi/linux/ethtool.h | 73 ++++++
> 3 files changed, 676 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
> index ff0ffbccf139..f15a693692ae 100644
> --- a/drivers/net/pse-pd/pse_core.c
> +++ b/drivers/net/pse-pd/pse_core.c
> @@ -40,10 +40,17 @@ struct pse_control {
> * struct pse_power_domain - a PSE power domain
> * @id: ID of the power domain
> * @supply: Power supply the Power Domain
> + * @port_prio_mode: Current port priority mode of the power domain
Same here, it is Budget Evaluation Strategy. May be: budget_eval_strategy
> + * @discon_pol: Current disonnection policy of the power domain
> + * @pi_lrc_id: ID of the last recently connected PI. -1 if none. Relevant
> + * for static port priority mode.
> */
> struct pse_power_domain {
> int id;
> struct regulator *supply;
> + u32 port_prio_mode;
> + u32 discon_pol;
> + int pi_lrc_id;
We should store all ports withing the domain in a list and process the
list backwards or forwards, depending on disconnection policy.
> };
>
> static int of_load_single_pse_pi_pairset(struct device_node *node,
> @@ -222,6 +229,33 @@ static int of_load_pse_pis(struct pse_controller_dev *pcdev)
> return ret;
> }
>
> +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);
> +}
> +
> +/* Helper returning true if the power control is managed from the software
> + * in the interrupt handler
> + */
Please use function comment format. I would really love to have comments
on all new functions.
> +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->port_prio_mode & ETHTOOL_PSE_PORT_PRIO_STATIC)
here should be pw_d->port_prio_mode == ETHTOOL_PSE_PORT_PRIO_STATIC
We can't support multiple evaluation strategies per port.
> + return true;
> + if (pw_d->port_prio_mode == ETHTOOL_PSE_PORT_PRIO_DISABLED &&
> + pcdev->ops->pi_enable && pcdev->ops->pi_get_pw_req &&
> + pcdev->irq)
> + return true;
> +
> + return false;
> +}
> +
....
> +int pse_ethtool_set_prio_mode(struct pse_control *psec,
> + struct netlink_ext_ack *extack,
> + u32 prio_mode)
> +{
> + struct pse_controller_dev *pcdev = psec->pcdev;
> + const struct pse_controller_ops *ops;
> + int ret = 0, i;
> +
> + if (!(prio_mode & pcdev->port_prio_supp_modes)) {
> + NL_SET_ERR_MSG(extack, "priority mode not supported");
> + return -EOPNOTSUPP;
> + }
> +
> + if (!pcdev->pi[psec->id].pw_d) {
> + NL_SET_ERR_MSG(extack, "no power domain attached");
> + return -EOPNOTSUPP;
> + }
> +
> + /* ETHTOOL_PSE_PORT_PRIO_DISABLED can't be ORed with another mode */
> + if (prio_mode & ETHTOOL_PSE_PORT_PRIO_DISABLED &&
> + prio_mode & ~ETHTOOL_PSE_PORT_PRIO_DISABLED) {
> + NL_SET_ERR_MSG(extack,
> + "port priority can't be enabled and disabled simultaneously");
> + return -EINVAL;
> + }
> +
> + ops = psec->pcdev->ops;
> +
> + /* We don't want priority mode change in the middle of an
> + * enable/disable call
> + */
> + mutex_lock(&pcdev->lock);
> + pcdev->pi[psec->id].pw_d->port_prio_mode = prio_mode;
In proposed implementation we have can set policies per port, but it
will affect complete domain. This is not good. It feels like a separate
challenge with extra discussion and work. I would recommend not to
implement policy setting right now.
If you will decide to implement setting of policies anyway, then we need
to discuss the interface.
- If the policy should be done per domain, then we will need a separate
interface to interact with domains.
Pro: seems to be easier to implement.
- If we will go with policy per port, wich would make sense too, then
some rework of this patch is needed.
Pro: can combine best of both strategies: set ports with wide load
range to static strategy and use dynamic strategy on other ports.
Right now we do not have software implementation for dynamic mode,
implementing configuration of the policies from user space can be
implemented later. It is enough to provide information about what
hard coded policy is currently used.
> /* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
> #define MAX_PI_CURRENT 1920000
> @@ -62,6 +63,13 @@ struct pse_control_config {
> * is in charge of the memory allocation.
> * @c33_pw_limit_nb_ranges: number of supported power limit configuration
> * ranges
> + * @c33_prio_supp_modes: PSE port priority modes supported. Set by PSE core.
> + * @c33_prio_mode: PSE port priority mode selected. Set by PSE core.
> + * @c33_prio_max: max priority allowed for the c33_prio variable value. Set
> + * by PSE core.
> + * @c33_prio: priority of the PSE. Set by PSE core in case of static port
> + * priority mode.
> + * @c33_discon_pol: PSE disconnection policy selected. Set by PSE core.
Priority configuration is not port of IEEE 802.3 specification. c33_
prefix should be removed here.
> */
> struct pse_control_status {
> u32 pse_id;
> @@ -76,6 +84,11 @@ struct 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;
> + u32 c33_prio_supp_modes;
> + enum pse_port_prio_modes c33_prio_mode;
> + u32 c33_prio_max;
> + u32 c33_prio;
> + u32 c33_discon_pol;
> };
....
> struct module;
> @@ -143,6 +163,12 @@ 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 port priority mode
> + * @isr_enabled: PSE PI power status managed by the interruption handler.
> + * This variable is relevant when the power enabled management
> + * is a managed in software like the static port priority mode.
> + * @pw_allocated: Power allocated to a PSE PI to manage power budget in
> + * static port priority mode
> */
> struct pse_pi {
> struct pse_pi_pairset pairset[2];
> @@ -150,6 +176,9 @@ struct pse_pi {
> struct regulator_dev *rdev;
> bool admin_state_enabled;
> struct pse_power_domain *pw_d;
> + int prio;
> + bool isr_enabled;
> + int pw_allocated;
s/pw_allocated/pw_allocated_mw/
> return false;
> diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
> index a4c93d6de218..b6727049840c 100644
> --- a/include/uapi/linux/ethtool.h
> +++ b/include/uapi/linux/ethtool.h
> @@ -1002,11 +1002,84 @@ 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 145.2.6 PSE detection of PDs
33.2.5 and 145.2.6 -> 30.9.1.1.5 aPSEPowerDetectionStatus
> + * @ETHTOOL_C33_PSE_EVENT_CLASSIFICATION: classification process occur on
> + * the PSE. IEEE 802.3-2022 145.2.8 PSE classification of PDs and
> + * mutual identification
33.2.6 and 145.2.8 -> 30.9.1.1.8 aPSEPowerClassification
> + * @ETHTOOL_C33_PSE_EVENT_DISCONNECTION: PD has been disconnected on the PSE.
This one seems to be related to following parts of specification:
33.3.8 and 145.3.9 PD Maintain Power Signature
33.5.1.2.9 MPS Absent
30.9.1.1.20 aPSEMPSAbsentCounter
> + * @ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR: PSE faced an error managing the
> + * power control from software.
> */
>
> 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_SW_PW_CONTROL_ERROR = 1 << 5,
> +};
--
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] 60+ messages in thread* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-26 8:38 ` Oleksij Rempel
@ 2024-11-26 15:31 ` Kory Maincent
2024-11-26 15:52 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-26 15:31 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
Hello Oleksij,
Thanks for your quick reviews!
On Tue, 26 Nov 2024 09:38:27 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> > +int pse_ethtool_set_prio_mode(struct pse_control *psec,
> > + struct netlink_ext_ack *extack,
> > + u32 prio_mode)
> > +{
> > + struct pse_controller_dev *pcdev = psec->pcdev;
> > + const struct pse_controller_ops *ops;
> > + int ret = 0, i;
> > +
> > + if (!(prio_mode & pcdev->port_prio_supp_modes)) {
> > + NL_SET_ERR_MSG(extack, "priority mode not supported");
> > + return -EOPNOTSUPP;
> > + }
> > +
> > + if (!pcdev->pi[psec->id].pw_d) {
> > + NL_SET_ERR_MSG(extack, "no power domain attached");
> > + return -EOPNOTSUPP;
> > + }
> > +
> > + /* ETHTOOL_PSE_PORT_PRIO_DISABLED can't be ORed with another mode
> > */
> > + if (prio_mode & ETHTOOL_PSE_PORT_PRIO_DISABLED &&
> > + prio_mode & ~ETHTOOL_PSE_PORT_PRIO_DISABLED) {
> > + NL_SET_ERR_MSG(extack,
> > + "port priority can't be enabled and
> > disabled simultaneously");
> > + return -EINVAL;
> > + }
> > +
> > + ops = psec->pcdev->ops;
> > +
> > + /* We don't want priority mode change in the middle of an
> > + * enable/disable call
> > + */
> > + mutex_lock(&pcdev->lock);
> > + pcdev->pi[psec->id].pw_d->port_prio_mode = prio_mode;
>
> In proposed implementation we have can set policies per port, but it
> will affect complete domain. This is not good. It feels like a separate
> challenge with extra discussion and work. I would recommend not to
> implement policy setting right now.
>
> If you will decide to implement setting of policies anyway, then we need
> to discuss the interface.
> - If the policy should be done per domain, then we will need a separate
> interface to interact with domains.
> Pro: seems to be easier to implement.
> - If we will go with policy per port, wich would make sense too, then
> some rework of this patch is needed.
> Pro: can combine best of both strategies: set ports with wide load
> range to static strategy and use dynamic strategy on other ports.
>
> Right now we do not have software implementation for dynamic mode,
> implementing configuration of the policies from user space can be
> implemented later. It is enough to provide information about what
> hard coded policy is currently used.
There is no PSE that support static and dynamic mode indeed but the aim was to
be able to disable the budget evaluation strategy.
In fact we could have static strategy with a disconnection policy that do not
power a newly connected PD if we become over budget. This behavior would be
something similar to no budget evaluation strategy.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-26 15:31 ` Kory Maincent
@ 2024-11-26 15:52 ` Kory Maincent
2024-11-27 9:30 ` Oleksij Rempel
0 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-26 15:52 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Tue, 26 Nov 2024 16:31:55 +0100
Kory Maincent <kory.maincent@bootlin.com> wrote:
> Hello Oleksij,
>
> Thanks for your quick reviews!
>
> On Tue, 26 Nov 2024 09:38:27 +0100
> Oleksij Rempel <o.rempel@pengutronix.de> wrote:
>
> > > +int pse_ethtool_set_prio_mode(struct pse_control *psec,
> > > + struct netlink_ext_ack *extack,
> > > + u32 prio_mode)
> > > +{
> > > + struct pse_controller_dev *pcdev = psec->pcdev;
> > > + const struct pse_controller_ops *ops;
> > > + int ret = 0, i;
> > > +
> > > + if (!(prio_mode & pcdev->port_prio_supp_modes)) {
> > > + NL_SET_ERR_MSG(extack, "priority mode not supported");
> > > + return -EOPNOTSUPP;
> > > + }
> > > +
> > > + if (!pcdev->pi[psec->id].pw_d) {
> > > + NL_SET_ERR_MSG(extack, "no power domain attached");
> > > + return -EOPNOTSUPP;
> > > + }
> > > +
> > > + /* ETHTOOL_PSE_PORT_PRIO_DISABLED can't be ORed with another mode
> > > */
> > > + if (prio_mode & ETHTOOL_PSE_PORT_PRIO_DISABLED &&
> > > + prio_mode & ~ETHTOOL_PSE_PORT_PRIO_DISABLED) {
> > > + NL_SET_ERR_MSG(extack,
> > > + "port priority can't be enabled and
> > > disabled simultaneously");
> > > + return -EINVAL;
> > > + }
> > > +
> > > + ops = psec->pcdev->ops;
> > > +
> > > + /* We don't want priority mode change in the middle of an
> > > + * enable/disable call
> > > + */
> > > + mutex_lock(&pcdev->lock);
> > > + pcdev->pi[psec->id].pw_d->port_prio_mode = prio_mode;
> >
> > In proposed implementation we have can set policies per port, but it
> > will affect complete domain. This is not good. It feels like a separate
> > challenge with extra discussion and work. I would recommend not to
> > implement policy setting right now.
> >
> > If you will decide to implement setting of policies anyway, then we need
> > to discuss the interface.
> > - If the policy should be done per domain, then we will need a separate
> > interface to interact with domains.
> > Pro: seems to be easier to implement.
> > - If we will go with policy per port, wich would make sense too, then
> > some rework of this patch is needed.
> > Pro: can combine best of both strategies: set ports with wide load
> > range to static strategy and use dynamic strategy on other ports.
We already talked about it but a policies per port seems irrelevant to me.
https://lore.kernel.org/netdev/ZySR75i3BEzNbjnv@pengutronix.de/
How do we compare the priority value of ports that use different budget
strategy? How do we manage in the same power domain two ports with
different budget strategies or disconnection policies?
We indeed may need a separate interface to configure the PSE power domain
budget strategies and disconnection policies.
I think not being able to set the budget evaluation strategy is not relevant
for now as we don't have PSE which could support both, but being able to
set the disconnection policies may be relevant.
If we don't add this support to this series how do we decide which is the
default disconnection policy supported?
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-26 15:52 ` Kory Maincent
@ 2024-11-27 9:30 ` Oleksij Rempel
2024-11-27 10:11 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-27 9:30 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Tue, Nov 26, 2024 at 04:52:28PM +0100, Kory Maincent wrote:
> On Tue, 26 Nov 2024 16:31:55 +0100
> Kory Maincent <kory.maincent@bootlin.com> wrote:
>
> > Hello Oleksij,
> >
> > Thanks for your quick reviews!
> >
> > On Tue, 26 Nov 2024 09:38:27 +0100
> > Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> >
> > > > +int pse_ethtool_set_prio_mode(struct pse_control *psec,
> > > > + struct netlink_ext_ack *extack,
> > > > + u32 prio_mode)
> > > > +{
> > > > + struct pse_controller_dev *pcdev = psec->pcdev;
> > > > + const struct pse_controller_ops *ops;
> > > > + int ret = 0, i;
> > > > +
> > > > + if (!(prio_mode & pcdev->port_prio_supp_modes)) {
> > > > + NL_SET_ERR_MSG(extack, "priority mode not supported");
> > > > + return -EOPNOTSUPP;
> > > > + }
> > > > +
> > > > + if (!pcdev->pi[psec->id].pw_d) {
> > > > + NL_SET_ERR_MSG(extack, "no power domain attached");
> > > > + return -EOPNOTSUPP;
> > > > + }
> > > > +
> > > > + /* ETHTOOL_PSE_PORT_PRIO_DISABLED can't be ORed with another mode
> > > > */
> > > > + if (prio_mode & ETHTOOL_PSE_PORT_PRIO_DISABLED &&
> > > > + prio_mode & ~ETHTOOL_PSE_PORT_PRIO_DISABLED) {
> > > > + NL_SET_ERR_MSG(extack,
> > > > + "port priority can't be enabled and
> > > > disabled simultaneously");
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + ops = psec->pcdev->ops;
> > > > +
> > > > + /* We don't want priority mode change in the middle of an
> > > > + * enable/disable call
> > > > + */
> > > > + mutex_lock(&pcdev->lock);
> > > > + pcdev->pi[psec->id].pw_d->port_prio_mode = prio_mode;
> > >
> > > In proposed implementation we have can set policies per port, but it
> > > will affect complete domain. This is not good. It feels like a separate
> > > challenge with extra discussion and work. I would recommend not to
> > > implement policy setting right now.
> > >
> > > If you will decide to implement setting of policies anyway, then we need
> > > to discuss the interface.
> > > - If the policy should be done per domain, then we will need a separate
> > > interface to interact with domains.
> > > Pro: seems to be easier to implement.
> > > - If we will go with policy per port, wich would make sense too, then
> > > some rework of this patch is needed.
> > > Pro: can combine best of both strategies: set ports with wide load
> > > range to static strategy and use dynamic strategy on other ports.
>
> We already talked about it but a policies per port seems irrelevant to me.
> https://lore.kernel.org/netdev/ZySR75i3BEzNbjnv@pengutronix.de/
> How do we compare the priority value of ports that use different budget
> strategy? How do we manage in the same power domain two ports with
> different budget strategies or disconnection policies?
Good question :)
> We indeed may need a separate interface to configure the PSE power domain
> budget strategies and disconnection policies.
And a way to upload everything in atomic way, but I see it as
optimization and can be done separately
> I think not being able to set the budget evaluation strategy is not relevant
> for now as we don't have PSE which could support both,
Both can be implemented for TI. By constantly polling the channel
current register, it should be possible to implement dynamic strategy.
> but being able to set the disconnection policies may be relevant.
> If we don't add this support to this series how do we decide which is the
> default disconnection policy supported?
Use hard coded one ¯\_(ツ)_/¯
Anyway, assuming you will decide to implement everything per port. Here
how I assume it would work.
Budget Evaluation Strategy: We have following modes for now: disabled, static, and
dynamic.
- 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.
- Static: The static method is the safest option and should be used by default.
When the static method is enabled for a port, the classification information
(such as power class) is used for budget evaluation.
- Dynamic: If the dynamic method is used, the software will start with the
classification as an initial step. After that, it will begin monitoring the
port by polling the current information for the related channel. The system
will likely use the maximum detected current and a threshold to update or
reduce the budget allocation for the related port.
Right now I'm not sure about manual mode - for the case where classification
is not working properly.
Disconnection Policy: can only be applied if the Budget Evaluation Strategy
is not disabled.
- Disabled: The port is not subject to disconnection under any circumstances.
This can be used for critical devices that need to remain powered at all
times, or for administrative purposes to avoid unexpected disconnections.
Possible use cases include testing, allowing user space to implement a
disconnection policy, or pinning certain ports as the highest priority that
cannot be overwritten for critical devices. Another use case could be
temporarily addressing misconfigured priorities: an admin could set the
policy to disabled, adjust the priority, and use a disconnection policy
resolution status interface (currently not implemented) to verify if the
port would be disconnected with the updated priority settings, and then set
the policy back to a non-disabled state.
- Port Index-Based Policy: "I Know What I Do, but I Do Not Have Permission to
Configure Software"
Behavior: With this approach, the port index becomes the way to determine the
priority of connections. Users can manage priorities simply by deciding which
port they plug into:
Lower-Indexed Ports: These ports have higher priority, meaning devices
plugged into these ports are protected from disconnection until absolutely
necessary. Higher-Indexed Ports: These ports are more likely to be
disconnected first when a power budget violation occurs.
Use Cases:
Structured Environment Without Full Control: Ideal for situations where
users understand the importance of the devices but do not have admin
access to configure software settings.
Mechanical Administration: Users can simply re-plug devices into
different ports to change their priority, using the port layout itself
as a mechanism for priority management. This allows an effective but
simple way of reassigning criticality without touching the software
layer.
- LRC-Based Policy: "I Have No Idea About the Architecture, and I Just Enabled
This One Device"
Behavior: In this case, the policy targets recent user actions, assuming
the user has minimal context about the system's architecture. The most
recently connected device is likely the least critical and is therefore
disconnected first.
Use Cases:
Chaotic Environment: Suitable for environments where users do not
know the priority structure and are randomly plugging in devices,
often without understanding the power budget implications.
Immediate Feedback: If a user connects a device and it is quickly
disconnected, they are more likely to notice and either try connecting
at a different time or consult someone for guidance.
- Round-Robin (RR) Policy: "I Do Not Care, but I Want You All to Suffer Equally"
Behavior: In the Round-Robin policy, all ports are treated equally without
any specific prioritization. The disconnection burden is distributed evenly
among all eligible ports, ensuring that no specific port is repeatedly
penalized. This policy ensures fairness by giving every port an equal
chance of being disconnected.
Use Cases:
Fair Distribution in Shared Environments: Suitable for environments
where all devices are of similar importance, and fairness is key. This
ensures that no single user or device consistently bears the impact of
a budget violation.
Non-Critical Setup: Ideal for situations where there are no critical
devices, and all ports should have an equal chance of being
disconnected. It provides a simple and fair mechanism for managing
power resources without requiring specific prioritization.
Regarding the mixing of disconnection policies within one power domain, I've
thought more about how we could implement this, particularly when we focus on
three primary types of policies: Least Recently Connected (LRC), Port
Index-Based (Index), and Round-Robin (RR).
Defined Priority Order:
To make the system straightforward and predictable, we could define a hard
execution priority order for these policies:
- LRC - Highest priority: If a port has LRC enabled, it will be considered for
disconnection first. This ensures that the least recently connected device is
always targeted first, which works well for devices that are likely temporary
or less critical.
- Index-Based - Second priority: Once no more LRC ports are eligible for
disconnection, the system evaluates Index-Based ports. Ports with a higher
physical index will be prioritized for disconnection, allowing for some manual
control by re-arranging device connections.
- Round-Robin (RR) - Lowest priority: Finally, Round-Robin is applied to ensure
fairness among the remaining eligible ports. This policy cycles through the
ports to distribute the disconnection burden evenly.
User Configuration
In terms of user configuration:
Users only need to set the top allowed priority for each port. For example, if
a port is set to LRC, it will always be considered first for disconnection
during a budget violation. The connection order of all LRC ports should be
preserved.
If a port is set to Index, it will be preserved until all LRC ports are
disconnected.
Setting a port to RR will make it the last in line for disconnection, thus
ensuring the fairest distribution when other more prioritized policies have
already been applied. However, in practice, it may never be executed if all
ports have higher priority policies.
--
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] 60+ messages in thread* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-27 9:30 ` Oleksij Rempel
@ 2024-11-27 10:11 ` Kory Maincent
2024-11-27 10:31 ` Oleksij Rempel
0 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-27 10:11 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, 27 Nov 2024 10:30:43 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> On Tue, Nov 26, 2024 at 04:52:28PM +0100, Kory Maincent wrote:
> > On Tue, 26 Nov 2024 16:31:55 +0100
> > Kory Maincent <kory.maincent@bootlin.com> wrote:
> >
> > > Hello Oleksij,
> > >
> > > Thanks for your quick reviews!
> > >
> > > On Tue, 26 Nov 2024 09:38:27 +0100
> > > Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> > >
> [...]
> [...]
> >
> > We already talked about it but a policies per port seems irrelevant to me.
> > https://lore.kernel.org/netdev/ZySR75i3BEzNbjnv@pengutronix.de/
> > How do we compare the priority value of ports that use different budget
> > strategy? How do we manage in the same power domain two ports with
> > different budget strategies or disconnection policies?
>
> Good question :)
>
> > We indeed may need a separate interface to configure the PSE power domain
> > budget strategies and disconnection policies.
>
> And a way to upload everything in atomic way, but I see it as
> optimization and can be done separately
>
> > I think not being able to set the budget evaluation strategy is not relevant
> > for now as we don't have PSE which could support both,
>
> Both can be implemented for TI. By constantly polling the channel
> current register, it should be possible to implement dynamic strategy.
>
> > but being able to set the disconnection policies may be relevant.
> > If we don't add this support to this series how do we decide which is the
> > default disconnection policy supported?
>
> Use hard coded one ¯\_(ツ)_/¯
I think we could start with disabled disconnection policy for now.
The user cans still play with the priority value which is really reasonable as
there is as many priority values as PSE ports in the static strategy.
Should we still report it in the status as there is no disconnection policy?
Maybe we could add it at the time we will support several disconnection
policies.
> In terms of user configuration:
>
> Users only need to set the top allowed priority for each port. For example, if
> a port is set to LRC, it will always be considered first for disconnection
> during a budget violation. The connection order of all LRC ports should be
> preserved.
>
> If a port is set to Index, it will be preserved until all LRC ports are
> disconnected.
>
> Setting a port to RR will make it the last in line for disconnection, thus
> ensuring the fairest distribution when other more prioritized policies have
> already been applied. However, in practice, it may never be executed if all
> ports have higher priority policies.
That's a nice brainstorm! With that we will have a first idea when we would
like to really implement the disconnection policies.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-27 10:11 ` Kory Maincent
@ 2024-11-27 10:31 ` Oleksij Rempel
2024-11-27 11:00 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Oleksij Rempel @ 2024-11-27 10:31 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, Nov 27, 2024 at 11:11:26AM +0100, Kory Maincent wrote:
> On Wed, 27 Nov 2024 10:30:43 +0100
> Oleksij Rempel <o.rempel@pengutronix.de> wrote:
>
> > On Tue, Nov 26, 2024 at 04:52:28PM +0100, Kory Maincent wrote:
> > > On Tue, 26 Nov 2024 16:31:55 +0100
> > > Kory Maincent <kory.maincent@bootlin.com> wrote:
> > >
> > > > Hello Oleksij,
> > > >
> > > > Thanks for your quick reviews!
> > > >
> > > > On Tue, 26 Nov 2024 09:38:27 +0100
> > > > Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> > > >
> > [...]
> > [...]
> > >
> > > We already talked about it but a policies per port seems irrelevant to me.
> > > https://lore.kernel.org/netdev/ZySR75i3BEzNbjnv@pengutronix.de/
> > > How do we compare the priority value of ports that use different budget
> > > strategy? How do we manage in the same power domain two ports with
> > > different budget strategies or disconnection policies?
> >
> > Good question :)
> >
> > > We indeed may need a separate interface to configure the PSE power domain
> > > budget strategies and disconnection policies.
> >
> > And a way to upload everything in atomic way, but I see it as
> > optimization and can be done separately
> >
> > > I think not being able to set the budget evaluation strategy is not relevant
> > > for now as we don't have PSE which could support both,
> >
> > Both can be implemented for TI. By constantly polling the channel
> > current register, it should be possible to implement dynamic strategy.
> >
> > > but being able to set the disconnection policies may be relevant.
> > > If we don't add this support to this series how do we decide which is the
> > > default disconnection policy supported?
> >
> > Use hard coded one ¯\_(ツ)_/¯
>
> I think we could start with disabled disconnection policy for now.
> The user cans still play with the priority value which is really reasonable as
> there is as many priority values as PSE ports in the static strategy.
Hm, since prios without disconnecting do not make sens and it looks more like
all disconnection policies are optimizations steps for configurations with
multiple ports having same prio, i would suggest an implementation where
no same prios are allowed on multiple ports.
> Should we still report it in the status as there is no disconnection policy?
> Maybe we could add it at the time we will support several disconnection
> policies.
Yes. It would be better to have a discussion with some one having real use case.
--
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] 60+ messages in thread
* Re: [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority
2024-11-27 10:31 ` Oleksij Rempel
@ 2024-11-27 11:00 ` Kory Maincent
0 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-27 11:00 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, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, 27 Nov 2024 11:31:18 +0100
Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> On Wed, Nov 27, 2024 at 11:11:26AM +0100, Kory Maincent wrote:
> > On Wed, 27 Nov 2024 10:30:43 +0100
> > Oleksij Rempel <o.rempel@pengutronix.de> wrote:
> >
> > > On Tue, Nov 26, 2024 at 04:52:28PM +0100, Kory Maincent wrote:
> [...]
> [...]
> > > [...]
> > > [...]
> [...]
> > >
> > > Good question :)
> > >
> [...]
> > >
> > > And a way to upload everything in atomic way, but I see it as
> > > optimization and can be done separately
> > >
> [...]
> > >
> > > Both can be implemented for TI. By constantly polling the channel
> > > current register, it should be possible to implement dynamic strategy.
> > >
> [...]
> > >
> > > Use hard coded one ¯\_(ツ)_/¯
> >
> > I think we could start with disabled disconnection policy for now.
> > The user cans still play with the priority value which is really reasonable
> > as there is as many priority values as PSE ports in the static strategy.
>
> Hm, since prios without disconnecting do not make sens and it looks more like
> all disconnection policies are optimizations steps for configurations with
> multiple ports having same prio, i would suggest an implementation where
> no same prios are allowed on multiple ports.
This won't allow users that don't care about priorities.
I think as we support only budget strategy for now. On the case of power budget
exceeded we should disconnect all the ports that are on the lowest priority
until we get enough power. If there is no ports with a lower priority than the
newly connected we should not power on the newly connected.
With my proposition, at boot as all the ports have the same priority it is like
we don't care about priority.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 22/27] net: ethtool: Add PSE new port priority support feature
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (20 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 21/27] net: pse-pd: Add support for getting and setting port priority Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 23/27] netlink: specs: Expand the PSE netlink command with newly supported features Kory Maincent
` (5 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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(), pse_ethtool_set_prio_mode() and
pse_ethtool_set_discon_pol() to configure the PSE port priority, mode and
disconnection policy.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Change in v3:
- Add disconnection policy.
Change in v2:
- Improve port priority documentation.
- Add port priority modes.
---
Documentation/networking/ethtool-netlink.rst | 77 ++++++++++++++++++++++++++++
include/uapi/linux/ethtool_netlink.h | 5 ++
net/ethtool/pse-pd.c | 66 ++++++++++++++++++++++++
3 files changed, 148 insertions(+)
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index 3573543ae5ad..b231641dd4a9 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1768,6 +1768,15 @@ 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_PRIO_SUPP_MODES`` u32 priority modes supported
+ ``ETHTOOL_A_C33_PSE_PRIO_MODE`` u32 priority mode of the PSE
+ currently configured
+ ``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
+ ``ETHTOOL_A_C33_PSE_DISCON_POL`` u32 disconnection policy
+ currently configured
========================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
@@ -1847,6 +1856,21 @@ 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_PRIO_MODE`` attributes is used to
+identifies the currently configured C33 PSE priority mode.
+When set, the optional ``ETHTOOL_A_C33_PSE_DISCON_POL`` attributes is used to
+identifies the currently configured C33 PSE disconnection policy.
+For a description of C33 PSE priority modes and disconnection policy,
+see ``PSE_SET``.
+
+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 C33 PSE priority attributes, see ``PSE_SET``.
+
PSE_SET
=======
@@ -1860,6 +1884,12 @@ 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_MODE`` u32 Control priority mode of the
+ PoE PSE
+ ``ETHTOOL_A_C33_PSE_PRIO`` u32 Control priority of the
+ PoE PSE
+ ``ETHTOOL_A_C33_PSE_DISCON_POL`` u32 Control disconnection policy
+ of the PoE PSE
====================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_CONTROL`` attribute is used
@@ -1882,6 +1912,53 @@ 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_MODE`` attributes is used to
+control the C33 PSE priority mode. The available mode are:
+
+1. 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.
+
+ 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:
+
+ 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.
+
+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.
+
+When set, the optional ``ETHTOOL_A_C33_PSE_DISCON_POL`` attributes is used
+to control the disconnection policy. When port are on the same priority
+the disconnection policy is used to specify the shutdown order.
+
+.. kernel-doc:: include/uapi/linux/ethtool.h
+ :identifiers: ethtool_pse_disconnection_policy
+
RSS_GET
=======
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 088ad7b956fb..e668a91ed1ca 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -973,6 +973,11 @@ enum {
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES, /* nest - _C33_PSE_PW_LIMIT_* */
ETHTOOL_A_PSE_ID, /* u32 */
ETHTOOL_A_PSE_PW_D_ID, /* u32 */
+ ETHTOOL_A_C33_PSE_PRIO_SUPP_MODES, /* u32 */
+ ETHTOOL_A_C33_PSE_PRIO_MODE, /* u32 */
+ ETHTOOL_A_C33_PSE_PRIO_MAX, /* u32 */
+ ETHTOOL_A_C33_PSE_PRIO, /* u32 */
+ ETHTOOL_A_C33_PSE_DISCON_POL, /* u32 */
/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index d67803b67e76..f8253f4c69cc 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -112,6 +112,18 @@ 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->c33_prio_supp_modes)
+ /* _C33_PSE_PRIO_SUPP_MODES */
+ len += nla_total_size(sizeof(u32));
+ if (st->c33_prio_mode)
+ /* _C33_PSE_PRIO_MODE */
+ len += nla_total_size(sizeof(u32));
+ if (st->c33_prio_max)
+ /* _C33_PSE_PRIO_MAX + _C33_PSE_PRIO */
+ len += nla_total_size(sizeof(u32)) * 2;
+ if (st->c33_discon_pol)
+ /* _C33_PSE_DISCON_POL */
+ len += nla_total_size(sizeof(u32));
return len;
}
@@ -209,6 +221,24 @@ static int pse_fill_reply(struct sk_buff *skb,
pse_put_pw_limit_ranges(skb, st))
return -EMSGSIZE;
+ if (st->c33_prio_supp_modes > 0 &&
+ nla_put_u32(skb, ETHTOOL_A_C33_PSE_PRIO_SUPP_MODES,
+ st->c33_prio_supp_modes))
+ return -EMSGSIZE;
+
+ if (st->c33_prio_mode > 0 &&
+ nla_put_u32(skb, ETHTOOL_A_C33_PSE_PRIO_MODE, st->c33_prio_mode))
+ return -EMSGSIZE;
+
+ if (st->c33_prio_max > 0 &&
+ (nla_put_u32(skb, ETHTOOL_A_C33_PSE_PRIO_MAX, st->c33_prio_max) ||
+ nla_put_u32(skb, ETHTOOL_A_C33_PSE_PRIO, st->c33_prio)))
+ return -EMSGSIZE;
+
+ if (st->c33_discon_pol > 0 &&
+ nla_put_u32(skb, ETHTOOL_A_C33_PSE_DISCON_POL, st->c33_discon_pol))
+ return -EMSGSIZE;
+
return 0;
}
@@ -230,6 +260,13 @@ 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_C33_PSE_PRIO_MODE] =
+ NLA_POLICY_RANGE(NLA_U32, ETHTOOL_PSE_PORT_PRIO_DISABLED,
+ ETHTOOL_PSE_PORT_PRIO_DYNAMIC),
+ [ETHTOOL_A_C33_PSE_PRIO] = { .type = NLA_U32 },
+ [ETHTOOL_A_C33_PSE_DISCON_POL] =
+ NLA_POLICY_RANGE(NLA_U32, ETHTOOL_PSE_DISCON_LRC,
+ ETHTOOL_PSE_DISCON_ROUND_ROBIN_IDX_LOWEST_FIRST),
};
static int
@@ -278,6 +315,35 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
if (ret)
return ret;
+ if (tb[ETHTOOL_A_C33_PSE_PRIO_MODE]) {
+ unsigned int prio_mode;
+
+ prio_mode = nla_get_u32(tb[ETHTOOL_A_C33_PSE_PRIO_MODE]);
+ ret = pse_ethtool_set_prio_mode(phydev->psec, info->extack,
+ prio_mode);
+ if (ret)
+ return ret;
+ }
+
+ if (tb[ETHTOOL_A_C33_PSE_DISCON_POL]) {
+ unsigned int pol;
+
+ pol = nla_get_u32(tb[ETHTOOL_A_C33_PSE_DISCON_POL]);
+ ret = pse_ethtool_set_discon_pol(phydev->psec, info->extack,
+ pol);
+ if (ret)
+ return ret;
+ }
+
+ if (tb[ETHTOOL_A_C33_PSE_PRIO]) {
+ unsigned int prio;
+
+ prio = nla_get_u32(tb[ETHTOOL_A_C33_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] 60+ messages in thread* [PATCH RFC net-next v3 23/27] netlink: specs: Expand the PSE netlink command with newly supported features
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (21 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 22/27] net: ethtool: Add PSE new port priority support feature Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature Kory Maincent
` (4 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent
From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
Expand the c33 PSE attributes with PSE id, PSE power domain id, priority
and priority max to be able to set and get the PSE Power Interface
priority.
./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema --do pse-get
--json '{"header":{"dev-name":"eth1"}}'
{'c33-pse-actual-pw': 1700,
'c33-pse-admin-state': 3,
'c33-pse-avail-pw-limit': 97500,
'c33-pse-prio': 2,
'c33-pse-prio-max': 2,
'c33-pse-pw-class': 4,
'c33-pse-pw-d-status': 4,
'c33-pse-pw-limit-ranges': [{'max': 18100, 'min': 15000},
{'max': 38000, 'min': 30000},
{'max': 65000, 'min': 60000},
{'max': 97500, 'min': 90000}],
'header': {'dev-index': 5, 'dev-name': 'eth1'}}
./ynl/cli.py --spec netlink/specs/ethtool.yaml --no-schema --do pse-set
--json '{"header":{"dev-name":"eth1"},
"c33-pse-prio":1}'
None
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Documentation/netlink/specs/ethtool.yaml | 37 ++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index f27c76d965d9..c089c315cc2f 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1025,6 +1025,34 @@ attribute-sets:
type: nest
multi-attr: true
nested-attributes: c33-pse-pw-limit
+ -
+ name: pse-id
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: pse-pw-d-id
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: c33-pse-prio-supp-modes
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: c33-pse-prio-mode
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: c33-pse-prio-max
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: c33-pse-prio
+ type: u32
+ name-prefix: ethtool-a-
+ -
+ name: c33-pse-discon-pol
+ type: u32
+ name-prefix: ethtool-a-
-
name: rss
attributes:
@@ -1793,6 +1821,13 @@ operations:
- c33-pse-ext-substate
- c33-pse-avail-pw-limit
- c33-pse-pw-limit-ranges
+ - pse-id
+ - pse-pw-d-id
+ - c33-pse-prio-supp-modes
+ - c33-pse-prio-mode
+ - c33-pse-prio-max
+ - c33-pse-prio
+ - c33-pse-discon-pol
dump: *pse-get-op
-
name: pse-set
@@ -1807,6 +1842,8 @@ operations:
- podl-pse-admin-control
- c33-pse-admin-control
- c33-pse-avail-pw-limit
+ - c33-pse-prio
+ - c33-pse-discon-pol
-
name: rss-get
doc: Get RSS params.
--
2.34.1
^ permalink raw reply related [flat|nested] 60+ messages in thread* [PATCH RFC net-next v3 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (22 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 23/27] netlink: specs: Expand the PSE netlink command with newly supported features Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 14:42 ` [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
` (3 subsequent siblings)
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 | 183 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 183 insertions(+)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index 0af7db80b2f8..be9fc4afaf97 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)
@@ -685,6 +701,8 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
if (ret < 0)
return ret;
status->c33_avail_pw_limit = ret;
+ /* PSE core priority start at 0 */
+ status->c33_prio = buf.data[2] - 1;
memset(&buf, 0, sizeof(buf));
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_CLASS];
@@ -731,6 +749,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;
};
@@ -822,6 +841,8 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv,
if (ret)
goto out;
+ of_node_get(node);
+ manager[manager_id].node = node;
nmanagers++;
}
@@ -834,6 +855,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);
@@ -841,6 +864,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,
@@ -963,6 +1110,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;
@@ -973,8 +1128,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;
}
@@ -1061,6 +1222,25 @@ static int pd692x0_pi_set_current_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,
.ethtool_get_status = pd692x0_ethtool_get_status,
@@ -1070,6 +1250,7 @@ static const struct pse_controller_ops pd692x0_ops = {
.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_set_prio = pd692x0_pi_set_prio,
};
#define PD692X0_FW_LINE_MAX_SZ 0xff
@@ -1486,6 +1667,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.port_prio_supp_modes = ETHTOOL_PSE_PORT_PRIO_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] 60+ messages in thread* [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (23 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 24/27] net: pse-pd: pd692x0: Add support for PSE PI priority feature Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-22 6:58 ` Krzysztof Kozlowski
2024-11-21 14:42 ` [PATCH RFC net-next v3 26/27] net: pse-pd: tps23881: Add support for static port priority feature Kory Maincent
` (2 subsequent siblings)
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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] 60+ messages in thread* Re: [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2024-11-21 14:42 ` [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
@ 2024-11-22 6:58 ` Krzysztof Kozlowski
2024-11-22 8:42 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-22 6:58 UTC (permalink / raw)
To: Kory Maincent, 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier
On 21/11/2024 15:42, Kory Maincent wrote:
> 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>
> ---
>
<form letter>
Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.
Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.
You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.
Please kindly resend and include all necessary To/Cc entries.
</form letter>
... unless you do not expect review.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2024-11-22 6:58 ` Krzysztof Kozlowski
@ 2024-11-22 8:42 ` Kory Maincent
2024-11-22 9:20 ` Krzysztof Kozlowski
0 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-22 8:42 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, Thomas Petazzoni,
linux-kernel, netdev, linux-doc, Kyle Swenson, Dent Project,
kernel, Maxime Chevallier
Hello Krzysztof,
On Fri, 22 Nov 2024 07:58:26 +0100
Krzysztof Kozlowski <krzk@kernel.org> wrote:
> On 21/11/2024 15:42, Kory Maincent wrote:
> > 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>
> > ---
> >
>
>
> <form letter>
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
>
> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, instead use mainline) or work on fork of kernel
> (don't, instead use mainline). Just use b4 and everything should be
> fine, although remember about `b4 prep --auto-to-cc` if you added new
> patches to the patchset.
>
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time.
>
> Please kindly resend and include all necessary To/Cc entries.
> </form letter>
>
> ... unless you do not expect review.
Indeed I didn't expected binding reviews on this series that's why I did not add
you and devicetree mailing list to the CC. I would like to confirm the core PSE
design choices before that.
Maybe I should have notify it somewhere to avoid you these emails, sorry.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply
2024-11-22 8:42 ` Kory Maincent
@ 2024-11-22 9:20 ` Krzysztof Kozlowski
0 siblings, 0 replies; 60+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-22 9:20 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, Thomas Petazzoni,
linux-kernel, netdev, linux-doc, Kyle Swenson, Dent Project,
kernel, Maxime Chevallier
On 22/11/2024 09:42, Kory Maincent wrote:
>> You missed at least devicetree list (maybe more), so this won't be
>> tested by automated tooling. Performing review on untested code might be
>> a waste of time.
>>
>> Please kindly resend and include all necessary To/Cc entries.
>> </form letter>
>>
>> ... unless you do not expect review.
>
> Indeed I didn't expected binding reviews on this series that's why I did not add
> you and devicetree mailing list to the CC. I would like to confirm the core PSE
> design choices before that.
> Maybe I should have notify it somewhere to avoid you these emails, sorry.
No worries, I just never know whether this is intentional.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 26/27] net: pse-pd: tps23881: Add support for static port priority feature
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (24 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 25/27] dt-bindings: net: pse-pd: microchip,pd692x0: Add manager regulator supply Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-12-03 10:29 ` Simon Horman
2024-11-21 14:42 ` [PATCH RFC net-next v3 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description Kory Maincent
2024-11-21 16:22 ` (subset) [PATCH RFC net-next v3 00/27] Add support for PSE port priority Mark Brown
27 siblings, 1 reply; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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 v3:
- New patch
---
drivers/net/pse-pd/tps23881.c | 197 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 188 insertions(+), 9 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 6fe8f150231f..49757e141990 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
@@ -189,6 +199,17 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
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;
}
@@ -226,6 +247,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)
@@ -1002,6 +1034,47 @@ static int tps23881_pi_set_current_limit(struct pse_controller_dev *pcdev,
return 0;
}
+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,
@@ -1011,6 +1084,7 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_get_voltage = tps23881_pi_get_voltage,
.pi_get_current_limit = tps23881_pi_get_current_limit,
.pi_set_current_limit = tps23881_pi_set_current_limit,
+ .pi_get_pw_req = tps23881_pi_get_pw_req,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
@@ -1181,12 +1255,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_it_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;
+ u8 chans;
+
+ chans = tps23881_it_export_chans_helper(reg_val, 0);
+ for_each_set_bit(i, (unsigned long *)&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;
+ u8 chans;
+
+ chans = tps23881_it_export_chans_helper(reg_val, 4);
+ for_each_set_bit(i, (unsigned long *)&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.
@@ -1198,13 +1343,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;
}
@@ -1250,7 +1415,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)
@@ -1260,11 +1432,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);
}
@@ -1342,17 +1522,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.port_prio_supp_modes = ETHTOOL_PSE_PORT_PRIO_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] 60+ messages in thread* Re: [PATCH RFC net-next v3 26/27] net: pse-pd: tps23881: Add support for static port priority feature
2024-11-21 14:42 ` [PATCH RFC net-next v3 26/27] net: pse-pd: tps23881: Add support for static port priority feature Kory Maincent
@ 2024-12-03 10:29 ` Simon Horman
2024-12-03 10:44 ` Kory Maincent
0 siblings, 1 reply; 60+ messages in thread
From: Simon Horman @ 2024-12-03 10:29 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, Heiner Kallweit, Russell King,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Thu, Nov 21, 2024 at 03:42:52PM +0100, Kory Maincent wrote:
> 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 v3:
> - New patch
> ---
> drivers/net/pse-pd/tps23881.c | 197 ++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 188 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
...
> +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;
> + u8 chans;
> +
> + chans = tps23881_it_export_chans_helper(reg_val, 0);
> + for_each_set_bit(i, (unsigned long *)&chans, TPS23881_MAX_CHANS) {
Hi Kory,
The storage size of chans is only 1 byte, but here we are pretending that
it has more space. Which seems to be a bit of a stretch. Perhaps it would
be better to simply use unsigned long as the type of chans here and in
tps23881_irq_event_classification().
W=1 build with gcc-14 on x86_64 complains about this line as follows:
In function 'find_next_bit',
inlined from 'tps23881_irq_event_detection' at drivers/net/pse-pd/tps23881.c:1281:2,
inlined from 'tps23881_irq_event_handler' at drivers/net/pse-pd/tps23881.c:1363:9,
inlined from 'tps23881_irq_handler' at drivers/net/pse-pd/tps23881.c:1400:9:
./include/linux/find.h:65:23: warning: array subscript 'long unsigned int[0]' is partly outside array bounds of 'u8[1]' {aka 'unsigned char[1]'} [-Warray-bounds=]
65 | val = *addr & GENMASK(size - 1, offset);
| ^~~~~
drivers/net/pse-pd/tps23881.c: In function 'tps23881_irq_handler':
drivers/net/pse-pd/tps23881.c:1278:12: note: object 'chans' of size 1
1278 | u8 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;
> +}
...
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH RFC net-next v3 26/27] net: pse-pd: tps23881: Add support for static port priority feature
2024-12-03 10:29 ` Simon Horman
@ 2024-12-03 10:44 ` Kory Maincent
0 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-12-03 10:44 UTC (permalink / raw)
To: Simon Horman
Cc: Andrew Lunn, Oleksij Rempel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Jonathan Corbet, Donald Hunter,
Rob Herring, Andrew Lunn, Heiner Kallweit, Russell King,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
Hello Simon,
On Tue, 3 Dec 2024 10:29:13 +0000
Simon Horman <horms@kernel.org> wrote:
>
> > +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;
> > + u8 chans;
> > +
> > + chans = tps23881_it_export_chans_helper(reg_val, 0);
> > + for_each_set_bit(i, (unsigned long *)&chans, TPS23881_MAX_CHANS) {
> >
>
> Hi Kory,
>
> The storage size of chans is only 1 byte, but here we are pretending that
> it has more space. Which seems to be a bit of a stretch. Perhaps it would
> be better to simply use unsigned long as the type of chans here and in
> tps23881_irq_event_classification().
Yes indeed. Thanks for the report.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH RFC net-next v3 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (25 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 26/27] net: pse-pd: tps23881: Add support for static port priority feature Kory Maincent
@ 2024-11-21 14:42 ` Kory Maincent
2024-11-21 16:22 ` (subset) [PATCH RFC net-next v3 00/27] Add support for PSE port priority Mark Brown
27 siblings, 0 replies; 60+ messages in thread
From: Kory Maincent @ 2024-11-21 14:42 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
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, 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] 60+ messages in thread* Re: (subset) [PATCH RFC net-next v3 00/27] Add support for PSE port priority
2024-11-21 14:42 [PATCH RFC net-next v3 00/27] Add support for PSE port priority Kory Maincent
` (26 preceding siblings ...)
2024-11-21 14:42 ` [PATCH RFC net-next v3 27/27] dt-bindings: net: pse-pd: ti,tps23881: Add interrupt description Kory Maincent
@ 2024-11-21 16:22 ` Mark Brown
27 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2024-11-21 16:22 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, Kory Maincent
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kalesh AP
On Thu, 21 Nov 2024 15:42:26 +0100, Kory Maincent wrote:
> This series brings support for port priority 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 16 and 17.
> There are also a few core regulator change along the way, patch 3 and 15.
> Not sure if they have to be sent with the Fixes tag.
> Also, 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?
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next
Thanks!
[02/27] regulator: core: Ignore unset max_uA constraints in current limit check
commit: 351f2bfe6362c663f45f5c6111f14365cfd094ab
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 60+ messages in thread