This patch expands the NETC switch driver with several foundational
features, including FDB and MDB management, STP state handling, MTU
configuration, port setup/teardown, and host flooding support.

At this stage, the driver operates only in standalone port mode. Each
port uses VLAN 0 as its PVID, meaning ingress frames are internally
assigned VID 0 regardless of whether they arrive tagged or untagged.
Note that this does not inject a VLAN 0 header into the frame, the VID
is used purely for subsequent VLAN processing within the switch.

Signed-off-by: Wei Fang <[email protected]>
---
 drivers/net/dsa/netc/netc_main.c      | 531 ++++++++++++++++++++++++++
 drivers/net/dsa/netc/netc_switch.h    |  33 ++
 drivers/net/dsa/netc/netc_switch_hw.h |  11 +
 3 files changed, 575 insertions(+)

diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
index 884ee899fc89..fd952b507cbd 100644
--- a/drivers/net/dsa/netc/netc_main.c
+++ b/drivers/net/dsa/netc/netc_main.c
@@ -7,11 +7,36 @@
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
 #include <linux/fsl/enetc_mdio.h>
+#include <linux/if_bridge.h>
 #include <linux/if_vlan.h>
 #include <linux/of_mdio.h>
 
 #include "netc_switch.h"
 
+static struct netc_fdb_entry *
+netc_lookup_fdb_entry(struct netc_switch *priv,
+                     const unsigned char *addr,
+                     u16 vid)
+{
+       struct netc_fdb_entry *entry;
+
+       hlist_for_each_entry(entry, &priv->fdb_list, node)
+               if (ether_addr_equal(entry->keye.mac_addr, addr) &&
+                   le16_to_cpu(entry->keye.fid) == vid)
+                       return entry;
+
+       return NULL;
+}
+
+static void netc_destroy_fdb_list(struct netc_switch *priv)
+{
+       struct netc_fdb_entry *entry;
+       struct hlist_node *tmp;
+
+       hlist_for_each_entry_safe(entry, tmp, &priv->fdb_list, node)
+               netc_del_fdb_entry(entry);
+}
+
 static enum dsa_tag_protocol
 netc_get_tag_protocol(struct dsa_switch *ds, int port,
                      enum dsa_tag_protocol mprot)
@@ -409,6 +434,212 @@ static void netc_port_default_config(struct netc_port *np)
        netc_port_rmw(np, NETC_POR, PCR_TXDIS, 0);
 }
 
+static u32 netc_available_port_bitmap(struct netc_switch *priv)
+{
+       struct dsa_port *dp;
+       u32 bitmap = 0;
+
+       dsa_switch_for_each_available_port(dp, priv->ds)
+               bitmap |= BIT(dp->index);
+
+       return bitmap;
+}
+
+static int netc_add_standalone_vlan_entry(struct netc_switch *priv)
+{
+       u32 bitmap_stg = VFT_STG_ID(0) | netc_available_port_bitmap(priv);
+       struct vft_cfge_data *cfge;
+       u16 cfg;
+       int err;
+
+       cfge = kzalloc_obj(*cfge);
+       if (!cfge)
+               return -ENOMEM;
+
+       cfge->bitmap_stg = cpu_to_le32(bitmap_stg);
+       cfge->et_eid = cpu_to_le32(NTMP_NULL_ENTRY_ID);
+       cfge->fid = cpu_to_le16(NETC_STANDALONE_PVID);
+
+       /* For standalone ports, MAC learning needs to be disabled, so frames
+        * from other user ports will not be forwarded to the standalone ports,
+        * because there are no FDB entries on the standalone ports. Also, the
+        * frames received by the standalone ports cannot be flooded to other
+        * ports, so MAC forwarding option needs to be set to
+        * MFO_NO_MATCH_DISCARD, so the frames will discarded rather than
+        * flooding to other ports.
+        */
+       cfg = FIELD_PREP(VFT_MLO, MLO_DISABLE) |
+             FIELD_PREP(VFT_MFO, MFO_NO_MATCH_DISCARD);
+       cfge->cfg = cpu_to_le16(cfg);
+
+       err = ntmp_vft_add_entry(&priv->ntmp, NETC_STANDALONE_PVID, cfge);
+       if (err)
+               dev_err(priv->dev,
+                       "Failed to add standalone VLAN entry\n");
+
+       kfree(cfge);
+
+       return err;
+}
+
+static int netc_port_add_fdb_entry(struct netc_port *np,
+                                  const unsigned char *addr, u16 vid)
+{
+       struct netc_switch *priv = np->switch_priv;
+       struct netc_fdb_entry *entry;
+       struct fdbt_keye_data *keye;
+       struct fdbt_cfge_data *cfge;
+       int port = np->dp->index;
+       u32 cfg = 0;
+       int err;
+
+       entry = kzalloc_obj(*entry);
+       if (!entry)
+               return -ENOMEM;
+
+       keye = &entry->keye;
+       cfge = &entry->cfge;
+       ether_addr_copy(keye->mac_addr, addr);
+       keye->fid = cpu_to_le16(vid);
+
+       cfge->port_bitmap = cpu_to_le32(BIT(port));
+       cfge->cfg = cpu_to_le32(cfg);
+       cfge->et_eid = cpu_to_le32(NTMP_NULL_ENTRY_ID);
+
+       err = ntmp_fdbt_add_entry(&priv->ntmp, &entry->entry_id, keye, cfge);
+       if (err) {
+               kfree(entry);
+
+               return err;
+       }
+
+       netc_add_fdb_entry(priv, entry);
+
+       return 0;
+}
+
+static int netc_port_set_fdb_entry(struct netc_port *np,
+                                  const unsigned char *addr, u16 vid)
+{
+       struct netc_switch *priv = np->switch_priv;
+       struct netc_fdb_entry *entry;
+       int port = np->dp->index;
+       u32 port_bitmap;
+       int err = 0;
+
+       mutex_lock(&priv->fdbt_lock);
+
+       entry = netc_lookup_fdb_entry(priv, addr, vid);
+       if (!entry) {
+               err = netc_port_add_fdb_entry(np, addr, vid);
+               if (err)
+                       dev_err(priv->dev,
+                               "Failed to add FDB entry on port %d\n",
+                               port);
+
+               goto unlock_fdbt;
+       }
+
+       port_bitmap = le32_to_cpu(entry->cfge.port_bitmap);
+       /* If the entry already exists on the port, return 0 directly */
+       if (unlikely(port_bitmap & BIT(port)))
+               goto unlock_fdbt;
+
+       /* If the entry already exists, but not on this port, we need to
+        * update the port bitmap. In general, it should only be valid
+        * for multicast or broadcast address.
+        */
+       port_bitmap ^= BIT(port);
+       entry->cfge.port_bitmap = cpu_to_le32(port_bitmap);
+       err = ntmp_fdbt_update_entry(&priv->ntmp, entry->entry_id,
+                                    &entry->cfge);
+       if (err) {
+               port_bitmap ^= BIT(port);
+               entry->cfge.port_bitmap = cpu_to_le32(port_bitmap);
+               dev_err(priv->dev, "Failed to set FDB entry on port %d\n",
+                       port);
+       }
+
+unlock_fdbt:
+       mutex_unlock(&priv->fdbt_lock);
+
+       return err;
+}
+
+static int netc_port_del_fdb_entry(struct netc_port *np,
+                                  const unsigned char *addr, u16 vid)
+{
+       struct netc_switch *priv = np->switch_priv;
+       struct ntmp_user *ntmp = &priv->ntmp;
+       struct netc_fdb_entry *entry;
+       int port = np->dp->index;
+       u32 port_bitmap;
+       int err = 0;
+
+       mutex_lock(&priv->fdbt_lock);
+
+       entry = netc_lookup_fdb_entry(priv, addr, vid);
+       if (unlikely(!entry))
+               goto unlock_fdbt;
+
+       port_bitmap = le32_to_cpu(entry->cfge.port_bitmap);
+       if (unlikely(!(port_bitmap & BIT(port))))
+               goto unlock_fdbt;
+
+       if (port_bitmap != BIT(port)) {
+               /* If the entry also exists on other ports, we need to
+                * update the entry in the FDB table.
+                */
+               port_bitmap ^= BIT(port);
+               entry->cfge.port_bitmap = cpu_to_le32(port_bitmap);
+               err = ntmp_fdbt_update_entry(ntmp, entry->entry_id,
+                                            &entry->cfge);
+               if (err) {
+                       port_bitmap ^= BIT(port);
+                       entry->cfge.port_bitmap = cpu_to_le32(port_bitmap);
+                       goto unlock_fdbt;
+               }
+       } else {
+               /* If the entry only exists on this port, just delete
+                * it from the FDB table.
+                */
+               err = ntmp_fdbt_delete_entry(ntmp, entry->entry_id);
+               if (err)
+                       goto unlock_fdbt;
+
+               netc_del_fdb_entry(entry);
+       }
+
+unlock_fdbt:
+       mutex_unlock(&priv->fdbt_lock);
+
+       return err;
+}
+
+static int netc_add_standalone_fdb_bcast_entry(struct netc_switch *priv)
+{
+       const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       struct dsa_port *dp, *cpu_dp = NULL;
+
+       dsa_switch_for_each_cpu_port(dp, priv->ds) {
+               cpu_dp = dp;
+               break;
+       }
+
+       if (!cpu_dp)
+               return -ENODEV;
+
+       /* If the user port acts as a standalone port, then its PVID is 0,
+        * MLO is set to "disable MAC learning" and MFO is set to "discard
+        * frames if no matching entry found in FDB table". Therefore, we
+        * need to add a broadcast FDB entry on the CPU port so that the
+        * broadcast frames received on the user port can be forwarded to
+        * the CPU port.
+        */
+       return netc_port_set_fdb_entry(NETC_PORT(priv->ds, cpu_dp->index),
+                                      bcast, NETC_STANDALONE_PVID);
+}
+
 static int netc_setup(struct dsa_switch *ds)
 {
        struct netc_switch *priv = ds->priv;
@@ -427,24 +658,57 @@ static int netc_setup(struct dsa_switch *ds)
        if (err)
                goto free_mdio_bus;
 
+       INIT_HLIST_HEAD(&priv->fdb_list);
+       mutex_init(&priv->fdbt_lock);
+
        netc_switch_fixed_config(priv);
 
        /* default setting for ports */
        dsa_switch_for_each_available_port(dp, ds)
                netc_port_default_config(priv->ports[dp->index]);
 
+       err = netc_add_standalone_vlan_entry(priv);
+       if (err)
+               goto free_ntmp_user;
+
+       err = netc_add_standalone_fdb_bcast_entry(priv);
+       if (err)
+               goto free_ntmp_user;
+
        return 0;
 
+free_ntmp_user:
+       netc_free_ntmp_user(priv);
 free_mdio_bus:
        netc_free_mdio_bus(priv);
 
        return err;
 }
 
+static void netc_destroy_all_lists(struct netc_switch *priv)
+{
+       netc_destroy_fdb_list(priv);
+       mutex_destroy(&priv->fdbt_lock);
+}
+
+static void netc_free_host_flood_rules(struct netc_switch *priv)
+{
+       struct dsa_port *dp;
+
+       dsa_switch_for_each_user_port(dp, priv->ds) {
+               struct netc_port *np = priv->ports[dp->index];
+
+               kfree(np->host_flood);
+               np->host_flood = NULL;
+       }
+}
+
 static void netc_teardown(struct dsa_switch *ds)
 {
        struct netc_switch *priv = ds->priv;
 
+       netc_destroy_all_lists(priv);
+       netc_free_host_flood_rules(priv);
        netc_free_ntmp_user(priv);
        netc_free_mdio_bus(priv);
 }
@@ -595,6 +859,261 @@ static void netc_switch_get_ip_revision(struct 
netc_switch *priv)
        priv->revision = val & IPBRR0_IP_REV;
 }
 
+static int netc_port_enable(struct dsa_switch *ds, int port,
+                           struct phy_device *phy)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       int err;
+
+       if (np->enable)
+               return 0;
+
+       err = clk_prepare_enable(np->ref_clk);
+       if (err) {
+               dev_err(ds->dev,
+                       "Failed to enable enet_ref_clk of port %d\n", port);
+               return err;
+       }
+
+       np->enable = true;
+
+       return 0;
+}
+
+static void netc_port_disable(struct dsa_switch *ds, int port)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+
+       /* When .port_disable() is called, .port_enable() may not have been
+        * called. In this case, both the prepare_count and enable_count of
+        * clock are 0. Calling clk_disable_unprepare() at this time will
+        * cause warnings.
+        */
+       if (!np->enable)
+               return;
+
+       clk_disable_unprepare(np->ref_clk);
+       np->enable = false;
+}
+
+static void netc_port_stp_state_set(struct dsa_switch *ds,
+                                   int port, u8 state)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+       u32 val;
+
+       switch (state) {
+       case BR_STATE_DISABLED:
+       case BR_STATE_LISTENING:
+       case BR_STATE_BLOCKING:
+               val = NETC_STG_STATE_DISABLED;
+               break;
+       case BR_STATE_LEARNING:
+               val = NETC_STG_STATE_LEARNING;
+               break;
+       case BR_STATE_FORWARDING:
+               val = NETC_STG_STATE_FORWARDING;
+               break;
+       default:
+               return;
+       }
+
+       netc_port_wr(np, NETC_BPSTGSR, val);
+}
+
+static int netc_port_change_mtu(struct dsa_switch *ds,
+                               int port, int mtu)
+{
+       u32 max_frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
+       struct netc_port *np = NETC_PORT(ds, port);
+
+       if (dsa_is_cpu_port(ds, port))
+               max_frame_size += NETC_TAG_MAX_LEN;
+
+       netc_port_set_max_frame_size(np, max_frame_size);
+
+       return 0;
+}
+
+static int netc_port_max_mtu(struct dsa_switch *ds, int port)
+{
+       return NETC_MAX_FRAME_LEN - VLAN_ETH_HLEN - ETH_FCS_LEN;
+}
+
+static int netc_port_fdb_add(struct dsa_switch *ds, int port,
+                            const unsigned char *addr, u16 vid,
+                            struct dsa_db db)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+
+       /* Currently, we only support standalone port mode, so all VLANs
+        * should be converted to NETC_STANDALONE_PVID.
+        */
+       return netc_port_set_fdb_entry(np, addr, NETC_STANDALONE_PVID);
+}
+
+static int netc_port_fdb_del(struct dsa_switch *ds, int port,
+                            const unsigned char *addr, u16 vid,
+                            struct dsa_db db)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+
+       return netc_port_del_fdb_entry(np, addr, NETC_STANDALONE_PVID);
+}
+
+static int netc_port_fdb_dump(struct dsa_switch *ds, int port,
+                             dsa_fdb_dump_cb_t *cb, void *data)
+{
+       struct netc_switch *priv = ds->priv;
+       u32 resume_eid = NTMP_NULL_ENTRY_ID;
+       struct fdbt_entry_data *entry;
+       struct fdbt_keye_data *keye;
+       struct fdbt_cfge_data *cfge;
+       bool is_static;
+       u32 cfg;
+       int err;
+       u16 vid;
+
+       entry = kmalloc_obj(*entry);
+       if (!entry)
+               return -ENOMEM;
+
+       keye = &entry->keye;
+       cfge = &entry->cfge;
+       mutex_lock(&priv->fdbt_lock);
+
+       do {
+               memset(entry, 0, sizeof(*entry));
+               err = ntmp_fdbt_search_port_entry(&priv->ntmp, port,
+                                                 &resume_eid, entry);
+               if (err || entry->entry_id == NTMP_NULL_ENTRY_ID)
+                       break;
+
+               cfg = le32_to_cpu(cfge->cfg);
+               is_static = (cfg & FDBT_DYNAMIC) ? false : true;
+               vid = le16_to_cpu(keye->fid);
+
+               err = cb(keye->mac_addr, vid, is_static, data);
+               if (err)
+                       break;
+       } while (resume_eid != NTMP_NULL_ENTRY_ID);
+
+       mutex_unlock(&priv->fdbt_lock);
+       kfree(entry);
+
+       return err;
+}
+
+static int netc_port_mdb_add(struct dsa_switch *ds, int port,
+                            const struct switchdev_obj_port_mdb *mdb,
+                            struct dsa_db db)
+{
+       return netc_port_fdb_add(ds, port, mdb->addr, mdb->vid, db);
+}
+
+static int netc_port_mdb_del(struct dsa_switch *ds, int port,
+                            const struct switchdev_obj_port_mdb *mdb,
+                            struct dsa_db db)
+{
+       return netc_port_fdb_del(ds, port, mdb->addr, mdb->vid, db);
+}
+
+static int netc_port_add_host_flood_rule(struct netc_port *np,
+                                        bool uc, bool mc)
+{
+       const u8 dmac_mask[ETH_ALEN] = {0x1, 0, 0, 0, 0, 0};
+       struct netc_switch *priv = np->switch_priv;
+       struct ipft_entry_data *host_flood;
+       struct ipft_keye_data *keye;
+       struct ipft_cfge_data *cfge;
+       u16 src_port;
+       u32 cfg;
+       int err;
+
+       if (!uc && !mc)
+               return 0;
+
+       host_flood = kzalloc_obj(*host_flood);
+       if (!host_flood)
+               return -ENOMEM;
+
+       keye = &host_flood->keye;
+       cfge = &host_flood->cfge;
+
+       src_port = FIELD_PREP(IPFT_SRC_PORT, np->dp->index);
+       src_port |= IPFT_SRC_PORT_MASK;
+       keye->src_port = cpu_to_le16(src_port);
+
+       /* If either only unicast or only multicast need to be flooded
+        * to the host, we always set the mask that tests the first MAC
+        * DA octet. The value should be 0 for the first bit (if unicast
+        * has to be flooded) or 1 (if multicast). If both unicast and
+        * multicast have to be flooded, we leave the key mask empty, so
+        * it matches everything.
+        */
+       if (uc && !mc)
+               ether_addr_copy(keye->dmac_mask, dmac_mask);
+
+       if (!uc && mc) {
+               ether_addr_copy(keye->dmac, dmac_mask);
+               ether_addr_copy(keye->dmac_mask, dmac_mask);
+       }
+
+       cfg = FIELD_PREP(IPFT_FLTFA, IPFT_FLTFA_REDIRECT);
+       cfg |= FIELD_PREP(IPFT_HR, NETC_HR_HOST_FLOOD);
+       cfge->cfg = cpu_to_le32(cfg);
+
+       err = ntmp_ipft_add_entry(&priv->ntmp, host_flood);
+       if (err) {
+               kfree(host_flood);
+               return err;
+       }
+
+       np->uc = uc;
+       np->mc = mc;
+       np->host_flood = host_flood;
+       /* Enable ingress port filter table lookup */
+       netc_port_wr(np, NETC_PIPFCR, PIPFCR_EN);
+
+       return 0;
+}
+
+static void netc_port_remove_host_flood(struct netc_port *np)
+{
+       struct netc_switch *priv = np->switch_priv;
+
+       if (!np->host_flood)
+               return;
+
+       ntmp_ipft_delete_entry(&priv->ntmp, np->host_flood->entry_id);
+       kfree(np->host_flood);
+       np->host_flood = NULL;
+       np->uc = false;
+       np->mc = false;
+       /* Disable ingress port filter table lookup */
+       netc_port_wr(np, NETC_PIPFCR, 0);
+}
+
+static void netc_port_set_host_flood(struct dsa_switch *ds, int port,
+                                    bool uc, bool mc)
+{
+       struct netc_port *np = NETC_PORT(ds, port);
+
+       if (np->uc == uc && np->mc == mc)
+               return;
+
+       /* IPFT does not support in-place updates to the KEYE element,
+        * so we need to delete the old IPFT entry and then add a new
+        * one.
+        */
+       if (np->host_flood)
+               netc_port_remove_host_flood(np);
+
+       if (netc_port_add_host_flood_rule(np, uc, mc))
+               dev_err(ds->dev, "Failed to add host flood rule on port %d\n",
+                       port);
+}
+
 static void netc_phylink_get_caps(struct dsa_switch *ds, int port,
                                  struct phylink_config *config)
 {
@@ -810,6 +1329,17 @@ static const struct dsa_switch_ops netc_switch_ops = {
        .setup                          = netc_setup,
        .teardown                       = netc_teardown,
        .phylink_get_caps               = netc_phylink_get_caps,
+       .port_enable                    = netc_port_enable,
+       .port_disable                   = netc_port_disable,
+       .port_stp_state_set             = netc_port_stp_state_set,
+       .port_change_mtu                = netc_port_change_mtu,
+       .port_max_mtu                   = netc_port_max_mtu,
+       .port_fdb_add                   = netc_port_fdb_add,
+       .port_fdb_del                   = netc_port_fdb_del,
+       .port_fdb_dump                  = netc_port_fdb_dump,
+       .port_mdb_add                   = netc_port_mdb_add,
+       .port_mdb_del                   = netc_port_mdb_del,
+       .port_set_host_flood            = netc_port_set_host_flood,
 };
 
 static int netc_switch_probe(struct pci_dev *pdev,
@@ -851,6 +1381,7 @@ static int netc_switch_probe(struct pci_dev *pdev,
        ds->num_tx_queues = NETC_TC_NUM;
        ds->ops = &netc_switch_ops;
        ds->phylink_mac_ops = &netc_phylink_mac_ops;
+       ds->fdb_isolation = true;
        ds->priv = priv;
 
        priv->ds = ds;
diff --git a/drivers/net/dsa/netc/netc_switch.h 
b/drivers/net/dsa/netc/netc_switch.h
index eb65c36ecead..4b229a71578e 100644
--- a/drivers/net/dsa/netc/netc_switch.h
+++ b/drivers/net/dsa/netc/netc_switch.h
@@ -30,6 +30,8 @@
 
 #define NETC_MAX_FRAME_LEN             9600
 
+#define NETC_STANDALONE_PVID           0
+
 struct netc_switch;
 
 struct netc_switch_info {
@@ -43,6 +45,11 @@ struct netc_port_caps {
        u32 pseudo_link:1;
 };
 
+enum netc_host_reason {
+       /* Software defined host reasons */
+       NETC_HR_HOST_FLOOD = 8,
+};
+
 struct netc_port {
        void __iomem *iobase;
        struct netc_switch *switch_priv;
@@ -50,6 +57,11 @@ struct netc_port {
        struct dsa_port *dp;
        struct clk *ref_clk; /* RGMII/RMII reference clock */
        struct mii_bus *emdio;
+
+       u16 enable:1;
+       u16 uc:1;
+       u16 mc:1;
+       struct ipft_entry_data *host_flood;
 };
 
 struct netc_switch_regs {
@@ -58,6 +70,13 @@ struct netc_switch_regs {
        void __iomem *global;
 };
 
+struct netc_fdb_entry {
+       u32 entry_id;
+       struct fdbt_cfge_data cfge;
+       struct fdbt_keye_data keye;
+       struct hlist_node node;
+};
+
 struct netc_switch {
        struct pci_dev *pdev;
        struct device *dev;
@@ -69,6 +88,8 @@ struct netc_switch {
        struct netc_port **ports;
 
        struct ntmp_user ntmp;
+       struct hlist_head fdb_list;
+       struct mutex fdbt_lock; /* FDB table lock */
 };
 
 #define NETC_PRIV(ds)                  ((struct netc_switch *)((ds)->priv))
@@ -91,6 +112,18 @@ static inline bool is_netc_pseudo_port(struct netc_port *np)
        return np->caps.pseudo_link;
 }
 
+static inline void netc_add_fdb_entry(struct netc_switch *priv,
+                                     struct netc_fdb_entry *entry)
+{
+       hlist_add_head(&entry->node, &priv->fdb_list);
+}
+
+static inline void netc_del_fdb_entry(struct netc_fdb_entry *entry)
+{
+       hlist_del(&entry->node);
+       kfree(entry);
+}
+
 int netc_switch_platform_probe(struct netc_switch *priv);
 
 #endif
diff --git a/drivers/net/dsa/netc/netc_switch_hw.h 
b/drivers/net/dsa/netc/netc_switch_hw.h
index 6d7758631e61..a2b0c1a712f8 100644
--- a/drivers/net/dsa/netc/netc_switch_hw.h
+++ b/drivers/net/dsa/netc/netc_switch_hw.h
@@ -67,6 +67,9 @@
 #define  PQOSMR_VQMP                   GENMASK(19, 16)
 #define  PQOSMR_QVMP                   GENMASK(23, 20)
 
+#define NETC_PIPFCR                    0x0084
+#define  PIPFCR_EN                     BIT(0)
+
 #define NETC_POR                       0x100
 #define  PCR_TXDIS                     BIT(0)
 #define  PCR_RXDIS                     BIT(1)
@@ -122,6 +125,14 @@ enum netc_mfo {
 #define  BPDVR_RXVAM                   BIT(24)
 #define  BPDVR_TXTAGA                  GENMASK(26, 25)
 
+#define NETC_BPSTGSR                   0x520
+
+enum netc_stg_stage {
+       NETC_STG_STATE_DISABLED = 0,
+       NETC_STG_STATE_LEARNING,
+       NETC_STG_STATE_FORWARDING,
+};
+
 /* Definition of Switch ethernet MAC port registers */
 #define NETC_PMAC_OFFSET               0x400
 #define NETC_PM_CMD_CFG(a)             (0x1008 + (a) * 0x400)
-- 
2.34.1


Reply via email to