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