Thread (24 messages) 24 messages, 4 authors, 2026-03-27
STALE106d
Revisions (2)
  1. v1 [diff vs current]
  2. v2 current

[PATCH net-next v2 02/12] ethtool: Convert per-PHY commands to dump_one_dev

From: Björn Töpel <bjorn@kernel.org>
Date: 2026-03-25 14:50:46
Also in: linux-kselftest, linux-rdma, lkml
Subsystem: networking [ethtool phy topology], networking [ethtool], networking [general], plca reconciliation sublayer (ieee802.3 clause 148), pse network driver, the rest · Maintainers: Maxime Chevallier, Andrew Lunn, Jakub Kicinski, "David S. Miller", Eric Dumazet, Paolo Abeni, Piergiorgio Beruto, Oleksij Rempel, Kory Maincent, Linus Torvalds

Convert PSE, PLCA, PHY, and MSE commands from the separate
ethnl_perphy_{start,dumpit,done} handlers to use the generic
dump_one_dev callback. This removes the per-PHY specific dump
infrastructure (ethnl_perphy_dump_ctx, ethnl_perphy_dump_context,
ethnl_perphy_start, ethnl_perphy_dumpit, ethnl_perphy_done, and the
internal helpers) in favor of a shared ethnl_perphy_dump_one_dev()
function.

Signed-off-by: Björn Töpel <bjorn@kernel.org>
---
 net/ethtool/mse.c     |   1 +
 net/ethtool/netlink.c | 194 ++++++------------------------------------
 net/ethtool/netlink.h |   4 +
 net/ethtool/phy.c     |   1 +
 net/ethtool/plca.c    |   2 +
 net/ethtool/pse-pd.c  |   1 +
 6 files changed, 35 insertions(+), 168 deletions(-)
diff --git a/net/ethtool/mse.c b/net/ethtool/mse.c
index e91b74430f76..3f33182283ce 100644
--- a/net/ethtool/mse.c
+++ b/net/ethtool/mse.c
@@ -325,4 +325,5 @@ const struct ethnl_request_ops ethnl_mse_request_ops = {
 	.cleanup_data = mse_cleanup_data,
 	.reply_size = mse_reply_size,
 	.fill_reply = mse_fill_reply,
+	.dump_one_dev = ethnl_perphy_dump_one_dev,
 };
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 8d161f0882d0..edeeca67918a 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -399,12 +399,6 @@ static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
 	return (struct ethnl_dump_ctx *)cb->ctx;
 }
 
-static struct ethnl_perphy_dump_ctx *
-ethnl_perphy_dump_context(struct netlink_callback *cb)
-{
-	return (struct ethnl_perphy_dump_ctx *)cb->ctx;
-}
-
 /**
  * ethnl_default_parse() - Parse request message
  * @req_info:    pointer to structure to put data into
@@ -686,169 +680,33 @@ static int ethnl_default_start(struct netlink_callback *cb)
 	return ret;
 }
 
-/* per-PHY ->start() handler for GET requests */
-static int ethnl_perphy_start(struct netlink_callback *cb)
+/* Shared dump_one_dev for per-PHY commands (PSE, PLCA, PHY, MSE) */
+int ethnl_perphy_dump_one_dev(struct sk_buff *skb,
+			      struct ethnl_dump_ctx *ctx,
+			      unsigned long *pos_sub,
+			      const struct genl_info *info)
 {
-	struct ethnl_perphy_dump_ctx *phy_ctx = ethnl_perphy_dump_context(cb);
-	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
-	struct ethnl_dump_ctx *ctx = &phy_ctx->ethnl_ctx;
-	struct ethnl_reply_data *reply_data;
-	const struct ethnl_request_ops *ops;
-	struct ethnl_req_info *req_info;
-	struct genlmsghdr *ghdr;
-	int ret;
-
-	BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
-
-	ghdr = nlmsg_data(cb->nlh);
-	ops = ethnl_default_requests[ghdr->cmd];
-	if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd))
-		return -EOPNOTSUPP;
-	req_info = kzalloc(ops->req_info_size, GFP_KERNEL);
-	if (!req_info)
-		return -ENOMEM;
-	reply_data = kmalloc(ops->reply_data_size, GFP_KERNEL);
-	if (!reply_data) {
-		ret = -ENOMEM;
-		goto free_req_info;
-	}
-
-	/* Unlike per-dev dump, don't ignore dev. The dump handler
-	 * will notice it and dump PHYs from given dev. We only keep track of
-	 * the dev's ifindex, .dumpit() will grab and release the netdev itself.
-	 */
-	ret = ethnl_default_parse(req_info, &info->info, ops, false);
-	if (ret < 0)
-		goto free_reply_data;
-	if (req_info->dev) {
-		phy_ctx->ifindex = req_info->dev->ifindex;
-		netdev_put(req_info->dev, &req_info->dev_tracker);
-		req_info->dev = NULL;
-	}
-
-	ctx->ops = ops;
-	ctx->req_info = req_info;
-	ctx->reply_data = reply_data;
-	ctx->pos_ifindex = 0;
-
-	return 0;
-
-free_reply_data:
-	kfree(reply_data);
-free_req_info:
-	kfree(req_info);
-
-	return ret;
-}
-
-static int ethnl_perphy_dump_one_dev(struct sk_buff *skb,
-				     struct ethnl_perphy_dump_ctx *ctx,
-				     const struct genl_info *info)
-{
-	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
-	struct net_device *dev = ethnl_ctx->req_info->dev;
+	struct net_device *dev = ctx->req_info->dev;
 	struct phy_device_node *pdn;
 	int ret;
 
 	if (!dev->link_topo)
 		return 0;
 
-	xa_for_each_start(&dev->link_topo->phys, ctx->pos_phyindex, pdn,
-			  ctx->pos_phyindex) {
-		ethnl_ctx->req_info->phy_index = ctx->pos_phyindex;
+	xa_for_each_start(&dev->link_topo->phys, *pos_sub, pdn,
+			  *pos_sub) {
+		ctx->req_info->phy_index = *pos_sub;
 
 		/* We can re-use the original dump_one as ->prepare_data in
 		 * commands use ethnl_req_get_phydev(), which gets the PHY from
 		 * the req_info->phy_index
 		 */
-		ret = ethnl_default_dump_one(skb, dev, ethnl_ctx, info);
+		ret = ethnl_default_dump_one(skb, dev, ctx, info);
 		if (ret)
 			return ret;
 	}
 
-	ctx->pos_phyindex = 0;
-
-	return 0;
-}
-
-static int ethnl_perphy_dump_all_dev(struct sk_buff *skb,
-				     struct ethnl_perphy_dump_ctx *ctx,
-				     const struct genl_info *info)
-{
-	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
-	struct net *net = sock_net(skb->sk);
-	netdevice_tracker dev_tracker;
-	struct net_device *dev;
-	int ret = 0;
-
-	rcu_read_lock();
-	for_each_netdev_dump(net, dev, ethnl_ctx->pos_ifindex) {
-		netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
-		rcu_read_unlock();
-
-		/* per-PHY commands use ethnl_req_get_phydev(), which needs the
-		 * net_device in the req_info
-		 */
-		ethnl_ctx->req_info->dev = dev;
-		ret = ethnl_perphy_dump_one_dev(skb, ctx, info);
-
-		rcu_read_lock();
-		netdev_put(dev, &dev_tracker);
-		ethnl_ctx->req_info->dev = NULL;
-
-		if (ret < 0 && ret != -EOPNOTSUPP) {
-			if (likely(skb->len))
-				ret = skb->len;
-			break;
-		}
-		ret = 0;
-	}
-	rcu_read_unlock();
-
-	return ret;
-}
-
-/* per-PHY ->dumpit() handler for GET requests. */
-static int ethnl_perphy_dumpit(struct sk_buff *skb,
-			       struct netlink_callback *cb)
-{
-	struct ethnl_perphy_dump_ctx *ctx = ethnl_perphy_dump_context(cb);
-	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
-	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
-	int ret = 0;
-
-	if (ctx->ifindex) {
-		netdevice_tracker dev_tracker;
-		struct net_device *dev;
-
-		dev = netdev_get_by_index(genl_info_net(&info->info),
-					  ctx->ifindex, &dev_tracker,
-					  GFP_KERNEL);
-		if (!dev)
-			return -ENODEV;
-
-		ethnl_ctx->req_info->dev = dev;
-		ret = ethnl_perphy_dump_one_dev(skb, ctx, genl_info_dump(cb));
-
-		if (ret < 0 && ret != -EOPNOTSUPP && likely(skb->len))
-			ret = skb->len;
-
-		netdev_put(dev, &dev_tracker);
-	} else {
-		ret = ethnl_perphy_dump_all_dev(skb, ctx, genl_info_dump(cb));
-	}
-
-	return ret;
-}
-
-/* per-PHY ->done() handler for GET requests */
-static int ethnl_perphy_done(struct netlink_callback *cb)
-{
-	struct ethnl_perphy_dump_ctx *ctx = ethnl_perphy_dump_context(cb);
-	struct ethnl_dump_ctx *ethnl_ctx = &ctx->ethnl_ctx;
-
-	kfree(ethnl_ctx->reply_data);
-	kfree(ethnl_ctx->req_info);
+	*pos_sub = 0;
 
 	return 0;
 }
@@ -1410,9 +1268,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
 	{
 		.cmd	= ETHTOOL_MSG_PSE_GET,
 		.doit	= ethnl_default_doit,
-		.start	= ethnl_perphy_start,
-		.dumpit	= ethnl_perphy_dumpit,
-		.done	= ethnl_perphy_done,
+		.start	= ethnl_default_start,
+		.dumpit	= ethnl_default_dumpit,
+		.done	= ethnl_default_done,
 		.policy = ethnl_pse_get_policy,
 		.maxattr = ARRAY_SIZE(ethnl_pse_get_policy) - 1,
 	},
@@ -1434,9 +1292,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
 	{
 		.cmd	= ETHTOOL_MSG_PLCA_GET_CFG,
 		.doit	= ethnl_default_doit,
-		.start	= ethnl_perphy_start,
-		.dumpit	= ethnl_perphy_dumpit,
-		.done	= ethnl_perphy_done,
+		.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,
 	},
@@ -1450,9 +1308,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
 	{
 		.cmd	= ETHTOOL_MSG_PLCA_GET_STATUS,
 		.doit	= ethnl_default_doit,
-		.start	= ethnl_perphy_start,
-		.dumpit	= ethnl_perphy_dumpit,
-		.done	= ethnl_perphy_done,
+		.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,
 	},
@@ -1482,9 +1340,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
 	{
 		.cmd	= ETHTOOL_MSG_PHY_GET,
 		.doit	= ethnl_default_doit,
-		.start	= ethnl_perphy_start,
-		.dumpit	= ethnl_perphy_dumpit,
-		.done	= ethnl_perphy_done,
+		.start	= ethnl_default_start,
+		.dumpit	= ethnl_default_dumpit,
+		.done	= ethnl_default_done,
 		.policy = ethnl_phy_get_policy,
 		.maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1,
 	},
@@ -1528,9 +1386,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
 	{
 		.cmd	= ETHTOOL_MSG_MSE_GET,
 		.doit	= ethnl_default_doit,
-		.start	= ethnl_perphy_start,
-		.dumpit	= ethnl_perphy_dumpit,
-		.done	= ethnl_perphy_done,
+		.start	= ethnl_default_start,
+		.dumpit	= ethnl_default_dumpit,
+		.done	= ethnl_default_done,
 		.policy = ethnl_mse_get_policy,
 		.maxattr = ARRAY_SIZE(ethnl_mse_get_policy) - 1,
 	},
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index e01adc5db02f..dda2f5593ed9 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -546,6 +546,10 @@ int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
 int ethnl_tsinfo_done(struct netlink_callback *cb);
 int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info);
 int ethnl_rss_delete_doit(struct sk_buff *skb, struct genl_info *info);
+int ethnl_perphy_dump_one_dev(struct sk_buff *skb,
+			      struct ethnl_dump_ctx *ctx,
+			      unsigned long *pos_sub,
+			      const 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/phy.c b/net/ethtool/phy.c
index d4e6887055ab..4bb23a5d6ad5 100644
--- a/net/ethtool/phy.c
+++ b/net/ethtool/phy.c
@@ -162,4 +162,5 @@ const struct ethnl_request_ops ethnl_phy_request_ops = {
 	.reply_size		= phy_reply_size,
 	.fill_reply		= phy_fill_reply,
 	.cleanup_data		= phy_cleanup_data,
+	.dump_one_dev		= ethnl_perphy_dump_one_dev,
 };
diff --git a/net/ethtool/plca.c b/net/ethtool/plca.c
index 91f0c4233298..84e902532617 100644
--- a/net/ethtool/plca.c
+++ b/net/ethtool/plca.c
@@ -188,6 +188,7 @@ const struct ethnl_request_ops ethnl_plca_cfg_request_ops = {
 	.prepare_data		= plca_get_cfg_prepare_data,
 	.reply_size		= plca_get_cfg_reply_size,
 	.fill_reply		= plca_get_cfg_fill_reply,
+	.dump_one_dev		= ethnl_perphy_dump_one_dev,
 
 	.set			= ethnl_set_plca,
 	.set_ntf_cmd		= ETHTOOL_MSG_PLCA_NTF,
@@ -268,4 +269,5 @@ const struct ethnl_request_ops ethnl_plca_status_request_ops = {
 	.prepare_data		= plca_get_status_prepare_data,
 	.reply_size		= plca_get_status_reply_size,
 	.fill_reply		= plca_get_status_fill_reply,
+	.dump_one_dev		= ethnl_perphy_dump_one_dev,
 };
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 2eb9bdc2dcb9..83f0205053a3 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -338,6 +338,7 @@ const struct ethnl_request_ops ethnl_pse_request_ops = {
 	.reply_size		= pse_reply_size,
 	.fill_reply		= pse_fill_reply,
 	.cleanup_data		= pse_cleanup_data,
+	.dump_one_dev		= ethnl_perphy_dump_one_dev,
 
 	.set			= ethnl_set_pse,
 	/* PSE has no notification */
-- 
2.53.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help