Netdev List
 help / color / mirror / Atom feed
* [RFC PATCH net-next 0/2] ethtool: add interface capabilities and PHY test
@ 2026-08-25  4:37 Shubham Das
  2026-08-25  4:37 ` [RFC PATCH net-next 1/2] ethtool: add interface capabilities query (intf-caps-get) Shubham Das
  2026-08-25  4:37 ` [RFC PATCH net-next 2/2] ethtool: add PHY test framework (phy-test-get, phy-test-act) Shubham Das
  0 siblings, 2 replies; 3+ messages in thread
From: Shubham Das @ 2026-08-25  4:37 UTC (permalink / raw)
  To: netdev, andrew, maxime.chevallier, alexander.duyck, lee
  Cc: siddaraju.dh, balaji.chintalapalle, dasshubhamk,
	magnus.k.lindberg, jonas.wirandi, Shubham Das

This series adds two new ethtool netlink commands:

1. intf-caps-get: Discovers the functional block layout of a network
   interface. Each block represents a hardware point (MAC/PHY/MODULE)
   at a specific 802.3 sublayer (RS/PCS/FEC/PMA/PMD) with its
   supported capabilities (loopback, test patterns, BERT, error
   injection).

2. phy-test-get / phy-test-act: Per-block, per-lane PHY testing using
   test patterns, BERT (Bit Error Ratio Test), and error injection.
   The block_id from intf-caps-get identifies which hardware point
   to test.

The block model uses:
  - component: which hardware entity (MAC, PHY, MODULE)
  - sublayer: which 802.3 layer (RS, PCS, FEC, PMA, PMD)
  - instance: identifies multiple instances of the same component
    (e.g., internal vs external PHY)
  - depth: host-side vs line-side within the same sublayer

Prior discussion on this proposal:
Link: https://lore.kernel.org/netdev/SN7PR11MB810923BBDEC398E860099150FF1B2@SN7PR11MB8109.namprd11.prod.outlook.com/

Shubham Das (2):
  ethtool: add interface capabilities query (intf-caps-get)
  ethtool: add PHY test framework (phy-test-get, phy-test-act)

 Documentation/netlink/specs/ethtool.yaml      | 206 ++++++++++++++++++
 include/linux/ethtool.h                       |  92 ++++++++
 .../uapi/linux/ethtool_netlink_generated.h    | 104 +++++++++
 net/ethtool/Makefile                          |   2 +-
 net/ethtool/intf_caps.c                       | 130 +++++++++++
 net/ethtool/netlink.c                         |  24 ++
 net/ethtool/netlink.h                         |   7 +
 net/ethtool/phytest.c                         | 171 +++++++++++++++
 8 files changed, 735 insertions(+), 1 deletion(-)
 create mode 100644 net/ethtool/intf_caps.c
 create mode 100644 net/ethtool/phytest.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC PATCH net-next 1/2] ethtool: add interface capabilities query (intf-caps-get)
  2026-08-25  4:37 [RFC PATCH net-next 0/2] ethtool: add interface capabilities and PHY test Shubham Das
@ 2026-08-25  4:37 ` Shubham Das
  2026-08-25  4:37 ` [RFC PATCH net-next 2/2] ethtool: add PHY test framework (phy-test-get, phy-test-act) Shubham Das
  1 sibling, 0 replies; 3+ messages in thread
From: Shubham Das @ 2026-08-25  4:37 UTC (permalink / raw)
  To: netdev, andrew, maxime.chevallier, alexander.duyck, lee
  Cc: siddaraju.dh, balaji.chintalapalle, dasshubhamk,
	magnus.k.lindberg, jonas.wirandi, Shubham Das

Modern network interfaces contain multiple functional blocks along
the data path (MAC, PHY, MODULE), each at different 802.3 sublayers
(RS, PCS, FEC, PMA, PMD). Currently there is no standard way for
userspace to discover this topology or query which blocks support
loopback, pattern generation, or BERT.

Add ETHTOOL_MSG_INTF_CAPS_GET so drivers can expose the block layout
and per-block capabilities. This allows userspace to discover the
interface topology and testing capabilities dynamically, rather than
relying on device-specific knowledge.

Each block reports:
  - id: unique block identifier for per-block commands
  - component: MAC, PHY, or MODULE
  - sublayer: RS, PCS, FEC, PMA, PMD, or NONE
  - instance: distinguishes multiple instances of the same component
    (e.g., internal vs external PHY, host vs port MAC)
  - name: driver-chosen label (e.g., host-pma, ext-phy-pma)
  - depth: ordering within same (component, sublayer) tuple
  - lanes: number of SerDes lanes at this block
  - loopback_supported: bitmask of supported loopback directions
  - supported_tx_patterns: bitmask of patterns block can generate
  - supported_rx_patterns: bitmask of patterns block can check
  - error_inject_supported: block supports bit error injection
  - bert_supported: block supports BERT (Bit Error Ratio Test)

Signed-off-by: Shubham Das <shubham.das@intel.com>
---
 Documentation/netlink/specs/ethtool.yaml      |  99 +++++++++++++
 include/linux/ethtool.h                       |  49 +++++++
 .../uapi/linux/ethtool_netlink_generated.h    |  48 +++++++
 net/ethtool/Makefile                          |   2 +-
 net/ethtool/intf_caps.c                       | 130 ++++++++++++++++++
 net/ethtool/netlink.c                         |  10 ++
 net/ethtool/netlink.h                         |   2 +
 7 files changed, 339 insertions(+), 1 deletion(-)
 create mode 100644 net/ethtool/intf_caps.c

diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 5dd4d1b5d94b..77d77a896fb0 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -210,6 +210,25 @@ definitions:
       -
         name: discard
         value: 31
+  -
+    name: intf-component
+    type: enum
+    doc: Type of hardware component in the interface.
+    entries:
+      - mac
+      - phy
+      - module
+  -
+    name: intf-sublayer
+    type: enum
+    doc: 802.3 sublayer within a component.
+    entries:
+      - none
+      - rs
+      - pcs
+      - fec
+      - pma
+      - pmd
 
 attribute-sets:
   -
@@ -1905,6 +1924,73 @@ attribute-sets:
         name: link
         type: nest
         nested-attributes: mse-snapshot
+  -
+    name: intf-block
+    doc: A single functional block in the interface.
+    attributes:
+      -
+        name: id
+        type: u32
+      -
+        name: component
+        type: u32
+        enum: intf-component
+      -
+        name: sublayer
+        type: u32
+        enum: intf-sublayer
+      -
+        name: instance
+        type: u32
+        doc: |
+          Identifies the hardware entity when multiple instances of
+          the same component exist in the interface. The driver
+          assigns instance numbers sequentially based on position in
+          the physical path. Defaults to 0 when only one instance of
+          a given component exists.
+          For PHY: instance 0 is the internal/host-side PHY,
+          instance 1 is an external PHY further along the path
+          toward the line side.
+          For MAC: instance 0 is the host-facing MAC, instance 1 is
+          a secondary MAC further along the data path (e.g., behind
+          an embedded switch).
+      -
+        name: name
+        type: string
+      -
+        name: depth
+        type: u8
+      -
+        name: lanes
+        type: u32
+      -
+        name: loopback-supported
+        type: u32
+      -
+        name: supported-tx-patterns
+        type: u32
+      -
+        name: supported-rx-patterns
+        type: u32
+      -
+        name: error-inject-supported
+        type: flag
+      -
+        name: bert-supported
+        type: flag
+  -
+    name: intf-caps
+    doc: Interface capabilities message.
+    attributes:
+      -
+        name: header
+        type: nest
+        nested-attributes: header
+      -
+        name: blocks
+        type: nest
+        nested-attributes: intf-block
+        multi-attr: true
 
 operations:
   enum-model: directional
@@ -2859,6 +2945,19 @@ operations:
             - worst-channel
             - link
       dump: *mse-get-op
+    -
+      name: intf-caps-get
+      doc: Get interface capabilities (functional block layout).
+      attribute-set: intf-caps
+      do: &intf-caps-get-op
+        request:
+          attributes:
+            - header
+        reply:
+          attributes:
+            - header
+            - blocks
+      dump: *intf-caps-get-op
 
 mcast-groups:
   list:
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 12683b5d125e..3465f9c2f0aa 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1197,6 +1197,53 @@ struct kernel_ethtool_ts_info {
  * See &struct net_device and &struct net_device_ops for documentation
  * of the generic netdev features interface.
  */
+
+#define INTF_CAPS_MAX_BLOCKS	16
+#define INTF_BLOCK_NAME_LEN	32
+
+#define LOOPBACK_SUPPORT_LOCAL	BIT(0)
+#define LOOPBACK_SUPPORT_REMOTE	BIT(1)
+
+/**
+ * struct ethtool_intf_block - Single functional block in the interface
+ * @id: Unique block identifier
+ * @component: Hardware component (MAC, PHY, MODULE)
+ * @sublayer: 802.3 sublayer (RS, PCS, FEC, PMA, PMD, or NONE)
+ * @instance: Index when multiple instances of same component exist
+ * @name: Driver-chosen label
+ * @depth: Ordering within same (component, sublayer) tuple
+ * @lanes: Number of lanes
+ * @loopback_supported: Bitmask of supported loopback directions
+ * @supported_tx_patterns: Bitmask of patterns this block can generate
+ * @supported_rx_patterns: Bitmask of patterns this block can check
+ * @error_inject_supported: Block supports bit error injection
+ * @bert_supported: Block supports BERT counters
+ */
+struct ethtool_intf_block {
+	u32 id;
+	enum intf_component component;
+	enum intf_sublayer sublayer;
+	u32 instance;
+	char name[INTF_BLOCK_NAME_LEN];
+	u8 depth;
+	u32 lanes;
+	u32 loopback_supported;
+	u32 supported_tx_patterns;
+	u32 supported_rx_patterns;
+	bool error_inject_supported;
+	bool bert_supported;
+};
+
+/**
+ * struct ethtool_intf_caps - Interface capabilities (all blocks)
+ * @num_blocks: Number of valid entries in blocks[]
+ * @blocks: Array of functional blocks
+ */
+struct ethtool_intf_caps {
+	u32 num_blocks;
+	struct ethtool_intf_block blocks[INTF_CAPS_MAX_BLOCKS];
+};
+
 struct ethtool_ops {
 	u32     supported_input_xfrm:8;
 	u32     cap_link_lanes_supported:1;
@@ -1354,6 +1401,8 @@ struct ethtool_ops {
 	int	(*set_mm)(struct net_device *dev, struct ethtool_mm_cfg *cfg,
 			  struct netlink_ext_ack *extack);
 	void	(*get_mm_stats)(struct net_device *dev, struct ethtool_mm_stats *stats);
+	int	(*get_intf_caps)(struct net_device *dev,
+				 struct ethtool_intf_caps *caps);
 };
 
 int ethtool_check_ops(const struct ethtool_ops *ops);
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index 8134baf7860f..bd4cca1cc4fc 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -893,6 +893,7 @@ enum {
 	ETHTOOL_MSG_RSS_CREATE_ACT,
 	ETHTOOL_MSG_RSS_DELETE_ACT,
 	ETHTOOL_MSG_MSE_GET,
+	ETHTOOL_MSG_INTF_CAPS_GET,
 
 	__ETHTOOL_MSG_USER_CNT,
 	ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1)
@@ -954,6 +955,7 @@ enum {
 	ETHTOOL_MSG_RSS_CREATE_NTF,
 	ETHTOOL_MSG_RSS_DELETE_NTF,
 	ETHTOOL_MSG_MSE_GET_REPLY,
+	ETHTOOL_MSG_INTF_CAPS_GET_REPLY,
 
 	__ETHTOOL_MSG_KERNEL_CNT,
 	ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
@@ -961,4 +963,50 @@ enum {
 
 #define ETHTOOL_MCGRP_MONITOR_NAME	"monitor"
 
+/* Interface component types */
+enum intf_component {
+	INTF_COMPONENT_MAC,
+	INTF_COMPONENT_PHY,
+	INTF_COMPONENT_MODULE,
+};
+
+/* Interface sublayer types */
+enum intf_sublayer {
+	INTF_SUBLAYER_NONE,
+	INTF_SUBLAYER_RS,
+	INTF_SUBLAYER_PCS,
+	INTF_SUBLAYER_FEC,
+	INTF_SUBLAYER_PMA,
+	INTF_SUBLAYER_PMD,
+};
+
+/* Attributes of a single interface block */
+enum {
+	ETHTOOL_A_INTF_BLOCK_ID,
+	ETHTOOL_A_INTF_BLOCK_COMPONENT,
+	ETHTOOL_A_INTF_BLOCK_SUBLAYER,
+	ETHTOOL_A_INTF_BLOCK_INSTANCE,
+	ETHTOOL_A_INTF_BLOCK_NAME,
+	ETHTOOL_A_INTF_BLOCK_DEPTH,
+	ETHTOOL_A_INTF_BLOCK_LANES,
+	ETHTOOL_A_INTF_BLOCK_LOOPBACK_SUPPORTED,
+	ETHTOOL_A_INTF_BLOCK_TX_PATTERNS,
+	ETHTOOL_A_INTF_BLOCK_RX_PATTERNS,
+	ETHTOOL_A_INTF_BLOCK_ERROR_INJECT,
+	ETHTOOL_A_INTF_BLOCK_BERT,
+
+	__ETHTOOL_A_INTF_BLOCK_CNT,
+	ETHTOOL_A_INTF_BLOCK_MAX = (__ETHTOOL_A_INTF_BLOCK_CNT - 1)
+};
+
+/* Attributes of intf-caps-get message */
+enum {
+	ETHTOOL_A_INTF_CAPS_UNSPEC,
+	ETHTOOL_A_INTF_CAPS_HEADER,
+	ETHTOOL_A_INTF_CAPS_BLOCKS,
+
+	__ETHTOOL_A_INTF_CAPS_CNT,
+	ETHTOOL_A_INTF_CAPS_MAX = (__ETHTOOL_A_INTF_CAPS_CNT - 1)
+};
+
 #endif /* _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H */
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 629c10916670..773b21c7ab7c 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -9,4 +9,4 @@ ethtool_nl-y	:= netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
 		   channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
 		   tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
 		   module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o \
-		   phy.o tsconfig.o mse.o
+		   phy.o tsconfig.o mse.o intf_caps.o
diff --git a/net/ethtool/intf_caps.c b/net/ethtool/intf_caps.c
new file mode 100644
index 000000000000..e45ccc4b88c9
--- /dev/null
+++ b/net/ethtool/intf_caps.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "netlink.h"
+#include "common.h"
+
+struct intf_caps_req_info {
+	struct ethnl_req_info base;
+};
+
+struct intf_caps_reply_data {
+	struct ethnl_reply_data base;
+	struct ethtool_intf_caps caps;
+};
+
+#define INTF_CAPS_REPDATA(__reply_base) \
+	container_of(__reply_base, struct intf_caps_reply_data, base)
+
+const struct nla_policy ethnl_intf_caps_get_policy[ETHTOOL_A_INTF_CAPS_HEADER + 1] = {
+	[ETHTOOL_A_INTF_CAPS_HEADER] =
+		NLA_POLICY_NESTED(ethnl_header_policy),
+};
+
+static int intf_caps_reply_size(const struct ethnl_req_info *req_base,
+				const struct ethnl_reply_data *reply_base)
+{
+	const struct intf_caps_reply_data *data = INTF_CAPS_REPDATA(reply_base);
+	int len = 0;
+	u32 i;
+
+	for (i = 0; i < data->caps.num_blocks; i++) {
+		len += nla_total_size(0);		/* nested block */
+		len += nla_total_size(sizeof(u32));	/* id */
+		len += nla_total_size(sizeof(u32));	/* component */
+		len += nla_total_size(sizeof(u32));	/* sublayer */
+		len += nla_total_size(sizeof(u32));	/* instance */
+		len += nla_total_size(INTF_BLOCK_NAME_LEN); /* name */
+		len += nla_total_size(sizeof(u8));	/* depth */
+		len += nla_total_size(sizeof(u32));	/* lanes */
+		len += nla_total_size(sizeof(u32));	/* loopback_supported */
+		len += nla_total_size(sizeof(u32));	/* tx_patterns */
+		len += nla_total_size(sizeof(u32));	/* rx_patterns */
+		len += nla_total_size(0);		/* error_inject (flag) */
+		len += nla_total_size(0);		/* bert (flag) */
+	}
+
+	/* outer BLOCKS nest */
+	len += nla_total_size(0);
+
+	return len;
+}
+
+static int intf_caps_prepare_data(const struct ethnl_req_info *req_base,
+				  struct ethnl_reply_data *reply_base,
+				  const struct genl_info *info)
+{
+	struct intf_caps_reply_data *data = INTF_CAPS_REPDATA(reply_base);
+	struct net_device *dev = reply_base->dev;
+
+	if (!dev->ethtool_ops->get_intf_caps)
+		return -EOPNOTSUPP;
+
+	return dev->ethtool_ops->get_intf_caps(dev, &data->caps);
+}
+
+static int intf_caps_fill_reply(struct sk_buff *skb,
+				const struct ethnl_req_info *req_base,
+				const struct ethnl_reply_data *reply_base)
+{
+	const struct intf_caps_reply_data *data = INTF_CAPS_REPDATA(reply_base);
+	struct nlattr *blocks_attr;
+	u32 i;
+
+	blocks_attr = nla_nest_start(skb, ETHTOOL_A_INTF_CAPS_BLOCKS);
+	if (!blocks_attr)
+		return -EMSGSIZE;
+
+	for (i = 0; i < data->caps.num_blocks; i++) {
+		const struct ethtool_intf_block *b = &data->caps.blocks[i];
+		struct nlattr *block_attr;
+
+		block_attr = nla_nest_start(skb, 0);
+		if (!block_attr)
+			goto nla_put_failure;
+
+		if (nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_ID, b->id) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_COMPONENT,
+				b->component) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_SUBLAYER,
+				b->sublayer) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_INSTANCE,
+				b->instance) ||
+		    nla_put_string(skb, ETHTOOL_A_INTF_BLOCK_NAME, b->name) ||
+		    nla_put_u8(skb, ETHTOOL_A_INTF_BLOCK_DEPTH, b->depth) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_LANES, b->lanes) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_LOOPBACK_SUPPORTED,
+				b->loopback_supported) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_TX_PATTERNS,
+				b->supported_tx_patterns) ||
+		    nla_put_u32(skb, ETHTOOL_A_INTF_BLOCK_RX_PATTERNS,
+				b->supported_rx_patterns))
+			goto nla_put_failure;
+		if (b->error_inject_supported &&
+		    nla_put_flag(skb, ETHTOOL_A_INTF_BLOCK_ERROR_INJECT))
+			goto nla_put_failure;
+		if (b->bert_supported &&
+		    nla_put_flag(skb, ETHTOOL_A_INTF_BLOCK_BERT))
+			goto nla_put_failure;
+			goto nla_put_failure;
+
+		nla_nest_end(skb, block_attr);
+	}
+
+	nla_nest_end(skb, blocks_attr);
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, blocks_attr);
+	return -EMSGSIZE;
+}
+
+const struct ethnl_request_ops ethnl_intf_caps_request_ops = {
+	.request_cmd	= ETHTOOL_MSG_INTF_CAPS_GET,
+	.reply_cmd	= ETHTOOL_MSG_INTF_CAPS_GET_REPLY,
+	.hdr_attr	= ETHTOOL_A_INTF_CAPS_HEADER,
+	.req_info_size	= sizeof(struct intf_caps_req_info),
+	.reply_data_size = sizeof(struct intf_caps_reply_data),
+	.prepare_data	= intf_caps_prepare_data,
+	.reply_size	= intf_caps_reply_size,
+	.fill_reply	= intf_caps_fill_reply,
+};
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1af395b54330..e90dae573452 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -431,6 +431,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
 	[ETHTOOL_MSG_TSCONFIG_SET]	= &ethnl_tsconfig_request_ops,
 	[ETHTOOL_MSG_PHY_GET]		= &ethnl_phy_request_ops,
 	[ETHTOOL_MSG_MSE_GET]		= &ethnl_mse_request_ops,
+	[ETHTOOL_MSG_INTF_CAPS_GET]	= &ethnl_intf_caps_request_ops,
 };
 
 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1572,6 +1573,15 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.policy = ethnl_mse_get_policy,
 		.maxattr = ARRAY_SIZE(ethnl_mse_get_policy) - 1,
 	},
+	{
+		.cmd	= ETHTOOL_MSG_INTF_CAPS_GET,
+		.doit	= ethnl_default_doit,
+		.start	= ethnl_default_start,
+		.dumpit	= ethnl_default_dumpit,
+		.done	= ethnl_default_done,
+		.policy = ethnl_intf_caps_get_policy,
+		.maxattr = ARRAY_SIZE(ethnl_intf_caps_get_policy) - 1,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 3e969a070f9f..32b16f81f453 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -474,6 +474,7 @@ extern const struct ethnl_request_ops ethnl_mm_request_ops;
 extern const struct ethnl_request_ops ethnl_phy_request_ops;
 extern const struct ethnl_request_ops ethnl_tsconfig_request_ops;
 extern const struct ethnl_request_ops ethnl_mse_request_ops;
+extern const struct ethnl_request_ops ethnl_intf_caps_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];
@@ -530,6 +531,7 @@ extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1];
 extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1];
 extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1];
 extern const struct nla_policy ethnl_mse_get_policy[ETHTOOL_A_MSE_HEADER + 1];
+extern const struct nla_policy ethnl_intf_caps_get_policy[ETHTOOL_A_INTF_CAPS_HEADER + 1];
 
 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH net-next 2/2] ethtool: add PHY test framework (phy-test-get, phy-test-act)
  2026-08-25  4:37 [RFC PATCH net-next 0/2] ethtool: add interface capabilities and PHY test Shubham Das
  2026-08-25  4:37 ` [RFC PATCH net-next 1/2] ethtool: add interface capabilities query (intf-caps-get) Shubham Das
@ 2026-08-25  4:37 ` Shubham Das
  1 sibling, 0 replies; 3+ messages in thread
From: Shubham Das @ 2026-08-25  4:37 UTC (permalink / raw)
  To: netdev, andrew, maxime.chevallier, alexander.duyck, lee
  Cc: siddaraju.dh, balaji.chintalapalle, dasshubhamk,
	magnus.k.lindberg, jonas.wirandi, Shubham Das

Add ETHTOOL_MSG_PHY_TEST_GET and ETHTOOL_MSG_PHY_TEST_ACT to
configure and monitor PHY test functions on individual interface
blocks and lanes.

The framework uses the block identifier returned by
ETHTOOL_MSG_INTF_CAPS_GET to select the hardware block under test.
This allows userspace to target test operations at specific PHY, MAC,
or module datapath components exposed by the driver.

Supported test patterns:
  - PRBS: prbs7, prbs9, prbs11, prbs13, prbs15, prbs23, prbs31
  - PRBS quaternary (PAM4): prbs13q, prbs31q
  - SSPRQ (Short Stress Pattern Random Quaternary)
  - Square wave: square-nrz, square-pam4 (JP03A)
  - TX linearity (LIN, IEEE 802.3 94.2.9.4)
  - Scrambled idle
  - 8b/10b comma: K28.5, K28.7

Supported test actions:
  - bert start / stop: bit error ratio measurement
  - inject-errors N: inject bit errors into the TX stream
  - active-tests: bitmask showing which tests are running

Usage flow:
  1. ethtool --get-intf-caps eth1     # discover testable blocks
  2. ethtool --phy-test eth1 block 3 lane 0 tx-pattern prbs31
  3. ethtool --phy-test eth2 block 3 lane 0 rx-pattern prbs31
  4. ethtool --phy-test eth2 block 3 lane 0 bert start
  5. ethtool --show-phy-test eth2 block 3  # read BERT counters
  6. ethtool --phy-test eth2 block 3 lane 0 inject-errors 5  # verify checker
  7. ethtool --show-phy-test eth2 block 3  # confirm error count increased
  8. ethtool --phy-test eth2 block 3 lane 0 bert stop

Signed-off-by: Shubham Das <shubham.das@intel.com>
---
 Documentation/netlink/specs/ethtool.yaml      | 107 +++++++++++
 include/linux/ethtool.h                       |  43 +++++
 .../uapi/linux/ethtool_netlink_generated.h    |  56 ++++++
 net/ethtool/Makefile                          |   2 +-
 net/ethtool/netlink.c                         |  14 ++
 net/ethtool/netlink.h                         |   5 +
 net/ethtool/phytest.c                         | 171 ++++++++++++++++++
 7 files changed, 397 insertions(+), 1 deletion(-)
 create mode 100644 net/ethtool/phytest.c

diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 77d77a896fb0..361eb3c66577 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -229,6 +229,36 @@ definitions:
       - fec
       - pma
       - pmd
+  -
+    name: phy-test-pattern
+    type: enum
+    doc: PHY test pattern types for PRBS generation/checking.
+    entries:
+      - off
+      - prbs7
+      - prbs9
+      - prbs11
+      - prbs13
+      - prbs15
+      - prbs23
+      - prbs31
+      - ssprq
+      - prbs13q
+      - prbs31q
+      - square-nrz
+      - square-pam4
+      - tx-linearity
+      - scrambled-idle
+      - k28-5
+      - k28-7
+  -
+    name: phy-test-action
+    type: enum
+    doc: BERT control actions.
+    entries:
+      - none
+      - start
+      - stop
 
 attribute-sets:
   -
@@ -1991,6 +2021,48 @@ attribute-sets:
         type: nest
         nested-attributes: intf-block
         multi-attr: true
+  -
+    name: phy-test
+    doc: PHY test configuration and status.
+    attributes:
+      -
+        name: header
+        type: nest
+        nested-attributes: header
+      -
+        name: block-id
+        type: u32
+      -
+        name: lane
+        type: u32
+      -
+        name: tx-pattern
+        type: u32
+        enum: phy-test-pattern
+      -
+        name: rx-pattern
+        type: u32
+        enum: phy-test-pattern
+      -
+        name: bert-action
+        type: u32
+        enum: phy-test-action
+      -
+        name: inject-error-count
+        type: u32
+      -
+        name: active-tests
+        type: u32
+        doc: Bitmask of currently running tests (bit 0 = BERT).
+      -
+        name: checker-lock
+        type: u8
+      -
+        name: error-count
+        type: u64
+      -
+        name: total-bits-sent
+        type: u64
 
 operations:
   enum-model: directional
@@ -2958,6 +3030,41 @@ operations:
             - header
             - blocks
       dump: *intf-caps-get-op
+    -
+      name: phy-test-get
+      doc: Get PHY test status (patterns, BERT counters).
+      attribute-set: phy-test
+      do:
+        request:
+          attributes:
+            - header
+            - block-id
+            - lane
+        reply:
+          attributes:
+            - header
+            - block-id
+            - lane
+            - tx-pattern
+            - rx-pattern
+            - active-tests
+            - checker-lock
+            - error-count
+            - total-bits-sent
+    -
+      name: phy-test-act
+      doc: Configure PHY test (set patterns, start/stop BERT, inject errors).
+      attribute-set: phy-test
+      do:
+        request:
+          attributes:
+            - header
+            - block-id
+            - lane
+            - tx-pattern
+            - rx-pattern
+            - bert-action
+            - inject-error-count
 
 mcast-groups:
   list:
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 3465f9c2f0aa..f9748e739f03 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1244,6 +1244,45 @@ struct ethtool_intf_caps {
 	struct ethtool_intf_block blocks[INTF_CAPS_MAX_BLOCKS];
 };
 
+/* Bitmask of which ethtool_phy_test fields were explicitly specified */
+#define PHY_TEST_CMD_TX_PATTERN		BIT(0)
+#define PHY_TEST_CMD_RX_PATTERN		BIT(1)
+#define PHY_TEST_CMD_BERT_ACTION		BIT(2)
+#define PHY_TEST_CMD_INJECT_COUNT		BIT(3)
+#define PHY_TEST_CMD_LANE			BIT(4)
+#define PHY_TEST_CMD_BLOCK_ID			BIT(5)
+
+/* Bitmask of currently active tests (read-only) */
+#define PHY_TEST_ACTIVE_BERT		BIT(0)
+
+/**
+ * struct ethtool_phy_test - PHY test configuration and status
+ * @cmd: Bitmask of which fields are valid (PHY_TEST_CMD_*)
+ * @block_id: Block to operate on (from intf-caps-get)
+ * @lane: Lane number (0-based)
+ * @tx_pattern: TX pattern generator setting
+ * @rx_pattern: RX pattern checker setting
+ * @bert_action: BERT start/stop control
+ * @inject_error_count: Number of errors to inject
+ * @active_tests: Bitmask of running tests (PHY_TEST_ACTIVE_*)
+ * @checker_lock: RX checker lock status (read-only)
+ * @error_count: BERT error counter (read-only)
+ * @total_bits_sent: BERT total bits counter (read-only)
+ */
+struct ethtool_phy_test {
+	u32 cmd;
+	u32 block_id;
+	u32 lane;
+	enum phy_test_pattern tx_pattern;
+	enum phy_test_pattern rx_pattern;
+	enum phy_test_action bert_action;
+	u32 inject_error_count;
+	u32 active_tests;
+	u8 checker_lock;
+	u64 error_count;
+	u64 total_bits_sent;
+};
+
 struct ethtool_ops {
 	u32     supported_input_xfrm:8;
 	u32     cap_link_lanes_supported:1;
@@ -1403,6 +1442,10 @@ struct ethtool_ops {
 	void	(*get_mm_stats)(struct net_device *dev, struct ethtool_mm_stats *stats);
 	int	(*get_intf_caps)(struct net_device *dev,
 				 struct ethtool_intf_caps *caps);
+	int	(*get_phy_test)(struct net_device *dev,
+				struct ethtool_phy_test *test);
+	int	(*set_phy_test)(struct net_device *dev,
+				struct ethtool_phy_test *test);
 };
 
 int ethtool_check_ops(const struct ethtool_ops *ops);
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index bd4cca1cc4fc..3102bb7ba337 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -894,6 +894,8 @@ enum {
 	ETHTOOL_MSG_RSS_DELETE_ACT,
 	ETHTOOL_MSG_MSE_GET,
 	ETHTOOL_MSG_INTF_CAPS_GET,
+	ETHTOOL_MSG_PHY_TEST_GET,
+	ETHTOOL_MSG_PHY_TEST_ACT,
 
 	__ETHTOOL_MSG_USER_CNT,
 	ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1)
@@ -956,6 +958,7 @@ enum {
 	ETHTOOL_MSG_RSS_DELETE_NTF,
 	ETHTOOL_MSG_MSE_GET_REPLY,
 	ETHTOOL_MSG_INTF_CAPS_GET_REPLY,
+	ETHTOOL_MSG_PHY_TEST_GET_REPLY,
 
 	__ETHTOOL_MSG_KERNEL_CNT,
 	ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
@@ -1009,4 +1012,57 @@ enum {
 	ETHTOOL_A_INTF_CAPS_MAX = (__ETHTOOL_A_INTF_CAPS_CNT - 1)
 };
 
+/* PHY test pattern types */
+enum phy_test_pattern {
+	PHY_TEST_PATTERN_OFF,
+	PHY_TEST_PATTERN_PRBS7,
+	PHY_TEST_PATTERN_PRBS9,
+	PHY_TEST_PATTERN_PRBS11,
+	PHY_TEST_PATTERN_PRBS13,
+	PHY_TEST_PATTERN_PRBS15,
+	PHY_TEST_PATTERN_PRBS23,
+	PHY_TEST_PATTERN_PRBS31,
+	PHY_TEST_PATTERN_SSPRQ,
+	PHY_TEST_PATTERN_PRBS13Q,
+	PHY_TEST_PATTERN_PRBS31Q,
+	PHY_TEST_PATTERN_SQUARE_NRZ,
+	PHY_TEST_PATTERN_SQUARE_PAM4,
+	PHY_TEST_PATTERN_TX_LINEARITY,
+	PHY_TEST_PATTERN_SCRAMBLED_IDLE,
+	PHY_TEST_PATTERN_K28_5,
+	PHY_TEST_PATTERN_K28_7,
+
+	__PHY_TEST_PATTERN_COUNT,
+	PHY_TEST_PATTERN_MAX = (__PHY_TEST_PATTERN_COUNT - 1)
+};
+
+/* PHY test BERT actions */
+enum phy_test_action {
+	PHY_TEST_ACTION_NONE,
+	PHY_TEST_ACTION_START,
+	PHY_TEST_ACTION_STOP,
+
+	__PHY_TEST_ACTION_COUNT,
+	PHY_TEST_ACTION_MAX = (__PHY_TEST_ACTION_COUNT - 1)
+};
+
+/* Attributes of phy-test-get / phy-test-act messages */
+enum {
+	ETHTOOL_A_PHY_TEST_UNSPEC,
+	ETHTOOL_A_PHY_TEST_HEADER,
+	ETHTOOL_A_PHY_TEST_BLOCK_ID,
+	ETHTOOL_A_PHY_TEST_LANE,
+	ETHTOOL_A_PHY_TEST_TX_PATTERN,
+	ETHTOOL_A_PHY_TEST_RX_PATTERN,
+	ETHTOOL_A_PHY_TEST_BERT_ACTION,
+	ETHTOOL_A_PHY_TEST_INJECT_ERROR_COUNT,
+	ETHTOOL_A_PHY_TEST_ACTIVE_TESTS,
+	ETHTOOL_A_PHY_TEST_CHECKER_LOCK,
+	ETHTOOL_A_PHY_TEST_ERROR_COUNT,
+	ETHTOOL_A_PHY_TEST_TOTAL_BITS_SENT,
+
+	__ETHTOOL_A_PHY_TEST_CNT,
+	ETHTOOL_A_PHY_TEST_MAX = (__ETHTOOL_A_PHY_TEST_CNT - 1)
+};
+
 #endif /* _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H */
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 773b21c7ab7c..7dd2c5624ced 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -9,4 +9,4 @@ ethtool_nl-y	:= netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
 		   channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
 		   tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
 		   module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o \
-		   phy.o tsconfig.o mse.o intf_caps.o
+		   phy.o tsconfig.o mse.o intf_caps.o phytest.o
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index e90dae573452..56e5c811454b 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -432,6 +432,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
 	[ETHTOOL_MSG_PHY_GET]		= &ethnl_phy_request_ops,
 	[ETHTOOL_MSG_MSE_GET]		= &ethnl_mse_request_ops,
 	[ETHTOOL_MSG_INTF_CAPS_GET]	= &ethnl_intf_caps_request_ops,
+	[ETHTOOL_MSG_PHY_TEST_GET]	= &ethnl_phy_test_request_ops,
 };
 
 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1582,6 +1583,19 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.policy = ethnl_intf_caps_get_policy,
 		.maxattr = ARRAY_SIZE(ethnl_intf_caps_get_policy) - 1,
 	},
+	{
+		.cmd	= ETHTOOL_MSG_PHY_TEST_GET,
+		.doit	= ethnl_default_doit,
+		.policy = ethnl_phy_test_get_policy,
+		.maxattr = ARRAY_SIZE(ethnl_phy_test_get_policy) - 1,
+	},
+	{
+		.cmd	= ETHTOOL_MSG_PHY_TEST_ACT,
+		.flags	= GENL_UNS_ADMIN_PERM,
+		.doit	= ethnl_act_phy_test,
+		.policy = ethnl_phy_test_act_policy,
+		.maxattr = ARRAY_SIZE(ethnl_phy_test_act_policy) - 1,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 32b16f81f453..1caba60d83c4 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -475,6 +475,7 @@ extern const struct ethnl_request_ops ethnl_phy_request_ops;
 extern const struct ethnl_request_ops ethnl_tsconfig_request_ops;
 extern const struct ethnl_request_ops ethnl_mse_request_ops;
 extern const struct ethnl_request_ops ethnl_intf_caps_request_ops;
+extern const struct ethnl_request_ops ethnl_phy_test_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];
@@ -532,6 +533,10 @@ extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEAD
 extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1];
 extern const struct nla_policy ethnl_mse_get_policy[ETHTOOL_A_MSE_HEADER + 1];
 extern const struct nla_policy ethnl_intf_caps_get_policy[ETHTOOL_A_INTF_CAPS_HEADER + 1];
+extern const struct nla_policy ethnl_phy_test_get_policy[ETHTOOL_A_PHY_TEST_LANE + 1];
+extern const struct nla_policy ethnl_phy_test_act_policy[ETHTOOL_A_PHY_TEST_MAX + 1];
+
+int ethnl_act_phy_test(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
diff --git a/net/ethtool/phytest.c b/net/ethtool/phytest.c
new file mode 100644
index 000000000000..dedcd036b7c2
--- /dev/null
+++ b/net/ethtool/phytest.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "netlink.h"
+#include "common.h"
+
+struct phy_test_req_info {
+	struct ethnl_req_info base;
+};
+
+struct phy_test_reply_data {
+	struct ethnl_reply_data base;
+	struct ethtool_phy_test test;
+};
+
+#define PHY_TEST_REPDATA(__reply_base) \
+	container_of(__reply_base, struct phy_test_reply_data, base)
+
+/* PHY_TEST_GET */
+
+const struct nla_policy ethnl_phy_test_get_policy[ETHTOOL_A_PHY_TEST_LANE + 1] = {
+	[ETHTOOL_A_PHY_TEST_HEADER]	= NLA_POLICY_NESTED(ethnl_header_policy),
+	[ETHTOOL_A_PHY_TEST_BLOCK_ID]	= { .type = NLA_U32 },
+	[ETHTOOL_A_PHY_TEST_LANE]	= { .type = NLA_U32 },
+};
+
+static int phy_test_reply_size(const struct ethnl_req_info *req_base,
+			       const struct ethnl_reply_data *reply_base)
+{
+	return nla_total_size(sizeof(u32)) +	/* block_id */
+	       nla_total_size(sizeof(u32)) +	/* lane */
+	       nla_total_size(sizeof(u32)) +	/* tx_pattern */
+	       nla_total_size(sizeof(u32)) +	/* rx_pattern */
+	       nla_total_size(sizeof(u32)) +	/* active_tests */
+	       nla_total_size(sizeof(u8))  +	/* checker_lock */
+	       nla_total_size(sizeof(u64)) +	/* error_count */
+	       nla_total_size(sizeof(u64));	/* total_bits_sent */
+}
+
+static int phy_test_prepare_data(const struct ethnl_req_info *req_base,
+				 struct ethnl_reply_data *reply_base,
+				 const struct genl_info *info)
+{
+	struct phy_test_reply_data *data = PHY_TEST_REPDATA(reply_base);
+	struct net_device *dev = reply_base->dev;
+	struct nlattr **tb = info->attrs;
+
+	if (!dev->ethtool_ops->get_phy_test)
+		return -EOPNOTSUPP;
+
+	memset(&data->test, 0, sizeof(data->test));
+
+	if (tb[ETHTOOL_A_PHY_TEST_BLOCK_ID]) {
+		data->test.block_id = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_BLOCK_ID]);
+		data->test.cmd |= PHY_TEST_CMD_BLOCK_ID;
+	}
+	if (tb[ETHTOOL_A_PHY_TEST_LANE]) {
+		data->test.lane = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_LANE]);
+		data->test.cmd |= PHY_TEST_CMD_LANE;
+	}
+
+	return dev->ethtool_ops->get_phy_test(dev, &data->test);
+}
+
+static int phy_test_fill_reply(struct sk_buff *skb,
+			       const struct ethnl_req_info *req_base,
+			       const struct ethnl_reply_data *reply_base)
+{
+	const struct phy_test_reply_data *data = PHY_TEST_REPDATA(reply_base);
+	const struct ethtool_phy_test *t = &data->test;
+
+	if (nla_put_u32(skb, ETHTOOL_A_PHY_TEST_BLOCK_ID, t->block_id) ||
+	    nla_put_u32(skb, ETHTOOL_A_PHY_TEST_LANE, t->lane) ||
+	    nla_put_u32(skb, ETHTOOL_A_PHY_TEST_TX_PATTERN, t->tx_pattern) ||
+	    nla_put_u32(skb, ETHTOOL_A_PHY_TEST_RX_PATTERN, t->rx_pattern) ||
+	    nla_put_u32(skb, ETHTOOL_A_PHY_TEST_ACTIVE_TESTS,
+			t->active_tests) ||
+	    nla_put_u8(skb, ETHTOOL_A_PHY_TEST_CHECKER_LOCK, t->checker_lock) ||
+	    nla_put_u64_64bit(skb, ETHTOOL_A_PHY_TEST_ERROR_COUNT,
+			      t->error_count, ETHTOOL_A_PHY_TEST_UNSPEC) ||
+	    nla_put_u64_64bit(skb, ETHTOOL_A_PHY_TEST_TOTAL_BITS_SENT,
+			      t->total_bits_sent, ETHTOOL_A_PHY_TEST_UNSPEC))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+const struct ethnl_request_ops ethnl_phy_test_request_ops = {
+	.request_cmd	= ETHTOOL_MSG_PHY_TEST_GET,
+	.reply_cmd	= ETHTOOL_MSG_PHY_TEST_GET_REPLY,
+	.hdr_attr	= ETHTOOL_A_PHY_TEST_HEADER,
+	.req_info_size	= sizeof(struct phy_test_req_info),
+	.reply_data_size = sizeof(struct phy_test_reply_data),
+	.prepare_data	= phy_test_prepare_data,
+	.reply_size	= phy_test_reply_size,
+	.fill_reply	= phy_test_fill_reply,
+};
+
+/* PHY_TEST_ACT */
+
+const struct nla_policy ethnl_phy_test_act_policy[ETHTOOL_A_PHY_TEST_MAX + 1] = {
+	[ETHTOOL_A_PHY_TEST_HEADER]		= NLA_POLICY_NESTED(ethnl_header_policy),
+	[ETHTOOL_A_PHY_TEST_BLOCK_ID]		= { .type = NLA_U32 },
+	[ETHTOOL_A_PHY_TEST_LANE]		= { .type = NLA_U32 },
+	[ETHTOOL_A_PHY_TEST_TX_PATTERN]		= { .type = NLA_U32 },
+	[ETHTOOL_A_PHY_TEST_RX_PATTERN]		= { .type = NLA_U32 },
+	[ETHTOOL_A_PHY_TEST_BERT_ACTION]	= { .type = NLA_U32 },
+	[ETHTOOL_A_PHY_TEST_INJECT_ERROR_COUNT]	= { .type = NLA_U32 },
+};
+
+int ethnl_act_phy_test(struct sk_buff *skb, struct genl_info *info)
+{
+	struct ethnl_req_info req_info = {};
+	struct nlattr **tb = info->attrs;
+	struct ethtool_phy_test test = {};
+	struct net_device *dev;
+	int ret;
+
+	ret = ethnl_parse_header_dev_get(&req_info,
+					 tb[ETHTOOL_A_PHY_TEST_HEADER],
+					 genl_info_net(info), info->extack,
+					 true);
+	if (ret < 0)
+		return ret;
+
+	dev = req_info.dev;
+
+	if (!dev->ethtool_ops->set_phy_test) {
+		ret = -EOPNOTSUPP;
+		goto out_dev;
+	}
+
+	if (tb[ETHTOOL_A_PHY_TEST_BLOCK_ID]) {
+		test.block_id = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_BLOCK_ID]);
+		test.cmd |= PHY_TEST_CMD_BLOCK_ID;
+	}
+	if (tb[ETHTOOL_A_PHY_TEST_LANE]) {
+		test.lane = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_LANE]);
+		test.cmd |= PHY_TEST_CMD_LANE;
+	}
+	if (tb[ETHTOOL_A_PHY_TEST_TX_PATTERN]) {
+		test.tx_pattern = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_TX_PATTERN]);
+		test.cmd |= PHY_TEST_CMD_TX_PATTERN;
+	}
+	if (tb[ETHTOOL_A_PHY_TEST_RX_PATTERN]) {
+		test.rx_pattern = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_RX_PATTERN]);
+		test.cmd |= PHY_TEST_CMD_RX_PATTERN;
+	}
+	if (tb[ETHTOOL_A_PHY_TEST_BERT_ACTION]) {
+		test.bert_action = nla_get_u32(tb[ETHTOOL_A_PHY_TEST_BERT_ACTION]);
+		test.cmd |= PHY_TEST_CMD_BERT_ACTION;
+	}
+	if (tb[ETHTOOL_A_PHY_TEST_INJECT_ERROR_COUNT]) {
+		test.inject_error_count =
+			nla_get_u32(tb[ETHTOOL_A_PHY_TEST_INJECT_ERROR_COUNT]);
+		test.cmd |= PHY_TEST_CMD_INJECT_COUNT;
+	}
+
+	rtnl_lock();
+	ret = ethnl_ops_begin(dev);
+	if (ret < 0)
+		goto out_rtnl;
+
+	ret = dev->ethtool_ops->set_phy_test(dev, &test);
+	ethnl_ops_complete(dev);
+
+out_rtnl:
+	rtnl_unlock();
+out_dev:
+	ethnl_parse_header_dev_put(&req_info);
+	return ret;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-25  4:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25  4:37 [RFC PATCH net-next 0/2] ethtool: add interface capabilities and PHY test Shubham Das
2026-08-25  4:37 ` [RFC PATCH net-next 1/2] ethtool: add interface capabilities query (intf-caps-get) Shubham Das
2026-08-25  4:37 ` [RFC PATCH net-next 2/2] ethtool: add PHY test framework (phy-test-get, phy-test-act) Shubham Das

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox