[PATCH v3 2/2] net/cnxk: add FEC get set and capability ops
Rakesh Kudurumalla
rkudurumalla at marvell.com
Tue Jun 16 06:35:36 CEST 2026
Add ethdev FEC operations for cnxk NIX driver:
- fec_get_capability: Report supported FEC modes per speed.
If firmware provides supported FEC info, return actual
capabilities for current link speed. Otherwise, fall back
to a default capability table for common speeds.
- fec_get: Query current FEC mode from link info
- fec_set: Configure FEC mode on the link. AUTO mode
defaults to Reed-Solomon FEC.
Signed-off-by: Rakesh Kudurumalla <rkudurumalla at marvell.com>
---
doc/guides/nics/cnxk.rst | 45 ++++++++++++++
doc/guides/nics/features/cnxk.ini | 1 +
drivers/net/cnxk/cnxk_ethdev.c | 3 +
drivers/net/cnxk/cnxk_ethdev.h | 6 ++
drivers/net/cnxk/cnxk_ethdev_ops.c | 94 ++++++++++++++++++++++++++++++
5 files changed, 149 insertions(+)
diff --git a/doc/guides/nics/cnxk.rst b/doc/guides/nics/cnxk.rst
index b5bd50ceea..0891767f83 100644
--- a/doc/guides/nics/cnxk.rst
+++ b/doc/guides/nics/cnxk.rst
@@ -29,6 +29,7 @@ Features of the CNXK Ethdev PMD are:
- Port hardware statistics
- Link state information
- Link flow control
+- Forward Error Correction (FEC)
- MTU update
- Scatter-Gather IO support
- Vector Poll mode driver
@@ -513,6 +514,50 @@ Runtime Config Options
parameters to all the PCIe devices if application requires to configure on
all the ethdev ports.
+Forward Error Correction (FEC)
+------------------------------
+
+The CNXK PMD supports the DPDK FEC ethdev APIs on physical function (PF) ports
+for links where firmware reports FEC support (typically high-speed Ethernet
+interfaces such as 25G, 50G and 100G).
+
+Supported FEC modes exposed through the ethdev API are:
+
+- ``RTE_ETH_FEC_NOFEC``: FEC disabled
+- ``RTE_ETH_FEC_AUTO``: maps to Reed-Solomon (RS) FEC on set
+- ``RTE_ETH_FEC_BASER``: Base-R FEC
+- ``RTE_ETH_FEC_RS``: Reed-Solomon FEC
+
+``rte_eth_fec_get_capability()`` reports the FEC modes supported by firmware for
+the current link speed. ``rte_eth_fec_get()`` returns the active FEC mode from
+link information. ``rte_eth_fec_set()`` configures the FEC mode on the link.
+
+.. note::
+
+ ``rte_eth_fec_get_capability()`` and ``rte_eth_fec_set()`` are supported on
+ PF ports only. SR-IOV virtual function (VF) ports can use
+ ``rte_eth_fec_get()`` to read the current FEC mode from link status.
+
+Example usage:
+
+.. code-block:: c
+
+ struct rte_eth_fec_capa capa[1];
+ uint32_t fec_capa;
+ int num, ret;
+
+ num = rte_eth_fec_get_capability(port_id, capa, RTE_DIM(capa));
+ if (num > 0)
+ printf("FEC capa 0x%x at speed %u\n", capa[0].capa, capa[0].speed);
+
+ ret = rte_eth_fec_get(port_id, &fec_capa);
+ if (ret == 0)
+ printf("Current FEC capa 0x%x\n", fec_capa);
+
+ ret = rte_eth_fec_set(port_id, RTE_ETH_FEC_MODE_CAPA_MASK(RS));
+ if (ret)
+ printf("FEC set failed: %s\n", rte_strerror(-ret));
+
Limitations
-----------
diff --git a/doc/guides/nics/features/cnxk.ini b/doc/guides/nics/features/cnxk.ini
index 2de156c695..dc75947d86 100644
--- a/doc/guides/nics/features/cnxk.ini
+++ b/doc/guides/nics/features/cnxk.ini
@@ -31,6 +31,7 @@ Congestion management = Y
Traffic manager = Y
Inline protocol = Y
Flow control = Y
+FEC = Y
Scattered Rx = Y
L3 checksum offload = Y
L4 checksum offload = Y
diff --git a/drivers/net/cnxk/cnxk_ethdev.c b/drivers/net/cnxk/cnxk_ethdev.c
index 7ae16186c6..4c3d906e16 100644
--- a/drivers/net/cnxk/cnxk_ethdev.c
+++ b/drivers/net/cnxk/cnxk_ethdev.c
@@ -2138,6 +2138,9 @@ struct eth_dev_ops cnxk_eth_dev_ops = {
.cman_config_set = cnxk_nix_cman_config_set,
.cman_config_get = cnxk_nix_cman_config_get,
.eth_tx_descriptor_dump = cnxk_nix_tx_descriptor_dump,
+ .fec_get_capability = cnxk_nix_fec_get_capability,
+ .fec_get = cnxk_nix_fec_get,
+ .fec_set = cnxk_nix_fec_set,
};
void
diff --git a/drivers/net/cnxk/cnxk_ethdev.h b/drivers/net/cnxk/cnxk_ethdev.h
index ea6a2be30e..4a8fb1b974 100644
--- a/drivers/net/cnxk/cnxk_ethdev.h
+++ b/drivers/net/cnxk/cnxk_ethdev.h
@@ -664,6 +664,12 @@ int cnxk_nix_tm_mark_ip_dscp(struct rte_eth_dev *eth_dev, int mark_green,
int cnxk_nix_tx_descriptor_dump(const struct rte_eth_dev *eth_dev, uint16_t qid, uint16_t offset,
uint16_t num, FILE *file);
+/* FEC */
+int cnxk_nix_fec_get_capability(struct rte_eth_dev *eth_dev,
+ struct rte_eth_fec_capa *speed_fec_capa, unsigned int num);
+int cnxk_nix_fec_get(struct rte_eth_dev *eth_dev, uint32_t *fec_capa);
+int cnxk_nix_fec_set(struct rte_eth_dev *eth_dev, uint32_t fec_capa);
+
/* MTR */
int cnxk_nix_mtr_ops_get(struct rte_eth_dev *dev, void *ops);
diff --git a/drivers/net/cnxk/cnxk_ethdev_ops.c b/drivers/net/cnxk/cnxk_ethdev_ops.c
index 460ffa32b6..0ea3d7e89f 100644
--- a/drivers/net/cnxk/cnxk_ethdev_ops.c
+++ b/drivers/net/cnxk/cnxk_ethdev_ops.c
@@ -1414,3 +1414,97 @@ cnxk_nix_tx_descriptor_dump(const struct rte_eth_dev *eth_dev, uint16_t qid, uin
return roc_nix_sq_desc_dump(nix, qid, offset, num, file);
}
+
+static uint32_t
+cnxk_roc_fec_to_ethdev_capa(int roc_fec)
+{
+ switch (roc_fec) {
+ case ROC_FEC_BASER:
+ return RTE_ETH_FEC_MODE_CAPA_MASK(BASER);
+ case ROC_FEC_RS:
+ return RTE_ETH_FEC_MODE_CAPA_MASK(RS);
+ default:
+ return RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC);
+ }
+}
+
+static int
+cnxk_ethdev_fec_to_roc(uint32_t fec_capa)
+{
+ if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(RS))
+ return ROC_FEC_RS;
+ if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(BASER))
+ return ROC_FEC_BASER;
+ return ROC_FEC_NONE;
+}
+
+static uint32_t
+cnxk_fec_capa_from_supported(uint64_t supported_fec)
+{
+ uint32_t capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | RTE_ETH_FEC_MODE_CAPA_MASK(AUTO);
+
+ if (supported_fec & (1ULL << ROC_FEC_BASER))
+ capa |= RTE_ETH_FEC_MODE_CAPA_MASK(BASER);
+ if (supported_fec & (1ULL << ROC_FEC_RS))
+ capa |= RTE_ETH_FEC_MODE_CAPA_MASK(RS);
+
+ return capa;
+}
+
+int
+cnxk_nix_fec_get_capability(struct rte_eth_dev *eth_dev, struct rte_eth_fec_capa *speed_fec_capa,
+ unsigned int num)
+{
+ struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+ struct roc_nix *nix = &dev->nix;
+ struct roc_nix_link_info link_info;
+ uint64_t supported_fec = 0;
+ int rc;
+
+ rc = roc_nix_mac_fec_supported_get(nix, &supported_fec);
+ if (rc == 0 && supported_fec != 0) {
+ rc = roc_nix_mac_link_info_get(nix, &link_info);
+ if (rc)
+ return rc;
+
+ if (speed_fec_capa == NULL || num == 0)
+ return 1;
+
+ speed_fec_capa[0].speed = link_info.speed;
+ speed_fec_capa[0].capa = cnxk_fec_capa_from_supported(supported_fec);
+ return 1;
+ }
+
+ return rc;
+}
+
+int
+cnxk_nix_fec_get(struct rte_eth_dev *eth_dev, uint32_t *fec_capa)
+{
+ struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+ struct roc_nix *nix = &dev->nix;
+ struct roc_nix_link_info link_info;
+ int rc;
+
+ rc = roc_nix_mac_link_info_get(nix, &link_info);
+ if (rc)
+ return rc;
+
+ *fec_capa = cnxk_roc_fec_to_ethdev_capa(link_info.fec);
+ return 0;
+}
+
+int
+cnxk_nix_fec_set(struct rte_eth_dev *eth_dev, uint32_t fec_capa)
+{
+ struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+ struct roc_nix *nix = &dev->nix;
+ int roc_fec;
+
+ if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(AUTO))
+ roc_fec = ROC_FEC_RS;
+ else
+ roc_fec = cnxk_ethdev_fec_to_roc(fec_capa);
+
+ return roc_nix_mac_fec_set(nix, roc_fec);
+}
--
2.25.1
More information about the dev
mailing list