2b1975239945d158e0b64616c0b3110bc76cd7c2
[openwrt/staging/xback.git] /
1 From 7028f54b620f8df344b18e46e4a78e266091ab45 Mon Sep 17 00:00:00 2001
2 From: Linus Walleij <linus.walleij@linaro.org>
3 Date: Sun, 26 Sep 2021 00:59:26 +0200
4 Subject: [PATCH 03/11] net: dsa: rtl8366rb: Rewrite weird VLAN filering
5 enablement
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
10 While we were defining one VLAN per port for isolating the ports
11 the port_vlan_filtering() callback was implemented to enable a
12 VLAN on the port + 1. This function makes no sense, not only is
13 it incomplete as it only enables the VLAN, it doesn't do what
14 the callback is supposed to do, which is to selectively enable
15 and disable filtering on a certain port.
16
17 Implement the correct callback: we have two registers dealing
18 with filtering on the RTL9366RB, so we implement an ASIC-specific
19 callback and implement filering using the register bit that makes
20 the switch drop frames if the port is not in the VLAN member set.
21
22 The DSA documentation Documentation/networking/switchdev.rst states:
23
24 When the bridge has VLAN filtering enabled and a PVID is not
25 configured on the ingress port, untagged and 802.1p tagged
26 packets must be dropped. When the bridge has VLAN filtering
27 enabled and a PVID exists on the ingress port, untagged and
28 priority-tagged packets must be accepted and forwarded according
29 to the bridge's port membership of the PVID VLAN. When the
30 bridge has VLAN filtering disabled, the presence/lack of a
31 PVID should not influence the packet forwarding decision.
32
33 To comply with this, we add two arrays of bool in the RTL8366RB
34 state that keeps track of if filtering and PVID is enabled or
35 not for each port. We then add code such that whenever filtering
36 or PVID changes, we update the filter according to the
37 specification.
38
39 Cc: Vladimir Oltean <olteanv@gmail.com>
40 Cc: Mauri Sandberg <sandberg@mailfence.com>
41 Cc: Alvin Šipraga <alsi@bang-olufsen.dk>
42 Cc: Florian Fainelli <f.fainelli@gmail.com>
43 Cc: DENG Qingfang <dqfext@gmail.com>
44 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
45 Signed-off-by: David S. Miller <davem@davemloft.net>
46 ---
47 drivers/net/dsa/realtek-smi-core.h | 2 -
48 drivers/net/dsa/rtl8366.c | 35 ----------
49 drivers/net/dsa/rtl8366rb.c | 102 +++++++++++++++++++++++++++--
50 3 files changed, 95 insertions(+), 44 deletions(-)
51
52 --- a/drivers/net/dsa/realtek-smi-core.h
53 +++ b/drivers/net/dsa/realtek-smi-core.h
54 @@ -129,8 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi
55 int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable);
56 int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable);
57 int rtl8366_reset_vlan(struct realtek_smi *smi);
58 -int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
59 - struct netlink_ext_ack *extack);
60 int rtl8366_vlan_add(struct dsa_switch *ds, int port,
61 const struct switchdev_obj_port_vlan *vlan,
62 struct netlink_ext_ack *extack);
63 --- a/drivers/net/dsa/rtl8366.c
64 +++ b/drivers/net/dsa/rtl8366.c
65 @@ -292,41 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm
66 }
67 EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
68
69 -int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
70 - struct netlink_ext_ack *extack)
71 -{
72 - struct realtek_smi *smi = ds->priv;
73 - struct rtl8366_vlan_4k vlan4k;
74 - int ret;
75 -
76 - /* Use VLAN nr port + 1 since VLAN0 is not valid */
77 - if (!smi->ops->is_vlan_valid(smi, port + 1))
78 - return -EINVAL;
79 -
80 - dev_info(smi->dev, "%s filtering on port %d\n",
81 - vlan_filtering ? "enable" : "disable",
82 - port);
83 -
84 - /* TODO:
85 - * The hardware support filter ID (FID) 0..7, I have no clue how to
86 - * support this in the driver when the callback only says on/off.
87 - */
88 - ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
89 - if (ret)
90 - return ret;
91 -
92 - /* Just set the filter to FID 1 for now then */
93 - ret = rtl8366_set_vlan(smi, port + 1,
94 - vlan4k.member,
95 - vlan4k.untag,
96 - 1);
97 - if (ret)
98 - return ret;
99 -
100 - return 0;
101 -}
102 -EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering);
103 -
104 int rtl8366_vlan_add(struct dsa_switch *ds, int port,
105 const struct switchdev_obj_port_vlan *vlan,
106 struct netlink_ext_ack *extack)
107 --- a/drivers/net/dsa/rtl8366rb.c
108 +++ b/drivers/net/dsa/rtl8366rb.c
109 @@ -143,6 +143,21 @@
110 #define RTL8366RB_PHY_NO_OFFSET 9
111 #define RTL8366RB_PHY_NO_MASK (0x1f << 9)
112
113 +/* VLAN Ingress Control Register 1, one bit per port.
114 + * bit 0 .. 5 will make the switch drop ingress frames without
115 + * VID such as untagged or priority-tagged frames for respective
116 + * port.
117 + * bit 6 .. 11 will make the switch drop ingress frames carrying
118 + * a C-tag with VID != 0 for respective port.
119 + */
120 +#define RTL8366RB_VLAN_INGRESS_CTRL1_REG 0x037E
121 +#define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) (BIT((port)) | BIT((port) + 6))
122 +
123 +/* VLAN Ingress Control Register 2, one bit per port.
124 + * bit0 .. bit5 will make the switch drop all ingress frames with
125 + * a VLAN classification that does not include the port is in its
126 + * member set.
127 + */
128 #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f
129
130 /* LED control registers */
131 @@ -321,9 +336,13 @@
132 /**
133 * struct rtl8366rb - RTL8366RB-specific data
134 * @max_mtu: per-port max MTU setting
135 + * @pvid_enabled: if PVID is set for respective port
136 + * @vlan_filtering: if VLAN filtering is enabled for respective port
137 */
138 struct rtl8366rb {
139 unsigned int max_mtu[RTL8366RB_NUM_PORTS];
140 + bool pvid_enabled[RTL8366RB_NUM_PORTS];
141 + bool vlan_filtering[RTL8366RB_NUM_PORTS];
142 };
143
144 static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
145 @@ -933,11 +952,13 @@ static int rtl8366rb_setup(struct dsa_sw
146 if (ret)
147 return ret;
148
149 - /* Discard VLAN tagged packets if the port is not a member of
150 - * the VLAN with which the packets is associated.
151 - */
152 + /* Accept all packets by default, we enable filtering on-demand */
153 + ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG,
154 + 0);
155 + if (ret)
156 + return ret;
157 ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
158 - RTL8366RB_PORT_ALL);
159 + 0);
160 if (ret)
161 return ret;
162
163 @@ -1209,6 +1230,53 @@ rtl8366rb_port_bridge_leave(struct dsa_s
164 RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0);
165 }
166
167 +/**
168 + * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged frames
169 + * @smi: SMI state container
170 + * @port: the port to drop untagged and C-tagged frames on
171 + * @drop: whether to drop or pass untagged and C-tagged frames
172 + */
173 +static int rtl8366rb_drop_untagged(struct realtek_smi *smi, int port, bool drop)
174 +{
175 + return regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG,
176 + RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port),
177 + drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0);
178 +}
179 +
180 +static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port,
181 + bool vlan_filtering,
182 + struct netlink_ext_ack *extack)
183 +{
184 + struct realtek_smi *smi = ds->priv;
185 + struct rtl8366rb *rb;
186 + int ret;
187 +
188 + rb = smi->chip_data;
189 +
190 + dev_dbg(smi->dev, "port %d: %s VLAN filtering\n", port,
191 + vlan_filtering ? "enable" : "disable");
192 +
193 + /* If the port is not in the member set, the frame will be dropped */
194 + ret = regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
195 + BIT(port), vlan_filtering ? BIT(port) : 0);
196 + if (ret)
197 + return ret;
198 +
199 + /* Keep track if filtering is enabled on each port */
200 + rb->vlan_filtering[port] = vlan_filtering;
201 +
202 + /* If VLAN filtering is enabled and PVID is also enabled, we must
203 + * not drop any untagged or C-tagged frames. If we turn off VLAN
204 + * filtering on a port, we need ti accept any frames.
205 + */
206 + if (vlan_filtering)
207 + ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]);
208 + else
209 + ret = rtl8366rb_drop_untagged(smi, port, false);
210 +
211 + return ret;
212 +}
213 +
214 static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
215 {
216 struct realtek_smi *smi = ds->priv;
217 @@ -1420,14 +1488,34 @@ static int rtl8366rb_get_mc_index(struct
218
219 static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int index)
220 {
221 + struct rtl8366rb *rb;
222 + bool pvid_enabled;
223 + int ret;
224 +
225 + rb = smi->chip_data;
226 + pvid_enabled = !!index;
227 +
228 if (port >= smi->num_ports || index >= RTL8366RB_NUM_VLANS)
229 return -EINVAL;
230
231 - return regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
232 + ret = regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
233 RTL8366RB_PORT_VLAN_CTRL_MASK <<
234 RTL8366RB_PORT_VLAN_CTRL_SHIFT(port),
235 (index & RTL8366RB_PORT_VLAN_CTRL_MASK) <<
236 RTL8366RB_PORT_VLAN_CTRL_SHIFT(port));
237 + if (ret)
238 + return ret;
239 +
240 + rb->pvid_enabled[port] = pvid_enabled;
241 +
242 + /* If VLAN filtering is enabled and PVID is also enabled, we must
243 + * not drop any untagged or C-tagged frames. Make sure to update the
244 + * filtering setting.
245 + */
246 + if (rb->vlan_filtering[port])
247 + ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled);
248 +
249 + return ret;
250 }
251
252 static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan)
253 @@ -1437,7 +1525,7 @@ static bool rtl8366rb_is_vlan_valid(stru
254 if (smi->vlan4k_enabled)
255 max = RTL8366RB_NUM_VIDS - 1;
256
257 - if (vlan == 0 || vlan > max)
258 + if (vlan > max)
259 return false;
260
261 return true;
262 @@ -1594,7 +1682,7 @@ static const struct dsa_switch_ops rtl83
263 .get_sset_count = rtl8366_get_sset_count,
264 .port_bridge_join = rtl8366rb_port_bridge_join,
265 .port_bridge_leave = rtl8366rb_port_bridge_leave,
266 - .port_vlan_filtering = rtl8366_vlan_filtering,
267 + .port_vlan_filtering = rtl8366rb_vlan_filtering,
268 .port_vlan_add = rtl8366_vlan_add,
269 .port_vlan_del = rtl8366_vlan_del,
270 .port_enable = rtl8366rb_port_enable,