1 // SPDX-License-Identifier: GPL-2.0
2 /* Realtek SMI library helpers for the RTL8366x variants
3 * RTL8366RB and RTL8366S
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>
11 #include <linux/if_bridge.h>
14 #include "realtek-smi.h"
16 int rtl8366_mc_is_used(struct realtek_smi
*smi
, int mc_index
, int *used
)
22 for (i
= 0; i
< smi
->num_ports
; i
++) {
25 ret
= smi
->ops
->get_mc_index(smi
, i
, &index
);
29 if (mc_index
== index
) {
37 EXPORT_SYMBOL_GPL(rtl8366_mc_is_used
);
39 int rtl8366_set_vlan(struct realtek_smi
*smi
, int vid
, u32 member
,
42 struct rtl8366_vlan_4k vlan4k
;
46 /* Update the 4K table */
47 ret
= smi
->ops
->get_vlan_4k(smi
, vid
, &vlan4k
);
51 vlan4k
.member
= member
;
54 ret
= smi
->ops
->set_vlan_4k(smi
, &vlan4k
);
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
;
62 ret
= smi
->ops
->get_vlan_mc(smi
, i
, &vlanmc
);
66 if (vid
== vlanmc
.vid
) {
67 /* update the MC entry */
68 vlanmc
.member
= member
;
72 ret
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
79 EXPORT_SYMBOL_GPL(rtl8366_set_vlan
);
81 int rtl8366_get_pvid(struct realtek_smi
*smi
, int port
, int *val
)
83 struct rtl8366_vlan_mc vlanmc
;
87 ret
= smi
->ops
->get_mc_index(smi
, port
, &index
);
91 ret
= smi
->ops
->get_vlan_mc(smi
, index
, &vlanmc
);
98 EXPORT_SYMBOL_GPL(rtl8366_get_pvid
);
100 int rtl8366_set_pvid(struct realtek_smi
*smi
, unsigned int port
,
103 struct rtl8366_vlan_mc vlanmc
;
104 struct rtl8366_vlan_4k vlan4k
;
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
);
114 if (vid
== vlanmc
.vid
) {
115 ret
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
119 ret
= smi
->ops
->set_mc_index(smi
, port
, i
);
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
);
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
);
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
);
144 ret
= smi
->ops
->set_mc_index(smi
, port
, i
);
149 /* MC table is full, try to find an unused entry and replace it */
150 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
153 ret
= rtl8366_mc_is_used(smi
, i
, &used
);
158 /* Update the entry from the 4K table */
159 ret
= smi
->ops
->get_vlan_4k(smi
, vid
, &vlan4k
);
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
);
171 ret
= smi
->ops
->set_mc_index(smi
, port
, i
);
177 "all VLAN member configurations are in use\n");
181 EXPORT_SYMBOL_GPL(rtl8366_set_pvid
);
183 int rtl8366_enable_vlan4k(struct realtek_smi
*smi
, bool enable
)
187 /* To enable 4k VLAN, ordinary VLAN must be enabled first,
188 * but if we disable 4k VLAN it is fine to leave ordinary
192 /* Make sure VLAN is ON */
193 ret
= smi
->ops
->enable_vlan(smi
, true);
197 smi
->vlan_enabled
= true;
200 ret
= smi
->ops
->enable_vlan4k(smi
, enable
);
204 smi
->vlan4k_enabled
= enable
;
207 EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k
);
209 int rtl8366_enable_vlan(struct realtek_smi
*smi
, bool enable
)
213 ret
= smi
->ops
->enable_vlan(smi
, enable
);
217 smi
->vlan_enabled
= enable
;
219 /* If we turn VLAN off, make sure that we turn off
220 * 4k VLAN as well, if that happened to be on.
223 smi
->vlan4k_enabled
= false;
224 ret
= smi
->ops
->enable_vlan4k(smi
, false);
229 EXPORT_SYMBOL_GPL(rtl8366_enable_vlan
);
231 int rtl8366_reset_vlan(struct realtek_smi
*smi
)
233 struct rtl8366_vlan_mc vlanmc
;
237 rtl8366_enable_vlan(smi
, false);
238 rtl8366_enable_vlan4k(smi
, false);
240 /* Clear the 16 VLAN member configurations */
246 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
247 ret
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
254 EXPORT_SYMBOL_GPL(rtl8366_reset_vlan
);
256 int rtl8366_init_vlan(struct realtek_smi
*smi
)
261 ret
= rtl8366_reset_vlan(smi
);
265 /* Loop over the available ports, for each port, associate
266 * it with the VLAN (port+1)
268 for (port
= 0; port
< smi
->num_ports
; port
++) {
271 if (port
== smi
->cpu_port
)
272 /* For the CPU port, make all ports members of this
275 mask
= GENMASK(smi
->num_ports
- 1, 0);
277 /* For all other ports, enable itself plus the
280 mask
= BIT(port
) | BIT(smi
->cpu_port
);
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).
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);
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));
300 return rtl8366_enable_vlan(smi
, true);
302 EXPORT_SYMBOL_GPL(rtl8366_init_vlan
);
304 int rtl8366_vlan_filtering(struct dsa_switch
*ds
, int port
, bool vlan_filtering
)
306 struct realtek_smi
*smi
= ds
->priv
;
307 struct rtl8366_vlan_4k vlan4k
;
310 if (!smi
->ops
->is_vlan_valid(smi
, port
))
313 dev_info(smi
->dev
, "%s filtering on port %d\n",
314 vlan_filtering
? "enable" : "disable",
318 * The hardware support filter ID (FID) 0..7, I have no clue how to
319 * support this in the driver when the callback only says on/off.
321 ret
= smi
->ops
->get_vlan_4k(smi
, port
, &vlan4k
);
325 /* Just set the filter to FID 1 for now then */
326 ret
= rtl8366_set_vlan(smi
, port
,
335 EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering
);
337 int rtl8366_vlan_prepare(struct dsa_switch
*ds
, int port
,
338 const struct switchdev_obj_port_vlan
*vlan
)
340 struct realtek_smi
*smi
= ds
->priv
;
343 if (!smi
->ops
->is_vlan_valid(smi
, port
))
346 dev_info(smi
->dev
, "prepare VLANs %04x..%04x\n",
347 vlan
->vid_begin
, vlan
->vid_end
);
349 /* Enable VLAN in the hardware
350 * FIXME: what's with this 4k business?
351 * Just rtl8366_enable_vlan() seems inconclusive.
353 ret
= rtl8366_enable_vlan4k(smi
, true);
359 EXPORT_SYMBOL_GPL(rtl8366_vlan_prepare
);
361 void rtl8366_vlan_add(struct dsa_switch
*ds
, int port
,
362 const struct switchdev_obj_port_vlan
*vlan
)
364 bool untagged
= !!(vlan
->flags
& BRIDGE_VLAN_INFO_UNTAGGED
);
365 bool pvid
= !!(vlan
->flags
& BRIDGE_VLAN_INFO_PVID
);
366 struct realtek_smi
*smi
= ds
->priv
;
372 if (!smi
->ops
->is_vlan_valid(smi
, port
))
375 dev_info(smi
->dev
, "add VLAN on port %d, %s, %s\n",
377 untagged
? "untagged" : "tagged",
378 pvid
? " PVID" : "no PVID");
380 if (dsa_is_dsa_port(ds
, port
) || dsa_is_cpu_port(ds
, port
))
381 dev_err(smi
->dev
, "port is DSA or CPU port\n");
383 for (vid
= vlan
->vid_begin
; vid
<= vlan
->vid_end
; ++vid
) {
386 dev_info(smi
->dev
, "add VLAN %04x\n", vid
);
392 /* To ensure that we have a valid MC entry for this VLAN,
393 * initialize the port VLAN ID here.
395 ret
= rtl8366_get_pvid(smi
, port
, &pvid_val
);
397 dev_err(smi
->dev
, "could not lookup PVID for port %d\n",
402 ret
= rtl8366_set_pvid(smi
, port
, vid
);
408 ret
= rtl8366_set_vlan(smi
, port
, member
, untag
, 0);
411 "failed to set up VLAN %04x",
414 EXPORT_SYMBOL_GPL(rtl8366_vlan_add
);
416 int rtl8366_vlan_del(struct dsa_switch
*ds
, int port
,
417 const struct switchdev_obj_port_vlan
*vlan
)
419 struct realtek_smi
*smi
= ds
->priv
;
423 dev_info(smi
->dev
, "del VLAN on port %d\n", port
);
425 for (vid
= vlan
->vid_begin
; vid
<= vlan
->vid_end
; ++vid
) {
428 dev_info(smi
->dev
, "del VLAN %04x\n", vid
);
430 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
431 struct rtl8366_vlan_mc vlanmc
;
433 ret
= smi
->ops
->get_vlan_mc(smi
, i
, &vlanmc
);
437 if (vid
== vlanmc
.vid
) {
438 /* clear VLAN member configurations */
445 ret
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
448 "failed to remove VLAN %04x\n",
459 EXPORT_SYMBOL_GPL(rtl8366_vlan_del
);
461 void rtl8366_get_strings(struct dsa_switch
*ds
, int port
, u32 stringset
,
464 struct realtek_smi
*smi
= ds
->priv
;
465 struct rtl8366_mib_counter
*mib
;
468 if (port
>= smi
->num_ports
)
471 for (i
= 0; i
< smi
->num_mib_counters
; i
++) {
472 mib
= &smi
->mib_counters
[i
];
473 strncpy(data
+ i
* ETH_GSTRING_LEN
,
474 mib
->name
, ETH_GSTRING_LEN
);
477 EXPORT_SYMBOL_GPL(rtl8366_get_strings
);
479 int rtl8366_get_sset_count(struct dsa_switch
*ds
, int port
, int sset
)
481 struct realtek_smi
*smi
= ds
->priv
;
483 /* We only support SS_STATS */
484 if (sset
!= ETH_SS_STATS
)
486 if (port
>= smi
->num_ports
)
489 return smi
->num_mib_counters
;
491 EXPORT_SYMBOL_GPL(rtl8366_get_sset_count
);
493 void rtl8366_get_ethtool_stats(struct dsa_switch
*ds
, int port
, uint64_t *data
)
495 struct realtek_smi
*smi
= ds
->priv
;
499 if (port
>= smi
->num_ports
)
502 for (i
= 0; i
< smi
->num_mib_counters
; i
++) {
503 struct rtl8366_mib_counter
*mib
;
506 mib
= &smi
->mib_counters
[i
];
507 ret
= smi
->ops
->get_mib_counter(smi
, port
, mib
, &mibvalue
);
509 dev_err(smi
->dev
, "error reading MIB counter %s\n",
515 EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats
);