Skip to content

Commit

Permalink
net: ethtool: Add new power limit get and set features
Browse files Browse the repository at this point in the history
This patch expands the status information provided by ethtool for PSE c33
with available power limit and available power limit ranges. It also adds
a call to pse_ethtool_set_pw_limit() to configure the PSE control power
limit.

Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Link: https://patch.msgid.link/20240704-feature_poe_power_cap-v6-5-320003204264@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
kmaincent authored and kuba-moo committed Jul 6, 2024
1 parent 4a83abc commit 30d7b67
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 25 deletions.
64 changes: 46 additions & 18 deletions Documentation/networking/ethtool-netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1730,24 +1730,28 @@ Request contents:

Kernel response contents:

====================================== ====== =============================
``ETHTOOL_A_PSE_HEADER`` nested reply header
``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` u32 Operational state of the PoDL
PSE functions
``ETHTOOL_A_PODL_PSE_PW_D_STATUS`` u32 power detection status of the
PoDL PSE.
``ETHTOOL_A_C33_PSE_ADMIN_STATE`` u32 Operational state of the PoE
PSE functions.
``ETHTOOL_A_C33_PSE_PW_D_STATUS`` u32 power detection status of the
PoE PSE.
``ETHTOOL_A_C33_PSE_PW_CLASS`` u32 power class of the PoE PSE.
``ETHTOOL_A_C33_PSE_ACTUAL_PW`` u32 actual power drawn on the
PoE PSE.
``ETHTOOL_A_C33_PSE_EXT_STATE`` u32 power extended state of the
PoE PSE.
``ETHTOOL_A_C33_PSE_EXT_SUBSTATE`` u32 power extended substatus of
the PoE PSE.
====================================== ====== =============================
========================================== ====== =============================
``ETHTOOL_A_PSE_HEADER`` nested reply header
``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` u32 Operational state of the PoDL
PSE functions
``ETHTOOL_A_PODL_PSE_PW_D_STATUS`` u32 power detection status of the
PoDL PSE.
``ETHTOOL_A_C33_PSE_ADMIN_STATE`` u32 Operational state of the PoE
PSE functions.
``ETHTOOL_A_C33_PSE_PW_D_STATUS`` u32 power detection status of the
PoE PSE.
``ETHTOOL_A_C33_PSE_PW_CLASS`` u32 power class of the PoE PSE.
``ETHTOOL_A_C33_PSE_ACTUAL_PW`` u32 actual power drawn on the
PoE PSE.
``ETHTOOL_A_C33_PSE_EXT_STATE`` u32 power extended state of the
PoE PSE.
``ETHTOOL_A_C33_PSE_EXT_SUBSTATE`` u32 power extended substatus of
the PoE PSE.
``ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT`` u32 currently configured power
limit of the PoE PSE.
``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested Supported power limit
configuration ranges.
========================================== ====== =============================

When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
the operational state of the PoDL PSE functions. The operational state of the
Expand Down Expand Up @@ -1809,6 +1813,16 @@ Possible values are:
ethtool_c33_pse_ext_substate_power_not_available
ethtool_c33_pse_ext_substate_short_detected

When set, the optional ``ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT`` attribute
identifies the C33 PSE power limit in mW.

When set the optional ``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested attribute
identifies the C33 PSE power limit ranges through
``ETHTOOL_A_C33_PSE_PWR_VAL_LIMIT_RANGE_MIN`` and
``ETHTOOL_A_C33_PSE_PWR_VAL_LIMIT_RANGE_MAX``.
If the controller works with fixed classes, the min and max values will be
equal.

PSE_SET
=======

Expand All @@ -1820,6 +1834,8 @@ Request contents:
``ETHTOOL_A_PSE_HEADER`` nested request header
``ETHTOOL_A_PODL_PSE_ADMIN_CONTROL`` u32 Control PoDL PSE Admin state
``ETHTOOL_A_C33_PSE_ADMIN_CONTROL`` u32 Control PSE Admin state
``ETHTOOL_A_C33_PSE_AVAIL_PWR_LIMIT`` u32 Control PoE PSE available
power limit
====================================== ====== =============================

When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_CONTROL`` attribute is used
Expand All @@ -1830,6 +1846,18 @@ to control PoDL PSE Admin functions. This option is implementing
The same goes for ``ETHTOOL_A_C33_PSE_ADMIN_CONTROL`` implementing
``IEEE 802.3-2022`` 30.9.1.2.1 acPSEAdminControl.

When set, the optional ``ETHTOOL_A_C33_PSE_AVAIL_PWR_LIMIT`` attribute is
used to control the available power value limit for C33 PSE in milliwatts.
This attribute corresponds to the `pse_available_power` variable described in
``IEEE 802.3-2022`` 33.2.4.4 Variables and `pse_avail_pwr` in 145.2.5.4
Variables, which are described in power classes.

It was decided to use milliwatts for this interface to unify it with other
power monitoring interfaces, which also use milliwatts, and to align with
various existing products that document power consumption in watts rather than
classes. If power limit configuration based on classes is needed, the
conversion can be done in user space, for example by ethtool.

RSS_GET
=======

Expand Down
5 changes: 5 additions & 0 deletions include/linux/ethtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -1288,4 +1288,9 @@ struct ethtool_c33_pse_ext_state_info {
u32 __c33_pse_ext_substate;
};
};

struct ethtool_c33_pse_pw_limit_range {
u32 min;
u32 max;
};
#endif /* _LINUX_ETHTOOL_H */
8 changes: 8 additions & 0 deletions include/uapi/linux/ethtool_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,12 @@ enum {
};

/* Power Sourcing Equipment */
enum {
ETHTOOL_A_C33_PSE_PW_LIMIT_UNSPEC,
ETHTOOL_A_C33_PSE_PW_LIMIT_MIN, /* u32 */
ETHTOOL_A_C33_PSE_PW_LIMIT_MAX, /* u32 */
};

enum {
ETHTOOL_A_PSE_UNSPEC,
ETHTOOL_A_PSE_HEADER, /* nest - _A_HEADER_* */
Expand All @@ -943,6 +949,8 @@ enum {
ETHTOOL_A_C33_PSE_ACTUAL_PW, /* u32 */
ETHTOOL_A_C33_PSE_EXT_STATE, /* u32 */
ETHTOOL_A_C33_PSE_EXT_SUBSTATE, /* u32 */
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT, /* u32 */
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES, /* nest - _C33_PSE_PW_LIMIT_* */

/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
Expand Down
89 changes: 82 additions & 7 deletions net/ethtool/pse-pd.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,46 @@ static int pse_reply_size(const struct ethnl_req_info *req_base,
/* _C33_PSE_EXT_SUBSTATE */
len += nla_total_size(sizeof(u32));
}
if (st->c33_avail_pw_limit > 0)
/* _C33_AVAIL_PSE_PW_LIMIT */
len += nla_total_size(sizeof(u32));
if (st->c33_pw_limit_nb_ranges > 0)
/* _C33_PSE_PW_LIMIT_RANGES */
len += st->c33_pw_limit_nb_ranges *
(nla_total_size(0) +
nla_total_size(sizeof(u32)) * 2);

return len;
}

static int pse_put_pw_limit_ranges(struct sk_buff *skb,
const struct pse_control_status *st)
{
const struct ethtool_c33_pse_pw_limit_range *pw_limit_ranges;
int i;

pw_limit_ranges = st->c33_pw_limit_ranges;
for (i = 0; i < st->c33_pw_limit_nb_ranges; i++) {
struct nlattr *nest;

nest = nla_nest_start(skb, ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES);
if (!nest)
return -EMSGSIZE;

if (nla_put_u32(skb, ETHTOOL_A_C33_PSE_PW_LIMIT_MIN,
pw_limit_ranges->min) ||
nla_put_u32(skb, ETHTOOL_A_C33_PSE_PW_LIMIT_MAX,
pw_limit_ranges->max)) {
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
nla_nest_end(skb, nest);
pw_limit_ranges++;
}

return 0;
}

static int pse_fill_reply(struct sk_buff *skb,
const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
Expand Down Expand Up @@ -147,9 +184,25 @@ static int pse_fill_reply(struct sk_buff *skb,
return -EMSGSIZE;
}

if (st->c33_avail_pw_limit > 0 &&
nla_put_u32(skb, ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT,
st->c33_avail_pw_limit))
return -EMSGSIZE;

if (st->c33_pw_limit_nb_ranges > 0 &&
pse_put_pw_limit_ranges(skb, st))
return -EMSGSIZE;

return 0;
}

static void pse_cleanup_data(struct ethnl_reply_data *reply_base)
{
const struct pse_reply_data *data = PSE_REPDATA(reply_base);

kfree(data->status.c33_pw_limit_ranges);
}

/* PSE_SET */

const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1] = {
Expand All @@ -160,6 +213,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_AVAIL_PW_LIMIT] = { .type = NLA_U32 },
};

static int
Expand Down Expand Up @@ -202,19 +256,39 @@ 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_AVAIL_PW_LIMIT]) {
unsigned int pw_limit;

pw_limit = nla_get_u32(tb[ETHTOOL_A_C33_PSE_AVAIL_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 = {
Expand All @@ -227,6 +301,7 @@ const struct ethnl_request_ops ethnl_pse_request_ops = {
.prepare_data = pse_prepare_data,
.reply_size = pse_reply_size,
.fill_reply = pse_fill_reply,
.cleanup_data = pse_cleanup_data,

.set_validate = ethnl_set_pse_validate,
.set = ethnl_set_pse,
Expand Down

0 comments on commit 30d7b67

Please sign in to comment.