diff mbox series

[1/3] generic: backport 5.16 RTL8366RB improvements

Message ID 20220411214619.3611855-2-linus.walleij@linaro.org
State Accepted
Delegated to: Petr Štetiar
Headers show
Series Update Gemini to v5.15 | expand

Commit Message

Linus Walleij April 11, 2022, 9:46 p.m. UTC
The prerequisite DSA changes for the nice RTL8366RB improvements
are already backported so bring back these changes as well.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 ...-rtl8366rb-Support-bridge-offloading.patch | 141 +++++++++
 ...-dsa-rtl8366-Drop-custom-VLAN-set-up.patch | 118 ++++++++
 ...b-Rewrite-weird-VLAN-filering-enable.patch | 270 ++++++++++++++++++
 ...-Drop-and-depromote-pointless-prints.patch |  51 ++++
 ...tl8366rb-Use-core-filtering-tracking.patch |  61 ++++
 ...rtl8366rb-Support-disabling-learning.patch | 115 ++++++++
 ...net-dsa-rtl8366rb-Support-fast-aging.patch |  57 ++++
 ...-rtl8366rb-Support-setting-STP-state.patch | 107 +++++++
 8 files changed, 920 insertions(+)
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch
 create mode 100644 target/linux/generic/backport-5.15/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch
diff mbox series

Patch

diff --git a/target/linux/generic/backport-5.15/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch b/target/linux/generic/backport-5.15/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch
new file mode 100644
index 000000000000..78570c5e6e3e
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch
@@ -0,0 +1,141 @@ 
+From c9111895fd38dadf125e07be627778a9950d8d77 Mon Sep 17 00:00:00 2001
+From: DENG Qingfang <dqfext@gmail.com>
+Date: Sun, 26 Sep 2021 00:59:24 +0200
+Subject: [PATCH 01/11] net: dsa: rtl8366rb: Support bridge offloading
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use port isolation registers to configure bridge offloading.
+
+Tested on the D-Link DIR-685, switching between ports and
+sniffing ports to make sure no packets leak.
+
+Cc: Vladimir Oltean <olteanv@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366rb.c | 86 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 86 insertions(+)
+
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -300,6 +300,13 @@
+ #define RTL8366RB_INTERRUPT_STATUS_REG	0x0442
+ #define RTL8366RB_NUM_INTERRUPT		14 /* 0..13 */
+ 
++/* Port isolation registers */
++#define RTL8366RB_PORT_ISO_BASE		0x0F08
++#define RTL8366RB_PORT_ISO(pnum)	(RTL8366RB_PORT_ISO_BASE + (pnum))
++#define RTL8366RB_PORT_ISO_EN		BIT(0)
++#define RTL8366RB_PORT_ISO_PORTS_MASK	GENMASK(7, 1)
++#define RTL8366RB_PORT_ISO_PORTS(pmask)	((pmask) << 1)
++
+ /* bits 0..5 enable force when cleared */
+ #define RTL8366RB_MAC_FORCE_CTRL_REG	0x0F11
+ 
+@@ -835,6 +842,21 @@ static int rtl8366rb_setup(struct dsa_sw
+ 	if (ret)
+ 		return ret;
+ 
++	/* Isolate all user ports so they can only send packets to itself and the CPU port */
++	for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
++		ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(i),
++				   RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) |
++				   RTL8366RB_PORT_ISO_EN);
++		if (ret)
++			return ret;
++	}
++	/* CPU port can send packets to all ports */
++	ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU),
++			   RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) |
++			   RTL8366RB_PORT_ISO_EN);
++	if (ret)
++		return ret;
++
+ 	/* Set up the "green ethernet" feature */
+ 	ret = rtl8366rb_jam_table(rtl8366rb_green_jam,
+ 				  ARRAY_SIZE(rtl8366rb_green_jam), smi, false);
+@@ -1127,6 +1149,68 @@ rtl8366rb_port_disable(struct dsa_switch
+ 	rb8366rb_set_port_led(smi, port, false);
+ }
+ 
++static int
++rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port,
++			   struct net_device *bridge)
++{
++	struct realtek_smi *smi = ds->priv;
++	unsigned int port_bitmap = 0;
++	int ret, i;
++
++	/* Loop over all other ports than the current one */
++	for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
++		/* Current port handled last */
++		if (i == port)
++			continue;
++		/* Not on this bridge */
++		if (dsa_to_port(ds, i)->bridge_dev != bridge)
++			continue;
++		/* Join this port to each other port on the bridge */
++		ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i),
++					 RTL8366RB_PORT_ISO_PORTS(BIT(port)),
++					 RTL8366RB_PORT_ISO_PORTS(BIT(port)));
++		if (ret)
++			dev_err(smi->dev, "failed to join port %d\n", port);
++
++		port_bitmap |= BIT(i);
++	}
++
++	/* Set the bits for the ports we can access */
++	return regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port),
++				  RTL8366RB_PORT_ISO_PORTS(port_bitmap),
++				  RTL8366RB_PORT_ISO_PORTS(port_bitmap));
++}
++
++static void
++rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port,
++			    struct net_device *bridge)
++{
++	struct realtek_smi *smi = ds->priv;
++	unsigned int port_bitmap = 0;
++	int ret, i;
++
++	/* Loop over all other ports than this one */
++	for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
++		/* Current port handled last */
++		if (i == port)
++			continue;
++		/* Not on this bridge */
++		if (dsa_to_port(ds, i)->bridge_dev != bridge)
++			continue;
++		/* Remove this port from any other port on the bridge */
++		ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i),
++					 RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0);
++		if (ret)
++			dev_err(smi->dev, "failed to leave port %d\n", port);
++
++		port_bitmap |= BIT(i);
++	}
++
++	/* Clear the bits for the ports we can not access, leave ourselves */
++	regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port),
++			   RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0);
++}
++
+ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ {
+ 	struct realtek_smi *smi = ds->priv;
+@@ -1510,6 +1594,8 @@ static const struct dsa_switch_ops rtl83
+ 	.get_strings = rtl8366_get_strings,
+ 	.get_ethtool_stats = rtl8366_get_ethtool_stats,
+ 	.get_sset_count = rtl8366_get_sset_count,
++	.port_bridge_join = rtl8366rb_port_bridge_join,
++	.port_bridge_leave = rtl8366rb_port_bridge_leave,
+ 	.port_vlan_filtering = rtl8366_vlan_filtering,
+ 	.port_vlan_add = rtl8366_vlan_add,
+ 	.port_vlan_del = rtl8366_vlan_del,
diff --git a/target/linux/generic/backport-5.15/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch b/target/linux/generic/backport-5.15/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch
new file mode 100644
index 000000000000..e61349a32cab
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch
@@ -0,0 +1,118 @@ 
+From 96cf10a8e7297065459473c081a6fb6432a22312 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Sun, 26 Sep 2021 00:59:25 +0200
+Subject: [PATCH 02/11] net: dsa: rtl8366: Drop custom VLAN set-up
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This hacky default VLAN setup was done in order to direct
+packets to the right ports and provide port isolation, both
+which we now support properly using custom tags and proper
+bridge port isolation.
+
+We can drop the custom VLAN code and leave all VLAN handling
+alone, as users expect things to be. We can also drop
+ds->configure_vlan_while_not_filtering = false; and let
+the core deal with any VLANs it wants.
+
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/realtek-smi-core.h |  1 -
+ drivers/net/dsa/rtl8366.c          | 48 ------------------------------
+ drivers/net/dsa/rtl8366rb.c        |  4 +--
+ 3 files changed, 1 insertion(+), 52 deletions(-)
+
+--- a/drivers/net/dsa/realtek-smi-core.h
++++ b/drivers/net/dsa/realtek-smi-core.h
+@@ -129,7 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi
+ int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable);
+ int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable);
+ int rtl8366_reset_vlan(struct realtek_smi *smi);
+-int rtl8366_init_vlan(struct realtek_smi *smi);
+ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+ 			   struct netlink_ext_ack *extack);
+ int rtl8366_vlan_add(struct dsa_switch *ds, int port,
+--- a/drivers/net/dsa/rtl8366.c
++++ b/drivers/net/dsa/rtl8366.c
+@@ -292,54 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm
+ }
+ EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
+ 
+-int rtl8366_init_vlan(struct realtek_smi *smi)
+-{
+-	int port;
+-	int ret;
+-
+-	ret = rtl8366_reset_vlan(smi);
+-	if (ret)
+-		return ret;
+-
+-	/* Loop over the available ports, for each port, associate
+-	 * it with the VLAN (port+1)
+-	 */
+-	for (port = 0; port < smi->num_ports; port++) {
+-		u32 mask;
+-
+-		if (port == smi->cpu_port)
+-			/* For the CPU port, make all ports members of this
+-			 * VLAN.
+-			 */
+-			mask = GENMASK((int)smi->num_ports - 1, 0);
+-		else
+-			/* For all other ports, enable itself plus the
+-			 * CPU port.
+-			 */
+-			mask = BIT(port) | BIT(smi->cpu_port);
+-
+-		/* For each port, set the port as member of VLAN (port+1)
+-		 * and untagged, except for the CPU port: the CPU port (5) is
+-		 * member of VLAN 6 and so are ALL the other ports as well.
+-		 * Use filter 0 (no filter).
+-		 */
+-		dev_info(smi->dev, "VLAN%d port mask for port %d, %08x\n",
+-			 (port + 1), port, mask);
+-		ret = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0);
+-		if (ret)
+-			return ret;
+-
+-		dev_info(smi->dev, "VLAN%d port %d, PVID set to %d\n",
+-			 (port + 1), port, (port + 1));
+-		ret = rtl8366_set_pvid(smi, port, (port + 1));
+-		if (ret)
+-			return ret;
+-	}
+-
+-	return rtl8366_enable_vlan(smi, true);
+-}
+-EXPORT_SYMBOL_GPL(rtl8366_init_vlan);
+-
+ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+ 			   struct netlink_ext_ack *extack)
+ {
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -985,7 +985,7 @@ static int rtl8366rb_setup(struct dsa_sw
+ 			return ret;
+ 	}
+ 
+-	ret = rtl8366_init_vlan(smi);
++	ret = rtl8366_reset_vlan(smi);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -999,8 +999,6 @@ static int rtl8366rb_setup(struct dsa_sw
+ 		return -ENODEV;
+ 	}
+ 
+-	ds->configure_vlan_while_not_filtering = false;
+-
+ 	return 0;
+ }
+ 
diff --git a/target/linux/generic/backport-5.15/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch b/target/linux/generic/backport-5.15/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch
new file mode 100644
index 000000000000..2b1975239945
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch
@@ -0,0 +1,270 @@ 
+From 7028f54b620f8df344b18e46e4a78e266091ab45 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Sun, 26 Sep 2021 00:59:26 +0200
+Subject: [PATCH 03/11] net: dsa: rtl8366rb: Rewrite weird VLAN filering
+ enablement
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+While we were defining one VLAN per port for isolating the ports
+the port_vlan_filtering() callback was implemented to enable a
+VLAN on the port + 1. This function makes no sense, not only is
+it incomplete as it only enables the VLAN, it doesn't do what
+the callback is supposed to do, which is to selectively enable
+and disable filtering on a certain port.
+
+Implement the correct callback: we have two registers dealing
+with filtering on the RTL9366RB, so we implement an ASIC-specific
+callback and implement filering using the register bit that makes
+the switch drop frames if the port is not in the VLAN member set.
+
+The DSA documentation Documentation/networking/switchdev.rst states:
+
+  When the bridge has VLAN filtering enabled and a PVID is not
+  configured on the ingress port, untagged and 802.1p tagged
+  packets must be dropped. When the bridge has VLAN filtering
+  enabled and a PVID exists on the ingress port, untagged and
+  priority-tagged packets must be accepted and forwarded according
+  to the bridge's port membership of the PVID VLAN. When the
+  bridge has VLAN filtering disabled, the presence/lack of a
+  PVID should not influence the packet forwarding decision.
+
+To comply with this, we add two arrays of bool in the RTL8366RB
+state that keeps track of if filtering and PVID is enabled or
+not for each port. We then add code such that whenever filtering
+or PVID changes, we update the filter according to the
+specification.
+
+Cc: Vladimir Oltean <olteanv@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: Alvin Šipraga <alsi@bang-olufsen.dk>
+Cc: Florian Fainelli <f.fainelli@gmail.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/realtek-smi-core.h |   2 -
+ drivers/net/dsa/rtl8366.c          |  35 ----------
+ drivers/net/dsa/rtl8366rb.c        | 102 +++++++++++++++++++++++++++--
+ 3 files changed, 95 insertions(+), 44 deletions(-)
+
+--- a/drivers/net/dsa/realtek-smi-core.h
++++ b/drivers/net/dsa/realtek-smi-core.h
+@@ -129,8 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi
+ int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable);
+ int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable);
+ int rtl8366_reset_vlan(struct realtek_smi *smi);
+-int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+-			   struct netlink_ext_ack *extack);
+ int rtl8366_vlan_add(struct dsa_switch *ds, int port,
+ 		     const struct switchdev_obj_port_vlan *vlan,
+ 		     struct netlink_ext_ack *extack);
+--- a/drivers/net/dsa/rtl8366.c
++++ b/drivers/net/dsa/rtl8366.c
+@@ -292,41 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm
+ }
+ EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
+ 
+-int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+-			   struct netlink_ext_ack *extack)
+-{
+-	struct realtek_smi *smi = ds->priv;
+-	struct rtl8366_vlan_4k vlan4k;
+-	int ret;
+-
+-	/* Use VLAN nr port + 1 since VLAN0 is not valid */
+-	if (!smi->ops->is_vlan_valid(smi, port + 1))
+-		return -EINVAL;
+-
+-	dev_info(smi->dev, "%s filtering on port %d\n",
+-		 vlan_filtering ? "enable" : "disable",
+-		 port);
+-
+-	/* TODO:
+-	 * The hardware support filter ID (FID) 0..7, I have no clue how to
+-	 * support this in the driver when the callback only says on/off.
+-	 */
+-	ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
+-	if (ret)
+-		return ret;
+-
+-	/* Just set the filter to FID 1 for now then */
+-	ret = rtl8366_set_vlan(smi, port + 1,
+-			       vlan4k.member,
+-			       vlan4k.untag,
+-			       1);
+-	if (ret)
+-		return ret;
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering);
+-
+ int rtl8366_vlan_add(struct dsa_switch *ds, int port,
+ 		     const struct switchdev_obj_port_vlan *vlan,
+ 		     struct netlink_ext_ack *extack)
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -143,6 +143,21 @@
+ #define RTL8366RB_PHY_NO_OFFSET			9
+ #define RTL8366RB_PHY_NO_MASK			(0x1f << 9)
+ 
++/* VLAN Ingress Control Register 1, one bit per port.
++ * bit 0 .. 5 will make the switch drop ingress frames without
++ * VID such as untagged or priority-tagged frames for respective
++ * port.
++ * bit 6 .. 11 will make the switch drop ingress frames carrying
++ * a C-tag with VID != 0 for respective port.
++ */
++#define RTL8366RB_VLAN_INGRESS_CTRL1_REG	0x037E
++#define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port)	(BIT((port)) | BIT((port) + 6))
++
++/* VLAN Ingress Control Register 2, one bit per port.
++ * bit0 .. bit5 will make the switch drop all ingress frames with
++ * a VLAN classification that does not include the port is in its
++ * member set.
++ */
+ #define RTL8366RB_VLAN_INGRESS_CTRL2_REG	0x037f
+ 
+ /* LED control registers */
+@@ -321,9 +336,13 @@
+ /**
+  * struct rtl8366rb - RTL8366RB-specific data
+  * @max_mtu: per-port max MTU setting
++ * @pvid_enabled: if PVID is set for respective port
++ * @vlan_filtering: if VLAN filtering is enabled for respective port
+  */
+ struct rtl8366rb {
+ 	unsigned int max_mtu[RTL8366RB_NUM_PORTS];
++	bool pvid_enabled[RTL8366RB_NUM_PORTS];
++	bool vlan_filtering[RTL8366RB_NUM_PORTS];
+ };
+ 
+ static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
+@@ -933,11 +952,13 @@ static int rtl8366rb_setup(struct dsa_sw
+ 	if (ret)
+ 		return ret;
+ 
+-	/* Discard VLAN tagged packets if the port is not a member of
+-	 * the VLAN with which the packets is associated.
+-	 */
++	/* Accept all packets by default, we enable filtering on-demand */
++	ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG,
++			   0);
++	if (ret)
++		return ret;
+ 	ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
+-			   RTL8366RB_PORT_ALL);
++			   0);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -1209,6 +1230,53 @@ rtl8366rb_port_bridge_leave(struct dsa_s
+ 			   RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0);
+ }
+ 
++/**
++ * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged frames
++ * @smi: SMI state container
++ * @port: the port to drop untagged and C-tagged frames on
++ * @drop: whether to drop or pass untagged and C-tagged frames
++ */
++static int rtl8366rb_drop_untagged(struct realtek_smi *smi, int port, bool drop)
++{
++	return regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG,
++				  RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port),
++				  drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0);
++}
++
++static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port,
++				    bool vlan_filtering,
++				    struct netlink_ext_ack *extack)
++{
++	struct realtek_smi *smi = ds->priv;
++	struct rtl8366rb *rb;
++	int ret;
++
++	rb = smi->chip_data;
++
++	dev_dbg(smi->dev, "port %d: %s VLAN filtering\n", port,
++		vlan_filtering ? "enable" : "disable");
++
++	/* If the port is not in the member set, the frame will be dropped */
++	ret = regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
++				 BIT(port), vlan_filtering ? BIT(port) : 0);
++	if (ret)
++		return ret;
++
++	/* Keep track if filtering is enabled on each port */
++	rb->vlan_filtering[port] = vlan_filtering;
++
++	/* If VLAN filtering is enabled and PVID is also enabled, we must
++	 * not drop any untagged or C-tagged frames. If we turn off VLAN
++	 * filtering on a port, we need ti accept any frames.
++	 */
++	if (vlan_filtering)
++		ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]);
++	else
++		ret = rtl8366rb_drop_untagged(smi, port, false);
++
++	return ret;
++}
++
+ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ {
+ 	struct realtek_smi *smi = ds->priv;
+@@ -1420,14 +1488,34 @@ static int rtl8366rb_get_mc_index(struct
+ 
+ static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int index)
+ {
++	struct rtl8366rb *rb;
++	bool pvid_enabled;
++	int ret;
++
++	rb = smi->chip_data;
++	pvid_enabled = !!index;
++
+ 	if (port >= smi->num_ports || index >= RTL8366RB_NUM_VLANS)
+ 		return -EINVAL;
+ 
+-	return regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
++	ret = regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
+ 				RTL8366RB_PORT_VLAN_CTRL_MASK <<
+ 					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port),
+ 				(index & RTL8366RB_PORT_VLAN_CTRL_MASK) <<
+ 					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port));
++	if (ret)
++		return ret;
++
++	rb->pvid_enabled[port] = pvid_enabled;
++
++	/* If VLAN filtering is enabled and PVID is also enabled, we must
++	 * not drop any untagged or C-tagged frames. Make sure to update the
++	 * filtering setting.
++	 */
++	if (rb->vlan_filtering[port])
++		ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled);
++
++	return ret;
+ }
+ 
+ static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan)
+@@ -1437,7 +1525,7 @@ static bool rtl8366rb_is_vlan_valid(stru
+ 	if (smi->vlan4k_enabled)
+ 		max = RTL8366RB_NUM_VIDS - 1;
+ 
+-	if (vlan == 0 || vlan > max)
++	if (vlan > max)
+ 		return false;
+ 
+ 	return true;
+@@ -1594,7 +1682,7 @@ static const struct dsa_switch_ops rtl83
+ 	.get_sset_count = rtl8366_get_sset_count,
+ 	.port_bridge_join = rtl8366rb_port_bridge_join,
+ 	.port_bridge_leave = rtl8366rb_port_bridge_leave,
+-	.port_vlan_filtering = rtl8366_vlan_filtering,
++	.port_vlan_filtering = rtl8366rb_vlan_filtering,
+ 	.port_vlan_add = rtl8366_vlan_add,
+ 	.port_vlan_del = rtl8366_vlan_del,
+ 	.port_enable = rtl8366rb_port_enable,
diff --git a/target/linux/generic/backport-5.15/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch b/target/linux/generic/backport-5.15/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch
new file mode 100644
index 000000000000..b56032c366b0
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch
@@ -0,0 +1,51 @@ 
+From ddb59a5dc42714999c335dab4bf256125ba3120c Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Sun, 26 Sep 2021 00:59:29 +0200
+Subject: [PATCH 06/11] net: dsa: rtl8366: Drop and depromote pointless prints
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We don't need a message for every VLAN association, dbg
+is fine. The message about adding the DSA or CPU
+port to a VLAN is directly misleading, this is perfectly
+fine.
+
+Cc: Vladimir Oltean <olteanv@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/dsa/rtl8366.c
++++ b/drivers/net/dsa/rtl8366.c
+@@ -318,12 +318,9 @@ int rtl8366_vlan_add(struct dsa_switch *
+ 		return ret;
+ 	}
+ 
+-	dev_info(smi->dev, "add VLAN %d on port %d, %s, %s\n",
+-		 vlan->vid, port, untagged ? "untagged" : "tagged",
+-		 pvid ? " PVID" : "no PVID");
+-
+-	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
+-		dev_err(smi->dev, "port is DSA or CPU port\n");
++	dev_dbg(smi->dev, "add VLAN %d on port %d, %s, %s\n",
++		vlan->vid, port, untagged ? "untagged" : "tagged",
++		pvid ? "PVID" : "no PVID");
+ 
+ 	member |= BIT(port);
+ 
+@@ -356,7 +353,7 @@ int rtl8366_vlan_del(struct dsa_switch *
+ 	struct realtek_smi *smi = ds->priv;
+ 	int ret, i;
+ 
+-	dev_info(smi->dev, "del VLAN %04x on port %d\n", vlan->vid, port);
++	dev_dbg(smi->dev, "del VLAN %d on port %d\n", vlan->vid, port);
+ 
+ 	for (i = 0; i < smi->num_vlan_mc; i++) {
+ 		struct rtl8366_vlan_mc vlanmc;
diff --git a/target/linux/generic/backport-5.15/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch b/target/linux/generic/backport-5.15/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch
new file mode 100644
index 000000000000..8cd1df97f24e
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch
@@ -0,0 +1,61 @@ 
+From 5c9b66f3c8a3f72fa2a58e89a57c6d7afd550bf0 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 29 Sep 2021 13:23:22 +0200
+Subject: [PATCH 07/11] net: dsa: rtl8366rb: Use core filtering tracking
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We added a state variable to track whether a certain port
+was VLAN filtering or not, but we can just inquire the DSA
+core about this.
+
+Cc: Vladimir Oltean <olteanv@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Cc: Alvin Šipraga <alsi@bang-olufsen.dk>
+Cc: Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366rb.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -337,12 +337,10 @@
+  * struct rtl8366rb - RTL8366RB-specific data
+  * @max_mtu: per-port max MTU setting
+  * @pvid_enabled: if PVID is set for respective port
+- * @vlan_filtering: if VLAN filtering is enabled for respective port
+  */
+ struct rtl8366rb {
+ 	unsigned int max_mtu[RTL8366RB_NUM_PORTS];
+ 	bool pvid_enabled[RTL8366RB_NUM_PORTS];
+-	bool vlan_filtering[RTL8366RB_NUM_PORTS];
+ };
+ 
+ static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
+@@ -1262,12 +1260,9 @@ static int rtl8366rb_vlan_filtering(stru
+ 	if (ret)
+ 		return ret;
+ 
+-	/* Keep track if filtering is enabled on each port */
+-	rb->vlan_filtering[port] = vlan_filtering;
+-
+ 	/* If VLAN filtering is enabled and PVID is also enabled, we must
+ 	 * not drop any untagged or C-tagged frames. If we turn off VLAN
+-	 * filtering on a port, we need ti accept any frames.
++	 * filtering on a port, we need to accept any frames.
+ 	 */
+ 	if (vlan_filtering)
+ 		ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]);
+@@ -1512,7 +1507,7 @@ static int rtl8366rb_set_mc_index(struct
+ 	 * not drop any untagged or C-tagged frames. Make sure to update the
+ 	 * filtering setting.
+ 	 */
+-	if (rb->vlan_filtering[port])
++	if (dsa_port_is_vlan_filtering(dsa_to_port(smi->ds, port)))
+ 		ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled);
+ 
+ 	return ret;
diff --git a/target/linux/generic/backport-5.15/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch b/target/linux/generic/backport-5.15/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch
new file mode 100644
index 000000000000..8306eb5aefa1
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch
@@ -0,0 +1,115 @@ 
+From 831a3d26bea0d14f8563eecf96def660a74a3000 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 5 Oct 2021 21:47:02 +0200
+Subject: [PATCH 08/11] net: dsa: rtl8366rb: Support disabling learning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The RTL8366RB hardware supports disabling learning per-port
+so let's make use of this feature. Rename some unfortunately
+named registers in the process.
+
+Suggested-by: Vladimir Oltean <olteanv@gmail.com>
+Cc: Alvin Šipraga <alsi@bang-olufsen.dk>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: Florian Fainelli <f.fainelli@gmail.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366rb.c | 50 ++++++++++++++++++++++++++++++++-----
+ 1 file changed, 44 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -14,6 +14,7 @@
+ 
+ #include <linux/bitops.h>
+ #include <linux/etherdevice.h>
++#include <linux/if_bridge.h>
+ #include <linux/interrupt.h>
+ #include <linux/irqdomain.h>
+ #include <linux/irqchip/chained_irq.h>
+@@ -42,9 +43,12 @@
+ /* Port Enable Control register */
+ #define RTL8366RB_PECR				0x0001
+ 
+-/* Switch Security Control registers */
+-#define RTL8366RB_SSCR0				0x0002
+-#define RTL8366RB_SSCR1				0x0003
++/* Switch per-port learning disablement register */
++#define RTL8366RB_PORT_LEARNDIS_CTRL		0x0002
++
++/* Security control, actually aging register */
++#define RTL8366RB_SECURITY_CTRL			0x0003
++
+ #define RTL8366RB_SSCR2				0x0004
+ #define RTL8366RB_SSCR2_DROP_UNKNOWN_DA		BIT(0)
+ 
+@@ -927,13 +931,14 @@ static int rtl8366rb_setup(struct dsa_sw
+ 		/* layer 2 size, see rtl8366rb_change_mtu() */
+ 		rb->max_mtu[i] = 1532;
+ 
+-	/* Enable learning for all ports */
+-	ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0);
++	/* Disable learning for all ports */
++	ret = regmap_write(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL,
++			   RTL8366RB_PORT_ALL);
+ 	if (ret)
+ 		return ret;
+ 
+ 	/* Enable auto ageing for all ports */
+-	ret = regmap_write(smi->map, RTL8366RB_SSCR1, 0);
++	ret = regmap_write(smi->map, RTL8366RB_SECURITY_CTRL, 0);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -1272,6 +1277,37 @@ static int rtl8366rb_vlan_filtering(stru
+ 	return ret;
+ }
+ 
++static int
++rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port,
++				struct switchdev_brport_flags flags,
++				struct netlink_ext_ack *extack)
++{
++	/* We support enabling/disabling learning */
++	if (flags.mask & ~(BR_LEARNING))
++		return -EINVAL;
++
++	return 0;
++}
++
++static int
++rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port,
++			    struct switchdev_brport_flags flags,
++			    struct netlink_ext_ack *extack)
++{
++	struct realtek_smi *smi = ds->priv;
++	int ret;
++
++	if (flags.mask & BR_LEARNING) {
++		ret = regmap_update_bits(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL,
++					 BIT(port),
++					 (flags.val & BR_LEARNING) ? 0 : BIT(port));
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
+ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ {
+ 	struct realtek_smi *smi = ds->priv;
+@@ -1682,6 +1718,8 @@ static const struct dsa_switch_ops rtl83
+ 	.port_vlan_del = rtl8366_vlan_del,
+ 	.port_enable = rtl8366rb_port_enable,
+ 	.port_disable = rtl8366rb_port_disable,
++	.port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags,
++	.port_bridge_flags = rtl8366rb_port_bridge_flags,
+ 	.port_change_mtu = rtl8366rb_change_mtu,
+ 	.port_max_mtu = rtl8366rb_max_mtu,
+ };
diff --git a/target/linux/generic/backport-5.15/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch b/target/linux/generic/backport-5.15/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch
new file mode 100644
index 000000000000..a74108e23dbd
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch
@@ -0,0 +1,57 @@ 
+From 8eb13420eb9ab4a4e2ebd612bf5dc9dba0039236 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 5 Oct 2021 21:47:03 +0200
+Subject: [PATCH 09/11] net: dsa: rtl8366rb: Support fast aging
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This implements fast aging per-port using the special "security"
+register, which will flush any learned L2 LUT entries on a port.
+
+The vendor API just enabled setting and clearing this bit, so
+we set it to age out any entries on the port and then we clear
+it again.
+
+Suggested-by: Vladimir Oltean <olteanv@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Cc: Florian Fainelli <f.fainelli@gmail.com>
+Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366rb.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -1308,6 +1308,19 @@ rtl8366rb_port_bridge_flags(struct dsa_s
+ 	return 0;
+ }
+ 
++static void
++rtl8366rb_port_fast_age(struct dsa_switch *ds, int port)
++{
++	struct realtek_smi *smi = ds->priv;
++
++	/* This will age out any learned L2 entries */
++	regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL,
++			   BIT(port), BIT(port));
++	/* Restore the normal state of things */
++	regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL,
++			   BIT(port), 0);
++}
++
+ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ {
+ 	struct realtek_smi *smi = ds->priv;
+@@ -1720,6 +1733,7 @@ static const struct dsa_switch_ops rtl83
+ 	.port_disable = rtl8366rb_port_disable,
+ 	.port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags,
+ 	.port_bridge_flags = rtl8366rb_port_bridge_flags,
++	.port_fast_age = rtl8366rb_port_fast_age,
+ 	.port_change_mtu = rtl8366rb_change_mtu,
+ 	.port_max_mtu = rtl8366rb_max_mtu,
+ };
diff --git a/target/linux/generic/backport-5.15/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch b/target/linux/generic/backport-5.15/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch
new file mode 100644
index 000000000000..e787ce948119
--- /dev/null
+++ b/target/linux/generic/backport-5.15/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch
@@ -0,0 +1,107 @@ 
+From 90c855471a89d3e05ecf5b6464bd04abf2c83b70 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 5 Oct 2021 21:47:04 +0200
+Subject: [PATCH 10/11] net: dsa: rtl8366rb: Support setting STP state
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This adds support for setting the STP state to the RTL8366RB
+DSA switch. This rids the following message from the kernel on
+e.g. OpenWrt:
+
+DSA: failed to set STP state 3 (-95)
+
+Since the RTL8366RB has one STP state register per FID with
+two bit per port in each, we simply loop over all the FIDs
+and set the state on all of them.
+
+Cc: Vladimir Oltean <olteanv@gmail.com>
+Cc: Alvin Šipraga <alsi@bang-olufsen.dk>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366rb.c | 48 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -110,6 +110,18 @@
+ 
+ #define RTL8366RB_POWER_SAVING_REG	0x0021
+ 
++/* Spanning tree status (STP) control, two bits per port per FID */
++#define RTL8366RB_STP_STATE_BASE	0x0050 /* 0x0050..0x0057 */
++#define RTL8366RB_STP_STATE_DISABLED	0x0
++#define RTL8366RB_STP_STATE_BLOCKING	0x1
++#define RTL8366RB_STP_STATE_LEARNING	0x2
++#define RTL8366RB_STP_STATE_FORWARDING	0x3
++#define RTL8366RB_STP_MASK		GENMASK(1, 0)
++#define RTL8366RB_STP_STATE(port, state) \
++	((state) << ((port) * 2))
++#define RTL8366RB_STP_STATE_MASK(port) \
++	RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK)
++
+ /* CPU port control reg */
+ #define RTL8368RB_CPU_CTRL_REG		0x0061
+ #define RTL8368RB_CPU_PORTS_MSK		0x00FF
+@@ -234,6 +246,7 @@
+ #define RTL8366RB_NUM_LEDGROUPS		4
+ #define RTL8366RB_NUM_VIDS		4096
+ #define RTL8366RB_PRIORITYMAX		7
++#define RTL8366RB_NUM_FIDS		8
+ #define RTL8366RB_FIDMAX		7
+ 
+ #define RTL8366RB_PORT_1		BIT(0) /* In userspace port 0 */
+@@ -1309,6 +1322,40 @@ rtl8366rb_port_bridge_flags(struct dsa_s
+ }
+ 
+ static void
++rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
++{
++	struct realtek_smi *smi = ds->priv;
++	u32 val;
++	int i;
++
++	switch (state) {
++	case BR_STATE_DISABLED:
++		val = RTL8366RB_STP_STATE_DISABLED;
++		break;
++	case BR_STATE_BLOCKING:
++	case BR_STATE_LISTENING:
++		val = RTL8366RB_STP_STATE_BLOCKING;
++		break;
++	case BR_STATE_LEARNING:
++		val = RTL8366RB_STP_STATE_LEARNING;
++		break;
++	case BR_STATE_FORWARDING:
++		val = RTL8366RB_STP_STATE_FORWARDING;
++		break;
++	default:
++		dev_err(smi->dev, "unknown bridge state requested\n");
++		return;
++	};
++
++	/* Set the same status for the port on all the FIDs */
++	for (i = 0; i < RTL8366RB_NUM_FIDS; i++) {
++		regmap_update_bits(smi->map, RTL8366RB_STP_STATE_BASE + i,
++				   RTL8366RB_STP_STATE_MASK(port),
++				   RTL8366RB_STP_STATE(port, val));
++	}
++}
++
++static void
+ rtl8366rb_port_fast_age(struct dsa_switch *ds, int port)
+ {
+ 	struct realtek_smi *smi = ds->priv;
+@@ -1733,6 +1780,7 @@ static const struct dsa_switch_ops rtl83
+ 	.port_disable = rtl8366rb_port_disable,
+ 	.port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags,
+ 	.port_bridge_flags = rtl8366rb_port_bridge_flags,
++	.port_stp_state_set = rtl8366rb_port_stp_state_set,
+ 	.port_fast_age = rtl8366rb_port_fast_age,
+ 	.port_change_mtu = rtl8366rb_change_mtu,
+ 	.port_max_mtu = rtl8366rb_max_mtu,