From ca283942e5b91894d3a9228eaf789837f66c986f Mon Sep 17 00:00:00 2001 From: "Mike Marciniszyn (Meta)" Date: Thu, 30 Apr 2026 11:08:00 -0400 Subject: [PATCH 1/3] net: mdio: Add support for RSFEC Control register for PMA Add the constants associated with RS-FEC configuration and status as well as the indicated separated bits for DEVS1 to convey a separated PMA. Reviewed-by: Andrew Lunn Signed-off-by: Mike Marciniszyn (Meta) Link: https://patch.msgid.link/20260430150802.3521-2-mike.marciniszyn@gmail.com Signed-off-by: Paolo Abeni --- include/uapi/linux/mdio.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index 8d769f100de6..b2541c948fc1 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -23,6 +23,10 @@ #define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */ #define MDIO_MMD_TC 6 /* Transmission Convergence */ #define MDIO_MMD_AN 7 /* Auto-Negotiation */ +#define MDIO_MMD_SEP_PMA1 8 /* Separated PMA (1) */ +#define MDIO_MMD_SEP_PMA2 9 /* Separated PMA (2) */ +#define MDIO_MMD_SEP_PMA3 10 /* Separated PMA (3) */ +#define MDIO_MMD_SEP_PMA4 11 /* Separated PMA (4) */ #define MDIO_MMD_POWER_UNIT 13 /* PHY Power Unit */ #define MDIO_MMD_C22EXT 29 /* Clause 22 extension */ #define MDIO_MMD_VEND1 30 /* Vendor specific 1 */ @@ -63,6 +67,8 @@ * Lanes B-D are numbered 134-136. */ #define MDIO_PMA_10GBR_FSRT_CSR 147 /* 10GBASE-R fast retrain status and control */ #define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */ +#define MDIO_PMA_RSFEC_CTRL 200 /* RSFEC control */ +#define MDIO_PMA_RSFEC_LANE_MAP 206 /* RSFEC lane mapping */ #define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */ #define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */ #define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */ @@ -175,6 +181,10 @@ #define MDIO_DEVS_DTEXS MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS) #define MDIO_DEVS_TC MDIO_DEVS_PRESENT(MDIO_MMD_TC) #define MDIO_DEVS_AN MDIO_DEVS_PRESENT(MDIO_MMD_AN) +#define MDIO_DEVS_SEP_PMA1 MDIO_DEVS_PRESENT(MDIO_MMD_SEP_PMA1) +#define MDIO_DEVS_SEP_PMA2 MDIO_DEVS_PRESENT(MDIO_MMD_SEP_PMA2) +#define MDIO_DEVS_SEP_PMA3 MDIO_DEVS_PRESENT(MDIO_MMD_SEP_PMA3) +#define MDIO_DEVS_SEP_PMA4 MDIO_DEVS_PRESENT(MDIO_MMD_SEP_PMA4) #define MDIO_DEVS_C22EXT MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT) #define MDIO_DEVS_VEND1 MDIO_DEVS_PRESENT(MDIO_MMD_VEND1) #define MDIO_DEVS_VEND2 MDIO_DEVS_PRESENT(MDIO_MMD_VEND2) From d7dbf00b4a5503def75487ed803698042ba1965d Mon Sep 17 00:00:00 2001 From: "Mike Marciniszyn (Meta)" Date: Thu, 30 Apr 2026 11:08:01 -0400 Subject: [PATCH 2/3] net: eth: fbnic: Consolidate register reads for ids and devs Consolidate the register reads for boiler plate registers to reduce LOC and cleanup pcs reads for DEVS1 to fetch overrides for reserved bits that the hardware does not return. Signed-off-by: Mike Marciniszyn (Meta) Link: https://patch.msgid.link/20260430150802.3521-3-mike.marciniszyn@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_mdio.c | 64 ++++++++++++-------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c index 709041f7fc43..a3a072597a2c 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c @@ -11,6 +11,26 @@ #define FBNIC_PCS_VENDOR BIT(9) #define FBNIC_PCS_ZERO_MASK (DW_VENDOR - FBNIC_PCS_VENDOR) +static int +fbnic_mdio_ids(int id, int regnum) +{ + /* return correct IDs */ + switch (regnum) { + case MDIO_DEVID1: + return id >> 16; + case MDIO_DEVID2: + return id & 0xffff; + case MDIO_DEVS1: + return MDIO_DEVS_SEP_PMA1 | MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS; + case MDIO_DEVS2: + return 0; + case MDIO_STAT2: + return MDIO_STAT2_DEVPRST_VAL; + } + + return 0; +} + static int fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum) { @@ -29,18 +49,6 @@ fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum) } switch (regnum) { - 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; case MDIO_PMA_RXDET: /* If training isn't complete default to 0 */ if (fbd->pmd_state != FBNIC_PMD_SEND_DATA) @@ -51,6 +59,7 @@ fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum) (MDIO_PMD_RXDET_1 / FBNIC_AUI_MODE_R2)); break; default: + ret = fbnic_mdio_ids(MP_FBNIC_XPCS_PMA_100G_ID, regnum); break; } @@ -64,7 +73,7 @@ fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum) static int fbnic_mdio_read_pcs(struct fbnic_dev *fbd, int addr, int regnum) { - int ret, offset = 0; + int ret, offset = 0, overrides = 0; /* We will need access to both PCS instances to get config info */ if (addr >= 2) @@ -75,18 +84,25 @@ fbnic_mdio_read_pcs(struct fbnic_dev *fbd, int addr, int regnum) 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; + switch (regnum) { + case MDIO_DEVID1 ... MDIO_DEVID2: + ret = fbnic_mdio_ids(DW_XPCS_ID, regnum); + break; + case MDIO_DEVS1: + /* DW IP returns MDIO_DEVS_SEP_PMA1, MDIO_DEVS_PMAPMD, + * and MDIO_DEVS_PCS as 0 + */ + overrides = fbnic_mdio_ids(DW_XPCS_ID, regnum); + fallthrough; + default: + /* Swap vendor page bit for FBNIC PCS vendor page bit */ + if (regnum & DW_VENDOR) + offset ^= DW_VENDOR | FBNIC_PCS_VENDOR; - /* Swap vendor page bit for FBNIC PCS vendor page bit */ - if (regnum & DW_VENDOR) - offset ^= DW_VENDOR | FBNIC_PCS_VENDOR; - - ret = fbnic_rd32(fbd, FBNIC_PCS_PAGE(addr) + (regnum ^ offset)); + ret = fbnic_rd32(fbd, FBNIC_PCS_PAGE(addr) + (regnum ^ offset)); + ret |= overrides; + break; + } dev_dbg(fbd->dev, "SWMII PCS Rd: Addr: %d RegNum: %d Value: 0x%04x\n", From 3877097c3c9e0356ad5ed8411f417a100090be9c Mon Sep 17 00:00:00 2001 From: "Mike Marciniszyn (Meta)" Date: Thu, 30 Apr 2026 11:08:02 -0400 Subject: [PATCH 3/3] net: eth: fbnic: Add pma read and write access Document the MDIO interface topology with an ASCII diagram showing the MAC, PCS (MMD 3), FEC, Separated PMA (MMD 8), and PMD (MMD 1) blocks and their interconnects. The diagram illustrates how 4 lanes connect the MAC through PCS, FEC, and PMA, then narrow to 2 lanes at the PMD. The c45 read and write routines are enhanced to support read and write of the separated PMA for the fbnic. Co-developed-by: Alexander Duyck Signed-off-by: Alexander Duyck Signed-off-by: Mike Marciniszyn (Meta) Link: https://patch.msgid.link/20260430150802.3521-4-mike.marciniszyn@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 1 + drivers/net/ethernet/meta/fbnic/fbnic_mdio.c | 71 ++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h index 81794bd326e1..64b958df7774 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h @@ -805,6 +805,7 @@ enum { #define FBNIC_CSR_END_PCS 0x10668 /* CSR section delimiter */ #define FBNIC_CSR_START_RSFEC 0x10800 /* CSR section delimiter */ +#define FBNIC_RSFEC_CONTROL(n) (0x10800 + 8 * (n)) /* 0x42000 + 32*n */ /* We have 4 RSFEC engines present in our part, however we are only using 1. * As such only CCW(0) and NCCW(0) will never be non-zero and the other diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c index a3a072597a2c..7a8727e8f6f2 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c @@ -7,6 +7,25 @@ #include "fbnic.h" #include "fbnic_netdev.h" +/* fbnic MDIO Interface Layout + * + * +-------------------+ + * | MAC | + * +-------------------+ + * | | | | <-- 25GMII, 50GMII, or CGMII + * +-------------------+ + * MMD 3 | PCS | + * +-------------------+ + * | FEC | + * +-------------------+ + * MMD 8 | Separated PMA | + * +-------------------+ + * | | <-- PMD Service Interface + * +-------------------+ + * MMD 1 | PMD | + * +-------------------+ + */ + #define DW_VENDOR BIT(15) #define FBNIC_PCS_VENDOR BIT(9) #define FBNIC_PCS_ZERO_MASK (DW_VENDOR - FBNIC_PCS_VENDOR) @@ -111,6 +130,32 @@ fbnic_mdio_read_pcs(struct fbnic_dev *fbd, int addr, int regnum) return ret; } +static int +fbnic_mdio_read_pma(struct fbnic_dev *fbd, int addr, int regnum) +{ + int ret = 0; + + /* We will need access to both PMA instances to get config info */ + if (addr >= 2) + return 0; + + switch (regnum) { + case MDIO_PMA_RSFEC_CTRL ... MDIO_PMA_RSFEC_LANE_MAP: + ret = fbnic_rd32(fbd, FBNIC_RSFEC_CONTROL(addr) + + regnum - MDIO_PMA_RSFEC_CTRL); + break; + default: + ret = fbnic_mdio_ids(MP_FBNIC_XPCS_PMA_100G_ID, regnum); + break; + } + + dev_dbg(fbd->dev, + "SWMII PMA 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) { @@ -122,6 +167,9 @@ fbnic_mdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum) if (devnum == MDIO_MMD_PCS) return fbnic_mdio_read_pcs(fbd, addr, regnum); + if (devnum == MDIO_MMD_SEP_PMA1) + return fbnic_mdio_read_pma(fbd, addr, regnum); + return 0; } @@ -155,6 +203,26 @@ fbnic_mdio_write_pcs(struct fbnic_dev *fbd, int addr, int regnum, u16 val) fbnic_wr32(fbd, FBNIC_PCS_PAGE(addr) + regnum, val); } +static void +fbnic_mdio_write_pma(struct fbnic_dev *fbd, int addr, int regnum, u16 val) +{ + dev_dbg(fbd->dev, + "SWMII PMA Wr: Addr: %d RegNum: %d Value: 0x%04x\n", + addr, regnum, val); + + if (addr >= 2) + return; + + switch (regnum) { + case MDIO_PMA_RSFEC_CTRL ... MDIO_PMA_RSFEC_LANE_MAP: + fbnic_wr32(fbd, FBNIC_RSFEC_CONTROL(addr) + + regnum - MDIO_PMA_RSFEC_CTRL, val); + break; + default: + break; + } +} + static int fbnic_mdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val) @@ -167,6 +235,9 @@ fbnic_mdio_write_c45(struct mii_bus *bus, int addr, int devnum, if (devnum == MDIO_MMD_PCS) fbnic_mdio_write_pcs(fbd, addr, regnum, val); + if (devnum == MDIO_MMD_SEP_PMA1) + fbnic_mdio_write_pma(fbd, addr, regnum, val); + return 0; }