From bbb7d478d91ac4d5c288e226cc8744daf3820798 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:07:22 -0700 Subject: [PATCH 1/8] net: phy: Add interface types for 50G and 100G Add support for 802.3cd based interface types 50GBASE-R and 100GBASE-P. This choice in naming is based on section 135 of the 802.3-2022 IEEE Standard. In addition it is adding support for what I am referring to as LAUI which is based on annex 135C of the IEEE Standard, and shares many similarities with the 25/50G consortium. The main difference between the two is that IEEE spec refers to LAUI as the AUI before the RS(544/514) FEC, whereas the 25/50G use this lane and frequency combination after going through RS(528/514), Base-R or no FEC at all. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028444205.625704.4191700324472974116.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/phy/phy-core.c | 3 +++ drivers/net/phy/phy_caps.c | 9 +++++++++ drivers/net/phy/phylink.c | 13 +++++++++++++ include/linux/phy.h | 12 ++++++++++++ 4 files changed, 37 insertions(+) diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 27f1833563ab..c480bb40fa73 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -142,6 +142,9 @@ int phy_interface_num_ports(phy_interface_t interface) case PHY_INTERFACE_MODE_RXAUI: case PHY_INTERFACE_MODE_XAUI: case PHY_INTERFACE_MODE_1000BASEKX: + case PHY_INTERFACE_MODE_50GBASER: + case PHY_INTERFACE_MODE_LAUI: + case PHY_INTERFACE_MODE_100GBASEP: return 1; case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_QUSGMII: diff --git a/drivers/net/phy/phy_caps.c b/drivers/net/phy/phy_caps.c index 38417e288611..d11ce1c7e712 100644 --- a/drivers/net/phy/phy_caps.c +++ b/drivers/net/phy/phy_caps.c @@ -351,6 +351,15 @@ unsigned long phy_caps_from_interface(phy_interface_t interface) link_caps |= BIT(LINK_CAPA_40000FD); break; + case PHY_INTERFACE_MODE_50GBASER: + case PHY_INTERFACE_MODE_LAUI: + link_caps |= BIT(LINK_CAPA_50000FD); + break; + + case PHY_INTERFACE_MODE_100GBASEP: + link_caps |= BIT(LINK_CAPA_100000FD); + break; + case PHY_INTERFACE_MODE_INTERNAL: link_caps |= LINK_CAPA_ALL; break; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 0faa3d97e06b..67218d278ce6 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -127,6 +127,9 @@ do { \ #endif static const phy_interface_t phylink_sfp_interface_preference[] = { + PHY_INTERFACE_MODE_100GBASEP, + PHY_INTERFACE_MODE_50GBASER, + PHY_INTERFACE_MODE_LAUI, PHY_INTERFACE_MODE_25GBASER, PHY_INTERFACE_MODE_USXGMII, PHY_INTERFACE_MODE_10GBASER, @@ -274,6 +277,13 @@ static int phylink_interface_max_speed(phy_interface_t interface) case PHY_INTERFACE_MODE_XLGMII: return SPEED_40000; + case PHY_INTERFACE_MODE_50GBASER: + case PHY_INTERFACE_MODE_LAUI: + return SPEED_50000; + + case PHY_INTERFACE_MODE_100GBASEP: + return SPEED_100000; + case PHY_INTERFACE_MODE_INTERNAL: case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_MAX: @@ -798,6 +808,9 @@ static int phylink_parse_mode(struct phylink *pl, case PHY_INTERFACE_MODE_10GKR: case PHY_INTERFACE_MODE_10GBASER: case PHY_INTERFACE_MODE_XLGMII: + case PHY_INTERFACE_MODE_50GBASER: + case PHY_INTERFACE_MODE_LAUI: + case PHY_INTERFACE_MODE_100GBASEP: caps = ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE); caps = phylink_get_capabilities(pl->link_config.interface, caps, RATE_MATCH_NONE); diff --git a/include/linux/phy.h b/include/linux/phy.h index b037aab7b71d..74c1bcf64b3c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -103,6 +103,9 @@ extern const int phy_basic_ports_array[3]; * @PHY_INTERFACE_MODE_QUSGMII: Quad Universal SGMII * @PHY_INTERFACE_MODE_1000BASEKX: 1000Base-KX - with Clause 73 AN * @PHY_INTERFACE_MODE_10G_QXGMII: 10G-QXGMII - 4 ports over 10G USXGMII + * @PHY_INTERFACE_MODE_50GBASER: 50GBase-R - with Clause 134 FEC + * @PHY_INTERFACE_MODE_LAUI: 50 Gigabit Attachment Unit Interface + * @PHY_INTERFACE_MODE_100GBASEP: 100GBase-P - with Clause 134 FEC * @PHY_INTERFACE_MODE_MAX: Book keeping * * Describes the interface between the MAC and PHY. @@ -144,6 +147,9 @@ typedef enum { PHY_INTERFACE_MODE_QUSGMII, PHY_INTERFACE_MODE_1000BASEKX, PHY_INTERFACE_MODE_10G_QXGMII, + PHY_INTERFACE_MODE_50GBASER, + PHY_INTERFACE_MODE_LAUI, + PHY_INTERFACE_MODE_100GBASEP, PHY_INTERFACE_MODE_MAX, } phy_interface_t; @@ -260,6 +266,12 @@ static inline const char *phy_modes(phy_interface_t interface) return "qusgmii"; case PHY_INTERFACE_MODE_10G_QXGMII: return "10g-qxgmii"; + case PHY_INTERFACE_MODE_50GBASER: + return "50gbase-r"; + case PHY_INTERFACE_MODE_LAUI: + return "laui"; + case PHY_INTERFACE_MODE_100GBASEP: + return "100gbase-p"; default: return "unknown"; } From 3b180b227eb19fb37714293d601ad49dcc7cf08f Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:07:28 -0700 Subject: [PATCH 2/8] fbnic: Do not consider mailbox "initialized" until we have verified fw version In order for us to make use of the information in the PHY we need to verify that the FW capabilities message has been processed. To do so we should poll until the FW version in the capabilities message is at least at the minimum level needed to verify that the FW can support the basic PHY config messages. As such this change adds logic so that we will poll the mailbox until such time as the FW version can be populated with an acceptable value. If it doesn't reach a sufficicient value the mailbox will be considered to have timed out. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028444873.625704.10269838393153693403.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c index 4521d0483d18..01756aba29fb 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c @@ -95,6 +95,9 @@ void fbnic_mbx_init(struct fbnic_dev *fbd) /* Initialize lock to protect Tx ring */ spin_lock_init(&fbd->fw_tx_lock); + /* Reset FW Capabilities */ + memset(&fbd->fw_cap, 0, sizeof(fbd->fw_cap)); + /* Reinitialize mailbox memory */ for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++) memset(&fbd->mbx[i], 0, sizeof(struct fbnic_fw_mbx)); @@ -1117,6 +1120,7 @@ void fbnic_mbx_poll(struct fbnic_dev *fbd) int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd) { + struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX]; unsigned long timeout = jiffies + 10 * HZ + 1; int err, i; @@ -1149,8 +1153,23 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd) if (err) goto clean_mbx; - /* Use "1" to indicate we entered the state waiting for a response */ - fbd->fw_cap.running.mgmt.version = 1; + /* Poll until we get a current management firmware version, use "1" + * to indicate we entered the polling state waiting for a response + */ + for (fbd->fw_cap.running.mgmt.version = 1; + fbd->fw_cap.running.mgmt.version < MIN_FW_VERSION_CODE;) { + if (!tx_mbx->ready) + err = -ENODEV; + if (err) + goto clean_mbx; + + msleep(20); + fbnic_mbx_poll(fbd); + + /* set err, but wait till mgmt.version check to report it */ + if (!time_is_after_jiffies(timeout)) + err = -ETIMEDOUT; + } return 0; clean_mbx: From a6bbbc5bc4c671f6cd791a65743f0c6c83d69edd Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:07:35 -0700 Subject: [PATCH 3/8] fbnic: Retire "AUTO" flags and cleanup handling of FW link settings There were several issues in the way we were handling the link info coming from firmware. First is the fact that we were carrying around "AUTO" flags to indicate that we needed to populate the values. We can just drop this and assume that we will always be populating the settings from firmware. With this we can also clean up the masking as the "AUTO" flags were just there to be stripped anyway. Second since we are getting rid of the "AUTO" setting we still need a way to report that the link is not configured. We convert the link_mode "AUTO" to "UNKNOWN" to do this. With this we can avoid reporting link up in the phylink_pcs_get_state call as we will just set link to 0 and return without updating the link speed. This is preferred versus the driver just forcing 50G which makes it harder to recover when the FW does start providing valid settings. With this the plan is to eventually replace the link_mode we use with the interface_mode from phylink for all intents and purposes and have the two be interchangeable. At that point we can convert the FW provided settings over to something closer to link partner settings and give phylink greater control of the interface allowing for user override of the settings and an asynchronous setup of the link versus having to pull early settings from firmware. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028445548.625704.1367708155813490215.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 89 +++++++++---------- drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 6 +- .../net/ethernet/meta/fbnic/fbnic_netdev.c | 2 - .../net/ethernet/meta/fbnic/fbnic_phylink.c | 17 ++-- 4 files changed, 48 insertions(+), 66 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c index ea5ea7e329cb..56b429c96a7c 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c @@ -452,7 +452,7 @@ static u32 __fbnic_mac_cmd_config_asic(struct fbnic_dev *fbd, command_config |= FBNIC_MAC_COMMAND_CONFIG_RX_PAUSE_DIS; /* Disable fault handling if no FEC is requested */ - if ((fbn->fec & FBNIC_FEC_MODE_MASK) == FBNIC_FEC_OFF) + if (fbn->fec == FBNIC_FEC_OFF) command_config |= FBNIC_MAC_COMMAND_CONFIG_FLT_HDL_DIS; return command_config; @@ -468,7 +468,7 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) return false; /* Define the expected lane mask for the status bits we need to check */ - switch (fbn->link_mode & FBNIC_LINK_MODE_MASK) { + switch (fbn->link_mode) { case FBNIC_LINK_100R2: lane_mask = 0xf; break; @@ -476,7 +476,7 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) lane_mask = 3; break; case FBNIC_LINK_50R2: - switch (fbn->fec & FBNIC_FEC_MODE_MASK) { + switch (fbn->fec) { case FBNIC_FEC_OFF: lane_mask = 0x63; break; @@ -494,7 +494,7 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) } /* Use an XOR to remove the bits we expect to see set */ - switch (fbn->fec & FBNIC_FEC_MODE_MASK) { + switch (fbn->fec) { case FBNIC_FEC_OFF: lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_BLOCK_LOCK, pcs_status); @@ -540,64 +540,55 @@ static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd) return link; } -static void fbnic_pcs_get_fw_settings(struct fbnic_dev *fbd) +static void +fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *link_mode, u8 *fec) { - struct fbnic_net *fbn = netdev_priv(fbd->netdev); - u8 link_mode = fbn->link_mode; - u8 fec = fbn->fec; - - /* Update FEC first to reflect FW current mode */ - if (fbn->fec & FBNIC_FEC_AUTO) { - switch (fbd->fw_cap.link_fec) { - case FBNIC_FW_LINK_FEC_NONE: - fec = FBNIC_FEC_OFF; - break; - case FBNIC_FW_LINK_FEC_RS: - fec = FBNIC_FEC_RS; - break; - case FBNIC_FW_LINK_FEC_BASER: - fec = FBNIC_FEC_BASER; - break; - default: - return; - } - - fbn->fec = fec; + /* Retrieve default speed from FW */ + switch (fbd->fw_cap.link_speed) { + case FBNIC_FW_LINK_SPEED_25R1: + *link_mode = FBNIC_LINK_25R1; + break; + case FBNIC_FW_LINK_SPEED_50R2: + *link_mode = FBNIC_LINK_50R2; + break; + case FBNIC_FW_LINK_SPEED_50R1: + *link_mode = FBNIC_LINK_50R1; + *fec = FBNIC_FEC_RS; + return; + case FBNIC_FW_LINK_SPEED_100R2: + *link_mode = FBNIC_LINK_100R2; + *fec = FBNIC_FEC_RS; + return; + default: + *link_mode = FBNIC_LINK_UNKONWN; + return; } - /* Do nothing if AUTO mode is not engaged */ - if (fbn->link_mode & FBNIC_LINK_AUTO) { - switch (fbd->fw_cap.link_speed) { - case FBNIC_FW_LINK_SPEED_25R1: - link_mode = FBNIC_LINK_25R1; - break; - case FBNIC_FW_LINK_SPEED_50R2: - link_mode = FBNIC_LINK_50R2; - break; - case FBNIC_FW_LINK_SPEED_50R1: - link_mode = FBNIC_LINK_50R1; - fec = FBNIC_FEC_RS; - break; - case FBNIC_FW_LINK_SPEED_100R2: - link_mode = FBNIC_LINK_100R2; - fec = FBNIC_FEC_RS; - break; - default: - return; - } - - fbn->link_mode = link_mode; + /* Update FEC first to reflect FW current mode */ + switch (fbd->fw_cap.link_fec) { + case FBNIC_FW_LINK_FEC_NONE: + *fec = FBNIC_FEC_OFF; + break; + case FBNIC_FW_LINK_FEC_RS: + default: + *fec = FBNIC_FEC_RS; + break; + case FBNIC_FW_LINK_FEC_BASER: + *fec = FBNIC_FEC_BASER; + break; } } static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd) { + struct fbnic_net *fbn = netdev_priv(fbd->netdev); + /* Mask and clear the PCS interrupt, will be enabled by link handler */ wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0); wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0); /* Pull in settings from FW */ - fbnic_pcs_get_fw_settings(fbd); + fbnic_mac_get_fw_settings(fbd, &fbn->link_mode, &fbn->fec); return 0; } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h index 4d508e1e2151..f4e75530a939 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h @@ -25,11 +25,8 @@ enum { FBNIC_FEC_OFF = 0, FBNIC_FEC_RS = 1, FBNIC_FEC_BASER = 2, - FBNIC_FEC_AUTO = 4, }; -#define FBNIC_FEC_MODE_MASK (FBNIC_FEC_AUTO - 1) - /* Treat the link modes as a set of modulation/lanes bitmask: * Bit 0: Lane Count, 0 = R1, 1 = R2 * Bit 1: Modulation, 0 = NRZ, 1 = PAM4 @@ -40,12 +37,11 @@ enum { FBNIC_LINK_50R2 = 1, FBNIC_LINK_50R1 = 2, FBNIC_LINK_100R2 = 3, - FBNIC_LINK_AUTO = 4, + FBNIC_LINK_UNKONWN = 4, }; #define FBNIC_LINK_MODE_R2 (FBNIC_LINK_50R2) #define FBNIC_LINK_MODE_PAM4 (FBNIC_LINK_50R1) -#define FBNIC_LINK_MODE_MASK (FBNIC_LINK_AUTO - 1) enum fbnic_sensor_id { FBNIC_SENSOR_TEMP, /* Temp in millidegrees Centigrade */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index aa812c63d5af..7bd7812d9c06 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -736,8 +736,6 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd) */ netdev->ethtool->wol_enabled = true; - fbn->fec = FBNIC_FEC_AUTO | FBNIC_FEC_RS; - fbn->link_mode = FBNIC_LINK_AUTO | FBNIC_LINK_50R2; netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c index 860b02b22c15..cb375a3dafe8 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c @@ -21,23 +21,20 @@ fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); struct fbnic_dev *fbd = fbn->fbd; - /* For now we use hard-coded defaults and FW config to determine - * the current values. In future patches we will add support for - * reconfiguring these values and changing link settings. - */ - switch (fbd->fw_cap.link_speed) { - case FBNIC_FW_LINK_SPEED_25R1: + switch (fbn->link_mode) { + case FBNIC_LINK_25R1: state->speed = SPEED_25000; break; - case FBNIC_FW_LINK_SPEED_50R2: + case FBNIC_LINK_50R2: + case FBNIC_LINK_50R1: state->speed = SPEED_50000; break; - case FBNIC_FW_LINK_SPEED_100R2: + case FBNIC_LINK_100R2: state->speed = SPEED_100000; break; default: - state->speed = SPEED_UNKNOWN; - break; + state->link = 0; + return; } state->duplex = DUPLEX_FULL; From f663a1abf39a16bdd8c5a3eb2d79b27c7d5c211b Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:07:42 -0700 Subject: [PATCH 4/8] fbnic: Replace link_mode with AUI The way we were using "link_mode" was really more to describe the interface between the attachment unit interface(s) we were using on the device. Specifically the AUI is describing the modulation and the number of lanes we are using. So we can simplify this by replacing link_mode with aui. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028446219.625704.8050098629750896117.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 25 +++++++++---------- drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 18 ++++++------- .../net/ethernet/meta/fbnic/fbnic_netdev.h | 3 +-- .../net/ethernet/meta/fbnic/fbnic_phylink.c | 10 ++++---- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c index 56b429c96a7c..0528724011c1 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c @@ -468,14 +468,14 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) return false; /* Define the expected lane mask for the status bits we need to check */ - switch (fbn->link_mode) { - case FBNIC_LINK_100R2: + switch (fbn->aui) { + case FBNIC_AUI_100GAUI2: lane_mask = 0xf; break; - case FBNIC_LINK_50R1: + case FBNIC_AUI_50GAUI1: lane_mask = 3; break; - case FBNIC_LINK_50R2: + case FBNIC_AUI_LAUI2: switch (fbn->fec) { case FBNIC_FEC_OFF: lane_mask = 0x63; @@ -488,7 +488,7 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) break; } break; - case FBNIC_LINK_25R1: + case FBNIC_AUI_25GAUI: lane_mask = 1; break; } @@ -540,27 +540,26 @@ static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd) return link; } -static void -fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *link_mode, u8 *fec) +static void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec) { /* Retrieve default speed from FW */ switch (fbd->fw_cap.link_speed) { case FBNIC_FW_LINK_SPEED_25R1: - *link_mode = FBNIC_LINK_25R1; + *aui = FBNIC_AUI_25GAUI; break; case FBNIC_FW_LINK_SPEED_50R2: - *link_mode = FBNIC_LINK_50R2; + *aui = FBNIC_AUI_LAUI2; break; case FBNIC_FW_LINK_SPEED_50R1: - *link_mode = FBNIC_LINK_50R1; + *aui = FBNIC_AUI_50GAUI1; *fec = FBNIC_FEC_RS; return; case FBNIC_FW_LINK_SPEED_100R2: - *link_mode = FBNIC_LINK_100R2; + *aui = FBNIC_AUI_100GAUI2; *fec = FBNIC_FEC_RS; return; default: - *link_mode = FBNIC_LINK_UNKONWN; + *aui = FBNIC_AUI_UNKNOWN; return; } @@ -588,7 +587,7 @@ static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd) wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0); /* Pull in settings from FW */ - fbnic_mac_get_fw_settings(fbd, &fbn->link_mode, &fbn->fec); + fbnic_mac_get_fw_settings(fbd, &fbn->aui, &fbn->fec); return 0; } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h index f4e75530a939..151d785116cb 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h @@ -27,21 +27,21 @@ enum { FBNIC_FEC_BASER = 2, }; -/* Treat the link modes as a set of modulation/lanes bitmask: +/* Treat the AUI modes as a modulation/lanes bitmask: * Bit 0: Lane Count, 0 = R1, 1 = R2 * Bit 1: Modulation, 0 = NRZ, 1 = PAM4 - * Bit 2: Retrieve link mode from FW + * Bit 2: Unknown Modulation/Lane Configuration */ enum { - FBNIC_LINK_25R1 = 0, - FBNIC_LINK_50R2 = 1, - FBNIC_LINK_50R1 = 2, - FBNIC_LINK_100R2 = 3, - FBNIC_LINK_UNKONWN = 4, + FBNIC_AUI_25GAUI = 0, /* 25.7812GBd 25.78125 * 1 */ + FBNIC_AUI_LAUI2 = 1, /* 51.5625GBd 25.78128 * 2 */ + FBNIC_AUI_50GAUI1 = 2, /* 53.125GBd 53.125 * 1 */ + FBNIC_AUI_100GAUI2 = 3, /* 106.25GBd 53.125 * 2 */ + FBNIC_AUI_UNKNOWN = 4, }; -#define FBNIC_LINK_MODE_R2 (FBNIC_LINK_50R2) -#define FBNIC_LINK_MODE_PAM4 (FBNIC_LINK_50R1) +#define FBNIC_AUI_MODE_R2 (FBNIC_AUI_LAUI2) +#define FBNIC_AUI_MODE_PAM4 (FBNIC_AUI_50GAUI1) enum fbnic_sensor_id { FBNIC_SENSOR_TEMP, /* Temp in millidegrees Centigrade */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 561837e80ec8..c30c060b72e0 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -42,9 +42,8 @@ struct fbnic_net { struct phylink_config phylink_config; struct phylink_pcs phylink_pcs; - /* TBD: Remove these when phylink supports FEC and lane config */ + u8 aui; u8 fec; - u8 link_mode; /* Cached top bits of the HW time counter for 40b -> 64b conversion */ u32 time_high; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c index cb375a3dafe8..edd8738c981a 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c @@ -21,15 +21,15 @@ fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); struct fbnic_dev *fbd = fbn->fbd; - switch (fbn->link_mode) { - case FBNIC_LINK_25R1: + switch (fbn->aui) { + case FBNIC_AUI_25GAUI: state->speed = SPEED_25000; break; - case FBNIC_LINK_50R2: - case FBNIC_LINK_50R1: + case FBNIC_AUI_LAUI2: + case FBNIC_AUI_50GAUI1: state->speed = SPEED_50000; break; - case FBNIC_LINK_100R2: + case FBNIC_AUI_100GAUI2: state->speed = SPEED_100000; break; default: From 0853d8521bc1ef71bbedab4aadd3b833287fd521 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:07:48 -0700 Subject: [PATCH 5/8] fbnic: Update FW link mode values to represent actual link modes Make it so that the enum we use for the FW values represents actual link modes that will be normally advertised by a link partner. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028446893.625704.10103673858068429312.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 8 ++++---- drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h index 08bc4b918de7..08bf87c5ddf6 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h @@ -155,10 +155,10 @@ enum { }; enum { - FBNIC_FW_LINK_SPEED_25R1 = 1, - FBNIC_FW_LINK_SPEED_50R2 = 2, - FBNIC_FW_LINK_SPEED_50R1 = 3, - FBNIC_FW_LINK_SPEED_100R2 = 4, + FBNIC_FW_LINK_MODE_25CR = 1, + FBNIC_FW_LINK_MODE_50CR2 = 2, + FBNIC_FW_LINK_MODE_50CR = 3, + FBNIC_FW_LINK_MODE_100CR2 = 4, }; enum { diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c index 0528724011c1..284fcfbedb74 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c @@ -544,17 +544,17 @@ static void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec) { /* Retrieve default speed from FW */ switch (fbd->fw_cap.link_speed) { - case FBNIC_FW_LINK_SPEED_25R1: + case FBNIC_FW_LINK_MODE_25CR: *aui = FBNIC_AUI_25GAUI; break; - case FBNIC_FW_LINK_SPEED_50R2: + case FBNIC_FW_LINK_MODE_50CR2: *aui = FBNIC_AUI_LAUI2; break; - case FBNIC_FW_LINK_SPEED_50R1: + case FBNIC_FW_LINK_MODE_50CR: *aui = FBNIC_AUI_50GAUI1; *fec = FBNIC_FEC_RS; return; - case FBNIC_FW_LINK_SPEED_100R2: + case FBNIC_FW_LINK_MODE_100CR2: *aui = FBNIC_AUI_100GAUI2; *fec = FBNIC_FEC_RS; return; From 22780f69fb45d546d2ae32479317049de3621729 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:07:55 -0700 Subject: [PATCH 6/8] fbnic: Set correct supported modes and speeds based on FW setting The fbnic driver was using the XLGMII link mode to enable phylink, however that mode wasn't the correct one to use as the NIC doesn't actually use XLGMII, it is using a combinations of 25G, 50G, and 100G interface modes and configuring those via pins exposed on the PCS, MAC, and PHY interfaces. To more accurately reflect that we should drop the uxe of XGMII and XLGMII and instead use the correct interface types. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028447568.625704.17971496887030109107.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 7 +--- drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 1 + .../net/ethernet/meta/fbnic/fbnic_phylink.c | 32 ++++++++++++++++--- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c index 284fcfbedb74..5ff45463f9d2 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c @@ -540,7 +540,7 @@ static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd) return link; } -static void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec) +void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec) { /* Retrieve default speed from FW */ switch (fbd->fw_cap.link_speed) { @@ -580,15 +580,10 @@ static void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec) static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd) { - struct fbnic_net *fbn = netdev_priv(fbd->netdev); - /* Mask and clear the PCS interrupt, will be enabled by link handler */ wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0); wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0); - /* Pull in settings from FW */ - fbnic_mac_get_fw_settings(fbd, &fbn->aui, &fbn->fec); - return 0; } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h index 151d785116cb..86fa06da2b3e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h @@ -93,4 +93,5 @@ struct fbnic_mac { }; int fbnic_mac_init(struct fbnic_dev *fbd); +void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec); #endif /* _FBNIC_MAC_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c index edd8738c981a..a693a9f4d5fd 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c @@ -8,6 +8,22 @@ #include "fbnic_mac.h" #include "fbnic_netdev.h" +static phy_interface_t fbnic_phylink_select_interface(u8 aui) +{ + switch (aui) { + case FBNIC_AUI_100GAUI2: + return PHY_INTERFACE_MODE_100GBASEP; + case FBNIC_AUI_50GAUI1: + return PHY_INTERFACE_MODE_50GBASER; + case FBNIC_AUI_LAUI2: + return PHY_INTERFACE_MODE_LAUI; + case FBNIC_AUI_25GAUI: + return PHY_INTERFACE_MODE_25GBASER; + } + + return PHY_INTERFACE_MODE_NA; +} + static struct fbnic_net * fbnic_pcs_to_net(struct phylink_pcs *pcs) { @@ -128,6 +144,7 @@ static const struct phylink_mac_ops fbnic_phylink_mac_ops = { int fbnic_phylink_init(struct net_device *netdev) { struct fbnic_net *fbn = netdev_priv(netdev); + struct fbnic_dev *fbd = fbn->fbd; struct phylink *phylink; fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops; @@ -135,18 +152,23 @@ int fbnic_phylink_init(struct net_device *netdev) fbn->phylink_config.dev = &netdev->dev; fbn->phylink_config.type = PHYLINK_NETDEV; fbn->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | - MAC_10000FD | MAC_25000FD | - MAC_40000FD | MAC_50000FD | + MAC_25000FD | MAC_50000FD | MAC_100000FD; fbn->phylink_config.default_an_inband = true; - __set_bit(PHY_INTERFACE_MODE_XGMII, + __set_bit(PHY_INTERFACE_MODE_100GBASEP, fbn->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_XLGMII, + __set_bit(PHY_INTERFACE_MODE_50GBASER, + fbn->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_LAUI, + fbn->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_25GBASER, fbn->phylink_config.supported_interfaces); + fbnic_mac_get_fw_settings(fbd, &fbn->aui, &fbn->fec); + phylink = phylink_create(&fbn->phylink_config, NULL, - PHY_INTERFACE_MODE_XLGMII, + fbnic_phylink_select_interface(fbn->aui), &fbnic_phylink_mac_ops); if (IS_ERR(phylink)) return PTR_ERR(phylink); From fb9a3bb7f7f23b86d05e94f85e523d7d3f5fa57d Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:08:02 -0700 Subject: [PATCH 7/8] fbnic: Add support for reporting link config This change adds some basic support for reporting the current link config to the user via ethtool. Currently the main components reported are the carrier status, link speed, and FEC. For now we are handling the FEC directly as phylink doesn't have support for it. The plan is to work on incorporating FEC support into phylink and eventually adding the ability for us to set the FEC configuration through phylink itself. In addition as we don't yet have SFP or PHY support the listed modes supported are including ones not supported by the media we are attached to. That will hopefully be addressed once we can get the QSFP modules supported. Signed-off-by: Alexander Duyck Link: https://patch.msgid.link/175028448275.625704.60592644122010798.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 3 + .../net/ethernet/meta/fbnic/fbnic_netdev.h | 4 ++ .../net/ethernet/meta/fbnic/fbnic_phylink.c | 61 +++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 4646e80c3462..7cb191155d79 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -1683,6 +1683,7 @@ static const struct ethtool_ops fbnic_ethtool_ops = { .get_drvinfo = fbnic_get_drvinfo, .get_regs_len = fbnic_get_regs_len, .get_regs = fbnic_get_regs, + .get_link = ethtool_op_get_link, .get_coalesce = fbnic_get_coalesce, .set_coalesce = fbnic_set_coalesce, .get_ringparam = fbnic_get_ringparam, @@ -1705,6 +1706,8 @@ static const struct ethtool_ops fbnic_ethtool_ops = { .set_channels = fbnic_set_channels, .get_ts_info = fbnic_get_ts_info, .get_ts_stats = fbnic_get_ts_stats, + .get_link_ksettings = fbnic_phylink_ethtool_ksettings_get, + .get_fecparam = fbnic_phylink_get_fecparam, .get_eth_mac_stats = fbnic_get_eth_mac_stats, .get_eth_ctrl_stats = fbnic_get_eth_ctrl_stats, .get_rmon_stats = fbnic_get_rmon_stats, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index c30c060b72e0..943a52c77ed3 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -92,5 +92,9 @@ void fbnic_time_stop(struct fbnic_net *fbn); void __fbnic_set_rx_mode(struct net_device *netdev); void fbnic_clear_rx_mode(struct net_device *netdev); +int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, + struct ethtool_link_ksettings *cmd); +int fbnic_phylink_get_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fecparam); int fbnic_phylink_init(struct net_device *netdev); #endif /* _FBNIC_NETDEV_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c index a693a9f4d5fd..3a11d2a27de9 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c @@ -24,6 +24,67 @@ static phy_interface_t fbnic_phylink_select_interface(u8 aui) return PHY_INTERFACE_MODE_NA; } +static void +fbnic_phylink_get_supported_fec_modes(unsigned long *supported) +{ + /* The NIC can support up to 8 possible combinations. + * Either 50G-CR, or 100G-CR2 + * This is with RS FEC mode only + * Either 25G-CR, or 50G-CR2 + * This is with No FEC, RS, or Base-R + */ + if (phylink_test(supported, 100000baseCR2_Full) || + phylink_test(supported, 50000baseCR_Full)) + phylink_set(supported, FEC_RS); + if (phylink_test(supported, 50000baseCR2_Full) || + phylink_test(supported, 25000baseCR_Full)) { + phylink_set(supported, FEC_BASER); + phylink_set(supported, FEC_NONE); + phylink_set(supported, FEC_RS); + } +} + +int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + int err; + + err = phylink_ethtool_ksettings_get(fbn->phylink, cmd); + if (!err) { + unsigned long *supp = cmd->link_modes.supported; + + cmd->base.port = PORT_DA; + cmd->lanes = (fbn->aui & FBNIC_AUI_MODE_R2) ? 2 : 1; + + fbnic_phylink_get_supported_fec_modes(supp); + } + + return err; +} + +int fbnic_phylink_get_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fecparam) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + if (fbn->fec & FBNIC_FEC_RS) { + fecparam->active_fec = ETHTOOL_FEC_RS; + fecparam->fec = ETHTOOL_FEC_RS; + } else if (fbn->fec & FBNIC_FEC_BASER) { + fecparam->active_fec = ETHTOOL_FEC_BASER; + fecparam->fec = ETHTOOL_FEC_BASER; + } else { + fecparam->active_fec = ETHTOOL_FEC_OFF; + fecparam->fec = ETHTOOL_FEC_OFF; + } + + if (fbn->aui & FBNIC_AUI_MODE_PAM4) + fecparam->fec |= ETHTOOL_FEC_AUTO; + + return 0; +} + static struct fbnic_net * fbnic_pcs_to_net(struct phylink_pcs *pcs) { From eb4c27edb4d8dbfbdcc7bc03e0394a0fab8af7d5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 18 Jun 2025 15:08:09 -0700 Subject: [PATCH 8/8] fbnic: Add support for setting/getting pause configuration Phylink already handles most of the pieces necessary for configuring autonegotation. With that being the case we can add support for getting/setting pause now by just passing through the ethtool call to the phylink code. Signed-off-by: Alexander Duyck Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/175028448974.625704.14427543910503058114.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c | 2 ++ drivers/net/ethernet/meta/fbnic/fbnic_netdev.h | 4 ++++ drivers/net/ethernet/meta/fbnic/fbnic_phylink.c | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 7cb191155d79..7fe9983d3c0e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -1688,6 +1688,8 @@ static const struct ethtool_ops fbnic_ethtool_ops = { .set_coalesce = fbnic_set_coalesce, .get_ringparam = fbnic_get_ringparam, .set_ringparam = fbnic_set_ringparam, + .get_pauseparam = fbnic_phylink_get_pauseparam, + .set_pauseparam = fbnic_phylink_set_pauseparam, .get_strings = fbnic_get_strings, .get_ethtool_stats = fbnic_get_ethtool_stats, .get_sset_count = fbnic_get_sset_count, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 943a52c77ed3..a3dc85d3838b 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -92,6 +92,10 @@ void fbnic_time_stop(struct fbnic_net *fbn); void __fbnic_set_rx_mode(struct net_device *netdev); void fbnic_clear_rx_mode(struct net_device *netdev); +void fbnic_phylink_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause); +int fbnic_phylink_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause); int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, struct ethtool_link_ksettings *cmd); int fbnic_phylink_get_fecparam(struct net_device *netdev, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c index 3a11d2a27de9..7ce3fdd25282 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c @@ -24,6 +24,22 @@ static phy_interface_t fbnic_phylink_select_interface(u8 aui) return PHY_INTERFACE_MODE_NA; } +void fbnic_phylink_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + phylink_ethtool_get_pauseparam(fbn->phylink, pause); +} + +int fbnic_phylink_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + return phylink_ethtool_set_pauseparam(fbn->phylink, pause); +} + static void fbnic_phylink_get_supported_fec_modes(unsigned long *supported) {