2024-05-29 14:21:56

by Kory Maincent

[permalink] [raw]
Subject: [PATCH 0/8] net: pse-pd: Add new PSE c33 features

From: "Kory Maincent (Dent Project)" <[email protected]>

This patch series adds new c33 features to the PSE API.
- Expand the PSE PI informations status with power, class and failure
reason
- Add the possibility to get and set the PSE PIs power limit

Jakub could you check if patchwork works correctly with this patch series.

Signed-off-by: Kory Maincent <[email protected]>
---
Kory Maincent (8):
net: pse-pd: Use EOPNOTSUPP error code instead of ENOTSUPP
net: ethtool: pse-pd: Expand C33 PSE status with class, power and status message
netlink: specs: Expand the PSE netlink command with C33 new features
net: pse-pd: pd692x0: Expand ethtool status message
net: pse-pd: Add new power limit get and set c33 features
net: ethtool: Add new power limit get and set features
netlink: specs: Expand the PSE netlink command with C33 pw-limit attributes
net: pse-pd: pd692x0: Enhance with new current limit and voltage read callbacks

Documentation/netlink/specs/ethtool.yaml | 20 +++
drivers/net/pse-pd/pd692x0.c | 261 ++++++++++++++++++++++++++++++-
drivers/net/pse-pd/pse_core.c | 169 ++++++++++++++++++--
include/linux/pse-pd/pse.h | 48 +++++-
include/uapi/linux/ethtool_netlink.h | 4 +
net/ethtool/pse-pd.c | 63 +++++++-
6 files changed, 544 insertions(+), 21 deletions(-)
---
base-commit: c7309fc9b716c653dc37c8ebcdc6e9132c370076
change-id: 20240425-feature_poe_power_cap-18e90ba7294b

Best regards,
--
K?ry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com



2024-05-29 14:21:57

by Kory Maincent

[permalink] [raw]
Subject: [PATCH 6/8] net: ethtool: Add new power limit get and set features

From: "Kory Maincent (Dent Project)" <[email protected]>

This patch expands the status information provided by ethtool for PSE c33
with power limit. It also adds a call to pse_ethtool_set_pw_limit() to
configure the PSE control power limit.

Signed-off-by: Kory Maincent <[email protected]>
---
include/uapi/linux/ethtool_netlink.h | 1 +
net/ethtool/pse-pd.c | 41 ++++++++++++++++++++++++++++++------
2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index c3f288b737e6..2b8c76278b9f 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -918,6 +918,7 @@ enum {
ETHTOOL_A_C33_PSE_PW_STATUS_MSG, /* binary */
ETHTOOL_A_C33_PSE_PW_CLASS, /* u32 */
ETHTOOL_A_C33_PSE_ACTUAL_PW, /* u32 */
+ ETHTOOL_A_C33_PSE_PW_LIMIT, /* u32 */

/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index faddc14efbea..dbd75eeae4eb 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -93,6 +93,8 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
if (st->c33_pw_status_msg)
/* _C33_PSE_PW_STATUS_MSG */
len += nla_total_size(strlen(st->c33_pw_status_msg) + 1);
+ if (st->c33_pw_limit > 0)
+ len += nla_total_size(sizeof(u32)); /* _C33_PSE_PW_LIMIT */

return len;
}
@@ -139,6 +141,11 @@ static int pse_fill_reply(struct sk_buff *skb,
st->c33_pw_status_msg))
return -EMSGSIZE;

+ if (st->c33_pw_limit > 0 &&
+ nla_put_u32(skb, ETHTOOL_A_C33_PSE_PW_LIMIT,
+ st->c33_pw_limit))
+ return -EMSGSIZE;
+
return 0;
}

@@ -152,6 +159,7 @@ const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1] = {
[ETHTOOL_A_C33_PSE_ADMIN_CONTROL] =
NLA_POLICY_RANGE(NLA_U32, ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED,
ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED),
+ [ETHTOOL_A_C33_PSE_PW_LIMIT] = { .type = NLA_U32 },
};

static int
@@ -194,19 +202,38 @@ static int
ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
{
struct net_device *dev = req_info->dev;
- struct pse_control_config config = {};
struct nlattr **tb = info->attrs;
struct phy_device *phydev;
+ int ret = 0;

phydev = dev->phydev;
+
+ if (tb[ETHTOOL_A_C33_PSE_PW_LIMIT]) {
+ unsigned int pw_limit = nla_get_u32(tb[ETHTOOL_A_C33_PSE_PW_LIMIT]);
+
+ ret = pse_ethtool_set_pw_limit(phydev->psec, info->extack,
+ pw_limit);
+ if (ret)
+ return ret;
+ }
+
/* These values are already validated by the ethnl_pse_set_policy */
- if (pse_has_podl(phydev->psec))
- config.podl_admin_control = nla_get_u32(tb[ETHTOOL_A_PODL_PSE_ADMIN_CONTROL]);
- if (pse_has_c33(phydev->psec))
- config.c33_admin_control = nla_get_u32(tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]);
+ if (tb[ETHTOOL_A_PODL_PSE_ADMIN_CONTROL] ||
+ tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]) {
+ struct pse_control_config config = {};
+
+ if (pse_has_podl(phydev->psec))
+ config.podl_admin_control = nla_get_u32(tb[ETHTOOL_A_PODL_PSE_ADMIN_CONTROL]);
+ if (pse_has_c33(phydev->psec))
+ config.c33_admin_control = nla_get_u32(tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]);
+
+ ret = pse_ethtool_set_config(phydev->psec, info->extack,
+ &config);
+ if (ret)
+ return ret;
+ }

- /* Return errno directly - PSE has no notification */
- return pse_ethtool_set_config(phydev->psec, info->extack, &config);
+ return ret;
}

const struct ethnl_request_ops ethnl_pse_request_ops = {

--
2.34.1


2024-05-29 14:22:31

by Kory Maincent

[permalink] [raw]
Subject: [PATCH 4/8] net: pse-pd: pd692x0: Expand ethtool status message

From: "Kory Maincent (Dent Project)" <[email protected]>

This update expands pd692x0_ethtool_get_status() callback with newly
introduced details such as the detected class, current power delivered,
and a detailed status message.

Signed-off-by: Kory Maincent <[email protected]>
---
drivers/net/pse-pd/pd692x0.c | 96 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)

diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c
index 6488b941703c..017a8efc43c4 100644
--- a/drivers/net/pse-pd/pd692x0.c
+++ b/drivers/net/pse-pd/pd692x0.c
@@ -73,6 +73,7 @@ enum {
PD692X0_MSG_SET_PORT_PARAM,
PD692X0_MSG_GET_PORT_STATUS,
PD692X0_MSG_DOWNLOAD_CMD,
+ PD692X0_MSG_GET_PORT_CLASS,

/* add new message above here */
PD692X0_MSG_CNT
@@ -149,6 +150,12 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
.data = {0x16, 0x16, 0x99, 0x4e,
0x4e, 0x4e, 0x4e, 0x4e},
},
+ [PD692X0_MSG_GET_PORT_CLASS] = {
+ .key = PD692X0_KEY_REQ,
+ .sub = {0x05, 0xc4},
+ .data = {0x4e, 0x4e, 0x4e, 0x4e,
+ 0x4e, 0x4e, 0x4e, 0x4e},
+ },
};

static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo)
@@ -435,6 +442,79 @@ static int pd692x0_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
}
}

+struct pd692x0_status_msg {
+ int id;
+ const char msg[63];
+};
+
+static const struct pd692x0_status_msg pd692x0_status_msg_list[] = {
+ {.id = 0x06, .msg = "Port is off: Main supply voltage is high."},
+ {.id = 0x07, .msg = "Port is off: Main supply voltage is low."},
+ {.id = 0x08, .msg = "Port is off: Disable all ports pin is active."},
+ {.id = 0x0C, .msg = "Port is off: Non-existing port number."},
+ {.id = 0x11, .msg = "Port is yet undefined."},
+ {.id = 0x12, .msg = "Port is off: Internal hardware fault."},
+ {.id = 0x1A, .msg = "Port is off: User setting."},
+ {.id = 0x1B, .msg = "Port is off: Detection is in process."},
+ {.id = 0x1C, .msg = "Port is off: Non-802.3AF/AT powered device."},
+ {.id = 0x1E, .msg = "Port is off: Underload state."},
+ {.id = 0x1F, .msg = "Port is off: Overload state."},
+ {.id = 0x20, .msg = "Port is off: Power budget exceeded."},
+ {.id = 0x21, .msg = "Port is off: Internal hardware routing error."},
+ {.id = 0x22, .msg = "Port is off: Configuration change."},
+ {.id = 0x24, .msg = "Port is off: Voltage injection into the port."},
+ {.id = 0x25, .msg = "Port is off: Improper Capacitor Detection"},
+ {.id = 0x26, .msg = "Port is off: Discharged load."},
+ {.id = 0x34, .msg = "Port is off: Short condition."},
+ {.id = 0x35, .msg = "Port is off: Over temperature at the port."},
+ {.id = 0x36, .msg = "Port is off: Device is too hot."},
+ {.id = 0x37, .msg = "Unknown device port status."},
+ {.id = 0x3C, .msg = "Power Management-Static."},
+ {.id = 0x3D, .msg = "Power Management-Static\u2014OVL."},
+ {.id = 0x41, .msg = "Power denied: Hardware power limit."},
+ {.id = 0x43, .msg = "Port is off: Class error."},
+ {.id = 0x44, .msg = "Port turn off during Host crash."},
+ {.id = 0x45, .msg = "Delivered power port was forced to be shut down at host crash."},
+ {.id = 0x46, .msg = "An enabled port was forced to be shut down at Host crash."},
+ {.id = 0x47, .msg = "Force Power Crash Error."},
+ {.id = 0x48, .msg = "Port is off: Recovery UDL."},
+ {.id = 0x49, .msg = "Port is off: Recovery PG Event."},
+ {.id = 0x4A, .msg = "Port is off: Recovery OVL."},
+ {.id = 0x4B, .msg = "Port is off: Recovery SC."},
+ {.id = 0x4C, .msg = "Port is off: Recovery Voltage injection."},
+ {.id = 0x80, .msg = "2P Port delivering non-IEEE."},
+ {.id = 0x81, .msg = "2P Port delivering IEEE."},
+ {.id = 0x82, .msg = "4P Port that deliver only 2 Pair non-IEEE."},
+ {.id = 0x83, .msg = "4P Port delivering 2P non-IEEE."},
+ {.id = 0x84, .msg = "4P Port delivering 4P non-IEEE."},
+ {.id = 0x85, .msg = "4P Port delivering 2P IEEE SSPD."},
+ {.id = 0x86, .msg = "4P Port delivering 4P IEEE SSPD."},
+ {.id = 0x87, .msg = "4P Port delivering 2P IEEE DSPD in the first phase."},
+ {.id = 0x88, .msg = "4P Port delivering 2P IEEE DSPD."},
+ {.id = 0x89, .msg = "4P Port delivering 4P IEEE DSPD."},
+ {.id = 0x90, .msg = "Force Power BT 2P."},
+ {.id = 0x91, .msg = "Force Power BT 4P."},
+ {.id = 0xA0, .msg = "Force Power BT error."},
+ {.id = 0xA7, .msg = "Connection Check error."},
+ {.id = 0xA8, .msg = "Open Port is not connected."},
+ { /* sentinel */ }
+};
+
+static const char *pd692x0_get_status_msg(int id)
+{
+ const struct pd692x0_status_msg *msg_list;
+
+ msg_list = pd692x0_status_msg_list;
+ while (msg_list->id) {
+ if (msg_list->id == id)
+ return msg_list->msg;
+
+ msg_list++;
+ }
+
+ return NULL;
+}
+
static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
unsigned long id,
struct netlink_ext_ack *extack,
@@ -442,6 +522,7 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
{
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
struct pd692x0_msg msg, buf = {0};
+ u32 class;
int ret;

ret = pd692x0_fw_unavailable(priv);
@@ -471,6 +552,21 @@ static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,

priv->admin_state[id] = status->c33_admin_state;

+ status->c33_pw_status_msg = pd692x0_get_status_msg(buf.sub[0]);
+
+ status->c33_actual_pw = (buf.data[0] << 4 | buf.data[1]) * 100;
+
+ 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);
+ if (ret < 0)
+ return ret;
+
+ class = buf.data[3] >> 4;
+ if (class <= 8)
+ status->c33_pw_class = class;
+
return 0;
}


--
2.34.1


2024-05-29 14:23:10

by Kory Maincent

[permalink] [raw]
Subject: [PATCH 5/8] net: pse-pd: Add new power limit get and set c33 features

From: "Kory Maincent (Dent Project)" <[email protected]>

This patch add a way to get and set the power limit of a PSE PI.
For that it uses regulator API callbacks wrapper like get_voltage() and
get/set_current_limit() as power is simply V * I.
We used mW unit as defined by the IEEE 802.3-2022 standards.

set_current_limit() uses the voltage return by get_voltage() and the desired
power limit to calculate the current limit. get_voltage() callback is then
mandatory to set the power limit.

get_current_limit() callback is by default looking at a driver callback
and fallback to extracting the current limit from _pse_ethtool_get_status()
if the driver does not set its callback. We prefer let the user the choice
because ethtool_get_status return much more information than the current
limit.

Signed-off-by: Kory Maincent <[email protected]>
---
drivers/net/pse-pd/pse_core.c | 169 +++++++++++++++++++++++++++++++++++++++---
include/linux/pse-pd/pse.h | 36 +++++++++
2 files changed, 194 insertions(+), 11 deletions(-)

diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 795ab264eaf2..d0f92e225cef 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -265,10 +265,110 @@ static int pse_pi_disable(struct regulator_dev *rdev)
return ret;
}

+static int _pse_pi_get_voltage(struct regulator_dev *rdev)
+{
+ struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
+ const struct pse_controller_ops *ops;
+ int id, ret;
+
+ ops = pcdev->ops;
+ if (!ops->pi_get_voltage)
+ return -EOPNOTSUPP;
+
+ id = rdev_get_id(rdev);
+ ret = ops->pi_get_voltage(pcdev, id);
+ if (ret > 0)
+ ret *= 1000;
+
+ return ret;
+}
+
+static int pse_pi_get_voltage(struct regulator_dev *rdev)
+{
+ struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
+ int ret;
+
+ mutex_lock(&pcdev->lock);
+ ret = _pse_pi_get_voltage(rdev);
+ mutex_unlock(&pcdev->lock);
+
+ 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, mV, ret;
+
+ ops = pcdev->ops;
+ id = rdev_get_id(rdev);
+ mutex_lock(&pcdev->lock);
+ if (ops->pi_get_current_limit) {
+ ret = ops->pi_get_current_limit(pcdev, id);
+ goto out;
+ }
+
+ /* 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);
+ if (!ret) {
+ dev_err(pcdev->dev, "Voltage null\n");
+ ret = -ERANGE;
+ goto out;
+ }
+ if (ret < 0)
+ goto out;
+ mV = ret;
+
+ ret = _pse_ethtool_get_status(pcdev, id, &extack, &st);
+ if (ret)
+ goto out;
+
+ if (st.c33_pw_limit)
+ /* mA = mW * 1000 / mV */
+ ret = st.c33_pw_limit * 1000 / mV;
+
+out:
+ mutex_unlock(&pcdev->lock);
+ return ret;
+}
+
+static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
+ int max_uA)
+{
+ struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
+ const struct pse_controller_ops *ops;
+ int id, ret;
+
+ ops = pcdev->ops;
+ if (!ops->pi_set_current_limit)
+ return -EOPNOTSUPP;
+
+ id = rdev_get_id(rdev);
+ mutex_lock(&pcdev->lock);
+ ret = ops->pi_set_current_limit(pcdev, id, max_uA / 1000);
+ mutex_unlock(&pcdev->lock);
+
+ return ret;
+}
+
static const struct regulator_ops pse_pi_ops = {
.is_enabled = pse_pi_is_enabled,
.enable = pse_pi_enable,
.disable = pse_pi_disable,
+ .get_voltage = pse_pi_get_voltage,
+ .get_current_limit = pse_pi_get_current_limit,
+ .set_current_limit = pse_pi_set_current_limit,
};

static int
@@ -298,7 +398,9 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
rdesc->ops = &pse_pi_ops;
rdesc->owner = pcdev->owner;

- rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
+ rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_CURRENT;
+ rinit_data->constraints.max_uA = MAX_PI_CURRENT * 1000;
rinit_data->supply_regulator = "vpwr";

rconfig.dev = pcdev->dev;
@@ -626,6 +728,23 @@ 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
@@ -638,19 +757,10 @@ 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;
int err;

- ops = psec->pcdev->ops;
-
- if (!ops->ethtool_get_status) {
- NL_SET_ERR_MSG(extack,
- "PSE driver does not support status report");
- return -EOPNOTSUPP;
- }
-
mutex_lock(&psec->pcdev->lock);
- err = ops->ethtool_get_status(psec->pcdev, psec->id, extack, status);
+ err = _pse_ethtool_get_status(psec->pcdev, psec->id, extack, status);
mutex_unlock(&psec->pcdev->lock);

return err;
@@ -732,6 +842,43 @@ int pse_ethtool_set_config(struct pse_control *psec,
}
EXPORT_SYMBOL_GPL(pse_ethtool_set_config);

+/**
+ * pse_ethtool_set_pw_limit - set PSE control power limit
+ * @psec: PSE control pointer
+ * @extack: extack for reporting useful error messages
+ * @pw_limit: power limit value in mW
+ *
+ * Return: 0 on success and failure value on error
+ */
+int pse_ethtool_set_pw_limit(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ const unsigned int pw_limit)
+{
+ int uV, mA, ret;
+
+ ret = regulator_get_voltage(psec->ps);
+ if (!ret) {
+ NL_SET_ERR_MSG(extack,
+ "Can't read current voltage");
+ return ret;
+ }
+ if (ret < 0) {
+ NL_SET_ERR_MSG(extack,
+ "Error reading current voltage");
+ return ret;
+ }
+ uV = ret;
+
+ /* mA = mW * 1000 / ( uV / 1000)
+ * mA precision is sufficient for PSE, and mW is the power unit
+ * used in IEEE 802.3-2022 145 standard.
+ */
+ mA = pw_limit * 1000 / (uV / 1000);
+
+ return regulator_set_current_limit(psec->ps, 0, mA * 1000);
+}
+EXPORT_SYMBOL_GPL(pse_ethtool_set_pw_limit);
+
bool pse_has_podl(struct pse_control *psec)
{
return psec->pcdev->types & ETHTOOL_PSE_PODL;
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 04219ca20d60..241b43c65137 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -9,6 +9,9 @@
#include <linux/list.h>
#include <uapi/linux/ethtool.h>

+/* Maximum current in mA according to IEEE 802.3-2022 Table 145-1 */
+#define MAX_PI_CURRENT 1920
+
struct phy_device;
struct pse_controller_dev;

@@ -41,6 +44,7 @@ struct pse_control_config {
* @c33_actual_pw: power currently delivered by the PSE in mW
* IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
* @c33_pw_status_msg: detailed power detection status of the PSE
+ * @c33_pw_limit: power limit of the PSE
*/
struct pse_control_status {
enum ethtool_podl_pse_admin_state podl_admin_state;
@@ -50,6 +54,7 @@ struct pse_control_status {
u32 c33_pw_class;
u32 c33_actual_pw;
const char *c33_pw_status_msg;
+ u32 c33_pw_limit;
};

/**
@@ -61,6 +66,14 @@ struct pse_control_status {
* 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 but in mV unit.
+ * @pi_get_current_limit: Get the configured current limit similarly to
+ * get_current_limit regulator callback but in mA
+ * unit.
+ * @pi_set_current_limit: Configure the current limit similarly to
+ * set_current_limit regulator callback but in mA
+ * unit.
*/
struct pse_controller_ops {
int (*ethtool_get_status)(struct pse_controller_dev *pcdev,
@@ -70,6 +83,11 @@ struct pse_controller_ops {
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);
+ 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_mA);
};

struct module;
@@ -156,6 +174,11 @@ int pse_ethtool_get_status(struct pse_control *psec,
int pse_ethtool_set_config(struct pse_control *psec,
struct netlink_ext_ack *extack,
const struct pse_control_config *config);
+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);
@@ -185,6 +208,19 @@ static inline int pse_ethtool_set_config(struct pse_control *psec,
return -EOPNOTSUPP;
}

+static inline int pse_ethtool_set_pw_limit(struct pse_control *psec,
+ struct netlink_ext_ack *extack,
+ const unsigned int pw_limit)
+{
+ 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


2024-05-29 23:14:30

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH 4/8] net: pse-pd: pd692x0: Expand ethtool status message

> +static const struct pd692x0_status_msg pd692x0_status_msg_list[] = {
> + {.id = 0x06, .msg = "Port is off: Main supply voltage is high."},
> + {.id = 0x07, .msg = "Port is off: Main supply voltage is low."},
> + {.id = 0x08, .msg = "Port is off: Disable all ports pin is active."},
> + {.id = 0x0C, .msg = "Port is off: Non-existing port number."},
> + {.id = 0x11, .msg = "Port is yet undefined."},
> + {.id = 0x12, .msg = "Port is off: Internal hardware fault."},
> + {.id = 0x1A, .msg = "Port is off: User setting."},
> + {.id = 0x1B, .msg = "Port is off: Detection is in process."},
> + {.id = 0x1C, .msg = "Port is off: Non-802.3AF/AT powered device."},
> + {.id = 0x1E, .msg = "Port is off: Underload state."},
> + {.id = 0x1F, .msg = "Port is off: Overload state."},
> + {.id = 0x20, .msg = "Port is off: Power budget exceeded."},
> + {.id = 0x21, .msg = "Port is off: Internal hardware routing error."},
> + {.id = 0x22, .msg = "Port is off: Configuration change."},
> + {.id = 0x24, .msg = "Port is off: Voltage injection into the port."},
> + {.id = 0x25, .msg = "Port is off: Improper Capacitor Detection"},
> + {.id = 0x26, .msg = "Port is off: Discharged load."},

I don't know of any other driver returning strings like this. Have you
seen any other PSE driver with anything similar?

> + {.id = 0x34, .msg = "Port is off: Short condition."},
> + {.id = 0x35, .msg = "Port is off: Over temperature at the port."},
> + {.id = 0x36, .msg = "Port is off: Device is too hot."},
> + {.id = 0x37, .msg = "Unknown device port status."},
> + {.id = 0x3C, .msg = "Power Management-Static."},
> + {.id = 0x3D, .msg = "Power Management-Static\u2014OVL."},

Is there something going on with UTF here? the \u2014 ?

Andrew

2024-05-30 09:34:02

by Kory Maincent

[permalink] [raw]
Subject: Re: [PATCH 4/8] net: pse-pd: pd692x0: Expand ethtool status message

Thanks for the review!

On Thu, 30 May 2024 01:13:59 +0200
Andrew Lunn <[email protected]> wrote:

> > +static const struct pd692x0_status_msg pd692x0_status_msg_list[] = {
> > + {.id = 0x06, .msg = "Port is off: Main supply voltage is high."},
> > + {.id = 0x07, .msg = "Port is off: Main supply voltage is low."},
> > + {.id = 0x08, .msg = "Port is off: Disable all ports pin is
> > active."},
> > + {.id = 0x0C, .msg = "Port is off: Non-existing port number."},
> > + {.id = 0x11, .msg = "Port is yet undefined."},
> > + {.id = 0x12, .msg = "Port is off: Internal hardware fault."},
> > + {.id = 0x1A, .msg = "Port is off: User setting."},
> > + {.id = 0x1B, .msg = "Port is off: Detection is in process."},
> > + {.id = 0x1C, .msg = "Port is off: Non-802.3AF/AT powered device."},
> > + {.id = 0x1E, .msg = "Port is off: Underload state."},
> > + {.id = 0x1F, .msg = "Port is off: Overload state."},
> > + {.id = 0x20, .msg = "Port is off: Power budget exceeded."},
> > + {.id = 0x21, .msg = "Port is off: Internal hardware routing
> > error."},
> > + {.id = 0x22, .msg = "Port is off: Configuration change."},
> > + {.id = 0x24, .msg = "Port is off: Voltage injection into the
> > port."},
> > + {.id = 0x25, .msg = "Port is off: Improper Capacitor Detection"},
> > + {.id = 0x26, .msg = "Port is off: Discharged load."},
>
> I don't know of any other driver returning strings like this. Have you
> seen any other PSE driver with anything similar?

We would like to be able to return the failure reason but there is nothing
generic in the IEEE 802.3 standard to be able to add it to the UAPI.
The TI controller has SUPPLY and FAULT EVENT Register which could report few
messages. I am not aware of other PoE controller and how they deal with it.
We could add sysfs for reporting the status messages for all the ports but I
don't think it is a better idea.

> > + {.id = 0x34, .msg = "Port is off: Short condition."},
> > + {.id = 0x35, .msg = "Port is off: Over temperature at the port."},
> > + {.id = 0x36, .msg = "Port is off: Device is too hot."},
> > + {.id = 0x37, .msg = "Unknown device port status."},
> > + {.id = 0x3C, .msg = "Power Management-Static."},
> > + {.id = 0x3D, .msg = "Power Management-Static\u2014OVL."},
>
> Is there something going on with UTF here? the \u2014 ?

Some copy paste of the messages bring a non utf-8 character :/
Will fix it, thanks for spotting it.

Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com

2024-05-30 10:14:12

by Oleksij Rempel

[permalink] [raw]
Subject: Re: [PATCH 4/8] net: pse-pd: pd692x0: Expand ethtool status message

Hi,

On Thu, May 30, 2024 at 11:33:41AM +0200, Kory Maincent wrote:
> Thanks for the review!
>
> On Thu, 30 May 2024 01:13:59 +0200
> Andrew Lunn <[email protected]> wrote:
>
> > > +static const struct pd692x0_status_msg pd692x0_status_msg_list[] = {
> > > + {.id = 0x06, .msg = "Port is off: Main supply voltage is high."},
> > > + {.id = 0x07, .msg = "Port is off: Main supply voltage is low."},
> > > + {.id = 0x08, .msg = "Port is off: Disable all ports pin is
> > > active."},
> > > + {.id = 0x0C, .msg = "Port is off: Non-existing port number."},
> > > + {.id = 0x11, .msg = "Port is yet undefined."},
> > > + {.id = 0x12, .msg = "Port is off: Internal hardware fault."},
> > > + {.id = 0x1A, .msg = "Port is off: User setting."},
> > > + {.id = 0x1B, .msg = "Port is off: Detection is in process."},
> > > + {.id = 0x1C, .msg = "Port is off: Non-802.3AF/AT powered device."},
> > > + {.id = 0x1E, .msg = "Port is off: Underload state."},
> > > + {.id = 0x1F, .msg = "Port is off: Overload state."},
> > > + {.id = 0x20, .msg = "Port is off: Power budget exceeded."},
> > > + {.id = 0x21, .msg = "Port is off: Internal hardware routing
> > > error."},
> > > + {.id = 0x22, .msg = "Port is off: Configuration change."},
> > > + {.id = 0x24, .msg = "Port is off: Voltage injection into the
> > > port."},
> > > + {.id = 0x25, .msg = "Port is off: Improper Capacitor Detection"},
> > > + {.id = 0x26, .msg = "Port is off: Discharged load."},
> >
> > I don't know of any other driver returning strings like this. Have you
> > seen any other PSE driver with anything similar?
>
> We would like to be able to return the failure reason but there is nothing
> generic in the IEEE 802.3 standard to be able to add it to the UAPI.
> The TI controller has SUPPLY and FAULT EVENT Register which could report few
> messages. I am not aware of other PoE controller and how they deal with it.
> We could add sysfs for reporting the status messages for all the ports but I
> don't think it is a better idea.

We have ETHTOOL_LINK_EXT_STATE* and THTOOL_LINK_EXT_SUBSTATE_ for
different kind of link fail diagnostic. I think it would be good to make
the same for PSE ports. Not all of them will overlap with other PSE
controllers, but we will have one unified diagnostic interface. It will
be easier for user space application to parse and react on it.

--
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 |