KCONFIG:=CONFIG_B53 \
CONFIG_NET_DSA_TAG_BRCM \
CONFIG_NET_DSA_TAG_BRCM_LEGACY \
+ CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS \
CONFIG_NET_DSA_TAG_BRCM_PREPEND
FILES:= \
$(LINUX_DIR)/drivers/net/dsa/b53/b53_common.ko \
+++ /dev/null
-From f4ed3dc77c598151a892b3c7622da4e8313bde2c Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 17:10:11 +0200
-Subject: [PATCH] net: dsa: tag_brcm: legacy: reorganize functions
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Move brcm_leg_tag_rcv() definition to top.
-This function is going to be shared between two different tags.
-
----
- net/dsa/tag_brcm.c | 64 +++++++++++++++++++++++-----------------------
- 1 file changed, 32 insertions(+), 32 deletions(-)
-
---- a/net/dsa/tag_brcm.c
-+++ b/net/dsa/tag_brcm.c
-@@ -213,6 +213,38 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROT
- #endif
-
- #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
-+static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
-+ struct net_device *dev)
-+{
-+ int len = BRCM_LEG_TAG_LEN;
-+ int source_port;
-+ u8 *brcm_tag;
-+
-+ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
-+ return NULL;
-+
-+ brcm_tag = dsa_etype_header_pos_rx(skb);
-+
-+ source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
-+
-+ skb->dev = dsa_conduit_find_user(dev, 0, source_port);
-+ if (!skb->dev)
-+ return NULL;
-+
-+ /* VLAN tag is added by BCM63xx internal switch */
-+ if (netdev_uses_dsa(skb->dev))
-+ len += VLAN_HLEN;
-+
-+ /* Remove Broadcom tag and update checksum */
-+ skb_pull_rcsum(skb, len);
-+
-+ dsa_default_offload_fwd_mark(skb);
-+
-+ dsa_strip_etype_header(skb, len);
-+
-+ return skb;
-+}
-+
- static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
- struct net_device *dev)
- {
-@@ -249,38 +281,6 @@ static struct sk_buff *brcm_leg_tag_xmit
-
- return skb;
- }
--
--static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
-- struct net_device *dev)
--{
-- int len = BRCM_LEG_TAG_LEN;
-- int source_port;
-- u8 *brcm_tag;
--
-- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
-- return NULL;
--
-- brcm_tag = dsa_etype_header_pos_rx(skb);
--
-- source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
--
-- skb->dev = dsa_conduit_find_user(dev, 0, source_port);
-- if (!skb->dev)
-- return NULL;
--
-- /* VLAN tag is added by BCM63xx internal switch */
-- if (netdev_uses_dsa(skb->dev))
-- len += VLAN_HLEN;
--
-- /* Remove Broadcom tag and update checksum */
-- skb_pull_rcsum(skb, len);
--
-- dsa_default_offload_fwd_mark(skb);
--
-- dsa_strip_etype_header(skb, len);
--
-- return skb;
--}
-
- static const struct dsa_device_ops brcm_legacy_netdev_ops = {
- .name = BRCM_LEGACY_NAME,
+++ /dev/null
-From fa4bb7220eb7b2f0d985dd9d1f60ba8bd84a8870 Mon Sep 17 00:00:00 2001
-Date: Mon, 17 Apr 2023 18:38:05 +0200
-Subject: [PATCH] net: dsa: tag_brcm: add support for legacy FCS tags
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add support for legacy Broadcom FCS tags, which are similar to
-DSA_TAG_PROTO_BRCM_LEGACY.
-BCM5325 and BCM5365 switches require including the original FCS value and
-length, as opposed to BCM63xx switches.
-Adding the original FCS value and length to DSA_TAG_PROTO_BRCM_LEGACY would
-impact performance of BCM63xx switches, so it's better to create a new tag.
-
----
- include/net/dsa.h | 2 ++
- net/dsa/Kconfig | 8 ++++++
- net/dsa/tag_brcm.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-
- 3 files changed, 80 insertions(+), 1 deletion(-)
-
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -54,11 +54,13 @@ struct tc_action;
- #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26
- #define DSA_TAG_PROTO_LAN937X_VALUE 27
- #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28
-+#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29
-
- enum dsa_tag_protocol {
- DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
- DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE,
- DSA_TAG_PROTO_BRCM_LEGACY = DSA_TAG_PROTO_BRCM_LEGACY_VALUE,
-+ DSA_TAG_PROTO_BRCM_LEGACY_FCS = DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE,
- DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE,
- DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE,
- DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE,
---- a/net/dsa/Kconfig
-+++ b/net/dsa/Kconfig
-@@ -49,6 +49,14 @@ config NET_DSA_TAG_BRCM_LEGACY
- Broadcom legacy switches which place the tag after the MAC source
- address.
-
-+config NET_DSA_TAG_BRCM_LEGACY_FCS
-+ tristate "Tag driver for Broadcom legacy switches using in-frame headers, FCS and length"
-+ select NET_DSA_TAG_BRCM_COMMON
-+ help
-+ Say Y if you want to enable support for tagging frames for the
-+ Broadcom legacy switches which place the tag after the MAC source
-+ address and require the original FCS and length.
-+
- config NET_DSA_TAG_BRCM_PREPEND
- tristate "Tag driver for Broadcom switches using prepended headers"
- select NET_DSA_TAG_BRCM_COMMON
---- a/net/dsa/tag_brcm.c
-+++ b/net/dsa/tag_brcm.c
-@@ -15,6 +15,7 @@
-
- #define BRCM_NAME "brcm"
- #define BRCM_LEGACY_NAME "brcm-legacy"
-+#define BRCM_LEGACY_FCS_NAME "brcm-legacy-fcs"
- #define BRCM_PREPEND_NAME "brcm-prepend"
-
- /* Legacy Broadcom tag (6 bytes) */
-@@ -32,6 +33,10 @@
- #define BRCM_LEG_MULTICAST (1 << 5)
- #define BRCM_LEG_EGRESS (2 << 5)
- #define BRCM_LEG_INGRESS (3 << 5)
-+#define BRCM_LEG_LEN_HI(x) (((x) >> 8) & 0x7)
-+
-+/* 4th byte in the tag */
-+#define BRCM_LEG_LEN_LO(x) ((x) & 0xff)
-
- /* 6th byte in the tag */
- #define BRCM_LEG_PORT_ID (0xf)
-@@ -212,7 +217,8 @@ DSA_TAG_DRIVER(brcm_netdev_ops);
- MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME);
- #endif
-
--#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
-+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) || \
-+ IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
- static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
- struct net_device *dev)
- {
-@@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(
-
- return skb;
- }
-+#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
-
-+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
- static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
- struct net_device *dev)
- {
-@@ -294,6 +302,66 @@ DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
- MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME);
- #endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */
-
-+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
-+static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
-+ struct net_device *dev)
-+{
-+ struct dsa_port *dp = dsa_user_to_port(dev);
-+ unsigned int fcs_len;
-+ u32 fcs_val;
-+ u8 *brcm_tag;
-+
-+ /* The Ethernet switch we are interfaced with needs packets to be at
-+ * least 64 bytes (including FCS) otherwise they will be discarded when
-+ * they enter the switch port logic. When Broadcom tags are enabled, we
-+ * need to make sure that packets are at least 70 bytes
-+ * (including FCS and tag) because the length verification is done after
-+ * the Broadcom tag is stripped off the ingress packet.
-+ *
-+ * Let dsa_user_xmit() free the SKB
-+ */
-+ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
-+ return NULL;
-+
-+ fcs_len = skb->len;
-+ fcs_val = swab32(crc32(~0, skb->data, fcs_len) ^ ~0);
-+
-+ skb_push(skb, BRCM_LEG_TAG_LEN);
-+
-+ dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
-+
-+ brcm_tag = skb->data + 2 * ETH_ALEN;
-+
-+ /* Broadcom tag type */
-+ brcm_tag[0] = BRCM_LEG_TYPE_HI;
-+ brcm_tag[1] = BRCM_LEG_TYPE_LO;
-+
-+ /* Broadcom tag value */
-+ brcm_tag[2] = BRCM_LEG_EGRESS | BRCM_LEG_LEN_HI(fcs_len);
-+ brcm_tag[3] = BRCM_LEG_LEN_LO(fcs_len);
-+ brcm_tag[4] = 0;
-+ brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
-+
-+ /* Original FCS value */
-+ if (__skb_pad(skb, ETH_FCS_LEN, false))
-+ return NULL;
-+ skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
-+
-+ return skb;
-+}
-+
-+static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {
-+ .name = BRCM_LEGACY_FCS_NAME,
-+ .proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS,
-+ .xmit = brcm_leg_fcs_tag_xmit,
-+ .rcv = brcm_leg_tag_rcv,
-+ .needed_headroom = BRCM_LEG_TAG_LEN,
-+};
-+
-+DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);
-+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME);
-+#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
-+
- #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
- static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
- struct net_device *dev)
-@@ -328,6 +396,9 @@ static struct dsa_tag_driver *dsa_tag_dr
- #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
- &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops),
- #endif
-+#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
-+ &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops),
-+#endif
- #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
- &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
- #endif
+++ /dev/null
-From acd751e9fe048cb51e9aee3c780f019c5e9732ec Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 17:31:39 +0200
-Subject: [PATCH] net: dsa: b53: support legacy FCS tags
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Commit 46c5176c586c ("net: dsa: b53: support legacy tags") introduced support
-for legacy tags, but it turns out that BCM5325 and BCM5365 switches require
-the original FCS value and length, so they have to be treated differently.
-
-Fixes: 46c5176c586c ("net: dsa: b53: support legacy tags")
----
- drivers/net/dsa/b53/Kconfig | 1 +
- drivers/net/dsa/b53/b53_common.c | 7 +++++--
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/b53/Kconfig
-+++ b/drivers/net/dsa/b53/Kconfig
-@@ -5,6 +5,7 @@ menuconfig B53
- select NET_DSA_TAG_NONE
- select NET_DSA_TAG_BRCM
- select NET_DSA_TAG_BRCM_LEGACY
-+ select NET_DSA_TAG_BRCM_LEGACY_FCS
- select NET_DSA_TAG_BRCM_PREPEND
- help
- This driver adds support for Broadcom managed switch chips. It supports
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -2244,8 +2244,11 @@ enum dsa_tag_protocol b53_get_tag_protoc
- goto out;
- }
-
-- /* Older models require a different 6 byte tag */
-- if (is5325(dev) || is5365(dev) || is63xx(dev)) {
-+ /* Older models require different 6 byte tags */
-+ if (is5325(dev) || is5365(dev)) {
-+ dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY_FCS;
-+ goto out;
-+ } else if (is63xx(dev)) {
- dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY;
- goto out;
- }
+++ /dev/null
-From 1cd53b29d573aef79ea69f6f502517a71e3f04a7 Mon Sep 17 00:00:00 2001
-Date: Sat, 9 Sep 2017 16:41:26 -0700
-Subject: [RFC PATCH net-next v2 01/10] net: dsa: b53: add support for FDB
- operations on 5325/5365
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 and BCM5365 are part of a much older generation of switches which,
-due to their limited number of ports and VLAN entries (up to 256) allowed
-a single 64-bit register to hold a full ARL entry.
-This requires a little bit of massaging when reading, writing and
-converting ARL entries in both directions.
-
----
- drivers/net/dsa/b53/b53_common.c | 104 +++++++++++++++++++++++++------
- drivers/net/dsa/b53/b53_priv.h | 29 +++++++++
- drivers/net/dsa/b53/b53_regs.h | 7 ++-
- 3 files changed, 117 insertions(+), 23 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -1763,6 +1763,45 @@ static int b53_arl_read(struct b53_devic
- return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
- }
-
-+static int b53_arl_read_25(struct b53_device *dev, u64 mac,
-+ u16 vid, struct b53_arl_entry *ent, u8 *idx)
-+{
-+ DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
-+ unsigned int i;
-+ int ret;
-+
-+ ret = b53_arl_op_wait(dev);
-+ if (ret)
-+ return ret;
-+
-+ bitmap_zero(free_bins, dev->num_arl_bins);
-+
-+ /* Read the bins */
-+ for (i = 0; i < dev->num_arl_bins; i++) {
-+ u64 mac_vid;
-+
-+ b53_read64(dev, B53_ARLIO_PAGE,
-+ B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);
-+
-+ b53_arl_to_entry_25(ent, mac_vid);
-+
-+ if (!(mac_vid & ARLTBL_VALID_25)) {
-+ set_bit(i, free_bins);
-+ continue;
-+ }
-+ if ((mac_vid & ARLTBL_MAC_MASK) != mac)
-+ continue;
-+ if (dev->vlan_enabled &&
-+ ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid)
-+ continue;
-+ *idx = i;
-+ return 0;
-+ }
-+
-+ *idx = find_first_bit(free_bins, dev->num_arl_bins);
-+ return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
-+}
-+
- static int b53_arl_op(struct b53_device *dev, int op, int port,
- const unsigned char *addr, u16 vid, bool is_valid)
- {
-@@ -1777,14 +1816,18 @@ static int b53_arl_op(struct b53_device
-
- /* Perform a read for the given MAC and VID */
- b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac);
-- b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid);
-+ if (!is5325(dev))
-+ b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid);
-
- /* Issue a read operation for this MAC */
- ret = b53_arl_rw_op(dev, 1);
- if (ret)
- return ret;
-
-- ret = b53_arl_read(dev, mac, vid, &ent, &idx);
-+ if (is5325(dev) || is5365(dev))
-+ ret = b53_arl_read_25(dev, mac, vid, &ent, &idx);
-+ else
-+ ret = b53_arl_read(dev, mac, vid, &ent, &idx);
-
- /* If this is a read, just finish now */
- if (op)
-@@ -1828,12 +1871,17 @@ static int b53_arl_op(struct b53_device
- ent.is_static = true;
- ent.is_age = false;
- memcpy(ent.mac, addr, ETH_ALEN);
-- b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
-+ if (is5325(dev) || is5365(dev))
-+ b53_arl_from_entry_25(&mac_vid, &ent);
-+ else
-+ b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
-
- b53_write64(dev, B53_ARLIO_PAGE,
- B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid);
-- b53_write32(dev, B53_ARLIO_PAGE,
-- B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
-+
-+ if (!is5325(dev) && !is5365(dev))
-+ b53_write32(dev, B53_ARLIO_PAGE,
-+ B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
-
- return b53_arl_rw_op(dev, 0);
- }
-@@ -1845,12 +1893,6 @@ int b53_fdb_add(struct dsa_switch *ds, i
- struct b53_device *priv = ds->priv;
- int ret;
-
-- /* 5325 and 5365 require some more massaging, but could
-- * be supported eventually
-- */
-- if (is5325(priv) || is5365(priv))
-- return -EOPNOTSUPP;
--
- mutex_lock(&priv->arl_mutex);
- ret = b53_arl_op(priv, 0, port, addr, vid, true);
- mutex_unlock(&priv->arl_mutex);
-@@ -1877,10 +1919,15 @@ EXPORT_SYMBOL(b53_fdb_del);
- static int b53_arl_search_wait(struct b53_device *dev)
- {
- unsigned int timeout = 1000;
-- u8 reg;
-+ u8 reg, offset;
-+
-+ if (is5325(dev) || is5365(dev))
-+ offset = B53_ARL_SRCH_CTL_25;
-+ else
-+ offset = B53_ARL_SRCH_CTL;
-
- do {
-- b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, ®);
-+ b53_read8(dev, B53_ARLIO_PAGE, offset, ®);
- if (!(reg & ARL_SRCH_STDN))
- return 0;
-
-@@ -1897,13 +1944,24 @@ static void b53_arl_search_rd(struct b53
- struct b53_arl_entry *ent)
- {
- u64 mac_vid;
-- u32 fwd_entry;
-
-- b53_read64(dev, B53_ARLIO_PAGE,
-- B53_ARL_SRCH_RSTL_MACVID(idx), &mac_vid);
-- b53_read32(dev, B53_ARLIO_PAGE,
-- B53_ARL_SRCH_RSTL(idx), &fwd_entry);
-- b53_arl_to_entry(ent, mac_vid, fwd_entry);
-+ if (is5325(dev)) {
-+ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25,
-+ &mac_vid);
-+ b53_arl_to_entry_25(ent, mac_vid);
-+ } else if (is5365(dev)) {
-+ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65,
-+ &mac_vid);
-+ b53_arl_to_entry_25(ent, mac_vid);
-+ } else {
-+ u32 fwd_entry;
-+
-+ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx),
-+ &mac_vid);
-+ b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx),
-+ &fwd_entry);
-+ b53_arl_to_entry(ent, mac_vid, fwd_entry);
-+ }
- }
-
- static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
-@@ -1924,14 +1982,20 @@ int b53_fdb_dump(struct dsa_switch *ds,
- struct b53_device *priv = ds->priv;
- struct b53_arl_entry results[2];
- unsigned int count = 0;
-+ u8 offset;
- int ret;
- u8 reg;
-
- mutex_lock(&priv->arl_mutex);
-
-+ if (is5325(priv) || is5365(priv))
-+ offset = B53_ARL_SRCH_CTL_25;
-+ else
-+ offset = B53_ARL_SRCH_CTL;
-+
- /* Start search operation */
- reg = ARL_SRCH_STDN;
-- b53_write8(priv, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, reg);
-+ b53_write8(priv, offset, B53_ARL_SRCH_CTL, reg);
-
- do {
- ret = b53_arl_search_wait(priv);
---- a/drivers/net/dsa/b53/b53_priv.h
-+++ b/drivers/net/dsa/b53/b53_priv.h
-@@ -298,6 +298,19 @@ static inline void b53_arl_to_entry(stru
- ent->vid = mac_vid >> ARLTBL_VID_S;
- }
-
-+static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent,
-+ u64 mac_vid)
-+{
-+ memset(ent, 0, sizeof(*ent));
-+ ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) &
-+ ARLTBL_DATA_PORT_ID_MASK_25;
-+ ent->is_valid = !!(mac_vid & ARLTBL_VALID_25);
-+ ent->is_age = !!(mac_vid & ARLTBL_AGE_25);
-+ ent->is_static = !!(mac_vid & ARLTBL_STATIC_25);
-+ u64_to_ether_addr(mac_vid, ent->mac);
-+ ent->vid = mac_vid >> ARLTBL_VID_S_65;
-+}
-+
- static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
- const struct b53_arl_entry *ent)
- {
-@@ -312,6 +325,22 @@ static inline void b53_arl_from_entry(u6
- *fwd_entry |= ARLTBL_AGE;
- }
-
-+static inline void b53_arl_from_entry_25(u64 *mac_vid,
-+ const struct b53_arl_entry *ent)
-+{
-+ *mac_vid = ether_addr_to_u64(ent->mac);
-+ *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) <<
-+ ARLTBL_DATA_PORT_ID_S_25;
-+ *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) <<
-+ ARLTBL_VID_S_65;
-+ if (ent->is_valid)
-+ *mac_vid |= ARLTBL_VALID_25;
-+ if (ent->is_static)
-+ *mac_vid |= ARLTBL_STATIC_25;
-+ if (ent->is_age)
-+ *mac_vid |= ARLTBL_AGE_25;
-+}
-+
- #ifdef CONFIG_BCM47XX
-
- #include <linux/bcm47xx_nvram.h>
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -324,9 +324,10 @@
- #define ARLTBL_VID_MASK 0xfff
- #define ARLTBL_DATA_PORT_ID_S_25 48
- #define ARLTBL_DATA_PORT_ID_MASK_25 0xf
--#define ARLTBL_AGE_25 BIT(61)
--#define ARLTBL_STATIC_25 BIT(62)
--#define ARLTBL_VALID_25 BIT(63)
-+#define ARLTBL_VID_S_65 53
-+#define ARLTBL_AGE_25 BIT_ULL(61)
-+#define ARLTBL_STATIC_25 BIT_ULL(62)
-+#define ARLTBL_VALID_25 BIT_ULL(63)
-
- /* ARL Table Data Entry N Registers (32 bit) */
- #define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x18)
+++ /dev/null
-From ccf1ce36586c922cf41d0bd41cd74804e6c1a7bc Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 22:44:47 +0200
-Subject: [RFC PATCH net-next v2 02/10] net: dsa: b53: prevent FAST_AGE access
- on BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement FAST_AGE registers so we should avoid reading or
-writing them.
-
-Fixes: 967dd82ffc52 ("net: dsa: b53: Add support for Broadcom RoboSwitch")
----
- drivers/net/dsa/b53/b53_common.c | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -487,6 +487,9 @@ static int b53_flush_arl(struct b53_devi
- {
- unsigned int i;
-
-+ if (is5325(dev))
-+ return 0;
-+
- b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
- FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask);
-
-@@ -511,6 +514,9 @@ out:
-
- static int b53_fast_age_port(struct b53_device *dev, int port)
- {
-+ if (is5325(dev))
-+ return 0;
-+
- b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_PORT_CTRL, port);
-
- return b53_flush_arl(dev, FAST_AGE_PORT);
-@@ -518,6 +524,9 @@ static int b53_fast_age_port(struct b53_
-
- static int b53_fast_age_vlan(struct b53_device *dev, u16 vid)
- {
-+ if (is5325(dev))
-+ return 0;
-+
- b53_write16(dev, B53_CTRL_PAGE, B53_FAST_AGE_VID_CTRL, vid);
-
- return b53_flush_arl(dev, FAST_AGE_VLAN);
+++ /dev/null
-From 6c08487730e4ac1c45daa87a5c836aecc9508299 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 22:57:06 +0200
-Subject: [RFC PATCH net-next v2 03/10] net: dsa: b53: prevent SWITCH_CTRL
- access on BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement SWITCH_CTRL register so we should avoid reading
-or writing it.
-
-Fixes: a424f0de6163 ("net: dsa: b53: Include IMP/CPU port in dumb forwarding mode")
----
- drivers/net/dsa/b53/b53_common.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -361,11 +361,12 @@ static void b53_set_forwarding(struct b5
-
- b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
-
-- /* Include IMP port in dumb forwarding mode
-- */
-- b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
-- mgmt |= B53_MII_DUMB_FWDG_EN;
-- b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
-+ if (!is5325(dev)) {
-+ /* Include IMP port in dumb forwarding mode */
-+ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
-+ mgmt |= B53_MII_DUMB_FWDG_EN;
-+ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
-+ }
-
- /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
- * frames should be flooded or not.
+++ /dev/null
-From 566c3b4e4ad6167c5a2fb4357e75eb5ba8d94f64 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 23:00:55 +0200
-Subject: [RFC PATCH net-next v2 04/10] net: dsa: b53: fix IP_MULTICAST_CTRL on
- BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement B53_UC_FWD_EN, B53_MC_FWD_EN or B53_IPMC_FWD_EN.
-
-Fixes: 53568438e381 ("net: dsa: b53: Add support for port_egress_floods callback")
----
- drivers/net/dsa/b53/b53_common.c | 18 +++++++++++-------
- drivers/net/dsa/b53/b53_regs.h | 1 +
- 2 files changed, 12 insertions(+), 7 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -366,14 +366,18 @@ static void b53_set_forwarding(struct b5
- b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
- mgmt |= B53_MII_DUMB_FWDG_EN;
- b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
-- }
-
-- /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
-- * frames should be flooded or not.
-- */
-- b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
-- mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN | B53_IPMC_FWD_EN;
-- b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
-+ /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
-+ * frames should be flooded or not.
-+ */
-+ b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
-+ mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN | B53_IPMC_FWD_EN;
-+ b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
-+ } else {
-+ b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
-+ mgmt |= B53_IP_MCAST_25;
-+ b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
-+ }
- }
-
- static void b53_enable_vlan(struct b53_device *dev, int port, bool enable,
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -106,6 +106,7 @@
-
- /* IP Multicast control (8 bit) */
- #define B53_IP_MULTICAST_CTRL 0x21
-+#define B53_IP_MCAST_25 BIT(0)
- #define B53_IPMC_FWD_EN BIT(1)
- #define B53_UC_FWD_EN BIT(6)
- #define B53_MC_FWD_EN BIT(7)
+++ /dev/null
-From 2c09136c63be15b91cf39b52a707b3be8eb1fe71 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 23:13:01 +0200
-Subject: [RFC PATCH net-next v2 05/10] net: dsa: b53: prevent DIS_LEARNING
- access on BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement DIS_LEARNING register so we should avoid reading
-or writing it.
-
-Fixes: f9b3827ee66c ("net: dsa: b53: Support setting learning on port")
----
- drivers/net/dsa/b53/b53_common.c | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -593,6 +593,9 @@ static void b53_port_set_learning(struct
- {
- u16 reg;
-
-+ if (is5325(dev))
-+ return;
-+
- b53_read16(dev, B53_CTRL_PAGE, B53_DIS_LEARNING, ®);
- if (learning)
- reg &= ~BIT(port);
-@@ -2246,7 +2249,13 @@ int b53_br_flags_pre(struct dsa_switch *
- struct switchdev_brport_flags flags,
- struct netlink_ext_ack *extack)
- {
-- if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_LEARNING))
-+ struct b53_device *dev = ds->priv;
-+ unsigned long mask = (BR_FLOOD | BR_MCAST_FLOOD);
-+
-+ if (!is5325(dev))
-+ mask |= BR_LEARNING;
-+
-+ if (flags.mask & ~mask)
- return -EINVAL;
-
- return 0;
+++ /dev/null
-From 2497ff2da6b938544868e49f6017bdbe56773d80 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 23:18:03 +0200
-Subject: [RFC PATCH net-next v2 06/10] net: dsa: b53: prevent BRCM_HDR access
- on BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement BRCM_HDR register so we should avoid reading or
-writing it.
-
-Fixes: b409a9efa183 ("net: dsa: b53: Move Broadcom header setup to b53")
----
- drivers/net/dsa/b53/b53_common.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -730,6 +730,10 @@ void b53_brcm_hdr_setup(struct dsa_switc
- hdr_ctl |= GC_FRM_MGMT_PORT_M;
- b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, hdr_ctl);
-
-+ /* B53_BRCM_HDR not present on BCM5325 */
-+ if (is5325(dev))
-+ return;
-+
- /* Enable Broadcom tags for IMP port */
- b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl);
- if (tag_en)
+++ /dev/null
-From 4eecebbe332e3cfd8d0aaeb39d764748f25259f1 Mon Sep 17 00:00:00 2001
-Date: Fri, 30 May 2025 23:33:13 +0200
-Subject: [RFC PATCH net-next v2 07/10] net: dsa: b53: prevent
- GMII_PORT_OVERRIDE_CTRL access on BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement GMII_PORT_OVERRIDE_CTRL register so we should
-avoid reading or writing it.
-PORT_OVERRIDE_RX_FLOW and PORT_OVERRIDE_TX_FLOW aren't defined on BCM5325
-and we should use PORT_OVERRIDE_LP_FLOW_25 instead.
-
-Fixes: 5e004460f874 ("net: dsa: b53: Add helper to set link parameters")
----
- drivers/net/dsa/b53/b53_common.c | 21 +++++++++++++++++----
- drivers/net/dsa/b53/b53_regs.h | 1 +
- 2 files changed, 18 insertions(+), 4 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -1278,6 +1278,8 @@ static void b53_force_link(struct b53_de
- if (port == dev->imp_port) {
- off = B53_PORT_OVERRIDE_CTRL;
- val = PORT_OVERRIDE_EN;
-+ } else if (is5325(dev)) {
-+ return;
- } else {
- off = B53_GMII_PORT_OVERRIDE_CTRL(port);
- val = GMII_PO_EN;
-@@ -1302,6 +1304,8 @@ static void b53_force_port_config(struct
- if (port == dev->imp_port) {
- off = B53_PORT_OVERRIDE_CTRL;
- val = PORT_OVERRIDE_EN;
-+ } else if (is5325(dev)) {
-+ return;
- } else {
- off = B53_GMII_PORT_OVERRIDE_CTRL(port);
- val = GMII_PO_EN;
-@@ -1332,10 +1336,19 @@ static void b53_force_port_config(struct
- return;
- }
-
-- if (rx_pause)
-- reg |= PORT_OVERRIDE_RX_FLOW;
-- if (tx_pause)
-- reg |= PORT_OVERRIDE_TX_FLOW;
-+ if (rx_pause) {
-+ if (is5325(dev))
-+ reg |= PORT_OVERRIDE_LP_FLOW_25;
-+ else
-+ reg |= PORT_OVERRIDE_RX_FLOW;
-+ }
-+
-+ if (tx_pause) {
-+ if (is5325(dev))
-+ reg |= PORT_OVERRIDE_LP_FLOW_25;
-+ else
-+ reg |= PORT_OVERRIDE_TX_FLOW;
-+ }
-
- b53_write8(dev, B53_CTRL_PAGE, off, reg);
- }
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -95,6 +95,7 @@
- #define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S)
- #define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S)
- #define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S)
-+#define PORT_OVERRIDE_LP_FLOW_25 BIT(3) /* BCM5325 only */
- #define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */
- #define PORT_OVERRIDE_RX_FLOW BIT(4)
- #define PORT_OVERRIDE_TX_FLOW BIT(5)
+++ /dev/null
-From e087a6480f0601d2eb2823b2c920ba7929ffafc4 Mon Sep 17 00:00:00 2001
-Date: Sat, 31 May 2025 09:31:55 +0200
-Subject: [RFC PATCH net-next v2 08/10] net: dsa: b53: fix unicast/multicast
- flooding on BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-BCM5325 doesn't implement UC_FLOOD_MASK, MC_FLOOD_MASK and IPMC_FLOOD_MASK
-registers.
-This has to be handled differently with other pages and registers.
-
-Fixes: a8b659e7ff75 ("net: dsa: act as passthrough for bridge port flags")
----
- drivers/net/dsa/b53/b53_common.c | 60 ++++++++++++++++++++++----------
- drivers/net/dsa/b53/b53_regs.h | 16 +++++++++
- 2 files changed, 58 insertions(+), 18 deletions(-)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -560,12 +560,24 @@ static void b53_port_set_ucast_flood(str
- {
- u16 uc;
-
-- b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc);
-- if (unicast)
-- uc |= BIT(port);
-- else
-- uc &= ~BIT(port);
-- b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc);
-+ if (is5325(dev)) {
-+ if (port == B53_CPU_PORT_25)
-+ port = B53_CPU_PORT;
-+
-+ b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, &uc);
-+ if (unicast)
-+ uc |= BIT(port) | B53_IEEE_UCAST_DROP_EN;
-+ else
-+ uc &= ~BIT(port);
-+ b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, uc);
-+ } else {
-+ b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc);
-+ if (unicast)
-+ uc |= BIT(port);
-+ else
-+ uc &= ~BIT(port);
-+ b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc);
-+ }
- }
-
- static void b53_port_set_mcast_flood(struct b53_device *dev, int port,
-@@ -573,19 +585,31 @@ static void b53_port_set_mcast_flood(str
- {
- u16 mc;
-
-- b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc);
-- if (multicast)
-- mc |= BIT(port);
-- else
-- mc &= ~BIT(port);
-- b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc);
--
-- b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc);
-- if (multicast)
-- mc |= BIT(port);
-- else
-- mc &= ~BIT(port);
-- b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc);
-+ if (is5325(dev)) {
-+ if (port == B53_CPU_PORT_25)
-+ port = B53_CPU_PORT;
-+
-+ b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, &mc);
-+ if (multicast)
-+ mc |= BIT(port) | B53_IEEE_MCAST_DROP_EN;
-+ else
-+ mc &= ~BIT(port);
-+ b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, mc);
-+ } else {
-+ b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc);
-+ if (multicast)
-+ mc |= BIT(port);
-+ else
-+ mc &= ~BIT(port);
-+ b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc);
-+
-+ b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc);
-+ if (multicast)
-+ mc |= BIT(port);
-+ else
-+ mc &= ~BIT(port);
-+ b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc);
-+ }
- }
-
- static void b53_port_set_learning(struct b53_device *dev, int port,
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -29,6 +29,7 @@
- #define B53_ARLIO_PAGE 0x05 /* ARL Access */
- #define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */
- #define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */
-+#define B53_IEEE_PAGE 0x0a /* IEEE 802.1X */
-
- /* PHY Registers */
- #define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */
-@@ -47,6 +48,9 @@
- /* VLAN Registers */
- #define B53_VLAN_PAGE 0x34
-
-+/* Rate Control Registers */
-+#define B53_RATE_CTL_PAGE 0x35
-+
- /* Jumbo Frame Registers */
- #define B53_JUMBO_PAGE 0x40
-
-@@ -369,6 +373,18 @@
- #define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10))
-
- /*************************************************************************
-+ * IEEE 802.1X Registers
-+ *************************************************************************/
-+
-+/* Multicast DLF Drop Control register (16 bit) */
-+#define B53_IEEE_MCAST_DLF 0x94
-+#define B53_IEEE_MCAST_DROP_EN BIT(11)
-+
-+/* Unicast DLF Drop Control register (16 bit) */
-+#define B53_IEEE_UCAST_DLF 0x96
-+#define B53_IEEE_UCAST_DROP_EN BIT(11)
-+
-+/*************************************************************************
- * Port VLAN Registers
- *************************************************************************/
-
+++ /dev/null
-From dd2bda07009f5c376a11b14c9445ccd11083c024 Mon Sep 17 00:00:00 2001
-Date: Sat, 31 May 2025 11:11:42 +0200
-Subject: [RFC PATCH net-next v2 09/10] net: dsa: b53: fix b53_imp_vlan_setup
- for BCM5325
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-CPU port should be B53_CPU_PORT instead of B53_CPU_PORT_25 for
-B53_PVLAN_PORT_MASK register.
-
-Fixes: ff39c2d68679 ("net: dsa: b53: Add bridge support")
----
- drivers/net/dsa/b53/b53_common.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -543,6 +543,10 @@ void b53_imp_vlan_setup(struct dsa_switc
- unsigned int i;
- u16 pvlan;
-
-+ /* BCM5325 CPU port is at 8 */
-+ if ((is5325(dev) || is5365(dev)) && cpu_port == B53_CPU_PORT_25)
-+ cpu_port = B53_CPU_PORT;
-+
- /* Enable the IMP port to be in the same VLAN as the other ports
- * on a per-port basis such that we only have Port i and IMP in
- * the same VLAN.
+++ /dev/null
-From 4368d82cccd1bdd9339a4aac1ce78873ef0d0031 Mon Sep 17 00:00:00 2001
-Date: Sat, 31 May 2025 11:20:13 +0200
-Subject: [RFC PATCH net-next v2 10/10] net: dsa: b53: ensure BCM5325 PHYs are
- enabled
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-According to the datasheet, BCM5325 uses B53_PD_MODE_CTRL_25 register to
-disable clocking to individual PHYs.
-Only ports 1-4 can be enabled or disabled and the datasheet is explicit
-about not toggling BIT(0) since it disables the PLL power and the switch.
-
----
- drivers/net/dsa/b53/b53_common.c | 13 +++++++++++++
- drivers/net/dsa/b53/b53_regs.h | 2 ++
- 2 files changed, 15 insertions(+)
-
---- a/drivers/net/dsa/b53/b53_common.c
-+++ b/drivers/net/dsa/b53/b53_common.c
-@@ -660,6 +660,19 @@ int b53_setup_port(struct dsa_switch *ds
- if (dsa_is_user_port(ds, port))
- b53_set_eap_mode(dev, port, EAP_MODE_SIMPLIFIED);
-
-+ if (is5325(dev) &&
-+ (port >= B53_PD_MODE_PORT_MIN) &&
-+ (port <= B53_PD_MODE_PORT_MAX)) {
-+ u8 reg;
-+
-+ b53_read8(dev, B53_CTRL_PAGE, B53_PD_MODE_CTRL_25, ®);
-+ if (dsa_is_unused_port(ds, port))
-+ reg |= BIT(port);
-+ else
-+ reg &= ~BIT(port);
-+ b53_write8(dev, B53_CTRL_PAGE, B53_PD_MODE_CTRL_25, reg);
-+ }
-+
- return 0;
- }
- EXPORT_SYMBOL(b53_setup_port);
---- a/drivers/net/dsa/b53/b53_regs.h
-+++ b/drivers/net/dsa/b53/b53_regs.h
-@@ -108,6 +108,8 @@
-
- /* Power-down mode control */
- #define B53_PD_MODE_CTRL_25 0x0f
-+#define B53_PD_MODE_PORT_MIN 1
-+#define B53_PD_MODE_PORT_MAX 4
-
- /* IP Multicast control (8 bit) */
- #define B53_IP_MULTICAST_CTRL 0x21
--- /dev/null
+From a4daaf063f8269a5881154c5b77c5ef6639d65d3 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:47 +0200
+Subject: [PATCH] net: dsa: tag_brcm: legacy: reorganize functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Move brcm_leg_tag_rcv() definition to top.
+This function is going to be shared between two different tags.
+
+---
+ net/dsa/tag_brcm.c | 64 +++++++++++++++++++++++-----------------------
+ 1 file changed, 32 insertions(+), 32 deletions(-)
+
+--- a/net/dsa/tag_brcm.c
++++ b/net/dsa/tag_brcm.c
+@@ -213,6 +213,38 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROT
+ #endif
+
+ #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
++static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
++ struct net_device *dev)
++{
++ int len = BRCM_LEG_TAG_LEN;
++ int source_port;
++ u8 *brcm_tag;
++
++ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
++ return NULL;
++
++ brcm_tag = dsa_etype_header_pos_rx(skb);
++
++ source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
++
++ skb->dev = dsa_conduit_find_user(dev, 0, source_port);
++ if (!skb->dev)
++ return NULL;
++
++ /* VLAN tag is added by BCM63xx internal switch */
++ if (netdev_uses_dsa(skb->dev))
++ len += VLAN_HLEN;
++
++ /* Remove Broadcom tag and update checksum */
++ skb_pull_rcsum(skb, len);
++
++ dsa_default_offload_fwd_mark(skb);
++
++ dsa_strip_etype_header(skb, len);
++
++ return skb;
++}
++
+ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+@@ -249,38 +281,6 @@ static struct sk_buff *brcm_leg_tag_xmit
+
+ return skb;
+ }
+-
+-static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
+- struct net_device *dev)
+-{
+- int len = BRCM_LEG_TAG_LEN;
+- int source_port;
+- u8 *brcm_tag;
+-
+- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
+- return NULL;
+-
+- brcm_tag = dsa_etype_header_pos_rx(skb);
+-
+- source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
+-
+- skb->dev = dsa_conduit_find_user(dev, 0, source_port);
+- if (!skb->dev)
+- return NULL;
+-
+- /* VLAN tag is added by BCM63xx internal switch */
+- if (netdev_uses_dsa(skb->dev))
+- len += VLAN_HLEN;
+-
+- /* Remove Broadcom tag and update checksum */
+- skb_pull_rcsum(skb, len);
+-
+- dsa_default_offload_fwd_mark(skb);
+-
+- dsa_strip_etype_header(skb, len);
+-
+- return skb;
+-}
+
+ static const struct dsa_device_ops brcm_legacy_netdev_ops = {
+ .name = BRCM_LEGACY_NAME,
--- /dev/null
+From ef07df397a621707903ef0d294a7df11f80cf206 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:48 +0200
+Subject: [PATCH] net: dsa: tag_brcm: add support for legacy FCS tags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add support for legacy Broadcom FCS tags, which are similar to
+DSA_TAG_PROTO_BRCM_LEGACY.
+BCM5325 and BCM5365 switches require including the original FCS value and
+length, as opposed to BCM63xx switches.
+Adding the original FCS value and length to DSA_TAG_PROTO_BRCM_LEGACY would
+impact performance of BCM63xx switches, so it's better to create a new tag.
+
+---
+ include/net/dsa.h | 2 ++
+ net/dsa/Kconfig | 16 ++++++++--
+ net/dsa/tag_brcm.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 88 insertions(+), 3 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -54,11 +54,13 @@ struct tc_action;
+ #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26
+ #define DSA_TAG_PROTO_LAN937X_VALUE 27
+ #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28
++#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29
+
+ enum dsa_tag_protocol {
+ DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
+ DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE,
+ DSA_TAG_PROTO_BRCM_LEGACY = DSA_TAG_PROTO_BRCM_LEGACY_VALUE,
++ DSA_TAG_PROTO_BRCM_LEGACY_FCS = DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE,
+ DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE,
+ DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE,
+ DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE,
+--- a/net/dsa/Kconfig
++++ b/net/dsa/Kconfig
+@@ -42,12 +42,24 @@ config NET_DSA_TAG_BRCM
+ Broadcom switches which place the tag after the MAC source address.
+
+ config NET_DSA_TAG_BRCM_LEGACY
+- tristate "Tag driver for Broadcom legacy switches using in-frame headers"
++ tristate "Tag driver for BCM63xx legacy switches using in-frame headers"
+ select NET_DSA_TAG_BRCM_COMMON
+ help
+ Say Y if you want to enable support for tagging frames for the
+- Broadcom legacy switches which place the tag after the MAC source
++ BCM63xx legacy switches which place the tag after the MAC source
+ address.
++ This tag is used in BCM63xx legacy switches which work without the
++ original FCS and length before the tag insertion.
++
++config NET_DSA_TAG_BRCM_LEGACY_FCS
++ tristate "Tag driver for BCM53xx legacy switches using in-frame headers"
++ select NET_DSA_TAG_BRCM_COMMON
++ help
++ Say Y if you want to enable support for tagging frames for the
++ BCM53xx legacy switches which place the tag after the MAC source
++ address.
++ This tag is used in BCM53xx legacy switches which expect original
++ FCS and length before the tag insertion to be present.
+
+ config NET_DSA_TAG_BRCM_PREPEND
+ tristate "Tag driver for Broadcom switches using prepended headers"
+--- a/net/dsa/tag_brcm.c
++++ b/net/dsa/tag_brcm.c
+@@ -15,6 +15,7 @@
+
+ #define BRCM_NAME "brcm"
+ #define BRCM_LEGACY_NAME "brcm-legacy"
++#define BRCM_LEGACY_FCS_NAME "brcm-legacy-fcs"
+ #define BRCM_PREPEND_NAME "brcm-prepend"
+
+ /* Legacy Broadcom tag (6 bytes) */
+@@ -32,6 +33,10 @@
+ #define BRCM_LEG_MULTICAST (1 << 5)
+ #define BRCM_LEG_EGRESS (2 << 5)
+ #define BRCM_LEG_INGRESS (3 << 5)
++#define BRCM_LEG_LEN_HI(x) (((x) >> 8) & 0x7)
++
++/* 4th byte in the tag */
++#define BRCM_LEG_LEN_LO(x) ((x) & 0xff)
+
+ /* 6th byte in the tag */
+ #define BRCM_LEG_PORT_ID (0xf)
+@@ -212,7 +217,8 @@ DSA_TAG_DRIVER(brcm_netdev_ops);
+ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME);
+ #endif
+
+-#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) || \
++ IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
+ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+@@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(
+
+ return skb;
+ }
++#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
+
++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
+ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+ {
+@@ -294,6 +302,66 @@ DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
+ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME);
+ #endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */
+
++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
++static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
++ struct net_device *dev)
++{
++ struct dsa_port *dp = dsa_user_to_port(dev);
++ unsigned int fcs_len;
++ __le32 fcs_val;
++ u8 *brcm_tag;
++
++ /* The Ethernet switch we are interfaced with needs packets to be at
++ * least 64 bytes (including FCS) otherwise they will be discarded when
++ * they enter the switch port logic. When Broadcom tags are enabled, we
++ * need to make sure that packets are at least 70 bytes (including FCS
++ * and tag) because the length verification is done after the Broadcom
++ * tag is stripped off the ingress packet.
++ *
++ * Let dsa_user_xmit() free the SKB.
++ */
++ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
++ return NULL;
++
++ fcs_len = skb->len;
++ fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0);
++
++ skb_push(skb, BRCM_LEG_TAG_LEN);
++
++ dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
++
++ brcm_tag = skb->data + 2 * ETH_ALEN;
++
++ /* Broadcom tag type */
++ brcm_tag[0] = BRCM_LEG_TYPE_HI;
++ brcm_tag[1] = BRCM_LEG_TYPE_LO;
++
++ /* Broadcom tag value */
++ brcm_tag[2] = BRCM_LEG_EGRESS | BRCM_LEG_LEN_HI(fcs_len);
++ brcm_tag[3] = BRCM_LEG_LEN_LO(fcs_len);
++ brcm_tag[4] = 0;
++ brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
++
++ /* Original FCS value */
++ if (__skb_pad(skb, ETH_FCS_LEN, false))
++ return NULL;
++ skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
++
++ return skb;
++}
++
++static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {
++ .name = BRCM_LEGACY_FCS_NAME,
++ .proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS,
++ .xmit = brcm_leg_fcs_tag_xmit,
++ .rcv = brcm_leg_tag_rcv,
++ .needed_headroom = BRCM_LEG_TAG_LEN,
++};
++
++DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);
++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME);
++#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
++
+ #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
+ static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
+ struct net_device *dev)
+@@ -328,6 +396,9 @@ static struct dsa_tag_driver *dsa_tag_dr
+ #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
+ &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops),
+ #endif
++#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
++ &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops),
++#endif
+ #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
+ &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
+ #endif
--- /dev/null
+From c3cf059a4d419b9c888ce7e9952fa13ba7569b61 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:49 +0200
+Subject: [PATCH] net: dsa: b53: support legacy FCS tags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 46c5176c586c ("net: dsa: b53: support legacy tags") introduced
+support for legacy tags, but it turns out that BCM5325 and BCM5365
+switches require the original FCS value and length, so they have to be
+treated differently.
+
+---
+ drivers/net/dsa/b53/Kconfig | 1 +
+ drivers/net/dsa/b53/b53_common.c | 7 +++++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/b53/Kconfig
++++ b/drivers/net/dsa/b53/Kconfig
+@@ -5,6 +5,7 @@ menuconfig B53
+ select NET_DSA_TAG_NONE
+ select NET_DSA_TAG_BRCM
+ select NET_DSA_TAG_BRCM_LEGACY
++ select NET_DSA_TAG_BRCM_LEGACY_FCS
+ select NET_DSA_TAG_BRCM_PREPEND
+ help
+ This driver adds support for Broadcom managed switch chips. It supports
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -2245,8 +2245,11 @@ enum dsa_tag_protocol b53_get_tag_protoc
+ goto out;
+ }
+
+- /* Older models require a different 6 byte tag */
+- if (is5325(dev) || is5365(dev) || is63xx(dev)) {
++ /* Older models require different 6 byte tags */
++ if (is5325(dev) || is5365(dev)) {
++ dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY_FCS;
++ goto out;
++ } else if (is63xx(dev)) {
+ dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY;
+ goto out;
+ }
--- /dev/null
+From 0cbec9aef5a86194117a956546dc1aec95031f37 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:50 +0200
+Subject: [PATCH] net: dsa: b53: detect BCM5325 variants
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We need to be able to differentiate the BCM5325 variants because:
+- BCM5325M switches lack the ARLIO_PAGE->VLAN_ID_IDX register.
+- BCM5325E have less 512 ARL buckets instead of 1024.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 24 +++++++++++++++++++++---
+ drivers/net/dsa/b53/b53_priv.h | 19 +++++++++++++++++++
+ 2 files changed, 40 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1778,7 +1778,8 @@ static int b53_arl_op(struct b53_device
+
+ /* Perform a read for the given MAC and VID */
+ b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac);
+- b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid);
++ if (!is5325m(dev))
++ b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid);
+
+ /* Issue a read operation for this MAC */
+ ret = b53_arl_rw_op(dev, 1);
+@@ -2844,6 +2845,9 @@ static int b53_switch_init(struct b53_de
+ }
+ }
+
++ if (is5325e(dev))
++ dev->num_arl_buckets = 512;
++
+ dev->num_ports = fls(dev->enabled_ports);
+
+ dev->ds->num_ports = min_t(unsigned int, dev->num_ports, DSA_MAX_PORTS);
+@@ -2945,10 +2949,24 @@ int b53_switch_detect(struct b53_device
+ b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf);
+ b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp);
+
+- if (tmp == 0xf)
++ if (tmp == 0xf) {
++ u32 phy_id;
++ int val;
++
+ dev->chip_id = BCM5325_DEVICE_ID;
+- else
++
++ val = b53_phy_read16(dev->ds, 0, MII_PHYSID1);
++ phy_id = (val & 0xffff) << 16;
++ val = b53_phy_read16(dev->ds, 0, MII_PHYSID2);
++ phy_id |= (val & 0xfff0);
++
++ if (phy_id == 0x00406330)
++ dev->variant_id = B53_VARIANT_5325M;
++ else if (phy_id == 0x0143bc30)
++ dev->variant_id = B53_VARIANT_5325E;
++ } else {
+ dev->chip_id = BCM5365_DEVICE_ID;
++ }
+ break;
+ case BCM5389_DEVICE_ID:
+ case BCM5395_DEVICE_ID:
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -84,6 +84,12 @@ enum {
+ BCM53134_DEVICE_ID = 0x5075,
+ };
+
++enum b53_variant_id {
++ B53_VARIANT_NONE = 0,
++ B53_VARIANT_5325E,
++ B53_VARIANT_5325M,
++};
++
+ struct b53_pcs {
+ struct phylink_pcs pcs;
+ struct b53_device *dev;
+@@ -118,6 +124,7 @@ struct b53_device {
+
+ /* chip specific data */
+ u32 chip_id;
++ enum b53_variant_id variant_id;
+ u8 core_rev;
+ u8 vta_regs[3];
+ u8 duplex_reg;
+@@ -165,6 +172,18 @@ static inline int is5325(struct b53_devi
+ return dev->chip_id == BCM5325_DEVICE_ID;
+ }
+
++static inline int is5325e(struct b53_device *dev)
++{
++ return is5325(dev) &&
++ dev->variant_id == B53_VARIANT_5325E;
++}
++
++static inline int is5325m(struct b53_device *dev)
++{
++ return is5325(dev) &&
++ dev->variant_id == B53_VARIANT_5325M;
++}
++
+ static inline int is5365(struct b53_device *dev)
+ {
+ #ifdef CONFIG_BCM47XX
--- /dev/null
+From c45655386e532c85ff1d679fc2aa40b3aaff9916 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:51 +0200
+Subject: [PATCH] net: dsa: b53: add support for FDB operations on 5325/5365
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 and BCM5365 are part of a much older generation of switches which,
+due to their limited number of ports and VLAN entries (up to 256) allowed
+a single 64-bit register to hold a full ARL entry.
+This requires a little bit of massaging when reading, writing and
+converting ARL entries in both directions.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 101 +++++++++++++++++++++++++------
+ drivers/net/dsa/b53/b53_priv.h | 29 +++++++++
+ drivers/net/dsa/b53/b53_regs.h | 7 ++-
+ 3 files changed, 115 insertions(+), 22 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1764,6 +1764,45 @@ static int b53_arl_read(struct b53_devic
+ return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
+ }
+
++static int b53_arl_read_25(struct b53_device *dev, u64 mac,
++ u16 vid, struct b53_arl_entry *ent, u8 *idx)
++{
++ DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES);
++ unsigned int i;
++ int ret;
++
++ ret = b53_arl_op_wait(dev);
++ if (ret)
++ return ret;
++
++ bitmap_zero(free_bins, dev->num_arl_bins);
++
++ /* Read the bins */
++ for (i = 0; i < dev->num_arl_bins; i++) {
++ u64 mac_vid;
++
++ b53_read64(dev, B53_ARLIO_PAGE,
++ B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);
++
++ b53_arl_to_entry_25(ent, mac_vid);
++
++ if (!(mac_vid & ARLTBL_VALID_25)) {
++ set_bit(i, free_bins);
++ continue;
++ }
++ if ((mac_vid & ARLTBL_MAC_MASK) != mac)
++ continue;
++ if (dev->vlan_enabled &&
++ ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid)
++ continue;
++ *idx = i;
++ return 0;
++ }
++
++ *idx = find_first_bit(free_bins, dev->num_arl_bins);
++ return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT;
++}
++
+ static int b53_arl_op(struct b53_device *dev, int op, int port,
+ const unsigned char *addr, u16 vid, bool is_valid)
+ {
+@@ -1786,7 +1825,10 @@ static int b53_arl_op(struct b53_device
+ if (ret)
+ return ret;
+
+- ret = b53_arl_read(dev, mac, vid, &ent, &idx);
++ if (is5325(dev) || is5365(dev))
++ ret = b53_arl_read_25(dev, mac, vid, &ent, &idx);
++ else
++ ret = b53_arl_read(dev, mac, vid, &ent, &idx);
+
+ /* If this is a read, just finish now */
+ if (op)
+@@ -1830,12 +1872,17 @@ static int b53_arl_op(struct b53_device
+ ent.is_static = true;
+ ent.is_age = false;
+ memcpy(ent.mac, addr, ETH_ALEN);
+- b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
++ if (is5325(dev) || is5365(dev))
++ b53_arl_from_entry_25(&mac_vid, &ent);
++ else
++ b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
+
+ b53_write64(dev, B53_ARLIO_PAGE,
+ B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid);
+- b53_write32(dev, B53_ARLIO_PAGE,
+- B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
++
++ if (!is5325(dev) && !is5365(dev))
++ b53_write32(dev, B53_ARLIO_PAGE,
++ B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
+
+ return b53_arl_rw_op(dev, 0);
+ }
+@@ -1847,12 +1894,6 @@ int b53_fdb_add(struct dsa_switch *ds, i
+ struct b53_device *priv = ds->priv;
+ int ret;
+
+- /* 5325 and 5365 require some more massaging, but could
+- * be supported eventually
+- */
+- if (is5325(priv) || is5365(priv))
+- return -EOPNOTSUPP;
+-
+ mutex_lock(&priv->arl_mutex);
+ ret = b53_arl_op(priv, 0, port, addr, vid, true);
+ mutex_unlock(&priv->arl_mutex);
+@@ -1879,10 +1920,15 @@ EXPORT_SYMBOL(b53_fdb_del);
+ static int b53_arl_search_wait(struct b53_device *dev)
+ {
+ unsigned int timeout = 1000;
+- u8 reg;
++ u8 reg, offset;
++
++ if (is5325(dev) || is5365(dev))
++ offset = B53_ARL_SRCH_CTL_25;
++ else
++ offset = B53_ARL_SRCH_CTL;
+
+ do {
+- b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, ®);
++ b53_read8(dev, B53_ARLIO_PAGE, offset, ®);
+ if (!(reg & ARL_SRCH_STDN))
+ return 0;
+
+@@ -1899,13 +1945,24 @@ static void b53_arl_search_rd(struct b53
+ struct b53_arl_entry *ent)
+ {
+ u64 mac_vid;
+- u32 fwd_entry;
+
+- b53_read64(dev, B53_ARLIO_PAGE,
+- B53_ARL_SRCH_RSTL_MACVID(idx), &mac_vid);
+- b53_read32(dev, B53_ARLIO_PAGE,
+- B53_ARL_SRCH_RSTL(idx), &fwd_entry);
+- b53_arl_to_entry(ent, mac_vid, fwd_entry);
++ if (is5325(dev)) {
++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25,
++ &mac_vid);
++ b53_arl_to_entry_25(ent, mac_vid);
++ } else if (is5365(dev)) {
++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65,
++ &mac_vid);
++ b53_arl_to_entry_25(ent, mac_vid);
++ } else {
++ u32 fwd_entry;
++
++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx),
++ &mac_vid);
++ b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx),
++ &fwd_entry);
++ b53_arl_to_entry(ent, mac_vid, fwd_entry);
++ }
+ }
+
+ static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
+@@ -1926,14 +1983,20 @@ int b53_fdb_dump(struct dsa_switch *ds,
+ struct b53_device *priv = ds->priv;
+ struct b53_arl_entry results[2];
+ unsigned int count = 0;
++ u8 offset;
+ int ret;
+ u8 reg;
+
+ mutex_lock(&priv->arl_mutex);
+
++ if (is5325(priv) || is5365(priv))
++ offset = B53_ARL_SRCH_CTL_25;
++ else
++ offset = B53_ARL_SRCH_CTL;
++
+ /* Start search operation */
+ reg = ARL_SRCH_STDN;
+- b53_write8(priv, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, reg);
++ b53_write8(priv, offset, B53_ARL_SRCH_CTL, reg);
+
+ do {
+ ret = b53_arl_search_wait(priv);
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -317,6 +317,19 @@ static inline void b53_arl_to_entry(stru
+ ent->vid = mac_vid >> ARLTBL_VID_S;
+ }
+
++static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent,
++ u64 mac_vid)
++{
++ memset(ent, 0, sizeof(*ent));
++ ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) &
++ ARLTBL_DATA_PORT_ID_MASK_25;
++ ent->is_valid = !!(mac_vid & ARLTBL_VALID_25);
++ ent->is_age = !!(mac_vid & ARLTBL_AGE_25);
++ ent->is_static = !!(mac_vid & ARLTBL_STATIC_25);
++ u64_to_ether_addr(mac_vid, ent->mac);
++ ent->vid = mac_vid >> ARLTBL_VID_S_65;
++}
++
+ static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
+ const struct b53_arl_entry *ent)
+ {
+@@ -331,6 +344,22 @@ static inline void b53_arl_from_entry(u6
+ *fwd_entry |= ARLTBL_AGE;
+ }
+
++static inline void b53_arl_from_entry_25(u64 *mac_vid,
++ const struct b53_arl_entry *ent)
++{
++ *mac_vid = ether_addr_to_u64(ent->mac);
++ *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) <<
++ ARLTBL_DATA_PORT_ID_S_25;
++ *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) <<
++ ARLTBL_VID_S_65;
++ if (ent->is_valid)
++ *mac_vid |= ARLTBL_VALID_25;
++ if (ent->is_static)
++ *mac_vid |= ARLTBL_STATIC_25;
++ if (ent->is_age)
++ *mac_vid |= ARLTBL_AGE_25;
++}
++
+ #ifdef CONFIG_BCM47XX
+
+ #include <linux/bcm47xx_nvram.h>
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -324,9 +324,10 @@
+ #define ARLTBL_VID_MASK 0xfff
+ #define ARLTBL_DATA_PORT_ID_S_25 48
+ #define ARLTBL_DATA_PORT_ID_MASK_25 0xf
+-#define ARLTBL_AGE_25 BIT(61)
+-#define ARLTBL_STATIC_25 BIT(62)
+-#define ARLTBL_VALID_25 BIT(63)
++#define ARLTBL_VID_S_65 53
++#define ARLTBL_AGE_25 BIT_ULL(61)
++#define ARLTBL_STATIC_25 BIT_ULL(62)
++#define ARLTBL_VALID_25 BIT_ULL(63)
+
+ /* ARL Table Data Entry N Registers (32 bit) */
+ #define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x18)
--- /dev/null
+From 9b6c767c312b4709e9aeb2314a6b47863e7fb72d Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:52 +0200
+Subject: [PATCH] net: dsa: b53: prevent FAST_AGE access on BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 doesn't implement FAST_AGE registers so we should avoid reading or
+writing them.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -487,6 +487,9 @@ static int b53_flush_arl(struct b53_devi
+ {
+ unsigned int i;
+
++ if (is5325(dev))
++ return 0;
++
+ b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+ FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask);
+
+@@ -511,6 +514,9 @@ out:
+
+ static int b53_fast_age_port(struct b53_device *dev, int port)
+ {
++ if (is5325(dev))
++ return 0;
++
+ b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_PORT_CTRL, port);
+
+ return b53_flush_arl(dev, FAST_AGE_PORT);
+@@ -518,6 +524,9 @@ static int b53_fast_age_port(struct b53_
+
+ static int b53_fast_age_vlan(struct b53_device *dev, u16 vid)
+ {
++ if (is5325(dev))
++ return 0;
++
+ b53_write16(dev, B53_CTRL_PAGE, B53_FAST_AGE_VID_CTRL, vid);
+
+ return b53_flush_arl(dev, FAST_AGE_VLAN);
--- /dev/null
+From 22ccaaca43440e90a3b68d2183045b42247dc4be Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:53 +0200
+Subject: [PATCH] net: dsa: b53: prevent SWITCH_CTRL access on BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 doesn't implement SWITCH_CTRL register so we should avoid reading
+or writing it.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -361,11 +361,12 @@ static void b53_set_forwarding(struct b5
+
+ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+
+- /* Include IMP port in dumb forwarding mode
+- */
+- b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
+- mgmt |= B53_MII_DUMB_FWDG_EN;
+- b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
++ if (!is5325(dev)) {
++ /* Include IMP port in dumb forwarding mode */
++ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
++ mgmt |= B53_MII_DUMB_FWDG_EN;
++ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
++ }
+
+ /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
+ * frames should be flooded or not.
--- /dev/null
+From 044d5ce2788b165798bfd173548e61bf7b6baf4d Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:54 +0200
+Subject: [PATCH] net: dsa: b53: fix IP_MULTICAST_CTRL on BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 doesn't implement B53_UC_FWD_EN, B53_MC_FWD_EN or B53_IPMC_FWD_EN.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 18 +++++++++++-------
+ drivers/net/dsa/b53/b53_regs.h | 1 +
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -366,14 +366,18 @@ static void b53_set_forwarding(struct b5
+ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
+ mgmt |= B53_MII_DUMB_FWDG_EN;
+ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
+- }
+
+- /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
+- * frames should be flooded or not.
+- */
+- b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
+- mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN | B53_IPMC_FWD_EN;
+- b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
++ /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
++ * frames should be flooded or not.
++ */
++ b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
++ mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN | B53_IPMC_FWD_EN;
++ b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
++ } else {
++ b53_read8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, &mgmt);
++ mgmt |= B53_IP_MCAST_25;
++ b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
++ }
+ }
+
+ static void b53_enable_vlan(struct b53_device *dev, int port, bool enable,
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -106,6 +106,7 @@
+
+ /* IP Multicast control (8 bit) */
+ #define B53_IP_MULTICAST_CTRL 0x21
++#define B53_IP_MCAST_25 BIT(0)
+ #define B53_IPMC_FWD_EN BIT(1)
+ #define B53_UC_FWD_EN BIT(6)
+ #define B53_MC_FWD_EN BIT(7)
--- /dev/null
+From 800728abd9f83bda4de62a30ce62a8b41c242020 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:55 +0200
+Subject: [PATCH] net: dsa: b53: prevent DIS_LEARNING access on BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 doesn't implement DIS_LEARNING register so we should avoid reading
+or writing it.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -593,6 +593,9 @@ static void b53_port_set_learning(struct
+ {
+ u16 reg;
+
++ if (is5325(dev))
++ return;
++
+ b53_read16(dev, B53_CTRL_PAGE, B53_DIS_LEARNING, ®);
+ if (learning)
+ reg &= ~BIT(port);
+@@ -2247,7 +2250,13 @@ int b53_br_flags_pre(struct dsa_switch *
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack)
+ {
+- if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_LEARNING))
++ struct b53_device *dev = ds->priv;
++ unsigned long mask = (BR_FLOOD | BR_MCAST_FLOOD);
++
++ if (!is5325(dev))
++ mask |= BR_LEARNING;
++
++ if (flags.mask & ~mask)
+ return -EINVAL;
+
+ return 0;
--- /dev/null
+From e17813968b08b1b09bf80699223dea48851cbd07 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:56 +0200
+Subject: [PATCH] net: dsa: b53: prevent BRCM_HDR access on older devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Older switches don't implement BRCM_HDR register so we should avoid
+reading or writing it.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -730,6 +730,11 @@ void b53_brcm_hdr_setup(struct dsa_switc
+ hdr_ctl |= GC_FRM_MGMT_PORT_M;
+ b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, hdr_ctl);
+
++ /* B53_BRCM_HDR not present on devices with legacy tags */
++ if (dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY ||
++ dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY_FCS)
++ return;
++
+ /* Enable Broadcom tags for IMP port */
+ b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl);
+ if (tag_en)
--- /dev/null
+From 37883bbc45a8555d6eca88d3a9730504d2dac86c Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:57 +0200
+Subject: [PATCH] net: dsa: b53: prevent GMII_PORT_OVERRIDE_CTRL access on
+ BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 doesn't implement GMII_PORT_OVERRIDE_CTRL register so we should
+avoid reading or writing it.
+PORT_OVERRIDE_RX_FLOW and PORT_OVERRIDE_TX_FLOW aren't defined on BCM5325
+and we should use PORT_OVERRIDE_LP_FLOW_25 instead.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 21 +++++++++++++++++----
+ drivers/net/dsa/b53/b53_regs.h | 1 +
+ 2 files changed, 18 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1279,6 +1279,8 @@ static void b53_force_link(struct b53_de
+ if (port == dev->imp_port) {
+ off = B53_PORT_OVERRIDE_CTRL;
+ val = PORT_OVERRIDE_EN;
++ } else if (is5325(dev)) {
++ return;
+ } else {
+ off = B53_GMII_PORT_OVERRIDE_CTRL(port);
+ val = GMII_PO_EN;
+@@ -1303,6 +1305,8 @@ static void b53_force_port_config(struct
+ if (port == dev->imp_port) {
+ off = B53_PORT_OVERRIDE_CTRL;
+ val = PORT_OVERRIDE_EN;
++ } else if (is5325(dev)) {
++ return;
+ } else {
+ off = B53_GMII_PORT_OVERRIDE_CTRL(port);
+ val = GMII_PO_EN;
+@@ -1333,10 +1337,19 @@ static void b53_force_port_config(struct
+ return;
+ }
+
+- if (rx_pause)
+- reg |= PORT_OVERRIDE_RX_FLOW;
+- if (tx_pause)
+- reg |= PORT_OVERRIDE_TX_FLOW;
++ if (rx_pause) {
++ if (is5325(dev))
++ reg |= PORT_OVERRIDE_LP_FLOW_25;
++ else
++ reg |= PORT_OVERRIDE_RX_FLOW;
++ }
++
++ if (tx_pause) {
++ if (is5325(dev))
++ reg |= PORT_OVERRIDE_LP_FLOW_25;
++ else
++ reg |= PORT_OVERRIDE_TX_FLOW;
++ }
+
+ b53_write8(dev, B53_CTRL_PAGE, off, reg);
+ }
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -95,6 +95,7 @@
+ #define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S)
+ #define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S)
+ #define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S)
++#define PORT_OVERRIDE_LP_FLOW_25 BIT(3) /* BCM5325 only */
+ #define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */
+ #define PORT_OVERRIDE_RX_FLOW BIT(4)
+ #define PORT_OVERRIDE_TX_FLOW BIT(5)
--- /dev/null
+From 651c9e71ffe44e99b5a9b011271c2117f0353b32 Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:58 +0200
+Subject: [PATCH] net: dsa: b53: fix unicast/multicast flooding on BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM5325 doesn't implement UC_FLOOD_MASK, MC_FLOOD_MASK and IPMC_FLOOD_MASK
+registers.
+This has to be handled differently with other pages and registers.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 60 ++++++++++++++++++++++----------
+ drivers/net/dsa/b53/b53_regs.h | 13 +++++++
+ 2 files changed, 55 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -560,12 +560,24 @@ static void b53_port_set_ucast_flood(str
+ {
+ u16 uc;
+
+- b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc);
+- if (unicast)
+- uc |= BIT(port);
+- else
+- uc &= ~BIT(port);
+- b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc);
++ if (is5325(dev)) {
++ if (port == B53_CPU_PORT_25)
++ port = B53_CPU_PORT;
++
++ b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, &uc);
++ if (unicast)
++ uc |= BIT(port) | B53_IEEE_UCAST_DROP_EN;
++ else
++ uc &= ~BIT(port);
++ b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, uc);
++ } else {
++ b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc);
++ if (unicast)
++ uc |= BIT(port);
++ else
++ uc &= ~BIT(port);
++ b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc);
++ }
+ }
+
+ static void b53_port_set_mcast_flood(struct b53_device *dev, int port,
+@@ -573,19 +585,31 @@ static void b53_port_set_mcast_flood(str
+ {
+ u16 mc;
+
+- b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc);
+- if (multicast)
+- mc |= BIT(port);
+- else
+- mc &= ~BIT(port);
+- b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc);
+-
+- b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc);
+- if (multicast)
+- mc |= BIT(port);
+- else
+- mc &= ~BIT(port);
+- b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc);
++ if (is5325(dev)) {
++ if (port == B53_CPU_PORT_25)
++ port = B53_CPU_PORT;
++
++ b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, &mc);
++ if (multicast)
++ mc |= BIT(port) | B53_IEEE_MCAST_DROP_EN;
++ else
++ mc &= ~BIT(port);
++ b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, mc);
++ } else {
++ b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc);
++ if (multicast)
++ mc |= BIT(port);
++ else
++ mc &= ~BIT(port);
++ b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc);
++
++ b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc);
++ if (multicast)
++ mc |= BIT(port);
++ else
++ mc &= ~BIT(port);
++ b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc);
++ }
+ }
+
+ static void b53_port_set_learning(struct b53_device *dev, int port,
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -29,6 +29,7 @@
+ #define B53_ARLIO_PAGE 0x05 /* ARL Access */
+ #define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */
+ #define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */
++#define B53_IEEE_PAGE 0x0a /* IEEE 802.1X */
+
+ /* PHY Registers */
+ #define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */
+@@ -369,6 +370,18 @@
+ #define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10))
+
+ /*************************************************************************
++ * IEEE 802.1X Registers
++ *************************************************************************/
++
++/* Multicast DLF Drop Control register (16 bit) */
++#define B53_IEEE_MCAST_DLF 0x94
++#define B53_IEEE_MCAST_DROP_EN BIT(11)
++
++/* Unicast DLF Drop Control register (16 bit) */
++#define B53_IEEE_UCAST_DLF 0x96
++#define B53_IEEE_UCAST_DROP_EN BIT(11)
++
++/*************************************************************************
+ * Port VLAN Registers
+ *************************************************************************/
+
--- /dev/null
+From c00df1018791185ea398f78af415a2a0aaa0c79c Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 09:59:59 +0200
+Subject: [PATCH] net: dsa: b53: fix b53_imp_vlan_setup for BCM5325
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+CPU port should be B53_CPU_PORT instead of B53_CPU_PORT_25 for
+B53_PVLAN_PORT_MASK register.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -543,6 +543,10 @@ void b53_imp_vlan_setup(struct dsa_switc
+ unsigned int i;
+ u16 pvlan;
+
++ /* BCM5325 CPU port is at 8 */
++ if ((is5325(dev) || is5365(dev)) && cpu_port == B53_CPU_PORT_25)
++ cpu_port = B53_CPU_PORT;
++
+ /* Enable the IMP port to be in the same VLAN as the other ports
+ * on a per-port basis such that we only have Port i and IMP in
+ * the same VLAN.
--- /dev/null
+From 966a83df36c6f27476ac3501771422e7852098bc Mon Sep 17 00:00:00 2001
+Date: Sat, 14 Jun 2025 10:00:00 +0200
+Subject: [PATCH] net: dsa: b53: ensure BCM5325 PHYs are enabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+According to the datasheet, BCM5325 uses B53_PD_MODE_CTRL_25 register to
+disable clocking to individual PHYs.
+Only ports 1-4 can be enabled or disabled and the datasheet is explicit
+about not toggling BIT(0) since it disables the PLL power and the switch.
+
+---
+ drivers/net/dsa/b53/b53_common.c | 13 +++++++++++++
+ drivers/net/dsa/b53/b53_regs.h | 5 ++++-
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -660,6 +660,19 @@ int b53_setup_port(struct dsa_switch *ds
+ if (dsa_is_user_port(ds, port))
+ b53_set_eap_mode(dev, port, EAP_MODE_SIMPLIFIED);
+
++ if (is5325(dev) &&
++ in_range(port, 1, 4)) {
++ u8 reg;
++
++ b53_read8(dev, B53_CTRL_PAGE, B53_PD_MODE_CTRL_25, ®);
++ reg &= ~PD_MODE_POWER_DOWN_PORT(0);
++ if (dsa_is_unused_port(ds, port))
++ reg |= PD_MODE_POWER_DOWN_PORT(port);
++ else
++ reg &= ~PD_MODE_POWER_DOWN_PORT(port);
++ b53_write8(dev, B53_CTRL_PAGE, B53_PD_MODE_CTRL_25, reg);
++ }
++
+ return 0;
+ }
+ EXPORT_SYMBOL(b53_setup_port);
+--- a/drivers/net/dsa/b53/b53_regs.h
++++ b/drivers/net/dsa/b53/b53_regs.h
+@@ -103,8 +103,11 @@
+ #define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */
+ #define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */
+
+-/* Power-down mode control */
++/* Power-down mode control (8 bit) */
+ #define B53_PD_MODE_CTRL_25 0x0f
++#define PD_MODE_PORT_MASK 0x1f
++/* Bit 0 also powers down the switch. */
++#define PD_MODE_POWER_DOWN_PORT(i) BIT(i)
+
+ /* IP Multicast control (8 bit) */
+ #define B53_IP_MULTICAST_CTRL 0x21
# CONFIG_NET_DSA_TAG_AR9331 is not set
# CONFIG_NET_DSA_TAG_BRCM is not set
# CONFIG_NET_DSA_TAG_BRCM_LEGACY is not set
+# CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS is not set
# CONFIG_NET_DSA_TAG_BRCM_PREPEND is not set
# CONFIG_NET_DSA_TAG_DSA is not set
# CONFIG_NET_DSA_TAG_EDSA is not set
struct dsa_chip_data {
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
-@@ -473,7 +473,7 @@ struct dsa_switch {
+@@ -475,7 +475,7 @@ struct dsa_switch {
/*
* User mii_bus and devices for the individual ports.
*/
struct mii_bus *user_mii_bus;
/* Ageing Time limits in msecs */
-@@ -609,24 +609,24 @@ static inline bool dsa_is_user_port(stru
+@@ -611,24 +611,24 @@ static inline bool dsa_is_user_port(stru
dsa_switch_for_each_port_continue_reverse((_dp), (_ds)) \
if (dsa_port_is_cpu((_dp)))
CONFIG_NET_DSA_TAG_BRCM=y
CONFIG_NET_DSA_TAG_BRCM_COMMON=y
CONFIG_NET_DSA_TAG_BRCM_LEGACY=y
+CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS=y
CONFIG_NET_DSA_TAG_BRCM_PREPEND=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_RTC_DRV_SUN6I=y