diff mbox series

[RFC,net-next,4/8] net: phy: add C73 base page helpers

Message ID 20230817150644.3605105-5-vladimir.oltean@nxp.com
State Superseded
Headers show
Series Add C72/C73 copper backplane support for LX2160 | expand

Commit Message

Vladimir Oltean Aug. 17, 2023, 3:06 p.m. UTC
IEEE 802.3 clause 73 defines auto-negotiation for backplanes and copper
cable assemblies. This is a medium type (link mode) just like Ethernet
over twisted pairs (BASE-T / BASE-TX) and over two wires for automotive
(BASE-T1) for which the PHY library currently contains support.

As a minimal framework for backplane PHY drivers, introduce a set of
helpers that parse and interpret the base pages that are exchanged by
PHYs during the clause 73 negotiation.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/mii.c   |  34 +++++++++++++-
 include/linux/mii.h | 105 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 22680f47385d..c8a1df5d52a9 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -648,6 +648,38 @@  int generic_mii_ioctl(struct mii_if_info *mii_if,
 	return rc;
 }
 
+static const enum ethtool_link_mode_bit_indices c73_linkmodes[] = {
+	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+	/* ETHTOOL_LINK_MODE_100000baseKP4_Full_BIT not supported */
+	/* ETHTOOL_LINK_MODE_100000baseCR10_Full_BIT not supported */
+	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+	/* ETHTOOL_LINK_MODE_25000baseKRS_Full_BIT not supported */
+	/* ETHTOOL_LINK_MODE_25000baseCRS_Full_BIT not supported */
+	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+};
+
+int
+linkmode_c73_priority_resolution(const unsigned long *modes,
+				 enum ethtool_link_mode_bit_indices *resolved)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(c73_linkmodes); i++) {
+		if (linkmode_test_bit(c73_linkmodes[i], modes)) {
+			*resolved = c73_linkmodes[i];
+			return 0;
+		}
+	}
+
+	return -ENOPROTOOPT;
+}
+
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
@@ -662,4 +694,4 @@  EXPORT_SYMBOL(mii_check_link);
 EXPORT_SYMBOL(mii_check_media);
 EXPORT_SYMBOL(mii_check_gmii_support);
 EXPORT_SYMBOL(generic_mii_ioctl);
-
+EXPORT_SYMBOL(linkmode_c73_priority_resolution);
diff --git a/include/linux/mii.h b/include/linux/mii.h
index d5a959ce4877..4b141e9acd08 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -13,6 +13,36 @@ 
 #include <linux/linkmode.h>
 #include <uapi/linux/mii.h>
 
+/* 802.3-2018 clause 73.6 Link codeword encoding */
+#define C73_BASE_PAGE_SELECTOR(x)		((x) & GENMASK(4, 0))
+#define C73_BASE_PAGE_ECHOED_NONCE(x)		(((x) << 5) & GENMASK(9, 5))
+#define C73_BASE_PAGE_ECHOED_NONCE_X(x)		(((x) & GENMASK(9, 5)) >> 5)
+#define C73_BASE_PAGE_ECHOED_NONCE_MSK		GENMASK(9, 5)
+#define C73_BASE_PAGE_PAUSE			BIT(10)
+#define C73_BASE_PAGE_ASM_DIR			BIT(11)
+#define C73_BASE_PAGE_RF			BIT(13)
+#define C73_BASE_PAGE_ACK			BIT(14)
+#define C73_BASE_PAGE_NP			BIT(15)
+#define C73_BASE_PAGE_TRANSMITTED_NONCE(x)	(((x) << 16) & GENMASK(20, 16))
+#define C73_BASE_PAGE_TRANSMITTED_NONCE_X(x)	(((x) & GENMASK(20, 16)) >> 16)
+#define C73_BASE_PAGE_TRANSMITTED_NONCE_MSK	GENMASK(20, 16)
+#define C73_BASE_PAGE_A(x)			BIT(21 + (x))
+#define C73_BASE_PAGE_TECH_ABL_1000BASEKX	C73_BASE_PAGE_A(0)
+#define C73_BASE_PAGE_TECH_ABL_10GBASEKX4	C73_BASE_PAGE_A(1)
+#define C73_BASE_PAGE_TECH_ABL_10GBASEKR	C73_BASE_PAGE_A(2)
+#define C73_BASE_PAGE_TECH_ABL_40GBASEKR4	C73_BASE_PAGE_A(3)
+#define C73_BASE_PAGE_TECH_ABL_40GBASECR4	C73_BASE_PAGE_A(4)
+#define C73_BASE_PAGE_TECH_ABL_100GBASECR10	C73_BASE_PAGE_A(5)
+#define C73_BASE_PAGE_TECH_ABL_100GBASEKP4	C73_BASE_PAGE_A(6)
+#define C73_BASE_PAGE_TECH_ABL_100GBASEKR4	C73_BASE_PAGE_A(7)
+#define C73_BASE_PAGE_TECH_ABL_100GBASECR4	C73_BASE_PAGE_A(8)
+#define C73_BASE_PAGE_TECH_ABL_25GBASEKRS	C73_BASE_PAGE_A(9)
+#define C73_BASE_PAGE_TECH_ABL_25GBASEKR	C73_BASE_PAGE_A(10)
+#define C73_BASE_PAGE_25G_RS_FEC_REQ		BIT_ULL(44)
+#define C73_BASE_PAGE_25G_BASER_FEC_REQ		BIT_ULL(45)
+#define C73_BASE_PAGE_10G_BASER_FEC_ABL		BIT_ULL(46)
+#define C73_BASE_PAGE_10G_BASER_FEC_REQ		BIT_ULL(47)
+
 struct ethtool_cmd;
 
 struct mii_if_info {
@@ -47,6 +77,10 @@  extern int generic_mii_ioctl(struct mii_if_info *mii_if,
 			     struct mii_ioctl_data *mii_data, int cmd,
 			     unsigned int *duplex_changed);
 
+extern int
+linkmode_c73_priority_resolution(const unsigned long *modes,
+				 enum ethtool_link_mode_bit_indices *resolved);
+
 
 static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
 {
@@ -506,6 +540,77 @@  static inline u16 linkmode_adv_to_mii_adv_x(const unsigned long *linkmodes,
 	return adv;
 }
 
+static inline u64 linkmode_adv_to_c73_base_page(const unsigned long *advertising)
+{
+	u64 result = 0;
+
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_1000BASEKX;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_10GBASEKX4;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_10GBASEKR;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_40GBASEKR4;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_40GBASECR4;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_100GBASEKR4;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_100GBASECR4;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+			      advertising))
+		result |= C73_BASE_PAGE_TECH_ABL_25GBASEKR;
+
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising))
+		result |= C73_BASE_PAGE_PAUSE;
+	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising))
+		result |= C73_BASE_PAGE_ASM_DIR;
+
+	return result;
+}
+
+static inline void mii_c73_mod_linkmode_lpa_t(unsigned long *advertising,
+					      u64 base_page)
+{
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_1000BASEKX);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_10GBASEKX4);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_10GBASEKR);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_40GBASEKR4);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_40GBASECR4);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_100GBASEKR4);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_100GBASECR4);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, advertising,
+			 base_page & C73_BASE_PAGE_TECH_ABL_25GBASEKR);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising,
+			 base_page & C73_BASE_PAGE_PAUSE);
+
+	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising,
+			 base_page & C73_BASE_PAGE_ASM_DIR);
+}
+
 /**
  * mii_advertise_flowctrl - get flow control advertisement flags
  * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)