From nobody Sun Feb 8 06:22:29 2026 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63D1E27587B; Tue, 15 Apr 2025 08:52:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744707124; cv=none; b=TZzFBDW/W9JSootiwbWs3fSZVv5OY4U93wPnRlKMd07ii9trgOdfG16nJzBhQQRBkIoUezHLqu+k7diaGmG9PH6P73UwAcAT/9smovmqn1Qhug8TQgnIuAAGc6cpePqZcwZFC0Q0MDXZBmexi0RzI9ak8sMzVtO+83JA10s7HbY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744707124; c=relaxed/simple; bh=HL0ZhZs1zQgnE7zPtvO9WCZUoFooDrSuef/24Z9yYz4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m/tWCTg3FC6/WWHViqL2dlMyvNUsZFEYXc2BZ1BA0p+dzQLZ3wAyaEsZ/GjbHTNXe41EUuaGJxMOoQlgUzB2PkSUIFYh/iSw+ruB1cKgV3khSD/N/bhninTAmHnTJCX07OI0fjb3ylyqEu4mRj6F/I1cVMwl0zJ76s8mGggEnyE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=jdcLNPU3; arc=none smtp.client-ip=217.70.183.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="jdcLNPU3" Received: by mail.gandi.net (Postfix) with ESMTPSA id 87451432FD; Tue, 15 Apr 2025 08:51:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1744707119; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=khKzl4zs7a80fLcDBgFBWkoB0YVlx2T1g/7fauNksCI=; b=jdcLNPU36Dns8snFhjipqW3ScdRpq21z7zTYm0paDnyNjJBNbhDoBp8JyTqUv6qYyeVNQu VHWSHmRv6KoUiOyOMJ5c5w4O9cbTMtn5GFOM36/nFYEugGpEpzSnsNlqFHmrTz3kkutxXW L7x/2VcDLWJ3b9jiLYI7E1NbWUoSPaFBUUFeI5lgqNKsTO1d20BG40PDj7aljD4zlAVbq0 UOnFJaqfS44A6K07u1wgE8ZDIASVkhVweKkQp8mN7otY7ArYObSq4fMIC1I8AVGsEHIQ4+ 7DG9N5Oee1n0MfpIwynARH7y58ik7IWVT8M1Euq5/jnW9aV2zmyEO7etgWb0cA== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, linux-arm-kernel@lists.infradead.org, Christophe Leroy , Herve Codina , Florian Fainelli , Russell King , Vladimir Oltean , =?UTF-8?q?K=C3=B6ry=20Maincent?= , Oleksij Rempel , Simon Horman , Romain Gantois , Piergiorgio Beruto Subject: [PATCH net-next v6 1/2] net: ethtool: Introduce per-PHY DUMP operations Date: Tue, 15 Apr 2025 10:51:53 +0200 Message-ID: <20250415085155.132963-2-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250415085155.132963-1-maxime.chevallier@bootlin.com> References: <20250415085155.132963-1-maxime.chevallier@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-GND-State: clean X-GND-Score: -100 X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddvvdeftdegucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuifetpfffkfdpucggtfgfnhhsuhgsshgtrhhisggvnecuuegrihhlohhuthemuceftddunecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefhvfevufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeforgigihhmvgcuvehhvghvrghllhhivghruceomhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomheqnecuggftrfgrthhtvghrnhepfeehheeuheefffeuhefgvdejieeugeejieevffejudeuueevhffffeduueevgfdvnecuffhomhgrihhnpehprghttghhrdhnvghtnecukfhppedvrgdtudemtggsudelmeekugegheemgeeltddtmeeiheeikeemvdelsgdumeelvghfheemvgektgejnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepvdgrtddumegtsgduleemkegugeehmeegledttdemieehieekmedvlegsudemlegvfhehmegvkegtjedphhgvlhhopehfvgguohhrrgdrhhhomhgvpdhmrghilhhfrhhomhepmhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomhdpnhgspghrtghpthhtohepvddupdhrtghpthhtohepuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvthdprhgtphhtthhopegrnhgurhgvfieslhhunhhnrdgthhdprhgtphhtthhopehkuhgsrgeskhgvrhhnv ghlrdhorhhgpdhrtghpthhtohepvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdprhgtphhtthhopehprggsvghnihesrhgvughhrghtrdgtohhmpdhrtghpthhtohephhhkrghllhifvghithdusehgmhgrihhlrdgtohhmpdhrtghpthhtohepmhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomhdprhgtphhtthhopehnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrgh X-GND-Sasl: maxime.chevallier@bootlin.com Content-Type: text/plain; charset="utf-8" ethnl commands that target a phy_device need a DUMP implementation that will fill the reply for every PHY behind a netdev. We therefore need to iterate over the dev->topo to list them. When multiple PHYs are behind the same netdev, it's also useful to perform DUMP with a filter on a given netdev, to get the capability of every PHY. Implement dedicated genl ->start(), ->dumpit() and ->done() operations for PHY-targetting command, allowing filtered dumps and using a dump context that keep track of the PHY iteration for multi-message dump. PSE-PD and PLCA are converted to this new set of ops along the way. Signed-off-by: Maxime Chevallier --- V6: Squashed PSE and PLCA into this patch. net/ethtool/netlink.c | 180 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 171 insertions(+), 9 deletions(-) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 977beeaaa2f9..afb609ed515a 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -357,6 +357,16 @@ struct ethnl_dump_ctx { unsigned long pos_ifindex; }; =20 +/** + * struct ethnl_perphy_dump_ctx - context for dumpit() PHY-aware callbacks + * @ethnl_ctx: generic ethnl context + * @pos_phyindex: iterator position for multi-msg DUMP + */ +struct ethnl_perphy_dump_ctx { + struct ethnl_dump_ctx ethnl_ctx; + unsigned long pos_phyindex; +}; + static const struct ethnl_request_ops * ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] =3D { [ETHTOOL_MSG_STRSET_GET] =3D ðnl_strset_request_ops, @@ -407,6 +417,12 @@ static struct ethnl_dump_ctx *ethnl_dump_context(struc= t netlink_callback *cb) return (struct ethnl_dump_ctx *)cb->ctx; } =20 +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 @@ -662,6 +678,152 @@ static int ethnl_default_start(struct netlink_callbac= k *cb) return ret; } =20 +/* perphy ->start() handler for GET requests */ +static int ethnl_perphy_start(struct netlink_callback *cb) +{ + struct ethnl_perphy_dump_ctx *phy_ctx =3D ethnl_perphy_dump_context(cb); + const struct genl_dumpit_info *info =3D genl_dumpit_info(cb); + struct ethnl_dump_ctx *ctx =3D &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 =3D nlmsg_data(cb->nlh); + ops =3D ethnl_default_requests[ghdr->cmd]; + if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd)) + return -EOPNOTSUPP; + req_info =3D kzalloc(ops->req_info_size, GFP_KERNEL); + if (!req_info) + return -ENOMEM; + reply_data =3D kmalloc(ops->reply_data_size, GFP_KERNEL); + if (!reply_data) { + ret =3D -ENOMEM; + goto free_req_info; + } + + /* Don't ignore the dev even for DUMP requests */ + ret =3D ethnl_default_parse(req_info, &info->info, ops, false); + if (ret < 0) + goto free_reply_data; + + ctx->ops =3D ops; + ctx->req_info =3D req_info; + ctx->reply_data =3D reply_data; + ctx->pos_ifindex =3D 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 net_device *dev, + struct ethnl_perphy_dump_ctx *ctx, + const struct genl_info *info) +{ + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + struct phy_device_node *pdn; + int ret =3D 0; + + 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 =3D ctx->pos_phyindex; + + /* 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 =3D ethnl_default_dump_one(skb, dev, ethnl_ctx, info); + if (ret) + break; + } + + return ret; +} + +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 =3D &ctx->ethnl_ctx; + struct net *net =3D sock_net(skb->sk); + struct net_device *dev; + int ret =3D 0; + + rcu_read_lock(); + for_each_netdev_dump(net, dev, ethnl_ctx->pos_ifindex) { + dev_hold(dev); + 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 =3D dev; + ret =3D ethnl_perphy_dump_one_dev(skb, dev, ctx, info); + + rcu_read_lock(); + dev_put(dev); + + if (ret < 0 && ret !=3D -EOPNOTSUPP) { + if (likely(skb->len)) + ret =3D skb->len; + break; + } + ret =3D 0; + } + rcu_read_unlock(); + + return ret; +} + +/* perphy ->dumpit() handler for GET requests. */ +static int ethnl_perphy_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct ethnl_perphy_dump_ctx *ctx =3D ethnl_perphy_dump_context(cb); + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + int ret =3D 0; + + if (ethnl_ctx->req_info->dev) { + ret =3D ethnl_perphy_dump_one_dev(skb, ethnl_ctx->req_info->dev, + ctx, genl_info_dump(cb)); + + if (ret < 0 && ret !=3D -EOPNOTSUPP && likely(skb->len)) + ret =3D skb->len; + + netdev_put(ethnl_ctx->req_info->dev, + ðnl_ctx->req_info->dev_tracker); + } else { + ret =3D ethnl_perphy_dump_all_dev(skb, ctx, genl_info_dump(cb)); + } + + return ret; +} + +/* perphy ->done() handler for GET requests */ +static int ethnl_perphy_done(struct netlink_callback *cb) +{ + struct ethnl_perphy_dump_ctx *ctx =3D ethnl_perphy_dump_context(cb); + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + + kfree(ethnl_ctx->reply_data); + kfree(ethnl_ctx->req_info); + + return 0; +} + /* default ->done() handler for GET requests */ static int ethnl_default_done(struct netlink_callback *cb) { @@ -1200,9 +1362,9 @@ static const struct genl_ops ethtool_genl_ops[] =3D { { .cmd =3D ETHTOOL_MSG_PSE_GET, .doit =3D ethnl_default_doit, - .start =3D ethnl_default_start, - .dumpit =3D ethnl_default_dumpit, - .done =3D ethnl_default_done, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_pse_get_policy, .maxattr =3D ARRAY_SIZE(ethnl_pse_get_policy) - 1, }, @@ -1224,9 +1386,9 @@ static const struct genl_ops ethtool_genl_ops[] =3D { { .cmd =3D ETHTOOL_MSG_PLCA_GET_CFG, .doit =3D ethnl_default_doit, - .start =3D ethnl_default_start, - .dumpit =3D ethnl_default_dumpit, - .done =3D ethnl_default_done, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_plca_get_cfg_policy, .maxattr =3D ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1, }, @@ -1240,9 +1402,9 @@ static const struct genl_ops ethtool_genl_ops[] =3D { { .cmd =3D ETHTOOL_MSG_PLCA_GET_STATUS, .doit =3D ethnl_default_doit, - .start =3D ethnl_default_start, - .dumpit =3D ethnl_default_dumpit, - .done =3D ethnl_default_done, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_plca_get_status_policy, .maxattr =3D ARRAY_SIZE(ethnl_plca_get_status_policy) - 1, }, --=20 2.49.0 From nobody Sun Feb 8 06:22:29 2026 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63CB71DDC18; Tue, 15 Apr 2025 08:52:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744707125; cv=none; b=WXdW8DB5ek1qiZIK3xfbRkQ2rX+4GpbJlq2WqsB4BD5iq2wxVX3l+NwKB7QIUFQz0xAtIEkeJAhqSUxv+IgcrVGMyu+vAfCVCvq0DSjd5QZAgygfxfQlk4hmiOBWO5SVl4gOf37aoX8iez0Z6hRFZuyRqYtLyphTcA4A1d5Km+I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744707125; c=relaxed/simple; bh=ftkaAuGCRjpsO4mqkauYH8ETLmjWiU1yTg6k8COK4uc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DaIiUpDLvovZRd0NPQpKxeOllBKUv0lo8kdJpjZC5GSTJqlvsIpEjbhVnrK4hDcqGuVPgVfHqVuTr+1m4b4wyQBymqvgJgQKiPGfH9/Z2wRPFQ/Y5HjNYSpRj49hlA4gPe5PpatQwIQw+NzPGpR+euBl9xQy0PJpDUnFODzG934= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=IkhkRHik; arc=none smtp.client-ip=217.70.183.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="IkhkRHik" Received: by mail.gandi.net (Postfix) with ESMTPSA id 93FD7432F9; Tue, 15 Apr 2025 08:51:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1744707120; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CL4VDDzYo+gIiDyrhm09oNU2W4rD91r8p0855Qcob/Y=; b=IkhkRHikiINIcguI107lZVBvRJLSRvJeEYzQirsoXMKHSpW0g3fDOSv7zHgi8h02xZHWo2 S2URt6wwt7ejiiixeYsqqvvc7n55wzcQoBRHxkjlYLSs23jIPrLq5uYOOQs5CfUq3cjU7p 6mB96PfCGbV7ukXaKY6bSzaBL87+dWnoGIAc6IvxIyZdXiW+QO3FdSk9ciGG8uFjjJ47jA fyahCviPUBksHml/45jcHQyTI0+hFzWoAizjVHKMd/K4pe8YbRxLXLBmtkvQvyYGRCo7qW x7Hd1/0cCrPc15m95R6CJMiiRv52vX2kvUVXmhN/9c6vefyAYWIP4uDEMAT+8w== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, linux-arm-kernel@lists.infradead.org, Christophe Leroy , Herve Codina , Florian Fainelli , Russell King , Vladimir Oltean , =?UTF-8?q?K=C3=B6ry=20Maincent?= , Oleksij Rempel , Simon Horman , Romain Gantois , Piergiorgio Beruto Subject: [PATCH net-next v6 2/2] net: ethtool: phy: Convert the PHY_GET command to generic phy dump Date: Tue, 15 Apr 2025 10:51:54 +0200 Message-ID: <20250415085155.132963-3-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250415085155.132963-1-maxime.chevallier@bootlin.com> References: <20250415085155.132963-1-maxime.chevallier@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-GND-State: clean X-GND-Score: -100 X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddvvdeftdegucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuifetpfffkfdpucggtfgfnhhsuhgsshgtrhhisggvnecuuegrihhlohhuthemuceftddunecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefhvfevufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeforgigihhmvgcuvehhvghvrghllhhivghruceomhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomheqnecuggftrfgrthhtvghrnhepvddtueefvdfhiefgieelfeeggeefiedvueevkedttddvffekleeujedtjeeuteehnecuffhomhgrihhnpegsrghsvgdruggvvhenucfkphepvdgrtddumegtsgduleemkegugeehmeegledttdemieehieekmedvlegsudemlegvfhehmegvkegtjeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpedvrgdtudemtggsudelmeekugegheemgeeltddtmeeiheeikeemvdelsgdumeelvghfheemvgektgejpdhhvghlohepfhgvughorhgrrdhhohhmvgdpmhgrihhlfhhrohhmpehmrgigihhmvgdrtghhvghvrghllhhivghrsegsohhothhlihhnrdgtohhmpdhnsggprhgtphhtthhopedvuddprhgtphhtthhopegurghvvghmsegurghvvghmlhhofhhtrdhnvghtpdhrtghpthhtoheprghnughrvgifsehluhhnnhdrtghhpdhrtghpthhtohepkhhusggrsehkvghrnhgvl hdrohhrghdprhgtphhtthhopegvughumhgriigvthesghhoohhglhgvrdgtohhmpdhrtghpthhtohepphgrsggvnhhisehrvgguhhgrthdrtghomhdprhgtphhtthhopehhkhgrlhhlfigvihhtudesghhmrghilhdrtghomhdprhgtphhtthhopehmrgigihhmvgdrtghhvghvrghllhhivghrsegsohhothhlihhnrdgtohhmpdhrtghpthhtohepnhgvthguvghvsehvghgvrhdrkhgvrhhnvghlrdhorhhg X-GND-Sasl: maxime.chevallier@bootlin.com Content-Type: text/plain; charset="utf-8" Now that we have an infrastructure in ethnl for perphy DUMPs, we can get rid of the custom ->doit and ->dumpit to deal with PHY listing commands. As most of the code was custom, this basically means re-writing how we deal with PHY listing. Signed-off-by: Maxime Chevallier --- V6: No changes net/ethtool/netlink.c | 9 +- net/ethtool/netlink.h | 4 - net/ethtool/phy.c | 342 ++++++++++++------------------------------ 3 files changed, 101 insertions(+), 254 deletions(-) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index afb609ed515a..db0c1acf116b 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -410,6 +410,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] =3D { [ETHTOOL_MSG_MM_SET] =3D ðnl_mm_request_ops, [ETHTOOL_MSG_TSCONFIG_GET] =3D ðnl_tsconfig_request_ops, [ETHTOOL_MSG_TSCONFIG_SET] =3D ðnl_tsconfig_request_ops, + [ETHTOOL_MSG_PHY_GET] =3D ðnl_phy_request_ops, }; =20 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *= cb) @@ -1433,10 +1434,10 @@ static const struct genl_ops ethtool_genl_ops[] =3D= { }, { .cmd =3D ETHTOOL_MSG_PHY_GET, - .doit =3D ethnl_phy_doit, - .start =3D ethnl_phy_start, - .dumpit =3D ethnl_phy_dumpit, - .done =3D ethnl_phy_done, + .doit =3D ethnl_default_doit, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_phy_get_policy, .maxattr =3D ARRAY_SIZE(ethnl_phy_get_policy) - 1, }, diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index ec6ab5443a6f..91b953924af3 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -499,10 +499,6 @@ int ethnl_tunnel_info_dumpit(struct sk_buff *skb, stru= ct netlink_callback *cb); int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info); int ethnl_rss_dump_start(struct netlink_callback *cb); int ethnl_rss_dumpit(struct sk_buff *skb, struct netlink_callback *cb); -int ethnl_phy_start(struct netlink_callback *cb); -int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info); -int ethnl_phy_dumpit(struct sk_buff *skb, struct netlink_callback *cb); -int ethnl_phy_done(struct netlink_callback *cb); int ethnl_tsinfo_start(struct netlink_callback *cb); int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int ethnl_tsinfo_done(struct netlink_callback *cb); diff --git a/net/ethtool/phy.c b/net/ethtool/phy.c index 1f590e8d75ed..68372bef4b2f 100644 --- a/net/ethtool/phy.c +++ b/net/ethtool/phy.c @@ -12,304 +12,154 @@ #include =20 struct phy_req_info { - struct ethnl_req_info base; - struct phy_device_node *pdn; + struct ethnl_req_info base; }; =20 -#define PHY_REQINFO(__req_base) \ - container_of(__req_base, struct phy_req_info, base) +struct phy_reply_data { + struct ethnl_reply_data base; + u32 phyindex; + char *drvname; + char *name; + unsigned int upstream_type; + char *upstream_sfp_name; + unsigned int upstream_index; + char *downstream_sfp_name; +}; + +#define PHY_REPDATA(__reply_base) \ + container_of(__reply_base, struct phy_reply_data, base) =20 const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1] =3D= { [ETHTOOL_A_PHY_HEADER] =3D NLA_POLICY_NESTED(ethnl_header_policy), }; =20 -/* Caller holds rtnl */ -static ssize_t -ethnl_phy_reply_size(const struct ethnl_req_info *req_base, - struct netlink_ext_ack *extack) +static int phy_reply_size(const struct ethnl_req_info *req_info, + const struct ethnl_reply_data *reply_data) { - struct phy_req_info *req_info =3D PHY_REQINFO(req_base); - struct phy_device_node *pdn =3D req_info->pdn; - struct phy_device *phydev =3D pdn->phy; + struct phy_reply_data *rep_data =3D PHY_REPDATA(reply_data); size_t size =3D 0; =20 - ASSERT_RTNL(); - /* ETHTOOL_A_PHY_INDEX */ size +=3D nla_total_size(sizeof(u32)); =20 /* ETHTOOL_A_DRVNAME */ - if (phydev->drv) - size +=3D nla_total_size(strlen(phydev->drv->name) + 1); + if (rep_data->drvname) + size +=3D nla_total_size(strlen(rep_data->drvname) + 1); =20 /* ETHTOOL_A_NAME */ - size +=3D nla_total_size(strlen(dev_name(&phydev->mdio.dev)) + 1); + size +=3D nla_total_size(strlen(rep_data->name) + 1); =20 /* ETHTOOL_A_PHY_UPSTREAM_TYPE */ size +=3D nla_total_size(sizeof(u32)); =20 - if (phy_on_sfp(phydev)) { - const char *upstream_sfp_name =3D sfp_get_name(pdn->parent_sfp_bus); - - /* ETHTOOL_A_PHY_UPSTREAM_SFP_NAME */ - if (upstream_sfp_name) - size +=3D nla_total_size(strlen(upstream_sfp_name) + 1); + /* ETHTOOL_A_PHY_UPSTREAM_SFP_NAME */ + if (rep_data->upstream_sfp_name) + size +=3D nla_total_size(strlen(rep_data->upstream_sfp_name) + 1); =20 - /* ETHTOOL_A_PHY_UPSTREAM_INDEX */ + /* ETHTOOL_A_PHY_UPSTREAM_INDEX */ + if (rep_data->upstream_index) size +=3D nla_total_size(sizeof(u32)); - } =20 /* ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME */ - if (phydev->sfp_bus) { - const char *sfp_name =3D sfp_get_name(phydev->sfp_bus); - - if (sfp_name) - size +=3D nla_total_size(strlen(sfp_name) + 1); - } + if (rep_data->downstream_sfp_name) + size +=3D nla_total_size(strlen(rep_data->downstream_sfp_name) + 1); =20 return size; } =20 -static int -ethnl_phy_fill_reply(const struct ethnl_req_info *req_base, struct sk_buff= *skb) +static int phy_prepare_data(const struct ethnl_req_info *req_info, + struct ethnl_reply_data *reply_data, + const struct genl_info *info) { - struct phy_req_info *req_info =3D PHY_REQINFO(req_base); - struct phy_device_node *pdn =3D req_info->pdn; - struct phy_device *phydev =3D pdn->phy; - enum phy_upstream ptype; + struct phy_link_topology *topo =3D reply_data->dev->link_topo; + struct phy_reply_data *rep_data =3D PHY_REPDATA(reply_data); + struct nlattr **tb =3D info->attrs; + struct phy_device_node *pdn; + struct phy_device *phydev; =20 - ptype =3D pdn->upstream_type; + /* RTNL is held by the caller */ + phydev =3D ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PHY_HEADER, + info->extack); + if (IS_ERR_OR_NULL(phydev)) + return -EOPNOTSUPP; =20 - if (nla_put_u32(skb, ETHTOOL_A_PHY_INDEX, phydev->phyindex) || - nla_put_string(skb, ETHTOOL_A_PHY_NAME, dev_name(&phydev->mdio.dev)) = || - nla_put_u32(skb, ETHTOOL_A_PHY_UPSTREAM_TYPE, ptype)) - return -EMSGSIZE; + pdn =3D xa_load(&topo->phys, phydev->phyindex); + if (!pdn) + return -EOPNOTSUPP; =20 - if (phydev->drv && - nla_put_string(skb, ETHTOOL_A_PHY_DRVNAME, phydev->drv->name)) - return -EMSGSIZE; + rep_data->phyindex =3D phydev->phyindex; + rep_data->name =3D kstrdup(dev_name(&phydev->mdio.dev), GFP_KERNEL); + rep_data->drvname =3D kstrdup(phydev->drv->name, GFP_KERNEL); + rep_data->upstream_type =3D pdn->upstream_type; =20 - if (ptype =3D=3D PHY_UPSTREAM_PHY) { + if (pdn->upstream_type =3D=3D PHY_UPSTREAM_PHY) { struct phy_device *upstream =3D pdn->upstream.phydev; - const char *sfp_upstream_name; - - /* Parent index */ - if (nla_put_u32(skb, ETHTOOL_A_PHY_UPSTREAM_INDEX, upstream->phyindex)) - return -EMSGSIZE; - - if (pdn->parent_sfp_bus) { - sfp_upstream_name =3D sfp_get_name(pdn->parent_sfp_bus); - if (sfp_upstream_name && - nla_put_string(skb, ETHTOOL_A_PHY_UPSTREAM_SFP_NAME, - sfp_upstream_name)) - return -EMSGSIZE; - } - } - - if (phydev->sfp_bus) { - const char *sfp_name =3D sfp_get_name(phydev->sfp_bus); - - if (sfp_name && - nla_put_string(skb, ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME, - sfp_name)) - return -EMSGSIZE; + rep_data->upstream_index =3D upstream->phyindex; } =20 - return 0; -} - -static int ethnl_phy_parse_request(struct ethnl_req_info *req_base, - struct nlattr **tb, - struct netlink_ext_ack *extack) -{ - struct phy_link_topology *topo =3D req_base->dev->link_topo; - struct phy_req_info *req_info =3D PHY_REQINFO(req_base); - struct phy_device *phydev; + if (pdn->parent_sfp_bus) + rep_data->upstream_sfp_name =3D kstrdup(sfp_get_name(pdn->parent_sfp_bus= ), + GFP_KERNEL); =20 - phydev =3D ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PHY_HEADER, - extack); - if (!phydev) - return 0; - - if (IS_ERR(phydev)) - return PTR_ERR(phydev); - - if (!topo) - return 0; - - req_info->pdn =3D xa_load(&topo->phys, phydev->phyindex); + if (phydev->sfp_bus) + rep_data->downstream_sfp_name =3D kstrdup(sfp_get_name(phydev->sfp_bus), + GFP_KERNEL); =20 return 0; } =20 -int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info) +static int phy_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_info, + const struct ethnl_reply_data *reply_data) { - struct phy_req_info req_info =3D {}; - struct nlattr **tb =3D info->attrs; - struct sk_buff *rskb; - void *reply_payload; - int reply_len; - int ret; - - ret =3D ethnl_parse_header_dev_get(&req_info.base, - tb[ETHTOOL_A_PHY_HEADER], - genl_info_net(info), info->extack, - true); - if (ret < 0) - return ret; - - rtnl_lock(); - netdev_lock_ops(req_info.base.dev); - - ret =3D ethnl_phy_parse_request(&req_info.base, tb, info->extack); - if (ret < 0) - goto err_unlock; - - /* No PHY, return early */ - if (!req_info.pdn) - goto err_unlock; - - ret =3D ethnl_phy_reply_size(&req_info.base, info->extack); - if (ret < 0) - goto err_unlock; - reply_len =3D ret + ethnl_reply_header_size(); - - rskb =3D ethnl_reply_init(reply_len, req_info.base.dev, - ETHTOOL_MSG_PHY_GET_REPLY, - ETHTOOL_A_PHY_HEADER, - info, &reply_payload); - if (!rskb) { - ret =3D -ENOMEM; - goto err_unlock; - } - - ret =3D ethnl_phy_fill_reply(&req_info.base, rskb); - if (ret) - goto err_free_msg; + struct phy_reply_data *rep_data =3D PHY_REPDATA(reply_data); =20 - netdev_unlock_ops(req_info.base.dev); - rtnl_unlock(); - ethnl_parse_header_dev_put(&req_info.base); - genlmsg_end(rskb, reply_payload); - - return genlmsg_reply(rskb, info); - -err_free_msg: - nlmsg_free(rskb); -err_unlock: - netdev_unlock_ops(req_info.base.dev); - rtnl_unlock(); - ethnl_parse_header_dev_put(&req_info.base); - return ret; -} - -struct ethnl_phy_dump_ctx { - struct phy_req_info *phy_req_info; - unsigned long ifindex; - unsigned long phy_index; -}; - -int ethnl_phy_start(struct netlink_callback *cb) -{ - const struct genl_info *info =3D genl_info_dump(cb); - struct ethnl_phy_dump_ctx *ctx =3D (void *)cb->ctx; - int ret; - - BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx)); - - ctx->phy_req_info =3D kzalloc(sizeof(*ctx->phy_req_info), GFP_KERNEL); - if (!ctx->phy_req_info) - return -ENOMEM; - - ret =3D ethnl_parse_header_dev_get(&ctx->phy_req_info->base, - info->attrs[ETHTOOL_A_PHY_HEADER], - sock_net(cb->skb->sk), cb->extack, - false); - ctx->ifindex =3D 0; - ctx->phy_index =3D 0; - - if (ret) - kfree(ctx->phy_req_info); + if (nla_put_u32(skb, ETHTOOL_A_PHY_INDEX, rep_data->phyindex) || + nla_put_string(skb, ETHTOOL_A_PHY_NAME, rep_data->name) || + nla_put_u32(skb, ETHTOOL_A_PHY_UPSTREAM_TYPE, rep_data->upstream_type= )) + return -EMSGSIZE; =20 - return ret; -} + if (rep_data->drvname && + nla_put_string(skb, ETHTOOL_A_PHY_DRVNAME, rep_data->drvname)) + return -EMSGSIZE; =20 -int ethnl_phy_done(struct netlink_callback *cb) -{ - struct ethnl_phy_dump_ctx *ctx =3D (void *)cb->ctx; + if (rep_data->upstream_index && + nla_put_u32(skb, ETHTOOL_A_PHY_UPSTREAM_INDEX, + rep_data->upstream_index)) + return -EMSGSIZE; =20 - if (ctx->phy_req_info->base.dev) - ethnl_parse_header_dev_put(&ctx->phy_req_info->base); + if (rep_data->upstream_sfp_name && + nla_put_string(skb, ETHTOOL_A_PHY_UPSTREAM_SFP_NAME, + rep_data->upstream_sfp_name)) + return -EMSGSIZE; =20 - kfree(ctx->phy_req_info); + if (rep_data->downstream_sfp_name && + nla_put_string(skb, ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME, + rep_data->downstream_sfp_name)) + return -EMSGSIZE; =20 return 0; } =20 -static int ethnl_phy_dump_one_dev(struct sk_buff *skb, struct net_device *= dev, - struct netlink_callback *cb) +static void phy_cleanup_data(struct ethnl_reply_data *reply_data) { - struct ethnl_phy_dump_ctx *ctx =3D (void *)cb->ctx; - struct phy_req_info *pri =3D ctx->phy_req_info; - struct phy_device_node *pdn; - int ret =3D 0; - void *ehdr; - - if (!dev->link_topo) - return 0; - - xa_for_each_start(&dev->link_topo->phys, ctx->phy_index, pdn, ctx->phy_in= dex) { - ehdr =3D ethnl_dump_put(skb, cb, ETHTOOL_MSG_PHY_GET_REPLY); - if (!ehdr) { - ret =3D -EMSGSIZE; - break; - } - - ret =3D ethnl_fill_reply_header(skb, dev, ETHTOOL_A_PHY_HEADER); - if (ret < 0) { - genlmsg_cancel(skb, ehdr); - break; - } - - pri->pdn =3D pdn; - ret =3D ethnl_phy_fill_reply(&pri->base, skb); - if (ret < 0) { - genlmsg_cancel(skb, ehdr); - break; - } - - genlmsg_end(skb, ehdr); - } + struct phy_reply_data *rep_data =3D PHY_REPDATA(reply_data); =20 - return ret; + kfree(rep_data->drvname); + kfree(rep_data->name); + kfree(rep_data->upstream_sfp_name); + kfree(rep_data->downstream_sfp_name); } =20 -int ethnl_phy_dumpit(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct ethnl_phy_dump_ctx *ctx =3D (void *)cb->ctx; - struct net *net =3D sock_net(skb->sk); - struct net_device *dev; - int ret =3D 0; - - rtnl_lock(); - - if (ctx->phy_req_info->base.dev) { - dev =3D ctx->phy_req_info->base.dev; - netdev_lock_ops(dev); - ret =3D ethnl_phy_dump_one_dev(skb, dev, cb); - netdev_unlock_ops(dev); - } else { - for_each_netdev_dump(net, dev, ctx->ifindex) { - netdev_lock_ops(dev); - ret =3D ethnl_phy_dump_one_dev(skb, dev, cb); - netdev_unlock_ops(dev); - if (ret) - break; - - ctx->phy_index =3D 0; - } - } - rtnl_unlock(); - - return ret; -} +const struct ethnl_request_ops ethnl_phy_request_ops =3D { + .request_cmd =3D ETHTOOL_MSG_PHY_GET, + .reply_cmd =3D ETHTOOL_MSG_PHY_GET_REPLY, + .hdr_attr =3D ETHTOOL_A_PHY_HEADER, + .req_info_size =3D sizeof(struct phy_req_info), + .reply_data_size =3D sizeof(struct phy_reply_data), + + .prepare_data =3D phy_prepare_data, + .reply_size =3D phy_reply_size, + .fill_reply =3D phy_fill_reply, + .cleanup_data =3D phy_cleanup_data, +}; --=20 2.49.0