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_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
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_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
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_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
case "$(board_name)" in
huawei,hg556a-b)
- ucidef_set_interface_lan "eth0"
+ ucidef_set_bridge_device switch
+ ucidef_set_interface_lan "lan1 lan2 lan3 lan4"
;;
esac
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_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
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_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
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_NET_DSA_TAG_NONE=y
CONFIG_NET_EGRESS=y
status = "okay";
};
+&mdio1 {
+ switch@1e {
+ compatible = "brcm,bcm5325";
+ reg = <30>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "lan1";
+
+ phy-mode = "mii";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan2";
+
+ phy-mode = "mii";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan3";
+
+ phy-mode = "mii";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan4";
+
+ phy-mode = "mii";
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "cpu";
+
+ phy-mode = "internal";
+ ethernet = <ðernet1>;
+
+ fixed-link {
+ speed = <100>;
+ full-duplex;
+ };
+ };
+ };
+ };
+};
+
&ohci {
status = "okay";
};
--- /dev/null
+From f4ed3dc77c598151a892b3c7622da4e8313bde2c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+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.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+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.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+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")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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
+@@ -2266,8 +2266,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 fec493475d7f0b17dc64f682a584faae5efe640e Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Sat, 9 Sep 2017 16:41:26 -0700
+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.
+
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ drivers/net/dsa/b53/b53_common.c | 64 ++++++++++++++++++++------------
+ drivers/net/dsa/b53/b53_priv.h | 57 ++++++++++++++++++++--------
+ drivers/net/dsa/b53/b53_regs.h | 7 ++--
+ 3 files changed, 86 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1760,13 +1760,15 @@ static int b53_arl_read(struct b53_devic
+ /* Read the bins */
+ for (i = 0; i < dev->num_arl_bins; i++) {
+ u64 mac_vid;
+- u32 fwd_entry;
++ u32 fwd_entry = 0;
+
+ b53_read64(dev, B53_ARLIO_PAGE,
+ B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);
+- b53_read32(dev, B53_ARLIO_PAGE,
+- B53_ARLTBL_DATA_ENTRY(i), &fwd_entry);
+- b53_arl_to_entry(ent, mac_vid, fwd_entry);
++
++ if (!is5325(dev) && !is5365(dev))
++ b53_read32(dev, B53_ARLIO_PAGE,
++ B53_ARLTBL_DATA_ENTRY(i), &fwd_entry);
++ b53_arl_to_entry(dev, ent, mac_vid, fwd_entry);
+
+ if (!(fwd_entry & ARLTBL_VALID)) {
+ set_bit(i, free_bins);
+@@ -1799,7 +1801,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 (!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);
+@@ -1850,12 +1853,14 @@ 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);
++ b53_arl_from_entry(dev, &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);
+ }
+@@ -1867,12 +1872,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);
+@@ -1899,10 +1898,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;
+
+@@ -1919,13 +1923,21 @@ static void b53_arl_search_rd(struct b53
+ struct b53_arl_entry *ent)
+ {
+ u64 mac_vid;
+- u32 fwd_entry;
++ u32 fwd_entry = 0;
+
+- 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);
++ } else if (is5365(dev)) {
++ b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65,
++ &mac_vid);
++ } else {
++ 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(dev, ent, mac_vid, fwd_entry);
+ }
+
+ static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
+@@ -1946,14 +1958,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
+@@ -286,30 +286,55 @@ struct b53_arl_entry {
+ u8 is_static:1;
+ };
+
+-static inline void b53_arl_to_entry(struct b53_arl_entry *ent,
++static inline void b53_arl_to_entry(struct b53_device *dev,
++ struct b53_arl_entry *ent,
+ u64 mac_vid, u32 fwd_entry)
+ {
+ memset(ent, 0, sizeof(*ent));
+- ent->port = fwd_entry & ARLTBL_DATA_PORT_ID_MASK;
+- ent->is_valid = !!(fwd_entry & ARLTBL_VALID);
+- ent->is_age = !!(fwd_entry & ARLTBL_AGE);
+- ent->is_static = !!(fwd_entry & ARLTBL_STATIC);
+- u64_to_ether_addr(mac_vid, ent->mac);
+- ent->vid = mac_vid >> ARLTBL_VID_S;
++ if (is5325(dev) || is5365(dev)) {
++ 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;
++ } else {
++ ent->port = fwd_entry & ARLTBL_DATA_PORT_ID_MASK;
++ ent->is_valid = !!(fwd_entry & ARLTBL_VALID);
++ ent->is_age = !!(fwd_entry & ARLTBL_AGE);
++ ent->is_static = !!(fwd_entry & ARLTBL_STATIC);
++ u64_to_ether_addr(mac_vid, ent->mac);
++ ent->vid = mac_vid >> ARLTBL_VID_S;
++ }
+ }
+
+-static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
++static inline void b53_arl_from_entry(struct b53_device *dev,
++ u64 *mac_vid, u32 *fwd_entry,
+ const struct b53_arl_entry *ent)
+ {
+ *mac_vid = ether_addr_to_u64(ent->mac);
+- *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK) << ARLTBL_VID_S;
+- *fwd_entry = ent->port & ARLTBL_DATA_PORT_ID_MASK;
+- if (ent->is_valid)
+- *fwd_entry |= ARLTBL_VALID;
+- if (ent->is_static)
+- *fwd_entry |= ARLTBL_STATIC;
+- if (ent->is_age)
+- *fwd_entry |= ARLTBL_AGE;
++ if (is5325(dev) || is5365(dev)) {
++ *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;
++ } else {
++ *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK) << ARLTBL_VID_S;
++ *fwd_entry = ent->port & ARLTBL_DATA_PORT_ID_MASK;
++ if (ent->is_valid)
++ *fwd_entry |= ARLTBL_VALID;
++ if (ent->is_static)
++ *fwd_entry |= ARLTBL_STATIC;
++ if (ent->is_age)
++ *fwd_entry |= ARLTBL_AGE;
++ }
+ }
+
+ #ifdef CONFIG_BCM47XX
+--- 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 b9441e624e39428f57baf30043aba225f02bfc73 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Fri, 30 May 2025 22:44:47 +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.
+
+Fixes: 967dd82ffc52 ("net: dsa: b53: Add support for Broadcom RoboSwitch")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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
+@@ -486,6 +486,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);
+
+@@ -510,6 +513,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);
+@@ -517,6 +523,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 8cece037d71dd2464b7405871d5ba34d28695940 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Fri, 30 May 2025 22:57:06 +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.
+
+Fixes: a424f0de6163 ("net: dsa: b53: Include IMP/CPU port in dumb forwarding mode")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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
+@@ -360,11 +360,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 85499f7068e67f82194170412617591d3d23a123 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Fri, 30 May 2025 23:00:55 +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.
+
+Fixes: 53568438e381 ("net: dsa: b53: Add support for port_egress_floods callback")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ drivers/net/dsa/b53/b53_common.c | 13 +++++++++----
+ drivers/net/dsa/b53/b53_regs.h | 1 +
+ 2 files changed, 10 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -367,11 +367,16 @@ static void b53_set_forwarding(struct b5
+ 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;
++ if (is5325(dev)) {
++ /* Enable IP multicast address scheme. */
++ mgmt |= B53_IP_MCAST_25;
++ } else {
++ /* Look at B53_UC_FWD_EN and B53_MC_FWD_EN to decide whether
++ * frames should be flooded or not.
++ */
++ mgmt |= B53_UC_FWD_EN | B53_MC_FWD_EN | B53_IPMC_FWD_EN;
++ }
+ b53_write8(dev, B53_CTRL_PAGE, B53_IP_MULTICAST_CTRL, mgmt);
+ }
+
+--- 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 077a4a60a89a0423295a8e5684f7f36bc4b0bc72 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Fri, 30 May 2025 23:13:01 +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.
+
+Fixes: f9b3827ee66c ("net: dsa: b53: Support setting learning on port")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ drivers/net/dsa/b53/b53_common.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- 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);
--- /dev/null
+From 171f3a42be30e2a62c6590ec2b0e5a96ddad57a0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Fri, 30 May 2025 23:18:03 +0200
+Subject: [PATCH] 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")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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 d2dceddf182520b474d2aab0798d925e47a68c5a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Fri, 30 May 2025 23:33:13 +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.
+
+Fixes: 5e004460f874 ("net: dsa: b53: Add helper to set link parameters")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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 1124bbbad49e1a657cb12dd6ab938fcb3035e872 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Sat, 31 May 2025 09:31:55 +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.
+
+Fixes: a8b659e7ff75 ("net: dsa: act as passthrough for bridge port flags")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ drivers/net/dsa/b53/b53_common.c | 85 +++++++++++++++++++++++++-------
+ drivers/net/dsa/b53/b53_regs.h | 38 ++++++++++++++
+ 2 files changed, 105 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -560,12 +560,36 @@ 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)) {
++ u8 rc;
++
++ 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);
++
++ if (port >= B53_CPU_PORT_25)
++ return;
++
++ b53_read8(dev, B53_RATE_CTL_PAGE, B53_RATE_CONTROL(port), &rc);
++ if (unicast)
++ rc |= (RC_DLF_EN | RC_BKT_SIZE_8K | RC_PERCENT_40);
++ else
++ rc &= ~(RC_DLF_EN);
++ b53_write8(dev, B53_RATE_CTL_PAGE, B53_RATE_CONTROL(port), rc);
++ } 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 +597,44 @@ 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)) {
++ u8 rc;
++
++ 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);
++
++ if (port >= B53_CPU_PORT_25)
++ return;
++
++ b53_read8(dev, B53_RATE_CTL_PAGE, B53_RATE_CONTROL(port), &rc);
++ if (multicast)
++ rc |= (RC_BCAST_EN | RC_MCAST_EN | RC_BKT_SIZE_8K |
++ RC_PERCENT_40);
++ else
++ rc &= ~(RC_BCAST_EN | RC_MCAST_EN);
++ b53_write8(dev, B53_RATE_CTL_PAGE, B53_RATE_CONTROL(port), rc);
++ } 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
+ *************************************************************************/
+
+@@ -479,6 +495,28 @@
+ #define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i))
+
+ /*************************************************************************
++ * Rate Control Page Registers
++ *************************************************************************/
++
++#define B53_RATE_CONTROL(i) (0x00 + (i))
++#define RC_PERCENT_S 0
++#define RC_PERCENT_10 (0 << RC_PERCENT_S)
++#define RC_PERCENT_20 (1 << RC_PERCENT_S)
++#define RC_PERCENT_30 (2 << RC_PERCENT_S)
++#define RC_PERCENT_40 (3 << RC_PERCENT_S)
++#define RC_PERCENT_MASK (3 << RC_PERCENT_S)
++#define RC_BKT_SIZE_S 2
++#define RC_BKT_SIZE_2K (0 << RC_BKT_SIZE_S)
++#define RC_BKT_SIZE_4K (1 << RC_BKT_SIZE_S)
++#define RC_BKT_SIZE_6K (2 << RC_BKT_SIZE_S)
++#define RC_BKT_SIZE_8K (3 << RC_BKT_SIZE_S)
++#define RC_BKT_SIZE_MASK (3 << RC_BKT_SIZE_S)
++#define RC_DLF_EN BIT(4)
++#define RC_BCAST_EN BIT(5)
++#define RC_MCAST_EN BIT(6)
++#define RC_DROP_FRAME BIT(7)
++
++/*************************************************************************
+ * Jumbo Frame Page Registers
+ *************************************************************************/
+
--- /dev/null
+From f5ad83d0a9ce63d0524c5838b7f3a7360bd647ec Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Sat, 31 May 2025 11:11:42 +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.
+
+Fixes: ff39c2d68679 ("net: dsa: b53: Add bridge support")
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ 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 48d5f0b6bbead8e62647a94c18f23be931bcf7b0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Sat, 31 May 2025 11:20:13 +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.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ drivers/net/dsa/b53/b53_common.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1299,6 +1299,9 @@ static int b53_setup(struct dsa_switch *
+
+ b53_reset_mib(dev);
+
++ if (is5325(dev))
++ b53_write8(dev, B53_CTRL_PAGE, B53_PD_MODE_CTRL_25, 0);
++
+ ret = b53_apply_config(dev);
+ if (ret) {
+ dev_err(ds->dev, "failed to apply configuration\n");