[PATCH net-next 04/14] net: enetc: add basic operations to the FDB table

Wei Fang
2026-03-16T09:40:54Z

The FDB table is used for MAC learning lookups and MAC forwarding lookups.
Each table entry includes information such as a FID and MAC address that
may be unicast or multicast and a forwarding destination field containing
a port bitmap identifying the associated port(s) with the MAC address.
FDB table entries can be static or dynamic. Static entries are added from
software whereby dynamic entries are added either by software or by the
hardware as MAC addresses are learned in the datapath.

The FDB table can only be managed by the command BD ring using table
management protocol version 2.0. Table management command operations Add,
Delete, Update and Query are supported. And the FDB table supports three
access methods: Entry ID, Exact Match Key Element and Search. This patch
adds the following basic supports to the FDB table.

ntmp_fdbt_update_entry() - update the configuration element data of a
specified FDB entry

ntmp_fdbt_delete_entry() - delete a specified FDB entry

ntmp_fdbt_add_entry() - add an entry into the FDB table

ntmp_fdbt_search_port_entry() - Search the FDB entry on the specified
port based on RESUME_ENTRY_ID.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/ntmp.c | 199 ++++++++++++++++++
.../ethernet/freescale/enetc/ntmp_private.h | 59 ++++++
include/linux/fsl/ntmp.h | 67 ++++++
3 files changed, 325 insertions(+)

diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index 703752995e93..f6f4316169b6 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -20,11 +20,15 @@
/* Define NTMP Table ID */
#define NTMP_MAFT_ID 1
#define NTMP_RSST_ID 3
+#define NTMP_FDBT_ID 15

/* Generic Update Actions for most tables */
#define NTMP_GEN_UA_CFGEU BIT(0)
#define NTMP_GEN_UA_STSEU BIT(1)

+/* Query Action: 0: Full query, 1: Only query entry ID */
+#define NTMP_QA_ENTRY_ID 1
+
#define NTMP_ENTRY_ID_SIZE 4
#define RSST_ENTRY_NUM 64
#define RSST_STSE_DATA_SIZE(n) ((n) * 8)
@@ -225,6 +229,8 @@ static const char *ntmp_table_name(int tbl_id)
return "MAC Address Filter Table";
case NTMP_RSST_ID:
return "RSS Table";
+ case NTMP_FDBT_ID:
+ return "FDB Table";
default:
return "Unknown Table";
}
@@ -453,5 +459,198 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
}
EXPORT_SYMBOL_GPL(ntmp_rsst_query_entry);

+/**
+ * ntmp_fdbt_add_entry - add an entry into the FDB table
+ * @user: target ntmp_user struct
+ * @entry_id: returned value, the entry ID of the new added entry
+ * @keye: key element data
+ * @cfge: configuration element data
+ *
+ * Return: 0 on success, otherwise a negative error code
+ */
+int ntmp_fdbt_add_entry(struct ntmp_user *user, u32 *entry_id,
+ const struct fdbt_keye_data *keye,
+ const struct fdbt_cfge_data *cfge)
+{
+ struct ntmp_dma_buf data = {
+ .dev = user->dev,
+ .size = sizeof(struct fdbt_req_ua),
+ };
+ struct fdbt_resp_query *resp;
+ struct fdbt_req_ua *req;
+ union netc_cbd cbd;
+ u32 len;
+ int err;
+
+ err = ntmp_alloc_data_mem(&data, (void **)&req);
+ if (err)
+ return err;
+
+ /* Request data */
+ ntmp_fill_crd(&req->crd, user->tbl.fdbt_ver, NTMP_QA_ENTRY_ID,
+ NTMP_GEN_UA_CFGEU);
+ req->ak.exact.keye = *keye;
+ req->cfge = *cfge;
+
+ len = NTMP_LEN(data.size, sizeof(*resp));
+ /* The entry ID is allotted by hardware, so we need to perform
+ * a query action after the add action to get the entry ID from
+ * hardware.
+ */
+ ntmp_fill_request_hdr(&cbd, data.dma, len, NTMP_FDBT_ID,
+ NTMP_CMD_AQ, NTMP_AM_EXACT_KEY);
+ err = netc_xmit_ntmp_cmd(user, &cbd);
+ if (err) {
+ dev_err(user->dev, "Failed to add %s entry, err: %pe\n",
+ ntmp_table_name(NTMP_FDBT_ID), ERR_PTR(err));
+ goto end;
+ }
+
+ if (entry_id) {
+ resp = (struct fdbt_resp_query *)req;
+ *entry_id = le32_to_cpu(resp->entry_id);
+ }
+
+end:
+ ntmp_free_data_mem(&data);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ntmp_fdbt_add_entry);
+
+/**
+ * ntmp_fdbt_update_entry - update the configuration element data of the
+ * specified FDB entry
+ * @user: target ntmp_user struct
+ * @entry_id: the specified entry ID of the FDB table
+ * @cfge: configuration element data
+ *
+ * Return: 0 on success, otherwise a negative error code
+ */
+int ntmp_fdbt_update_entry(struct ntmp_user *user, u32 entry_id,
+ const struct fdbt_cfge_data *cfge)
+{
+ struct ntmp_dma_buf data = {
+ .dev = user->dev,
+ .size = sizeof(struct fdbt_req_ua),
+ };
+ struct fdbt_req_ua *req;
+ union netc_cbd cbd;
+ u32 len;
+ int err;
+
+ err = ntmp_alloc_data_mem(&data, (void **)&req);
+ if (err)
+ return err;
+
+ /* Request data */
+ ntmp_fill_crd(&req->crd, user->tbl.fdbt_ver, 0, NTMP_GEN_UA_CFGEU);
+ req->ak.eid.entry_id = cpu_to_le32(entry_id);
+ req->cfge = *cfge;
+
+ /* Request header */
+ len = NTMP_LEN(data.size, NTMP_STATUS_RESP_LEN);
+ ntmp_fill_request_hdr(&cbd, data.dma, len, NTMP_FDBT_ID,
+ NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
+ err = netc_xmit_ntmp_cmd(user, &cbd);
+ if (err)
+ dev_err(user->dev, "Failed to update %s entry, err: %pe\n",
+ ntmp_table_name(NTMP_FDBT_ID), ERR_PTR(err));
+
+ ntmp_free_data_mem(&data);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ntmp_fdbt_update_entry);
+
+/**
+ * ntmp_fdbt_delete_entry - delete the specified FDB entry
+ * @user: target ntmp_user struct
+ * @entry_id: the specified ID of the FDB entry
+ *
+ * Return: 0 on success, otherwise a negative error code
+ */
+int ntmp_fdbt_delete_entry(struct ntmp_user *user, u32 entry_id)
+{
+ u32 req_len = sizeof(struct fdbt_req_qd);
+
+ return ntmp_delete_entry_by_id(user, NTMP_FDBT_ID,
+ user->tbl.fdbt_ver,
+ entry_id, req_len,
+ NTMP_STATUS_RESP_LEN);
+}
+EXPORT_SYMBOL_GPL(ntmp_fdbt_delete_entry);
+
+/**
+ * ntmp_fdbt_search_port_entry - Search the FDB entry on the specified
+ * port based on RESUME_ENTRY_ID
+ * @user: target ntmp_user struct
+ * @port: the specified switch port ID
+ * @resume_entry_id: it is both an input and an output. As an input, it
+ * represents the FDB entry ID to be searched. If it is a NULL entry ID,
+ * it indicates that the first FDB entry for that port is being searched.
+ * As an output, it represents the next FDB entry ID to be searched.
+ * @entry: returned value, the response data of the searched FDB entry
+ *
+ * Return: 0 on success, otherwise a negative error code
+ */
+int ntmp_fdbt_search_port_entry(struct ntmp_user *user, int port,
+ u32 *resume_entry_id,
+ struct fdbt_entry_data *entry)
+{
+ struct ntmp_dma_buf data = {
+ .dev = user->dev,
+ .size = sizeof(struct fdbt_req_qd),
+ };
+ struct fdbt_resp_query *resp;
+ struct fdbt_req_qd *req;
+ union netc_cbd cbd;
+ u32 len;
+ int err;
+
+ err = ntmp_alloc_data_mem(&data, (void **)&req);
+ if (err)
+ return err;
+
+ /* Request data */
+ ntmp_fill_crd(&req->crd, user->tbl.fdbt_ver, 0, 0);
+ req->ak.search.resume_eid = cpu_to_le32(*resume_entry_id);
+ req->ak.search.cfge.port_bitmap = cpu_to_le32(BIT(port));
+ /* Match CFGE_DATA[PORT_BITMAP] field */
+ req->ak.search.cfge_mc = FDBT_CFGE_MC_PORT_BITMAP;
+
+ /* Request header */
+ len = NTMP_LEN(data.size, sizeof(*resp));
+ ntmp_fill_request_hdr(&cbd, data.dma, len, NTMP_FDBT_ID,
+ NTMP_CMD_QUERY, NTMP_AM_SEARCH);
+
+ err = netc_xmit_ntmp_cmd(user, &cbd);
+ if (err) {
+ dev_err(user->dev,
+ "Failed to search %s entry on port %d, err: %pe\n",
+ ntmp_table_name(NTMP_FDBT_ID), port, ERR_PTR(err));
+ goto end;
+ }
+
+ if (!cbd.resp_hdr.num_matched) {
+ entry->entry_id = NTMP_NULL_ENTRY_ID;
+ *resume_entry_id = NTMP_NULL_ENTRY_ID;
+ goto end;
+ }
+
+ resp = (struct fdbt_resp_query *)req;
+ *resume_entry_id = le32_to_cpu(resp->status);
+ entry->entry_id = le32_to_cpu(resp->entry_id);
+ entry->keye = resp->keye;
+ entry->cfge = resp->cfge;
+ entry->acte = resp->acte;
+
+end:
+ ntmp_free_data_mem(&data);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ntmp_fdbt_search_port_entry);
+
MODULE_DESCRIPTION("NXP NETC Library");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 34394e40fddd..9e2a18cf3507 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -11,6 +11,7 @@
#include <linux/fsl/ntmp.h>

#define NTMP_EID_REQ_LEN 8
+#define NTMP_STATUS_RESP_LEN 4
#define NETC_CBDR_BD_NUM 256

union netc_cbd {
@@ -27,6 +28,7 @@ union netc_cbd {
#define NTMP_CMD_QUERY BIT(2)
#define NTMP_CMD_ADD BIT(3)
#define NTMP_CMD_QU (NTMP_CMD_QUERY | NTMP_CMD_UPDATE)
+#define NTMP_CMD_AQ (NTMP_CMD_ADD | NTMP_CMD_QUERY)
u8 access_method;
#define NTMP_ACCESS_METHOD GENMASK(7, 4)
#define NTMP_AM_ENTRY_ID 0
@@ -101,4 +103,61 @@ struct rsst_req_update {
u8 groups[];
};

+/* Access Key Format of FDB Table */
+struct fdbt_ak_eid {
+ __le32 entry_id;
+ __le32 resv[7];
+};
+
+struct fdbt_ak_exact {
+ struct fdbt_keye_data keye;
+ __le32 resv[5];
+};
+
+struct fdbt_ak_search {
+ __le32 resume_eid;
+ struct fdbt_keye_data keye;
+ struct fdbt_cfge_data cfge;
+ u8 acte;
+ u8 keye_mc;
+#define FDBT_KEYE_MAC GENMASK(1, 0)
+ u8 cfge_mc;
+#define FDBT_CFGE_MC GENMASK(2, 0)
+#define FDBT_CFGE_MC_ANY 0
+#define FDBT_CFGE_MC_DYNAMIC 1
+#define FDBT_CFGE_MC_PORT_BITMAP 2
+#define FDBT_CFGE_MC_DYNAMIC_AND_PORT_BITMAP 3
+ u8 acte_mc;
+#define FDBT_ACTE_MC BIT(0)
+};
+
+union fdbt_access_key {
+ struct fdbt_ak_eid eid;
+ struct fdbt_ak_exact exact;
+ struct fdbt_ak_search search;
+};
+
+/* FDB Table Request Data Buffer Format of Update and Add actions */
+struct fdbt_req_ua {
+ struct ntmp_cmn_req_data crd;
+ union fdbt_access_key ak;
+ struct fdbt_cfge_data cfge;
+};
+
+/* FDB Table Request Data Buffer Format of Query and Delete actions */
+struct fdbt_req_qd {
+ struct ntmp_cmn_req_data crd;
+ union fdbt_access_key ak;
+};
+
+/* FDB Table Response Data Buffer Format of Query action */
+struct fdbt_resp_query {
+ __le32 status;
+ __le32 entry_id;
+ struct fdbt_keye_data keye;
+ struct fdbt_cfge_data cfge;
+ u8 acte;
+ u8 resv[3];
+};
+
#endif
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
index 916dc4fe7de3..ba56d4ae0ff4 100644
--- a/include/linux/fsl/ntmp.h
+++ b/include/linux/fsl/ntmp.h
@@ -6,6 +6,8 @@
#include <linux/bitops.h>
#include <linux/if_ether.h>

+#define NTMP_NULL_ENTRY_ID 0xffffffffU
+
struct maft_keye_data {
u8 mac_addr[ETH_ALEN];
__le16 resv;
@@ -29,6 +31,7 @@ struct netc_cbdr_regs {
struct netc_tbl_vers {
u8 maft_ver;
u8 rsst_ver;
+ u8 fdbt_ver;
};

struct netc_cbdr {
@@ -61,6 +64,36 @@ struct maft_entry_data {
struct maft_cfge_data cfge;
};

+struct fdbt_keye_data {
+ u8 mac_addr[ETH_ALEN]; /* big-endian */
+ __le16 resv0;
+ __le16 fid;
+#define FDBT_FID GENMASK(11, 0)
+ __le16 resv1;
+};
+
+struct fdbt_cfge_data {
+ __le32 port_bitmap;
+#define FDBT_PORT_BITMAP GENMASK(23, 0)
+ __le32 cfg;
+#define FDBT_OETEID GENMASK(1, 0)
+#define FDBT_EPORT GENMASK(6, 2)
+#define FDBT_IMIRE BIT(7)
+#define FDBT_CTD GENMASK(10, 9)
+#define FDBT_DYNAMIC BIT(11)
+#define FDBT_TIMECAPE BIT(12)
+ __le32 et_eid;
+};
+
+struct fdbt_entry_data {
+ u32 entry_id;
+ struct fdbt_keye_data keye;
+ struct fdbt_cfge_data cfge;
+ u8 acte;
+#define FDBT_ACT_CNT GENMASK(6, 0)
+#define FDBT_ACT_FLAG BIT(7)
+};
+
#if IS_ENABLED(CONFIG_NXP_NETC_LIB)
int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
const struct netc_cbdr_regs *regs);
@@ -76,6 +109,15 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
int count);
int ntmp_rsst_query_entry(struct ntmp_user *user,
u32 *table, int count);
+int ntmp_fdbt_add_entry(struct ntmp_user *user, u32 *entry_id,
+ const struct fdbt_keye_data *keye,
+ const struct fdbt_cfge_data *cfge);
+int ntmp_fdbt_update_entry(struct ntmp_user *user, u32 entry_id,
+ const struct fdbt_cfge_data *cfge);
+int ntmp_fdbt_delete_entry(struct ntmp_user *user, u32 entry_id);
+int ntmp_fdbt_search_port_entry(struct ntmp_user *user, int port,
+ u32 *resume_entry_id,
+ struct fdbt_entry_data *entry);
#else
static inline int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
const struct netc_cbdr_regs *regs)
@@ -116,6 +158,31 @@ static inline int ntmp_rsst_query_entry(struct ntmp_user *user,
return 0;
}

+static inline int ntmp_fdbt_add_entry(struct ntmp_user *user, u32 *entry_id,
+ const struct fdbt_keye_data *keye,
+ const struct fdbt_cfge_data *data)
+{
+ return 0;
+}
+
+static inline int ntmp_fdbt_update_entry(struct ntmp_user *user, u32 entry_id,
+ const struct fdbt_cfge_data *cfge)
+{
+ return 0;
+}
+
+static inline int ntmp_fdbt_delete_entry(struct ntmp_user *user, u32 entry_id)
+{
+ return 0;
+}
+
+static inline int ntmp_fdbt_search_port_entry(struct ntmp_user *user, int port,
+ u32 *resume_entry_id,
+ struct fdbt_entry_data *entry)
+{
+ return 0;
+}
+
#endif

#endif
--
2.34.1