diff mbox series

[net-next,v1,1/2] ethtool: add ETHTOOL_A_FEC_ALL request for FEC

Message ID 20221128170354.2537171-2-mikael.barsehyan@intel.com
State Changes Requested
Headers show
Series add ethtool FEC-all option | expand

Commit Message

Mikael Barsehyan Nov. 28, 2022, 5:03 p.m. UTC
ETHTOOL_A_FEC_ALL requests the driver to choose FEC mode (including no FEC)
based on SFP module parameters.

Suggested-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: Mikael Barsehyan <mikael.barsehyan@intel.com>
---
 Documentation/networking/ethtool-netlink.rst | 14 ++++++++---
 include/uapi/linux/ethtool.h                 |  3 +++
 include/uapi/linux/ethtool_netlink.h         |  1 +
 net/ethtool/fec.c                            | 26 ++++++++++++++------
 net/ethtool/netlink.h                        |  2 +-
 5 files changed, 35 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index bede24ef44fd..c682e5bf727b 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -1383,6 +1383,7 @@  Kernel response contents:
   ``ETHTOOL_A_FEC_HEADER``               nested  request header
   ``ETHTOOL_A_FEC_MODES``                bitset  configured modes
   ``ETHTOOL_A_FEC_AUTO``                 bool    FEC mode auto selection
+  ``ETHTOOL_A_FEC_ALL``                  bool    auto selection(incl. NO FEC)
   ``ETHTOOL_A_FEC_ACTIVE``               u32     index of active FEC mode
   ``ETHTOOL_A_FEC_STATS``                nested  FEC statistics
   =====================================  ======  ==========================
@@ -1391,10 +1392,13 @@  Kernel response contents:
 active on the interface. This attribute may not be present if device does
 not support FEC.
 
-``ETHTOOL_A_FEC_MODES`` and ``ETHTOOL_A_FEC_AUTO`` are only meaningful when
-autonegotiation is disabled. If ``ETHTOOL_A_FEC_AUTO`` is non-zero driver will
-select the FEC mode automatically based on the parameters of the SFP module.
+``ETHTOOL_A_FEC_MODES``, ``ETHTOOL_A_FEC_AUTO`` and ``ETHTOOL_A_FEC_ALL``
+are only meaningful when autonegotiation is disabled.
+If ``ETHTOOL_A_FEC_AUTO`` is non-zero driver will select the FEC mode
+automatically based on the parameters of the SFP module.
 This is equivalent to the ``ETHTOOL_FEC_AUTO`` bit of the ioctl interface.
+If ``ETHTOOL_A_FEC_ALL`` is non-zero driver will select the FEC mode
+automatically (including no FEC) based on the parameters of the SFP module.
 ``ETHTOOL_A_FEC_MODES`` carry the current FEC configuration using link mode
 bits (rather than old ``ETHTOOL_FEC_*`` bits).
 
@@ -1429,6 +1433,7 @@  Request contents:
   ``ETHTOOL_A_FEC_HEADER``               nested  request header
   ``ETHTOOL_A_FEC_MODES``                bitset  configured modes
   ``ETHTOOL_A_FEC_AUTO``                 bool    FEC mode auto selection
+  ``ETHTOOL_A_FEC_ALL``                  bool    auto selection(incl. NO FEC)
   =====================================  ======  ==========================
 
 ``FEC_SET`` is only meaningful when autonegotiation is disabled. Otherwise
@@ -1441,6 +1446,9 @@  in an implementation specific way.
 ``ETHTOOL_A_FEC_AUTO`` requests the driver to choose FEC mode based on SFP
 module parameters. This does not mean autonegotiation.
 
+``ETHTOOL_A_FEC_ALL`` requests the driver to choose FEC mode (including not using
+FEC) based on SFP module parameters. This does not mean autonegotiation.
+
 MODULE_EEPROM_GET
 =================
 
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 58e587ba0450..274b28ed1f8e 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1516,6 +1516,7 @@  struct ethtool_fecparam {
  * @ETHTOOL_FEC_BASER_BIT: Base-R/Reed-Solomon FEC Mode
  * @ETHTOOL_FEC_LLRS_BIT: Low Latency Reed Solomon FEC Mode (25G/50G Ethernet
  *			Consortium)
+ * @ETHTOOL_FEC_ALL_BIT: Same as AUTO but also includes NO FEC.
  */
 enum ethtool_fec_config_bits {
 	ETHTOOL_FEC_NONE_BIT,
@@ -1524,6 +1525,7 @@  enum ethtool_fec_config_bits {
 	ETHTOOL_FEC_RS_BIT,
 	ETHTOOL_FEC_BASER_BIT,
 	ETHTOOL_FEC_LLRS_BIT,
+	ETHTOOL_FEC_ALL_BIT,
 };
 
 #define ETHTOOL_FEC_NONE		(1 << ETHTOOL_FEC_NONE_BIT)
@@ -1532,6 +1534,7 @@  enum ethtool_fec_config_bits {
 #define ETHTOOL_FEC_RS			(1 << ETHTOOL_FEC_RS_BIT)
 #define ETHTOOL_FEC_BASER		(1 << ETHTOOL_FEC_BASER_BIT)
 #define ETHTOOL_FEC_LLRS		(1 << ETHTOOL_FEC_LLRS_BIT)
+#define ETHTOOL_FEC_ALL			(1 << ETHTOOL_FEC_ALL_BIT)
 
 /* CMDs currently supported */
 #define ETHTOOL_GSET		0x00000001 /* DEPRECATED, Get settings.
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index aaf7c6963d61..7f3857f1a7cb 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -684,6 +684,7 @@  enum {
 	ETHTOOL_A_FEC_AUTO,				/* u8 */
 	ETHTOOL_A_FEC_ACTIVE,				/* u32 */
 	ETHTOOL_A_FEC_STATS,				/* nest - _A_FEC_STAT */
+	ETHTOOL_A_FEC_ALL,				/* nest - _A_FEC_STAT */
 
 	__ETHTOOL_A_FEC_CNT,
 	ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
diff --git a/net/ethtool/fec.c b/net/ethtool/fec.c
index 9f5a134e2e01..48b0d091cd0a 100644
--- a/net/ethtool/fec.c
+++ b/net/ethtool/fec.c
@@ -13,6 +13,7 @@  struct fec_reply_data {
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(fec_link_modes);
 	u32 active_fec;
 	u8 fec_auto;
+	u8 fec_all;
 	struct fec_stat_grp {
 		u64 stats[1 + ETHTOOL_MAX_LANES];
 		u8 cnt;
@@ -29,10 +30,13 @@  const struct nla_policy ethnl_fec_get_policy[ETHTOOL_A_FEC_HEADER + 1] = {
 };
 
 static void
-ethtool_fec_to_link_modes(u32 fec, unsigned long *link_modes, u8 *fec_auto)
+ethtool_fec_to_link_modes(u32 fec, unsigned long *link_modes, u8 *fec_auto,
+			  u8 *fec_all)
 {
 	if (fec_auto)
 		*fec_auto = !!(fec & ETHTOOL_FEC_AUTO);
+	if (fec_all)
+		*fec_all = !!(fec & ETHTOOL_FEC_ALL);
 
 	if (fec & ETHTOOL_FEC_OFF)
 		__set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, link_modes);
@@ -46,12 +50,14 @@  ethtool_fec_to_link_modes(u32 fec, unsigned long *link_modes, u8 *fec_auto)
 
 static int
 ethtool_link_modes_to_fecparam(struct ethtool_fecparam *fec,
-			       unsigned long *link_modes, u8 fec_auto)
+			       unsigned long *link_modes, u8 fec_auto, u8 fec_all)
 {
 	memset(fec, 0, sizeof(*fec));
 
 	if (fec_auto)
 		fec->fec |= ETHTOOL_FEC_AUTO;
+	if (fec_all)
+		fec->fec |= ETHTOOL_FEC_ALL;
 
 	if (__test_and_clear_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, link_modes))
 		fec->fec |= ETHTOOL_FEC_OFF;
@@ -123,9 +129,9 @@  static int fec_prepare_data(const struct ethnl_req_info *req_base,
 	WARN_ON_ONCE(fec.reserved);
 
 	ethtool_fec_to_link_modes(fec.fec, data->fec_link_modes,
-				  &data->fec_auto);
+				  &data->fec_auto, &data->fec_all);
 
-	ethtool_fec_to_link_modes(fec.active_fec, active_fec_modes, NULL);
+	ethtool_fec_to_link_modes(fec.active_fec, active_fec_modes, NULL, NULL);
 	data->active_fec = find_first_bit(active_fec_modes,
 					  __ETHTOOL_LINK_MODE_MASK_NBITS);
 	/* Don't report attr if no FEC mode set. Note that
@@ -155,6 +161,7 @@  static int fec_reply_size(const struct ethnl_req_info *req_base,
 	len += ret;
 
 	len += nla_total_size(sizeof(u8)) +	/* _FEC_AUTO */
+	       nla_total_size(sizeof(u8)) + /* _FEC_ALL */
 	       nla_total_size(sizeof(u32));	/* _FEC_ACTIVE */
 
 	if (req_base->flags & ETHTOOL_FLAG_STATS)
@@ -207,6 +214,7 @@  static int fec_fill_reply(struct sk_buff *skb,
 		return ret;
 
 	if (nla_put_u8(skb, ETHTOOL_A_FEC_AUTO, data->fec_auto) ||
+	    nla_put_u8(skb, ETHTOOL_A_FEC_ALL, data->fec_all) ||
 	    (data->active_fec &&
 	     nla_put_u32(skb, ETHTOOL_A_FEC_ACTIVE, data->active_fec)))
 		return -EMSGSIZE;
@@ -231,10 +239,11 @@  const struct ethnl_request_ops ethnl_fec_request_ops = {
 
 /* FEC_SET */
 
-const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1] = {
+const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_ALL + 1] = {
 	[ETHTOOL_A_FEC_HEADER]	= NLA_POLICY_NESTED(ethnl_header_policy),
 	[ETHTOOL_A_FEC_MODES]	= { .type = NLA_NESTED },
 	[ETHTOOL_A_FEC_AUTO]	= NLA_POLICY_MAX(NLA_U8, 1),
+	[ETHTOOL_A_FEC_ALL]		= NLA_POLICY_MAX(NLA_U8, 1),
 };
 
 int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info)
@@ -247,6 +256,7 @@  int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info)
 	struct net_device *dev;
 	bool mod = false;
 	u8 fec_auto;
+	u8 fec_all;
 	int ret;
 
 	ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_FEC_HEADER],
@@ -268,7 +278,7 @@  int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info)
 	if (ret < 0)
 		goto out_ops;
 
-	ethtool_fec_to_link_modes(fec.fec, fec_link_modes, &fec_auto);
+	ethtool_fec_to_link_modes(fec.fec, fec_link_modes, &fec_auto, &fec_all);
 
 	ret = ethnl_update_bitset(fec_link_modes,
 				  __ETHTOOL_LINK_MODE_MASK_NBITS,
@@ -277,12 +287,14 @@  int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info)
 	if (ret < 0)
 		goto out_ops;
 	ethnl_update_u8(&fec_auto, tb[ETHTOOL_A_FEC_AUTO], &mod);
+	ethnl_update_u8(&fec_all, tb[ETHTOOL_A_FEC_ALL], &mod);
 
 	ret = 0;
 	if (!mod)
 		goto out_ops;
 
-	ret = ethtool_link_modes_to_fecparam(&fec, fec_link_modes, fec_auto);
+	ret = ethtool_link_modes_to_fecparam(&fec, fec_link_modes, fec_auto,
+					     fec_all);
 	if (ret) {
 		NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_FEC_MODES],
 				    "invalid FEC modes requested");
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 1bfd374f9718..3d553363532e 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -378,7 +378,7 @@  extern const struct nla_policy ethnl_cable_test_act_policy[ETHTOOL_A_CABLE_TEST_
 extern const struct nla_policy ethnl_cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG + 1];
 extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_HEADER + 1];
 extern const struct nla_policy ethnl_fec_get_policy[ETHTOOL_A_FEC_HEADER + 1];
-extern const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1];
+extern const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_ALL + 1];
 extern const struct nla_policy ethnl_module_eeprom_get_policy[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS + 1];
 extern const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1];
 extern const struct nla_policy ethnl_phc_vclocks_get_policy[ETHTOOL_A_PHC_VCLOCKS_HEADER + 1];