1 // SPDX-License-Identifier: GPL-2.0
2 /* Realtek SMI library helpers for the RTL8366x variants
3  * RTL8366RB and RTL8366S
4  *
5  * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
6  * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
7  * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
8  * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
9  * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
10  */
11 #include <linux/if_bridge.h>
12 #include <net/dsa.h>
13 
14 #include "realtek-smi-core.h"
15 
rtl8366_mc_is_used(struct realtek_smi * smi,int mc_index,int * used)16 int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used)
17 {
18 	int ret;
19 	int i;
20 
21 	*used = 0;
22 	for (i = 0; i < smi->num_ports; i++) {
23 		int index = 0;
24 
25 		ret = smi->ops->get_mc_index(smi, i, &index);
26 		if (ret)
27 			return ret;
28 
29 		if (mc_index == index) {
30 			*used = 1;
31 			break;
32 		}
33 	}
34 
35 	return 0;
36 }
37 EXPORT_SYMBOL_GPL(rtl8366_mc_is_used);
38 
rtl8366_set_vlan(struct realtek_smi * smi,int vid,u32 member,u32 untag,u32 fid)39 int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member,
40 		     u32 untag, u32 fid)
41 {
42 	struct rtl8366_vlan_4k vlan4k;
43 	int ret;
44 	int i;
45 
46 	/* Update the 4K table */
47 	ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
48 	if (ret)
49 		return ret;
50 
51 	vlan4k.member = member;
52 	vlan4k.untag = untag;
53 	vlan4k.fid = fid;
54 	ret = smi->ops->set_vlan_4k(smi, &vlan4k);
55 	if (ret)
56 		return ret;
57 
58 	/* Try to find an existing MC entry for this VID */
59 	for (i = 0; i < smi->num_vlan_mc; i++) {
60 		struct rtl8366_vlan_mc vlanmc;
61 
62 		ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
63 		if (ret)
64 			return ret;
65 
66 		if (vid == vlanmc.vid) {
67 			/* update the MC entry */
68 			vlanmc.member = member;
69 			vlanmc.untag = untag;
70 			vlanmc.fid = fid;
71 
72 			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
73 			break;
74 		}
75 	}
76 
77 	return ret;
78 }
79 EXPORT_SYMBOL_GPL(rtl8366_set_vlan);
80 
rtl8366_get_pvid(struct realtek_smi * smi,int port,int * val)81 int rtl8366_get_pvid(struct realtek_smi *smi, int port, int *val)
82 {
83 	struct rtl8366_vlan_mc vlanmc;
84 	int ret;
85 	int index;
86 
87 	ret = smi->ops->get_mc_index(smi, port, &index);
88 	if (ret)
89 		return ret;
90 
91 	ret = smi->ops->get_vlan_mc(smi, index, &vlanmc);
92 	if (ret)
93 		return ret;
94 
95 	*val = vlanmc.vid;
96 	return 0;
97 }
98 EXPORT_SYMBOL_GPL(rtl8366_get_pvid);
99 
rtl8366_set_pvid(struct realtek_smi * smi,unsigned int port,unsigned int vid)100 int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port,
101 		     unsigned int vid)
102 {
103 	struct rtl8366_vlan_mc vlanmc;
104 	struct rtl8366_vlan_4k vlan4k;
105 	int ret;
106 	int i;
107 
108 	/* Try to find an existing MC entry for this VID */
109 	for (i = 0; i < smi->num_vlan_mc; i++) {
110 		ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
111 		if (ret)
112 			return ret;
113 
114 		if (vid == vlanmc.vid) {
115 			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
116 			if (ret)
117 				return ret;
118 
119 			ret = smi->ops->set_mc_index(smi, port, i);
120 			return ret;
121 		}
122 	}
123 
124 	/* We have no MC entry for this VID, try to find an empty one */
125 	for (i = 0; i < smi->num_vlan_mc; i++) {
126 		ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
127 		if (ret)
128 			return ret;
129 
130 		if (vlanmc.vid == 0 && vlanmc.member == 0) {
131 			/* Update the entry from the 4K table */
132 			ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
133 			if (ret)
134 				return ret;
135 
136 			vlanmc.vid = vid;
137 			vlanmc.member = vlan4k.member;
138 			vlanmc.untag = vlan4k.untag;
139 			vlanmc.fid = vlan4k.fid;
140 			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
141 			if (ret)
142 				return ret;
143 
144 			ret = smi->ops->set_mc_index(smi, port, i);
145 			return ret;
146 		}
147 	}
148 
149 	/* MC table is full, try to find an unused entry and replace it */
150 	for (i = 0; i < smi->num_vlan_mc; i++) {
151 		int used;
152 
153 		ret = rtl8366_mc_is_used(smi, i, &used);
154 		if (ret)
155 			return ret;
156 
157 		if (!used) {
158 			/* Update the entry from the 4K table */
159 			ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
160 			if (ret)
161 				return ret;
162 
163 			vlanmc.vid = vid;
164 			vlanmc.member = vlan4k.member;
165 			vlanmc.untag = vlan4k.untag;
166 			vlanmc.fid = vlan4k.fid;
167 			ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
168 			if (ret)
169 				return ret;
170 
171 			ret = smi->ops->set_mc_index(smi, port, i);
172 			return ret;
173 		}
174 	}
175 
176 	dev_err(smi->dev,
177 		"all VLAN member configurations are in use\n");
178 
179 	return -ENOSPC;
180 }
181 EXPORT_SYMBOL_GPL(rtl8366_set_pvid);
182 
rtl8366_enable_vlan4k(struct realtek_smi * smi,bool enable)183 int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable)
184 {
185 	int ret;
186 
187 	/* To enable 4k VLAN, ordinary VLAN must be enabled first,
188 	 * but if we disable 4k VLAN it is fine to leave ordinary
189 	 * VLAN enabled.
190 	 */
191 	if (enable) {
192 		/* Make sure VLAN is ON */
193 		ret = smi->ops->enable_vlan(smi, true);
194 		if (ret)
195 			return ret;
196 
197 		smi->vlan_enabled = true;
198 	}
199 
200 	ret = smi->ops->enable_vlan4k(smi, enable);
201 	if (ret)
202 		return ret;
203 
204 	smi->vlan4k_enabled = enable;
205 	return 0;
206 }
207 EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k);
208 
rtl8366_enable_vlan(struct realtek_smi * smi,bool enable)209 int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable)
210 {
211 	int ret;
212 
213 	ret = smi->ops->enable_vlan(smi, enable);
214 	if (ret)
215 		return ret;
216 
217 	smi->vlan_enabled = enable;
218 
219 	/* If we turn VLAN off, make sure that we turn off
220 	 * 4k VLAN as well, if that happened to be on.
221 	 */
222 	if (!enable) {
223 		smi->vlan4k_enabled = false;
224 		ret = smi->ops->enable_vlan4k(smi, false);
225 	}
226 
227 	return ret;
228 }
229 EXPORT_SYMBOL_GPL(rtl8366_enable_vlan);
230 
rtl8366_reset_vlan(struct realtek_smi * smi)231 int rtl8366_reset_vlan(struct realtek_smi *smi)
232 {
233 	struct rtl8366_vlan_mc vlanmc;
234 	int ret;
235 	int i;
236 
237 	rtl8366_enable_vlan(smi, false);
238 	rtl8366_enable_vlan4k(smi, false);
239 
240 	/* Clear the 16 VLAN member configurations */
241 	vlanmc.vid = 0;
242 	vlanmc.priority = 0;
243 	vlanmc.member = 0;
244 	vlanmc.untag = 0;
245 	vlanmc.fid = 0;
246 	for (i = 0; i < smi->num_vlan_mc; i++) {
247 		ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
248 		if (ret)
249 			return ret;
250 	}
251 
252 	return 0;
253 }
254 EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
255 
rtl8366_init_vlan(struct realtek_smi * smi)256 int rtl8366_init_vlan(struct realtek_smi *smi)
257 {
258 	int port;
259 	int ret;
260 
261 	ret = rtl8366_reset_vlan(smi);
262 	if (ret)
263 		return ret;
264 
265 	/* Loop over the available ports, for each port, associate
266 	 * it with the VLAN (port+1)
267 	 */
268 	for (port = 0; port < smi->num_ports; port++) {
269 		u32 mask;
270 
271 		if (port == smi->cpu_port)
272 			/* For the CPU port, make all ports members of this
273 			 * VLAN.
274 			 */
275 			mask = GENMASK(smi->num_ports - 1, 0);
276 		else
277 			/* For all other ports, enable itself plus the
278 			 * CPU port.
279 			 */
280 			mask = BIT(port) | BIT(smi->cpu_port);
281 
282 		/* For each port, set the port as member of VLAN (port+1)
283 		 * and untagged, except for the CPU port: the CPU port (5) is
284 		 * member of VLAN 6 and so are ALL the other ports as well.
285 		 * Use filter 0 (no filter).
286 		 */
287 		dev_info(smi->dev, "VLAN%d port mask for port %d, %08x\n",
288 			 (port + 1), port, mask);
289 		ret = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0);
290 		if (ret)
291 			return ret;
292 
293 		dev_info(smi->dev, "VLAN%d port %d, PVID set to %d\n",
294 			 (port + 1), port, (port + 1));
295 		ret = rtl8366_set_pvid(smi, port, (port + 1));
296 		if (ret)
297 			return ret;
298 	}
299 
300 	return rtl8366_enable_vlan(smi, true);
301 }
302 EXPORT_SYMBOL_GPL(rtl8366_init_vlan);
303 
rtl8366_vlan_filtering(struct dsa_switch * ds,int port,bool vlan_filtering)304 int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
305 {
306 	struct realtek_smi *smi = ds->priv;
307 	struct rtl8366_vlan_4k vlan4k;
308 	int ret;
309 
310 	/* Use VLAN nr port + 1 since VLAN0 is not valid */
311 	if (!smi->ops->is_vlan_valid(smi, port + 1))
312 		return -EINVAL;
313 
314 	dev_info(smi->dev, "%s filtering on port %d\n",
315 		 vlan_filtering ? "enable" : "disable",
316 		 port);
317 
318 	/* TODO:
319 	 * The hardware support filter ID (FID) 0..7, I have no clue how to
320 	 * support this in the driver when the callback only says on/off.
321 	 */
322 	ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
323 	if (ret)
324 		return ret;
325 
326 	/* Just set the filter to FID 1 for now then */
327 	ret = rtl8366_set_vlan(smi, port + 1,
328 			       vlan4k.member,
329 			       vlan4k.untag,
330 			       1);
331 	if (ret)
332 		return ret;
333 
334 	return 0;
335 }
336 EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering);
337 
rtl8366_vlan_prepare(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan)338 int rtl8366_vlan_prepare(struct dsa_switch *ds, int port,
339 			 const struct switchdev_obj_port_vlan *vlan)
340 {
341 	struct realtek_smi *smi = ds->priv;
342 	u16 vid;
343 	int ret;
344 
345 	for (vid = vlan->vid_begin; vid < vlan->vid_end; vid++)
346 		if (!smi->ops->is_vlan_valid(smi, vid))
347 			return -EINVAL;
348 
349 	dev_info(smi->dev, "prepare VLANs %04x..%04x\n",
350 		 vlan->vid_begin, vlan->vid_end);
351 
352 	/* Enable VLAN in the hardware
353 	 * FIXME: what's with this 4k business?
354 	 * Just rtl8366_enable_vlan() seems inconclusive.
355 	 */
356 	ret = rtl8366_enable_vlan4k(smi, true);
357 	if (ret)
358 		return ret;
359 
360 	return 0;
361 }
362 EXPORT_SYMBOL_GPL(rtl8366_vlan_prepare);
363 
rtl8366_vlan_add(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan)364 void rtl8366_vlan_add(struct dsa_switch *ds, int port,
365 		      const struct switchdev_obj_port_vlan *vlan)
366 {
367 	bool untagged = !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
368 	bool pvid = !!(vlan->flags & BRIDGE_VLAN_INFO_PVID);
369 	struct realtek_smi *smi = ds->priv;
370 	u32 member = 0;
371 	u32 untag = 0;
372 	u16 vid;
373 	int ret;
374 
375 	for (vid = vlan->vid_begin; vid < vlan->vid_end; vid++)
376 		if (!smi->ops->is_vlan_valid(smi, vid))
377 			return;
378 
379 	dev_info(smi->dev, "add VLAN on port %d, %s, %s\n",
380 		 port,
381 		 untagged ? "untagged" : "tagged",
382 		 pvid ? " PVID" : "no PVID");
383 
384 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
385 		dev_err(smi->dev, "port is DSA or CPU port\n");
386 
387 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
388 		int pvid_val = 0;
389 
390 		dev_info(smi->dev, "add VLAN %04x\n", vid);
391 		member |= BIT(port);
392 
393 		if (untagged)
394 			untag |= BIT(port);
395 
396 		/* To ensure that we have a valid MC entry for this VLAN,
397 		 * initialize the port VLAN ID here.
398 		 */
399 		ret = rtl8366_get_pvid(smi, port, &pvid_val);
400 		if (ret < 0) {
401 			dev_err(smi->dev, "could not lookup PVID for port %d\n",
402 				port);
403 			return;
404 		}
405 		if (pvid_val == 0) {
406 			ret = rtl8366_set_pvid(smi, port, vid);
407 			if (ret < 0)
408 				return;
409 		}
410 	}
411 
412 	ret = rtl8366_set_vlan(smi, port, member, untag, 0);
413 	if (ret)
414 		dev_err(smi->dev,
415 			"failed to set up VLAN %04x",
416 			vid);
417 }
418 EXPORT_SYMBOL_GPL(rtl8366_vlan_add);
419 
rtl8366_vlan_del(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan)420 int rtl8366_vlan_del(struct dsa_switch *ds, int port,
421 		     const struct switchdev_obj_port_vlan *vlan)
422 {
423 	struct realtek_smi *smi = ds->priv;
424 	u16 vid;
425 	int ret;
426 
427 	dev_info(smi->dev, "del VLAN on port %d\n", port);
428 
429 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
430 		int i;
431 
432 		dev_info(smi->dev, "del VLAN %04x\n", vid);
433 
434 		for (i = 0; i < smi->num_vlan_mc; i++) {
435 			struct rtl8366_vlan_mc vlanmc;
436 
437 			ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
438 			if (ret)
439 				return ret;
440 
441 			if (vid == vlanmc.vid) {
442 				/* clear VLAN member configurations */
443 				vlanmc.vid = 0;
444 				vlanmc.priority = 0;
445 				vlanmc.member = 0;
446 				vlanmc.untag = 0;
447 				vlanmc.fid = 0;
448 
449 				ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
450 				if (ret) {
451 					dev_err(smi->dev,
452 						"failed to remove VLAN %04x\n",
453 						vid);
454 					return ret;
455 				}
456 				break;
457 			}
458 		}
459 	}
460 
461 	return 0;
462 }
463 EXPORT_SYMBOL_GPL(rtl8366_vlan_del);
464 
rtl8366_get_strings(struct dsa_switch * ds,int port,u32 stringset,uint8_t * data)465 void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
466 			 uint8_t *data)
467 {
468 	struct realtek_smi *smi = ds->priv;
469 	struct rtl8366_mib_counter *mib;
470 	int i;
471 
472 	if (port >= smi->num_ports)
473 		return;
474 
475 	for (i = 0; i < smi->num_mib_counters; i++) {
476 		mib = &smi->mib_counters[i];
477 		strncpy(data + i * ETH_GSTRING_LEN,
478 			mib->name, ETH_GSTRING_LEN);
479 	}
480 }
481 EXPORT_SYMBOL_GPL(rtl8366_get_strings);
482 
rtl8366_get_sset_count(struct dsa_switch * ds,int port,int sset)483 int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset)
484 {
485 	struct realtek_smi *smi = ds->priv;
486 
487 	/* We only support SS_STATS */
488 	if (sset != ETH_SS_STATS)
489 		return 0;
490 	if (port >= smi->num_ports)
491 		return -EINVAL;
492 
493 	return smi->num_mib_counters;
494 }
495 EXPORT_SYMBOL_GPL(rtl8366_get_sset_count);
496 
rtl8366_get_ethtool_stats(struct dsa_switch * ds,int port,uint64_t * data)497 void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
498 {
499 	struct realtek_smi *smi = ds->priv;
500 	int i;
501 	int ret;
502 
503 	if (port >= smi->num_ports)
504 		return;
505 
506 	for (i = 0; i < smi->num_mib_counters; i++) {
507 		struct rtl8366_mib_counter *mib;
508 		u64 mibvalue = 0;
509 
510 		mib = &smi->mib_counters[i];
511 		ret = smi->ops->get_mib_counter(smi, port, mib, &mibvalue);
512 		if (ret) {
513 			dev_err(smi->dev, "error reading MIB counter %s\n",
514 				mib->name);
515 		}
516 		data[i] = mibvalue;
517 	}
518 }
519 EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats);
520