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 <[email protected]>
---
 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

Reply via email to