Merge branch 'first-series-for-xpcs-based-rsfec-configuration'

Mike Marciniszyn says:

====================
first series for xpcs based rsfec configuration

The series:
- Fixes an addr validation error
- Adds MDIO defines associated with RS-FEC
- consolidates the handling of the boilerplat ID registers
  into a routine to report id'ish registers and reduces the lines
  of code across the entire set of c45 routines.
- adds PMA read/write routines

https://lore.kernel.org/all/20260428172810.175077-2-mike.marciniszyn@gmail.com/
has been removed from the series and submitted to net as
https://lore.kernel.org/all/20260429150049.1643-1-mike.marciniszyn@gmail.com/

pcs reads for DEVS1 and DEVS2 cleaned up 2/3
====================

Link: https://patch.msgid.link/20260430150802.3521-1-mike.marciniszyn@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-05-05 14:40:40 +02:00
commit 8c699be3da
3 changed files with 122 additions and 24 deletions

View File

@ -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

View File

@ -7,10 +7,49 @@
#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)
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 +68,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 +78,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 +92,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 +103,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",
@ -95,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)
{
@ -106,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;
}
@ -139,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)
@ -151,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;
}

View File

@ -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)