[PATCH 2/7] net/nfb: get correct link speed

spinler
2026-02-06T17:04:54Z

Read link speed capabilities and actual link speed
from the MDIO registers.

Signed-off-by: Martin Spinler <spinler@cesnet.cz>
---
drivers/net/nfb/meson.build | 1 +
drivers/net/nfb/nfb.h | 7 ++++
drivers/net/nfb/nfb_ethdev.c | 78 +++++++++++++++++++++++++++---------
drivers/net/nfb/nfb_mdio.c | 42 +++++++++++++++++++
drivers/net/nfb/nfb_mdio.h | 34 ++++++++++++++++
5 files changed, 142 insertions(+), 20 deletions(-)
create mode 100644 drivers/net/nfb/nfb_mdio.c
create mode 100644 drivers/net/nfb/nfb_mdio.h

diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
index 9e458dfb4a..b57d1d48fa 100644
--- a/drivers/net/nfb/meson.build
+++ b/drivers/net/nfb/meson.build
@@ -21,6 +21,7 @@ sources = files(
'nfb_rxmode.c',
'nfb_stats.c',
'nfb_tx.c',
+ 'nfb_mdio.c',
)

cflags += no_wvla_cflag
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
index 2bce71ac89..6ffb940c6d 100644
--- a/drivers/net/nfb/nfb.h
+++ b/drivers/net/nfb/nfb.h
@@ -11,6 +11,7 @@
#include <nfb/ndp.h>
#include <netcope/rxmac.h>
#include <netcope/txmac.h>
+#include <netcope/mdio_if_info.h>
#include <netcope/info.h>

extern int nfb_logtype;
@@ -50,6 +51,10 @@ extern int nfb_logtype;
NFB_ARG_PORT "=<number>" \
""

+struct eth_node {
+ struct mdio_if_info if_info; /**< MDIO interface handles */
+};
+
/*
* Handles obtained from the libnfb: each process must use own instance.
* Stored inside dev->process_private.
@@ -57,8 +62,10 @@ extern int nfb_logtype;
struct pmd_internals {
uint16_t max_rxmac; /**< Count of valid rxmac items */
uint16_t max_txmac; /**< Count of valid txmac items */
+ uint16_t max_eth; /**< Count of valid eth nodes */
struct nc_rxmac **rxmac; /**< Array of Rx MAC handles */
struct nc_txmac **txmac; /**< Array of Tx MAC handles */
+ struct eth_node *eth_node; /**< Array of Eth nodes */
struct nfb_device *nfb;

TAILQ_ENTRY(pmd_internals) eth_dev_list; /**< Item in list of all devices */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
index ca3dbad879..437aed9ae7 100644
--- a/drivers/net/nfb/nfb_ethdev.c
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -14,6 +14,8 @@
#include <netcope/eth.h>
#include <netcope/rxmac.h>
#include <netcope/txmac.h>
+#include <netcope/mdio.h>
+#include <netcope/ieee802_3.h>

#include <ethdev_pci.h>
#include <rte_kvargs.h>
@@ -24,6 +26,8 @@
#include "nfb_rxmode.h"
#include "nfb.h"

+#include "nfb_mdio.h"
+
static const char * const VALID_KEYS[] = {
NFB_ARG_PORT,
NULL
@@ -46,6 +50,18 @@ static struct nfb_pmd_internals_head nfb_eth_dev_list =

static int nfb_eth_dev_uninit(struct rte_eth_dev *dev);

+static int
+nfb_mdio_read(void *priv, int prtad, int devad, uint16_t addr)
+{
+ return nc_mdio_read((struct nc_mdio *)priv, prtad, devad, addr);
+}
+
+static int
+nfb_mdio_write(void *priv, int prtad, int devad, uint16_t addr, uint16_t val)
+{
+ return nc_mdio_write((struct nc_mdio *)priv, prtad, devad, addr, val);
+}
+
/**
* Default MAC addr
*/
@@ -65,10 +81,17 @@ static int
nfb_nc_eth_init(struct pmd_internals *intl, struct nfb_ifc_create_params *params)
{
int ret;
- int i, rxm, txm;
+ int i, rxm, txm, eth;
struct nc_ifc_info *ifc = params->ifc_info;
struct nc_ifc_map_info *mi = &params->map_info;

+ int node, node_cp;
+ const int32_t *prop32;
+ int proplen;
+ const void *fdt;
+
+ fdt = nfb_get_fdt(intl->nfb);
+
ret = -ENOMEM;
if (ifc->eth_cnt == 0)
return 0;
@@ -81,9 +104,14 @@ nfb_nc_eth_init(struct pmd_internals *intl, struct nfb_ifc_create_params *params
if (intl->txmac == NULL)
goto err_alloc_txmac;

+ intl->eth_node = calloc(ifc->eth_cnt, sizeof(*intl->eth_node));
+ if (intl->eth_node == NULL)
+ goto err_alloc_ethnode;
+
/* Some eths may not have assigned MAC nodes, hence use separate var for indexing */
rxm = 0;
txm = 0;
+ eth = 0;
for (i = 0; i < mi->eth_cnt; i++) {
if (mi->eth[i].ifc != ifc->id)
continue;
@@ -95,12 +123,30 @@ nfb_nc_eth_init(struct pmd_internals *intl, struct nfb_ifc_create_params *params
intl->txmac[txm] = nc_txmac_open(intl->nfb, mi->eth[i].node_txmac);
if (intl->txmac[txm])
txm++;
+
+ node = nc_eth_get_pcspma_control_node(fdt, mi->eth[i].node_eth, &node_cp);
+
+ intl->eth_node[eth].if_info.dev = nc_mdio_open(intl->nfb, node, node_cp);
+ if (intl->eth_node[eth].if_info.dev) {
+ intl->eth_node[eth].if_info.prtad = 0;
+ intl->eth_node[eth].if_info.mdio_read = nfb_mdio_read;
+ intl->eth_node[eth].if_info.mdio_write = nfb_mdio_write;
+
+ prop32 = fdt_getprop(fdt, node_cp, "dev", &proplen);
+ if (proplen == sizeof(*prop32))
+ intl->eth_node[eth].if_info.prtad = fdt32_to_cpu(*prop32);
+
+ eth++;
+ }
}

intl->max_rxmac = rxm;
intl->max_txmac = txm;
+ intl->max_eth = eth;
return 0;

+err_alloc_ethnode:
+ free(intl->txmac);
err_alloc_txmac:
free(intl->rxmac);
err_alloc_rxmac:
@@ -116,6 +162,8 @@ static void
nfb_nc_eth_deinit(struct pmd_internals *intl)
{
uint16_t i;
+ for (i = 0; i < intl->max_eth; i++)
+ nc_mdio_close(intl->eth_node[i].if_info.dev);
for (i = 0; i < intl->max_txmac; i++)
nc_txmac_close(intl->txmac[i]);
for (i = 0; i < intl->max_rxmac; i++)
@@ -262,16 +310,22 @@ nfb_eth_dev_info(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info)
{
struct pmd_priv *priv = dev->data->dev_private;
+ struct pmd_internals *intl = dev->process_private;

dev_info->max_mac_addrs = nfb_eth_get_max_mac_address_count(dev);

dev_info->max_rx_pktlen = (uint32_t)-1;
dev_info->max_rx_queues = priv->max_rx_queues;
dev_info->max_tx_queues = priv->max_tx_queues;
- dev_info->speed_capa = RTE_ETH_LINK_SPEED_100G;
+ dev_info->speed_capa = RTE_ETH_LINK_SPEED_FIXED;
dev_info->rx_offload_capa =
RTE_ETH_RX_OFFLOAD_TIMESTAMP;

+ if (intl->max_eth) {
+ nfb_mdio_cl45_pma_get_speed_capa(&intl->eth_node[0].if_info,
+ &dev_info->speed_capa);
+ }
+
return 0;
}

@@ -339,24 +393,8 @@ nfb_eth_link_update(struct rte_eth_dev *dev,
link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
link.link_autoneg = RTE_ETH_LINK_SPEED_FIXED;

- if (internals->max_rxmac) {
- nc_rxmac_read_status(internals->rxmac[0], &status);
-
- switch (status.speed) {
- case MAC_SPEED_10G:
- link.link_speed = RTE_ETH_SPEED_NUM_10G;
- break;
- case MAC_SPEED_40G:
- link.link_speed = RTE_ETH_SPEED_NUM_40G;
- break;
- case MAC_SPEED_100G:
- link.link_speed = RTE_ETH_SPEED_NUM_100G;
- break;
- default:
- link.link_speed = RTE_ETH_SPEED_NUM_NONE;
- break;
- }
- }
+ if (internals->max_eth)
+ link.link_speed = ieee802_3_get_pma_speed_value(&internals->eth_node->if_info);

for (i = 0; i < internals->max_rxmac; ++i) {
nc_rxmac_read_status(internals->rxmac[i], &status);
diff --git a/drivers/net/nfb/nfb_mdio.c b/drivers/net/nfb/nfb_mdio.c
new file mode 100644
index 0000000000..19a433635b
--- /dev/null
+++ b/drivers/net/nfb/nfb_mdio.c
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 CESNET, z.s.p.o.
+ */
+
+#include <eal_export.h>
+#include <rte_ethdev.h>
+
+#include "nfb_mdio.h"
+
+RTE_EXPORT_INTERNAL_SYMBOL(nfb_mdio_cl45_pma_get_speed_capa)
+void
+nfb_mdio_cl45_pma_get_speed_capa(struct mdio_if_info *info, uint32_t *capa)
+{
+ int i;
+ int reg;
+
+ const int speed_ability[NFB_MDIO_WIDTH] = {
+ RTE_ETH_LINK_SPEED_10G,
+ 0,
+ 0,
+ RTE_ETH_LINK_SPEED_50G,
+ RTE_ETH_LINK_SPEED_1G,
+ RTE_ETH_LINK_SPEED_100M,
+ RTE_ETH_LINK_SPEED_10M,
+ 0,
+ RTE_ETH_LINK_SPEED_40G,
+ RTE_ETH_LINK_SPEED_100G,
+ 0,
+ RTE_ETH_LINK_SPEED_25G,
+ RTE_ETH_LINK_SPEED_200G,
+ RTE_ETH_LINK_SPEED_2_5G,
+ RTE_ETH_LINK_SPEED_5G,
+ RTE_ETH_LINK_SPEED_400G,
+ };
+
+ reg = nfb_mdio_if_read_pma(info, NFB_MDIO_PMA_SPEED_ABILITY);
+
+ for (i = 0; i < NFB_MDIO_WIDTH; i++) {
+ if (reg & NFB_MDIO_BIT(i))
+ *capa |= speed_ability[i];
+ }
+}
diff --git a/drivers/net/nfb/nfb_mdio.h b/drivers/net/nfb/nfb_mdio.h
new file mode 100644
index 0000000000..f783e71c4b
--- /dev/null
+++ b/drivers/net/nfb/nfb_mdio.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 CESNET, z.s.p.o.
+ */
+
+#include <stdint.h>
+#include <rte_bitops.h>
+#include <netcope/mdio_if_info.h>
+
+
+#define NFB_MDIO_WIDTH (UINT16_WIDTH)
+#define NFB_MDIO_BIT(nr) (UINT16_C(1) << (nr))
+
+#define NFB_MDIO_DEV_PMA 1
+
+#define NFB_MDIO_PMA_CTRL 0
+#define NFB_MDIO_PMA_CTRL_RESET NFB_MDIO_BIT(15)
+
+#define NFB_MDIO_PMA_SPEED_ABILITY 4
+
+#define NFB_MDIO_PMA_RSFEC_CR 200
+#define NFB_MDIO_PMA_RSFEC_CR_ENABLE NFB_MDIO_BIT(2)
+
+static inline int nfb_mdio_if_read_pma(struct mdio_if_info *if_info, uint16_t addr)
+{
+ return if_info->mdio_read(if_info->dev, if_info->prtad, NFB_MDIO_DEV_PMA, addr);
+}
+
+static inline int nfb_mdio_if_write_pma(struct mdio_if_info *if_info, uint16_t addr, uint16_t val)
+{
+ return if_info->mdio_write(if_info->dev, if_info->prtad, NFB_MDIO_DEV_PMA, addr, val);
+}
+
+__rte_internal
+void nfb_mdio_cl45_pma_get_speed_capa(struct mdio_if_info *if_info, uint32_t *capa);
--
2.53.0