Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/2] second series for xpcs based rsfec configuration
@ 2026-05-11 18:26 mike.marciniszyn
  2026-05-11 18:26 ` [PATCH net-next v2 1/2] net: pcs: xpcs: Add hooks for xpcs configuration of rsfec mike.marciniszyn
  2026-05-11 18:26 ` [PATCH net-next v2 2/2] net: pcs: xpcs: Add handling for 4 channel rsfec device mike.marciniszyn
  0 siblings, 2 replies; 5+ messages in thread
From: mike.marciniszyn @ 2026-05-11 18:26 UTC (permalink / raw)
  To: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
	David S. Miller, Eric Dumazet, Paolo Abeni, Heiner Kallweit,
	Russell King, Kees Cook, Andrew Lunn
  Cc: mike.marciniszyn, netdev, linux-kernel

From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>

This series adds to xxxx to add the necessary configuration steps
for the DW PCS/refec part of high speed interfaces.

v2 removes any use of a hardcoded address by using new helpers all
based on phy_find*.

The changes now probe for addr 0 and addr 1 to allow the helpers
to function properly.

Mike Marciniszyn (Meta) (2):
  net: pcs: xpcs: Add hooks for xpcs configuration of rsfec
  net: pcs: xpcs: Add handling for 4 channel rsfec device

 drivers/net/ethernet/meta/fbnic/fbnic_mdio.c |   3 +-
 drivers/net/pcs/pcs-xpcs.c                   | 194 +++++++++++++++++++
 drivers/net/pcs/pcs-xpcs.h                   |  31 +++
 include/uapi/linux/mdio.h                    |   3 +
 4 files changed, 229 insertions(+), 2 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 1/2] net: pcs: xpcs: Add hooks for xpcs configuration of rsfec
  2026-05-11 18:26 [PATCH net-next v2 0/2] second series for xpcs based rsfec configuration mike.marciniszyn
@ 2026-05-11 18:26 ` mike.marciniszyn
  2026-05-15 16:52   ` Alexander H Duyck
  2026-05-11 18:26 ` [PATCH net-next v2 2/2] net: pcs: xpcs: Add handling for 4 channel rsfec device mike.marciniszyn
  1 sibling, 1 reply; 5+ messages in thread
From: mike.marciniszyn @ 2026-05-11 18:26 UTC (permalink / raw)
  To: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
	David S. Miller, Eric Dumazet, Paolo Abeni, Heiner Kallweit,
	Russell King, Kees Cook, Andrew Lunn
  Cc: mike.marciniszyn, netdev, linux-kernel

From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>

The DW PCS IP data sheet calls out the need to populate
these vendor registers when operating at speeds above 10Gbps.
This change enables the correct FEC settings to enable RS-FEC
encoding on the link which is the standard used for most links
at these higher speeds.

Note that the overwriting of the MDIO_PMA_RSFEC_CTRL register
is intentional and consistent DW PCS IP requirements.

Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
---
v2:
  - Allow mdiobus probing for addr 0 and addr 1
  - Add xpcs_find* helpers based on phy_find* to avoid hardcoded addresses
  - Remove xpcs_bus write and use mdiodev_c45_write instead
  - Address comment on use of MDIO_PMA_RSFEC_CTRL
v1: https://lore.kernel.org/all/20260506190904.4029-2-mike.marciniszyn@gmail.com/

 drivers/net/ethernet/meta/fbnic/fbnmdiodev_c45_writeic_mdio.c |   3 +-
 drivers/net/pcs/pcs-xpcs.c                   | 105 +++++++++++++++++++
 drivers/net/pcs/pcs-xpcs.h                   |   6 ++
 include/uapi/linux/mdio.h                    |   3 +
 4 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
index fe3a4ce88413..e29534dd1e0c 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
@@ -263,8 +263,7 @@ int fbnic_mdiobus_create(struct fbnic_dev *fbd)
 	bus->read_c45 = &fbnic_mdio_read_c45;
 	bus->write_c45 = &fbnic_mdio_write_c45;
 
-	/* Disable PHY auto probing. We will add PCS manually */
-	bus->phy_mask = ~0;
+	bus->phy_mask = GENMASK(31, 2);
 
 	bus->parent = fbd->dev;
 	bus->priv = fbd;
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index e69fa2f0a0e8..14f89e56958c 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -1402,6 +1402,107 @@ static int xpcs_read_ids(struct dw_xpcs *xpcs)
 	return 0;
 }
 
+static int xpcs_get_pma_mmd(struct dw_xpcs *xpcs)
+{
+	int devs1, b;
+
+	devs1 = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVS1);
+	if (devs1 < 0)
+		return devs1;
+
+	/* Locate the PMA closest to the PCS as this should be the one provided
+	 * with the DW IP. This is identified by being the PMA with the
+	 * highest MMD device address.
+	 */
+	devs1 &= MDIO_DEVS_SEP_PMA1 | MDIO_DEVS_SEP_PMA2 | MDIO_DEVS_SEP_PMA3 |
+		 MDIO_DEVS_SEP_PMA4 | MDIO_DEVS_PMAPMD;
+	b = fls(devs1);
+	if (b)
+		return b - 1;
+
+	return -ENODEV;
+}
+
+struct pma_pcs_values {
+	int lanes;
+	u16 rsfec_ctrl;
+};
+
+static struct mdio_device *xpcs_find_first_mdev(struct dw_xpcs *xpcs)
+{
+	struct phy_device *p = phy_find_first(xpcs->mdiodev->bus);
+
+	if (!p)
+		return NULL;
+	return &p->mdio;
+}
+
+static struct mdio_device *
+xpcs_find_next_mdev(struct dw_xpcs *xpcs, struct mdio_device *mdev)
+{
+	struct phy_device *p = container_of(mdev, struct phy_device, mdio), *n;
+
+	n = phy_find_next(xpcs->mdiodev->bus, p);
+	if (!n)
+		return NULL;
+	return &n->mdio;
+}
+
+static int
+xpcs_config_rsfec_pma(struct dw_xpcs *xpcs, const struct pma_pcs_values *v)
+{
+	struct mdio_device *mdev;
+	int ret = 0, i, pma_mmd;
+
+	pma_mmd = xpcs_get_pma_mmd(xpcs);
+	if (pma_mmd < 1)
+		return pma_mmd;
+
+	mdev = xpcs_find_first_mdev(xpcs);
+	if (!mdev)
+		return -ENODEV;
+
+	for (i = 0; mdev && ret >= 0 && i < v->lanes;
+	     i++, mdev = xpcs_find_next_mdev(xpcs, mdev)) {
+		ret = mdiodev_c45_write(mdev, pma_mmd, MDIO_PMA_RSFEC_CTRL,
+					v->rsfec_ctrl);
+	}
+	if (!ret && i < v->lanes)
+		return -ENODEV;
+
+	return ret;
+}
+
+static int xpcs_25gbaser_pma_config(struct dw_xpcs *xpcs)
+{
+	const struct pma_pcs_values v = {
+		.rsfec_ctrl = 0,
+		.lanes = 1,
+	};
+
+	return xpcs_config_rsfec_pma(xpcs, &v);
+}
+
+static int xpcs_50gbaser_pma_config(struct dw_xpcs *xpcs)
+{
+	const struct pma_pcs_values v = {
+		.rsfec_ctrl = DW_VR_RSFEC_CTRL_TC_PAD_ALTER,
+		.lanes = 2,
+	};
+
+	return xpcs_config_rsfec_pma(xpcs, &v);
+}
+
+static int xpcs_100gbasep_pma_config(struct dw_xpcs *xpcs)
+{
+	const struct pma_pcs_values v = {
+		.rsfec_ctrl = MDIO_PMA_RSFEC_CTRL_4LANE_PMD,
+		.lanes = 2,
+	};
+
+	return xpcs_config_rsfec_pma(xpcs, &v);
+}
+
 static const struct dw_xpcs_compat synopsys_xpcs_compat[] = {
 	{
 		.interface = PHY_INTERFACE_MODE_USXGMII,
@@ -1415,6 +1516,7 @@ static const struct dw_xpcs_compat synopsys_xpcs_compat[] = {
 		.interface = PHY_INTERFACE_MODE_25GBASER,
 		.supported = xpcs_25gbaser_features,
 		.an_mode = DW_AN_C73,
+		.pma_config = xpcs_25gbaser_pma_config,
 	}, {
 		.interface = PHY_INTERFACE_MODE_XLGMII,
 		.supported = xpcs_xlgmii_features,
@@ -1423,14 +1525,17 @@ static const struct dw_xpcs_compat synopsys_xpcs_compat[] = {
 		.interface = PHY_INTERFACE_MODE_50GBASER,
 		.supported = xpcs_50gbaser_features,
 		.an_mode = DW_AN_C73,
+		.pma_config = xpcs_50gbaser_pma_config,
 	}, {
 		.interface = PHY_INTERFACE_MODE_LAUI,
 		.supported = xpcs_50gbaser2_features,
 		.an_mode = DW_AN_C73,
+		.pma_config = xpcs_50gbaser_pma_config,
 	}, {
 		.interface = PHY_INTERFACE_MODE_100GBASEP,
 		.supported = xpcs_100gbasep_features,
 		.an_mode = DW_AN_C73,
+		.pma_config = xpcs_100gbasep_pma_config,
 	}, {
 		.interface = PHY_INTERFACE_MODE_10GBASER,
 		.supported = xpcs_10gbaser_features,
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
index 929fa238445e..187cdec30e70 100644
--- a/drivers/net/pcs/pcs-xpcs.h
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -94,6 +94,12 @@
 #define DW_VR_MII_DIG_CTRL2_TX_POL_INV		BIT(4)
 #define DW_VR_MII_DIG_CTRL2_RX_POL_INV		BIT(0)
 
+/* Clause 133 defines */
+/* RSFEC transcode pad alter
+ * DW vendor extension in RS-FEC control
+ */
+#define DW_VR_RSFEC_CTRL_TC_PAD_ALTER	BIT(10)
+
 #define DW_XPCS_INFO_DECLARE(_name, _pcs, _pma)				\
 	static const struct dw_xpcs_info _name = { .pcs = _pcs, .pma = _pma }
 
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index b2541c948fc1..5219c877b2cf 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -317,6 +317,9 @@
 #define MDIO_PMA_10GBR_FECABLE_ABLE	0x0001	/* FEC ability */
 #define MDIO_PMA_10GBR_FECABLE_ERRABLE	0x0002	/* FEC error indic. ability */
 
+/* RSFEC PMA Control register */
+#define MDIO_PMA_RSFEC_CTRL_4LANE_PMD	BIT(3)
+
 /* PMA 10GBASE-R Fast Retrain status and control register. */
 #define MDIO_PMA_10GBR_FSRT_ENABLE	0x0001	/* Fast retrain enable */
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 2/2] net: pcs: xpcs: Add handling for 4 channel rsfec device
  2026-05-11 18:26 [PATCH net-next v2 0/2] second series for xpcs based rsfec configuration mike.marciniszyn
  2026-05-11 18:26 ` [PATCH net-next v2 1/2] net: pcs: xpcs: Add hooks for xpcs configuration of rsfec mike.marciniszyn
@ 2026-05-11 18:26 ` mike.marciniszyn
  2026-05-15 17:12   ` Alexander H Duyck
  1 sibling, 1 reply; 5+ messages in thread
From: mike.marciniszyn @ 2026-05-11 18:26 UTC (permalink / raw)
  To: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
	David S. Miller, Eric Dumazet, Paolo Abeni, Heiner Kallweit,
	Russell King, Kees Cook, Andrew Lunn
  Cc: mike.marciniszyn, netdev, linux-kernel

From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>

This patch introduces the configuration of vendor specific
registers for alignment encoding, PCS Mode, and VL_INTVL
over the one or two instances as required.

The DW_PCS IP specification calls out the need to configure both
lanes identically when using 2 lane modes such as 50-R2 and 100-R2, so
the programming is repeated for each lane.

The encoding tables are derived from the IEEE 8023-2022 spec sections
82.2.7 and tables 82-2 and 82-3 for the alignment markers and their
insertion.

Note that there is a conflict between VRs DW_VR_XS_PCS_DIG_STS and
and the DW_PCS_IP DW_VR_MII_PCS_PCS_MODE.  The bit mask for
DW_VR_XS_PCS_DIG_STS/RX_FIFO_ERR fits within the reserved bits for
the DW_PCS IP the DW_VR_MII_PCS_PCS_MODE register so there is no issue.

There is also a confict between DW_VR_MII_PCS_VL_INTVL and
DW_VR_MII_AN_INTR_STS but an_mode differs, so again there is no issue.

Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
---
v2:
  - Replace xpcs_write_pcs_prtad() wiht xpcs_write_pcs_mdev() to
    avoid hardcoded prtaddr value
v1: https://lore.kernel.org/all/20260506190904.4029-3-mike.marciniszyn@gmail.com/

 drivers/net/pcs/pcs-xpcs.c | 91 +++++++++++++++++++++++++++++++++++++-
 drivers/net/pcs/pcs-xpcs.h | 25 +++++++++++
 2 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 14f89e56958c..42d64f7ebf34 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -1423,9 +1423,39 @@ static int xpcs_get_pma_mmd(struct dw_xpcs *xpcs)
 	return -ENODEV;
 }
 
+/* m0 - m2 from Table 82-2/82-3
+ * m4 - m6 are skipped since they are inversions of m0 - m2.
+ * Inverted parity fields (IEEE 82.2.8) bip3 and bip7 are omitted.
+ */
+struct lane_markers {
+	u8 m0, m1, m2;
+};
+
+/* Alignment marker encodings, see table 82-2 in IEEE 802.3-2022 */
+static const struct lane_markers xpcs_100gbaser_markers[] = {
+	{0xc1, 0x68, 0x21},
+	{0x9d, 0x71, 0x8e},
+	{0x59, 0x4b, 0xe8},
+	{0x4d, 0x95, 0x7b},
+};
+
+/* Alignment marker encodings, see table 82-3 in IEEE 802.3-2022
+ * The content of the 50G markers is identical to 40G values (IEEE 133.2.2).
+ */
+static const struct lane_markers xpcs_50gbaser_markers[] = {
+	{0x90, 0x76, 0x47},
+	{0xf0, 0xc4, 0xe6},
+	{0xc5, 0x65, 0x9b},
+	{0xa2, 0x79, 0x3d},
+};
+
 struct pma_pcs_values {
+	const struct lane_markers *vl0_markers;
+	const struct lane_markers *vl123_markers;
 	int lanes;
 	u16 rsfec_ctrl;
+	u16 pcs_mode;
+	u16 vl_intvl;
 };
 
 static struct mdio_device *xpcs_find_first_mdev(struct dw_xpcs *xpcs)
@@ -1448,11 +1478,38 @@ xpcs_find_next_mdev(struct dw_xpcs *xpcs, struct mdio_device *mdev)
 	return &n->mdio;
 }
 
+#define XPCS_VL_TO_REG(vl, lh) \
+	(((vl) * 2) + DW_VR_MII_PCS_VL0_##lh)
+
+static int
+xpcs_write_pcs_mdev(struct mdio_device *mdev, int reg, u16 val)
+{
+	return mdiodev_c45_write(mdev, MDIO_MMD_PCS, reg, val);
+}
+
+static int
+xpcs_config_vl_markers(struct dw_xpcs *xpcs, int vl, struct mdio_device *mdev,
+		       const struct lane_markers *m)
+{
+	int ret;
+
+	/* m0, m1, m2 written to _L and _H registers
+	 *
+	 * _L = (m1 << 8) | m0
+	 * _H = m2
+	 */
+	ret = xpcs_write_pcs_mdev(mdev, XPCS_VL_TO_REG(vl, L),
+				  ((u16)m->m1 << 8) | m->m0);
+	if (ret < 0)
+		return ret;
+	return xpcs_write_pcs_mdev(mdev, XPCS_VL_TO_REG(vl, H), m->m2);
+}
+
 static int
 xpcs_config_rsfec_pma(struct dw_xpcs *xpcs, const struct pma_pcs_values *v)
 {
+	int ret = 0, i, vl, pma_mmd;
 	struct mdio_device *mdev;
-	int ret = 0, i, pma_mmd;
 
 	pma_mmd = xpcs_get_pma_mmd(xpcs);
 	if (pma_mmd < 1)
@@ -1464,6 +1521,23 @@ xpcs_config_rsfec_pma(struct dw_xpcs *xpcs, const struct pma_pcs_values *v)
 
 	for (i = 0; mdev && ret >= 0 && i < v->lanes;
 	     i++, mdev = xpcs_find_next_mdev(xpcs, mdev)) {
+		/* code word markings */
+		for (vl = 0; mdev && ret >= 0 && vl < 4; vl++)
+			ret = xpcs_config_vl_markers(xpcs, vl, mdev,
+						     !vl ? &v->vl0_markers[0] :
+						     &v->vl123_markers[vl - 1]);
+		if (ret < 0)
+			break;
+		/* vendor registers */
+		ret = xpcs_write_pcs_mdev(mdev, DW_VR_MII_PCS_VL_INTVL,
+					  v->vl_intvl);
+		if (ret < 0)
+			break;
+		ret = xpcs_write_pcs_mdev(mdev, DW_VR_MII_PCS_PCS_MODE,
+					  v->pcs_mode);
+		if (ret < 0)
+			break;
+		/* rsfec register */
 		ret = mdiodev_c45_write(mdev, pma_mmd, MDIO_PMA_RSFEC_CTRL,
 					v->rsfec_ctrl);
 	}
@@ -1478,6 +1552,13 @@ static int xpcs_25gbaser_pma_config(struct dw_xpcs *xpcs)
 	const struct pma_pcs_values v = {
 		.rsfec_ctrl = 0,
 		.lanes = 1,
+		/* 25g markers from 100g and 50g tables per 802.3-2022
+		 * 108.5.2.4
+		 */
+		.vl0_markers = &xpcs_100gbaser_markers[0],
+		.vl123_markers = &xpcs_50gbaser_markers[1],
+		.vl_intvl = 20479,
+		.pcs_mode = DW_VR_MII_PCS_MODE_CLAUSE107,
 	};
 
 	return xpcs_config_rsfec_pma(xpcs, &v);
@@ -1488,6 +1569,10 @@ static int xpcs_50gbaser_pma_config(struct dw_xpcs *xpcs)
 	const struct pma_pcs_values v = {
 		.rsfec_ctrl = DW_VR_RSFEC_CTRL_TC_PAD_ALTER,
 		.lanes = 2,
+		.vl0_markers = &xpcs_50gbaser_markers[0],
+		.vl123_markers = &xpcs_50gbaser_markers[1],
+		.pcs_mode = 0,
+		.vl_intvl = 20479,
 	};
 
 	return xpcs_config_rsfec_pma(xpcs, &v);
@@ -1498,6 +1583,10 @@ static int xpcs_100gbasep_pma_config(struct dw_xpcs *xpcs)
 	const struct pma_pcs_values v = {
 		.rsfec_ctrl = MDIO_PMA_RSFEC_CTRL_4LANE_PMD,
 		.lanes = 2,
+		.vl0_markers = &xpcs_100gbaser_markers[0],
+		.vl123_markers = &xpcs_100gbaser_markers[1],
+		.pcs_mode = DW_VR_MII_PCS_MODE_DISABLE_MLD,
+		.vl_intvl = 16383,
 	};
 
 	return xpcs_config_rsfec_pma(xpcs, &v);
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
index 187cdec30e70..8161d75370e6 100644
--- a/drivers/net/pcs/pcs-xpcs.h
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -100,6 +100,31 @@
  */
 #define DW_VR_RSFEC_CTRL_TC_PAD_ALTER	BIT(10)
 
+/* Vendor specific 4 channel PCS registers */
+
+/* DW_VR_MII_PCS_VL_INTVL and DW_VR_MII_AN_INTR_STS conflict
+ * but code paths are different
+ */
+#define DW_VR_MII_PCS_VL_INTVL		0x8002
+/* 0x8008 - 0x800f */
+#define DW_VR_MII_PCS_VL0_L		0x8008
+#define DW_VR_MII_PCS_VL0_H		0x8009
+#define DW_VR_MII_PCS_PCS_MODE		0x8010
+
+/* DW_VR_MII_PCS_PCS_MODE bits */
+#define DW_VR_MII_PCS_MODE_HI_BER25		BIT(2)
+#define DW_VR_MII_PCS_MODE_DISABLE_MLD		BIT(1)
+#define DW_VR_MII_PCS_MODE_CLAUSE49		BIT(0)
+
+/* 25G requires these two bits are set.
+ *
+ * The CLAUSE49 bit changes the interface with the MAC
+ * to 64 bit and the BER25 bit changes the measurement
+ * interval to 2ms.
+ */
+#define DW_VR_MII_PCS_MODE_CLAUSE107 \
+	(DW_VR_MII_PCS_MODE_HI_BER25 | DW_VR_MII_PCS_MODE_CLAUSE49)
+
 #define DW_XPCS_INFO_DECLARE(_name, _pcs, _pma)				\
 	static const struct dw_xpcs_info _name = { .pcs = _pcs, .pma = _pma }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v2 1/2] net: pcs: xpcs: Add hooks for xpcs configuration of rsfec
  2026-05-11 18:26 ` [PATCH net-next v2 1/2] net: pcs: xpcs: Add hooks for xpcs configuration of rsfec mike.marciniszyn
@ 2026-05-15 16:52   ` Alexander H Duyck
  0 siblings, 0 replies; 5+ messages in thread
From: Alexander H Duyck @ 2026-05-15 16:52 UTC (permalink / raw)
  To: mike.marciniszyn, Alexander Duyck, Jakub Kicinski, kernel-team,
	Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
	Heiner Kallweit, Russell King, Kees Cook, Andrew Lunn
  Cc: netdev, linux-kernel

On Mon, 2026-05-11 at 14:26 -0400, mike.marciniszyn@gmail.com wrote:
> From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
> 
> The DW PCS IP data sheet calls out the need to populate
> these vendor registers when operating at speeds above 10Gbps.
> This change enables the correct FEC settings to enable RS-FEC
> encoding on the link which is the standard used for most links
> at these higher speeds.
> 
> Note that the overwriting of the MDIO_PMA_RSFEC_CTRL register
> is intentional and consistent DW PCS IP requirements.
> 
> Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
> Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
> ---
> v2:
>   - Allow mdiobus probing for addr 0 and addr 1
>   - Add xpcs_find* helpers based on phy_find* to avoid hardcoded addresses
>   - Remove xpcs_bus write and use mdiodev_c45_write instead
>   - Address comment on use of MDIO_PMA_RSFEC_CTRL
> v1: https://lore.kernel.org/all/20260506190904.4029-2-mike.marciniszyn@gmail.com/
> 
>  drivers/net/ethernet/meta/fbnic/fbnmdiodev_c45_writeic_mdio.c |   3 +-
>  drivers/net/pcs/pcs-xpcs.c                   | 105 +++++++++++++++++++
>  drivers/net/pcs/pcs-xpcs.h                   |   6 ++
>  include/uapi/linux/mdio.h                    |   3 +
>  4 files changed, 115 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
> index fe3a4ce88413..e29534dd1e0c 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
> @@ -263,8 +263,7 @@ int fbnic_mdiobus_create(struct fbnic_dev *fbd)
>  	bus->read_c45 = &fbnic_mdio_read_c45;
>  	bus->write_c45 = &fbnic_mdio_write_c45;
>  
> -	/* Disable PHY auto probing. We will add PCS manually */
> -	bus->phy_mask = ~0;
> +	bus->phy_mask = GENMASK(31, 2);
>  
>  	bus->parent = fbd->dev;
>  	bus->priv = fbd;

Why are you messing with the PHY autoprobing mask? That doesn't make
sense to add to this patch. The side effect is that it is going to
expose a phydev that won't be used as we access the PMD direcly.

[...]

> +static struct mdio_device *xpcs_find_first_mdev(struct dw_xpcs *xpcs)
> +{
> +	struct phy_device *p = phy_find_first(xpcs->mdiodev->bus);
> +
> +	if (!p)
> +		return NULL;
> +	return &p->mdio;
> +}
> +
> +static struct mdio_device *
> +xpcs_find_next_mdev(struct dw_xpcs *xpcs, struct mdio_device *mdev)
> +{
> +	struct phy_device *p = container_of(mdev, struct phy_device, mdio), *n;
> +
> +	n = phy_find_next(xpcs->mdiodev->bus, p);
> +	if (!n)
> +		return NULL;
> +	return &n->mdio;
> +}
> +

Okay, the use of these functions explains the issue. You shouldn't be
using phy_find_next. You know the bus will be located on mdio.addr + 1.
You should not need to have a phy_device assigned for each of the PMA
devices.

The general idea is you have mdio_devices you shouldn't be trying to
use the phy_device functions in the PCS driver.

> +static int
> +xpcs_config_rsfec_pma(struct dw_xpcs *xpcs, const struct pma_pcs_values *v)
> +{
> +	struct mdio_device *mdev;
> +	int ret = 0, i, pma_mmd;
> +
> +	pma_mmd = xpcs_get_pma_mmd(xpcs);
> +	if (pma_mmd < 1)
> +		return pma_mmd;
> +
> +	mdev = xpcs_find_first_mdev(xpcs);
> +	if (!mdev)
> +		return -ENODEV;
> +

There shouldn't be any need for a special for this. You already have
the capabilities to write to the devices you need to write to.

The only things you need to change would be to access the nearest PMA
to the PCS as that is the one that holds the RSFEC configuration. For
that you just need to know what devices are already enabled and you can
access them.

> +	for (i = 0; mdev && ret >= 0 && i < v->lanes;
> +	     i++, mdev = xpcs_find_next_mdev(xpcs, mdev)) {
> +		ret = mdiodev_c45_write(mdev, pma_mmd, MDIO_PMA_RSFEC_CTRL,
> +					v->rsfec_ctrl);
> +	}

You don't need this "find next" logic. It is just the device on the
adjacent bus. Also I am not sure we even need the loop logic since
there are only 2 devices you have to configure as currently only 2
lanes are supported.

[...]

> diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
> index b2541c948fc1..5219c877b2cf 100644
> --- a/include/uapi/linux/mdio.h
> +++ b/include/uapi/linux/mdio.h
> @@ -317,6 +317,9 @@
>  #define MDIO_PMA_10GBR_FECABLE_ABLE	0x0001	/* FEC ability */
>  #define MDIO_PMA_10GBR_FECABLE_ERRABLE	0x0002	/* FEC error indic. ability */
>  
> +/* RSFEC PMA Control register */
> +#define MDIO_PMA_RSFEC_CTRL_4LANE_PMD	BIT(3)
> +
>  /* PMA 10GBASE-R Fast Retrain status and control register. */
>  #define MDIO_PMA_10GBR_FSRT_ENABLE	0x0001	/* Fast retrain enable */
>  

The AI review complaint about this bit seems to be based on an outdated
version of the IEEE specification.

This is called out in 9802.3-2022 as "Four lane PMD indication" so
perhaps sashiko needs to be updated.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v2 2/2] net: pcs: xpcs: Add handling for 4 channel rsfec device
  2026-05-11 18:26 ` [PATCH net-next v2 2/2] net: pcs: xpcs: Add handling for 4 channel rsfec device mike.marciniszyn
@ 2026-05-15 17:12   ` Alexander H Duyck
  0 siblings, 0 replies; 5+ messages in thread
From: Alexander H Duyck @ 2026-05-15 17:12 UTC (permalink / raw)
  To: mike.marciniszyn, Alexander Duyck, Jakub Kicinski, kernel-team,
	Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
	Heiner Kallweit, Russell King, Kees Cook, Andrew Lunn
  Cc: netdev, linux-kernel

On Mon, 2026-05-11 at 14:26 -0400, mike.marciniszyn@gmail.com wrote:
> From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
> 
> This patch introduces the configuration of vendor specific
> registers for alignment encoding, PCS Mode, and VL_INTVL
> over the one or two instances as required.
> 
> The DW_PCS IP specification calls out the need to configure both
> lanes identically when using 2 lane modes such as 50-R2 and 100-R2, so
> the programming is repeated for each lane.
> 
> The encoding tables are derived from the IEEE 8023-2022 spec sections
> 82.2.7 and tables 82-2 and 82-3 for the alignment markers and their
> insertion.
> 
> Note that there is a conflict between VRs DW_VR_XS_PCS_DIG_STS and
> and the DW_PCS_IP DW_VR_MII_PCS_PCS_MODE.  The bit mask for
> DW_VR_XS_PCS_DIG_STS/RX_FIFO_ERR fits within the reserved bits for
> the DW_PCS IP the DW_VR_MII_PCS_PCS_MODE register so there is no issue.
> 
> There is also a confict between DW_VR_MII_PCS_VL_INTVL and
> DW_VR_MII_AN_INTR_STS but an_mode differs, so again there is no issue.
> 
> Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
> Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
> ---
> v2:
>   - Replace xpcs_write_pcs_prtad() wiht xpcs_write_pcs_mdev() to
>     avoid hardcoded prtaddr value
> v1: https://lore.kernel.org/all/20260506190904.4029-3-mike.marciniszyn@gmail.com/
> 
>  drivers/net/pcs/pcs-xpcs.c | 91 +++++++++++++++++++++++++++++++++++++-
>  drivers/net/pcs/pcs-xpcs.h | 25 +++++++++++
>  2 files changed, 115 insertions(+), 1 deletion(-)
> 
> 

[...]

> @@ -1464,6 +1521,23 @@ xpcs_config_rsfec_pma(struct dw_xpcs *xpcs, const struct pma_pcs_values *v)
>  
>  	for (i = 0; mdev && ret >= 0 && i < v->lanes;
>  	     i++, mdev = xpcs_find_next_mdev(xpcs, mdev)) {

The use of the "find_next_mdev" essentially taints this patch with the
same issues from the first.

We know the offsets. We shouldn't be blindly reaching around for
devices and writing to them. If we need to we should be creating the
devices for the second lane of the PCS ourselves and using that instead
of letting the phy_device code autoprobe in a device based on the PMD.

Specifically we should just be writing to our bus ID and bus ID + 1 in
the case of the 50GR2 and 100G configurations as we have to configure
the 2 lanes. We shouldn't risk this thing going off the rails and
grabbing some random bus ID if it were loaded on another device. If we
need to we could make it so that the Meta device ID on the PCS is what
triggers it setting.

My advice would be to look at creating a new version of
xpcs_create_pcs_mdiodev, maybe "xpcs_create_pcs_mdiodevs", that you can
pass a lanes value to and perhaps look at making addr an array of
addresses. Then you could have that spawn the additional lanes via
mdio_device_create, record them in the dw_xpcs struct, and avoid having
to do as much blind searching to find the devices that you are
currently doing.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-05-15 17:12 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 18:26 [PATCH net-next v2 0/2] second series for xpcs based rsfec configuration mike.marciniszyn
2026-05-11 18:26 ` [PATCH net-next v2 1/2] net: pcs: xpcs: Add hooks for xpcs configuration of rsfec mike.marciniszyn
2026-05-15 16:52   ` Alexander H Duyck
2026-05-11 18:26 ` [PATCH net-next v2 2/2] net: pcs: xpcs: Add handling for 4 channel rsfec device mike.marciniszyn
2026-05-15 17:12   ` Alexander H Duyck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox