]> Git Repo - linux.git/blob - drivers/net/dsa/rtl8366.c
ASoC: simple-card: Use snd_soc_of_parse_aux_devs()
[linux.git] / drivers / net / dsa / rtl8366.c
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 <[email protected]>
6  * Copyright (C) 2009-2010 Gabor Juhos <[email protected]>
7  * Copyright (C) 2010 Antti Seppälä <[email protected]>
8  * Copyright (C) 2010 Roman Yeryomin <[email protected]>
9  * Copyright (C) 2011 Colin Leitner <[email protected]>
10  */
11 #include <linux/if_bridge.h>
12 #include <net/dsa.h>
13
14 #include "realtek-smi-core.h"
15
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
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         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 }
92 EXPORT_SYMBOL_GPL(rtl8366_set_vlan);
93
94 int 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 }
111 EXPORT_SYMBOL_GPL(rtl8366_get_pvid);
112
113 int 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 }
194 EXPORT_SYMBOL_GPL(rtl8366_set_pvid);
195
196 int 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 }
220 EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k);
221
222 int 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 }
242 EXPORT_SYMBOL_GPL(rtl8366_enable_vlan);
243
244 int 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 }
267 EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
268
269 int 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 }
315 EXPORT_SYMBOL_GPL(rtl8366_init_vlan);
316
317 int 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 }
349 EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering);
350
351 int 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 }
375 EXPORT_SYMBOL_GPL(rtl8366_vlan_prepare);
376
377 void 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 }
431 EXPORT_SYMBOL_GPL(rtl8366_vlan_add);
432
433 int 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                                 /* clear VLAN member configurations */
456                                 vlanmc.vid = 0;
457                                 vlanmc.priority = 0;
458                                 vlanmc.member = 0;
459                                 vlanmc.untag = 0;
460                                 vlanmc.fid = 0;
461
462                                 ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
463                                 if (ret) {
464                                         dev_err(smi->dev,
465                                                 "failed to remove VLAN %04x\n",
466                                                 vid);
467                                         return ret;
468                                 }
469                                 break;
470                         }
471                 }
472         }
473
474         return 0;
475 }
476 EXPORT_SYMBOL_GPL(rtl8366_vlan_del);
477
478 void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
479                          uint8_t *data)
480 {
481         struct realtek_smi *smi = ds->priv;
482         struct rtl8366_mib_counter *mib;
483         int i;
484
485         if (port >= smi->num_ports)
486                 return;
487
488         for (i = 0; i < smi->num_mib_counters; i++) {
489                 mib = &smi->mib_counters[i];
490                 strncpy(data + i * ETH_GSTRING_LEN,
491                         mib->name, ETH_GSTRING_LEN);
492         }
493 }
494 EXPORT_SYMBOL_GPL(rtl8366_get_strings);
495
496 int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset)
497 {
498         struct realtek_smi *smi = ds->priv;
499
500         /* We only support SS_STATS */
501         if (sset != ETH_SS_STATS)
502                 return 0;
503         if (port >= smi->num_ports)
504                 return -EINVAL;
505
506         return smi->num_mib_counters;
507 }
508 EXPORT_SYMBOL_GPL(rtl8366_get_sset_count);
509
510 void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
511 {
512         struct realtek_smi *smi = ds->priv;
513         int i;
514         int ret;
515
516         if (port >= smi->num_ports)
517                 return;
518
519         for (i = 0; i < smi->num_mib_counters; i++) {
520                 struct rtl8366_mib_counter *mib;
521                 u64 mibvalue = 0;
522
523                 mib = &smi->mib_counters[i];
524                 ret = smi->ops->get_mib_counter(smi, port, mib, &mibvalue);
525                 if (ret) {
526                         dev_err(smi->dev, "error reading MIB counter %s\n",
527                                 mib->name);
528                 }
529                 data[i] = mibvalue;
530         }
531 }
532 EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats);
This page took 0.065058 seconds and 4 git commands to generate.