GNU Linux-libre 4.14.313-gnu1
[releases.git] / drivers / net / dsa / mv88e6xxx / global1_vtu.c
1 /*
2  * Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support
3  *
4  * Copyright (c) 2008 Marvell Semiconductor
5  * Copyright (c) 2015 CMC Electronics, Inc.
6  * Copyright (c) 2017 Savoir-faire Linux, Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13
14 #include "chip.h"
15 #include "global1.h"
16
17 /* Offset 0x02: VTU FID Register */
18
19 static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip,
20                                      struct mv88e6xxx_vtu_entry *entry)
21 {
22         u16 val;
23         int err;
24
25         err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID, &val);
26         if (err)
27                 return err;
28
29         entry->fid = val & MV88E6352_G1_VTU_FID_MASK;
30
31         return 0;
32 }
33
34 static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip *chip,
35                                       struct mv88e6xxx_vtu_entry *entry)
36 {
37         u16 val = entry->fid & MV88E6352_G1_VTU_FID_MASK;
38
39         return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_FID, val);
40 }
41
42 /* Offset 0x03: VTU SID Register */
43
44 static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip,
45                                      struct mv88e6xxx_vtu_entry *entry)
46 {
47         u16 val;
48         int err;
49
50         err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, &val);
51         if (err)
52                 return err;
53
54         entry->sid = val & MV88E6352_G1_VTU_SID_MASK;
55
56         return 0;
57 }
58
59 static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip,
60                                       struct mv88e6xxx_vtu_entry *entry)
61 {
62         u16 val = entry->sid & MV88E6352_G1_VTU_SID_MASK;
63
64         return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val);
65 }
66
67 /* Offset 0x05: VTU Operation Register */
68
69 static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip *chip)
70 {
71         return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_VTU_OP,
72                                  MV88E6XXX_G1_VTU_OP_BUSY);
73 }
74
75 static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op)
76 {
77         int err;
78
79         err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_OP,
80                                  MV88E6XXX_G1_VTU_OP_BUSY | op);
81         if (err)
82                 return err;
83
84         return mv88e6xxx_g1_vtu_op_wait(chip);
85 }
86
87 /* Offset 0x06: VTU VID Register */
88
89 static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip,
90                                      struct mv88e6xxx_vtu_entry *entry)
91 {
92         u16 val;
93         int err;
94
95         err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, &val);
96         if (err)
97                 return err;
98
99         entry->vid = val & 0xfff;
100
101         if (val & MV88E6390_G1_VTU_VID_PAGE)
102                 entry->vid |= 0x1000;
103
104         entry->valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID);
105
106         return 0;
107 }
108
109 static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip,
110                                       struct mv88e6xxx_vtu_entry *entry)
111 {
112         u16 val = entry->vid & 0xfff;
113
114         if (entry->vid & 0x1000)
115                 val |= MV88E6390_G1_VTU_VID_PAGE;
116
117         if (entry->valid)
118                 val |= MV88E6XXX_G1_VTU_VID_VALID;
119
120         return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val);
121 }
122
123 /* Offset 0x07: VTU/STU Data Register 1
124  * Offset 0x08: VTU/STU Data Register 2
125  * Offset 0x09: VTU/STU Data Register 3
126  */
127 static int mv88e6185_g1_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
128                                           u16 *regs)
129 {
130         int i;
131
132         /* Read all 3 VTU/STU Data registers */
133         for (i = 0; i < 3; ++i) {
134                 u16 *reg = &regs[i];
135                 int err;
136
137                 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
138                 if (err)
139                         return err;
140         }
141
142         return 0;
143 }
144
145 static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip,
146                                       struct mv88e6xxx_vtu_entry *entry)
147 {
148         u16 regs[3];
149         int err;
150         int i;
151
152         err = mv88e6185_g1_vtu_stu_data_read(chip, regs);
153         if (err)
154                 return err;
155
156         /* Extract MemberTag data */
157         for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
158                 unsigned int member_offset = (i % 4) * 4;
159
160                 entry->member[i] = (regs[i / 4] >> member_offset) & 0x3;
161         }
162
163         return 0;
164 }
165
166 static int mv88e6185_g1_stu_data_read(struct mv88e6xxx_chip *chip,
167                                       struct mv88e6xxx_vtu_entry *entry)
168 {
169         u16 regs[3];
170         int err;
171         int i;
172
173         err = mv88e6185_g1_vtu_stu_data_read(chip, regs);
174         if (err)
175                 return err;
176
177         /* Extract PortState data */
178         for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
179                 unsigned int state_offset = (i % 4) * 4 + 2;
180
181                 entry->state[i] = (regs[i / 4] >> state_offset) & 0x3;
182         }
183
184         return 0;
185 }
186
187 static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip,
188                                        struct mv88e6xxx_vtu_entry *entry)
189 {
190         u16 regs[3] = { 0 };
191         int i;
192
193         /* Insert MemberTag and PortState data */
194         for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
195                 unsigned int member_offset = (i % 4) * 4;
196                 unsigned int state_offset = member_offset + 2;
197
198                 regs[i / 4] |= (entry->member[i] & 0x3) << member_offset;
199                 regs[i / 4] |= (entry->state[i] & 0x3) << state_offset;
200         }
201
202         /* Write all 3 VTU/STU Data registers */
203         for (i = 0; i < 3; ++i) {
204                 u16 reg = regs[i];
205                 int err;
206
207                 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
208                 if (err)
209                         return err;
210         }
211
212         return 0;
213 }
214
215 static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data)
216 {
217         u16 regs[2];
218         int i;
219
220         /* Read the 2 VTU/STU Data registers */
221         for (i = 0; i < 2; ++i) {
222                 u16 *reg = &regs[i];
223                 int err;
224
225                 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
226                 if (err)
227                         return err;
228         }
229
230         /* Extract data */
231         for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
232                 unsigned int offset = (i % 8) * 2;
233
234                 data[i] = (regs[i / 8] >> offset) & 0x3;
235         }
236
237         return 0;
238 }
239
240 static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data)
241 {
242         u16 regs[2] = { 0 };
243         int i;
244
245         /* Insert data */
246         for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
247                 unsigned int offset = (i % 8) * 2;
248
249                 regs[i / 8] |= (data[i] & 0x3) << offset;
250         }
251
252         /* Write the 2 VTU/STU Data registers */
253         for (i = 0; i < 2; ++i) {
254                 u16 reg = regs[i];
255                 int err;
256
257                 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
258                 if (err)
259                         return err;
260         }
261
262         return 0;
263 }
264
265 /* VLAN Translation Unit Operations */
266
267 static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip,
268                                         struct mv88e6xxx_vtu_entry *entry)
269 {
270         int err;
271
272         err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
273         if (err)
274                 return err;
275
276         err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT);
277         if (err)
278                 return err;
279
280         err = mv88e6xxx_g1_vtu_sid_read(chip, entry);
281         if (err)
282                 return err;
283
284         return mv88e6xxx_g1_vtu_vid_read(chip, entry);
285 }
286
287 static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip,
288                                     struct mv88e6xxx_vtu_entry *vtu)
289 {
290         struct mv88e6xxx_vtu_entry stu;
291         int err;
292
293         err = mv88e6xxx_g1_vtu_sid_read(chip, vtu);
294         if (err)
295                 return err;
296
297         stu.sid = vtu->sid - 1;
298
299         err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu);
300         if (err)
301                 return err;
302
303         if (stu.sid != vtu->sid || !stu.valid)
304                 return -EINVAL;
305
306         return 0;
307 }
308
309 static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
310                                     struct mv88e6xxx_vtu_entry *entry)
311 {
312         int err;
313
314         err = mv88e6xxx_g1_vtu_op_wait(chip);
315         if (err)
316                 return err;
317
318         /* To get the next higher active VID, the VTU GetNext operation can be
319          * started again without setting the VID registers since it already
320          * contains the last VID.
321          *
322          * To save a few hardware accesses and abstract this to the caller,
323          * write the VID only once, when the entry is given as invalid.
324          */
325         if (!entry->valid) {
326                 err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
327                 if (err)
328                         return err;
329         }
330
331         err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT);
332         if (err)
333                 return err;
334
335         return mv88e6xxx_g1_vtu_vid_read(chip, entry);
336 }
337
338 int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
339                              struct mv88e6xxx_vtu_entry *entry)
340 {
341         u16 val;
342         int err;
343
344         err = mv88e6xxx_g1_vtu_getnext(chip, entry);
345         if (err)
346                 return err;
347
348         if (entry->valid) {
349                 err = mv88e6185_g1_vtu_data_read(chip, entry);
350                 if (err)
351                         return err;
352
353                 err = mv88e6185_g1_stu_data_read(chip, entry);
354                 if (err)
355                         return err;
356
357                 /* VTU DBNum[3:0] are located in VTU Operation 3:0
358                  * VTU DBNum[7:4] are located in VTU Operation 11:8
359                  */
360                 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val);
361                 if (err)
362                         return err;
363
364                 entry->fid = val & 0x000f;
365                 entry->fid |= (val & 0x0f00) >> 4;
366         }
367
368         return 0;
369 }
370
371 int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
372                              struct mv88e6xxx_vtu_entry *entry)
373 {
374         int err;
375
376         /* Fetch VLAN MemberTag data from the VTU */
377         err = mv88e6xxx_g1_vtu_getnext(chip, entry);
378         if (err)
379                 return err;
380
381         if (entry->valid) {
382                 err = mv88e6185_g1_vtu_data_read(chip, entry);
383                 if (err)
384                         return err;
385
386                 err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
387                 if (err)
388                         return err;
389
390                 /* Fetch VLAN PortState data from the STU */
391                 err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
392                 if (err)
393                         return err;
394
395                 err = mv88e6185_g1_stu_data_read(chip, entry);
396                 if (err)
397                         return err;
398         }
399
400         return 0;
401 }
402
403 int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
404                              struct mv88e6xxx_vtu_entry *entry)
405 {
406         int err;
407
408         /* Fetch VLAN MemberTag data from the VTU */
409         err = mv88e6xxx_g1_vtu_getnext(chip, entry);
410         if (err)
411                 return err;
412
413         if (entry->valid) {
414                 err = mv88e6390_g1_vtu_data_read(chip, entry->member);
415                 if (err)
416                         return err;
417
418                 /* Fetch VLAN PortState data from the STU */
419                 err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
420                 if (err)
421                         return err;
422
423                 err = mv88e6390_g1_vtu_data_read(chip, entry->state);
424                 if (err)
425                         return err;
426
427                 err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
428                 if (err)
429                         return err;
430         }
431
432         return 0;
433 }
434
435 int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
436                                struct mv88e6xxx_vtu_entry *entry)
437 {
438         u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE;
439         int err;
440
441         err = mv88e6xxx_g1_vtu_op_wait(chip);
442         if (err)
443                 return err;
444
445         err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
446         if (err)
447                 return err;
448
449         if (entry->valid) {
450                 err = mv88e6185_g1_vtu_data_write(chip, entry);
451                 if (err)
452                         return err;
453
454                 /* VTU DBNum[3:0] are located in VTU Operation 3:0
455                  * VTU DBNum[7:4] are located in VTU Operation 11:8
456                  */
457                 op |= entry->fid & 0x000f;
458                 op |= (entry->fid & 0x00f0) << 4;
459         }
460
461         return mv88e6xxx_g1_vtu_op(chip, op);
462 }
463
464 int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
465                                struct mv88e6xxx_vtu_entry *entry)
466 {
467         int err;
468
469         err = mv88e6xxx_g1_vtu_op_wait(chip);
470         if (err)
471                 return err;
472
473         err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
474         if (err)
475                 return err;
476
477         if (entry->valid) {
478                 /* Write MemberTag and PortState data */
479                 err = mv88e6185_g1_vtu_data_write(chip, entry);
480                 if (err)
481                         return err;
482
483                 err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
484                 if (err)
485                         return err;
486
487                 /* Load STU entry */
488                 err = mv88e6xxx_g1_vtu_op(chip,
489                                           MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE);
490                 if (err)
491                         return err;
492
493                 err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
494                 if (err)
495                         return err;
496         }
497
498         /* Load/Purge VTU entry */
499         return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE);
500 }
501
502 int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
503                                struct mv88e6xxx_vtu_entry *entry)
504 {
505         int err;
506
507         err = mv88e6xxx_g1_vtu_op_wait(chip);
508         if (err)
509                 return err;
510
511         err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
512         if (err)
513                 return err;
514
515         if (entry->valid) {
516                 /* Write PortState data */
517                 err = mv88e6390_g1_vtu_data_write(chip, entry->state);
518                 if (err)
519                         return err;
520
521                 err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
522                 if (err)
523                         return err;
524
525                 /* Load STU entry */
526                 err = mv88e6xxx_g1_vtu_op(chip,
527                                           MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE);
528                 if (err)
529                         return err;
530
531                 /* Write MemberTag data */
532                 err = mv88e6390_g1_vtu_data_write(chip, entry->member);
533                 if (err)
534                         return err;
535
536                 err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
537                 if (err)
538                         return err;
539         }
540
541         /* Load/Purge VTU entry */
542         return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE);
543 }
544
545 int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip)
546 {
547         int err;
548
549         err = mv88e6xxx_g1_vtu_op_wait(chip);
550         if (err)
551                 return err;
552
553         return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL);
554 }