* [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support
@ 2025-11-10 16:00 Alexander Duyck
2025-11-10 16:00 ` [net-next PATCH v3 01/10] net: phy: Add support for 25, 50 and 100Gbps PMA to genphy_c45_read_pma Alexander Duyck
` (10 more replies)
0 siblings, 11 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:00 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
To transition the fbnic driver to using the XPCS driver we need to address
the fact that we need a representation for the FW managed PMA/PMD that is
actually a SerDes PHY to handle link bouncing during link training.
This patch set first introduces the necessary bits to the
generic c45 driver code to enable it to read 25G, 50G, and 100G modes from
the PHY. After that we update the XPCS driver to to do the same.
The rest of this patch set enables the changes to fbnic to make use of these
interfaces and expose a PMA/PMD that can provide a necessary link delay to
avoid link flapping in the event that a cable is disconnected and
reconnected, and to correctly provide the count for the link down events.
With this we have the basic groundwork laid as with this all the bits and
pieces are in place in terms of reading the configuration. The general plan for
follow-on patch sets is to start looking at enabling changing the configuration
in environments where that is supported.
v2: Added XPCS code to the patch set
Dropped code adding bits for extended ability registers
Switched from enabling code in generic c45 to enabling code in fbnic_phy.c
Fixed several bugs related to phy state machine and use of resume
Moved PHY assignment into ndo_init/uninit
Renamed fbnic_swmii.c to fbnic_mdio.c
v3: Modified XPCS to have it read link from PMA instead of using a phydev
Fixed naming for PCS vs PMA for CTRL1 register speed bit values
Added logic to XPCS to get speed from PCS CTRL1 register
Swapped fbnic link delay timer from tracking training start to end
Dropped driver code for fbnic_phy.c and phydev code from patches
Updated patch naming to match expectations for PCS changes
Cleaned up dead code and defines from earlier versions
---
Alexander Duyck (10):
net: phy: Add support for 25, 50 and 100Gbps PMA to genphy_c45_read_pma
net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values
net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces
net: pcs: xpcs: Fix PMA identifier handling in XPCS
net: pcs: xpcs: Add support for FBNIC 25G, 50G, 100G PMA
fbnic: Rename PCS IRQ to MAC IRQ as it is actually a MAC interrupt
fbnic: Add logic to track PMD state via MAC/PCS signals
fbnic: Cleanup handling for link down event statistics
fbnic: Add SW shim for MDIO interface to PMA/PMD and PCS
fbnic: Replace use of internal PCS w/ Designware XPCS
drivers/net/ethernet/meta/Kconfig | 1 +
drivers/net/ethernet/meta/fbnic/Makefile | 1 +
drivers/net/ethernet/meta/fbnic/fbnic.h | 15 +-
drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 2 +
.../net/ethernet/meta/fbnic/fbnic_ethtool.c | 9 +
drivers/net/ethernet/meta/fbnic/fbnic_irq.c | 45 +++--
drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 71 ++++---
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 40 +++-
drivers/net/ethernet/meta/fbnic/fbnic_mdio.c | 190 ++++++++++++++++++
.../net/ethernet/meta/fbnic/fbnic_netdev.c | 11 +-
.../net/ethernet/meta/fbnic/fbnic_netdev.h | 6 +-
drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 17 +-
.../net/ethernet/meta/fbnic/fbnic_phylink.c | 163 ++++++++-------
drivers/net/pcs/pcs-xpcs.c | 135 ++++++++++++-
drivers/net/phy/phy-c45.c | 17 +-
include/linux/pcs/pcs-xpcs.h | 4 +-
include/uapi/linux/mdio.h | 18 +-
17 files changed, 592 insertions(+), 153 deletions(-)
create mode 100644 drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
--
^ permalink raw reply [flat|nested] 17+ messages in thread
* [net-next PATCH v3 01/10] net: phy: Add support for 25, 50 and 100Gbps PMA to genphy_c45_read_pma
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
@ 2025-11-10 16:00 ` Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values Alexander Duyck
` (9 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:00 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
Add support for reading 25, 50, and 100G from the PMA interface for a C45
device. By doing this we enable support for future devices that support
higher speeds than the current limit of 10G.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/phy/phy-c45.c | 9 +++++++++
include/uapi/linux/mdio.h | 6 ++++++
2 files changed, 15 insertions(+)
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index e8e5be4684ab..1d747fbaa10c 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -627,6 +627,15 @@ int genphy_c45_read_pma(struct phy_device *phydev)
case MDIO_CTRL1_SPEED10G:
phydev->speed = SPEED_10000;
break;
+ case MDIO_PMA_CTRL1_SPEED25G:
+ phydev->speed = SPEED_25000;
+ break;
+ case MDIO_PMA_CTRL1_SPEED50G:
+ phydev->speed = SPEED_50000;
+ break;
+ case MDIO_PMA_CTRL1_SPEED100G:
+ phydev->speed = SPEED_100000;
+ break;
default:
phydev->speed = SPEED_UNKNOWN;
break;
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index 6975f182b22c..75ed41fc46c6 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -116,6 +116,12 @@
#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00)
/* 10PASS-TS/2BASE-TL */
#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04)
+/* 100 Gb/s */
+#define MDIO_PMA_CTRL1_SPEED100G (MDIO_CTRL1_SPEEDSELEXT | 0x0c)
+/* 25 Gb/s */
+#define MDIO_PMA_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x10)
+/* 50 Gb/s */
+#define MDIO_PMA_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x14)
/* 2.5 Gb/s */
#define MDIO_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
/* 5 Gb/s */
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
2025-11-10 16:00 ` [net-next PATCH v3 01/10] net: phy: Add support for 25, 50 and 100Gbps PMA to genphy_c45_read_pma Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-12 8:53 ` Maxime Chevallier
2025-11-12 10:42 ` Russell King (Oracle)
2025-11-10 16:01 ` [net-next PATCH v3 03/10] net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces Alexander Duyck
` (8 subsequent siblings)
10 siblings, 2 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
The 2.5G and 5G values are not consistent between the PCS CTRL1 and PMA
CTRL1 values. In order to avoid confusion between the two I am updating the
values to include "PMA" in the name similar to values used in similar
places.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/phy/phy-c45.c | 8 ++++----
include/uapi/linux/mdio.h | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 1d747fbaa10c..d161fe3fee75 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -148,12 +148,12 @@ int genphy_c45_pma_setup_forced(struct phy_device *phydev)
ctrl2 |= MDIO_PMA_CTRL2_1000BT;
break;
case SPEED_2500:
- ctrl1 |= MDIO_CTRL1_SPEED2_5G;
+ ctrl1 |= MDIO_PMA_CTRL1_SPEED2_5G;
/* Assume 2.5Gbase-T */
ctrl2 |= MDIO_PMA_CTRL2_2_5GBT;
break;
case SPEED_5000:
- ctrl1 |= MDIO_CTRL1_SPEED5G;
+ ctrl1 |= MDIO_PMA_CTRL1_SPEED5G;
/* Assume 5Gbase-T */
ctrl2 |= MDIO_PMA_CTRL2_5GBT;
break;
@@ -618,10 +618,10 @@ int genphy_c45_read_pma(struct phy_device *phydev)
case MDIO_PMA_CTRL1_SPEED1000:
phydev->speed = SPEED_1000;
break;
- case MDIO_CTRL1_SPEED2_5G:
+ case MDIO_PMA_CTRL1_SPEED2_5G:
phydev->speed = SPEED_2500;
break;
- case MDIO_CTRL1_SPEED5G:
+ case MDIO_PMA_CTRL1_SPEED5G:
phydev->speed = SPEED_5000;
break;
case MDIO_CTRL1_SPEED10G:
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index 75ed41fc46c6..c33aa864ef66 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -123,9 +123,9 @@
/* 50 Gb/s */
#define MDIO_PMA_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x14)
/* 2.5 Gb/s */
-#define MDIO_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
+#define MDIO_PMA_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
/* 5 Gb/s */
-#define MDIO_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c)
+#define MDIO_PMA_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c)
/* Status register 1. */
#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 03/10] net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
2025-11-10 16:00 ` [net-next PATCH v3 01/10] net: phy: Add support for 25, 50 and 100Gbps PMA to genphy_c45_read_pma Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 04/10] net: pcs: xpcs: Fix PMA identifier handling in XPCS Alexander Duyck
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
With this change we are adding support for 25G, 50G, and 100G interface
types to the XPCS driver. This had supposedly been enabled with the
addition of XLGMII but I don't see any capability for configuration there
so I suspect it may need to be refactored in the future.
With this change we can enable the XPCS driver with the selected interface
and it should be able to detect link, speed, and report the link status to
the phylink interface.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/pcs/pcs-xpcs.c | 105 ++++++++++++++++++++++++++++++++++++++++++--
include/uapi/linux/mdio.h | 3 +
2 files changed, 104 insertions(+), 4 deletions(-)
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 3d1bd5aac093..b33767c7b45c 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -37,6 +37,16 @@ static const int xpcs_10gkr_features[] = {
__ETHTOOL_LINK_MODE_MASK_NBITS,
};
+static const int xpcs_25gbaser_features[] = {
+ ETHTOOL_LINK_MODE_MII_BIT,
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
static const int xpcs_xlgmii_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
@@ -67,6 +77,40 @@ static const int xpcs_xlgmii_features[] = {
__ETHTOOL_LINK_MODE_MASK_NBITS,
};
+static const int xpcs_50gbaser_features[] = {
+ ETHTOOL_LINK_MODE_MII_BIT,
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
+static const int xpcs_50gbaser2_features[] = {
+ ETHTOOL_LINK_MODE_MII_BIT,
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
+static const int xpcs_100gbasep_features[] = {
+ ETHTOOL_LINK_MODE_MII_BIT,
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
static const int xpcs_10gbaser_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
@@ -523,9 +567,38 @@ static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,
return speed;
}
-static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
- struct phylink_link_state *state)
+static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs,
+ struct phylink_link_state *state)
{
+ int pcs_ctrl1;
+
+ pcs_ctrl1 = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL1);
+ if (pcs_ctrl1 < 0)
+ return pcs_ctrl1;
+
+ switch (pcs_ctrl1 & MDIO_CTRL1_SPEEDSEL) {
+ case MDIO_PCS_CTRL1_SPEED25G:
+ state->speed = SPEED_25000;
+ break;
+ case MDIO_PCS_CTRL1_SPEED50G:
+ state->speed = SPEED_50000;
+ break;
+ case MDIO_PCS_CTRL1_SPEED100G:
+ state->speed = SPEED_100000;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int xpcs_resolve_pma(struct dw_xpcs *xpcs,
+ struct phylink_link_state *state)
+{
+ int err = 0;
+
state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
state->duplex = DUPLEX_FULL;
@@ -536,10 +609,18 @@ static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
case PHY_INTERFACE_MODE_XLGMII:
state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
break;
+ case PHY_INTERFACE_MODE_25GBASER:
+ case PHY_INTERFACE_MODE_50GBASER:
+ case PHY_INTERFACE_MODE_LAUI:
+ case PHY_INTERFACE_MODE_100GBASEP:
+ err = xpcs_c45_read_pcs_speed(xpcs, state);
+ break;
default:
state->speed = SPEED_UNKNOWN;
break;
}
+
+ return err;
}
static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
@@ -945,10 +1026,10 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
phylink_resolve_c73(state);
} else {
- xpcs_resolve_pma(xpcs, state);
+ ret = xpcs_resolve_pma(xpcs, state);
}
- return 0;
+ return ret;
}
static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
@@ -1312,10 +1393,26 @@ static const struct dw_xpcs_compat synopsys_xpcs_compat[] = {
.interface = PHY_INTERFACE_MODE_10GKR,
.supported = xpcs_10gkr_features,
.an_mode = DW_AN_C73,
+ }, {
+ .interface = PHY_INTERFACE_MODE_25GBASER,
+ .supported = xpcs_25gbaser_features,
+ .an_mode = DW_AN_C73,
}, {
.interface = PHY_INTERFACE_MODE_XLGMII,
.supported = xpcs_xlgmii_features,
.an_mode = DW_AN_C73,
+ }, {
+ .interface = PHY_INTERFACE_MODE_50GBASER,
+ .supported = xpcs_50gbaser_features,
+ .an_mode = DW_AN_C73,
+ }, {
+ .interface = PHY_INTERFACE_MODE_LAUI,
+ .supported = xpcs_50gbaser2_features,
+ .an_mode = DW_AN_C73,
+ }, {
+ .interface = PHY_INTERFACE_MODE_100GBASEP,
+ .supported = xpcs_100gbasep_features,
+ .an_mode = DW_AN_C73,
}, {
.interface = PHY_INTERFACE_MODE_10GBASER,
.supported = xpcs_10gbaser_features,
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index c33aa864ef66..2da509c9c0a5 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -118,10 +118,13 @@
#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04)
/* 100 Gb/s */
#define MDIO_PMA_CTRL1_SPEED100G (MDIO_CTRL1_SPEEDSELEXT | 0x0c)
+#define MDIO_PCS_CTRL1_SPEED100G (MDIO_CTRL1_SPEEDSELEXT | 0x10)
/* 25 Gb/s */
#define MDIO_PMA_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x10)
+#define MDIO_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14)
/* 50 Gb/s */
#define MDIO_PMA_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x14)
+#define MDIO_PCS_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
/* 2.5 Gb/s */
#define MDIO_PMA_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
/* 5 Gb/s */
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 04/10] net: pcs: xpcs: Fix PMA identifier handling in XPCS
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (2 preceding siblings ...)
2025-11-10 16:01 ` [net-next PATCH v3 03/10] net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 05/10] net: pcs: xpcs: Add support for FBNIC 25G, 50G, 100G PMA Alexander Duyck
` (6 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
The XPCS driver was mangling the PMA identifier as the original code
appears to have been focused on just capturing the OUI. Rather than store a
mangled ID it is better to work with the actual PMA ID and instead just
mask out the values that don't apply rather than shifting them and
reordering them as you still don't get the original OUI for the NIC without
having to bitswap the values as per the definition of the layout in IEEE
802.3-2022 22.2.4.3.1.
By laying it out as it was in the hardware it is also less likely for us to
have an unintentional collision as the enum values will occupy the revision
number area while the OUI occupies the upper 22 bits.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/pcs/pcs-xpcs.c | 9 ++++-----
include/linux/pcs/pcs-xpcs.h | 2 +-
include/uapi/linux/mdio.h | 5 +++++
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index b33767c7b45c..8b5b5b63b74b 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -1365,17 +1365,16 @@ static int xpcs_read_ids(struct dw_xpcs *xpcs)
if (ret < 0)
return ret;
- id = ret;
+ id = ret << 16;
ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
if (ret < 0)
return ret;
- /* Note the inverted dword order and masked out Model/Revision numbers
- * with respect to what is done with the PCS ID...
+ /* For now we only record the OUI for the PMAPMD, we may want to
+ * add the model number at some point in the future.
*/
- ret = (ret >> 10) & 0x3F;
- id |= ret << 16;
+ id |= ret & MDIO_DEVID2_OUI;
/* Set the PMA ID if it hasn't been pre-initialized */
if (xpcs->info.pma == DW_XPCS_PMA_ID_NATIVE)
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index e40f554ff717..4cf6bd611e5a 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -38,7 +38,7 @@ enum dw_xpcs_pma_id {
DW_XPCS_PMA_GEN4_6G_ID,
DW_XPCS_PMA_GEN5_10G_ID,
DW_XPCS_PMA_GEN5_12G_ID,
- WX_TXGBE_XPCS_PMA_10G_ID = 0x0018fc80,
+ WX_TXGBE_XPCS_PMA_10G_ID = 0xfc806000,
};
struct dw_xpcs_info {
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index 2da509c9c0a5..b287f84036a5 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -142,6 +142,11 @@
#define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */
#define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */
+/* Device Identifier 2 */
+#define MDIO_DEVID2_OUI 0xfc00 /* OUI Portion of PHY ID */
+#define MDIO_DEVID2_MODEL_NUM 0x03f0 /* Manufacturer's Model Number */
+#define MDIO_DEVID2_REV_NUM 0x000f /* Revision Number */
+
/* Speed register. */
#define MDIO_SPEED_10G 0x0001 /* 10G capable */
#define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 05/10] net: pcs: xpcs: Add support for FBNIC 25G, 50G, 100G PMA
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (3 preceding siblings ...)
2025-11-10 16:01 ` [net-next PATCH v3 04/10] net: pcs: xpcs: Fix PMA identifier handling in XPCS Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 06/10] fbnic: Rename PCS IRQ to MAC IRQ as it is actually a MAC interrupt Alexander Duyck
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
The fbnic driver is planning to make use of the XPCS driver to enable
support for PCS and better integration with phylink. To do this though we
will need to enable several workarounds since the PMA/PMD interface for
fbnic is likely to be unique since it is a mix of two different vendor
products with a unique wrapper around the IP.
As such I have generated a PHY identifier based on IEEE 802.3-2022
22.2.4.3.1 using the OUI belonging to Meta Platforms and used with our
NICs. Using this we will provide it as the PHY ID via the SW based MDIO
interface so that the fbnic device can be identified and necessary
workarounds enabled in the XPCS driver.
As an initial workaround this change adds an exception so that soft_reset
is not set when the driver is initially bound to the PCS.
In addition I have added logic to integrate the PMA link state into the
link state for the PCS. With this we can avoid the link coming up too soon
on the FBNIC PHY and as a result we can avoid link flaps.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/pcs/pcs-xpcs.c | 23 +++++++++++++++++++++--
include/linux/pcs/pcs-xpcs.h | 2 ++
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 8b5b5b63b74b..69a6c03fd9e7 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -597,7 +597,25 @@ static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs,
static int xpcs_resolve_pma(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
- int err = 0;
+ int pma_stat1, err = 0;
+
+ /* The Meta Platforms FBNIC PMD will go into a training state for
+ * about 4 seconds when the link first comes up. During this time the
+ * PCS link will bounce. To avoid reporting link up too soon we include
+ * the PMA/PMD state provided by the driver.
+ */
+ if (xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID) {
+ pma_stat1 = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_STAT1);
+ if (pma_stat1 < 0) {
+ state->link = false;
+ return pma_stat1;
+ }
+
+ if (!(pma_stat1 & MDIO_STAT1_LSTATUS)) {
+ state->link = false;
+ return 0;
+ }
+ }
state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
state->duplex = DUPLEX_FULL;
@@ -1591,7 +1609,8 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev)
xpcs_get_interfaces(xpcs, xpcs->pcs.supported_interfaces);
- if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID)
+ if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID ||
+ xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID)
xpcs->pcs.poll = false;
else
xpcs->need_reset = true;
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index 4cf6bd611e5a..36073f7b6bb4 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -39,6 +39,8 @@ enum dw_xpcs_pma_id {
DW_XPCS_PMA_GEN5_10G_ID,
DW_XPCS_PMA_GEN5_12G_ID,
WX_TXGBE_XPCS_PMA_10G_ID = 0xfc806000,
+ /* Meta Platforms OUI 88:25:08, model 0, revision 0 */
+ MP_FBNIC_XPCS_PMA_100G_ID = 0x46904000,
};
struct dw_xpcs_info {
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 06/10] fbnic: Rename PCS IRQ to MAC IRQ as it is actually a MAC interrupt
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (4 preceding siblings ...)
2025-11-10 16:01 ` [net-next PATCH v3 05/10] net: pcs: xpcs: Add support for FBNIC 25G, 50G, 100G PMA Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 07/10] fbnic: Add logic to track PMD state via MAC/PCS signals Alexander Duyck
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
Throughout several spots in the code I had called out the IRQ as being
related to the PCS. However the actual IRQ is a part of the MAC and it is
just exposing PCS data. To more accurately reflect the owner of the calls
this change makes it so that we rename the functions and values that are
taking in the interrupt value and processing it to reflect that it is a MAC
call and not a PCS one.
This change is mostly motivated by the fact that we will be moving the
handling of this interrupt from being PCS focused to being more PMA/PMD
focused as this will drive the phydev driver that I am adding instead of
driving the PCS directly.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/ethernet/meta/fbnic/fbnic.h | 6 ++---
drivers/net/ethernet/meta/fbnic/fbnic_irq.c | 30 ++++++++++++-----------
drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 14 +++++------
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 8 +++---
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 4 ++-
drivers/net/ethernet/meta/fbnic/fbnic_phylink.c | 2 +-
6 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index b03e5a3d5144..98929add5f21 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -34,7 +34,7 @@ struct fbnic_dev {
u32 __iomem *uc_addr4;
const struct fbnic_mac *mac;
unsigned int fw_msix_vector;
- unsigned int pcs_msix_vector;
+ unsigned int mac_msix_vector;
unsigned short num_irqs;
struct {
@@ -175,8 +175,8 @@ void fbnic_fw_free_mbx(struct fbnic_dev *fbd);
void fbnic_hwmon_register(struct fbnic_dev *fbd);
void fbnic_hwmon_unregister(struct fbnic_dev *fbd);
-int fbnic_pcs_request_irq(struct fbnic_dev *fbd);
-void fbnic_pcs_free_irq(struct fbnic_dev *fbd);
+int fbnic_mac_request_irq(struct fbnic_dev *fbd);
+void fbnic_mac_free_irq(struct fbnic_dev *fbd);
void fbnic_napi_name_irqs(struct fbnic_dev *fbd);
int fbnic_napi_request_irq(struct fbnic_dev *fbd,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
index 1c88a2bf3a7a..40947e142c5d 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
@@ -118,12 +118,12 @@ void fbnic_fw_free_mbx(struct fbnic_dev *fbd)
fbd->fw_msix_vector = 0;
}
-static irqreturn_t fbnic_pcs_msix_intr(int __always_unused irq, void *data)
+static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)
{
struct fbnic_dev *fbd = data;
struct fbnic_net *fbn;
- if (fbd->mac->pcs_get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) {
+ if (fbd->mac->get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) {
fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0),
1u << FBNIC_PCS_MSIX_ENTRY);
return IRQ_HANDLED;
@@ -137,20 +137,20 @@ static irqreturn_t fbnic_pcs_msix_intr(int __always_unused irq, void *data)
}
/**
- * fbnic_pcs_request_irq - Configure the PCS to enable it to advertise link
+ * fbnic_mac_request_irq - Configure the MAC to enable it to advertise link
* @fbd: Pointer to device to initialize
*
- * This function provides basic bringup for the MAC/PCS IRQ. For now the IRQ
+ * This function provides basic bringup for the MAC/PHY IRQ. For now the IRQ
* will remain disabled until we start the MAC/PCS/PHY logic via phylink.
*
* Return: non-zero on failure.
**/
-int fbnic_pcs_request_irq(struct fbnic_dev *fbd)
+int fbnic_mac_request_irq(struct fbnic_dev *fbd)
{
struct pci_dev *pdev = to_pci_dev(fbd->dev);
int vector, err;
- WARN_ON(fbd->pcs_msix_vector);
+ WARN_ON(fbd->mac_msix_vector);
vector = pci_irq_vector(pdev, FBNIC_PCS_MSIX_ENTRY);
if (vector < 0)
@@ -159,7 +159,7 @@ int fbnic_pcs_request_irq(struct fbnic_dev *fbd)
/* Request the IRQ for PCS link vector.
* Map PCS cause to it, and unmask it
*/
- err = request_irq(vector, &fbnic_pcs_msix_intr, 0,
+ err = request_irq(vector, &fbnic_mac_msix_intr, 0,
fbd->netdev->name, fbd);
if (err)
return err;
@@ -168,22 +168,22 @@ int fbnic_pcs_request_irq(struct fbnic_dev *fbd)
fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX),
FBNIC_PCS_MSIX_ENTRY | FBNIC_INTR_MSIX_CTRL_ENABLE);
- fbd->pcs_msix_vector = vector;
+ fbd->mac_msix_vector = vector;
return 0;
}
/**
- * fbnic_pcs_free_irq - Teardown the PCS IRQ to prepare for stopping
+ * fbnic_mac_free_irq - Teardown the MAC IRQ to prepare for stopping
* @fbd: Pointer to device that is stopping
*
- * This function undoes the work done in fbnic_pcs_request_irq and prepares
+ * This function undoes the work done in fbnic_mac_request_irq and prepares
* the device to no longer receive traffic on the host interface.
**/
-void fbnic_pcs_free_irq(struct fbnic_dev *fbd)
+void fbnic_mac_free_irq(struct fbnic_dev *fbd)
{
/* Vector has already been freed */
- if (!fbd->pcs_msix_vector)
+ if (!fbd->mac_msix_vector)
return;
/* Disable interrupt */
@@ -192,14 +192,14 @@ void fbnic_pcs_free_irq(struct fbnic_dev *fbd)
fbnic_wrfl(fbd);
/* Synchronize IRQ to prevent race that would unmask vector */
- synchronize_irq(fbd->pcs_msix_vector);
+ synchronize_irq(fbd->mac_msix_vector);
/* Mask the vector */
fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_PCS_MSIX_ENTRY);
/* Free the vector */
- free_irq(fbd->pcs_msix_vector, fbd);
- fbd->pcs_msix_vector = 0;
+ free_irq(fbd->mac_msix_vector, fbd);
+ fbd->mac_msix_vector = 0;
}
void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
index 2a84bd1d7e26..28a2e1fd3760 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
@@ -434,14 +434,14 @@ static void fbnic_mac_tx_pause_config(struct fbnic_dev *fbd, bool tx_pause)
wr32(fbd, FBNIC_RXB_PAUSE_DROP_CTRL, rxb_pause_ctrl);
}
-static int fbnic_pcs_get_link_event_asic(struct fbnic_dev *fbd)
+static int fbnic_mac_get_link_event(struct fbnic_dev *fbd)
{
- u32 pcs_intr_mask = rd32(fbd, FBNIC_SIG_PCS_INTR_STS);
+ u32 intr_mask = rd32(fbd, FBNIC_SIG_PCS_INTR_STS);
- if (pcs_intr_mask & FBNIC_SIG_PCS_INTR_LINK_DOWN)
+ if (intr_mask & FBNIC_SIG_PCS_INTR_LINK_DOWN)
return FBNIC_LINK_EVENT_DOWN;
- return (pcs_intr_mask & FBNIC_SIG_PCS_INTR_LINK_UP) ?
+ return (intr_mask & FBNIC_SIG_PCS_INTR_LINK_UP) ?
FBNIC_LINK_EVENT_UP : FBNIC_LINK_EVENT_NONE;
}
@@ -521,7 +521,7 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd)
return !lane_mask;
}
-static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd)
+static bool fbnic_mac_get_link(struct fbnic_dev *fbd)
{
bool link;
@@ -869,8 +869,8 @@ static const struct fbnic_mac fbnic_mac_asic = {
.init_regs = fbnic_mac_init_regs,
.pcs_enable = fbnic_pcs_enable_asic,
.pcs_disable = fbnic_pcs_disable_asic,
- .pcs_get_link = fbnic_pcs_get_link_asic,
- .pcs_get_link_event = fbnic_pcs_get_link_event_asic,
+ .get_link = fbnic_mac_get_link,
+ .get_link_event = fbnic_mac_get_link_event,
.get_fec_stats = fbnic_mac_get_fec_stats,
.get_pcs_stats = fbnic_mac_get_pcs_stats,
.get_eth_mac_stats = fbnic_mac_get_eth_mac_stats,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
index ede5ff0dae22..414c170abcba 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
@@ -59,9 +59,9 @@ enum fbnic_sensor_id {
* Configure and enable PCS to enable link if not already enabled
* void (*pcs_disable)(struct fbnic_dev *fbd);
* Shutdown the link if we are the only consumer of it.
- * bool (*pcs_get_link)(struct fbnic_dev *fbd);
+ * bool (*get_link)(struct fbnic_dev *fbd);
* Check PCS link status
- * int (*pcs_get_link_event)(struct fbnic_dev *fbd)
+ * int (*get_link_event)(struct fbnic_dev *fbd)
* Get the current link event status, reports true if link has
* changed to either FBNIC_LINK_EVENT_DOWN or FBNIC_LINK_EVENT_UP
*
@@ -76,8 +76,8 @@ struct fbnic_mac {
int (*pcs_enable)(struct fbnic_dev *fbd);
void (*pcs_disable)(struct fbnic_dev *fbd);
- bool (*pcs_get_link)(struct fbnic_dev *fbd);
- int (*pcs_get_link_event)(struct fbnic_dev *fbd);
+ bool (*get_link)(struct fbnic_dev *fbd);
+ int (*get_link_event)(struct fbnic_dev *fbd);
void (*get_fec_stats)(struct fbnic_dev *fbd, bool reset,
struct fbnic_fec_stats *fec_stats);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index e95be0e7bd9e..2d5ae89b4a15 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -44,7 +44,7 @@ int __fbnic_open(struct fbnic_net *fbn)
if (err)
goto time_stop;
- err = fbnic_pcs_request_irq(fbd);
+ err = fbnic_mac_request_irq(fbd);
if (err)
goto time_stop;
@@ -89,7 +89,7 @@ static int fbnic_stop(struct net_device *netdev)
phylink_suspend(fbn->phylink, fbnic_bmc_present(fbn->fbd));
fbnic_down(fbn);
- fbnic_pcs_free_irq(fbn->fbd);
+ fbnic_mac_free_irq(fbn->fbd);
fbnic_time_stop(fbn);
fbnic_fw_xmit_ownership_msg(fbn->fbd, false);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index 7ce3fdd25282..3c0bd435ee28 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -132,7 +132,7 @@ fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
state->duplex = DUPLEX_FULL;
- state->link = fbd->mac->pcs_get_link(fbd);
+ state->link = fbd->mac->get_link(fbd);
}
static int
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 07/10] fbnic: Add logic to track PMD state via MAC/PCS signals
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (5 preceding siblings ...)
2025-11-10 16:01 ` [net-next PATCH v3 06/10] fbnic: Rename PCS IRQ to MAC IRQ as it is actually a MAC interrupt Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 08/10] fbnic: Cleanup handling for link down event statistics Alexander Duyck
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
One complication with the design of our part is that the PMD doesn't
provide a direct signal to the host. Instead we have visibility to signals
that the PCS provides to the MAC that allow us to check the link state
through that.
That said we need to account for several things in the PMD and firmware
when managing the link. Specifically when the link first starts to come up
the PMD will cause the link to flap as the firmware will begin a training
cycle when the link is first detected. As a result this will cause link
flapping if we were to immediately report link up when the PCS first
detects it.
To address that we are adding a pmd_state variable that is meant to be a
countdown of sorts indicating the state of the PMD. If the link is down the
PMD will start out in the initialize state, otherwise if the link is up it
will start out in the training state ready to report link up. If link is
detected while in the initialize state the PMD state will switch to
training, and if after 4 seconds the link is still stable we will
transition to the send_data state. With this we can avoid link flapping
when a cable is first connected to the NIC.
One side effect of this is that we need to pull the link state away from
the PCS. For now we use a union of the PCS link state register value and
the pmd_state. The plan is to add a phydev driver to report the pmd_state
to the phylink interface. With that we can then look at switching over to
the use of the XPCS driver for fbnic instead of having an internal one.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/ethernet/meta/fbnic/fbnic.h | 4 +
drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 2 +
drivers/net/ethernet/meta/fbnic/fbnic_irq.c | 4 +
drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 59 ++++++++++++-----
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 35 ++++++++--
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 2 -
drivers/net/ethernet/meta/fbnic/fbnic_netdev.h | 2 -
drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 14 +++-
drivers/net/ethernet/meta/fbnic/fbnic_phylink.c | 79 +++++++++++++++++------
9 files changed, 145 insertions(+), 56 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index 98929add5f21..fac1283d0ade 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -83,6 +83,10 @@ struct fbnic_dev {
/* Last @time_high refresh time in jiffies (to catch stalls) */
unsigned long last_read;
+ /* PMD specific data */
+ unsigned long end_of_pmd_training;
+ u8 pmd_state;
+
/* Local copy of hardware statistics */
struct fbnic_hw_stats hw_stats;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
index d3a7ad921f18..422265dc7abd 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
@@ -787,6 +787,8 @@ enum {
/* MAC PCS registers */
#define FBNIC_CSR_START_PCS 0x10000 /* CSR section delimiter */
+#define FBNIC_PCS_PAGE(n) (0x10000 + 0x400 * (n)) /* 0x40000 + 1024*n */
+#define FBNIC_PCS(reg, n) ((reg) + FBNIC_PCS_PAGE(n))
#define FBNIC_CSR_END_PCS 0x10668 /* CSR section delimiter */
#define FBNIC_CSR_START_RSFEC 0x10800 /* CSR section delimiter */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
index 40947e142c5d..9b068b82f30a 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
@@ -131,7 +131,9 @@ static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)
fbn = netdev_priv(fbd->netdev);
- phylink_pcs_change(&fbn->phylink_pcs, false);
+ /* Record link down events */
+ if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec))
+ phylink_pcs_change(&fbn->phylink_pcs, false);
return IRQ_HANDLED;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
index 28a2e1fd3760..fd01d95c5348 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
@@ -466,9 +466,8 @@ static u32 __fbnic_mac_cmd_config_asic(struct fbnic_dev *fbd,
return command_config;
}
-static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd)
+static bool fbnic_mac_get_link_status(struct fbnic_dev *fbd, u8 aui, u8 fec)
{
- struct fbnic_net *fbn = netdev_priv(fbd->netdev);
u32 pcs_status, lane_mask = ~0;
pcs_status = rd32(fbd, FBNIC_SIG_PCS_OUT0);
@@ -476,7 +475,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->aui) {
+ switch (aui) {
case FBNIC_AUI_100GAUI2:
lane_mask = 0xf;
break;
@@ -484,7 +483,7 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd)
lane_mask = 3;
break;
case FBNIC_AUI_LAUI2:
- switch (fbn->fec) {
+ switch (fec) {
case FBNIC_FEC_OFF:
lane_mask = 0x63;
break;
@@ -502,7 +501,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) {
+ switch (fec) {
case FBNIC_FEC_OFF:
lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_BLOCK_LOCK,
pcs_status);
@@ -521,7 +520,36 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd)
return !lane_mask;
}
-static bool fbnic_mac_get_link(struct fbnic_dev *fbd)
+static bool fbnic_pmd_update_state(struct fbnic_dev *fbd, bool signal_detect)
+{
+ /* Delay link up for 4 seconds to allow for link training.
+ * The state transitions for this are as follows:
+ *
+ * All states have the following two transitions in common:
+ * Loss of signal -> FBNIC_PMD_INITIALIZE
+ * The condition handled below (!signal)
+ * Reconfiguration -> FBNIC_PMD_INITIALIZE
+ * Occurs when mac_prepare starts a PHY reconfig
+ * FBNIC_PMD_TRAINING:
+ * signal still detected && 4s have passed -> Report link up
+ * When link is brought up in link_up -> FBNIC_PMD_SEND_DATA
+ * FBNIC_PMD_INITIALIZE:
+ * signal detected -> FBNIC_PMD_TRAINING
+ */
+ if (!signal_detect) {
+ fbd->pmd_state = FBNIC_PMD_INITIALIZE;
+ } else if (fbd->pmd_state == FBNIC_PMD_TRAINING &&
+ time_before(fbd->end_of_pmd_training, jiffies)) {
+ return true;
+ } else if (fbd->pmd_state == FBNIC_PMD_INITIALIZE) {
+ fbd->end_of_pmd_training = jiffies + 4 * HZ;
+ fbd->pmd_state = FBNIC_PMD_TRAINING;
+ }
+
+ return fbd->pmd_state == FBNIC_PMD_SEND_DATA;
+}
+
+static bool fbnic_mac_get_link(struct fbnic_dev *fbd, u8 aui, u8 fec)
{
bool link;
@@ -538,7 +566,8 @@ static bool fbnic_mac_get_link(struct fbnic_dev *fbd)
wr32(fbd, FBNIC_SIG_PCS_INTR_STS,
FBNIC_SIG_PCS_INTR_LINK_DOWN | FBNIC_SIG_PCS_INTR_LINK_UP);
- link = fbnic_mac_get_pcs_link_status(fbd);
+ link = fbnic_mac_get_link_status(fbd, aui, fec);
+ link = fbnic_pmd_update_state(fbd, link);
/* Enable interrupt to only capture changes in link state */
wr32(fbd, FBNIC_SIG_PCS_INTR_MASK,
@@ -586,20 +615,15 @@ void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec)
}
}
-static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd)
+static void fbnic_mac_prepare(struct fbnic_dev *fbd, u8 aui, u8 fec)
{
/* 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);
- return 0;
-}
-
-static void fbnic_pcs_disable_asic(struct fbnic_dev *fbd)
-{
- /* Mask and clear the PCS interrupt */
- wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0);
- wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0);
+ /* If we don't have link tear it all down and start over */
+ if (!fbnic_mac_get_link_status(fbd, aui, fec))
+ fbd->pmd_state = FBNIC_PMD_INITIALIZE;
}
static void fbnic_mac_link_down_asic(struct fbnic_dev *fbd)
@@ -867,10 +891,9 @@ static int fbnic_mac_get_sensor_asic(struct fbnic_dev *fbd, int id,
static const struct fbnic_mac fbnic_mac_asic = {
.init_regs = fbnic_mac_init_regs,
- .pcs_enable = fbnic_pcs_enable_asic,
- .pcs_disable = fbnic_pcs_disable_asic,
.get_link = fbnic_mac_get_link,
.get_link_event = fbnic_mac_get_link_event,
+ .prepare = fbnic_mac_prepare,
.get_fec_stats = fbnic_mac_get_fec_stats,
.get_pcs_stats = fbnic_mac_get_pcs_stats,
.get_eth_mac_stats = fbnic_mac_get_eth_mac_stats,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
index 414c170abcba..2b08046645f2 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
@@ -10,6 +10,23 @@ struct fbnic_dev;
#define FBNIC_MAX_JUMBO_FRAME_SIZE 9742
+/* States loosely based on section 136.8.11.7.5 of IEEE 802.3-2022 Ethernet
+ * Standard. These are needed to track the state of the PHY as it has a delay
+ * of several seconds from the time link comes up until it has completed
+ * training that we need to wait to report the link.
+ *
+ * Currently we treat training as a single block as this is managed by the
+ * firmware.
+ *
+ * We have FBNIC_PMD_SEND_DATA set to 0 as the expected default at driver load
+ * and we initialize the structure containing it to zero at allocation.
+ */
+enum {
+ FBNIC_PMD_SEND_DATA = 0x0,
+ FBNIC_PMD_INITIALIZE = 0x1,
+ FBNIC_PMD_TRAINING = 0x2,
+};
+
enum {
FBNIC_LINK_EVENT_NONE = 0,
FBNIC_LINK_EVENT_UP = 1,
@@ -55,15 +72,15 @@ enum fbnic_sensor_id {
* void (*init_regs)(struct fbnic_dev *fbd);
* Initialize MAC registers to enable Tx/Rx paths and FIFOs.
*
- * void (*pcs_enable)(struct fbnic_dev *fbd);
- * Configure and enable PCS to enable link if not already enabled
- * void (*pcs_disable)(struct fbnic_dev *fbd);
- * Shutdown the link if we are the only consumer of it.
- * bool (*get_link)(struct fbnic_dev *fbd);
- * Check PCS link status
* int (*get_link_event)(struct fbnic_dev *fbd)
* Get the current link event status, reports true if link has
* changed to either FBNIC_LINK_EVENT_DOWN or FBNIC_LINK_EVENT_UP
+ * bool (*get_link)(struct fbnic_dev *fbd, u8 aui, u8 fec);
+ * Check link status
+ *
+ * void (*prepare)(struct fbnic_dev *fbd, u8 aui, u8 fec);
+ * Prepare PHY for init by fetching settings, disabling interrupts,
+ * and sending an updated PHY config to FW if needed.
*
* void (*link_down)(struct fbnic_dev *fbd);
* Configure MAC for link down event
@@ -74,10 +91,10 @@ enum fbnic_sensor_id {
struct fbnic_mac {
void (*init_regs)(struct fbnic_dev *fbd);
- int (*pcs_enable)(struct fbnic_dev *fbd);
- void (*pcs_disable)(struct fbnic_dev *fbd);
- bool (*get_link)(struct fbnic_dev *fbd);
int (*get_link_event)(struct fbnic_dev *fbd);
+ bool (*get_link)(struct fbnic_dev *fbd, u8 aui, u8 fec);
+
+ void (*prepare)(struct fbnic_dev *fbd, u8 aui, u8 fec);
void (*get_fec_stats)(struct fbnic_dev *fbd, bool reset,
struct fbnic_fec_stats *fec_stats);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index 2d5ae89b4a15..65318a5b466e 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -86,10 +86,10 @@ static int fbnic_stop(struct net_device *netdev)
{
struct fbnic_net *fbn = netdev_priv(netdev);
+ fbnic_mac_free_irq(fbn->fbd);
phylink_suspend(fbn->phylink, fbnic_bmc_present(fbn->fbd));
fbnic_down(fbn);
- fbnic_mac_free_irq(fbn->fbd);
fbnic_time_stop(fbn);
fbnic_fw_xmit_ownership_msg(fbn->fbd, false);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
index b0a87c57910f..c2e45ff64e34 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
@@ -107,7 +107,7 @@ int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev,
int fbnic_phylink_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fecparam);
int fbnic_phylink_init(struct net_device *netdev);
-
+void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev);
bool fbnic_check_split_frames(struct bpf_prog *prog,
unsigned int mtu, u32 hds_threshold);
#endif /* _FBNIC_NETDEV_H_ */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
index 4620f1847f2e..040bd520b160 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
@@ -207,6 +207,10 @@ static void fbnic_service_task(struct work_struct *work)
{
struct fbnic_dev *fbd = container_of(to_delayed_work(work),
struct fbnic_dev, service_task);
+ struct net_device *netdev = fbd->netdev;
+
+ if (netif_running(netdev))
+ fbnic_phylink_pmd_training_complete_notify(netdev);
rtnl_lock();
@@ -218,13 +222,13 @@ static void fbnic_service_task(struct work_struct *work)
fbnic_bmc_rpc_check(fbd);
- if (netif_carrier_ok(fbd->netdev)) {
- netdev_lock(fbd->netdev);
- fbnic_napi_depletion_check(fbd->netdev);
- netdev_unlock(fbd->netdev);
+ if (netif_carrier_ok(netdev)) {
+ netdev_lock(netdev);
+ fbnic_napi_depletion_check(netdev);
+ netdev_unlock(netdev);
}
- if (netif_running(fbd->netdev))
+ if (netif_running(netdev))
schedule_delayed_work(&fbd->service_task, HZ);
rtnl_unlock();
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index 3c0bd435ee28..27e4073d9898 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -132,25 +132,9 @@ fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
state->duplex = DUPLEX_FULL;
- state->link = fbd->mac->get_link(fbd);
-}
-
-static int
-fbnic_phylink_pcs_enable(struct phylink_pcs *pcs)
-{
- struct fbnic_net *fbn = fbnic_pcs_to_net(pcs);
- struct fbnic_dev *fbd = fbn->fbd;
-
- return fbd->mac->pcs_enable(fbd);
-}
-
-static void
-fbnic_phylink_pcs_disable(struct phylink_pcs *pcs)
-{
- struct fbnic_net *fbn = fbnic_pcs_to_net(pcs);
- struct fbnic_dev *fbd = fbn->fbd;
-
- return fbd->mac->pcs_disable(fbd);
+ state->link = (fbd->pmd_state == FBNIC_PMD_SEND_DATA) &&
+ (rd32(fbd, FBNIC_PCS(MDIO_STAT1, 0)) &
+ MDIO_STAT1_LSTATUS);
}
static int
@@ -164,8 +148,6 @@ fbnic_phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
static const struct phylink_pcs_ops fbnic_phylink_pcs_ops = {
.pcs_config = fbnic_phylink_pcs_config,
- .pcs_enable = fbnic_phylink_pcs_enable,
- .pcs_disable = fbnic_phylink_pcs_disable,
.pcs_get_state = fbnic_phylink_pcs_get_state,
};
@@ -179,12 +161,39 @@ fbnic_phylink_mac_select_pcs(struct phylink_config *config,
return &fbn->phylink_pcs;
}
+static int
+fbnic_phylink_mac_prepare(struct phylink_config *config, unsigned int mode,
+ phy_interface_t iface)
+{
+ struct net_device *netdev = to_net_dev(config->dev);
+ struct fbnic_net *fbn = netdev_priv(netdev);
+ struct fbnic_dev *fbd = fbn->fbd;
+
+ fbd->mac->prepare(fbd, fbn->aui, fbn->fec);
+
+ return 0;
+}
+
static void
fbnic_phylink_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
}
+static int
+fbnic_phylink_mac_finish(struct phylink_config *config, unsigned int mode,
+ phy_interface_t iface)
+{
+ struct net_device *netdev = to_net_dev(config->dev);
+ struct fbnic_net *fbn = netdev_priv(netdev);
+ struct fbnic_dev *fbd = fbn->fbd;
+
+ /* Retest the link state and restart interrupts */
+ fbd->mac->get_link(fbd, fbn->aui, fbn->fec);
+
+ return 0;
+}
+
static void
fbnic_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
@@ -213,7 +222,9 @@ fbnic_phylink_mac_link_up(struct phylink_config *config,
static const struct phylink_mac_ops fbnic_phylink_mac_ops = {
.mac_select_pcs = fbnic_phylink_mac_select_pcs,
+ .mac_prepare = fbnic_phylink_mac_prepare,
.mac_config = fbnic_phylink_mac_config,
+ .mac_finish = fbnic_phylink_mac_finish,
.mac_link_down = fbnic_phylink_mac_link_down,
.mac_link_up = fbnic_phylink_mac_link_up,
};
@@ -254,3 +265,29 @@ int fbnic_phylink_init(struct net_device *netdev)
return 0;
}
+
+/**
+ * fbnic_phylink_pmd_training_complete_notify - PMD training complete notifier
+ * @netdev: Netdev struct phylink device attached to
+ *
+ * When the link first comes up the PMD will have a period of 2 to 3 seconds
+ * where the link will flutter due to link training. To avoid spamming the
+ * kernel log with messages about this we add a delay of 4 seconds from the
+ * time of the last PCS report of link so that we can guarantee we are unlikely
+ * to see any further link loss events due to link training.
+ **/
+void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+ struct fbnic_dev *fbd = fbn->fbd;
+
+ if (fbd->pmd_state != FBNIC_PMD_TRAINING)
+ return;
+
+ if (!time_before(fbd->end_of_pmd_training, jiffies))
+ return;
+
+ fbd->pmd_state = FBNIC_PMD_SEND_DATA;
+
+ phylink_pcs_change(&fbn->phylink_pcs, false);
+}
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 08/10] fbnic: Cleanup handling for link down event statistics
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (6 preceding siblings ...)
2025-11-10 16:01 ` [net-next PATCH v3 07/10] fbnic: Add logic to track PMD state via MAC/PCS signals Alexander Duyck
@ 2025-11-10 16:01 ` Alexander Duyck
2025-11-10 16:02 ` [net-next PATCH v3 09/10] fbnic: Add SW shim for MDIO interface to PMA/PMD and PCS Alexander Duyck
` (2 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:01 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
The code for handling link down event tracking wasn't working in the
existing code. Specifically we should be tracking unexpected link down
events, not expected ones.
To do this tracking we can use the pmd_state variable and track cases where
we transition from send_data to initialize in the interrupt. These should
be the cases where we would be seeing unexpected link down events.
In addition we have cases where the PCS will reset following the training
due to errors generated while the PMD was training. This will result in a
PCS reset which will flap the link. To avoid counting this link flap as the
NIC has yet to report link up we will only record the link event if the
netif_carrier was already reporeted as present.
In order for the stat to have any value we have to display it so this
change adds logic to display it as a part of the ethtool stats.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c | 9 +++++++++
drivers/net/ethernet/meta/fbnic/fbnic_irq.c | 13 ++++++++++++-
drivers/net/ethernet/meta/fbnic/fbnic_phylink.c | 2 --
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index 95fac020eb93..693ebdf38705 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -1863,6 +1863,14 @@ fbnic_get_rmon_stats(struct net_device *netdev,
*ranges = fbnic_rmon_ranges;
}
+static void fbnic_get_link_ext_stats(struct net_device *netdev,
+ struct ethtool_link_ext_stats *stats)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+
+ stats->link_down_events = fbn->link_down_events;
+}
+
static const struct ethtool_ops fbnic_ethtool_ops = {
.cap_link_lanes_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
@@ -1874,6 +1882,7 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
.get_regs_len = fbnic_get_regs_len,
.get_regs = fbnic_get_regs,
.get_link = ethtool_op_get_link,
+ .get_link_ext_stats = fbnic_get_link_ext_stats,
.get_coalesce = fbnic_get_coalesce,
.set_coalesce = fbnic_set_coalesce,
.get_ringparam = fbnic_get_ringparam,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
index 9b068b82f30a..73dd10b7a1a8 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
@@ -122,6 +122,7 @@ static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)
{
struct fbnic_dev *fbd = data;
struct fbnic_net *fbn;
+ u64 link_down_event;
if (fbd->mac->get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) {
fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0),
@@ -129,11 +130,21 @@ static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)
return IRQ_HANDLED;
}
+ /* If the link is up this would be a loss event */
+ link_down_event = (fbd->pmd_state == FBNIC_PMD_SEND_DATA) ? 1 : 0;
+
fbn = netdev_priv(fbd->netdev);
/* Record link down events */
- if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec))
+ if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec)) {
+ /* Do not count link down events if the PCS has yet to
+ * acknowledge the link. This allows for the flushing out
+ * PCS errors generated during link training.
+ */
+ if (netif_carrier_ok(fbd->netdev))
+ fbn->link_down_events += link_down_event;
phylink_pcs_change(&fbn->phylink_pcs, false);
+ }
return IRQ_HANDLED;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index 27e4073d9898..592e9642a418 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -203,8 +203,6 @@ fbnic_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
struct fbnic_dev *fbd = fbn->fbd;
fbd->mac->link_down(fbd);
-
- fbn->link_down_events++;
}
static void
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 09/10] fbnic: Add SW shim for MDIO interface to PMA/PMD and PCS
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (7 preceding siblings ...)
2025-11-10 16:01 ` [net-next PATCH v3 08/10] fbnic: Cleanup handling for link down event statistics Alexander Duyck
@ 2025-11-10 16:02 ` Alexander Duyck
2025-11-10 16:02 ` [net-next PATCH v3 10/10] fbnic: Replace use of internal PCS w/ Designware XPCS Alexander Duyck
2025-11-11 14:23 ` [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Paolo Abeni
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:02 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
In order for us to support a phydev and PCS device we need to add an MDIO
bus to allow the drivers to have access to the registers for the device.
This change adds such an interface.
The interface will consist of 2 PHYs each consisting of a PMA/PMD and a PCS
located at addresses 0 and 1. There is a need for 2 PHYs due to the fact
that in order to support the 2 lane modes we will needed to access and
configure the PCS vendor registers and RSFEC registers from the second lane
identical to the first.
One side effect of this is that we have to report config values for both
lanes of the PHY as those registers can be poked and technically they would
be valid. For now I am going to have the second lane report speeds
equivalent to the given config for 2 lanes as we should be configuring both
lanes identical for the 2 lane modes.
The plan is in the future to extend out this interface adding RSFEC support
to the PMA through a remapping our CSRs which will essentially convert the
standard c45 offsets to ones matching the setup within our device.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/ethernet/meta/fbnic/Makefile | 1
drivers/net/ethernet/meta/fbnic/fbnic.h | 5 +
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 1
drivers/net/ethernet/meta/fbnic/fbnic_mdio.c | 190 ++++++++++++++++++++++++++
drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 3
5 files changed, 200 insertions(+)
create mode 100644 drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
diff --git a/drivers/net/ethernet/meta/fbnic/Makefile b/drivers/net/ethernet/meta/fbnic/Makefile
index 15e8ff649615..72c41af65364 100644
--- a/drivers/net/ethernet/meta/fbnic/Makefile
+++ b/drivers/net/ethernet/meta/fbnic/Makefile
@@ -21,6 +21,7 @@ fbnic-y := fbnic_csr.o \
fbnic_pci.o \
fbnic_phylink.o \
fbnic_rpc.o \
+ fbnic_mdio.o \
fbnic_time.o \
fbnic_tlv.o \
fbnic_txrx.o \
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index fac1283d0ade..779a083b9215 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -95,6 +95,9 @@ struct fbnic_dev {
u64 prev_firmware_time;
struct fbnic_fw_log fw_log;
+
+ /* MDIO bus for PHYs */
+ struct mii_bus *mdio_bus;
};
/* Reserve entry 0 in the MSI-X "others" array until we have filled all
@@ -204,6 +207,8 @@ void fbnic_dbg_exit(void);
void fbnic_rpc_reset_valid_entries(struct fbnic_dev *fbd);
+int fbnic_mdiobus_create(struct fbnic_dev *fbd);
+
void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version);
int fbnic_csr_regs_len(struct fbnic_dev *fbd);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
index 2b08046645f2..2a9440df5e1d 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
@@ -55,6 +55,7 @@ enum {
FBNIC_AUI_50GAUI1 = 2, /* 53.125GBd 53.125 * 1 */
FBNIC_AUI_100GAUI2 = 3, /* 106.25GBd 53.125 * 2 */
FBNIC_AUI_UNKNOWN = 4,
+ __FBNIC_AUI_MAX__
};
#define FBNIC_AUI_MODE_R2 (FBNIC_AUI_LAUI2)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
new file mode 100644
index 000000000000..7eeaeb03529b
--- /dev/null
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#include <linux/mdio.h>
+#include <linux/pcs/pcs-xpcs.h>
+
+#include "fbnic.h"
+#include "fbnic_netdev.h"
+
+#define DW_VENDOR BIT(15)
+#define FBNIC_PCS_VENDOR BIT(9)
+#define FBNIC_PCS_ZERO_MASK (DW_VENDOR - FBNIC_PCS_VENDOR)
+
+static int
+fbnic_mdio_read_pmapmd(struct fbnic_dev *fbd, int addr, int regnum)
+{
+ u16 ctrl1[__FBNIC_AUI_MAX__][2] = {
+ { MDIO_PMA_CTRL1_SPEED25G, MDIO_PMA_CTRL1_SPEED50G },
+ { MDIO_PMA_CTRL1_SPEED50G, MDIO_PMA_CTRL1_SPEED50G },
+ { MDIO_PMA_CTRL1_SPEED50G, MDIO_PMA_CTRL1_SPEED100G },
+ { MDIO_PMA_CTRL1_SPEED100G, MDIO_PMA_CTRL1_SPEED100G },
+ { 0, 0 }};
+ u8 aui = FBNIC_AUI_UNKNOWN;
+ struct fbnic_net *fbn;
+ int ret = 0;
+
+ if (fbd->netdev) {
+ fbn = netdev_priv(fbd->netdev);
+ if (fbn->aui < FBNIC_AUI_UNKNOWN)
+ aui = fbn->aui;
+ }
+
+ switch (regnum) {
+ case MDIO_CTRL1:
+ ret = ctrl1[aui][addr & 1];
+ break;
+ case MDIO_STAT1:
+ ret = (fbd->pmd_state == FBNIC_PMD_SEND_DATA) ?
+ MDIO_STAT1_LSTATUS : 0;
+ break;
+ case MDIO_DEVID1:
+ ret = MP_FBNIC_XPCS_PMA_100G_ID >> 16;
+ break;
+ case MDIO_DEVID2:
+ ret = MP_FBNIC_XPCS_PMA_100G_ID & 0xffff;
+ break;
+ case MDIO_DEVS1:
+ ret = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS;
+ break;
+ case MDIO_STAT2:
+ ret = MDIO_STAT2_DEVPRST_VAL;
+ break;
+ default:
+ break;
+ }
+
+ dev_dbg(fbd->dev,
+ "SWMII PMAPMD Rd: Addr: %d RegNum: %d Value: 0x%04x\n",
+ addr, regnum, ret);
+
+ return ret;
+}
+
+static int
+fbnic_mdio_read_pcs(struct fbnic_dev *fbd, int addr, int regnum)
+{
+ int ret;
+
+ /* Report 0 for reserved registers */
+ if (regnum & FBNIC_PCS_ZERO_MASK)
+ return 0;
+
+ /* Intercept and return correct ID for PCS */
+ if (regnum == MDIO_DEVID1)
+ return DW_XPCS_ID >> 16;
+ if (regnum == MDIO_DEVID2)
+ return DW_XPCS_ID & 0xffff;
+ if (regnum == MDIO_DEVS1)
+ return MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS;
+
+ /* Swap vendor page bit for FBNIC PCS vendor page bit */
+ if (regnum & DW_VENDOR)
+ regnum ^= DW_VENDOR | FBNIC_PCS_VENDOR;
+
+ ret = fbnic_rd32(fbd, FBNIC_PCS_PAGE(addr) + regnum);
+
+ dev_dbg(fbd->dev,
+ "SWMII PCS Rd: Addr: %d RegNum: %d Value: 0x%04x\n",
+ addr, regnum, ret);
+
+ return ret;
+}
+
+static int
+fbnic_mdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum)
+{
+ struct fbnic_dev *fbd = bus->priv;
+
+ if (addr & ~1)
+ return 0;
+
+ if (devnum == MDIO_MMD_PMAPMD)
+ return fbnic_mdio_read_pmapmd(fbd, addr, regnum);
+
+ if (devnum == MDIO_MMD_PCS)
+ return fbnic_mdio_read_pcs(fbd, addr, regnum);
+
+ return 0;
+}
+
+static void
+fbnic_mdio_write_pmapmd(struct fbnic_dev *fbd, int addr, int regnum, u16 val)
+{
+ dev_dbg(fbd->dev,
+ "SWMII PMAPMD Wr: Addr: %d RegNum: %d Value: 0x%04x\n",
+ addr, regnum, val);
+}
+
+static void
+fbnic_mdio_write_pcs(struct fbnic_dev *fbd, int addr, int regnum, u16 val)
+{
+ /* Skip write for reserved registers */
+ if (regnum & FBNIC_PCS_ZERO_MASK)
+ return;
+
+ /* Swap vendor page bit for FBNIC PCS vendor page bit */
+ if (regnum & DW_VENDOR)
+ regnum ^= DW_VENDOR | FBNIC_PCS_VENDOR;
+
+ fbnic_wr32(fbd, FBNIC_PCS_PAGE(addr) + regnum, val);
+
+ dev_dbg(fbd->dev,
+ "SWMII PCS Wr: Addr: %d RegNum: %d Value: 0x%04x\n",
+ addr, regnum, val);
+}
+
+static int
+fbnic_mdio_write_c45(struct mii_bus *bus, int addr, int devnum,
+ int regnum, u16 val)
+{
+ struct fbnic_dev *fbd = bus->priv;
+
+ if (addr & ~1)
+ return 0;
+
+ if (devnum == MDIO_MMD_PMAPMD)
+ fbnic_mdio_write_pmapmd(fbd, addr, regnum, val);
+
+ if (devnum == MDIO_MMD_PCS)
+ fbnic_mdio_write_pcs(fbd, addr, regnum, val);
+
+ return 0;
+}
+
+/**
+ * fbnic_mdiobus_create - Create an MDIO bus to allow interfacing w/ PHYs
+ * @fbd: Pointer to FBNIC device structure to populate bus on
+ *
+ * Initialize an MDIO bus and place a pointer to it on the fbd struct. This bus
+ * will be used to interface with the PMA/PMD and PCS.
+ *
+ * Return: 0 on success, negative on failure
+ **/
+int fbnic_mdiobus_create(struct fbnic_dev *fbd)
+{
+ struct mii_bus *bus;
+ int err;
+
+ bus = devm_mdiobus_alloc(fbd->dev);
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "fbnic_mii_bus";
+ bus->read_c45 = &fbnic_mdio_read_c45;
+ bus->write_c45 = &fbnic_mdio_write_c45;
+ bus->parent = fbd->dev;
+ bus->phy_mask = GENMASK(31, 2);
+ bus->priv = fbd;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(fbd->dev));
+
+ err = devm_mdiobus_register(fbd->dev, bus);
+ if (err) {
+ dev_err(fbd->dev, "Failed to create MDIO bus: %d\n", err);
+ return err;
+ }
+
+ fbd->mdio_bus = bus;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
index 040bd520b160..7991e2870081 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
@@ -339,6 +339,9 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto init_failure_mode;
}
+ if (fbnic_mdiobus_create(fbd))
+ goto init_failure_mode;
+
netdev = fbnic_netdev_alloc(fbd);
if (!netdev) {
dev_err(&pdev->dev, "Netdev allocation failed\n");
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [net-next PATCH v3 10/10] fbnic: Replace use of internal PCS w/ Designware XPCS
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (8 preceding siblings ...)
2025-11-10 16:02 ` [net-next PATCH v3 09/10] fbnic: Add SW shim for MDIO interface to PMA/PMD and PCS Alexander Duyck
@ 2025-11-10 16:02 ` Alexander Duyck
2025-11-11 14:23 ` [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Paolo Abeni
10 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-10 16:02 UTC (permalink / raw)
To: netdev; +Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
From: Alexander Duyck <alexanderduyck@fb.com>
As we have exposed the PCS registers via the SWMII we can now start looking
at connecting the XPCS driver to those registers and let it mange the PCS
instead of us doing it directly from the fbnic driver.
For now this just gets us the ability to detect link. The hop is in the
future to add some of the vendor specific registers to being enabling XPCS
configuration of the interface.
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
---
drivers/net/ethernet/meta/Kconfig | 1
drivers/net/ethernet/meta/fbnic/fbnic_irq.c | 2
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 7 --
drivers/net/ethernet/meta/fbnic/fbnic_netdev.h | 4 +
drivers/net/ethernet/meta/fbnic/fbnic_phylink.c | 104 +++++++++++------------
5 files changed, 55 insertions(+), 63 deletions(-)
diff --git a/drivers/net/ethernet/meta/Kconfig b/drivers/net/ethernet/meta/Kconfig
index dff51f23d295..ca5c7ac2a5bc 100644
--- a/drivers/net/ethernet/meta/Kconfig
+++ b/drivers/net/ethernet/meta/Kconfig
@@ -26,6 +26,7 @@ config FBNIC
depends on PTP_1588_CLOCK_OPTIONAL
select NET_DEVLINK
select PAGE_POOL
+ select PCS_XPCS
select PHYLINK
select PLDMFW
help
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
index 73dd10b7a1a8..f2ccb33fa67a 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_irq.c
@@ -143,7 +143,7 @@ static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)
*/
if (netif_carrier_ok(fbd->netdev))
fbn->link_down_events += link_down_event;
- phylink_pcs_change(&fbn->phylink_pcs, false);
+ phylink_pcs_change(fbn->pcs, false);
}
return IRQ_HANDLED;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index 65318a5b466e..81c9d5c9a4b2 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -697,10 +697,7 @@ void fbnic_reset_queues(struct fbnic_net *fbn,
**/
void fbnic_netdev_free(struct fbnic_dev *fbd)
{
- struct fbnic_net *fbn = netdev_priv(fbd->netdev);
-
- if (fbn->phylink)
- phylink_destroy(fbn->phylink);
+ fbnic_phylink_destroy(fbd->netdev);
free_netdev(fbd->netdev);
fbd->netdev = NULL;
@@ -802,7 +799,7 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
netif_tx_stop_all_queues(netdev);
- if (fbnic_phylink_init(netdev)) {
+ if (fbnic_phylink_create(netdev)) {
fbnic_netdev_free(fbd);
return NULL;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
index c2e45ff64e34..54a8bf172fa6 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
@@ -44,7 +44,7 @@ struct fbnic_net {
struct phylink *phylink;
struct phylink_config phylink_config;
- struct phylink_pcs phylink_pcs;
+ struct phylink_pcs *pcs;
u8 aui;
u8 fec;
@@ -106,6 +106,8 @@ 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_create(struct net_device *netdev);
+void fbnic_phylink_destroy(struct net_device *netdev);
int fbnic_phylink_init(struct net_device *netdev);
void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev);
bool fbnic_check_split_frames(struct bpf_prog *prog,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index 592e9642a418..188155f43416 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+#include <linux/pcs/pcs-xpcs.h>
#include <linux/phy.h>
#include <linux/phylink.h>
@@ -101,56 +102,6 @@ int fbnic_phylink_get_fecparam(struct net_device *netdev,
return 0;
}
-static struct fbnic_net *
-fbnic_pcs_to_net(struct phylink_pcs *pcs)
-{
- return container_of(pcs, struct fbnic_net, phylink_pcs);
-}
-
-static void
-fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
- struct phylink_link_state *state)
-{
- struct fbnic_net *fbn = fbnic_pcs_to_net(pcs);
- struct fbnic_dev *fbd = fbn->fbd;
-
- switch (fbn->aui) {
- case FBNIC_AUI_25GAUI:
- state->speed = SPEED_25000;
- break;
- case FBNIC_AUI_LAUI2:
- case FBNIC_AUI_50GAUI1:
- state->speed = SPEED_50000;
- break;
- case FBNIC_AUI_100GAUI2:
- state->speed = SPEED_100000;
- break;
- default:
- state->link = 0;
- return;
- }
-
- state->duplex = DUPLEX_FULL;
-
- state->link = (fbd->pmd_state == FBNIC_PMD_SEND_DATA) &&
- (rd32(fbd, FBNIC_PCS(MDIO_STAT1, 0)) &
- MDIO_STAT1_LSTATUS);
-}
-
-static int
-fbnic_phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
- phy_interface_t interface,
- const unsigned long *advertising,
- bool permit_pause_to_mac)
-{
- return 0;
-}
-
-static const struct phylink_pcs_ops fbnic_phylink_pcs_ops = {
- .pcs_config = fbnic_phylink_pcs_config,
- .pcs_get_state = fbnic_phylink_pcs_get_state,
-};
-
static struct phylink_pcs *
fbnic_phylink_mac_select_pcs(struct phylink_config *config,
phy_interface_t interface)
@@ -158,7 +109,7 @@ fbnic_phylink_mac_select_pcs(struct phylink_config *config,
struct net_device *netdev = to_net_dev(config->dev);
struct fbnic_net *fbn = netdev_priv(netdev);
- return &fbn->phylink_pcs;
+ return fbn->pcs;
}
static int
@@ -227,13 +178,33 @@ static const struct phylink_mac_ops fbnic_phylink_mac_ops = {
.mac_link_up = fbnic_phylink_mac_link_up,
};
-int fbnic_phylink_init(struct net_device *netdev)
+/**
+ * fbnic_phylink_create - Phylink device creation
+ * @netdev: Network Device struct to attach phylink device
+ *
+ * Initialize and attach a phylink instance to the device. The phylink
+ * device will make use of the netdev struct to track carrier and will
+ * eventually be used to expose the current state of the MAC and PCS
+ * setup.
+ *
+ * Return: 0 on success, negative on failure
+ **/
+int fbnic_phylink_create(struct net_device *netdev)
{
struct fbnic_net *fbn = netdev_priv(netdev);
struct fbnic_dev *fbd = fbn->fbd;
+ struct phylink_pcs *pcs;
struct phylink *phylink;
+ int err;
+
+ pcs = xpcs_create_pcs_mdiodev(fbd->mdio_bus, 0);
+ if (IS_ERR(pcs)) {
+ err = PTR_ERR(pcs);
+ dev_err(fbd->dev, "Failed to create PCS device: %d\n", err);
+ return err;
+ }
- fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops;
+ fbn->pcs = pcs;
fbn->phylink_config.dev = &netdev->dev;
fbn->phylink_config.type = PHYLINK_NETDEV;
@@ -256,14 +227,35 @@ int fbnic_phylink_init(struct net_device *netdev)
phylink = phylink_create(&fbn->phylink_config, NULL,
fbnic_phylink_select_interface(fbn->aui),
&fbnic_phylink_mac_ops);
- if (IS_ERR(phylink))
- return PTR_ERR(phylink);
+ if (IS_ERR(phylink)) {
+ err = PTR_ERR(phylink);
+ dev_err(netdev->dev.parent,
+ "Failed to create Phylink interface, err: %d\n", err);
+ xpcs_destroy_pcs(pcs);
+ return err;
+ }
fbn->phylink = phylink;
return 0;
}
+/**
+ * fbnic_phylink_destroy - Teardown phylink related interfaces
+ * @netdev: Network Device struct containing phylink device
+ *
+ * Detach and free resources related to phylink interface.
+ **/
+void fbnic_phylink_destroy(struct net_device *netdev)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+
+ if (fbn->phylink)
+ phylink_destroy(fbn->phylink);
+ if (fbn->pcs)
+ xpcs_destroy_pcs(fbn->pcs);
+}
+
/**
* fbnic_phylink_pmd_training_complete_notify - PMD training complete notifier
* @netdev: Netdev struct phylink device attached to
@@ -287,5 +279,5 @@ void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev)
fbd->pmd_state = FBNIC_PMD_SEND_DATA;
- phylink_pcs_change(&fbn->phylink_pcs, false);
+ phylink_pcs_change(fbn->pcs, false);
}
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
` (9 preceding siblings ...)
2025-11-10 16:02 ` [net-next PATCH v3 10/10] fbnic: Replace use of internal PCS w/ Designware XPCS Alexander Duyck
@ 2025-11-11 14:23 ` Paolo Abeni
2025-11-11 15:23 ` Jakub Kicinski
10 siblings, 1 reply; 17+ messages in thread
From: Paolo Abeni @ 2025-11-11 14:23 UTC (permalink / raw)
To: Alexander Duyck, kuba
Cc: kernel-team, andrew+netdev, hkallweit1, linux, davem, netdev
Hi,
On 11/10/25 5:00 PM, Alexander Duyck wrote:
> To transition the fbnic driver to using the XPCS driver we need to address
> the fact that we need a representation for the FW managed PMA/PMD that is
> actually a SerDes PHY to handle link bouncing during link training.
>
> This patch set first introduces the necessary bits to the
> generic c45 driver code to enable it to read 25G, 50G, and 100G modes from
> the PHY. After that we update the XPCS driver to to do the same.
>
> The rest of this patch set enables the changes to fbnic to make use of these
> interfaces and expose a PMA/PMD that can provide a necessary link delay to
> avoid link flapping in the event that a cable is disconnected and
> reconnected, and to correctly provide the count for the link down events.
>
> With this we have the basic groundwork laid as with this all the bits and
> pieces are in place in terms of reading the configuration. The general plan for
> follow-on patch sets is to start looking at enabling changing the configuration
> in environments where that is supported.
>
> v2: Added XPCS code to the patch set
> Dropped code adding bits for extended ability registers
> Switched from enabling code in generic c45 to enabling code in fbnic_phy.c
> Fixed several bugs related to phy state machine and use of resume
> Moved PHY assignment into ndo_init/uninit
> Renamed fbnic_swmii.c to fbnic_mdio.c
> v3: Modified XPCS to have it read link from PMA instead of using a phydev
> Fixed naming for PCS vs PMA for CTRL1 register speed bit values
> Added logic to XPCS to get speed from PCS CTRL1 register
> Swapped fbnic link delay timer from tracking training start to end
> Dropped driver code for fbnic_phy.c and phydev code from patches
> Updated patch naming to match expectations for PCS changes
> Cleaned up dead code and defines from earlier versions
Not a real review, but on top of this series our CI reports most/all
fbnic H/W test failing with something alike:
Traceback (most recent call last):
File
"/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/./xdp.py",
line 810, in <module>
main()
File
"/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/./xdp.py",
line 786, in main
with NetDrvEpEnv(__file__) as cfg:
File
"/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/lib/py/env.py",
line 59, in __enter__
wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier",
File
"/home/virtme/testing/wt-25/tools/testing/selftests/net/lib/py/utils.py",
line 273, in wait_file
raise TimeoutError("Wait for file contents failed", fname)
TimeoutError: [Errno Wait for file contents failed]
/sys/class/net/enp1s0/carrier
not ok 1 selftests: drivers/net: xdp.py # exit=1
even if I wild guess the root cause is the removal from the nipa tree of
"nipa: fbnic: link up on QEMU" (which IIRC is a local patch from Jakub
to make the tests happy with the nipa setup).
/P
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support
2025-11-11 14:23 ` [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Paolo Abeni
@ 2025-11-11 15:23 ` Jakub Kicinski
2025-11-11 16:09 ` Alexander Duyck
0 siblings, 1 reply; 17+ messages in thread
From: Jakub Kicinski @ 2025-11-11 15:23 UTC (permalink / raw)
To: Paolo Abeni
Cc: Alexander Duyck, kernel-team, andrew+netdev, hkallweit1, linux,
davem, netdev
On Tue, 11 Nov 2025 15:23:21 +0100 Paolo Abeni wrote:
> Traceback (most recent call last):
> File
> "/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/./xdp.py",
> line 810, in <module>
> main()
> File
> "/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/./xdp.py",
> line 786, in main
> with NetDrvEpEnv(__file__) as cfg:
> File
> "/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/lib/py/env.py",
> line 59, in __enter__
> wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier",
> File
> "/home/virtme/testing/wt-25/tools/testing/selftests/net/lib/py/utils.py",
> line 273, in wait_file
> raise TimeoutError("Wait for file contents failed", fname)
> TimeoutError: [Errno Wait for file contents failed]
> /sys/class/net/enp1s0/carrier
> not ok 1 selftests: drivers/net: xdp.py # exit=1
>
> even if I wild guess the root cause is the removal from the nipa tree of
> "nipa: fbnic: link up on QEMU" (which IIRC is a local patch from Jakub
> to make the tests happy with the nipa setup).
Yes, let me queue up a version of that patch which applies on top of
Alex's series. QEMU does not seem to get link up. I need to get around
to updating the build at some point..
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support
2025-11-11 15:23 ` Jakub Kicinski
@ 2025-11-11 16:09 ` Alexander Duyck
0 siblings, 0 replies; 17+ messages in thread
From: Alexander Duyck @ 2025-11-11 16:09 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Paolo Abeni, kernel-team, andrew+netdev, hkallweit1, linux, davem,
netdev
On Tue, Nov 11, 2025 at 7:23 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Tue, 11 Nov 2025 15:23:21 +0100 Paolo Abeni wrote:
> > Traceback (most recent call last):
> > File
> > "/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/./xdp.py",
> > line 810, in <module>
> > main()
> > File
> > "/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/./xdp.py",
> > line 786, in main
> > with NetDrvEpEnv(__file__) as cfg:
> > File
> > "/home/virtme/testing/wt-25/tools/testing/selftests/drivers/net/lib/py/env.py",
> > line 59, in __enter__
> > wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier",
> > File
> > "/home/virtme/testing/wt-25/tools/testing/selftests/net/lib/py/utils.py",
> > line 273, in wait_file
> > raise TimeoutError("Wait for file contents failed", fname)
> > TimeoutError: [Errno Wait for file contents failed]
> > /sys/class/net/enp1s0/carrier
> > not ok 1 selftests: drivers/net: xdp.py # exit=1
> >
> > even if I wild guess the root cause is the removal from the nipa tree of
> > "nipa: fbnic: link up on QEMU" (which IIRC is a local patch from Jakub
> > to make the tests happy with the nipa setup).
>
> Yes, let me queue up a version of that patch which applies on top of
> Alex's series. QEMU does not seem to get link up. I need to get around
> to updating the build at some point..
Yeah, the old QEMU is missing the pieces for the PCS needed to handle
the XPCS driver. I have had to make a few updates to get the XPCS
driver working with QEMU. Specifically the old QEMU doesn't report
link via the MDIO_STAT1 register, and the BaseR register was reporting
~0 which was treated as errors triggering reset.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values
2025-11-10 16:01 ` [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values Alexander Duyck
@ 2025-11-12 8:53 ` Maxime Chevallier
2025-11-12 10:42 ` Russell King (Oracle)
1 sibling, 0 replies; 17+ messages in thread
From: Maxime Chevallier @ 2025-11-12 8:53 UTC (permalink / raw)
To: Alexander Duyck, netdev
Cc: kuba, kernel-team, andrew+netdev, hkallweit1, linux, pabeni,
davem
Hi Alexander,
On 10/11/2025 17:01, Alexander Duyck wrote:
> From: Alexander Duyck <alexanderduyck@fb.com>
>
> The 2.5G and 5G values are not consistent between the PCS CTRL1 and PMA
> CTRL1 values. In order to avoid confusion between the two I am updating the
> values to include "PMA" in the name similar to values used in similar
> places.
>
> Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
> ---
> drivers/net/phy/phy-c45.c | 8 ++++----
> include/uapi/linux/mdio.h | 4 ++--
> 2 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
> index 1d747fbaa10c..d161fe3fee75 100644
> --- a/drivers/net/phy/phy-c45.c
> +++ b/drivers/net/phy/phy-c45.c
> @@ -148,12 +148,12 @@ int genphy_c45_pma_setup_forced(struct phy_device *phydev)
> ctrl2 |= MDIO_PMA_CTRL2_1000BT;
> break;
> case SPEED_2500:
> - ctrl1 |= MDIO_CTRL1_SPEED2_5G;
> + ctrl1 |= MDIO_PMA_CTRL1_SPEED2_5G;
> /* Assume 2.5Gbase-T */
> ctrl2 |= MDIO_PMA_CTRL2_2_5GBT;
> break;
> case SPEED_5000:
> - ctrl1 |= MDIO_CTRL1_SPEED5G;
> + ctrl1 |= MDIO_PMA_CTRL1_SPEED5G;
> /* Assume 5Gbase-T */
> ctrl2 |= MDIO_PMA_CTRL2_5GBT;
> break;
> @@ -618,10 +618,10 @@ int genphy_c45_read_pma(struct phy_device *phydev)
> case MDIO_PMA_CTRL1_SPEED1000:
> phydev->speed = SPEED_1000;
> break;
> - case MDIO_CTRL1_SPEED2_5G:
> + case MDIO_PMA_CTRL1_SPEED2_5G:
> phydev->speed = SPEED_2500;
> break;
> - case MDIO_CTRL1_SPEED5G:
> + case MDIO_PMA_CTRL1_SPEED5G:
> phydev->speed = SPEED_5000;
> break;
> case MDIO_CTRL1_SPEED10G:
> diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
> index 75ed41fc46c6..c33aa864ef66 100644
> --- a/include/uapi/linux/mdio.h
> +++ b/include/uapi/linux/mdio.h
> @@ -123,9 +123,9 @@
> /* 50 Gb/s */
> #define MDIO_PMA_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x14)
> /* 2.5 Gb/s */
> -#define MDIO_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
> +#define MDIO_PMA_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18)
> /* 5 Gb/s */
> -#define MDIO_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c)
> +#define MDIO_PMA_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c)
>
> /* Status register 1. */
> #define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */
This is UAPI, I guess it's too late to rename that :(
Maxime
>
>
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values
2025-11-10 16:01 ` [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values Alexander Duyck
2025-11-12 8:53 ` Maxime Chevallier
@ 2025-11-12 10:42 ` Russell King (Oracle)
2025-11-12 16:32 ` Alexander H Duyck
1 sibling, 1 reply; 17+ messages in thread
From: Russell King (Oracle) @ 2025-11-12 10:42 UTC (permalink / raw)
To: Alexander Duyck
Cc: netdev, kuba, kernel-team, andrew+netdev, hkallweit1, pabeni,
davem
On Mon, Nov 10, 2025 at 08:01:10AM -0800, Alexander Duyck wrote:
> From: Alexander Duyck <alexanderduyck@fb.com>
>
> The 2.5G and 5G values are not consistent between the PCS CTRL1 and PMA
> CTRL1 values. In order to avoid confusion between the two I am updating the
> values to include "PMA" in the name similar to values used in similar
> places.
As this us UAPI, please _add_ new values with _PCS_ and _PMA_ infixes
rather than renaming existing definitionsi.
Thanks.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values
2025-11-12 10:42 ` Russell King (Oracle)
@ 2025-11-12 16:32 ` Alexander H Duyck
0 siblings, 0 replies; 17+ messages in thread
From: Alexander H Duyck @ 2025-11-12 16:32 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, kuba, kernel-team, andrew+netdev, hkallweit1, pabeni,
davem
On Wed, 2025-11-12 at 10:42 +0000, Russell King (Oracle) wrote:
> On Mon, Nov 10, 2025 at 08:01:10AM -0800, Alexander Duyck wrote:
> > From: Alexander Duyck <alexanderduyck@fb.com>
> >
> > The 2.5G and 5G values are not consistent between the PCS CTRL1 and PMA
> > CTRL1 values. In order to avoid confusion between the two I am updating the
> > values to include "PMA" in the name similar to values used in similar
> > places.
>
> As this us UAPI, please _add_ new values with _PCS_ and _PMA_ infixes
> rather than renaming existing definitionsi.
>
> Thanks.
Sorry about that. I had overlooked that this was UAPI.
Would something like the following add-on work, or would you prefer I
just don't touch the existing defines?
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index 75ed41fc46c6..e80bcad1b278 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -116,6 +116,14 @@
#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00)
/* 10PASS-TS/2BASE-TL */
#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04)
+/* The MDIO_CTRL1_SPEED_XXX values for everything past 10PASS-TS/2BASE-TL do
+ * not match between the PCS and PMA values. For this reason any additions past
+ * this point should be PMA or PCS specific. The following 2 defines are
+ * workarounds for values added before this was caught. They should be
+ * considered deprecated.
+ */
+#define MDIO_CTRL1_SPEED2_5G MDIO_PMA_CTRL1_SPEED2_5G
+#define MDIO_CTRL1_SPEED5G MDIO_PMA_CTRL1_SPEED5G
/* 100 Gb/s */
#define MDIO_PMA_CTRL1_SPEED100G (MDIO_CTRL1_SPEEDSELEXT | 0x0c)
/* 25 Gb/s */
^ permalink raw reply related [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-11-12 16:32 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-10 16:00 [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Alexander Duyck
2025-11-10 16:00 ` [net-next PATCH v3 01/10] net: phy: Add support for 25, 50 and 100Gbps PMA to genphy_c45_read_pma Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 02/10] net: phy: Rename MDIO_CTRL1_SPEED for 2.5G and 5G to reflect PMA values Alexander Duyck
2025-11-12 8:53 ` Maxime Chevallier
2025-11-12 10:42 ` Russell King (Oracle)
2025-11-12 16:32 ` Alexander H Duyck
2025-11-10 16:01 ` [net-next PATCH v3 03/10] net: pcs: xpcs: Add support for 25G, 50G, and 100G interfaces Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 04/10] net: pcs: xpcs: Fix PMA identifier handling in XPCS Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 05/10] net: pcs: xpcs: Add support for FBNIC 25G, 50G, 100G PMA Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 06/10] fbnic: Rename PCS IRQ to MAC IRQ as it is actually a MAC interrupt Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 07/10] fbnic: Add logic to track PMD state via MAC/PCS signals Alexander Duyck
2025-11-10 16:01 ` [net-next PATCH v3 08/10] fbnic: Cleanup handling for link down event statistics Alexander Duyck
2025-11-10 16:02 ` [net-next PATCH v3 09/10] fbnic: Add SW shim for MDIO interface to PMA/PMD and PCS Alexander Duyck
2025-11-10 16:02 ` [net-next PATCH v3 10/10] fbnic: Replace use of internal PCS w/ Designware XPCS Alexander Duyck
2025-11-11 14:23 ` [net-next PATCH v3 00/10] net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support Paolo Abeni
2025-11-11 15:23 ` Jakub Kicinski
2025-11-11 16:09 ` Alexander Duyck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).