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

From: Vladimir Oltean
Date: Thu Aug 17 2023 - 11:07:47 EST


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@xxxxxxx>
---
drivers/net/mii.c | 34 +++++++++++++-
include/linux/mii.h | 105 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 138 insertions(+), 1 deletion(-)

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@xxxxxxxxx>");
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)
--
2.34.1