Merge branch 'net-dsa-netc-add-bridge-mode-support'

Wei Fang says:

====================
net: dsa: netc: add bridge mode support

This series adds bridge mode support to the NETC DSA switch driver,
covering both VLAN-aware and VLAN-unaware operation.

The NETC switch manages forwarding through a set of hardware tables
accessed via NTMP: the FDB table (FDBT), VLAN filter table (VFT), egress
treatment table (ETT), and egress count table (ECT). The series extends
the NTMP layer with the operations required for bridging, then builds the
DSA bridge callbacks on top.

Since all switch ports share the VFT, so only one VLAN-aware bridge is
supported.

FDB aging is managed in software. A periodic delayed work sweeps the
table using the hardware activity element mechanism, with a default aging
time of 300 seconds matching the IEEE 802.1Q standard. Per-port entries
are also flushed immediately on bridge leave and link-down events.
====================

Link: https://patch.msgid.link/20260611021458.2629145-1-wei.fang@oss.nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-06-15 14:32:45 -07:00
commit f34c6b3a3c
6 changed files with 1499 additions and 26 deletions

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
#define NETC_MAX_FRAME_LEN 9600
#define NETC_STANDALONE_PVID 0
#define NETC_VLAN_UNAWARE_PVID(br_id) (4096 - (br_id))
/* Threshold format: MANT (bits 11:4) * 2^EXP (bits 3:0)
* Unit: Memory words (average of 20 bytes each)
@ -49,6 +50,9 @@
/* PAUSE refresh threshold: send refresh when timer reaches this value */
#define NETC_PAUSE_THRESH 0x7FFF
#define NETC_FDBT_AGEING_DELAY (3 * HZ)
#define NETC_FDBT_AGEING_THRESH 100
struct netc_switch;
struct netc_switch_info {
@ -74,10 +78,12 @@ struct netc_port {
struct dsa_port *dp;
struct clk *ref_clk; /* RGMII/RMII reference clock */
struct mii_bus *emdio;
int ett_offset;
u16 enable:1;
u16 uc:1;
u16 mc:1;
u16 pvid;
struct ipft_entry_data *host_flood;
};
@ -94,6 +100,14 @@ struct netc_fdb_entry {
struct hlist_node node;
};
struct netc_vlan_entry {
u16 vid;
u32 ect_gid;
u32 untagged_port_bitmap;
struct vft_cfge_data cfge;
struct hlist_node node;
};
struct netc_port_stat {
int reg;
char name[ETH_GSTRING_LEN] __nonstring;
@ -108,10 +122,17 @@ struct netc_switch {
const struct netc_switch_info *info;
struct netc_switch_regs regs;
struct netc_port **ports;
u32 port_bitmap; /* bitmap of available ports */
struct ntmp_user ntmp;
struct hlist_head fdb_list;
struct mutex fdbt_lock; /* FDB table lock */
struct delayed_work fdbt_ageing_work;
/* (fdbt_ageing_delay * NETC_FDBT_AGEING_THRESH) is ageing time */
unsigned long fdbt_ageing_delay;
atomic_t br_cnt;
struct hlist_head vlan_list;
struct mutex vft_lock; /* VLAN filter table lock */
/* Switch hardware capabilities */
u32 htmcapr_num_words;
@ -153,6 +174,18 @@ static inline void netc_del_fdb_entry(struct netc_fdb_entry *entry)
kfree(entry);
}
static inline void netc_add_vlan_entry(struct netc_switch *priv,
struct netc_vlan_entry *entry)
{
hlist_add_head(&entry->node, &priv->vlan_list);
}
static inline void netc_del_vlan_entry(struct netc_vlan_entry *entry)
{
hlist_del(&entry->node);
kfree(entry);
}
int netc_switch_platform_probe(struct netc_switch *priv);
/* ethtool APIs */

View File

@ -36,6 +36,12 @@
#define DOSL3CR_SAMEADDR BIT(0)
#define DOSL3CR_IPSAMCC BIT(1)
#define NETC_ETTCAPR 0x18c4
#define NETC_ECTCAPR 0x18ec
/* Index table NUM_ENTRIES mask */
#define NETC_NUM_ENTRIES GENMASK(15, 0)
#define NETC_GET_NUM_ENTRIES(v) FIELD_GET(NETC_NUM_ENTRIES, (v))
/* Hash table memory capability register, the memory is shared by
* the following tables:
*

View File

@ -24,6 +24,8 @@
#define NTMP_IPFT_ID 13
#define NTMP_FDBT_ID 15
#define NTMP_VFT_ID 18
#define NTMP_ETT_ID 33
#define NTMP_ECT_ID 39
#define NTMP_BPT_ID 41
/* Generic Update Actions for most tables */
@ -31,6 +33,8 @@
#define NTMP_GEN_UA_STSEU BIT(1)
/* Specific Update Actions for some tables */
#define FDBT_UA_ACTEU BIT(1)
#define ECT_UA_STSEU BIT(0)
#define BPT_UA_BPSEU BIT(1)
/* Query Action: 0: Full query. 1: Query entry ID, the fields after entry
@ -43,6 +47,30 @@
#define RSST_STSE_DATA_SIZE(n) ((n) * 8)
#define RSST_CFGE_DATA_SIZE(n) (n)
u32 ntmp_lookup_free_eid(unsigned long *bitmap, u32 size)
{
u32 entry_id;
entry_id = find_first_zero_bit(bitmap, size);
if (entry_id == size)
return NTMP_NULL_ENTRY_ID;
/* Set the bit once we found it */
__set_bit(entry_id, bitmap);
return entry_id;
}
EXPORT_SYMBOL_GPL(ntmp_lookup_free_eid);
void ntmp_clear_eid_bitmap(unsigned long *bitmap, u32 entry_id)
{
if (entry_id == NTMP_NULL_ENTRY_ID)
return;
__clear_bit(entry_id, bitmap);
}
EXPORT_SYMBOL_GPL(ntmp_clear_eid_bitmap);
int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
const struct netc_cbdr_regs *regs)
{
@ -283,6 +311,10 @@ static const char *ntmp_table_name(int tbl_id)
return "FDB Table";
case NTMP_VFT_ID:
return "VLAN Filter Table";
case NTMP_ETT_ID:
return "Egress Treatment Table";
case NTMP_ECT_ID:
return "Egress Count Table";
case NTMP_BPT_ID:
return "Buffer Pool Table";
default:
@ -794,18 +826,26 @@ int ntmp_fdbt_search_port_entry(struct ntmp_user *user, int port,
EXPORT_SYMBOL_GPL(ntmp_fdbt_search_port_entry);
/**
* ntmp_vft_add_entry - add an entry into the VLAN filter table
* ntmp_fdbt_update_activity_element - update the activity element of all
* the dynamic entries in the FDB table.
* @user: target ntmp_user struct
* @vid: VLAN ID
* @cfge: configuration element data
*
* A single activity update management could be used to process all the
* dynamic entries in the FDB table. When hardware process an activity
* update management command for an entry in the FDB table and the entry
* does not have its activity flag set, the activity counter is incremented.
* However, if the activity flag is set, then both the activity flag and
* activity counter are reset. Software can issue the activity update
* management commands at predefined times and the value of the activity
* counter can then be used to estimate the period of how long an FDB
* entry has been inactive.
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_vft_add_entry(struct ntmp_user *user, u16 vid,
const struct vft_cfge_data *cfge)
int ntmp_fdbt_update_activity_element(struct ntmp_user *user)
{
struct fdbt_req_ua *req;
struct netc_swcbd swcbd;
struct vft_req_ua *req;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
u32 len;
@ -817,28 +857,414 @@ int ntmp_vft_add_entry(struct ntmp_user *user, u16 vid,
return err;
/* Request data */
ntmp_fill_crd(&req->crd, user->tbl.vft_ver, 0,
NTMP_GEN_UA_CFGEU);
ntmp_fill_crd(&req->crd, user->tbl.fdbt_ver, 0, FDBT_UA_ACTEU);
req->ak.search.resume_eid = cpu_to_le32(NTMP_NULL_ENTRY_ID);
req->ak.search.cfge.cfg = cpu_to_le32(FDBT_DYNAMIC);
req->ak.search.cfge_mc = FDBT_CFGE_MC_DYNAMIC;
/* Request header */
len = NTMP_LEN(swcbd.size, NTMP_STATUS_RESP_LEN);
/* For activity update, the access method must be search */
ntmp_fill_request_hdr(&cbd, swcbd.dma, len, NTMP_FDBT_ID,
NTMP_CMD_UPDATE, NTMP_AM_SEARCH);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to update activity of %s, err: %pe\n",
ntmp_table_name(NTMP_FDBT_ID), ERR_PTR(err));
ntmp_unlock_cbdr(cbdr);
return err;
}
EXPORT_SYMBOL_GPL(ntmp_fdbt_update_activity_element);
/**
* ntmp_fdbt_delete_ageing_entries - delete all the ageing dynamic entries
* in the FDB table
* @user: target ntmp_user struct
* @act_cnt: the target value of the activity counter
*
* The matching rule is that the activity flag is not set and the activity
* counter is greater than or equal to act_cnt
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_fdbt_delete_ageing_entries(struct ntmp_user *user, u8 act_cnt)
{
struct fdbt_req_qd *req;
struct netc_swcbd swcbd;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
u32 len;
int err;
if (act_cnt > FDBT_ACT_CNT)
return -EINVAL;
swcbd.size = sizeof(*req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (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(NTMP_NULL_ENTRY_ID);
req->ak.search.cfge.cfg = cpu_to_le32(FDBT_DYNAMIC);
req->ak.search.acte = act_cnt;
/* Exact match with ACTE_DATA[ACT_FLAG] AND
* match >= ACTE_DATA[ACT_CNT]
*/
req->ak.search.acte_mc = FDBT_ACTE_MC;
req->ak.search.cfge_mc = FDBT_CFGE_MC_DYNAMIC;
/* Request header */
len = NTMP_LEN(swcbd.size, NTMP_STATUS_RESP_LEN);
ntmp_fill_request_hdr(&cbd, swcbd.dma, len, NTMP_FDBT_ID,
NTMP_CMD_DELETE, NTMP_AM_SEARCH);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to delete ageing entries of %s, err: %pe\n",
ntmp_table_name(NTMP_FDBT_ID), ERR_PTR(err));
ntmp_unlock_cbdr(cbdr);
return err;
}
EXPORT_SYMBOL_GPL(ntmp_fdbt_delete_ageing_entries);
/**
* ntmp_fdbt_delete_port_dynamic_entries - delete all dynamic FDB entries
* associated with the specified switch port
* @user: target ntmp_user struct
* @port: the specified switch port ID
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_fdbt_delete_port_dynamic_entries(struct ntmp_user *user, int port)
{
struct fdbt_req_qd *req;
struct netc_swcbd swcbd;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
u32 len;
int err;
swcbd.size = sizeof(*req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (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(NTMP_NULL_ENTRY_ID);
req->ak.search.cfge.port_bitmap = cpu_to_le32(BIT(port));
req->ak.search.cfge.cfg = cpu_to_le32(FDBT_DYNAMIC);
/* Match CFGE_DATA[DYNAMIC & PORT_BITMAP] field */
req->ak.search.cfge_mc = FDBT_CFGE_MC_DYNAMIC_AND_PORT_BITMAP;
/* Request header */
len = NTMP_LEN(swcbd.size, NTMP_STATUS_RESP_LEN);
ntmp_fill_request_hdr(&cbd, swcbd.dma, len, NTMP_FDBT_ID,
NTMP_CMD_DELETE, NTMP_AM_SEARCH);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to delete dynamic %s entries on port %d, err: %pe\n",
ntmp_table_name(NTMP_FDBT_ID), port, ERR_PTR(err));
ntmp_unlock_cbdr(cbdr);
return err;
}
EXPORT_SYMBOL_GPL(ntmp_fdbt_delete_port_dynamic_entries);
/**
* ntmp_vft_set_entry - add an entry into the VLAN filter table or update
* the configuration element data of the specified VLAN filter entry
* @user: target ntmp_user struct
* @vid: VLAN ID
* @cmd: command type, NTMP_CMD_ADD or NTMP_CMD_UPDATE
* @cfge: configuration element data
*
* Return: 0 on success, otherwise a negative error code
*/
static int ntmp_vft_set_entry(struct ntmp_user *user, u16 vid, int cmd,
const struct vft_cfge_data *cfge)
{
struct netc_swcbd swcbd;
struct vft_req_ua *req;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
u32 len;
int err;
if (cmd != NTMP_CMD_ADD && cmd != NTMP_CMD_UPDATE)
return -EINVAL;
swcbd.size = sizeof(*req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Request data */
ntmp_fill_crd(&req->crd, user->tbl.vft_ver, 0, NTMP_GEN_UA_CFGEU);
req->ak.exact.vid = cpu_to_le16(vid);
req->cfge = *cfge;
/* Request header */
len = NTMP_LEN(swcbd.size, NTMP_STATUS_RESP_LEN);
ntmp_fill_request_hdr(&cbd, swcbd.dma, len, NTMP_VFT_ID,
NTMP_CMD_ADD, NTMP_AM_EXACT_KEY);
cmd, NTMP_AM_EXACT_KEY);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
ntmp_unlock_cbdr(cbdr);
return err;
}
/**
* ntmp_vft_add_entry - add an entry into the VLAN filter table
* @user: target ntmp_user struct
* @vid: VLAN ID
* @cfge: configuration element data
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_vft_add_entry(struct ntmp_user *user, u16 vid,
const struct vft_cfge_data *cfge)
{
int err;
err = ntmp_vft_set_entry(user, vid, NTMP_CMD_ADD, cfge);
if (err)
dev_err(user->dev,
"Failed to add %s entry, vid: %u, err: %pe\n",
ntmp_table_name(NTMP_VFT_ID), vid, ERR_PTR(err));
return err;
}
EXPORT_SYMBOL_GPL(ntmp_vft_add_entry);
/**
* ntmp_vft_update_entry - update the configuration element data of the
* specified VLAN filter entry
* @user: target ntmp_user struct
* @vid: VLAN ID
* @cfge: configuration element data
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_vft_update_entry(struct ntmp_user *user, u16 vid,
const struct vft_cfge_data *cfge)
{
int err;
err = ntmp_vft_set_entry(user, vid, NTMP_CMD_UPDATE, cfge);
if (err)
dev_err(user->dev,
"Failed to update %s entry, vid: %u, err: %pe\n",
ntmp_table_name(NTMP_VFT_ID), vid, ERR_PTR(err));
return err;
}
EXPORT_SYMBOL_GPL(ntmp_vft_update_entry);
/**
* ntmp_vft_delete_entry - delete the VLAN filter entry based on the
* specified VLAN ID
* @user: target ntmp_user struct
* @vid: VLAN ID
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_vft_delete_entry(struct ntmp_user *user, u16 vid)
{
struct netc_swcbd swcbd;
struct vft_req_qd *req;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
u32 len;
int err;
swcbd.size = sizeof(*req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Request data */
ntmp_fill_crd(&req->crd, user->tbl.vft_ver, 0, 0);
req->ak.exact.vid = cpu_to_le16(vid);
/* Request header */
len = NTMP_LEN(swcbd.size, NTMP_STATUS_RESP_LEN);
ntmp_fill_request_hdr(&cbd, swcbd.dma, len, NTMP_VFT_ID,
NTMP_CMD_DELETE, NTMP_AM_EXACT_KEY);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to add %s entry, vid: %u, err: %pe\n",
"Failed to delete %s entry, vid: %u, err: %pe\n",
ntmp_table_name(NTMP_VFT_ID), vid, ERR_PTR(err));
ntmp_unlock_cbdr(cbdr);
return err;
}
EXPORT_SYMBOL_GPL(ntmp_vft_add_entry);
EXPORT_SYMBOL_GPL(ntmp_vft_delete_entry);
/**
* ntmp_ett_set_entry - add a new entry to the egress treatment table or
* update the configuration element data of the specified entry
* @user: target ntmp_user struct
* @entry_id: entry ID
* @cmd: command type, NTMP_CMD_ADD or NTMP_CMD_UPDATE
* @cfge: configuration element data
*
* Return: 0 on success, otherwise a negative error code
*/
static int ntmp_ett_set_entry(struct ntmp_user *user, u32 entry_id,
int cmd, const struct ett_cfge_data *cfge)
{
struct netc_swcbd swcbd;
struct ett_req_ua *req;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err;
if (cmd != NTMP_CMD_ADD && cmd != NTMP_CMD_UPDATE)
return -EINVAL;
swcbd.size = sizeof(*req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Request data */
ntmp_fill_crd_eid(&req->rbe, user->tbl.ett_ver, 0,
NTMP_GEN_UA_CFGEU, entry_id);
req->cfge = *cfge;
/* Request header */
ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_ETT_ID, cmd, NTMP_AM_ENTRY_ID);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
ntmp_unlock_cbdr(cbdr);
return err;
}
/**
* ntmp_ett_add_entry - add a new entry to the egress treatment table
* @user: target ntmp_user struct
* @entry_id: entry ID
* @cfge: configuration element data
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_ett_add_entry(struct ntmp_user *user, u32 entry_id,
const struct ett_cfge_data *cfge)
{
int err;
err = ntmp_ett_set_entry(user, entry_id, NTMP_CMD_ADD, cfge);
if (err)
dev_err(user->dev, "Failed to add %s entry 0x%x, err: %pe\n",
ntmp_table_name(NTMP_ETT_ID), entry_id, ERR_PTR(err));
return err;
}
EXPORT_SYMBOL_GPL(ntmp_ett_add_entry);
/**
* ntmp_ett_update_entry - update the configuration element data of the
* specified entry
* @user: target ntmp_user struct
* @entry_id: entry ID
* @cfge: configuration element data
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_ett_update_entry(struct ntmp_user *user, u32 entry_id,
const struct ett_cfge_data *cfge)
{
int err;
err = ntmp_ett_set_entry(user, entry_id, NTMP_CMD_UPDATE, cfge);
if (err)
dev_err(user->dev,
"Failed to update %s entry 0x%x, err: %pe\n",
ntmp_table_name(NTMP_ETT_ID), entry_id, ERR_PTR(err));
return err;
}
EXPORT_SYMBOL_GPL(ntmp_ett_update_entry);
/**
* ntmp_ett_delete_entry - delete the specified egress treatment table entry
* @user: target ntmp_user struct
* @entry_id: entry ID
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_ett_delete_entry(struct ntmp_user *user, u32 entry_id)
{
return ntmp_delete_entry_by_id(user, NTMP_ETT_ID, user->tbl.ett_ver,
entry_id, NTMP_EID_REQ_LEN, 0);
}
EXPORT_SYMBOL_GPL(ntmp_ett_delete_entry);
/**
* ntmp_ect_update_entry - reset the statistics element data of the
* specified egress counter table entry
* @user: target ntmp_user struct
* @entry_id: entry ID
*
* Return: 0 on success, otherwise a negative error code
*/
int ntmp_ect_update_entry(struct ntmp_user *user, u32 entry_id)
{
struct ntmp_req_by_eid *req;
struct netc_swcbd swcbd;
struct netc_cbdr *cbdr;
union netc_cbd cbd;
int err;
swcbd.size = sizeof(*req);
err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req);
if (err)
return err;
/* Request data */
ntmp_fill_crd_eid(req, user->tbl.ect_ver, 0, ECT_UA_STSEU, entry_id);
/* Request header */
ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0),
NTMP_ECT_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
ntmp_select_and_lock_cbdr(user, &cbdr);
err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd);
if (err)
dev_err(user->dev,
"Failed to update %s entry 0x%x, err: %pe\n",
ntmp_table_name(NTMP_ECT_ID), entry_id, ERR_PTR(err));
ntmp_unlock_cbdr(cbdr);
return err;
}
EXPORT_SYMBOL_GPL(ntmp_ect_update_entry);
int ntmp_bpt_update_entry(struct ntmp_user *user, u32 entry_id,
const struct bpt_cfge_data *cfge)

View File

@ -155,8 +155,8 @@ struct fdbt_ak_search {
#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_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;
@ -211,6 +211,20 @@ struct vft_req_ua {
struct vft_cfge_data cfge;
};
/* VLAN Filter Table Request Data Buffer Format of Query and Delete actions */
struct vft_req_qd {
struct ntmp_cmn_req_data crd;
union vft_access_key ak;
};
/* Egress Treatment Table Request Data Buffer Format of Update and Add
* actions
*/
struct ett_req_ua {
struct ntmp_req_by_eid rbe;
struct ett_cfge_data cfge;
};
/* Buffer Pool Table Request Data Buffer Format of Update action */
struct bpt_req_update {
struct ntmp_req_by_eid rbe;

View File

@ -3,6 +3,7 @@
#ifndef __NETC_NTMP_H
#define __NETC_NTMP_H
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/if_ether.h>
@ -36,6 +37,8 @@ struct netc_tbl_vers {
u8 vft_ver;
u8 bpt_ver;
u8 ipft_ver;
u8 ett_ver;
u8 ect_ver;
};
struct netc_swcbd {
@ -68,6 +71,12 @@ struct ntmp_user {
struct device *dev;
struct netc_cbdr *ring;
struct netc_tbl_vers tbl;
/* NTMP table bitmaps for resource management */
u32 ett_bitmap_size;
u32 ect_bitmap_size;
unsigned long *ett_gid_bitmap; /* only valid for switch */
unsigned long *ect_gid_bitmap; /* only valid for switch */
};
struct maft_entry_data {
@ -214,6 +223,23 @@ struct vft_cfge_data {
__le32 et_eid;
};
struct ett_cfge_data {
__le16 efm_cfg;
#define ETT_EFM_MODE GENMASK(1, 0)
#define ETT_ESQA GENMASK(5, 4)
#define ETT_ECA GENMASK(8, 6)
#define ETT_ECA_INC 1
#define ETT_EFM_LEN_CHANGE GENMASK(15, 9)
#define ETT_FRM_LEN_DEL_VLAN 0x7c
#define ETT_FRM_LEN_DEL_RTAG 0x7a
#define ETT_FRM_LEN_DEL_VLAN_RTAG 0x76
__le16 efm_data_len;
#define ETT_EFM_DATA_LEN GENMASK(10, 0)
__le32 efm_eid;
__le32 ec_eid;
__le32 esqa_tgt_eid;
};
struct bpt_bpse_data {
__le32 amount_used;
__le32 amount_used_hwm;
@ -236,10 +262,27 @@ struct bpt_cfge_data {
__le32 fc_ports;
};
union ntmp_fmt_eid {
__le32 index;
#define FMTEID_INDEX GENMASK(12, 0)
__le32 vuda_sqta;
#define FMTEID_VUDA GENMASK(1, 0)
#define FMTEID_VUDA_DEL_OTAG 2
#define FMTEID_SQTA GENMASK(4, 2)
#define FMTEID_SQTA_DEL 2
#define FMTEID_VUDA_SQTA BIT(13)
__le32 vara_vid;
#define FMTEID_VID GENMASK(11, 0)
#define FMTEID_VARA GENMASK(13, 12)
#define FMTEID_VARA_VID BIT(14)
};
#if IS_ENABLED(CONFIG_NXP_NETC_LIB)
int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
const struct netc_cbdr_regs *regs);
void ntmp_free_cbdr(struct netc_cbdr *cbdr);
u32 ntmp_lookup_free_eid(unsigned long *bitmap, u32 size);
void ntmp_clear_eid_bitmap(unsigned long *bitmap, u32 entry_id);
/* NTMP APIs */
int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
@ -263,8 +306,20 @@ 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);
int ntmp_fdbt_update_activity_element(struct ntmp_user *user);
int ntmp_fdbt_delete_ageing_entries(struct ntmp_user *user, u8 act_cnt);
int ntmp_fdbt_delete_port_dynamic_entries(struct ntmp_user *user, int port);
int ntmp_vft_add_entry(struct ntmp_user *user, u16 vid,
const struct vft_cfge_data *cfge);
int ntmp_vft_update_entry(struct ntmp_user *user, u16 vid,
const struct vft_cfge_data *cfge);
int ntmp_vft_delete_entry(struct ntmp_user *user, u16 vid);
int ntmp_ett_add_entry(struct ntmp_user *user, u32 entry_id,
const struct ett_cfge_data *cfge);
int ntmp_ett_update_entry(struct ntmp_user *user, u32 entry_id,
const struct ett_cfge_data *cfge);
int ntmp_ett_delete_entry(struct ntmp_user *user, u32 entry_id);
int ntmp_ect_update_entry(struct ntmp_user *user, u32 entry_id);
int ntmp_bpt_update_entry(struct ntmp_user *user, u32 entry_id,
const struct bpt_cfge_data *cfge);
#else