diff mbox series

[RFC,ethtool] phy-tunables: add support for get/set rx/tx latencies

Message ID 20220401093800.3341760-1-horatiu.vultur@microchip.com (mailing list archive)
State RFC
Delegated to: Michal Kubecek
Headers show
Series [RFC,ethtool] phy-tunables: add support for get/set rx/tx latencies | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Horatiu Vultur April 1, 2022, 9:38 a.m. UTC
Add support for "ethtool --set-phy-tunable <dev> latency-rx/tx-<speed> %d"
and "ethtool --get-phy-tunable <dev> latency-rx/tx-<speed>" to set/get
the latency of the PHY.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 ethtool.c            | 254 +++++++++++++++++++++++++++++++++++++++++++
 uapi/linux/ethtool.h |   6 +
 2 files changed, 260 insertions(+)
diff mbox series

Patch

diff --git a/ethtool.c b/ethtool.c
index 5d718a2..01e0594 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5257,6 +5257,96 @@  static int do_get_phy_tunable(struct cmd_context *ctx)
 			fprintf(stdout,
 				"Energy Detect Power Down: enabled, TX %u msecs\n",
 				cont.msecs);
+	} else if (!strcmp(argp[0], "latency-rx-1000mbit")) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_RX_1000MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		if (send_ioctl(ctx, &cont.latency) < 0) {
+			perror("Cannot Get PHY Latency RX 1000Mbit value");
+			return 87;
+		}
+		fprintf(stdout, "Latency RX 1000Mbit: %d\n", cont.lat);
+	} else if (!strcmp(argp[0], "latency-tx-1000mbit")) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_TX_1000MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		if (send_ioctl(ctx, &cont.latency) < 0) {
+			perror("Cannot Get PHY Latency TX 1000Mbit value");
+			return 87;
+		}
+		fprintf(stdout, "Latency TX 1000Mbit: %d\n", cont.lat);
+	} else if (!strcmp(argp[0], "latency-rx-100mbit")) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_RX_100MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		if (send_ioctl(ctx, &cont.latency) < 0) {
+			perror("Cannot Get PHY Latency RX 100Mbit value");
+			return 87;
+		}
+		fprintf(stdout, "Latency RX 100Mbit: %d\n", cont.lat);
+	} else if (!strcmp(argp[0], "latency-tx-100mbit")) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_TX_100MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		if (send_ioctl(ctx, &cont.latency) < 0) {
+			perror("Cannot Get PHY Latency TX 100Mbit value");
+			return 87;
+		}
+		fprintf(stdout, "Latency TX 100Mbit: %d\n", cont.lat);
+	} else if (!strcmp(argp[0], "latency-rx-10mbit")) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_RX_10MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		if (send_ioctl(ctx, &cont.latency) < 0) {
+			perror("Cannot Get PHY Latency RX 10Mbit value");
+			return 87;
+		}
+		fprintf(stdout, "Latency RX 10Mbit: %d\n", cont.lat);
+	} else if (!strcmp(argp[0], "latency-tx-10mbit")) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_TX_10MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		if (send_ioctl(ctx, &cont.latency) < 0) {
+			perror("Cannot Get PHY Latency TX 10Mbit value");
+			return 87;
+		}
+		fprintf(stdout, "Latency TX 10Mbit: %d\n", cont.lat);
 	} else {
 		exit_bad_args();
 	}
@@ -5397,6 +5487,26 @@  static int parse_named_uint(struct cmd_context *ctx,
 	return 1;
 }
 
+static int parse_named_int(struct cmd_context *ctx,
+			   const char *name,
+			   long long *val,
+			   long long min,
+			   long long max)
+{
+	if (ctx->argc < 2)
+		return 0;
+
+	if (strcmp(*ctx->argp, name))
+		return 0;
+
+	*val = get_int_range(*(ctx->argp + 1), 10, min, max);
+
+	ctx->argc -= 2;
+	ctx->argp += 2;
+
+	return 1;
+}
+
 static int parse_named_u8(struct cmd_context *ctx, const char *name, u8 *val)
 {
 	unsigned long long val1;
@@ -5421,6 +5531,18 @@  static int parse_named_u16(struct cmd_context *ctx, const char *name, u16 *val)
 	return ret;
 }
 
+static int parse_named_s32(struct cmd_context *ctx, const char *name, s32 *val)
+{
+	long long val1;
+	int ret;
+
+	ret = parse_named_int(ctx, name, &val1, INT_MIN, INT_MAX);
+	if (ret)
+		*val = val1;
+
+	return ret;
+}
+
 static int do_set_phy_tunable(struct cmd_context *ctx)
 {
 	int err = 0;
@@ -5430,6 +5552,12 @@  static int do_set_phy_tunable(struct cmd_context *ctx)
 	u8 fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON;
 	u8 edpd_changed = 0, edpd_enable = 0;
 	u16 edpd_tx_interval = ETHTOOL_PHY_EDPD_DFLT_TX_MSECS;
+	u8 latency_rx_1000mbit_changed = 0, latency_tx_1000mbit_changed = 0;
+	u8 latency_rx_100mbit_changed = 0, latency_tx_100mbit_changed = 0;
+	u8 latency_rx_10mbit_changed = 0, latency_tx_10mbit_changed = 0;
+	s32 latency_rx_1000mbit_val = 0, latency_tx_1000mbit_val = 0;
+	s32 latency_rx_100mbit_val = 0, latency_tx_100mbit_val = 0;
+	s32 latency_rx_10mbit_val = 0, latency_tx_10mbit_val = 0;
 
 	/* Parse arguments */
 	if (parse_named_bool(ctx, "downshift", &ds_enable)) {
@@ -5444,6 +5572,24 @@  static int do_set_phy_tunable(struct cmd_context *ctx)
 		edpd_changed = 1;
 		if (edpd_enable)
 			parse_named_u16(ctx, "msecs", &edpd_tx_interval);
+	} else if (parse_named_s32(ctx, "latency-rx-1000mbit",
+				   &latency_rx_1000mbit_val)) {
+		latency_rx_1000mbit_changed = 1;
+	} else if (parse_named_s32(ctx, "latency-tx-1000mbit",
+				   &latency_tx_1000mbit_val)) {
+		latency_tx_1000mbit_changed = 1;
+	} else if (parse_named_s32(ctx, "latency-rx-100mbit",
+				   &latency_rx_100mbit_val)) {
+		latency_rx_100mbit_changed = 1;
+	} else if (parse_named_s32(ctx, "latency-tx-100mbit",
+				   &latency_tx_100mbit_val)) {
+		latency_tx_100mbit_changed = 1;
+	} else if (parse_named_s32(ctx, "latency-rx-10mbit",
+				   &latency_rx_10mbit_val)) {
+		latency_rx_10mbit_changed = 1;
+	} else if (parse_named_s32(ctx, "latency-tx-10mbit",
+				   &latency_tx_10mbit_val)) {
+		latency_tx_10mbit_changed = 1;
 	} else {
 		exit_bad_args();
 	}
@@ -5529,6 +5675,102 @@  static int do_set_phy_tunable(struct cmd_context *ctx)
 			perror("Cannot Set PHY Energy Detect Power Down");
 			err = 87;
 		}
+	} else if (latency_rx_1000mbit_changed) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_RX_1000MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		cont.lat = latency_rx_1000mbit_val;
+		err = send_ioctl(ctx, &cont.latency);
+		if (err < 0) {
+			perror("Cannot Set PHY Latency RX 1000Mbit value");
+			err = 87;
+		}
+	} else if (latency_tx_1000mbit_changed) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_TX_1000MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		cont.lat = latency_tx_1000mbit_val;
+		err = send_ioctl(ctx, &cont.latency);
+		if (err < 0) {
+			perror("Cannot Set PHY Latency TX 1000Mbit value");
+			err = 87;
+		}
+	} else if (latency_rx_100mbit_changed) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_RX_100MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		cont.lat = latency_rx_100mbit_val;
+		err = send_ioctl(ctx, &cont.latency);
+		if (err < 0) {
+			perror("Cannot Set PHY Latency RX 100Mbit value");
+			err = 87;
+		}
+	} else if (latency_tx_100mbit_changed) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_TX_100MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		cont.lat = latency_tx_100mbit_val;
+		err = send_ioctl(ctx, &cont.latency);
+		if (err < 0) {
+			perror("Cannot Set PHY Latency TX 100Mbit value");
+			err = 87;
+		}
+	} else if (latency_rx_10mbit_changed) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_RX_10MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		cont.lat = latency_rx_10mbit_val;
+		err = send_ioctl(ctx, &cont.latency);
+		if (err < 0) {
+			perror("Cannot Set PHY Latency RX 10Mbit value");
+			err = 87;
+		}
+	} else if (latency_tx_10mbit_changed) {
+		struct {
+			struct ethtool_tunable latency;
+			s32 lat;
+		} cont;
+
+		cont.latency.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.latency.id = ETHTOOL_PHY_LATENCY_TX_10MBIT;
+		cont.latency.type_id = ETHTOOL_TUNABLE_S32;
+		cont.latency.len = 4;
+		cont.lat = latency_tx_10mbit_val;
+		err = send_ioctl(ctx, &cont.latency);
+		if (err < 0) {
+			perror("Cannot Set PHY Latency TX 10Mbit value");
+			err = 87;
+		}
 	}
 
 	return err;
@@ -5952,6 +6194,12 @@  static const struct option args[] = {
 		.xhelp	= "		[ downshift on|off [count N] ]\n"
 			  "		[ fast-link-down on|off [msecs N] ]\n"
 			  "		[ energy-detect-power-down on|off [msecs N] ]\n"
+			  "		[ latency-rx-1000mbit %d ]\n"
+			  "		[ latency-tx-1000mbit %d ]\n"
+			  "		[ latency-rx-100mbit %d ]\n"
+			  "		[ latency-tx-100mbit %d ]\n"
+			  "		[ latency-rx-10mbit %d ]\n"
+			  "		[ latency-tx-10mbit %d ]\n"
 	},
 	{
 		.opts	= "--get-phy-tunable",
@@ -5960,6 +6208,12 @@  static const struct option args[] = {
 		.xhelp	= "		[ downshift ]\n"
 			  "		[ fast-link-down ]\n"
 			  "		[ energy-detect-power-down ]\n"
+			  "		[ latency-rx-1000mbit ]\n"
+			  "		[ latency-tx-1000mbit ]\n"
+			  "		[ latency-rx-100mbit ]\n"
+			  "		[ latency-tx-100mbit ]\n"
+			  "		[ latency-rx-10mbit ]\n"
+			  "		[ latency-tx-10mbit ]\n"
 	},
 	{
 		.opts	= "--get-tunable",
diff --git a/uapi/linux/ethtool.h b/uapi/linux/ethtool.h
index 85548f9..01c07a6 100644
--- a/uapi/linux/ethtool.h
+++ b/uapi/linux/ethtool.h
@@ -294,6 +294,12 @@  enum phy_tunable_id {
 	ETHTOOL_PHY_DOWNSHIFT,
 	ETHTOOL_PHY_FAST_LINK_DOWN,
 	ETHTOOL_PHY_EDPD,
+	ETHTOOL_PHY_LATENCY_RX_10MBIT,
+	ETHTOOL_PHY_LATENCY_TX_10MBIT,
+	ETHTOOL_PHY_LATENCY_RX_100MBIT,
+	ETHTOOL_PHY_LATENCY_TX_100MBIT,
+	ETHTOOL_PHY_LATENCY_RX_1000MBIT,
+	ETHTOOL_PHY_LATENCY_TX_1000MBIT,
 	/*
 	 * Add your fresh new phy tunable attribute above and remember to update
 	 * phy_tunable_strings[] in net/ethtool/common.c