* [PATCH net-next 01/14] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 02/14] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
` (12 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, Liam Girdwood, Mark Brown
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent, Kalesh AP,
Andrew Lunn
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] 28+ messages in thread* [PATCH net-next 02/14] net: pse-pd: Avoid setting max_uA in regulator constraints
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 01/14] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-08 11:14 ` Oleksij Rempel
2025-01-04 22:27 ` [PATCH net-next 03/14] net: pse-pd: Add power limit check Kory Maincent
` (11 subsequent siblings)
13 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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>
---
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] 28+ messages in thread* Re: [PATCH net-next 02/14] net: pse-pd: Avoid setting max_uA in regulator constraints
2025-01-04 22:27 ` [PATCH net-next 02/14] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
@ 2025-01-08 11:14 ` Oleksij Rempel
0 siblings, 0 replies; 28+ messages in thread
From: Oleksij Rempel @ 2025-01-08 11:14 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sat, Jan 04, 2025 at 11:27:27PM +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.
>
> 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] 28+ messages in thread
* [PATCH net-next 03/14] net: pse-pd: Add power limit check
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 01/14] net: pse-pd: Remove unused pse_ethtool_get_pw_limit function declaration Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 02/14] net: pse-pd: Avoid setting max_uA in regulator constraints Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 04/14] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
` (10 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
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] 28+ messages in thread* [PATCH net-next 04/14] net: pse-pd: tps23881: Simplify function returns by removing redundant checks
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (2 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 03/14] net: pse-pd: Add power limit check Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 05/14] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent
` (9 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, Liam Girdwood, Mark Brown
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent,
Andrew Lunn
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 | 34 ++++++----------------------------
1 file changed, 6 insertions(+), 28 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 8797ca1a8a21..a3507520ff87 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -59,7 +59,6 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
- int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -78,11 +77,7 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
val |= BIT(chan + 4);
}
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
}
static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
@@ -91,7 +86,6 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
- int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -110,11 +104,7 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
val |= BIT(chan + 8);
}
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
}
static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
@@ -480,7 +470,7 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
struct i2c_client *client = priv->client;
u8 pi_id, lgcl_chan, hw_chan;
u16 val = 0;
- int i, ret;
+ int i;
for (i = 0; i < port_cnt; i++) {
pi_id = port_matrix[i].pi_id;
@@ -511,11 +501,7 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
}
/* Write hardware ports matrix */
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_PORT_MAP, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_PORT_MAP, val);
}
static int
@@ -564,11 +550,7 @@ tps23881_set_ports_conf(struct tps23881_priv *priv,
val |= BIT(port_matrix[i].lgcl_chan[1]) |
BIT(port_matrix[i].lgcl_chan[1] + 4);
}
- ret = i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
- if (ret)
- return ret;
-
- return 0;
+ return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
}
static int
@@ -594,11 +576,7 @@ tps23881_set_ports_matrix(struct tps23881_priv *priv,
if (ret)
return ret;
- ret = tps23881_set_ports_conf(priv, port_matrix);
- if (ret)
- return ret;
-
- return 0;
+ return tps23881_set_ports_conf(priv, port_matrix);
}
static int tps23881_setup_pi_matrix(struct pse_controller_dev *pcdev)
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH net-next 05/14] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (3 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 04/14] net: pse-pd: tps23881: Simplify function returns by removing redundant checks Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 06/14] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
` (8 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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>
---
drivers/net/pse-pd/tps23881.c | 107 +++++++++++++++++++++++++++---------------
1 file changed, 69 insertions(+), 38 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index a3507520ff87..4a75206b2de6 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -53,6 +53,55 @@ static struct tps23881_priv *to_tps23881_priv(struct pse_controller_dev *pcdev)
return container_of(pcdev, struct tps23881_priv, pcdev);
}
+/*
+ * Helper to extract a value from a u16 register value, which is made of two
+ * u8 registers. The function calculates the bit offset based on the channel
+ * and extracts the relevant bits using a provided field mask.
+ *
+ * @param reg_val: The u16 register value (composed of two u8 registers).
+ * @param chan: The channel number (0-7).
+ * @param field_offset: The base bit offset to apply (e.g., 0 or 4).
+ * @param field_mask: The mask to apply to extract the required bits.
+ * @return: The extracted value for the specific channel.
+ */
+static u16 tps23881_calc_val(u16 reg_val, u8 chan, u8 field_offset,
+ u16 field_mask)
+{
+ if (chan >= 4)
+ reg_val >>= 8;
+
+ return (reg_val >> field_offset) & field_mask;
+}
+
+/*
+ * Helper to combine individual channel values into a u16 register value.
+ * The function sets the value for a specific channel in the appropriate
+ * position.
+ *
+ * @param reg_val: The current u16 register value.
+ * @param chan: The channel number (0-7).
+ * @param field_offset: The base bit offset to apply (e.g., 0 or 4).
+ * @param field_mask: The mask to apply for the field (e.g., 0x0F).
+ * @param field_val: The value to set for the specific channel (masked by
+ * field_mask).
+ * @return: The updated u16 register value with the channel value set.
+ */
+static u16 tps23881_set_val(u16 reg_val, u8 chan, u8 field_offset,
+ u16 field_mask, u16 field_val)
+{
+ field_val &= field_mask;
+
+ if (chan < 4) {
+ reg_val &= ~(field_mask << field_offset);
+ reg_val |= (field_val << field_offset);
+ } else {
+ reg_val &= ~(field_mask << (field_offset + 8));
+ reg_val |= (field_val << (field_offset + 8));
+ }
+
+ return reg_val;
+}
+
static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
@@ -64,17 +113,12 @@ static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
return -ERANGE;
chan = priv->port[id].chan[0];
- if (chan < 4)
- val = BIT(chan);
- else
- val = BIT(chan + 4);
+ val = tps23881_set_val(0, chan, 0, BIT(chan % 4), BIT(chan % 4));
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4)
- val |= BIT(chan);
- else
- val |= BIT(chan + 4);
+ val = tps23881_set_val(val, chan, 0, BIT(chan % 4),
+ BIT(chan % 4));
}
return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
@@ -91,17 +135,12 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
return -ERANGE;
chan = priv->port[id].chan[0];
- if (chan < 4)
- val = BIT(chan + 4);
- else
- val = BIT(chan + 8);
+ val = tps23881_set_val(0, chan, 4, BIT(chan % 4), BIT(chan % 4));
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4)
- val |= BIT(chan + 4);
- else
- val |= BIT(chan + 8);
+ val = tps23881_set_val(val, chan, 4, BIT(chan % 4),
+ BIT(chan % 4));
}
return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
@@ -113,6 +152,7 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
bool enabled;
u8 chan;
+ u16 val;
int ret;
ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
@@ -120,17 +160,13 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
return ret;
chan = priv->port[id].chan[0];
- if (chan < 4)
- enabled = ret & BIT(chan);
- else
- enabled = ret & BIT(chan + 4);
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled = !!(val);
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4)
- enabled &= !!(ret & BIT(chan));
- else
- enabled &= !!(ret & BIT(chan + 4));
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled &= !!(val);
}
/* Return enabled status only if both channel are on this state */
@@ -146,6 +182,7 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
struct i2c_client *client = priv->client;
bool enabled, delivering;
u8 chan;
+ u16 val;
int ret;
ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
@@ -153,23 +190,17 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
return ret;
chan = priv->port[id].chan[0];
- if (chan < 4) {
- enabled = ret & BIT(chan);
- delivering = ret & BIT(chan + 4);
- } else {
- enabled = ret & BIT(chan + 4);
- delivering = ret & BIT(chan + 8);
- }
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled = !!(val);
+ val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
+ delivering = !!(val);
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
- if (chan < 4) {
- enabled &= !!(ret & BIT(chan));
- delivering &= !!(ret & BIT(chan + 4));
- } else {
- enabled &= !!(ret & BIT(chan + 4));
- delivering &= !!(ret & BIT(chan + 8));
- }
+ val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
+ enabled &= !!(val);
+ val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
+ delivering &= !!(val);
}
/* Return delivering status only if both channel are on this state */
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH net-next 06/14] net: pse-pd: tps23881: Add missing configuration register after disable
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (4 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 05/14] net: pse-pd: tps23881: Use helpers to calculate bit offset for a channel Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 07/14] net: pse-pd: Use power limit at driver side instead of current limit Kory Maincent
` (7 subsequent siblings)
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/net/pse-pd/tps23881.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 4a75206b2de6..b87c391ae0f5 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -130,6 +130,7 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
struct i2c_client *client = priv->client;
u8 chan;
u16 val;
+ int ret;
if (id >= TPS23881_MAX_CHANS)
return -ERANGE;
@@ -143,7 +144,34 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
BIT(chan % 4));
}
- return i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_PW_EN, val);
+ if (ret)
+ return ret;
+
+ /* PWOFF command resets lots of register which need to be
+ * configured again. According to the datasheet "It may take upwards
+ * of 5ms after PWOFFn command for all register values to be updated"
+ */
+ mdelay(5);
+
+ /* Enable detection and classification */
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_DET_CLA_EN);
+ if (ret < 0)
+ return ret;
+
+ chan = priv->port[id].chan[0];
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ val = tps23881_set_val(val, chan, 4, BIT(chan % 4), BIT(chan % 4));
+
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4),
+ BIT(chan % 4));
+ val = tps23881_set_val(val, chan, 4, BIT(chan % 4),
+ BIT(chan % 4));
+ }
+
+ return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
}
static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH net-next 07/14] net: pse-pd: Use power limit at driver side instead of current limit
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (5 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 06/14] net: pse-pd: tps23881: Add missing configuration register after disable Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-08 11:13 ` Oleksij Rempel
2025-01-04 22:27 ` [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks Kory Maincent
` (6 subsequent siblings)
13 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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 regulator framework uses current limits, but the PSE standard and
known PSE controllers rely on power limits. Instead of converting
current to power within each driver, perform the conversion in the PSE
core. This avoids redundancy in driver implementation and aligns better
with the standard, simplifying driver development.
Remove at the same time the _pse_ethtool_get_status() function which is
not needed anymore.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/net/pse-pd/pd692x0.c | 45 +++++----------------
drivers/net/pse-pd/pse_core.c | 91 +++++++++++++++++++------------------------
include/linux/pse-pd/pse.h | 16 +++-----
3 files changed, 57 insertions(+), 95 deletions(-)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index 0af7db80b2f8..9f00538f7e45 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -999,13 +999,12 @@ static int pd692x0_pi_get_voltage(struct pse_controller_dev *pcdev, int id)
return (buf.sub[0] << 8 | buf.sub[1]) * 100000;
}
-static int pd692x0_pi_get_current_limit(struct pse_controller_dev *pcdev,
- int id)
+static int pd692x0_pi_get_pw_limit(struct pse_controller_dev *pcdev,
+ int id)
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct pd692x0_msg msg, buf = {0};
- int mW, uV, uA, ret;
- s64 tmp_64;
+ int ret;
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
msg.sub[2] = id;
@@ -1013,48 +1012,24 @@ static int pd692x0_pi_get_current_limit(struct pse_controller_dev *pcdev,
if (ret < 0)
return ret;
- ret = pd692x0_pi_get_pw_from_table(buf.data[2], buf.data[3]);
- if (ret < 0)
- return ret;
- mW = ret;
-
- ret = pd692x0_pi_get_voltage(pcdev, id);
- if (ret < 0)
- return ret;
- uV = ret;
-
- tmp_64 = mW;
- tmp_64 *= 1000000000ull;
- /* uA = mW * 1000000000 / uV */
- uA = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
- return uA;
+ return pd692x0_pi_get_pw_from_table(buf.data[2], buf.data[3]);
}
-static int pd692x0_pi_set_current_limit(struct pse_controller_dev *pcdev,
- int id, int max_uA)
+static int pd692x0_pi_set_pw_limit(struct pse_controller_dev *pcdev,
+ int id, int max_mW)
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct device *dev = &priv->client->dev;
struct pd692x0_msg msg, buf = {0};
- int uV, ret, mW;
- s64 tmp_64;
+ int ret;
ret = pd692x0_fw_unavailable(priv);
if (ret)
return ret;
- ret = pd692x0_pi_get_voltage(pcdev, id);
- if (ret < 0)
- return ret;
- uV = ret;
-
msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
msg.sub[2] = id;
- tmp_64 = uV;
- tmp_64 *= max_uA;
- /* mW = uV * uA / 1000000000 */
- mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
- ret = pd692x0_pi_set_pw_from_table(dev, &msg, mW);
+ ret = pd692x0_pi_set_pw_from_table(dev, &msg, max_mW);
if (ret)
return ret;
@@ -1068,8 +1043,8 @@ static const struct pse_controller_ops pd692x0_ops = {
.pi_disable = pd692x0_pi_disable,
.pi_is_enabled = pd692x0_pi_is_enabled,
.pi_get_voltage = pd692x0_pi_get_voltage,
- .pi_get_current_limit = pd692x0_pi_get_current_limit,
- .pi_set_current_limit = pd692x0_pi_set_current_limit,
+ .pi_get_pw_limit = pd692x0_pi_get_pw_limit,
+ .pi_set_pw_limit = pd692x0_pi_set_pw_limit,
};
#define PD692X0_FW_LINE_MAX_SZ 0xff
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 432b6c2c04f8..ae819bfed1b1 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -291,33 +291,25 @@ static int pse_pi_get_voltage(struct regulator_dev *rdev)
return ret;
}
-static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
- int id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status);
-
static int pse_pi_get_current_limit(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
const struct pse_controller_ops *ops;
- struct netlink_ext_ack extack = {};
- struct pse_control_status st = {};
- int id, uV, ret;
+ int id, uV, mW, ret;
s64 tmp_64;
ops = pcdev->ops;
id = rdev_get_id(rdev);
+ if (!ops->pi_get_pw_limit || !ops->pi_get_voltage)
+ return -EOPNOTSUPP;
+
mutex_lock(&pcdev->lock);
- if (ops->pi_get_current_limit) {
- ret = ops->pi_get_current_limit(pcdev, id);
+ ret = ops->pi_get_pw_limit(pcdev, id);
+ if (ret < 0)
goto out;
- }
+ mW = ret;
- /* If pi_get_current_limit() callback not populated get voltage
- * from pi_get_voltage() and power limit from ethtool_get_status()
- * to calculate current limit.
- */
- ret = _pse_pi_get_voltage(rdev);
+ ret = pse_pi_get_voltage(rdev);
if (!ret) {
dev_err(pcdev->dev, "Voltage null\n");
ret = -ERANGE;
@@ -327,16 +319,7 @@ static int pse_pi_get_current_limit(struct regulator_dev *rdev)
goto out;
uV = ret;
- ret = _pse_ethtool_get_status(pcdev, id, &extack, &st);
- if (ret)
- goto out;
-
- if (!st.c33_avail_pw_limit) {
- ret = -ENODATA;
- goto out;
- }
-
- tmp_64 = st.c33_avail_pw_limit;
+ tmp_64 = mW;
tmp_64 *= 1000000000ull;
/* uA = mW * 1000000000 / uV */
ret = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
@@ -351,10 +334,11 @@ static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
const struct pse_controller_ops *ops;
- int id, ret;
+ int id, mW, ret;
+ s64 tmp_64;
ops = pcdev->ops;
- if (!ops->pi_set_current_limit)
+ if (!ops->pi_set_pw_limit || !ops->pi_get_voltage)
return -EOPNOTSUPP;
if (max_uA > MAX_PI_CURRENT)
@@ -362,7 +346,21 @@ static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
- ret = ops->pi_set_current_limit(pcdev, id, max_uA);
+ ret = pse_pi_get_voltage(rdev);
+ if (!ret) {
+ dev_err(pcdev->dev, "Voltage null\n");
+ ret = -ERANGE;
+ goto out;
+ }
+ if (ret < 0)
+ goto out;
+
+ tmp_64 = ret;
+ tmp_64 *= max_uA;
+ /* mW = uA * uV / 1000000000 */
+ mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
+ ret = ops->pi_set_pw_limit(pcdev, id, mW);
+out:
mutex_unlock(&pcdev->lock);
return ret;
@@ -406,7 +404,7 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
- if (pcdev->ops->pi_set_current_limit)
+ if (pcdev->ops->pi_set_pw_limit)
rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_CURRENT;
@@ -737,23 +735,6 @@ struct pse_control *of_pse_control_get(struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_pse_control_get);
-static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
- int id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
-{
- const struct pse_controller_ops *ops;
-
- ops = pcdev->ops;
- if (!ops->ethtool_get_status) {
- NL_SET_ERR_MSG(extack,
- "PSE driver does not support status report");
- return -EOPNOTSUPP;
- }
-
- return ops->ethtool_get_status(pcdev, id, extack, status);
-}
-
/**
* pse_ethtool_get_status - get status of PSE control
* @psec: PSE control pointer
@@ -766,11 +747,21 @@ int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
struct pse_control_status *status)
{
+ const struct pse_controller_ops *ops;
+ struct pse_controller_dev *pcdev;
int err;
- mutex_lock(&psec->pcdev->lock);
- err = _pse_ethtool_get_status(psec->pcdev, psec->id, extack, status);
- mutex_unlock(&psec->pcdev->lock);
+ pcdev = psec->pcdev;
+ ops = pcdev->ops;
+ if (!ops->ethtool_get_status) {
+ NL_SET_ERR_MSG(extack,
+ "PSE driver does not support status report");
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&pcdev->lock);
+ err = ops->ethtool_get_status(pcdev, psec->id, extack, status);
+ mutex_unlock(&pcdev->lock);
return err;
}
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index bc5addccbf32..a721651cd1e0 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -77,12 +77,8 @@ struct pse_control_status {
* @pi_disable: Configure the PSE PI as disabled.
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
* callback.
- * @pi_get_current_limit: Get the configured current limit similarly to
- * get_current_limit regulator callback.
- * @pi_set_current_limit: Configure the current limit similarly to
- * set_current_limit regulator callback.
- * Should not return an error in case of MAX_PI_CURRENT
- * current value set.
+ * @pi_get_pw_limit: Get the configured power limit of the PSE PI.
+ * @pi_set_pw_limit: Configure the power limit of the PSE PI.
*/
struct pse_controller_ops {
int (*ethtool_get_status)(struct pse_controller_dev *pcdev,
@@ -93,10 +89,10 @@ struct pse_controller_ops {
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
int (*pi_get_voltage)(struct pse_controller_dev *pcdev, int id);
- int (*pi_get_current_limit)(struct pse_controller_dev *pcdev,
- int id);
- int (*pi_set_current_limit)(struct pse_controller_dev *pcdev,
- int id, int max_uA);
+ int (*pi_get_pw_limit)(struct pse_controller_dev *pcdev,
+ int id);
+ int (*pi_set_pw_limit)(struct pse_controller_dev *pcdev,
+ int id, int max_mW);
};
struct module;
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH net-next 07/14] net: pse-pd: Use power limit at driver side instead of current limit
2025-01-04 22:27 ` [PATCH net-next 07/14] net: pse-pd: Use power limit at driver side instead of current limit Kory Maincent
@ 2025-01-08 11:13 ` Oleksij Rempel
0 siblings, 0 replies; 28+ messages in thread
From: Oleksij Rempel @ 2025-01-08 11:13 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sat, Jan 04, 2025 at 11:27:32PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> The regulator framework uses current limits, but the PSE standard and
> known PSE controllers rely on power limits. Instead of converting
> current to power within each driver, perform the conversion in the PSE
> core. This avoids redundancy in driver implementation and aligns better
> with the standard, simplifying driver development.
>
> Remove at the same time the _pse_ethtool_get_status() function which is
> not needed anymore.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
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] 28+ messages in thread
* [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (6 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 07/14] net: pse-pd: Use power limit at driver side instead of current limit Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-08 1:15 ` Jakub Kicinski
2025-01-04 22:27 ` [PATCH net-next 09/14] net: pse-pd: Remove is_enabled callback from drivers Kory Maincent
` (5 subsequent siblings)
13 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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 ethtool_get_status callback currently handles all status and PSE
information within a single function. This approach has two key
drawbacks:
1. If the core requires some information for purposes other than
ethtool_get_status, redundant code will be needed to fetch the same
data from the driver (like is_enabled).
2. Drivers currently have access to all information passed to ethtool.
New variables will soon be added to ethtool status, such as PSE ID,
power domain IDs, and budget evaluation strategies, which are meant
to be managed solely by the core. Drivers should not have the ability
to modify these variables.
To resolve these issues, ethtool_get_status has been split into multiple
callbacks, with each handling a specific piece of information required
by ethtool or the core.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/net/pse-pd/pd692x0.c | 153 ++++++++++++++++++++++++++-----------
drivers/net/pse-pd/pse_core.c | 83 +++++++++++++++++---
drivers/net/pse-pd/pse_regulator.c | 26 +++++--
drivers/net/pse-pd/tps23881.c | 60 +++++++++++----
include/linux/ethtool.h | 36 +++++++++
include/linux/pse-pd/pse.h | 87 +++++++++++++--------
net/ethtool/pse-pd.c | 8 +-
7 files changed, 341 insertions(+), 112 deletions(-)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index 9f00538f7e45..da5d09ed628a 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -517,21 +517,38 @@ pd692x0_pse_ext_state_map[] = {
{ /* sentinel */ }
};
-static void
-pd692x0_get_ext_state(struct ethtool_c33_pse_ext_state_info *c33_ext_state_info,
- u32 status_code)
+static int
+pd692x0_pi_get_ext_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_ext_state_info *ext_state_info)
{
+ struct ethtool_c33_pse_ext_state_info *c33_ext_state_info;
const struct pd692x0_pse_ext_state_mapping *ext_state_map;
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
+ msg.sub[2] = id;
+ ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
+ if (ret < 0)
+ return ret;
+
+ c33_ext_state_info = &ext_state_info->c33_ext_state_info;
ext_state_map = pd692x0_pse_ext_state_map;
while (ext_state_map->status_code) {
- if (ext_state_map->status_code == status_code) {
+ if (ext_state_map->status_code == buf.sub[0]) {
c33_ext_state_info->c33_pse_ext_state = ext_state_map->pse_ext_state;
c33_ext_state_info->__c33_pse_ext_substate = ext_state_map->pse_ext_substate;
- return;
+ return 0;
}
ext_state_map++;
}
+
+ return 0;
}
struct pd692x0_class_pw {
@@ -613,35 +630,36 @@ static int pd692x0_pi_set_pw_from_table(struct device *dev,
}
static int
-pd692x0_pi_get_pw_ranges(struct pse_control_status *st)
+pd692x0_pi_get_pw_limit_ranges(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_limit_ranges *pw_limit_ranges)
{
+ struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
const struct pd692x0_class_pw *pw_table;
int i;
pw_table = pd692x0_class_pw_table;
- st->c33_pw_limit_ranges = kcalloc(PD692X0_CLASS_PW_TABLE_SIZE,
- sizeof(struct ethtool_c33_pse_pw_limit_range),
- GFP_KERNEL);
- if (!st->c33_pw_limit_ranges)
+ c33_pw_limit_ranges = kcalloc(PD692X0_CLASS_PW_TABLE_SIZE,
+ sizeof(*c33_pw_limit_ranges),
+ GFP_KERNEL);
+ if (!c33_pw_limit_ranges)
return -ENOMEM;
for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
- st->c33_pw_limit_ranges[i].min = pw_table->class_pw;
- st->c33_pw_limit_ranges[i].max = pw_table->class_pw + pw_table->max_added_class_pw;
+ c33_pw_limit_ranges[i].min = pw_table->class_pw;
+ c33_pw_limit_ranges[i].max = pw_table->class_pw +
+ pw_table->max_added_class_pw;
}
- st->c33_pw_limit_nb_ranges = i;
- return 0;
+ pw_limit_ranges->c33_pw_limit_ranges = c33_pw_limit_ranges;
+ return i;
}
-static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
- unsigned long id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+static int
+pd692x0_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state)
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct pd692x0_msg msg, buf = {0};
- u32 class;
int ret;
ret = pd692x0_fw_unavailable(priv);
@@ -654,39 +672,65 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
if (ret < 0)
return ret;
- /* Compare Port Status (Communication Protocol Document par. 7.1) */
- if ((buf.sub[0] & 0xf0) == 0x80 || (buf.sub[0] & 0xf0) == 0x90)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
- else if (buf.sub[0] == 0x1b || buf.sub[0] == 0x22)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING;
- else if (buf.sub[0] == 0x12)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_FAULT;
- else
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
-
if (buf.sub[1])
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
else
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
- priv->admin_state[id] = status->c33_admin_state;
+ priv->admin_state[id] = admin_state->c33_admin_state;
- pd692x0_get_ext_state(&status->c33_ext_state_info, buf.sub[0]);
- status->c33_actual_pw = (buf.data[0] << 4 | buf.data[1]) * 100;
+ return 0;
+}
- msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
+static int
+pd692x0_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
+
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
msg.sub[2] = id;
- memset(&buf, 0, sizeof(buf));
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
if (ret < 0)
return ret;
- ret = pd692x0_pi_get_pw_from_table(buf.data[0], buf.data[1]);
- if (ret < 0)
+ /* Compare Port Status (Communication Protocol Document par. 7.1) */
+ if ((buf.sub[0] & 0xf0) == 0x80 || (buf.sub[0] & 0xf0) == 0x90)
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
+ else if (buf.sub[0] == 0x1b || buf.sub[0] == 0x22)
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING;
+ else if (buf.sub[0] == 0x12)
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_FAULT;
+ else
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
+
+ return 0;
+}
+
+static int
+pd692x0_pi_get_pw_class(struct pse_controller_dev *pcdev, int id)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ u32 class;
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
return ret;
- status->c33_avail_pw_limit = ret;
- memset(&buf, 0, sizeof(buf));
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_CLASS];
msg.sub[2] = id;
ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
@@ -695,13 +739,29 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
class = buf.data[3] >> 4;
if (class <= 8)
- status->c33_pw_class = class;
+ return class;
+
+ return 0;
+}
+
+static int
+pd692x0_pi_get_actual_pw(struct pse_controller_dev *pcdev, int id)
+{
+ struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
+ struct pd692x0_msg msg, buf = {0};
+ int ret;
+
+ ret = pd692x0_fw_unavailable(priv);
+ if (ret)
+ return ret;
- ret = pd692x0_pi_get_pw_ranges(status);
+ msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
+ msg.sub[2] = id;
+ ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
if (ret < 0)
return ret;
- return 0;
+ return (buf.data[0] << 4 | buf.data[1]) * 100;
}
static struct pd692x0_msg_ver pd692x0_get_sw_version(struct pd692x0_priv *priv)
@@ -1038,13 +1098,18 @@ static int pd692x0_pi_set_pw_limit(struct pse_controller_dev *pcdev,
static const struct pse_controller_ops pd692x0_ops = {
.setup_pi_matrix = pd692x0_setup_pi_matrix,
- .ethtool_get_status = pd692x0_ethtool_get_status,
+ .pi_get_admin_state = pd692x0_pi_get_admin_state,
+ .pi_get_pw_status = pd692x0_pi_get_pw_status,
+ .pi_get_ext_state = pd692x0_pi_get_ext_state,
+ .pi_get_pw_class = pd692x0_pi_get_pw_class,
+ .pi_get_actual_pw = pd692x0_pi_get_actual_pw,
.pi_enable = pd692x0_pi_enable,
.pi_disable = pd692x0_pi_disable,
.pi_is_enabled = pd692x0_pi_is_enabled,
.pi_get_voltage = pd692x0_pi_get_voltage,
.pi_get_pw_limit = pd692x0_pi_get_pw_limit,
.pi_set_pw_limit = pd692x0_pi_set_pw_limit,
+ .pi_get_pw_limit_ranges = pd692x0_pi_get_pw_limit_ranges,
};
#define PD692X0_FW_LINE_MAX_SZ 0xff
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index ae819bfed1b1..5f2a9f36e4ed 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -443,6 +443,13 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
if (!pcdev->nr_lines)
pcdev->nr_lines = 1;
+ if (!pcdev->ops->pi_get_admin_state ||
+ !pcdev->ops->pi_get_pw_status) {
+ dev_err(pcdev->dev,
+ "Mandatory status report callbacks are missing");
+ return -EINVAL;
+ }
+
ret = of_load_pse_pis(pcdev);
if (ret)
return ret;
@@ -745,25 +752,81 @@ EXPORT_SYMBOL_GPL(of_pse_control_get);
*/
int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+ struct ethtool_pse_control_status *status)
{
+ struct pse_admin_state admin_state = {0};
+ struct pse_pw_status pw_status = {0};
const struct pse_controller_ops *ops;
struct pse_controller_dev *pcdev;
- int err;
+ int ret;
pcdev = psec->pcdev;
ops = pcdev->ops;
- if (!ops->ethtool_get_status) {
- NL_SET_ERR_MSG(extack,
- "PSE driver does not support status report");
- return -EOPNOTSUPP;
+ mutex_lock(&pcdev->lock);
+ ret = ops->pi_get_admin_state(pcdev, psec->id, &admin_state);
+ if (ret)
+ goto out;
+ status->podl_admin_state = admin_state.podl_admin_state;
+ status->c33_admin_state = admin_state.c33_admin_state;
+
+ ret = ops->pi_get_pw_status(pcdev, psec->id, &pw_status);
+ if (ret)
+ goto out;
+ status->podl_pw_status = pw_status.podl_pw_status;
+ status->c33_pw_status = pw_status.c33_pw_status;
+
+ if (ops->pi_get_ext_state) {
+ struct pse_ext_state_info ext_state_info = {0};
+
+ ret = ops->pi_get_ext_state(pcdev, psec->id,
+ &ext_state_info);
+ if (ret)
+ goto out;
+
+ memcpy(&status->c33_ext_state_info,
+ &ext_state_info.c33_ext_state_info,
+ sizeof(status->c33_ext_state_info));
}
- mutex_lock(&pcdev->lock);
- err = ops->ethtool_get_status(pcdev, psec->id, extack, status);
- mutex_unlock(&pcdev->lock);
+ if (ops->pi_get_pw_class) {
+ ret = ops->pi_get_pw_class(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
- return err;
+ status->c33_pw_class = ret;
+ }
+
+ if (ops->pi_get_actual_pw) {
+ ret = ops->pi_get_actual_pw(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
+
+ status->c33_actual_pw = ret;
+ }
+
+ if (ops->pi_get_pw_limit) {
+ ret = ops->pi_get_pw_limit(pcdev, psec->id);
+ if (ret < 0)
+ goto out;
+
+ status->c33_avail_pw_limit = ret;
+ }
+
+ if (ops->pi_get_pw_limit_ranges) {
+ struct pse_pw_limit_ranges pw_limit_ranges = {0};
+
+ ret = ops->pi_get_pw_limit_ranges(pcdev, psec->id,
+ &pw_limit_ranges);
+ if (ret < 0)
+ goto out;
+
+ status->c33_pw_limit_ranges =
+ pw_limit_ranges.c33_pw_limit_ranges;
+ status->c33_pw_limit_nb_ranges = ret;
+ }
+out:
+ mutex_unlock(&psec->pcdev->lock);
+ return ret;
}
EXPORT_SYMBOL_GPL(pse_ethtool_get_status);
diff --git a/drivers/net/pse-pd/pse_regulator.c b/drivers/net/pse-pd/pse_regulator.c
index 64ab36974fe0..86360056b2f5 100644
--- a/drivers/net/pse-pd/pse_regulator.c
+++ b/drivers/net/pse-pd/pse_regulator.c
@@ -60,9 +60,19 @@ pse_reg_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
}
static int
-pse_reg_ethtool_get_status(struct pse_controller_dev *pcdev, unsigned long id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+pse_reg_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state)
+{
+ struct pse_reg_priv *priv = to_pse_reg(pcdev);
+
+ admin_state->podl_admin_state = priv->admin_state;
+
+ return 0;
+}
+
+static int
+pse_reg_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status)
{
struct pse_reg_priv *priv = to_pse_reg(pcdev);
int ret;
@@ -72,18 +82,18 @@ pse_reg_ethtool_get_status(struct pse_controller_dev *pcdev, unsigned long id,
return ret;
if (!ret)
- status->podl_pw_status = ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED;
+ pw_status->podl_pw_status =
+ ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED;
else
- status->podl_pw_status =
+ pw_status->podl_pw_status =
ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING;
- status->podl_admin_state = priv->admin_state;
-
return 0;
}
static const struct pse_controller_ops pse_reg_ops = {
- .ethtool_get_status = pse_reg_ethtool_get_status,
+ .pi_get_admin_state = pse_reg_pi_get_admin_state,
+ .pi_get_pw_status = pse_reg_pi_get_pw_status,
.pi_enable = pse_reg_pi_enable,
.pi_is_enabled = pse_reg_pi_is_enabled,
.pi_disable = pse_reg_pi_disable,
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index b87c391ae0f5..f735b6917f8b 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -201,14 +201,13 @@ static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
return enabled;
}
-static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
- unsigned long id,
- struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+static int
+tps23881_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
struct i2c_client *client = priv->client;
- bool enabled, delivering;
+ bool enabled;
u8 chan;
u16 val;
int ret;
@@ -220,28 +219,56 @@ static int tps23881_ethtool_get_status(struct pse_controller_dev *pcdev,
chan = priv->port[id].chan[0];
val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
enabled = !!(val);
- val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
- delivering = !!(val);
if (priv->port[id].is_4p) {
chan = priv->port[id].chan[1];
val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
enabled &= !!(val);
+ }
+
+ /* Return enabled status only if both channel are on this state */
+ if (enabled)
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ else
+ admin_state->c33_admin_state =
+ ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+
+ return 0;
+}
+
+static int
+tps23881_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ bool delivering;
+ u8 chan;
+ u16 val;
+ int ret;
+
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
+ if (ret < 0)
+ return ret;
+
+ chan = priv->port[id].chan[0];
+ val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
+ delivering = !!(val);
+
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
val = tps23881_calc_val(ret, chan, 4, BIT(chan % 4));
delivering &= !!(val);
}
/* Return delivering status only if both channel are on this state */
if (delivering)
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
- else
- status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
-
- /* Return enabled status only if both channel are on this state */
- if (enabled)
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
else
- status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
+ pw_status->c33_pw_status =
+ ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
return 0;
}
@@ -664,7 +691,8 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_enable = tps23881_pi_enable,
.pi_disable = tps23881_pi_disable,
.pi_is_enabled = tps23881_pi_is_enabled,
- .ethtool_get_status = tps23881_ethtool_get_status,
+ .pi_get_admin_state = tps23881_pi_get_admin_state,
+ .pi_get_pw_status = tps23881_pi_get_pw_status,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index f711bfd75c4d..2bdf7e72ee50 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1323,4 +1323,40 @@ struct ethtool_c33_pse_pw_limit_range {
u32 min;
u32 max;
};
+
+/**
+ * struct ethtool_pse_control_status - PSE control/channel status.
+ *
+ * @podl_admin_state: operational state of the PoDL PSE
+ * functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
+ * @podl_pw_status: power detection status of the PoDL PSE.
+ * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
+ * @c33_admin_state: operational state of the PSE
+ * functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
+ * @c33_pw_status: power detection status of the PSE.
+ * IEEE 802.3-2022 30.9.1.1.5 aPSEPowerDetectionStatus:
+ * @c33_pw_class: detected class of a powered PD
+ * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification
+ * @c33_actual_pw: power currently delivered by the PSE in mW
+ * IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
+ * @c33_ext_state_info: extended state information of the PSE
+ * @c33_avail_pw_limit: available power limit of the PSE in mW
+ * IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
+ * @c33_pw_limit_ranges: supported power limit configuration range. The driver
+ * is in charge of the memory allocation
+ * @c33_pw_limit_nb_ranges: number of supported power limit configuration
+ * ranges
+ */
+struct ethtool_pse_control_status {
+ enum ethtool_podl_pse_admin_state podl_admin_state;
+ enum ethtool_podl_pse_pw_d_status podl_pw_status;
+ enum ethtool_c33_pse_admin_state c33_admin_state;
+ enum ethtool_c33_pse_pw_d_status c33_pw_status;
+ u32 c33_pw_class;
+ u32 c33_actual_pw;
+ struct ethtool_c33_pse_ext_state_info c33_ext_state_info;
+ u32 c33_avail_pw_limit;
+ struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
+ u32 c33_pw_limit_nb_ranges;
+};
#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index a721651cd1e0..db8b3db7b849 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -31,60 +31,84 @@ struct pse_control_config {
};
/**
- * struct pse_control_status - PSE control/channel status.
+ * struct pse_admin_state - PSE operational state
*
* @podl_admin_state: operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
- * @podl_pw_status: power detection status of the PoDL PSE.
- * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
* @c33_admin_state: operational state of the PSE
* functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
+ */
+struct pse_admin_state {
+ enum ethtool_podl_pse_admin_state podl_admin_state;
+ enum ethtool_c33_pse_admin_state c33_admin_state;
+};
+
+/**
+ * struct pse_pw_status - PSE power detection status
+ *
+ * @podl_pw_status: power detection status of the PoDL PSE.
+ * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
* @c33_pw_status: power detection status of the PSE.
* IEEE 802.3-2022 30.9.1.1.5 aPSEPowerDetectionStatus:
- * @c33_pw_class: detected class of a powered PD
- * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification
- * @c33_actual_pw: power currently delivered by the PSE in mW
- * IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
- * @c33_ext_state_info: extended state information of the PSE
- * @c33_avail_pw_limit: available power limit of the PSE in mW
- * IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
- * @c33_pw_limit_ranges: supported power limit configuration range. The driver
- * is in charge of the memory allocation.
- * @c33_pw_limit_nb_ranges: number of supported power limit configuration
- * ranges
*/
-struct pse_control_status {
- enum ethtool_podl_pse_admin_state podl_admin_state;
+struct pse_pw_status {
enum ethtool_podl_pse_pw_d_status podl_pw_status;
- enum ethtool_c33_pse_admin_state c33_admin_state;
enum ethtool_c33_pse_pw_d_status c33_pw_status;
- u32 c33_pw_class;
- u32 c33_actual_pw;
+};
+
+/**
+ * struct pse_ext_state_info - PSE extended state information
+ *
+ * @c33_ext_state_info: extended state information of the PSE
+ */
+struct pse_ext_state_info {
struct ethtool_c33_pse_ext_state_info c33_ext_state_info;
- u32 c33_avail_pw_limit;
+};
+
+/**
+ * struct pse_pw_limit_ranges - PSE power limit configuration range
+ *
+ * @c33_pw_limit_ranges: supported power limit configuration range. The driver
+ * is in charge of the memory allocation.
+ */
+struct pse_pw_limit_ranges {
struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
- u32 c33_pw_limit_nb_ranges;
};
/**
* struct pse_controller_ops - PSE controller driver callbacks
*
- * @ethtool_get_status: get PSE control status for ethtool interface
* @setup_pi_matrix: setup PI matrix of the PSE controller
+ * @pi_get_admin_state: Get the operational state of the PSE PI. This ops
+ * is mandatory.
+ * @pi_get_pw_status: Get the power detection status of the PSE PI. This
+ * ops is mandatory.
+ * @pi_get_ext_state: Get the extended state of the PSE PI.
+ * @pi_get_pw_class: Get the power class of the PSE PI.
+ * @pi_get_actual_pw: Get actual power of the PSE PI in mW.
* @pi_is_enabled: Return 1 if the PSE PI is enabled, 0 if not.
* May also return negative errno.
* @pi_enable: Configure the PSE PI as enabled.
* @pi_disable: Configure the PSE PI as disabled.
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
- * callback.
- * @pi_get_pw_limit: Get the configured power limit of the PSE PI.
- * @pi_set_pw_limit: Configure the power limit of the PSE PI.
+ * callback in uV.
+ * @pi_get_pw_limit: Get the configured power limit of the PSE PI in mW.
+ * @pi_set_pw_limit: Configure the power limit of the PSE PI in mW.
+ * @pi_get_pw_limit_ranges: Get the supported power limit configuration
+ * range. The driver is in charge of the memory
+ * allocation and should return the number of
+ * ranges.
*/
struct pse_controller_ops {
- int (*ethtool_get_status)(struct pse_controller_dev *pcdev,
- unsigned long id, struct netlink_ext_ack *extack,
- struct pse_control_status *status);
int (*setup_pi_matrix)(struct pse_controller_dev *pcdev);
+ int (*pi_get_admin_state)(struct pse_controller_dev *pcdev, int id,
+ struct pse_admin_state *admin_state);
+ int (*pi_get_pw_status)(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_status *pw_status);
+ int (*pi_get_ext_state)(struct pse_controller_dev *pcdev, int id,
+ struct pse_ext_state_info *ext_state_info);
+ int (*pi_get_pw_class)(struct pse_controller_dev *pcdev, int id);
+ int (*pi_get_actual_pw)(struct pse_controller_dev *pcdev, int id);
int (*pi_is_enabled)(struct pse_controller_dev *pcdev, int id);
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
@@ -93,12 +117,15 @@ struct pse_controller_ops {
int id);
int (*pi_set_pw_limit)(struct pse_controller_dev *pcdev,
int id, int max_mW);
+ int (*pi_get_pw_limit_ranges)(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_limit_ranges *pw_limit_ranges);
};
struct module;
struct device_node;
struct of_phandle_args;
struct pse_control;
+struct ethtool_pse_control_status;
/* PSE PI pairset pinout can either be Alternative A or Alternative B */
enum pse_pi_pairset_pinout {
@@ -175,7 +202,7 @@ void pse_control_put(struct pse_control *psec);
int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
- struct pse_control_status *status);
+ struct ethtool_pse_control_status *status);
int pse_ethtool_set_config(struct pse_control *psec,
struct netlink_ext_ack *extack,
const struct pse_control_config *config);
@@ -199,7 +226,7 @@ static inline void pse_control_put(struct pse_control *psec)
static inline int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
- struct pse_control_status *status)
+ struct ethtool_pse_control_status *status)
{
return -EOPNOTSUPP;
}
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index a0705edca22a..2819e2ba6be2 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -19,7 +19,7 @@ struct pse_req_info {
struct pse_reply_data {
struct ethnl_reply_data base;
- struct pse_control_status status;
+ struct ethtool_pse_control_status status;
};
#define PSE_REPDATA(__reply_base) \
@@ -80,7 +80,7 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
const struct pse_reply_data *data = PSE_REPDATA(reply_base);
- const struct pse_control_status *st = &data->status;
+ const struct ethtool_pse_control_status *st = &data->status;
int len = 0;
if (st->podl_admin_state > 0)
@@ -114,7 +114,7 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
}
static int pse_put_pw_limit_ranges(struct sk_buff *skb,
- const struct pse_control_status *st)
+ const struct ethtool_pse_control_status *st)
{
const struct ethtool_c33_pse_pw_limit_range *pw_limit_ranges;
int i;
@@ -146,7 +146,7 @@ static int pse_fill_reply(struct sk_buff *skb,
const struct ethnl_reply_data *reply_base)
{
const struct pse_reply_data *data = PSE_REPDATA(reply_base);
- const struct pse_control_status *st = &data->status;
+ const struct ethtool_pse_control_status *st = &data->status;
if (st->podl_admin_state > 0 &&
nla_put_u32(skb, ETHTOOL_A_PODL_PSE_ADMIN_STATE,
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-04 22:27 ` [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks Kory Maincent
@ 2025-01-08 1:15 ` Jakub Kicinski
2025-01-08 9:27 ` Kory Maincent
0 siblings, 1 reply; 28+ messages in thread
From: Jakub Kicinski @ 2025-01-08 1:15 UTC (permalink / raw)
To: Kory Maincent
Cc: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sat, 04 Jan 2025 23:27:33 +0100 Kory Maincent wrote:
> diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
> index f711bfd75c4d..2bdf7e72ee50 100644
> --- a/include/linux/ethtool.h
> +++ b/include/linux/ethtool.h
> @@ -1323,4 +1323,40 @@ struct ethtool_c33_pse_pw_limit_range {
> u32 min;
> u32 max;
> };
> +
> +/**
> + * struct ethtool_pse_control_status - PSE control/channel status.
> + *
> + * @podl_admin_state: operational state of the PoDL PSE
> + * functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
> + * @podl_pw_status: power detection status of the PoDL PSE.
> + * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
> + * @c33_admin_state: operational state of the PSE
> + * functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
> + * @c33_pw_status: power detection status of the PSE.
> + * IEEE 802.3-2022 30.9.1.1.5 aPSEPowerDetectionStatus:
> + * @c33_pw_class: detected class of a powered PD
> + * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification
> + * @c33_actual_pw: power currently delivered by the PSE in mW
> + * IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
> + * @c33_ext_state_info: extended state information of the PSE
> + * @c33_avail_pw_limit: available power limit of the PSE in mW
> + * IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
> + * @c33_pw_limit_ranges: supported power limit configuration range. The driver
> + * is in charge of the memory allocation
> + * @c33_pw_limit_nb_ranges: number of supported power limit configuration
> + * ranges
> + */
Is there a reason this is defined in ethtool.h?
I have a weak preference towards keeping it in pse-pd/pse.h
since touching ethtool.h rebuilds bulk of networking code.
From that perspective it's also suboptimal that pse-pd/pse.h
pulls in ethtool.h.
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-08 1:15 ` Jakub Kicinski
@ 2025-01-08 9:27 ` Kory Maincent
2025-01-08 17:36 ` Jakub Kicinski
0 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-08 9:27 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Tue, 7 Jan 2025 17:15:54 -0800
Jakub Kicinski <kuba@kernel.org> wrote:
> On Sat, 04 Jan 2025 23:27:33 +0100 Kory Maincent wrote:
> > diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
> > index f711bfd75c4d..2bdf7e72ee50 100644
> > --- a/include/linux/ethtool.h
> > +++ b/include/linux/ethtool.h
> > @@ -1323,4 +1323,40 @@ struct ethtool_c33_pse_pw_limit_range {
> > u32 min;
> > u32 max;
> > };
> > +
> > +/**
> > + * struct ethtool_pse_control_status - PSE control/channel status.
> > + *
> > + * @podl_admin_state: operational state of the PoDL PSE
> > + * functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
> > + * @podl_pw_status: power detection status of the PoDL PSE.
> > + * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus:
> > + * @c33_admin_state: operational state of the PSE
> > + * functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
> > + * @c33_pw_status: power detection status of the PSE.
> > + * IEEE 802.3-2022 30.9.1.1.5 aPSEPowerDetectionStatus:
> > + * @c33_pw_class: detected class of a powered PD
> > + * IEEE 802.3-2022 30.9.1.1.8 aPSEPowerClassification
> > + * @c33_actual_pw: power currently delivered by the PSE in mW
> > + * IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
> > + * @c33_ext_state_info: extended state information of the PSE
> > + * @c33_avail_pw_limit: available power limit of the PSE in mW
> > + * IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
> > + * @c33_pw_limit_ranges: supported power limit configuration range. The
> > driver
> > + * is in charge of the memory allocation
> > + * @c33_pw_limit_nb_ranges: number of supported power limit configuration
> > + * ranges
> > + */
>
> Is there a reason this is defined in ethtool.h?
I moved in to ethtool because the PSE drivers does not need it anymore.
I can keep it in pse.h.
> I have a weak preference towards keeping it in pse-pd/pse.h
> since touching ethtool.h rebuilds bulk of networking code.
> From that perspective it's also suboptimal that pse-pd/pse.h
> pulls in ethtool.h.
Do you prefer the other way around, ethtool.h pulls in pse.h?
Several structure are used in ethtool, PSE core and even drivers at the same
time so I don't have much choice. Or, is it preferable to add a new header?
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-08 9:27 ` Kory Maincent
@ 2025-01-08 17:36 ` Jakub Kicinski
2025-01-09 9:01 ` Kory Maincent
2025-01-09 9:37 ` Paolo Abeni
0 siblings, 2 replies; 28+ messages in thread
From: Jakub Kicinski @ 2025-01-08 17:36 UTC (permalink / raw)
To: Kory Maincent
Cc: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, 8 Jan 2025 10:27:36 +0100 Kory Maincent wrote:
> > Is there a reason this is defined in ethtool.h?
>
> I moved in to ethtool because the PSE drivers does not need it anymore.
> I can keep it in pse.h.
>
> > I have a weak preference towards keeping it in pse-pd/pse.h
> > since touching ethtool.h rebuilds bulk of networking code.
> > From that perspective it's also suboptimal that pse-pd/pse.h
> > pulls in ethtool.h.
>
> Do you prefer the other way around, ethtool.h pulls in pse.h?
No, no, I'd say the order of deceasing preference is:
- headers are independent
- smaller header includes bigger one
- bigger one includes smaller one
> Several structure are used in ethtool, PSE core and even drivers at the same
> time so I don't have much choice. Or, is it preferable to add a new header?
From a quick look it seemed like pse.h definitely needs the enums from
the uAPI. But I couldn't find anything from the kernel side ethtool.h
header it'd actually require (struct ethtool_c33_pse_ext_state_info
can be moved to pse.h as well?).
Anyways, it's not a major issue for existing code, more of forward guidance.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-08 17:36 ` Jakub Kicinski
@ 2025-01-09 9:01 ` Kory Maincent
2025-01-09 9:37 ` Paolo Abeni
1 sibling, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-09 9:01 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, 8 Jan 2025 09:36:45 -0800
Jakub Kicinski <kuba@kernel.org> wrote:
> On Wed, 8 Jan 2025 10:27:36 +0100 Kory Maincent wrote:
> > > Is there a reason this is defined in ethtool.h?
> >
> > I moved in to ethtool because the PSE drivers does not need it anymore.
> > I can keep it in pse.h.
> >
> > > I have a weak preference towards keeping it in pse-pd/pse.h
> > > since touching ethtool.h rebuilds bulk of networking code.
> > > From that perspective it's also suboptimal that pse-pd/pse.h
> > > pulls in ethtool.h.
> >
> > Do you prefer the other way around, ethtool.h pulls in pse.h?
>
> No, no, I'd say the order of deceasing preference is:
> - headers are independent
> - smaller header includes bigger one
> - bigger one includes smaller one
Ok good to know.
> > Several structure are used in ethtool, PSE core and even drivers at the same
> > time so I don't have much choice. Or, is it preferable to add a new header?
> >
>
> From a quick look it seemed like pse.h definitely needs the enums from
> the uAPI. But I couldn't find anything from the kernel side ethtool.h
> header it'd actually require (struct ethtool_c33_pse_ext_state_info
> can be moved to pse.h as well?).
>
> Anyways, it's not a major issue for existing code, more of forward guidance.
I am fully open to guidance to have proper code.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks
2025-01-08 17:36 ` Jakub Kicinski
2025-01-09 9:01 ` Kory Maincent
@ 2025-01-09 9:37 ` Paolo Abeni
1 sibling, 0 replies; 28+ messages in thread
From: Paolo Abeni @ 2025-01-09 9:37 UTC (permalink / raw)
To: Jakub Kicinski, Kory Maincent
Cc: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Simon Horman, Donald Hunter, Jonathan Corbet, Liam Girdwood,
Mark Brown, Thomas Petazzoni, linux-kernel, netdev, linux-doc,
Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On 1/8/25 6:36 PM, Jakub Kicinski wrote:
> On Wed, 8 Jan 2025 10:27:36 +0100 Kory Maincent wrote:
>>> Is there a reason this is defined in ethtool.h?
>>
>> I moved in to ethtool because the PSE drivers does not need it anymore.
>> I can keep it in pse.h.
>>
>>> I have a weak preference towards keeping it in pse-pd/pse.h
>>> since touching ethtool.h rebuilds bulk of networking code.
>>> From that perspective it's also suboptimal that pse-pd/pse.h
>>> pulls in ethtool.h.
>>
>> Do you prefer the other way around, ethtool.h pulls in pse.h?
>
> No, no, I'd say the order of deceasing preference is:
> - headers are independent
> - smaller header includes bigger one
> - bigger one includes smaller one
In this specific case, given the widespread inclusion of ethtool.h, I
think keeping the struct definition in pse.h is necessary - the reduced
incremental builds time would be a good enough reason for it.
Thanks!
Paolo
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH net-next 09/14] net: pse-pd: Remove is_enabled callback from drivers
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (7 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 08/14] net: pse-pd: Split ethtool_get_status into multiple callbacks Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-08 11:09 ` Oleksij Rempel
2025-01-04 22:27 ` [PATCH net-next 10/14] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
` (4 subsequent siblings)
13 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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 is_enabled callback is now redundant as the admin_state can be obtained
directly from the driver and provides the same information.
To simplify functionality, the core will handle this internally, making
the is_enabled callback unnecessary at the driver level. Remove the
callback from all drivers.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/net/pse-pd/pd692x0.c | 26 --------------------------
drivers/net/pse-pd/pse_core.c | 13 +++++++++++--
drivers/net/pse-pd/pse_regulator.c | 9 ---------
drivers/net/pse-pd/tps23881.c | 28 ----------------------------
include/linux/pse-pd/pse.h | 3 ---
5 files changed, 11 insertions(+), 68 deletions(-)
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index da5d09ed628a..fc9e23927b3b 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -431,31 +431,6 @@ static int pd692x0_pi_disable(struct pse_controller_dev *pcdev, int id)
return 0;
}
-static int pd692x0_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
-{
- struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
- struct pd692x0_msg msg, buf = {0};
- int ret;
-
- ret = pd692x0_fw_unavailable(priv);
- if (ret)
- return ret;
-
- msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
- msg.sub[2] = id;
- ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
- if (ret < 0)
- return ret;
-
- if (buf.sub[1]) {
- priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
- return 1;
- } else {
- priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
- return 0;
- }
-}
-
struct pd692x0_pse_ext_state_mapping {
u32 status_code;
enum ethtool_c33_pse_ext_state pse_ext_state;
@@ -1105,7 +1080,6 @@ static const struct pse_controller_ops pd692x0_ops = {
.pi_get_actual_pw = pd692x0_pi_get_actual_pw,
.pi_enable = pd692x0_pi_enable,
.pi_disable = pd692x0_pi_disable,
- .pi_is_enabled = pd692x0_pi_is_enabled,
.pi_get_voltage = pd692x0_pi_get_voltage,
.pi_get_pw_limit = pd692x0_pi_get_pw_limit,
.pi_set_pw_limit = pd692x0_pi_set_pw_limit,
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 5f2a9f36e4ed..887a477197a6 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -210,16 +210,25 @@ static int of_load_pse_pis(struct pse_controller_dev *pcdev)
static int pse_pi_is_enabled(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
+ struct pse_admin_state admin_state = {0};
const struct pse_controller_ops *ops;
int id, ret;
ops = pcdev->ops;
- if (!ops->pi_is_enabled)
+ if (!ops->pi_get_admin_state)
return -EOPNOTSUPP;
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
- ret = ops->pi_is_enabled(pcdev, id);
+ ret = ops->pi_get_admin_state(pcdev, id, &admin_state);
+ if (ret)
+ goto out;
+
+ if (admin_state.podl_admin_state == ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED ||
+ admin_state.c33_admin_state == ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED)
+ ret = 1;
+
+out:
mutex_unlock(&pcdev->lock);
return ret;
diff --git a/drivers/net/pse-pd/pse_regulator.c b/drivers/net/pse-pd/pse_regulator.c
index 86360056b2f5..6ce6773fff31 100644
--- a/drivers/net/pse-pd/pse_regulator.c
+++ b/drivers/net/pse-pd/pse_regulator.c
@@ -51,14 +51,6 @@ pse_reg_pi_disable(struct pse_controller_dev *pcdev, int id)
return 0;
}
-static int
-pse_reg_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
-{
- struct pse_reg_priv *priv = to_pse_reg(pcdev);
-
- return regulator_is_enabled(priv->ps);
-}
-
static int
pse_reg_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
struct pse_admin_state *admin_state)
@@ -95,7 +87,6 @@ static const struct pse_controller_ops pse_reg_ops = {
.pi_get_admin_state = pse_reg_pi_get_admin_state,
.pi_get_pw_status = pse_reg_pi_get_pw_status,
.pi_enable = pse_reg_pi_enable,
- .pi_is_enabled = pse_reg_pi_is_enabled,
.pi_disable = pse_reg_pi_disable,
};
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index f735b6917f8b..340d70ee37fe 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -174,33 +174,6 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
}
-static int tps23881_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
-{
- struct tps23881_priv *priv = to_tps23881_priv(pcdev);
- struct i2c_client *client = priv->client;
- bool enabled;
- u8 chan;
- u16 val;
- int ret;
-
- ret = i2c_smbus_read_word_data(client, TPS23881_REG_PW_STATUS);
- if (ret < 0)
- return ret;
-
- chan = priv->port[id].chan[0];
- val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
- enabled = !!(val);
-
- if (priv->port[id].is_4p) {
- chan = priv->port[id].chan[1];
- val = tps23881_calc_val(ret, chan, 0, BIT(chan % 4));
- enabled &= !!(val);
- }
-
- /* Return enabled status only if both channel are on this state */
- return enabled;
-}
-
static int
tps23881_pi_get_admin_state(struct pse_controller_dev *pcdev, int id,
struct pse_admin_state *admin_state)
@@ -690,7 +663,6 @@ static const struct pse_controller_ops tps23881_ops = {
.setup_pi_matrix = tps23881_setup_pi_matrix,
.pi_enable = tps23881_pi_enable,
.pi_disable = tps23881_pi_disable,
- .pi_is_enabled = tps23881_pi_is_enabled,
.pi_get_admin_state = tps23881_pi_get_admin_state,
.pi_get_pw_status = tps23881_pi_get_pw_status,
};
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index db8b3db7b849..09e62d8c3271 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -86,8 +86,6 @@ struct pse_pw_limit_ranges {
* @pi_get_ext_state: Get the extended state of the PSE PI.
* @pi_get_pw_class: Get the power class of the PSE PI.
* @pi_get_actual_pw: Get actual power of the PSE PI in mW.
- * @pi_is_enabled: Return 1 if the PSE PI is enabled, 0 if not.
- * May also return negative errno.
* @pi_enable: Configure the PSE PI as enabled.
* @pi_disable: Configure the PSE PI as disabled.
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
@@ -109,7 +107,6 @@ struct pse_controller_ops {
struct pse_ext_state_info *ext_state_info);
int (*pi_get_pw_class)(struct pse_controller_dev *pcdev, int id);
int (*pi_get_actual_pw)(struct pse_controller_dev *pcdev, int id);
- int (*pi_is_enabled)(struct pse_controller_dev *pcdev, int id);
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
int (*pi_get_voltage)(struct pse_controller_dev *pcdev, int id);
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH net-next 09/14] net: pse-pd: Remove is_enabled callback from drivers
2025-01-04 22:27 ` [PATCH net-next 09/14] net: pse-pd: Remove is_enabled callback from drivers Kory Maincent
@ 2025-01-08 11:09 ` Oleksij Rempel
0 siblings, 0 replies; 28+ messages in thread
From: Oleksij Rempel @ 2025-01-08 11:09 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sat, Jan 04, 2025 at 11:27:34PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> The is_enabled callback is now redundant as the admin_state can be obtained
> directly from the driver and provides the same information.
>
> To simplify functionality, the core will handle this internally, making
> the is_enabled callback unnecessary at the driver level. Remove the
> callback from all drivers.
>
> 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] 28+ messages in thread
* [PATCH net-next 10/14] net: pse-pd: tps23881: Add support for power limit and measurement features
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (8 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 09/14] net: pse-pd: Remove is_enabled callback from drivers Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-08 11:17 ` Oleksij Rempel
2025-01-04 22:27 ` [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index Kory Maincent
` (3 subsequent siblings)
13 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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_pw_limit() and pi_get_voltage() functions. These callbacks
allow for power limit configuration in the TPS23881 controller.
Additionally, the patch includes the pi_get_pw_class() the
pi_get_actual_pw(), and the pi_get_pw_limit_ranges') callbacks providing
more comprehensive PoE status reporting.
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/net/pse-pd/tps23881.c | 258 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 256 insertions(+), 2 deletions(-)
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index 340d70ee37fe..5e9dda2c0eac 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -25,20 +25,32 @@
#define TPS23881_REG_GEN_MASK 0x17
#define TPS23881_REG_NBITACC BIT(5)
#define TPS23881_REG_PW_EN 0x19
+#define TPS23881_REG_2PAIR_POL1 0x1e
#define TPS23881_REG_PORT_MAP 0x26
#define TPS23881_REG_PORT_POWER 0x29
-#define TPS23881_REG_POEPLUS 0x40
+#define TPS23881_REG_4PAIR_POL1 0x2a
+#define TPS23881_REG_INPUT_V 0x2e
+#define TPS23881_REG_CHAN1_A 0x30
+#define TPS23881_REG_CHAN1_V 0x32
+#define TPS23881_REG_FOLDBACK 0x40
#define TPS23881_REG_TPON BIT(0)
#define TPS23881_REG_FWREV 0x41
#define TPS23881_REG_DEVID 0x43
#define TPS23881_REG_DEVID_MASK 0xF0
#define TPS23881_DEVICE_ID 0x02
+#define TPS23881_REG_CHAN1_CLASS 0x4c
#define TPS23881_REG_SRAM_CTRL 0x60
#define TPS23881_REG_SRAM_DATA 0x61
+#define TPS23881_UV_STEP 3662
+#define TPS23881_NA_STEP 70190
+#define TPS23881_MW_STEP 500
+#define TPS23881_MIN_PI_PW_LIMIT_MW 2000
+
struct tps23881_port_desc {
u8 chan[2];
bool is_4p;
+ int pw_pol;
};
struct tps23881_priv {
@@ -102,6 +114,54 @@ static u16 tps23881_set_val(u16 reg_val, u8 chan, u8 field_offset,
return reg_val;
}
+static int
+tps23881_pi_set_pw_pol_limit(struct tps23881_priv *priv, int id, u8 pw_pol,
+ bool is_4p)
+{
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u16 val;
+ u8 chan;
+
+ chan = priv->port[id].chan[0];
+ if (!is_4p) {
+ reg = TPS23881_REG_2PAIR_POL1 + (chan % 4);
+ } else {
+ /* One chan is enough to configure the 4p PI power limit */
+ if ((chan % 4) < 2)
+ reg = TPS23881_REG_4PAIR_POL1;
+ else
+ reg = TPS23881_REG_4PAIR_POL1 + 1;
+ }
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_set_val(ret, chan, 0, 0xff, pw_pol);
+ return i2c_smbus_write_word_data(client, reg, val);
+}
+
+static int tps23881_pi_enable_manual_pol(struct tps23881_priv *priv, int id)
+{
+ struct i2c_client *client = priv->client;
+ int ret;
+ u8 chan;
+ u16 val;
+
+ ret = i2c_smbus_read_byte_data(client, TPS23881_REG_FOLDBACK);
+ if (ret < 0)
+ return ret;
+
+ /* No need to test if the chan is PoE4 as setting either bit for a
+ * 4P configured port disables the automatic configuration on both
+ * channels.
+ */
+ chan = priv->port[id].chan[0];
+ val = tps23881_set_val(ret, chan, 0, BIT(chan % 4), BIT(chan % 4));
+ return i2c_smbus_write_byte_data(client, TPS23881_REG_FOLDBACK, val);
+}
+
static int tps23881_pi_enable(struct pse_controller_dev *pcdev, int id)
{
struct tps23881_priv *priv = to_tps23881_priv(pcdev);
@@ -171,7 +231,21 @@ static int tps23881_pi_disable(struct pse_controller_dev *pcdev, int id)
BIT(chan % 4));
}
- return i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
+ ret = i2c_smbus_write_word_data(client, TPS23881_REG_DET_CLA_EN, val);
+ if (ret)
+ return ret;
+
+ /* No power policy */
+ if (priv->port[id].pw_pol < 0)
+ return 0;
+
+ ret = tps23881_pi_enable_manual_pol(priv, id);
+ if (ret < 0)
+ return ret;
+
+ /* Set power policy */
+ return tps23881_pi_set_pw_pol_limit(priv, id, priv->port[id].pw_pol,
+ priv->port[id].is_4p);
}
static int
@@ -246,6 +320,177 @@ tps23881_pi_get_pw_status(struct pse_controller_dev *pcdev, int id,
return 0;
}
+static int tps23881_pi_get_voltage(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ int ret;
+ u64 uV;
+
+ ret = i2c_smbus_read_word_data(client, TPS23881_REG_INPUT_V);
+ if (ret < 0)
+ return ret;
+
+ uV = ret & 0x3fff;
+ uV *= TPS23881_UV_STEP;
+
+ return (int)uV;
+}
+
+static int
+tps23881_pi_get_chan_current(struct tps23881_priv *priv, u8 chan)
+{
+ struct i2c_client *client = priv->client;
+ int reg, ret;
+ u64 tmp_64;
+
+ /* Registers 0x30 to 0x3d */
+ reg = TPS23881_REG_CHAN1_A + (chan % 4) * 4 + (chan >= 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ tmp_64 = ret & 0x3fff;
+ tmp_64 *= TPS23881_NA_STEP;
+ /* uA = nA / 1000 */
+ tmp_64 = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000);
+ return (int)tmp_64;
+}
+
+static int tps23881_pi_get_pw_class(struct pse_controller_dev *pcdev,
+ int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u8 chan;
+
+ chan = priv->port[id].chan[0];
+ reg = TPS23881_REG_CHAN1_CLASS + (chan % 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ return tps23881_calc_val(ret, chan, 4, 0x0f);
+}
+
+static int
+tps23881_pi_get_actual_pw(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ int ret, uV, uA;
+ u64 tmp_64;
+ u8 chan;
+
+ ret = tps23881_pi_get_voltage(&priv->pcdev, id);
+ if (ret < 0)
+ return ret;
+ uV = ret;
+
+ chan = priv->port[id].chan[0];
+ ret = tps23881_pi_get_chan_current(priv, chan);
+ if (ret < 0)
+ return ret;
+ uA = ret;
+
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
+ ret = tps23881_pi_get_chan_current(priv, chan);
+ if (ret < 0)
+ return ret;
+ uA += ret;
+ }
+
+ tmp_64 = uV;
+ tmp_64 *= uA;
+ /* mW = uV * uA / 1000000000 */
+ return DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
+}
+
+static int
+tps23881_pi_get_pw_limit_chan(struct tps23881_priv *priv, u8 chan)
+{
+ struct i2c_client *client = priv->client;
+ int ret, reg;
+ u16 val;
+
+ reg = TPS23881_REG_2PAIR_POL1 + (chan % 4);
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = tps23881_calc_val(ret, chan, 0, 0xff);
+ return val * TPS23881_MW_STEP;
+}
+
+static int tps23881_pi_get_pw_limit(struct pse_controller_dev *pcdev, int id)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ int ret, mW;
+ u8 chan;
+
+ chan = priv->port[id].chan[0];
+ ret = tps23881_pi_get_pw_limit_chan(priv, chan);
+ if (ret < 0)
+ return ret;
+
+ mW = ret;
+ if (priv->port[id].is_4p) {
+ chan = priv->port[id].chan[1];
+ ret = tps23881_pi_get_pw_limit_chan(priv, chan);
+ if (ret < 0)
+ return ret;
+ mW += ret;
+ }
+
+ return mW;
+}
+
+static int tps23881_pi_set_pw_limit(struct pse_controller_dev *pcdev,
+ int id, int max_mW)
+{
+ struct tps23881_priv *priv = to_tps23881_priv(pcdev);
+ u8 pw_pol;
+ int ret;
+
+ if (max_mW < TPS23881_MIN_PI_PW_LIMIT_MW || MAX_PI_PW < max_mW) {
+ dev_err(&priv->client->dev,
+ "power limit %d out of ranges [%d,%d]",
+ max_mW, TPS23881_MIN_PI_PW_LIMIT_MW, MAX_PI_PW);
+ return -ERANGE;
+ }
+
+ ret = tps23881_pi_enable_manual_pol(priv, id);
+ if (ret < 0)
+ return ret;
+
+ pw_pol = DIV_ROUND_CLOSEST_ULL(max_mW, TPS23881_MW_STEP);
+
+ /* Save power policy to reconfigure it after a disabled call */
+ priv->port[id].pw_pol = pw_pol;
+ return tps23881_pi_set_pw_pol_limit(priv, id, pw_pol,
+ priv->port[id].is_4p);
+}
+
+static int
+tps23881_pi_get_pw_limit_ranges(struct pse_controller_dev *pcdev, int id,
+ struct pse_pw_limit_ranges *pw_limit_ranges)
+{
+ struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
+
+ c33_pw_limit_ranges = kzalloc(sizeof(*c33_pw_limit_ranges),
+ GFP_KERNEL);
+ if (!c33_pw_limit_ranges)
+ return -ENOMEM;
+
+ c33_pw_limit_ranges->min = TPS23881_MIN_PI_PW_LIMIT_MW;
+ c33_pw_limit_ranges->max = MAX_PI_PW;
+ pw_limit_ranges->c33_pw_limit_ranges = c33_pw_limit_ranges;
+
+ /* Return the number of ranges */
+ return 1;
+}
+
/* Parse managers subnode into a array of device node */
static int
tps23881_get_of_channels(struct tps23881_priv *priv,
@@ -540,6 +785,9 @@ tps23881_write_port_matrix(struct tps23881_priv *priv,
if (port_matrix[i].exist)
priv->port[pi_id].chan[0] = lgcl_chan;
+ /* Initialize power policy internal value */
+ priv->port[pi_id].pw_pol = -1;
+
/* Set hardware port matrix for all ports */
val |= hw_chan << (lgcl_chan * 2);
@@ -665,6 +913,12 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_disable = tps23881_pi_disable,
.pi_get_admin_state = tps23881_pi_get_admin_state,
.pi_get_pw_status = tps23881_pi_get_pw_status,
+ .pi_get_pw_class = tps23881_pi_get_pw_class,
+ .pi_get_actual_pw = tps23881_pi_get_actual_pw,
+ .pi_get_voltage = tps23881_pi_get_voltage,
+ .pi_get_pw_limit = tps23881_pi_get_pw_limit,
+ .pi_set_pw_limit = tps23881_pi_set_pw_limit,
+ .pi_get_pw_limit_ranges = tps23881_pi_get_pw_limit_ranges,
};
static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH net-next 10/14] net: pse-pd: tps23881: Add support for power limit and measurement features
2025-01-04 22:27 ` [PATCH net-next 10/14] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
@ 2025-01-08 11:17 ` Oleksij Rempel
0 siblings, 0 replies; 28+ messages in thread
From: Oleksij Rempel @ 2025-01-08 11:17 UTC (permalink / raw)
To: Kory Maincent
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sat, Jan 04, 2025 at 11:27:35PM +0100, Kory Maincent wrote:
> From: Kory Maincent (Dent Project) <kory.maincent@bootlin.com>
>
> Expand PSE callbacks to support the newly introduced
> pi_get/set_pw_limit() and pi_get_voltage() functions. These callbacks
> allow for power limit configuration in the TPS23881 controller.
>
> Additionally, the patch includes the pi_get_pw_class() the
> pi_get_actual_pw(), and the pi_get_pw_limit_ranges') callbacks providing
> more comprehensive PoE status reporting.
>
> Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
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] 28+ messages in thread
* [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (9 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 10/14] net: pse-pd: tps23881: Add support for power limit and measurement features Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-08 1:18 ` Jakub Kicinski
2025-01-04 22:27 ` [PATCH net-next 12/14] net: ethtool: Add support for new PSE device index description Kory Maincent
` (2 subsequent siblings)
13 siblings, 1 reply; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/net/pse-pd/pse_core.c | 24 +++++++++++++++++++-----
include/linux/ethtool.h | 2 ++
include/linux/pse-pd/pse.h | 2 ++
3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 887a477197a6..830e8d567d4d 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -13,6 +13,7 @@
static DEFINE_MUTEX(pse_list_mutex);
static LIST_HEAD(pse_controller_list);
+static DEFINE_IDA(pse_ida);
/**
* struct pse_control - a PSE control
@@ -448,6 +449,10 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
mutex_init(&pcdev->lock);
INIT_LIST_HEAD(&pcdev->pse_control_head);
+ ret = ida_alloc_max(&pse_ida, INT_MAX, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+ pcdev->id = ret;
if (!pcdev->nr_lines)
pcdev->nr_lines = 1;
@@ -461,12 +466,12 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
ret = of_load_pse_pis(pcdev);
if (ret)
- return ret;
+ goto free_pse_ida;
if (pcdev->ops->setup_pi_matrix) {
ret = pcdev->ops->setup_pi_matrix(pcdev);
if (ret)
- return ret;
+ goto free_pse_ida;
}
/* Each regulator name len is pcdev dev name + 7 char +
@@ -483,15 +488,17 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
continue;
reg_name = devm_kzalloc(pcdev->dev, reg_name_len, GFP_KERNEL);
- if (!reg_name)
- return -ENOMEM;
+ if (!reg_name) {
+ ret = -ENOMEM;
+ goto free_pse_ida;
+ }
snprintf(reg_name, reg_name_len, "pse-%s_pi%d",
dev_name(pcdev->dev), i);
ret = devm_pse_pi_regulator_register(pcdev, reg_name, i);
if (ret)
- return ret;
+ goto free_pse_ida;
}
mutex_lock(&pse_list_mutex);
@@ -499,6 +506,10 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
mutex_unlock(&pse_list_mutex);
return 0;
+
+free_pse_ida:
+ ida_free(&pse_ida, pcdev->id);
+ return ret;
}
EXPORT_SYMBOL_GPL(pse_controller_register);
@@ -509,6 +520,7 @@ EXPORT_SYMBOL_GPL(pse_controller_register);
void pse_controller_unregister(struct pse_controller_dev *pcdev)
{
pse_release_pis(pcdev);
+ ida_free(&pse_ida, pcdev->id);
mutex_lock(&pse_list_mutex);
list_del(&pcdev->list);
mutex_unlock(&pse_list_mutex);
@@ -771,6 +783,8 @@ int pse_ethtool_get_status(struct pse_control *psec,
pcdev = psec->pcdev;
ops = pcdev->ops;
+ status->pse_id = pcdev->id;
+
mutex_lock(&pcdev->lock);
ret = ops->pi_get_admin_state(pcdev, psec->id, &admin_state);
if (ret)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 2bdf7e72ee50..d5d13a3d4447 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1327,6 +1327,7 @@ struct ethtool_c33_pse_pw_limit_range {
/**
* struct ethtool_pse_control_status - PSE control/channel status.
*
+ * @pse_id: index number of the PSE.
* @podl_admin_state: operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
* @podl_pw_status: power detection status of the PoDL PSE.
@@ -1348,6 +1349,7 @@ struct ethtool_c33_pse_pw_limit_range {
* ranges
*/
struct ethtool_pse_control_status {
+ u32 pse_id;
enum ethtool_podl_pse_admin_state podl_admin_state;
enum ethtool_podl_pse_pw_d_status podl_pw_status;
enum ethtool_c33_pse_admin_state c33_admin_state;
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 09e62d8c3271..8780a4160d3c 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -172,6 +172,7 @@ struct pse_pi {
* @types: types of the PSE controller
* @pi: table of PSE PIs described in this controller device
* @no_of_pse_pi: flag set if the pse_pis devicetree node is not used
+ * @id: Index of the PSE
*/
struct pse_controller_dev {
const struct pse_controller_ops *ops;
@@ -185,6 +186,7 @@ struct pse_controller_dev {
enum ethtool_pse_types types;
struct pse_pi *pi;
bool no_of_pse_pi;
+ u32 id;
};
#if IS_ENABLED(CONFIG_PSE_CONTROLLER)
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index
2025-01-04 22:27 ` [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index Kory Maincent
@ 2025-01-08 1:18 ` Jakub Kicinski
2025-01-08 5:47 ` Oleksij Rempel
0 siblings, 1 reply; 28+ messages in thread
From: Jakub Kicinski @ 2025-01-08 1:18 UTC (permalink / raw)
To: Kory Maincent
Cc: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Sat, 04 Jan 2025 23:27:36 +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.
Can you say more? How do the PSE controllers relate to netdevs?
ethtool is primarily driven by netdev / ifindex.
If you're starting to build your own object hierarchy you may be
better off with a separate genl family.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index
2025-01-08 1:18 ` Jakub Kicinski
@ 2025-01-08 5:47 ` Oleksij Rempel
2025-01-08 17:42 ` Jakub Kicinski
0 siblings, 1 reply; 28+ messages in thread
From: Oleksij Rempel @ 2025-01-08 5:47 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Kory Maincent, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Tue, Jan 07, 2025 at 05:18:34PM -0800, Jakub Kicinski wrote:
> On Sat, 04 Jan 2025 23:27:36 +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.
>
> Can you say more? How do the PSE controllers relate to netdevs?
> ethtool is primarily driven by netdev / ifindex.
> If you're starting to build your own object hierarchy you may be
> better off with a separate genl family.
I hope this schema may help to explain the topology:
+--- netdev / ifindex 0
+--- PSE power domain 0 --+--- netdev / ifindex 1
| +--- netdev / ifindex 2
PSE ctrl 0 -+
| +--- netdev / ifindex 3
+--- PSE power domain 1 --+--- netdev / ifindex 4
+--- netdev / ifindex 5
+--- netdev / ifindex 6
+--- PSE power domain 2 --+--- netdev / ifindex 7
| +--- netdev / ifindex 8
PSE ctrl 1 -+
| +--- netdev / ifindex 9
+--- PSE power domain 3 --+--- netdev / ifindex 10
+--- netdev / ifindex 11
PSE device index is needed to find actually PSE controller related to
specific netdev / ifindex.
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] 28+ messages in thread* Re: [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index
2025-01-08 5:47 ` Oleksij Rempel
@ 2025-01-08 17:42 ` Jakub Kicinski
2025-01-08 18:17 ` Oleksij Rempel
0 siblings, 1 reply; 28+ messages in thread
From: Jakub Kicinski @ 2025-01-08 17:42 UTC (permalink / raw)
To: Oleksij Rempel
Cc: Kory Maincent, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, 8 Jan 2025 06:47:10 +0100 Oleksij Rempel wrote:
> On Tue, Jan 07, 2025 at 05:18:34PM -0800, Jakub Kicinski wrote:
> > On Sat, 04 Jan 2025 23:27:36 +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.
> >
> > Can you say more? How do the PSE controllers relate to netdevs?
> > ethtool is primarily driven by netdev / ifindex.
> > If you're starting to build your own object hierarchy you may be
> > better off with a separate genl family.
>
> I hope this schema may help to explain the topology:
>
> +--- netdev / ifindex 0
> +--- PSE power domain 0 --+--- netdev / ifindex 1
> | +--- netdev / ifindex 2
> PSE ctrl 0 -+
> | +--- netdev / ifindex 3
> +--- PSE power domain 1 --+--- netdev / ifindex 4
> +--- netdev / ifindex 5
>
> +--- netdev / ifindex 6
> +--- PSE power domain 2 --+--- netdev / ifindex 7
> | +--- netdev / ifindex 8
> PSE ctrl 1 -+
> | +--- netdev / ifindex 9
> +--- PSE power domain 3 --+--- netdev / ifindex 10
> +--- netdev / ifindex 11
>
> PSE device index is needed to find actually PSE controller related to
> specific netdev / ifindex.
Makes sense. So how does it end up looking in terms of APIs
and attributes? Will we need much more than power limits at
the domain and ctrl level?
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index
2025-01-08 17:42 ` Jakub Kicinski
@ 2025-01-08 18:17 ` Oleksij Rempel
0 siblings, 0 replies; 28+ messages in thread
From: Oleksij Rempel @ 2025-01-08 18:17 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Kory Maincent, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Donald Hunter, Jonathan Corbet,
Liam Girdwood, Mark Brown, Thomas Petazzoni, linux-kernel, netdev,
linux-doc, Kyle Swenson, Dent Project, kernel, Maxime Chevallier
On Wed, Jan 08, 2025 at 09:42:01AM -0800, Jakub Kicinski wrote:
> On Wed, 8 Jan 2025 06:47:10 +0100 Oleksij Rempel wrote:
> > On Tue, Jan 07, 2025 at 05:18:34PM -0800, Jakub Kicinski wrote:
> > > On Sat, 04 Jan 2025 23:27:36 +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.
> > >
> > > Can you say more? How do the PSE controllers relate to netdevs?
> > > ethtool is primarily driven by netdev / ifindex.
> > > If you're starting to build your own object hierarchy you may be
> > > better off with a separate genl family.
> >
> > I hope this schema may help to explain the topology:
> >
> > +--- netdev / ifindex 0
> > +--- PSE power domain 0 --+--- netdev / ifindex 1
> > | +--- netdev / ifindex 2
> > PSE ctrl 0 -+
> > | +--- netdev / ifindex 3
> > +--- PSE power domain 1 --+--- netdev / ifindex 4
> > +--- netdev / ifindex 5
> >
> > +--- netdev / ifindex 6
> > +--- PSE power domain 2 --+--- netdev / ifindex 7
> > | +--- netdev / ifindex 8
> > PSE ctrl 1 -+
> > | +--- netdev / ifindex 9
> > +--- PSE power domain 3 --+--- netdev / ifindex 10
> > +--- netdev / ifindex 11
> >
> > PSE device index is needed to find actually PSE controller related to
> > specific netdev / ifindex.
>
> Makes sense. So how does it end up looking in terms of APIs
> and attributes? Will we need much more than power limits at
> the domain and ctrl level?
The PSE power domains are based on regulator framework. So, we will get
some diagnostic and may be control API on this side.
The PSE controller will need some configuration and diagnostic
interfaces. For example:
- not port specific configurations
- not port specific diagnostics
Every thing port related can be passed to the netdev
--
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] 28+ messages in thread
* [PATCH net-next 12/14] net: ethtool: Add support for new PSE device index description
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (10 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 11/14] net: pse-pd: Add support for PSE device index Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 13/14] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 14/14] net: pse-pd: Fix missing PI of_node description Kory Maincent
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, Liam Girdwood, Mark Brown
Cc: Thomas Petazzoni, linux-kernel, netdev, linux-doc, Kyle Swenson,
Dent Project, kernel, Maxime Chevallier, Kory Maincent,
Andrew Lunn
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>
---
Documentation/netlink/specs/ethtool.yaml | 5 +++++
Documentation/networking/ethtool-netlink.rst | 4 ++++
include/uapi/linux/ethtool_netlink.h | 1 -
include/uapi/linux/ethtool_netlink_generated.h | 1 +
net/ethtool/pse-pd.c | 4 ++++
5 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 60f85fbf4156..cc26a9dfa8f7 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -1357,6 +1357,10 @@ attribute-sets:
type: nest
multi-attr: true
nested-attributes: c33-pse-pw-limit
+ -
+ name: pse-id
+ type: u32
+ name-prefix: ethtool-a-
-
name: rss
attr-cnt-name: __ethtool-a-rss-cnt
@@ -2162,6 +2166,7 @@ operations:
- c33-pse-ext-substate
- c33-pse-avail-pw-limit
- c33-pse-pw-limit-ranges
+ - pse-id
dump: *pse-get-op
-
name: pse-set
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index a7ba6368a4d5..6f5a880d8df2 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1771,6 +1771,7 @@ Kernel response contents:
limit of the PoE PSE.
``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested Supported power limit
configuration ranges.
+ ``ETHTOOL_A_PSE_ID`` u32 Index of the PSE
========================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
@@ -1844,6 +1845,9 @@ identifies the C33 PSE power limit ranges through
If the controller works with fixed classes, the min and max values will be
equal.
+The ``ETHTOOL_A_PSE_ID`` attribute identifies the index of the PSE
+controller.
+
PSE_SET
=======
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 9c909ce733a5..335127b895fe 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -193,7 +193,6 @@ enum {
ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1)
};
-
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index 43993a2d68e5..b3c928c71ca3 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -630,6 +630,7 @@ enum {
ETHTOOL_A_C33_PSE_EXT_SUBSTATE,
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT,
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES,
+ ETHTOOL_A_PSE_ID,
__ETHTOOL_A_PSE_CNT,
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 2819e2ba6be2..6cfdfaa47c1c 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -83,6 +83,7 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
const struct ethtool_pse_control_status *st = &data->status;
int len = 0;
+ len += nla_total_size(sizeof(u32)); /* _PSE_ID */
if (st->podl_admin_state > 0)
len += nla_total_size(sizeof(u32)); /* _PODL_PSE_ADMIN_STATE */
if (st->podl_pw_status > 0)
@@ -148,6 +149,9 @@ static int pse_fill_reply(struct sk_buff *skb,
const struct pse_reply_data *data = PSE_REPDATA(reply_base);
const struct ethtool_pse_control_status *st = &data->status;
+ if (nla_put_u32(skb, ETHTOOL_A_PSE_ID, st->pse_id))
+ return -EMSGSIZE;
+
if (st->podl_admin_state > 0 &&
nla_put_u32(skb, ETHTOOL_A_PODL_PSE_ADMIN_STATE,
st->podl_admin_state))
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH net-next 13/14] regulator: core: Resolve supply using of_node from regulator_config
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (11 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 12/14] net: ethtool: Add support for new PSE device index description Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
2025-01-04 22:27 ` [PATCH net-next 14/14] net: pse-pd: Fix missing PI of_node description Kory Maincent
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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.
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
drivers/regulator/core.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8cb948a91e60..c092b78c5f12 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1936,6 +1936,20 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
return dev ? dev_to_rdev(dev) : NULL;
}
+static struct regulator_dev *regulator_dt_lookup(struct device *dev,
+ const char *supply)
+{
+ struct regulator_dev *r = NULL;
+
+ if (dev_of_node(dev)) {
+ r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
+ if (PTR_ERR(r) == -ENODEV)
+ r = NULL;
+ }
+
+ return r;
+}
+
/**
* regulator_dev_lookup - lookup a regulator device.
* @dev: device for regulator "consumer".
@@ -1960,16 +1974,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
regulator_supply_alias(&dev, &supply);
/* first do a dt based lookup */
- if (dev_of_node(dev)) {
- r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
- if (!IS_ERR(r))
- return r;
- if (PTR_ERR(r) == -EPROBE_DEFER)
- return r;
-
- if (PTR_ERR(r) == -ENODEV)
- r = NULL;
- }
+ r = regulator_dt_lookup(dev, supply);
+ if (r)
+ return r;
/* if not found, try doing it non-dt way */
if (dev)
@@ -2015,7 +2022,17 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (rdev->supply)
return 0;
- r = regulator_dev_lookup(dev, rdev->supply_name);
+ /* first do a dt based lookup on the node described in the virtual
+ * device.
+ */
+ r = regulator_dt_lookup(&rdev->dev, rdev->supply_name);
+
+ /* If regulator not found use usual search path in the parent
+ * device.
+ */
+ if (!r)
+ r = regulator_dev_lookup(dev, rdev->supply_name);
+
if (IS_ERR(r)) {
ret = PTR_ERR(r);
--
2.34.1
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH net-next 14/14] net: pse-pd: Fix missing PI of_node description
2025-01-04 22:27 [PATCH net-next 00/14] Arrange PSE core and update TPS23881 driver Kory Maincent
` (12 preceding siblings ...)
2025-01-04 22:27 ` [PATCH net-next 13/14] regulator: core: Resolve supply using of_node from regulator_config Kory Maincent
@ 2025-01-04 22:27 ` Kory Maincent
13 siblings, 0 replies; 28+ messages in thread
From: Kory Maincent @ 2025-01-04 22:27 UTC (permalink / raw)
To: Oleksij Rempel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Donald Hunter,
Jonathan Corbet, 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.
Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
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 830e8d567d4d..be56b3f5425c 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -423,6 +423,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] 28+ messages in thread