2022-12-05 01:48:54

by Piergiorgio Beruto

[permalink] [raw]
Subject: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

Add support for configuring the PLCA Reconciliation Sublayer on
multi-drop PHYs that support IEEE802.3cg-2019 Clause 148 (e.g.,
10BASE-T1S). This patch adds the appropriate netlink interface
to ethtool.

Signed-off-by: Piergiorgio Beruto <[email protected]>
---
MAINTAINERS | 6 +
drivers/net/phy/phy.c | 34 ++++
drivers/net/phy/phy_device.c | 3 +
include/linux/ethtool.h | 11 +
include/linux/phy.h | 64 ++++++
include/uapi/linux/ethtool_netlink.h | 25 +++
net/ethtool/Makefile | 2 +-
net/ethtool/netlink.c | 30 +++
net/ethtool/netlink.h | 6 +
net/ethtool/plca.c | 290 +++++++++++++++++++++++++++
10 files changed, 470 insertions(+), 1 deletion(-)
create mode 100644 net/ethtool/plca.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 955c1be1efb2..7952243e4b43 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16396,6 +16396,12 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
F: drivers/iio/chemical/pms7003.c

+PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148)
+M: Piergiorgio Beruto <[email protected]>
+L: [email protected]
+S: Maintained
+F: net/ethtool/plca.c
+
PLDMFW LIBRARY
M: Jacob Keller <[email protected]>
S: Maintained
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e5b6cb1a77f9..99e3497b6aa1 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -543,6 +543,40 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
}
EXPORT_SYMBOL(phy_ethtool_get_stats);

+/**
+ *
+ */
+int phy_ethtool_get_plca_cfg(struct phy_device *dev,
+ struct phy_plca_cfg *plca_cfg)
+{
+ // TODO
+ return 0;
+}
+EXPORT_SYMBOL(phy_ethtool_get_plca_cfg);
+
+/**
+ *
+ */
+int phy_ethtool_set_plca_cfg(struct phy_device *dev,
+ struct netlink_ext_ack *extack,
+ const struct phy_plca_cfg *plca_cfg)
+{
+ // TODO
+ return 0;
+}
+EXPORT_SYMBOL(phy_ethtool_set_plca_cfg);
+
+/**
+ *
+ */
+int phy_ethtool_get_plca_status(struct phy_device *dev,
+ struct phy_plca_status *plca_st)
+{
+ // TODO
+ return 0;
+}
+EXPORT_SYMBOL(phy_ethtool_get_plca_status);
+
/**
* phy_start_cable_test - Start a cable test
*
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 716870a4499c..f248010c403d 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3262,6 +3262,9 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
.get_sset_count = phy_ethtool_get_sset_count,
.get_strings = phy_ethtool_get_strings,
.get_stats = phy_ethtool_get_stats,
+ .get_plca_cfg = phy_ethtool_get_plca_cfg,
+ .set_plca_cfg = phy_ethtool_set_plca_cfg,
+ .get_plca_status = phy_ethtool_get_plca_status,
.start_cable_test = phy_start_cable_test,
.start_cable_test_tdr = phy_start_cable_test_tdr,
};
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 9e0a76fc7de9..4bfe95ec1f0a 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -802,12 +802,16 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev,

struct phy_device;
struct phy_tdr_config;
+struct phy_plca_cfg;
+struct phy_plca_status;

/**
* struct ethtool_phy_ops - Optional PHY device options
* @get_sset_count: Get number of strings that @get_strings will write.
* @get_strings: Return a set of strings that describe the requested objects
* @get_stats: Return extended statistics about the PHY device.
+ * @get_plca_cfg: Return PLCA configuration.
+ * @set_plca_cfg: Set PLCA configuration.
* @start_cable_test: Start a cable test
* @start_cable_test_tdr: Start a Time Domain Reflectometry cable test
*
@@ -819,6 +823,13 @@ struct ethtool_phy_ops {
int (*get_strings)(struct phy_device *dev, u8 *data);
int (*get_stats)(struct phy_device *dev,
struct ethtool_stats *stats, u64 *data);
+ int (*get_plca_cfg)(struct phy_device *dev,
+ struct phy_plca_cfg *plca_cfg);
+ int (*set_plca_cfg)(struct phy_device *dev,
+ struct netlink_ext_ack *extack,
+ const struct phy_plca_cfg *plca_cfg);
+ int (*get_plca_status)(struct phy_device *dev,
+ struct phy_plca_status *plca_st);
int (*start_cable_test)(struct phy_device *phydev,
struct netlink_ext_ack *extack);
int (*start_cable_test_tdr)(struct phy_device *phydev,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 71eeb4e3b1fd..ab2c134d0a05 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -765,6 +765,63 @@ struct phy_tdr_config {
};
#define PHY_PAIR_ALL -1

+/**
+ * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
+ * Avoidance) Reconciliation Sublayer.
+ *
+ * @version: read-only PLCA register map version. 0 = not available. Ignored
+ * when setting the configuration. Format is the same as reported by the PLCA
+ * IDVER register (31.CA00). -1 = not available.
+ * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't
+ * set. 0 = disabled, anything else = enabled.
+ * @node_id: the PLCA local node identifier. -1 = not available / don't set.
+ * Allowed values [0 .. 254]. 255 = node disabled.
+ * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only
+ * meaningful for the coordinator (node_id = 0). -1 = not available / don't
+ * set. Allowed values [0 .. 255].
+ * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the
+ * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for
+ * more details. The to_timer shall be set equal over all nodes.
+ * -1 = not available / don't set. Allowed values [0 .. 255].
+ * @burst_cnt: controls how many additional frames a node is allowed to send in
+ * single transmit opportunity (TO). The default value of 0 means that the
+ * node is allowed exactly one frame per TO. A value of 1 allows two frames
+ * per TO, and so on. -1 = not available / don't set.
+ * Allowed values [0 .. 255].
+ * @burst_tmr: controls how many bit times to wait for the MAC to send a new
+ * frame before interrupting the burst. This value should be set to a value
+ * greater than the MAC inter-packet gap (which is typically 96 bits).
+ * -1 = not available / don't set. Allowed values [0 .. 255].
+ *
+ * A structure containing configuration parameters for setting/getting the PLCA
+ * RS configuration. The driver does not need to implement all the parameters,
+ * but should report what is actually used.
+ */
+struct phy_plca_cfg {
+ s32 version;
+ s16 enabled;
+ s16 node_id;
+ s16 node_cnt;
+ s16 to_tmr;
+ s16 burst_cnt;
+ s16 burst_tmr;
+};
+
+/**
+ * struct phy_plca_status - Status of the PLCA (Physical Layer Collision
+ * Avoidance) Reconciliation Sublayer.
+ *
+ * @pst: The PLCA status as reported by the PST bit in the PLCA STATUS
+ * register(31.CA03), indicating BEACON activity.
+ *
+ * A structure containing status information of the PLCA RS configuration.
+ * The driver does not need to implement all the parameters, but should report
+ * what is actually used.
+ */
+struct phy_plca_status {
+ bool pst;
+};
+
/**
* struct phy_driver - Driver structure for a particular PHY type
*
@@ -1775,6 +1832,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
int phy_ethtool_get_sset_count(struct phy_device *phydev);
int phy_ethtool_get_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data);
+int phy_ethtool_get_plca_cfg(struct phy_device *dev,
+ struct phy_plca_cfg *plca_cfg);
+int phy_ethtool_set_plca_cfg(struct phy_device *dev,
+ struct netlink_ext_ack *extack,
+ const struct phy_plca_cfg *plca_cfg);
+int phy_ethtool_get_plca_status(struct phy_device *dev,
+ struct phy_plca_status *plca_st);

static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
{
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index aaf7c6963d61..81e3d7b42d0f 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -51,6 +51,9 @@ enum {
ETHTOOL_MSG_MODULE_SET,
ETHTOOL_MSG_PSE_GET,
ETHTOOL_MSG_PSE_SET,
+ ETHTOOL_MSG_PLCA_GET_CFG,
+ ETHTOOL_MSG_PLCA_SET_CFG,
+ ETHTOOL_MSG_PLCA_GET_STATUS,

/* add new constants above here */
__ETHTOOL_MSG_USER_CNT,
@@ -97,6 +100,9 @@ enum {
ETHTOOL_MSG_MODULE_GET_REPLY,
ETHTOOL_MSG_MODULE_NTF,
ETHTOOL_MSG_PSE_GET_REPLY,
+ ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
+ ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
+ ETHTOOL_MSG_PLCA_NTF,

/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
@@ -880,6 +886,25 @@ enum {
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
};

+/* PLCA */
+
+enum {
+ ETHTOOL_A_PLCA_UNSPEC,
+ ETHTOOL_A_PLCA_HEADER, /* nest - _A_HEADER_* */
+ ETHTOOL_A_PLCA_VERSION, /* u16 */
+ ETHTOOL_A_PLCA_ENABLED, /* u8 */
+ ETHTOOL_A_PLCA_STATUS, /* u8 */
+ ETHTOOL_A_PLCA_NODE_CNT, /* u8 */
+ ETHTOOL_A_PLCA_NODE_ID, /* u8 */
+ ETHTOOL_A_PLCA_TO_TMR, /* u8 */
+ ETHTOOL_A_PLCA_BURST_CNT, /* u8 */
+ ETHTOOL_A_PLCA_BURST_TMR, /* u8 */
+
+ /* add new constants above here */
+ __ETHTOOL_A_PLCA_CNT,
+ ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 72ab0944262a..b18930e2ce9a 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \
linkstate.o debug.o wol.o features.o privflags.o rings.o \
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \
- pse-pd.o
+ pse-pd.o plca.o
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1a4c11356c96..eb044f48cb24 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -287,6 +287,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
[ETHTOOL_MSG_PHC_VCLOCKS_GET] = &ethnl_phc_vclocks_request_ops,
[ETHTOOL_MSG_MODULE_GET] = &ethnl_module_request_ops,
[ETHTOOL_MSG_PSE_GET] = &ethnl_pse_request_ops,
+ [ETHTOOL_MSG_PLCA_GET_CFG] = &ethnl_plca_cfg_request_ops,
+ [ETHTOOL_MSG_PLCA_GET_STATUS] = &ethnl_plca_status_request_ops,
};

static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -602,6 +604,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
[ETHTOOL_MSG_EEE_NTF] = &ethnl_eee_request_ops,
[ETHTOOL_MSG_FEC_NTF] = &ethnl_fec_request_ops,
[ETHTOOL_MSG_MODULE_NTF] = &ethnl_module_request_ops,
+ [ETHTOOL_MSG_PLCA_NTF] = &ethnl_plca_cfg_request_ops,
};

/* default notification handler */
@@ -695,6 +698,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
[ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify,
[ETHTOOL_MSG_FEC_NTF] = ethnl_default_notify,
[ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify,
+ [ETHTOOL_MSG_PLCA_NTF] = ethnl_default_notify,
};

void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
@@ -1040,6 +1044,32 @@ static const struct genl_ops ethtool_genl_ops[] = {
.policy = ethnl_pse_set_policy,
.maxattr = ARRAY_SIZE(ethnl_pse_set_policy) - 1,
},
+ {
+ .cmd = ETHTOOL_MSG_PLCA_GET_CFG,
+ .doit = ethnl_default_doit,
+ .start = ethnl_default_start,
+ .dumpit = ethnl_default_dumpit,
+ .done = ethnl_default_done,
+ .policy = ethnl_plca_get_cfg_policy,
+ .maxattr = ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1,
+ },
+ {
+ .cmd = ETHTOOL_MSG_PLCA_SET_CFG,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = ethnl_set_plca_cfg,
+ .policy = ethnl_plca_set_cfg_policy,
+ .maxattr = ARRAY_SIZE(ethnl_plca_set_cfg_policy) - 1,
+ },
+ {
+ .cmd = ETHTOOL_MSG_PLCA_GET_STATUS,
+ .doit = ethnl_default_doit,
+ .start = ethnl_default_start,
+ .dumpit = ethnl_default_dumpit,
+ .done = ethnl_default_done,
+ .policy = ethnl_plca_get_status_policy,
+ .maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1,
+ },
+
};

static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 1bfd374f9718..c0ed1a6d0833 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -346,6 +346,8 @@ extern const struct ethnl_request_ops ethnl_stats_request_ops;
extern const struct ethnl_request_ops ethnl_phc_vclocks_request_ops;
extern const struct ethnl_request_ops ethnl_module_request_ops;
extern const struct ethnl_request_ops ethnl_pse_request_ops;
+extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
+extern const struct ethnl_request_ops ethnl_plca_status_request_ops;

extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
@@ -386,6 +388,9 @@ extern const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER +
extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1];
extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1];
extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1];
+extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1];
+extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1];
+extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];

int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
@@ -406,6 +411,7 @@ int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_module(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_pse(struct sk_buff *skb, struct genl_info *info);
+int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info);

extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
diff --git a/net/ethtool/plca.c b/net/ethtool/plca.c
new file mode 100644
index 000000000000..ab50d8b48bd6
--- /dev/null
+++ b/net/ethtool/plca.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/phy.h>
+#include <linux/ethtool_netlink.h>
+
+#include "netlink.h"
+#include "common.h"
+
+struct plca_req_info {
+ struct ethnl_req_info base;
+};
+
+struct plca_reply_data {
+ struct ethnl_reply_data base;
+ struct phy_plca_cfg plca_cfg;
+ struct phy_plca_status plca_st;
+};
+
+#define PLCA_REPDATA(__reply_base) \
+ container_of(__reply_base, struct plca_reply_data, base)
+
+// PLCA get configuration message ------------------------------------------- //
+
+const struct nla_policy ethnl_plca_get_cfg_policy[] = {
+ [ETHTOOL_A_PLCA_HEADER] =
+ NLA_POLICY_NESTED(ethnl_header_policy),
+};
+
+static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
+ struct ethnl_reply_data *reply_base,
+ struct genl_info *info)
+{
+ struct plca_reply_data *data = PLCA_REPDATA(reply_base);
+ struct net_device *dev = reply_base->dev;
+ const struct ethtool_phy_ops *ops;
+ int ret;
+
+ // check that the PHY device is available and connected
+ if (!dev->phydev) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ // note: rtnl_lock is held already by ethnl_default_doit
+ ops = ethtool_phy_ops;
+ if (!ops || !ops->get_plca_cfg) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ ret = ethnl_ops_begin(dev);
+ if (ret < 0)
+ goto out;
+
+ ret = ops->get_plca_cfg(dev->phydev, &data->plca_cfg);
+ if (ret < 0)
+ goto out;
+
+ ethnl_ops_complete(dev);
+
+out:
+ return ret;
+}
+
+static int plca_get_cfg_reply_size(const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ return nla_total_size(sizeof(u16)) + /* _VERSION */
+ nla_total_size(sizeof(u8)) + /* _ENABLED */
+ nla_total_size(sizeof(u8)) + /* _STATUS */
+ nla_total_size(sizeof(u8)) + /* _NODE_CNT */
+ nla_total_size(sizeof(u8)) + /* _NODE_ID */
+ nla_total_size(sizeof(u8)) + /* _TO_TIMER */
+ nla_total_size(sizeof(u8)) + /* _BURST_COUNT */
+ nla_total_size(sizeof(u8)); /* _BURST_TIMER */
+}
+
+static int plca_get_cfg_fill_reply(struct sk_buff *skb,
+ const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ const struct plca_reply_data *data = PLCA_REPDATA(reply_base);
+ const struct phy_plca_cfg *plca = &data->plca_cfg;
+
+ if ((plca->version >= 0 &&
+ nla_put_u16(skb, ETHTOOL_A_PLCA_VERSION, (u16)plca->version)) ||
+ (plca->enabled >= 0 &&
+ nla_put_u8(skb, ETHTOOL_A_PLCA_ENABLED, !!plca->enabled)) ||
+ (plca->node_id >= 0 &&
+ nla_put_u8(skb, ETHTOOL_A_PLCA_NODE_ID, (u8)plca->node_id)) ||
+ (plca->node_cnt >= 0 &&
+ nla_put_u8(skb, ETHTOOL_A_PLCA_NODE_CNT, (u8)plca->node_cnt)) ||
+ (plca->to_tmr >= 0 &&
+ nla_put_u8(skb, ETHTOOL_A_PLCA_TO_TMR, (u8)plca->to_tmr)) ||
+ (plca->burst_cnt >= 0 &&
+ nla_put_u8(skb, ETHTOOL_A_PLCA_BURST_CNT, (u8)plca->burst_cnt)) ||
+ (plca->burst_tmr >= 0 &&
+ nla_put_u8(skb, ETHTOOL_A_PLCA_BURST_TMR, (u8)plca->burst_tmr)))
+ return -EMSGSIZE;
+
+ return 0;
+};
+
+const struct ethnl_request_ops ethnl_plca_cfg_request_ops = {
+ .request_cmd = ETHTOOL_MSG_PLCA_GET_CFG,
+ .reply_cmd = ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
+ .hdr_attr = ETHTOOL_A_PLCA_HEADER,
+ .req_info_size = sizeof(struct plca_req_info),
+ .reply_data_size = sizeof(struct plca_reply_data),
+
+ .prepare_data = plca_get_cfg_prepare_data,
+ .reply_size = plca_get_cfg_reply_size,
+ .fill_reply = plca_get_cfg_fill_reply,
+};
+
+// PLCA set configuration message ------------------------------------------- //
+
+const struct nla_policy ethnl_plca_set_cfg_policy[] = {
+ [ETHTOOL_A_PLCA_HEADER] =
+ NLA_POLICY_NESTED(ethnl_header_policy),
+ [ETHTOOL_A_PLCA_ENABLED] = { .type = NLA_U8 },
+ [ETHTOOL_A_PLCA_NODE_ID] = { .type = NLA_U8 },
+ [ETHTOOL_A_PLCA_NODE_CNT] = { .type = NLA_U8 },
+ [ETHTOOL_A_PLCA_TO_TMR] = { .type = NLA_U8 },
+ [ETHTOOL_A_PLCA_BURST_CNT] = { .type = NLA_U8 },
+ [ETHTOOL_A_PLCA_BURST_TMR] = { .type = NLA_U8 },
+};
+
+int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info)
+{
+ struct ethnl_req_info req_info = {};
+ struct nlattr **tb = info->attrs;
+ const struct ethtool_phy_ops *ops;
+ struct phy_plca_cfg plca_cfg;
+ struct net_device *dev;
+
+ bool mod = false;
+ int ret;
+
+ ret = ethnl_parse_header_dev_get(&req_info,
+ tb[ETHTOOL_A_PLCA_HEADER],
+ genl_info_net(info), info->extack,
+ true);
+ if (ret < 0)
+ return ret;
+
+ dev = req_info.dev;
+
+ // check that the PHY device is available and connected
+ if (!dev->phydev) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+
+ ops = ethtool_phy_ops;
+ if (!ops || !ops->set_plca_cfg) {
+ ret = -EOPNOTSUPP;
+ goto out_rtnl;
+ }
+
+ ret = ethnl_ops_begin(dev);
+ if (ret < 0)
+ goto out_rtnl;
+
+ memset(&plca_cfg, 0xFF, sizeof(plca_cfg));
+
+ if (tb[ETHTOOL_A_PLCA_ENABLED]) {
+ plca_cfg.enabled = !!nla_get_u8(tb[ETHTOOL_A_PLCA_ENABLED]);
+ mod = true;
+ }
+
+ if (tb[ETHTOOL_A_PLCA_NODE_ID]) {
+ plca_cfg.node_id = nla_get_u8(tb[ETHTOOL_A_PLCA_NODE_ID]);
+ mod = true;
+ }
+
+ if (tb[ETHTOOL_A_PLCA_NODE_CNT]) {
+ plca_cfg.node_cnt = nla_get_u8(tb[ETHTOOL_A_PLCA_NODE_CNT]);
+ mod = true;
+ }
+
+ if (tb[ETHTOOL_A_PLCA_TO_TMR]) {
+ plca_cfg.to_tmr = nla_get_u8(tb[ETHTOOL_A_PLCA_TO_TMR]);
+ mod = true;
+ }
+
+ if (tb[ETHTOOL_A_PLCA_BURST_CNT]) {
+ plca_cfg.burst_cnt = nla_get_u8(tb[ETHTOOL_A_PLCA_BURST_CNT]);
+ mod = true;
+ }
+
+ if (tb[ETHTOOL_A_PLCA_BURST_TMR]) {
+ plca_cfg.burst_tmr = nla_get_u8(tb[ETHTOOL_A_PLCA_BURST_TMR]);
+ mod = true;
+ }
+
+ ret = 0;
+ if (!mod)
+ goto out_ops;
+
+ ret = ops->set_plca_cfg(dev->phydev, info->extack, &plca_cfg);
+
+ if (ret < 0)
+ goto out_ops;
+
+ ethtool_notify(dev, ETHTOOL_MSG_PLCA_NTF, NULL);
+
+out_ops:
+ ethnl_ops_complete(dev);
+out_rtnl:
+ rtnl_unlock();
+ ethnl_parse_header_dev_put(&req_info);
+out:
+ return ret;
+}
+
+// PLCA get status message -------------------------------------------------- //
+
+const struct nla_policy ethnl_plca_get_status_policy[] = {
+ [ETHTOOL_A_PLCA_HEADER] =
+ NLA_POLICY_NESTED(ethnl_header_policy),
+};
+
+static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
+ struct ethnl_reply_data *reply_base,
+ struct genl_info *info)
+{
+ struct plca_reply_data *data = PLCA_REPDATA(reply_base);
+ struct net_device *dev = reply_base->dev;
+ const struct ethtool_phy_ops *ops;
+ int ret;
+
+ // check that the PHY device is available and connected
+ if (!dev->phydev) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ // note: rtnl_lock is held already by ethnl_default_doit
+ ops = ethtool_phy_ops;
+ if (!ops || !ops->get_plca_status) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ ret = ethnl_ops_begin(dev);
+ if (ret < 0)
+ goto out;
+
+ ret = ops->get_plca_status(dev->phydev, &data->plca_st);
+ if (ret < 0)
+ goto out;
+
+ ethnl_ops_complete(dev);
+out:
+ return ret;
+}
+
+static int plca_get_status_reply_size(const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ return nla_total_size(sizeof(u8)); /* _STATUS */
+}
+
+static int plca_get_status_fill_reply(struct sk_buff *skb,
+ const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ const struct plca_reply_data *data = PLCA_REPDATA(reply_base);
+ const u8 status = data->plca_st.pst;
+
+ if (nla_put_u8(skb, ETHTOOL_A_PLCA_STATUS, !!status))
+ return -EMSGSIZE;
+
+ return 0;
+};
+
+const struct ethnl_request_ops ethnl_plca_status_request_ops = {
+ .request_cmd = ETHTOOL_MSG_PLCA_GET_STATUS,
+ .reply_cmd = ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
+ .hdr_attr = ETHTOOL_A_PLCA_HEADER,
+ .req_info_size = sizeof(struct plca_req_info),
+ .reply_data_size = sizeof(struct plca_reply_data),
+
+ .prepare_data = plca_get_status_prepare_data,
+ .reply_size = plca_get_status_reply_size,
+ .fill_reply = plca_get_status_fill_reply,
+};
--
2.35.1


2022-12-05 01:57:09

by Piergiorgio Beruto

[permalink] [raw]
Subject: [PATCH v2 net-next 2/4] drivers/net/phy: add the link modes for the 10BASE-T1S Ethernet PHY

This patch adds the link modes for the IEEE 802.3cg Clause 147 10BASE-T1S
Ethernet PHY. According to the specifications, the 10BASE-T1S supports
Point-To-Point Full-Duplex, Point-To-Point Half-Duplex and/or
Point-To-Multipoint (AKA Multi-Drop) Hal-Duplex operations.

Signed-off-by: Piergiorgio Beruto <[email protected]>
---
drivers/net/phy/phy-core.c | 5 ++++-
drivers/net/phy/phylink.c | 6 +++++-
include/uapi/linux/ethtool.h | 3 +++
net/ethtool/common.c | 8 ++++++++
4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 5d08c627a516..a64186dc53f8 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -13,7 +13,7 @@
*/
const char *phy_speed_to_str(int speed)
{
- BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 99,
+ BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102,
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
"If a speed or mode has been added please update phy_speed_to_str "
"and the PHY settings array.\n");
@@ -260,6 +260,9 @@ static const struct phy_setting settings[] = {
PHY_SETTING( 10, FULL, 10baseT_Full ),
PHY_SETTING( 10, HALF, 10baseT_Half ),
PHY_SETTING( 10, FULL, 10baseT1L_Full ),
+ PHY_SETTING( 10, FULL, 10baseT1S_Full ),
+ PHY_SETTING( 10, HALF, 10baseT1S_Half ),
+ PHY_SETTING( 10, HALF, 10baseT1S_P2MP_Half ),
};
#undef PHY_SETTING

diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 09cc65c0da93..319790221d7f 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -241,12 +241,16 @@ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps)
if (caps & MAC_ASYM_PAUSE)
__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes);

- if (caps & MAC_10HD)
+ if (caps & MAC_10HD) {
__set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes);
+ __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Half_BIT, linkmodes);
+ __set_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, linkmodes);
+ }

if (caps & MAC_10FD) {
__set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes);
__set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, linkmodes);
+ __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Full_BIT, linkmodes);
}

if (caps & MAC_100HD) {
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 58e587ba0450..5f414deacf23 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1741,6 +1741,9 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96,
ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97,
ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98,
+ ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99,
+ ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100,
+ ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101,

/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 21cfe8557205..c586db0c5e68 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -208,6 +208,9 @@ const char link_mode_names[][ETH_GSTRING_LEN] = {
__DEFINE_LINK_MODE_NAME(800000, DR8_2, Full),
__DEFINE_LINK_MODE_NAME(800000, SR8, Full),
__DEFINE_LINK_MODE_NAME(800000, VR8, Full),
+ __DEFINE_LINK_MODE_NAME(10, T1S, Full),
+ __DEFINE_LINK_MODE_NAME(10, T1S, Half),
+ __DEFINE_LINK_MODE_NAME(10, T1S_P2MP, Half),
};
static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);

@@ -244,6 +247,8 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
#define __LINK_MODE_LANES_X 1
#define __LINK_MODE_LANES_FX 1
#define __LINK_MODE_LANES_T1L 1
+#define __LINK_MODE_LANES_T1S 1
+#define __LINK_MODE_LANES_T1S_P2MP 1
#define __LINK_MODE_LANES_VR8 8
#define __LINK_MODE_LANES_DR8_2 8

@@ -366,6 +371,9 @@ const struct link_mode_info link_mode_params[] = {
__DEFINE_LINK_MODE_PARAMS(800000, DR8_2, Full),
__DEFINE_LINK_MODE_PARAMS(800000, SR8, Full),
__DEFINE_LINK_MODE_PARAMS(800000, VR8, Full),
+ __DEFINE_LINK_MODE_PARAMS(10, T1S, Full),
+ __DEFINE_LINK_MODE_PARAMS(10, T1S, Half),
+ __DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half),
};
static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS);

--
2.35.1

2022-12-05 01:58:36

by Piergiorgio Beruto

[permalink] [raw]
Subject: [PATCH v2 net-next 3/4] drivers/net/phy: add connection between ethtool and phylib for PLCA

This patch adds the required connection between netlink ethtool and
phylib to resolve PLCA get/set config and get status messages.

Signed-off-by: Piergiorgio Beruto <[email protected]>
---
drivers/net/phy/phy.c | 163 +++++++++++++++++++++++++++++++++++++++---
include/linux/phy.h | 17 ++++-
2 files changed, 168 insertions(+), 12 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 99e3497b6aa1..6bea928e405b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -544,36 +544,181 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
EXPORT_SYMBOL(phy_ethtool_get_stats);

/**
+ * phy_ethtool_get_plca_cfg - Get PLCA RS configuration
*
+ * @phydev: the phy_device struct
+ * @plca_cfg: where to store the retrieved configuration
*/
-int phy_ethtool_get_plca_cfg(struct phy_device *dev,
+int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg)
{
- // TODO
- return 0;
+ int ret;
+
+ if (!phydev->drv) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (!phydev->drv->get_plca_cfg) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ memset(plca_cfg, 0xFF, sizeof(*plca_cfg));
+
+ mutex_lock(&phydev->lock);
+ ret = phydev->drv->get_plca_cfg(phydev, plca_cfg);
+
+ if (ret)
+ goto out_drv;
+
+out_drv:
+ mutex_unlock(&phydev->lock);
+out:
+ return ret;
}
EXPORT_SYMBOL(phy_ethtool_get_plca_cfg);

/**
+ * phy_ethtool_set_plca_cfg - Set PLCA RS configuration
*
+ * @phydev: the phy_device struct
+ * @extack: extack for reporting useful error messages
+ * @plca_cfg: new PLCA configuration to apply
*/
-int phy_ethtool_set_plca_cfg(struct phy_device *dev,
+int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
struct netlink_ext_ack *extack,
const struct phy_plca_cfg *plca_cfg)
{
- // TODO
- return 0;
+ int ret;
+ struct phy_plca_cfg *curr_plca_cfg = 0;
+
+ if (!phydev->drv) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (!phydev->drv->set_plca_cfg ||
+ !phydev->drv->get_plca_cfg) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ curr_plca_cfg = kmalloc(sizeof(*curr_plca_cfg), GFP_KERNEL);
+ memset(curr_plca_cfg, 0xFF, sizeof(*curr_plca_cfg));
+
+ mutex_lock(&phydev->lock);
+
+ ret = phydev->drv->get_plca_cfg(phydev, curr_plca_cfg);
+ if (ret)
+ goto out_drv;
+
+ if (curr_plca_cfg->enabled < 0 && plca_cfg->enabled >= 0) {
+ NL_SET_ERR_MSG(extack,
+ "PHY does not support changing the PLCA 'enable' attribute");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+
+ if (curr_plca_cfg->node_id < 0 && plca_cfg->node_id >= 0) {
+ NL_SET_ERR_MSG(extack,
+ "PHY does not support changing the PLCA 'local node ID' attribute");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+
+ if (curr_plca_cfg->node_cnt < 0 && plca_cfg->node_cnt >= 0) {
+ NL_SET_ERR_MSG(extack,
+ "PHY does not support changing the PLCA 'node count' attribute");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+
+ if (curr_plca_cfg->to_tmr < 0 && plca_cfg->to_tmr >= 0) {
+ NL_SET_ERR_MSG(extack,
+ "PHY does not support changing the PLCA 'TO timer' attribute");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+
+ if (curr_plca_cfg->burst_cnt < 0 && plca_cfg->burst_cnt >= 0) {
+ NL_SET_ERR_MSG(extack,
+ "PHY does not support changing the PLCA 'burst count' attribute");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+
+ if (curr_plca_cfg->burst_tmr < 0 && plca_cfg->burst_tmr >= 0) {
+ NL_SET_ERR_MSG(extack,
+ "PHY does not support changing the PLCA 'burst timer' attribute");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+
+ // if enabling PLCA, perform additional sanity checks
+ if (plca_cfg->enabled > 0) {
+ if (!linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
+ phydev->advertising)) {
+ ret = -EOPNOTSUPP;
+ NL_SET_ERR_MSG(extack,
+ "Point to Multi-Point mode is not enabled");
+ }
+
+ // allow setting node_id concurrently with enabled
+ if (plca_cfg->node_id >= 0)
+ curr_plca_cfg->node_id = plca_cfg->node_id;
+
+ if (curr_plca_cfg->node_id >= 255) {
+ NL_SET_ERR_MSG(extack, "PLCA node ID is not set");
+ ret = -EINVAL;
+ goto out_drv;
+ }
+ }
+
+ ret = phydev->drv->set_plca_cfg(phydev, plca_cfg);
+ if (ret)
+ goto out_drv;
+
+out_drv:
+ kfree(curr_plca_cfg);
+ mutex_unlock(&phydev->lock);
+out:
+ return ret;
+
}
EXPORT_SYMBOL(phy_ethtool_set_plca_cfg);

/**
+ * phy_ethtool_get_plca_status - Get PLCA RS status information
*
+ * @phydev: the phy_device struct
+ * @plca_st: where to store the retrieved status information
*/
-int phy_ethtool_get_plca_status(struct phy_device *dev,
+int phy_ethtool_get_plca_status(struct phy_device *phydev,
struct phy_plca_status *plca_st)
{
- // TODO
- return 0;
+ int ret;
+
+ if (!phydev->drv) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (!phydev->drv->get_plca_status) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ mutex_lock(&phydev->lock);
+ ret = phydev->drv->get_plca_status(phydev, plca_st);
+
+ if (ret)
+ goto out_drv;
+
+out_drv:
+ mutex_unlock(&phydev->lock);
+out:
+ return ret;
}
EXPORT_SYMBOL(phy_ethtool_get_plca_status);

diff --git a/include/linux/phy.h b/include/linux/phy.h
index ab2c134d0a05..49d0488bf480 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1036,6 +1036,17 @@ struct phy_driver {
int (*get_sqi)(struct phy_device *dev);
/** @get_sqi_max: Get the maximum signal quality indication */
int (*get_sqi_max)(struct phy_device *dev);
+
+ /* PLCA RS interface */
+ /** @get_plca_cfg: Return the current PLCA configuration */
+ int (*get_plca_cfg)(struct phy_device *dev,
+ struct phy_plca_cfg *plca_cfg);
+ /** @set_plca_cfg: Set the PLCA configuration */
+ int (*set_plca_cfg)(struct phy_device *dev,
+ const struct phy_plca_cfg *plca_cfg);
+ /** @get_plca_status: Return the current PLCA status info */
+ int (*get_plca_status)(struct phy_device *dev,
+ struct phy_plca_status *plca_st);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
@@ -1832,12 +1843,12 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
int phy_ethtool_get_sset_count(struct phy_device *phydev);
int phy_ethtool_get_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data);
-int phy_ethtool_get_plca_cfg(struct phy_device *dev,
+int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg);
-int phy_ethtool_set_plca_cfg(struct phy_device *dev,
+int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
struct netlink_ext_ack *extack,
const struct phy_plca_cfg *plca_cfg);
-int phy_ethtool_get_plca_status(struct phy_device *dev,
+int phy_ethtool_get_plca_status(struct phy_device *phydev,
struct phy_plca_status *plca_st);

static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
--
2.35.1

2022-12-05 02:12:15

by Piergiorgio Beruto

[permalink] [raw]
Subject: [PATCH v2 net-next 4/4] drivers/net/phy: add driver for the onsemi NCN26000 10BASE-T1S PHY

Add support for the onsemi NCN26000 10BASE-T1S industrial Ethernet PHY.
The driver supports Point-to-Multipoint operation without
auto-negotiation and with link control handling. The PLCA RS support
will be included on a separate patch.

Signed-off-by: Piergiorgio Beruto <[email protected]>
---
MAINTAINERS | 8 ++
drivers/net/phy/Kconfig | 7 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-open-alliance.h | 44 +++++++
drivers/net/phy/ncn26000.c | 187 +++++++++++++++++++++++++++
drivers/net/phy/phy-c45.c | 180 ++++++++++++++++++++++++++
include/linux/phy.h | 6 +
7 files changed, 433 insertions(+)
create mode 100644 drivers/net/phy/mdio-open-alliance.h
create mode 100644 drivers/net/phy/ncn26000.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7952243e4b43..09f0bfa3ae64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15357,6 +15357,13 @@ L: [email protected]
S: Maintained
F: arch/mips/boot/dts/ralink/omega2p.dts

+ONSEMI ETHERNET PHY DRIVERS
+M: Piergiorgio Beruto <[email protected]>
+L: [email protected]
+S: Supported
+W: http://www.onsemi.com
+F: drivers/net/phy/ncn*
+
OP-TEE DRIVER
M: Jens Wiklander <[email protected]>
L: [email protected]
@@ -16400,6 +16407,7 @@ PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148)
M: Piergiorgio Beruto <[email protected]>
L: [email protected]
S: Maintained
+F: drivers/net/phy/mdio-open-alliance.h
F: net/ethtool/plca.c

PLDMFW LIBRARY
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index af00cf44cd97..7c466830c611 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -267,6 +267,13 @@ config NATIONAL_PHY
help
Currently supports the DP83865 PHY.

+config NCN26000_PHY
+ tristate "onsemi 10BASE-T1S Ethernet PHY"
+ help
+ Adds support for the onsemi 10BASE-T1S Ethernet PHY.
+ Currently supports the NCN26000 10BASE-T1S Industrial PHY
+ with MII interface.
+
config NXP_C45_TJA11XX_PHY
tristate "NXP C45 TJA11XX PHYs"
depends on PTP_1588_CLOCK_OPTIONAL
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index f7138d3c896b..b5138066ba04 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o
obj-$(CONFIG_MICROSEMI_PHY) += mscc/
obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
+obj-$(CONFIG_NCN26000_PHY) += ncn26000.o
obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
diff --git a/drivers/net/phy/mdio-open-alliance.h b/drivers/net/phy/mdio-open-alliance.h
new file mode 100644
index 000000000000..565f4162611d
--- /dev/null
+++ b/drivers/net/phy/mdio-open-alliance.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mdio-open-alliance.h - definition of OPEN Alliance SIG standard registers
+ */
+
+#ifndef __MDIO_OPEN_ALLIANCE__
+#define __MDIO_OPEN_ALLIANCE__
+
+#include <linux/mdio.h>
+
+/* MDIO Manageable Devices (MMDs). */
+#define MDIO_MMD_OATC14 MDIO_MMD_VEND2
+
+/* Open Alliance TC14 (10BASE-T1S) registers */
+#define MDIO_OATC14_PLCA_IDVER 0xca00 /* PLCA ID and version */
+#define MDIO_OATC14_PLCA_CTRL0 0xca01 /* PLCA Control register 0 */
+#define MDIO_OATC14_PLCA_CTRL1 0xca02 /* PLCA Control register 1 */
+#define MDIO_OATC14_PLCA_STATUS 0xca03 /* PLCA Status register */
+#define MDIO_OATC14_PLCA_TOTMR 0xca04 /* PLCA TO Timer register */
+#define MDIO_OATC14_PLCA_BURST 0xca05 /* PLCA BURST mode register */
+
+/* Open Alliance TC14 PLCA IDVER register */
+#define MDIO_OATC14_PLCA_IDM 0xff00 /* PLCA MAP ID */
+#define MDIO_OATC14_PLCA_VER 0x00ff /* PLCA MAP version */
+
+/* Open Alliance TC14 PLCA CTRL0 register */
+#define MDIO_OATC14_PLCA_EN 0x8000 /* PLCA enable */
+#define MDIO_OATC14_PLCA_RST 0x4000 /* PLCA reset */
+
+/* Open Alliance TC14 PLCA CTRL1 register */
+#define MDIO_OATC14_PLCA_NCNT 0xff00 /* PLCA node count */
+#define MDIO_OATC14_PLCA_ID 0x00ff /* PLCA local node ID */
+
+/* Open Alliance TC14 PLCA STATUS register */
+#define MDIO_OATC14_PLCA_PST 0x8000 /* PLCA status indication */
+
+/* Open Alliance TC14 PLCA TOTMR register */
+#define MDIO_OATC14_PLCA_TOT 0x00ff
+
+/* Open Alliance TC14 PLCA BURST register */
+#define MDIO_OATC14_PLCA_MAXBC 0xff00
+#define MDIO_OATC14_PLCA_BTMR 0x00ff
+
+#endif /* __MDIO_OPEN_ALLIANCE__ */
diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c
new file mode 100644
index 000000000000..49d4fee20cbc
--- /dev/null
+++ b/drivers/net/phy/ncn26000.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Driver for the onsemi 10BASE-T1S NCN26000 PHYs family.
+ *
+ * Copyright 2022 onsemi
+ */
+#include <linux/kernel.h>
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include "mdio-open-alliance.h"
+
+#define PHY_ID_NCN26000 0x180FF5A1
+
+#define NCN26000_REG_IRQ_CTL 16
+#define NCN26000_REG_IRQ_STATUS 17
+
+// the NCN26000 maps link_ctrl to BMCR_ANENABLE
+#define NCN26000_BCMR_LINK_CTRL_BIT BMCR_ANENABLE
+
+// the NCN26000 maps link_status to BMSR_ANEGCOMPLETE
+#define NCN26000_BMSR_LINK_STATUS_BIT BMSR_ANEGCOMPLETE
+
+#define NCN26000_IRQ_LINKST_BIT BIT(0)
+#define NCN26000_IRQ_PLCAST_BIT BIT(1)
+#define NCN26000_IRQ_LJABBER_BIT BIT(2)
+#define NCN26000_IRQ_RJABBER_BIT BIT(3)
+#define NCN26000_IRQ_PLCAREC_BIT BIT(4)
+#define NCN26000_IRQ_PHYSCOL_BIT BIT(5)
+
+#define TO_TMR_DEFAULT 32
+
+struct ncn26000_priv {
+ u16 enabled_irqs;
+};
+
+// module parameter: if set, the link status is derived from the PLCA status
+// default: false
+static bool link_status_plca;
+module_param(link_status_plca, bool, 0644);
+
+// driver callbacks
+
+static int ncn26000_config_init(struct phy_device *phydev)
+{
+ /* HW bug workaround: the default value of the PLCA TO_TIMER should be
+ * 32, where the current version of NCN26000 reports 24. This will be
+ * fixed in future PHY versions. For the time being, we force the
+ * correct default here.
+ */
+ return phy_write_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_TOTMR,
+ TO_TMR_DEFAULT);
+}
+
+static int ncn26000_config_aneg(struct phy_device *phydev)
+{
+ // Note: the NCN26000 supports only P2MP link mode. Therefore, AN is not
+ // supported. However, this function is invoked by phylib to enable the
+ // PHY, regardless of the AN support.
+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+ phydev->mdix = ETH_TP_MDI;
+
+ // bring up the link
+ return phy_write(phydev, MII_BMCR, NCN26000_BCMR_LINK_CTRL_BIT);
+}
+
+static int ncn26000_get_features(struct phy_device *phydev)
+{
+ linkmode_zero(phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_MII_BIT, phydev->supported);
+
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
+ phydev->supported);
+
+ linkmode_copy(phydev->advertising, phydev->supported);
+ return 0;
+}
+
+static int ncn26000_read_status(struct phy_device *phydev)
+{
+ // The NCN26000 reports NCN26000_LINK_STATUS_BIT if the link status of
+ // the PHY is up. It further reports the logical AND of the link status
+ // and the PLCA status in the BMSR_LSTATUS bit. Thus, report the link
+ // status by testing the appropriate BMSR bit according to the module's
+ // parameter configuration.
+ const int lstatus_flag = link_status_plca ?
+ BMSR_LSTATUS : NCN26000_BMSR_LINK_STATUS_BIT;
+
+ int ret;
+
+ ret = phy_read(phydev, MII_BMSR);
+ if (unlikely(ret < 0))
+ return ret;
+
+ // update link status
+ phydev->link = (ret & lstatus_flag) ? 1 : 0;
+
+ // handle more IRQs here
+
+ return 0;
+}
+
+static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
+{
+ const struct ncn26000_priv *const priv = phydev->priv;
+ int ret;
+
+ // clear the latched bits in MII_BMSR
+ phy_read(phydev, MII_BMSR);
+
+ // read and aknowledge the IRQ status register
+ ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS);
+
+ if (unlikely(ret < 0) || (ret & priv->enabled_irqs) == 0)
+ return IRQ_NONE;
+
+ phy_trigger_machine(phydev);
+ return IRQ_HANDLED;
+}
+
+static int ncn26000_config_intr(struct phy_device *phydev)
+{
+ int ret;
+ struct ncn26000_priv *priv = phydev->priv;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ // acknowledge IRQs
+ ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS);
+ if (ret < 0)
+ return ret;
+
+ // get link status notifications
+ priv->enabled_irqs = NCN26000_IRQ_LINKST_BIT;
+ } else {
+ // disable all IRQs
+ priv->enabled_irqs = 0;
+ }
+
+ ret = phy_write(phydev, NCN26000_REG_IRQ_CTL, priv->enabled_irqs);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+static int ncn26000_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct ncn26000_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
+static struct phy_driver ncn26000_driver[] = {
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_NCN26000),
+ .name = "NCN26000",
+ .probe = ncn26000_probe,
+ .get_features = ncn26000_get_features,
+ .config_init = ncn26000_config_init,
+ .config_intr = ncn26000_config_intr,
+ .config_aneg = ncn26000_config_aneg,
+ .read_status = ncn26000_read_status,
+ .handle_interrupt = ncn26000_handle_interrupt,
+ .get_plca_cfg = genphy_c45_plca_get_cfg,
+ .set_plca_cfg = genphy_c45_plca_set_cfg,
+ .get_plca_status = genphy_c45_plca_get_status,
+ .soft_reset = genphy_soft_reset,
+ },
+};
+
+module_phy_driver(ncn26000_driver);
+
+MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);
+MODULE_AUTHOR("Piergiorgio Beruto");
+MODULE_DESCRIPTION("onsemi 10BASE-T1S PHY driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index a87a4b3ffce4..dace5d3b29ad 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -8,6 +8,8 @@
#include <linux/mii.h>
#include <linux/phy.h>

+#include "mdio-open-alliance.h"
+
/**
* genphy_c45_baset1_able - checks if the PMA has BASE-T1 extended abilities
* @phydev: target phy_device struct
@@ -931,6 +933,184 @@ int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable)
}
EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain);

+/**
+ * genphy_c45_plca_get_cfg - get PLCA configuration from standard registers
+ * @phydev: target phy_device struct
+ * @plca_cfg: output structure to store the PLCA configuration
+ *
+ * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
+ * Management Registers specifications, this function can be used to retrieve
+ * the current PLCA configuration from the standard registers in MMD 31.
+ */
+int genphy_c45_plca_get_cfg(struct phy_device *phydev,
+ struct phy_plca_cfg *plca_cfg)
+{
+ int ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_IDVER);
+ if (ret < 0)
+ return ret;
+
+ plca_cfg->version = ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_CTRL0);
+ if (ret < 0)
+ return ret;
+
+ plca_cfg->enabled = !!(ret & MDIO_OATC14_PLCA_EN);
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_CTRL1);
+ if (ret < 0)
+ return ret;
+
+ plca_cfg->node_cnt = (ret & MDIO_OATC14_PLCA_NCNT) >> 8;
+ plca_cfg->node_id = (ret & MDIO_OATC14_PLCA_ID);
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_TOTMR);
+ if (ret < 0)
+ return ret;
+
+ plca_cfg->to_tmr = ret & MDIO_OATC14_PLCA_TOT;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_BURST);
+ if (ret < 0)
+ return ret;
+
+ plca_cfg->burst_cnt = (ret & MDIO_OATC14_PLCA_MAXBC) >> 8;
+ plca_cfg->burst_tmr = (ret & MDIO_OATC14_PLCA_BTMR);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_plca_get_cfg);
+
+/**
+ * genphy_c45_plca_set_cfg - set PLCA configuration using standard registers
+ * @phydev: target phy_device struct
+ * @plca_cfg: structure containing the PLCA configuration. Fields set to -1 are
+ * not to be changed.
+ *
+ * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
+ * Management Registers specifications, this function can be used to modify
+ * the PLCA configuration using the standard registers in MMD 31.
+ */
+int genphy_c45_plca_set_cfg(struct phy_device *phydev,
+ const struct phy_plca_cfg *plca_cfg)
+{
+ int ret;
+ u16 val;
+
+ // PLCA IDVER is read-only
+ if (plca_cfg->version >= 0)
+ return -EINVAL;
+
+ // first of all, disable PLCA if required
+ if (plca_cfg->enabled == 0) {
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_CTRL0,
+ MDIO_OATC14_PLCA_EN);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ if (plca_cfg->node_cnt >= 0 || plca_cfg->node_id >= 0) {
+ if (plca_cfg->node_cnt < 0 || plca_cfg->node_id < 0) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_CTRL1);
+
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+ }
+
+ if (plca_cfg->node_cnt >= 0)
+ val = (val & ~MDIO_OATC14_PLCA_NCNT) |
+ (plca_cfg->node_cnt << 8);
+
+ if (plca_cfg->node_id >= 0)
+ val = (val & ~MDIO_OATC14_PLCA_ID) |
+ (plca_cfg->node_id);
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_CTRL1, val);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ if (plca_cfg->to_tmr >= 0) {
+ ret = phy_write_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_TOTMR,
+ plca_cfg->to_tmr);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ if (plca_cfg->burst_cnt >= 0 || plca_cfg->burst_tmr >= 0) {
+ if (plca_cfg->burst_cnt < 0 || plca_cfg->burst_tmr < 0) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_BURST);
+
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+ }
+
+ if (plca_cfg->burst_cnt >= 0)
+ val = (val & ~MDIO_OATC14_PLCA_MAXBC) |
+ (plca_cfg->burst_cnt << 8);
+
+ if (plca_cfg->burst_tmr >= 0)
+ val = (val & ~MDIO_OATC14_PLCA_BTMR) |
+ (plca_cfg->burst_tmr);
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_BURST, val);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ // if we need to enable PLCA, do it at the end
+ if (plca_cfg->enabled > 0) {
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_OATC14,
+ MDIO_OATC14_PLCA_CTRL0,
+ MDIO_OATC14_PLCA_EN);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_plca_set_cfg);
+
+/**
+ * genphy_c45_plca_get_status - get PLCA status from standard registers
+ * @phydev: target phy_device struct
+ * @plca_st: output structure to store the PLCA status
+ *
+ * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
+ * Management Registers specifications, this function can be used to retrieve
+ * the current PLCA status information from the standard registers in MMD 31.
+ */
+int genphy_c45_plca_get_status(struct phy_device *phydev,
+ struct phy_plca_status *plca_st)
+{
+ int ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_OATC14, MDIO_OATC14_PLCA_STATUS);
+ if (ret < 0)
+ return ret;
+
+ plca_st->pst = !!(ret & MDIO_OATC14_PLCA_PST);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_plca_get_status);
+
struct phy_driver genphy_c45_driver = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 49d0488bf480..4548c8e8f6a9 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1745,6 +1745,12 @@ int genphy_c45_loopback(struct phy_device *phydev, bool enable);
int genphy_c45_pma_resume(struct phy_device *phydev);
int genphy_c45_pma_suspend(struct phy_device *phydev);
int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable);
+int genphy_c45_plca_get_cfg(struct phy_device *phydev,
+ struct phy_plca_cfg *plca_cfg);
+int genphy_c45_plca_set_cfg(struct phy_device *phydev,
+ const struct phy_plca_cfg *plca_cfg);
+int genphy_c45_plca_get_status(struct phy_device *phydev,
+ struct phy_plca_status *plca_st);

/* Generic C45 PHY driver */
extern struct phy_driver genphy_c45_driver;
--
2.35.1

2022-12-05 05:42:04

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 4/4] drivers/net/phy: add driver for the onsemi NCN26000 10BASE-T1S PHY

Hi Piergiorgio,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url: https://github.com/intel-lab-lkp/linux/commits/Piergiorgio-Beruto/net-ethtool-add-netlink-interface-for-the-PLCA-RS/20221205-094500
patch link: https://lore.kernel.org/r/fb10b2a22255d493c6e3abc330b6e3f5f28c495e.1670204277.git.piergiorgio.beruto%40gmail.com
patch subject: [PATCH v2 net-next 4/4] drivers/net/phy: add driver for the onsemi NCN26000 10BASE-T1S PHY
config: m68k-allmodconfig
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/91aaf14d7c224d0b9883922a14086dd4c60da5f0
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Piergiorgio-Beruto/net-ethtool-add-netlink-interface-for-the-PLCA-RS/20221205-094500
git checkout 91aaf14d7c224d0b9883922a14086dd4c60da5f0
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/net/phy/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

In file included from drivers/net/phy/ncn26000.c:11:
>> drivers/net/phy/ncn26000.c:184:27: error: 'ncn26000_tbl' undeclared here (not in a function); did you mean 'ncn26000_probe'?
184 | MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);
| ^~~~~~~~~~~~
include/linux/module.h:243:15: note: in definition of macro 'MODULE_DEVICE_TABLE'
243 | extern typeof(name) __mod_##type##__##name##_device_table \
| ^~~~
>> include/linux/module.h:243:21: error: '__mod_mdio__ncn26000_tbl_device_table' aliased to undefined symbol 'ncn26000_tbl'
243 | extern typeof(name) __mod_##type##__##name##_device_table \
| ^~~~~~
drivers/net/phy/ncn26000.c:184:1: note: in expansion of macro 'MODULE_DEVICE_TABLE'
184 | MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);
| ^~~~~~~~~~~~~~~~~~~


vim +184 drivers/net/phy/ncn26000.c

183
> 184 MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (2.49 kB)
config (282.09 kB)
Download all attachments

2022-12-05 06:43:57

by Oleksij Rempel

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

Hi Beruto,

On Mon, Dec 05, 2022 at 02:41:35AM +0100, Piergiorgio Beruto wrote:
> Add support for configuring the PLCA Reconciliation Sublayer on
> multi-drop PHYs that support IEEE802.3cg-2019 Clause 148 (e.g.,
> 10BASE-T1S). This patch adds the appropriate netlink interface
> to ethtool.
>
> Signed-off-by: Piergiorgio Beruto <[email protected]>
> ---
> MAINTAINERS | 6 +
> drivers/net/phy/phy.c | 34 ++++
> drivers/net/phy/phy_device.c | 3 +
> include/linux/ethtool.h | 11 +
> include/linux/phy.h | 64 ++++++
> include/uapi/linux/ethtool_netlink.h | 25 +++
> net/ethtool/Makefile | 2 +-
> net/ethtool/netlink.c | 30 +++
> net/ethtool/netlink.h | 6 +
> net/ethtool/plca.c | 290 +++++++++++++++++++++++++++
> 10 files changed, 470 insertions(+), 1 deletion(-)
> create mode 100644 net/ethtool/plca.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 955c1be1efb2..7952243e4b43 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16396,6 +16396,12 @@ S: Maintained
> F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
> F: drivers/iio/chemical/pms7003.c
>
> +PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148)
> +M: Piergiorgio Beruto <[email protected]>
> +L: [email protected]
> +S: Maintained
> +F: net/ethtool/plca.c
> +
> PLDMFW LIBRARY
> M: Jacob Keller <[email protected]>
> S: Maintained
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index e5b6cb1a77f9..99e3497b6aa1 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -543,6 +543,40 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
> }
> EXPORT_SYMBOL(phy_ethtool_get_stats);
>
> +/**
> + *
> + */
> +int phy_ethtool_get_plca_cfg(struct phy_device *dev,
> + struct phy_plca_cfg *plca_cfg)
> +{
> + // TODO
> + return 0;
> +}
> +EXPORT_SYMBOL(phy_ethtool_get_plca_cfg);
> +
> +/**
> + *
> + */
> +int phy_ethtool_set_plca_cfg(struct phy_device *dev,
> + struct netlink_ext_ack *extack,
> + const struct phy_plca_cfg *plca_cfg)
> +{
> + // TODO
> + return 0;
> +}
> +EXPORT_SYMBOL(phy_ethtool_set_plca_cfg);
> +
> +/**
> + *
> + */
> +int phy_ethtool_get_plca_status(struct phy_device *dev,
> + struct phy_plca_status *plca_st)
> +{
> + // TODO
> + return 0;
> +}
> +EXPORT_SYMBOL(phy_ethtool_get_plca_status);
> +
> /**
> * phy_start_cable_test - Start a cable test
> *
> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
> index 716870a4499c..f248010c403d 100644
> --- a/drivers/net/phy/phy_device.c
> +++ b/drivers/net/phy/phy_device.c
> @@ -3262,6 +3262,9 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
> .get_sset_count = phy_ethtool_get_sset_count,
> .get_strings = phy_ethtool_get_strings,
> .get_stats = phy_ethtool_get_stats,
> + .get_plca_cfg = phy_ethtool_get_plca_cfg,
> + .set_plca_cfg = phy_ethtool_set_plca_cfg,
> + .get_plca_status = phy_ethtool_get_plca_status,
> .start_cable_test = phy_start_cable_test,
> .start_cable_test_tdr = phy_start_cable_test_tdr,
> };
> diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
> index 9e0a76fc7de9..4bfe95ec1f0a 100644
> --- a/include/linux/ethtool.h
> +++ b/include/linux/ethtool.h
> @@ -802,12 +802,16 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev,
>
> struct phy_device;
> struct phy_tdr_config;
> +struct phy_plca_cfg;
> +struct phy_plca_status;
>
> /**
> * struct ethtool_phy_ops - Optional PHY device options
> * @get_sset_count: Get number of strings that @get_strings will write.
> * @get_strings: Return a set of strings that describe the requested objects
> * @get_stats: Return extended statistics about the PHY device.
> + * @get_plca_cfg: Return PLCA configuration.
> + * @set_plca_cfg: Set PLCA configuration.
> * @start_cable_test: Start a cable test
> * @start_cable_test_tdr: Start a Time Domain Reflectometry cable test
> *
> @@ -819,6 +823,13 @@ struct ethtool_phy_ops {
> int (*get_strings)(struct phy_device *dev, u8 *data);
> int (*get_stats)(struct phy_device *dev,
> struct ethtool_stats *stats, u64 *data);
> + int (*get_plca_cfg)(struct phy_device *dev,
> + struct phy_plca_cfg *plca_cfg);
> + int (*set_plca_cfg)(struct phy_device *dev,
> + struct netlink_ext_ack *extack,
> + const struct phy_plca_cfg *plca_cfg);
> + int (*get_plca_status)(struct phy_device *dev,
> + struct phy_plca_status *plca_st);
> int (*start_cable_test)(struct phy_device *phydev,
> struct netlink_ext_ack *extack);
> int (*start_cable_test_tdr)(struct phy_device *phydev,
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index 71eeb4e3b1fd..ab2c134d0a05 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -765,6 +765,63 @@ struct phy_tdr_config {
> };
> #define PHY_PAIR_ALL -1
>
> +/**
> + * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
> + * Avoidance) Reconciliation Sublayer.
> + *
> + * @version: read-only PLCA register map version. 0 = not available. Ignored
> + * when setting the configuration. Format is the same as reported by the PLCA
> + * IDVER register (31.CA00). -1 = not available.
> + * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't
> + * set. 0 = disabled, anything else = enabled.
> + * @node_id: the PLCA local node identifier. -1 = not available / don't set.
> + * Allowed values [0 .. 254]. 255 = node disabled.
> + * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only
> + * meaningful for the coordinator (node_id = 0). -1 = not available / don't
> + * set. Allowed values [0 .. 255].
> + * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the
> + * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for
> + * more details. The to_timer shall be set equal over all nodes.
> + * -1 = not available / don't set. Allowed values [0 .. 255].
> + * @burst_cnt: controls how many additional frames a node is allowed to send in
> + * single transmit opportunity (TO). The default value of 0 means that the
> + * node is allowed exactly one frame per TO. A value of 1 allows two frames
> + * per TO, and so on. -1 = not available / don't set.
> + * Allowed values [0 .. 255].
> + * @burst_tmr: controls how many bit times to wait for the MAC to send a new
> + * frame before interrupting the burst. This value should be set to a value
> + * greater than the MAC inter-packet gap (which is typically 96 bits).
> + * -1 = not available / don't set. Allowed values [0 .. 255].
> + *
> + * A structure containing configuration parameters for setting/getting the PLCA
> + * RS configuration. The driver does not need to implement all the parameters,
> + * but should report what is actually used.
> + */
> +struct phy_plca_cfg {
> + s32 version;
> + s16 enabled;
> + s16 node_id;
> + s16 node_cnt;
> + s16 to_tmr;
> + s16 burst_cnt;
> + s16 burst_tmr;
> +};
> +
> +/**
> + * struct phy_plca_status - Status of the PLCA (Physical Layer Collision
> + * Avoidance) Reconciliation Sublayer.
> + *
> + * @pst: The PLCA status as reported by the PST bit in the PLCA STATUS
> + * register(31.CA03), indicating BEACON activity.
> + *
> + * A structure containing status information of the PLCA RS configuration.
> + * The driver does not need to implement all the parameters, but should report
> + * what is actually used.
> + */
> +struct phy_plca_status {
> + bool pst;
> +};
> +
> /**
> * struct phy_driver - Driver structure for a particular PHY type
> *
> @@ -1775,6 +1832,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
> int phy_ethtool_get_sset_count(struct phy_device *phydev);
> int phy_ethtool_get_stats(struct phy_device *phydev,
> struct ethtool_stats *stats, u64 *data);
> +int phy_ethtool_get_plca_cfg(struct phy_device *dev,
> + struct phy_plca_cfg *plca_cfg);
> +int phy_ethtool_set_plca_cfg(struct phy_device *dev,
> + struct netlink_ext_ack *extack,
> + const struct phy_plca_cfg *plca_cfg);
> +int phy_ethtool_get_plca_status(struct phy_device *dev,
> + struct phy_plca_status *plca_st);
>
> static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
> {
> diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
> index aaf7c6963d61..81e3d7b42d0f 100644
> --- a/include/uapi/linux/ethtool_netlink.h
> +++ b/include/uapi/linux/ethtool_netlink.h
> @@ -51,6 +51,9 @@ enum {
> ETHTOOL_MSG_MODULE_SET,
> ETHTOOL_MSG_PSE_GET,
> ETHTOOL_MSG_PSE_SET,
> + ETHTOOL_MSG_PLCA_GET_CFG,
> + ETHTOOL_MSG_PLCA_SET_CFG,
> + ETHTOOL_MSG_PLCA_GET_STATUS,
>
> /* add new constants above here */
> __ETHTOOL_MSG_USER_CNT,
> @@ -97,6 +100,9 @@ enum {
> ETHTOOL_MSG_MODULE_GET_REPLY,
> ETHTOOL_MSG_MODULE_NTF,
> ETHTOOL_MSG_PSE_GET_REPLY,
> + ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
> + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
> + ETHTOOL_MSG_PLCA_NTF,
>
> /* add new constants above here */
> __ETHTOOL_MSG_KERNEL_CNT,
> @@ -880,6 +886,25 @@ enum {
> ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
> };
>
> +/* PLCA */
> +

Please use names used in the specification as close as possible and
document in comments real specification names.

> +enum {
> + ETHTOOL_A_PLCA_UNSPEC,
> + ETHTOOL_A_PLCA_HEADER, /* nest - _A_HEADER_* */
> + ETHTOOL_A_PLCA_VERSION, /* u16 */
> + ETHTOOL_A_PLCA_ENABLED, /* u8 */

30.16.1.1.1 aPLCAAdminState / 30.16.1.2.1 acPLCAAdminControl

> + ETHTOOL_A_PLCA_STATUS, /* u8 */

30.16.1.1.2 aPLCAStatus

> + ETHTOOL_A_PLCA_NODE_CNT, /* u8 */

30.16.1.1.3 aPLCANodeCount

> + ETHTOOL_A_PLCA_NODE_ID, /* u8 */

30.16.1.1.4 aPLCALocalNodeID

> + ETHTOOL_A_PLCA_TO_TMR, /* u8 */

30.16.1.1.5 aPLCATransmitOpportunityTimer

> + ETHTOOL_A_PLCA_BURST_CNT, /* u8 */

30.16.1.1.6 aPLCAMaxBurstCount

> + ETHTOOL_A_PLCA_BURST_TMR, /* u8 */

30.16.1.1.7 aPLCABurstTimer

> +
> + /* add new constants above here */
> + __ETHTOOL_A_PLCA_CNT,
> + ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
> +};

Should we have access to 30.16.1.2.2 acPLCAReset in user space?

> +
> /* generic netlink info */
> #define ETHTOOL_GENL_NAME "ethtool"
> #define ETHTOOL_GENL_VERSION 1
> diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
> index 72ab0944262a..b18930e2ce9a 100644
> --- a/net/ethtool/Makefile
> +++ b/net/ethtool/Makefile
> @@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \
> linkstate.o debug.o wol.o features.o privflags.o rings.o \
> channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
> tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \
> - pse-pd.o
> + pse-pd.o plca.o
> diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
> index 1a4c11356c96..eb044f48cb24 100644
> --- a/net/ethtool/netlink.c
> +++ b/net/ethtool/netlink.c
> @@ -287,6 +287,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
> [ETHTOOL_MSG_PHC_VCLOCKS_GET] = &ethnl_phc_vclocks_request_ops,
> [ETHTOOL_MSG_MODULE_GET] = &ethnl_module_request_ops,
> [ETHTOOL_MSG_PSE_GET] = &ethnl_pse_request_ops,
> + [ETHTOOL_MSG_PLCA_GET_CFG] = &ethnl_plca_cfg_request_ops,
> + [ETHTOOL_MSG_PLCA_GET_STATUS] = &ethnl_plca_status_request_ops,
> };
>
> static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
> @@ -602,6 +604,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
> [ETHTOOL_MSG_EEE_NTF] = &ethnl_eee_request_ops,
> [ETHTOOL_MSG_FEC_NTF] = &ethnl_fec_request_ops,
> [ETHTOOL_MSG_MODULE_NTF] = &ethnl_module_request_ops,
> + [ETHTOOL_MSG_PLCA_NTF] = &ethnl_plca_cfg_request_ops,
> };
>
> /* default notification handler */
> @@ -695,6 +698,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
> [ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify,
> [ETHTOOL_MSG_FEC_NTF] = ethnl_default_notify,
> [ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify,
> + [ETHTOOL_MSG_PLCA_NTF] = ethnl_default_notify,
> };
>
> void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
> @@ -1040,6 +1044,32 @@ static const struct genl_ops ethtool_genl_ops[] = {
> .policy = ethnl_pse_set_policy,
> .maxattr = ARRAY_SIZE(ethnl_pse_set_policy) - 1,
> },
> + {
> + .cmd = ETHTOOL_MSG_PLCA_GET_CFG,
> + .doit = ethnl_default_doit,
> + .start = ethnl_default_start,
> + .dumpit = ethnl_default_dumpit,
> + .done = ethnl_default_done,
> + .policy = ethnl_plca_get_cfg_policy,
> + .maxattr = ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1,
> + },
> + {
> + .cmd = ETHTOOL_MSG_PLCA_SET_CFG,
> + .flags = GENL_UNS_ADMIN_PERM,
> + .doit = ethnl_set_plca_cfg,
> + .policy = ethnl_plca_set_cfg_policy,
> + .maxattr = ARRAY_SIZE(ethnl_plca_set_cfg_policy) - 1,
> + },
> + {
> + .cmd = ETHTOOL_MSG_PLCA_GET_STATUS,
> + .doit = ethnl_default_doit,
> + .start = ethnl_default_start,
> + .dumpit = ethnl_default_dumpit,
> + .done = ethnl_default_done,
> + .policy = ethnl_plca_get_status_policy,
> + .maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1,
> + },
> +
> };
>
> static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
> diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
> index 1bfd374f9718..c0ed1a6d0833 100644
> --- a/net/ethtool/netlink.h
> +++ b/net/ethtool/netlink.h
> @@ -346,6 +346,8 @@ extern const struct ethnl_request_ops ethnl_stats_request_ops;
> extern const struct ethnl_request_ops ethnl_phc_vclocks_request_ops;
> extern const struct ethnl_request_ops ethnl_module_request_ops;
> extern const struct ethnl_request_ops ethnl_pse_request_ops;
> +extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
> +extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
>
> extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
> extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
> @@ -386,6 +388,9 @@ extern const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER +
> extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1];
> extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1];
> extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1];
> +extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1];
> +extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1];
> +extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];
>
> int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
> int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
> @@ -406,6 +411,7 @@ int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
> int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info);
> int ethnl_set_module(struct sk_buff *skb, struct genl_info *info);
> int ethnl_set_pse(struct sk_buff *skb, struct genl_info *info);
> +int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info);
>
> extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
> extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
> diff --git a/net/ethtool/plca.c b/net/ethtool/plca.c
> new file mode 100644
> index 000000000000..ab50d8b48bd6
> --- /dev/null
> +++ b/net/ethtool/plca.c
> @@ -0,0 +1,290 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/phy.h>
> +#include <linux/ethtool_netlink.h>
> +
> +#include "netlink.h"
> +#include "common.h"
> +
> +struct plca_req_info {
> + struct ethnl_req_info base;
> +};
> +
> +struct plca_reply_data {
> + struct ethnl_reply_data base;
> + struct phy_plca_cfg plca_cfg;
> + struct phy_plca_status plca_st;
> +};
> +
> +#define PLCA_REPDATA(__reply_base) \
> + container_of(__reply_base, struct plca_reply_data, base)
> +
> +// PLCA get configuration message ------------------------------------------- //
> +
> +const struct nla_policy ethnl_plca_get_cfg_policy[] = {
> + [ETHTOOL_A_PLCA_HEADER] =
> + NLA_POLICY_NESTED(ethnl_header_policy),
> +};
> +
> +static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
> + struct ethnl_reply_data *reply_base,
> + struct genl_info *info)
> +{
> + struct plca_reply_data *data = PLCA_REPDATA(reply_base);
> + struct net_device *dev = reply_base->dev;
> + const struct ethtool_phy_ops *ops;
> + int ret;
> +
> + // check that the PHY device is available and connected
> + if (!dev->phydev) {
> + ret = -EOPNOTSUPP;
> + goto out;
> + }
> +
> + // note: rtnl_lock is held already by ethnl_default_doit
> + ops = ethtool_phy_ops;
> + if (!ops || !ops->get_plca_cfg) {
> + ret = -EOPNOTSUPP;
> + goto out;
> + }
> +
> + ret = ethnl_ops_begin(dev);
> + if (ret < 0)
> + goto out;
> +
> + ret = ops->get_plca_cfg(dev->phydev, &data->plca_cfg);
> + if (ret < 0)
> + goto out;
> +
> + ethnl_ops_complete(dev);
> +
> +out:
> + return ret;
> +}
> +
> +static int plca_get_cfg_reply_size(const struct ethnl_req_info *req_base,
> + const struct ethnl_reply_data *reply_base)
> +{
> + return nla_total_size(sizeof(u16)) + /* _VERSION */
> + nla_total_size(sizeof(u8)) + /* _ENABLED */
> + nla_total_size(sizeof(u8)) + /* _STATUS */
> + nla_total_size(sizeof(u8)) + /* _NODE_CNT */
> + nla_total_size(sizeof(u8)) + /* _NODE_ID */
> + nla_total_size(sizeof(u8)) + /* _TO_TIMER */
> + nla_total_size(sizeof(u8)) + /* _BURST_COUNT */
> + nla_total_size(sizeof(u8)); /* _BURST_TIMER */
> +}
> +
> +static int plca_get_cfg_fill_reply(struct sk_buff *skb,
> + const struct ethnl_req_info *req_base,
> + const struct ethnl_reply_data *reply_base)
> +{
> + const struct plca_reply_data *data = PLCA_REPDATA(reply_base);
> + const struct phy_plca_cfg *plca = &data->plca_cfg;
> +
> + if ((plca->version >= 0 &&
> + nla_put_u16(skb, ETHTOOL_A_PLCA_VERSION, (u16)plca->version)) ||
> + (plca->enabled >= 0 &&
> + nla_put_u8(skb, ETHTOOL_A_PLCA_ENABLED, !!plca->enabled)) ||
> + (plca->node_id >= 0 &&
> + nla_put_u8(skb, ETHTOOL_A_PLCA_NODE_ID, (u8)plca->node_id)) ||
> + (plca->node_cnt >= 0 &&
> + nla_put_u8(skb, ETHTOOL_A_PLCA_NODE_CNT, (u8)plca->node_cnt)) ||
> + (plca->to_tmr >= 0 &&
> + nla_put_u8(skb, ETHTOOL_A_PLCA_TO_TMR, (u8)plca->to_tmr)) ||
> + (plca->burst_cnt >= 0 &&
> + nla_put_u8(skb, ETHTOOL_A_PLCA_BURST_CNT, (u8)plca->burst_cnt)) ||
> + (plca->burst_tmr >= 0 &&
> + nla_put_u8(skb, ETHTOOL_A_PLCA_BURST_TMR, (u8)plca->burst_tmr)))
> + return -EMSGSIZE;
> +
> + return 0;
> +};
> +
> +const struct ethnl_request_ops ethnl_plca_cfg_request_ops = {
> + .request_cmd = ETHTOOL_MSG_PLCA_GET_CFG,
> + .reply_cmd = ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
> + .hdr_attr = ETHTOOL_A_PLCA_HEADER,
> + .req_info_size = sizeof(struct plca_req_info),
> + .reply_data_size = sizeof(struct plca_reply_data),
> +
> + .prepare_data = plca_get_cfg_prepare_data,
> + .reply_size = plca_get_cfg_reply_size,
> + .fill_reply = plca_get_cfg_fill_reply,
> +};
> +
> +// PLCA set configuration message ------------------------------------------- //
> +
> +const struct nla_policy ethnl_plca_set_cfg_policy[] = {
> + [ETHTOOL_A_PLCA_HEADER] =
> + NLA_POLICY_NESTED(ethnl_header_policy),
> + [ETHTOOL_A_PLCA_ENABLED] = { .type = NLA_U8 },
> + [ETHTOOL_A_PLCA_NODE_ID] = { .type = NLA_U8 },
> + [ETHTOOL_A_PLCA_NODE_CNT] = { .type = NLA_U8 },
> + [ETHTOOL_A_PLCA_TO_TMR] = { .type = NLA_U8 },
> + [ETHTOOL_A_PLCA_BURST_CNT] = { .type = NLA_U8 },
> + [ETHTOOL_A_PLCA_BURST_TMR] = { .type = NLA_U8 },
> +};
> +
> +int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info)
> +{
> + struct ethnl_req_info req_info = {};
> + struct nlattr **tb = info->attrs;
> + const struct ethtool_phy_ops *ops;
> + struct phy_plca_cfg plca_cfg;
> + struct net_device *dev;
> +
> + bool mod = false;
> + int ret;
> +
> + ret = ethnl_parse_header_dev_get(&req_info,
> + tb[ETHTOOL_A_PLCA_HEADER],
> + genl_info_net(info), info->extack,
> + true);
> + if (ret < 0)
> + return ret;
> +
> + dev = req_info.dev;
> +
> + // check that the PHY device is available and connected
> + if (!dev->phydev) {
> + ret = -EOPNOTSUPP;
> + goto out;
> + }
> +
> + rtnl_lock();
> +
> + ops = ethtool_phy_ops;
> + if (!ops || !ops->set_plca_cfg) {
> + ret = -EOPNOTSUPP;
> + goto out_rtnl;
> + }
> +
> + ret = ethnl_ops_begin(dev);
> + if (ret < 0)
> + goto out_rtnl;
> +
> + memset(&plca_cfg, 0xFF, sizeof(plca_cfg));
> +
> + if (tb[ETHTOOL_A_PLCA_ENABLED]) {
> + plca_cfg.enabled = !!nla_get_u8(tb[ETHTOOL_A_PLCA_ENABLED]);
> + mod = true;
> + }
> +
> + if (tb[ETHTOOL_A_PLCA_NODE_ID]) {
> + plca_cfg.node_id = nla_get_u8(tb[ETHTOOL_A_PLCA_NODE_ID]);
> + mod = true;
> + }
> +
> + if (tb[ETHTOOL_A_PLCA_NODE_CNT]) {
> + plca_cfg.node_cnt = nla_get_u8(tb[ETHTOOL_A_PLCA_NODE_CNT]);
> + mod = true;
> + }
> +
> + if (tb[ETHTOOL_A_PLCA_TO_TMR]) {
> + plca_cfg.to_tmr = nla_get_u8(tb[ETHTOOL_A_PLCA_TO_TMR]);
> + mod = true;
> + }
> +
> + if (tb[ETHTOOL_A_PLCA_BURST_CNT]) {
> + plca_cfg.burst_cnt = nla_get_u8(tb[ETHTOOL_A_PLCA_BURST_CNT]);
> + mod = true;
> + }
> +
> + if (tb[ETHTOOL_A_PLCA_BURST_TMR]) {
> + plca_cfg.burst_tmr = nla_get_u8(tb[ETHTOOL_A_PLCA_BURST_TMR]);
> + mod = true;
> + }
> +
> + ret = 0;
> + if (!mod)
> + goto out_ops;
> +
> + ret = ops->set_plca_cfg(dev->phydev, info->extack, &plca_cfg);
> +
> + if (ret < 0)
> + goto out_ops;
> +
> + ethtool_notify(dev, ETHTOOL_MSG_PLCA_NTF, NULL);
> +
> +out_ops:
> + ethnl_ops_complete(dev);
> +out_rtnl:
> + rtnl_unlock();
> + ethnl_parse_header_dev_put(&req_info);
> +out:
> + return ret;
> +}
> +
> +// PLCA get status message -------------------------------------------------- //
> +
> +const struct nla_policy ethnl_plca_get_status_policy[] = {
> + [ETHTOOL_A_PLCA_HEADER] =
> + NLA_POLICY_NESTED(ethnl_header_policy),
> +};
> +
> +static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
> + struct ethnl_reply_data *reply_base,
> + struct genl_info *info)
> +{
> + struct plca_reply_data *data = PLCA_REPDATA(reply_base);
> + struct net_device *dev = reply_base->dev;
> + const struct ethtool_phy_ops *ops;
> + int ret;
> +
> + // check that the PHY device is available and connected
> + if (!dev->phydev) {
> + ret = -EOPNOTSUPP;
> + goto out;
> + }
> +
> + // note: rtnl_lock is held already by ethnl_default_doit
> + ops = ethtool_phy_ops;
> + if (!ops || !ops->get_plca_status) {
> + ret = -EOPNOTSUPP;
> + goto out;
> + }
> +
> + ret = ethnl_ops_begin(dev);
> + if (ret < 0)
> + goto out;
> +
> + ret = ops->get_plca_status(dev->phydev, &data->plca_st);
> + if (ret < 0)
> + goto out;
> +
> + ethnl_ops_complete(dev);
> +out:
> + return ret;
> +}
> +
> +static int plca_get_status_reply_size(const struct ethnl_req_info *req_base,
> + const struct ethnl_reply_data *reply_base)
> +{
> + return nla_total_size(sizeof(u8)); /* _STATUS */
> +}
> +
> +static int plca_get_status_fill_reply(struct sk_buff *skb,
> + const struct ethnl_req_info *req_base,
> + const struct ethnl_reply_data *reply_base)
> +{
> + const struct plca_reply_data *data = PLCA_REPDATA(reply_base);
> + const u8 status = data->plca_st.pst;
> +
> + if (nla_put_u8(skb, ETHTOOL_A_PLCA_STATUS, !!status))
> + return -EMSGSIZE;
> +
> + return 0;
> +};
> +
> +const struct ethnl_request_ops ethnl_plca_status_request_ops = {
> + .request_cmd = ETHTOOL_MSG_PLCA_GET_STATUS,
> + .reply_cmd = ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
> + .hdr_attr = ETHTOOL_A_PLCA_HEADER,
> + .req_info_size = sizeof(struct plca_req_info),
> + .reply_data_size = sizeof(struct plca_reply_data),
> +
> + .prepare_data = plca_get_status_prepare_data,
> + .reply_size = plca_get_status_reply_size,
> + .fill_reply = plca_get_status_fill_reply,
> +};
> --
> 2.35.1
>
>

--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |

2022-12-05 09:49:28

by Piergiorgio Beruto

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

On Mon, Dec 05, 2022 at 09:28:51AM +0000, Russell King (Oracle) wrote:
> On Mon, Dec 05, 2022 at 02:41:35AM +0100, Piergiorgio Beruto wrote:
> > +int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info)
> > +{
> > + struct ethnl_req_info req_info = {};
> > + struct nlattr **tb = info->attrs;
> > + const struct ethtool_phy_ops *ops;
> > + struct phy_plca_cfg plca_cfg;
> > + struct net_device *dev;
> > +
> > + bool mod = false;
> > + int ret;
> > +
> > + ret = ethnl_parse_header_dev_get(&req_info,
> > + tb[ETHTOOL_A_PLCA_HEADER],
> > + genl_info_net(info), info->extack,
> > + true);
> > + if (ret < 0)
> > + return ret;
> > +
> > + dev = req_info.dev;
> > +
> > + // check that the PHY device is available and connected
> > + if (!dev->phydev) {
> > + ret = -EOPNOTSUPP;
> > + goto out;
> > + }
>
> This check should really be done under the RTNL lock. phydevs can come
> and go with SFP cages.
>
> > +
> > + rtnl_lock();
Good point Russell, I'll fix that. And I wish to seize the opportunity
to remark that the same problem may be present in cabletest.c
(see below).

Maybe we should post a patch to fix that?

Thanks,
Piergiorgio

int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
{
struct ethnl_req_info req_info = {};
const struct ethtool_phy_ops *ops;
struct nlattr **tb = info->attrs;
struct net_device *dev;
int ret;

ret = ethnl_parse_header_dev_get(&req_info,
tb[ETHTOOL_A_CABLE_TEST_HEADER],
genl_info_net(info), info->extack,
true);
if (ret < 0)
return ret;

dev = req_info.dev;
if (!dev->phydev) {
ret = -EOPNOTSUPP;
goto out_dev_put;
}

rtnl_lock();

2022-12-05 09:49:35

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

On Mon, Dec 05, 2022 at 02:41:35AM +0100, Piergiorgio Beruto wrote:
> +int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info)
> +{
> + struct ethnl_req_info req_info = {};
> + struct nlattr **tb = info->attrs;
> + const struct ethtool_phy_ops *ops;
> + struct phy_plca_cfg plca_cfg;
> + struct net_device *dev;
> +
> + bool mod = false;
> + int ret;
> +
> + ret = ethnl_parse_header_dev_get(&req_info,
> + tb[ETHTOOL_A_PLCA_HEADER],
> + genl_info_net(info), info->extack,
> + true);
> + if (ret < 0)
> + return ret;
> +
> + dev = req_info.dev;
> +
> + // check that the PHY device is available and connected
> + if (!dev->phydev) {
> + ret = -EOPNOTSUPP;
> + goto out;
> + }

This check should really be done under the RTNL lock. phydevs can come
and go with SFP cages.

> +
> + rtnl_lock();

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

2022-12-05 10:51:13

by Oleksij Rempel

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

On Mon, Dec 05, 2022 at 11:03:58AM +0100, Piergiorgio Beruto wrote:
> Hello Oleksij, and thank you for your review!
> Please see my comments below.
>
> On Mon, Dec 05, 2022 at 07:00:57AM +0100, Oleksij Rempel wrote:
> > > diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
> > > index aaf7c6963d61..81e3d7b42d0f 100644
> > > --- a/include/uapi/linux/ethtool_netlink.h
> > > +++ b/include/uapi/linux/ethtool_netlink.h
> > > @@ -51,6 +51,9 @@ enum {
> > > ETHTOOL_MSG_MODULE_SET,
> > > ETHTOOL_MSG_PSE_GET,
> > > ETHTOOL_MSG_PSE_SET,
> > > + ETHTOOL_MSG_PLCA_GET_CFG,
> > > + ETHTOOL_MSG_PLCA_SET_CFG,
> > > + ETHTOOL_MSG_PLCA_GET_STATUS,
> > >
> > > /* add new constants above here */
> > > __ETHTOOL_MSG_USER_CNT,
> > > @@ -97,6 +100,9 @@ enum {
> > > ETHTOOL_MSG_MODULE_GET_REPLY,
> > > ETHTOOL_MSG_MODULE_NTF,
> > > ETHTOOL_MSG_PSE_GET_REPLY,
> > > + ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
> > > + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
> > > + ETHTOOL_MSG_PLCA_NTF,
> > >
> > > /* add new constants above here */
> > > __ETHTOOL_MSG_KERNEL_CNT,
> > > @@ -880,6 +886,25 @@ enum {
> > > ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
> > > };
> > >
> > > +/* PLCA */
> > > +
> >
> > Please use names used in the specification as close as possible and
> > document in comments real specification names.
> I was actually following the names in the OPEN Alliance SIG
> specifications which I referenced. Additionally, the OPEN names are more
> similar to those that you can find in Clause 147. As I was trying to
> explain in other threads, the names in Clause 30 were sort of a workaround
> because we were not allowed to add registers in Clause 45.
>
> I can change the names if you really want to, but I'm inclined to keep
> it simple and "user-friendly". People using this technology are more
> used to these names, and they totally ignore Clause 30.
>
> Please, let me know what you think.

A comment about name mapping to specification, spec version and reason
to take one variants instead of other one will be enough Somewhat similar to
what i did for PoDL. See ETHTOOL_A_PODL_* in
Documentation/networking/ethtool-netlink.rst and include/uapi/linux/ethtool.h

It will help people who use spec to review or extend this UAPI.

> > > +
> > > + /* add new constants above here */
> > > + __ETHTOOL_A_PLCA_CNT,
> > > + ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
> > > +};
> >
> > Should we have access to 30.16.1.2.2 acPLCAReset in user space?
> I omitted that parameter on purpose. The reason is that again, we were
> "forced" to do this in IEEE802.3cg, but it was a poor choice. I
> understand purity of the specifications, but in the real-world where
> PLCA is implemented in the PHY, resetting the PLCA layer independently
> of the PCS/PMA is all but a good idea: it does more harm than good. As a
> matter of fact, PHY vendors typically map the PLCA reset bit to the PHY
> soft reset bit, or at least to the PCS reset bit.
>
> I'm inclined to keep this as-is and see in the future if and why someone
> would need this feature. What you think?

Ok. Sounds good.

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 |

2022-12-05 10:54:50

by Piergiorgio Beruto

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

Hello Oleksij, and thank you for your review!
Please see my comments below.

On Mon, Dec 05, 2022 at 07:00:57AM +0100, Oleksij Rempel wrote:
> > diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
> > index aaf7c6963d61..81e3d7b42d0f 100644
> > --- a/include/uapi/linux/ethtool_netlink.h
> > +++ b/include/uapi/linux/ethtool_netlink.h
> > @@ -51,6 +51,9 @@ enum {
> > ETHTOOL_MSG_MODULE_SET,
> > ETHTOOL_MSG_PSE_GET,
> > ETHTOOL_MSG_PSE_SET,
> > + ETHTOOL_MSG_PLCA_GET_CFG,
> > + ETHTOOL_MSG_PLCA_SET_CFG,
> > + ETHTOOL_MSG_PLCA_GET_STATUS,
> >
> > /* add new constants above here */
> > __ETHTOOL_MSG_USER_CNT,
> > @@ -97,6 +100,9 @@ enum {
> > ETHTOOL_MSG_MODULE_GET_REPLY,
> > ETHTOOL_MSG_MODULE_NTF,
> > ETHTOOL_MSG_PSE_GET_REPLY,
> > + ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
> > + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
> > + ETHTOOL_MSG_PLCA_NTF,
> >
> > /* add new constants above here */
> > __ETHTOOL_MSG_KERNEL_CNT,
> > @@ -880,6 +886,25 @@ enum {
> > ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
> > };
> >
> > +/* PLCA */
> > +
>
> Please use names used in the specification as close as possible and
> document in comments real specification names.
I was actually following the names in the OPEN Alliance SIG
specifications which I referenced. Additionally, the OPEN names are more
similar to those that you can find in Clause 147. As I was trying to
explain in other threads, the names in Clause 30 were sort of a workaround
because we were not allowed to add registers in Clause 45.

I can change the names if you really want to, but I'm inclined to keep
it simple and "user-friendly". People using this technology are more
used to these names, and they totally ignore Clause 30.

Please, let me know what you think.

> > +
> > + /* add new constants above here */
> > + __ETHTOOL_A_PLCA_CNT,
> > + ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
> > +};
>
> Should we have access to 30.16.1.2.2 acPLCAReset in user space?
I omitted that parameter on purpose. The reason is that again, we were
"forced" to do this in IEEE802.3cg, but it was a poor choice. I
understand purity of the specifications, but in the real-world where
PLCA is implemented in the PHY, resetting the PLCA layer independently
of the PCS/PMA is all but a good idea: it does more harm than good. As a
matter of fact, PHY vendors typically map the PLCA reset bit to the PHY
soft reset bit, or at least to the PCS reset bit.

I'm inclined to keep this as-is and see in the future if and why someone
would need this feature. What you think?

Thanks,
Piergiorgio

2022-12-05 13:44:34

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

On Mon, Dec 05, 2022 at 07:00:57AM +0100, Oleksij Rempel wrote:
> Hi Beruto,

> On Mon, Dec 05, 2022 at 02:41:35AM +0100, Piergiorgio Beruto wrote:
> > Add support for configuring the PLCA Reconciliation Sublayer on
> > multi-drop PHYs that support IEEE802.3cg-2019 Clause 148 (e.g.,
> > 10BASE-T1S). This patch adds the appropriate netlink interface
> > to ethtool.
> >
> > Signed-off-by: Piergiorgio Beruto <[email protected]>
> > ---
> > MAINTAINERS | 6 +
> > drivers/net/phy/phy.c | 34 ++++
> > drivers/net/phy/phy_device.c | 3 +
> > include/linux/ethtool.h | 11 +
> > include/linux/phy.h | 64 ++++++
> > include/uapi/linux/ethtool_netlink.h | 25 +++
> > net/ethtool/Makefile | 2 +-
> > net/ethtool/netlink.c | 30 +++
> > net/ethtool/netlink.h | 6 +
> > net/ethtool/plca.c | 290 +++++++++++++++++++++++++++
> > 10 files changed, 470 insertions(+), 1 deletion(-)
> > create mode 100644 net/ethtool/plca.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 955c1be1efb2..7952243e4b43 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -16396,6 +16396,12 @@ S: Maintained
> > F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
> > F: drivers/iio/chemical/pms7003.c
> >
> > +PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148)
> > +M: Piergiorgio Beruto <[email protected]>
> > +L: [email protected]
> > +S: Maintained
> > +F: net/ethtool/plca.c
> > +
> > PLDMFW LIBRARY
> > M: Jacob Keller <[email protected]>
> > S: Maintained
> > diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> > index e5b6cb1a77f9..99e3497b6aa1 100644
> > --- a/drivers/net/phy/phy.c
> > +++ b/drivers/net/phy/phy.c
> > @@ -543,6 +543,40 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
> > }
> > EXPORT_SYMBOL(phy_ethtool_get_stats);
> >
> > +/**
> > + *
> > + */
> > +int phy_ethtool_get_plca_cfg(struct phy_device *dev,
> > + struct phy_plca_cfg *plca_cfg)
> > +{
> > + // TODO
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(phy_ethtool_get_plca_cfg);
> > +
> > +/**
> > + *
> > + */
> > +int phy_ethtool_set_plca_cfg(struct phy_device *dev,
> > + struct netlink_ext_ack *extack,
> > + const struct phy_plca_cfg *plca_cfg)
> > +{
> > + // TODO
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(phy_ethtool_set_plca_cfg);
> > +
> > +/**
> > + *
> > + */
> > +int phy_ethtool_get_plca_status(struct phy_device *dev,
> > + struct phy_plca_status *plca_st)
> > +{
> > + // TODO
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(phy_ethtool_get_plca_status);
> > +
> > /**
> > * phy_start_cable_test - Start a cable test
> > *
> > diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
> > index 716870a4499c..f248010c403d 100644
> > --- a/drivers/net/phy/phy_device.c
> > +++ b/drivers/net/phy/phy_device.c
> > @@ -3262,6 +3262,9 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
> > .get_sset_count = phy_ethtool_get_sset_count,
> > .get_strings = phy_ethtool_get_strings,
> > .get_stats = phy_ethtool_get_stats,
> > + .get_plca_cfg = phy_ethtool_get_plca_cfg,
> > + .set_plca_cfg = phy_ethtool_set_plca_cfg,
> > + .get_plca_status = phy_ethtool_get_plca_status,
> > .start_cable_test = phy_start_cable_test,
> > .start_cable_test_tdr = phy_start_cable_test_tdr,
> > };
> > diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
> > index 9e0a76fc7de9..4bfe95ec1f0a 100644
> > --- a/include/linux/ethtool.h
> > +++ b/include/linux/ethtool.h
> > @@ -802,12 +802,16 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev,
> >
> > struct phy_device;
> > struct phy_tdr_config;
> > +struct phy_plca_cfg;
> > +struct phy_plca_status;
> >
> > /**
> > * struct ethtool_phy_ops - Optional PHY device options
> > * @get_sset_count: Get number of strings that @get_strings will write.
> > * @get_strings: Return a set of strings that describe the requested objects
> > * @get_stats: Return extended statistics about the PHY device.
> > + * @get_plca_cfg: Return PLCA configuration.
> > + * @set_plca_cfg: Set PLCA configuration.
> > * @start_cable_test: Start a cable test
> > * @start_cable_test_tdr: Start a Time Domain Reflectometry cable test
> > *
> > @@ -819,6 +823,13 @@ struct ethtool_phy_ops {
> > int (*get_strings)(struct phy_device *dev, u8 *data);
> > int (*get_stats)(struct phy_device *dev,
> > struct ethtool_stats *stats, u64 *data);
> > + int (*get_plca_cfg)(struct phy_device *dev,
> > + struct phy_plca_cfg *plca_cfg);
> > + int (*set_plca_cfg)(struct phy_device *dev,
> > + struct netlink_ext_ack *extack,
> > + const struct phy_plca_cfg *plca_cfg);
> > + int (*get_plca_status)(struct phy_device *dev,
> > + struct phy_plca_status *plca_st);
> > int (*start_cable_test)(struct phy_device *phydev,
> > struct netlink_ext_ack *extack);
> > int (*start_cable_test_tdr)(struct phy_device *phydev,
> > diff --git a/include/linux/phy.h b/include/linux/phy.h
> > index 71eeb4e3b1fd..ab2c134d0a05 100644
> > --- a/include/linux/phy.h
> > +++ b/include/linux/phy.h
> > @@ -765,6 +765,63 @@ struct phy_tdr_config {
> > };
> > #define PHY_PAIR_ALL -1
> >
> > +/**
> > + * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
> > + * Avoidance) Reconciliation Sublayer.
> > + *
> > + * @version: read-only PLCA register map version. 0 = not available. Ignored
> > + * when setting the configuration. Format is the same as reported by the PLCA
> > + * IDVER register (31.CA00). -1 = not available.
> > + * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't
> > + * set. 0 = disabled, anything else = enabled.
> > + * @node_id: the PLCA local node identifier. -1 = not available / don't set.
> > + * Allowed values [0 .. 254]. 255 = node disabled.
> > + * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only
> > + * meaningful for the coordinator (node_id = 0). -1 = not available / don't
> > + * set. Allowed values [0 .. 255].
> > + * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the
> > + * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for
> > + * more details. The to_timer shall be set equal over all nodes.
> > + * -1 = not available / don't set. Allowed values [0 .. 255].
> > + * @burst_cnt: controls how many additional frames a node is allowed to send in
> > + * single transmit opportunity (TO). The default value of 0 means that the
> > + * node is allowed exactly one frame per TO. A value of 1 allows two frames
> > + * per TO, and so on. -1 = not available / don't set.
> > + * Allowed values [0 .. 255].
> > + * @burst_tmr: controls how many bit times to wait for the MAC to send a new
> > + * frame before interrupting the burst. This value should be set to a value
> > + * greater than the MAC inter-packet gap (which is typically 96 bits).
> > + * -1 = not available / don't set. Allowed values [0 .. 255].
> > + *
> > + * A structure containing configuration parameters for setting/getting the PLCA
> > + * RS configuration. The driver does not need to implement all the parameters,
> > + * but should report what is actually used.
> > + */
> > +struct phy_plca_cfg {
> > + s32 version;
> > + s16 enabled;
> > + s16 node_id;
> > + s16 node_cnt;
> > + s16 to_tmr;
> > + s16 burst_cnt;
> > + s16 burst_tmr;
> > +};
> > +
> > +/**
> > + * struct phy_plca_status - Status of the PLCA (Physical Layer Collision
> > + * Avoidance) Reconciliation Sublayer.
> > + *
> > + * @pst: The PLCA status as reported by the PST bit in the PLCA STATUS
> > + * register(31.CA03), indicating BEACON activity.
> > + *
> > + * A structure containing status information of the PLCA RS configuration.
> > + * The driver does not need to implement all the parameters, but should report
> > + * what is actually used.
> > + */
> > +struct phy_plca_status {
> > + bool pst;
> > +};
> > +
> > /**
> > * struct phy_driver - Driver structure for a particular PHY type
> > *
> > @@ -1775,6 +1832,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
> > int phy_ethtool_get_sset_count(struct phy_device *phydev);
> > int phy_ethtool_get_stats(struct phy_device *phydev,
> > struct ethtool_stats *stats, u64 *data);
> > +int phy_ethtool_get_plca_cfg(struct phy_device *dev,
> > + struct phy_plca_cfg *plca_cfg);
> > +int phy_ethtool_set_plca_cfg(struct phy_device *dev,
> > + struct netlink_ext_ack *extack,
> > + const struct phy_plca_cfg *plca_cfg);
> > +int phy_ethtool_get_plca_status(struct phy_device *dev,
> > + struct phy_plca_status *plca_st);
> >
> > static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
> > {
> > diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
> > index aaf7c6963d61..81e3d7b42d0f 100644
> > --- a/include/uapi/linux/ethtool_netlink.h
> > +++ b/include/uapi/linux/ethtool_netlink.h
> > @@ -51,6 +51,9 @@ enum {
> > ETHTOOL_MSG_MODULE_SET,
> > ETHTOOL_MSG_PSE_GET,
> > ETHTOOL_MSG_PSE_SET,
> > + ETHTOOL_MSG_PLCA_GET_CFG,
> > + ETHTOOL_MSG_PLCA_SET_CFG,
> > + ETHTOOL_MSG_PLCA_GET_STATUS,
> >
> > /* add new constants above here */
> > __ETHTOOL_MSG_USER_CNT,
> > @@ -97,6 +100,9 @@ enum {
> > ETHTOOL_MSG_MODULE_GET_REPLY,
> > ETHTOOL_MSG_MODULE_NTF,
> > ETHTOOL_MSG_PSE_GET_REPLY,
> > + ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
> > + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
> > + ETHTOOL_MSG_PLCA_NTF,
> >
> > /* add new constants above here */
> > __ETHTOOL_MSG_KERNEL_CNT,
> > @@ -880,6 +886,25 @@ enum {
> > ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
> > };
> >
> > +/* PLCA */
> > +

Hi Oleksij

Please trim the text when replying. It is possible to miss comments
when having to page down, page down, page down all the time.

Thanks
Andrew

2022-12-05 13:44:54

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

> Good point Russell, I'll fix that. And I wish to seize the opportunity
> to remark that the same problem may be present in cabletest.c
> (see below).
>
> Maybe we should post a patch to fix that?

Thanks for pointing this out. I will fix it, and take a look to see if
the same problem exists anywhere else.

Andrew

2022-12-05 14:27:41

by Piergiorgio Beruto

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

On Mon, Dec 05, 2022 at 11:22:09AM +0100, Oleksij Rempel wrote:
> A comment about name mapping to specification, spec version and reason
> to take one variants instead of other one will be enough Somewhat similar to
> what i did for PoDL. See ETHTOOL_A_PODL_* in
> Documentation/networking/ethtool-netlink.rst and include/uapi/linux/ethtool.h
>
> It will help people who use spec to review or extend this UAPI.
What about the following? This is the first time I write the
documentation in this format, hence I would appreciate if you could give
me some feedback prior to regenerating the patches.

Thanks!
Piergiorgio

diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index bede24ef44fd..85a7fd6399cb 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1687,6 +1687,136 @@ to control PoDL PSE Admin functions. This option is implementing
``IEEE 802.3-2018`` 30.15.1.2.1 acPoDLPSEAdminControl. See
``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` for supported values.

+PLCA_GET_CFG
+=======
+
+Gets PLCA RS attributes.
+
+Request contents:
+
+ ===================================== ====== ==========================
+ ``ETHTOOL_A_PLCA_HEADER`` nested request header
+ ===================================== ====== ==========================
+
+Kernel response contents:
+
+ ====================================== ====== =============================
+ ``ETHTOOL_A_PLCA_HEADER`` nested reply header
+ ``ETHTOOL_A_PLCA_VERSION`` u16 Supported PLCA management
+ interface standard/version
+ ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State
+ ``ETHTOOL_A_PLCA_NODE_ID`` u8 PLCA unique local node ID
+ ``ETHTOOL_A_PLCA_NODE_CNT`` u8 Number of PLCA nodes on the
+ netkork, including the
+ coordinator
+ ``ETHTOOL_A_PLCA_TO_TMR`` u8 Transmit Opportunity Timer
+ value in bit-times (BT)
+ ``ETHTOOL_A_PLCA_BURST_CNT`` u8 Number of additional packets
+ the node is allowed to send
+ within a single TO
+ ``ETHTOOL_A_PLCA_BURST_TMR`` u8 Time to wait for the MAC to
+ transmit a new frame before
+ terminating the burst
+ ====================================== ====== =============================
+
+When set, the optional ``ETHTOOL_A_PLCA_VERSION`` attribute indicates which
+standard and version the PLCA management interface complies to. When not set,
+the interface is vendor-specific and (possibly) supplied by the driver.
+The OPEN Alliance SIG specifies a standard register map for 10BASE-T1S PHYs
+embedding the PLCA Reconcialiation Sublayer. See "10BASE-T1S PLCA Management
+Registers" at https://www.opensig.org/about/specifications/. When this standard
+is supported, ETHTOOL_A_PLCA_VERSION is reported as 0Axx where 'xx' denotes the
+map version (see Table A.1.0 — IDVER bits assignment).
+
+When set, the optional ``ETHTOOL_A_PLCA_ENABLED`` attribute indicates the
+administrative state of the PLCA RS. When not set, the node operates in "plain"
+CSMA/CD mode. This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.1
+aPLCAAdminState / 30.16.1.2.1 acPLCAAdminControl.
+
+When set, the optional ``ETHTOOL_A_PLCA_NODE_ID`` attribute indicates the
+configured local node ID of the PHY. This ID determines which transmit
+opportunity (TO) is reseverd for the node to transmit into. This option is
+corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.4 aPLCALocalNodeID.
+
+When set, the optional ``ETHTOOL_A_PLCA_NODE_CNT`` attribute indicates the
+configured maximum number of PLCA nodes on the mixing-segment. This number
+determines the total number of transmit opportunities generated during a
+PLCA cycle. This attribute is relevant only for the PLCA coordinator, which is
+the node with aPLCALocalNodeID set to 0. Follower nodes ignore this setting.
+This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.3
+aPLCANodeCount.
+
+When set, the optional ``ETHTOOL_A_PLCA_TO_TMR`` attribute indicates the
+configured value of the transmit opportunity timer in bit-times. This value
+must be set equal across all nodes sharing the medium for PLCA to work
+correctly. This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.5
+aPLCATransmitOpportunityTimer.
+
+When set, the optional ``ETHTOOL_A_PLCA_BURST_CNT`` attribute indicates the
+configured number of extra packets that the node is allowed to send during a
+single transmit opportunity. By default, this attribute is 0, meaning that
+the node can only send a sigle frame per TO. When greater than 0, the PLCA RS
+keeps the TO after any transmission, waiting for the MAC to send a new frame
+for up to aPLCABurstTimer BTs. This can only happen a number of times per PLCA
+cycle up to the value of this parameter. After that, the burst is over and the
+normal counting of TOs resumes. This option is corresponding to
+``IEEE 802.3cg-2019`` 30.16.1.1.6 aPLCAMaxBurstCount.
+
+When set, the optional ``ETHTOOL_A_PLCA_BURST_TMR`` attribute indicates how
+many bit-times the PLCA RS waits for the MAC to initiate a new transmission
+when aPLCAMaxBurstCount is greater than 0. If the MAC fails to send a new
+frame within this time, the burst ends and the counting of TOs resumes.
+Otherwise, the new frame is sent as part of the current burst. This option
+is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.7 aPLCABurstTimer.
+
+PLCA_SET_CFG
+=======
+
+Sets PLCA RS parameters.
+
+Request contents:
+
+ ====================================== ====== =============================
+ ``ETHTOOL_A_PLCA_HEADER`` nested request header
+ ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State
+ ``ETHTOOL_A_PLCA_NODE_ID`` u8 PLCA unique local node ID
+ ``ETHTOOL_A_PLCA_NODE_CNT`` u8 Number of PLCA nodes on the
+ netkork, including the
+ coordinator
+ ``ETHTOOL_A_PLCA_TO_TMR`` u8 Transmit Opportunity Timer
+ value in bit-times (BT)
+ ``ETHTOOL_A_PLCA_BURST_CNT`` u8 Number of additional packets
+ the node is allowed to send
+ within a single TO
+ ``ETHTOOL_A_PLCA_BURST_TMR`` u8 Time to wait for the MAC to
+ transmit a new frame before
+ terminating the burst
+ ====================================== ====== =============================
+
+For a description of each attribute, see ``PLCA_GET_CFG``.
+
+PLCA_GET_STATUS
+=======
+
+Gets PLCA RS status information.
+
+Request contents:
+
+ ===================================== ====== ==========================
+ ``ETHTOOL_A_PLCA_HEADER`` nested request header
+ ===================================== ====== ==========================
+
+Kernel response contents:
+
+ ====================================== ====== =============================
+ ``ETHTOOL_A_PLCA_HEADER`` nested reply header
+ ``ETHTOOL_A_PLCA_STATUS`` u8 PLCA RS operational status
+ ====================================== ====== =============================
+
+When set, the ``ETHTOOL_A_PLCA_STATUS`` attribute indicates whether the node is
+detecting the presence of the BEACON on the network. This flag is
+corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.2 aPLCAStatus.
+
Request translation
===================

@@ -1788,4 +1918,7 @@ are netlink only.
n/a ``ETHTOOL_MSG_PHC_VCLOCKS_GET``
n/a ``ETHTOOL_MSG_MODULE_GET``
n/a ``ETHTOOL_MSG_MODULE_SET``
+ n/a ``ETHTOOL_MSG_PLCA_GET_CFG``
+ n/a ``ETHTOOL_MSG_PLCA_SET_CFG``
+ n/a ``ETHTOOL_MSG_PLCA_GET_STATUS``
=================================== =====================================

2022-12-05 15:46:35

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH v2 net-next 1/4] net/ethtool: add netlink interface for the PLCA RS

> +PLCA_GET_CFG
> +=======

You probably get a warning from this. The === needs to be as long as
what it underlines.

> +
> +Gets PLCA RS attributes.
> +
> +Request contents:
> +
> + ===================================== ====== ==========================
> + ``ETHTOOL_A_PLCA_HEADER`` nested request header
> + ===================================== ====== ==========================
> +
> +Kernel response contents:
> +
> + ====================================== ====== =============================
> + ``ETHTOOL_A_PLCA_HEADER`` nested reply header
> + ``ETHTOOL_A_PLCA_VERSION`` u16 Supported PLCA management
> + interface standard/version
> + ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State
> + ``ETHTOOL_A_PLCA_NODE_ID`` u8 PLCA unique local node ID
> + ``ETHTOOL_A_PLCA_NODE_CNT`` u8 Number of PLCA nodes on the
> + netkork, including the
> + coordinator

tabs vs spaces. The indentation needs to be correct here or you will
get warnings when the documentation is built.

You can build the documentation with

make htmldocs

Not looked at the actual contents yet, just the markup.

Andrew