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

