generic: backport 5.16 RTL8366RB improvements
[openwrt/staging/mkresin.git] / target / linux / generic / backport-5.15 / 774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch
1 From c9111895fd38dadf125e07be627778a9950d8d77 Mon Sep 17 00:00:00 2001
2 From: DENG Qingfang <dqfext@gmail.com>
3 Date: Sun, 26 Sep 2021 00:59:24 +0200
4 Subject: [PATCH 01/11] net: dsa: rtl8366rb: Support bridge offloading
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 Use port isolation registers to configure bridge offloading.
10
11 Tested on the D-Link DIR-685, switching between ports and
12 sniffing ports to make sure no packets leak.
13
14 Cc: Vladimir Oltean <olteanv@gmail.com>
15 Cc: Mauri Sandberg <sandberg@mailfence.com>
16 Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
17 Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
18 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
19 Signed-off-by: DENG Qingfang <dqfext@gmail.com>
20 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
21 Signed-off-by: David S. Miller <davem@davemloft.net>
22 ---
23 drivers/net/dsa/rtl8366rb.c | 86 +++++++++++++++++++++++++++++++++++++
24 1 file changed, 86 insertions(+)
25
26 --- a/drivers/net/dsa/rtl8366rb.c
27 +++ b/drivers/net/dsa/rtl8366rb.c
28 @@ -300,6 +300,13 @@
29 #define RTL8366RB_INTERRUPT_STATUS_REG 0x0442
30 #define RTL8366RB_NUM_INTERRUPT 14 /* 0..13 */
31
32 +/* Port isolation registers */
33 +#define RTL8366RB_PORT_ISO_BASE 0x0F08
34 +#define RTL8366RB_PORT_ISO(pnum) (RTL8366RB_PORT_ISO_BASE + (pnum))
35 +#define RTL8366RB_PORT_ISO_EN BIT(0)
36 +#define RTL8366RB_PORT_ISO_PORTS_MASK GENMASK(7, 1)
37 +#define RTL8366RB_PORT_ISO_PORTS(pmask) ((pmask) << 1)
38 +
39 /* bits 0..5 enable force when cleared */
40 #define RTL8366RB_MAC_FORCE_CTRL_REG 0x0F11
41
42 @@ -835,6 +842,21 @@ static int rtl8366rb_setup(struct dsa_sw
43 if (ret)
44 return ret;
45
46 + /* Isolate all user ports so they can only send packets to itself and the CPU port */
47 + for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
48 + ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(i),
49 + RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) |
50 + RTL8366RB_PORT_ISO_EN);
51 + if (ret)
52 + return ret;
53 + }
54 + /* CPU port can send packets to all ports */
55 + ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU),
56 + RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) |
57 + RTL8366RB_PORT_ISO_EN);
58 + if (ret)
59 + return ret;
60 +
61 /* Set up the "green ethernet" feature */
62 ret = rtl8366rb_jam_table(rtl8366rb_green_jam,
63 ARRAY_SIZE(rtl8366rb_green_jam), smi, false);
64 @@ -1127,6 +1149,68 @@ rtl8366rb_port_disable(struct dsa_switch
65 rb8366rb_set_port_led(smi, port, false);
66 }
67
68 +static int
69 +rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port,
70 + struct net_device *bridge)
71 +{
72 + struct realtek_smi *smi = ds->priv;
73 + unsigned int port_bitmap = 0;
74 + int ret, i;
75 +
76 + /* Loop over all other ports than the current one */
77 + for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
78 + /* Current port handled last */
79 + if (i == port)
80 + continue;
81 + /* Not on this bridge */
82 + if (dsa_to_port(ds, i)->bridge_dev != bridge)
83 + continue;
84 + /* Join this port to each other port on the bridge */
85 + ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i),
86 + RTL8366RB_PORT_ISO_PORTS(BIT(port)),
87 + RTL8366RB_PORT_ISO_PORTS(BIT(port)));
88 + if (ret)
89 + dev_err(smi->dev, "failed to join port %d\n", port);
90 +
91 + port_bitmap |= BIT(i);
92 + }
93 +
94 + /* Set the bits for the ports we can access */
95 + return regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port),
96 + RTL8366RB_PORT_ISO_PORTS(port_bitmap),
97 + RTL8366RB_PORT_ISO_PORTS(port_bitmap));
98 +}
99 +
100 +static void
101 +rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port,
102 + struct net_device *bridge)
103 +{
104 + struct realtek_smi *smi = ds->priv;
105 + unsigned int port_bitmap = 0;
106 + int ret, i;
107 +
108 + /* Loop over all other ports than this one */
109 + for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
110 + /* Current port handled last */
111 + if (i == port)
112 + continue;
113 + /* Not on this bridge */
114 + if (dsa_to_port(ds, i)->bridge_dev != bridge)
115 + continue;
116 + /* Remove this port from any other port on the bridge */
117 + ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i),
118 + RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0);
119 + if (ret)
120 + dev_err(smi->dev, "failed to leave port %d\n", port);
121 +
122 + port_bitmap |= BIT(i);
123 + }
124 +
125 + /* Clear the bits for the ports we can not access, leave ourselves */
126 + regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port),
127 + RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0);
128 +}
129 +
130 static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
131 {
132 struct realtek_smi *smi = ds->priv;
133 @@ -1510,6 +1594,8 @@ static const struct dsa_switch_ops rtl83
134 .get_strings = rtl8366_get_strings,
135 .get_ethtool_stats = rtl8366_get_ethtool_stats,
136 .get_sset_count = rtl8366_get_sset_count,
137 + .port_bridge_join = rtl8366rb_port_bridge_join,
138 + .port_bridge_leave = rtl8366rb_port_bridge_leave,
139 .port_vlan_filtering = rtl8366_vlan_filtering,
140 .port_vlan_add = rtl8366_vlan_add,
141 .port_vlan_del = rtl8366_vlan_del,