xref: /linux/drivers/net/dsa/mv88e6xxx/global1_vtu.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
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 "mv88e6xxx.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, GLOBAL_VTU_FID, &val);
26 	if (err)
27 		return err;
28 
29 	entry->fid = val & GLOBAL_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 & GLOBAL_VTU_FID_MASK;
38 
39 	return mv88e6xxx_g1_write(chip, GLOBAL_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, GLOBAL_VTU_SID, &val);
51 	if (err)
52 		return err;
53 
54 	entry->sid = val & GLOBAL_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 & GLOBAL_VTU_SID_MASK;
63 
64 	return mv88e6xxx_g1_write(chip, GLOBAL_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, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY);
72 }
73 
74 static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op)
75 {
76 	int err;
77 
78 	err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op);
79 	if (err)
80 		return err;
81 
82 	return mv88e6xxx_g1_vtu_op_wait(chip);
83 }
84 
85 /* Offset 0x06: VTU VID Register */
86 
87 static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip,
88 				     struct mv88e6xxx_vtu_entry *entry)
89 {
90 	u16 val;
91 	int err;
92 
93 	err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
94 	if (err)
95 		return err;
96 
97 	entry->vid = val & 0xfff;
98 
99 	if (val & GLOBAL_VTU_VID_PAGE)
100 		entry->vid |= 0x1000;
101 
102 	entry->valid = !!(val & GLOBAL_VTU_VID_VALID);
103 
104 	return 0;
105 }
106 
107 static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip,
108 				      struct mv88e6xxx_vtu_entry *entry)
109 {
110 	u16 val = entry->vid & 0xfff;
111 
112 	if (entry->vid & 0x1000)
113 		val |= GLOBAL_VTU_VID_PAGE;
114 
115 	if (entry->valid)
116 		val |= GLOBAL_VTU_VID_VALID;
117 
118 	return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, val);
119 }
120 
121 /* Offset 0x07: VTU/STU Data Register 1
122  * Offset 0x08: VTU/STU Data Register 2
123  * Offset 0x09: VTU/STU Data Register 3
124  */
125 
126 static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip,
127 				      struct mv88e6xxx_vtu_entry *entry)
128 {
129 	u16 regs[3];
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, GLOBAL_VTU_DATA_0_3 + i, reg);
138 		if (err)
139 			return err;
140 	}
141 
142 	/* Extract MemberTag and PortState data */
143 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
144 		unsigned int member_offset = (i % 4) * 4;
145 		unsigned int state_offset = member_offset + 2;
146 
147 		entry->member[i] = (regs[i / 4] >> member_offset) & 0x3;
148 		entry->state[i] = (regs[i / 4] >> state_offset) & 0x3;
149 	}
150 
151 	return 0;
152 }
153 
154 static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip,
155 				       struct mv88e6xxx_vtu_entry *entry)
156 {
157 	u16 regs[3] = { 0 };
158 	int i;
159 
160 	/* Insert MemberTag and PortState data */
161 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
162 		unsigned int member_offset = (i % 4) * 4;
163 		unsigned int state_offset = member_offset + 2;
164 
165 		regs[i / 4] |= (entry->member[i] & 0x3) << member_offset;
166 		regs[i / 4] |= (entry->state[i] & 0x3) << state_offset;
167 	}
168 
169 	/* Write all 3 VTU/STU Data registers */
170 	for (i = 0; i < 3; ++i) {
171 		u16 reg = regs[i];
172 		int err;
173 
174 		err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
175 		if (err)
176 			return err;
177 	}
178 
179 	return 0;
180 }
181 
182 static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data)
183 {
184 	u16 regs[2];
185 	int i;
186 
187 	/* Read the 2 VTU/STU Data registers */
188 	for (i = 0; i < 2; ++i) {
189 		u16 *reg = &regs[i];
190 		int err;
191 
192 		err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
193 		if (err)
194 			return err;
195 	}
196 
197 	/* Extract data */
198 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
199 		unsigned int offset = (i % 8) * 2;
200 
201 		data[i] = (regs[i / 8] >> offset) & 0x3;
202 	}
203 
204 	return 0;
205 }
206 
207 static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data)
208 {
209 	u16 regs[2] = { 0 };
210 	int i;
211 
212 	/* Insert data */
213 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
214 		unsigned int offset = (i % 8) * 2;
215 
216 		regs[i / 8] |= (data[i] & 0x3) << offset;
217 	}
218 
219 	/* Write the 2 VTU/STU Data registers */
220 	for (i = 0; i < 2; ++i) {
221 		u16 reg = regs[i];
222 		int err;
223 
224 		err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
225 		if (err)
226 			return err;
227 	}
228 
229 	return 0;
230 }
231 
232 /* VLAN Translation Unit Operations */
233 
234 static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip,
235 					struct mv88e6xxx_vtu_entry *entry)
236 {
237 	int err;
238 
239 	err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
240 	if (err)
241 		return err;
242 
243 	err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
244 	if (err)
245 		return err;
246 
247 	err = mv88e6xxx_g1_vtu_sid_read(chip, entry);
248 	if (err)
249 		return err;
250 
251 	return mv88e6xxx_g1_vtu_vid_read(chip, entry);
252 }
253 
254 static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip,
255 				    struct mv88e6xxx_vtu_entry *vtu)
256 {
257 	struct mv88e6xxx_vtu_entry stu;
258 	int err;
259 
260 	err = mv88e6xxx_g1_vtu_sid_read(chip, vtu);
261 	if (err)
262 		return err;
263 
264 	stu.sid = vtu->sid - 1;
265 
266 	err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu);
267 	if (err)
268 		return err;
269 
270 	if (stu.sid != vtu->sid || !stu.valid)
271 		return -EINVAL;
272 
273 	return 0;
274 }
275 
276 static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
277 				    struct mv88e6xxx_vtu_entry *entry)
278 {
279 	int err;
280 
281 	err = mv88e6xxx_g1_vtu_op_wait(chip);
282 	if (err)
283 		return err;
284 
285 	/* To get the next higher active VID, the VTU GetNext operation can be
286 	 * started again without setting the VID registers since it already
287 	 * contains the last VID.
288 	 *
289 	 * To save a few hardware accesses and abstract this to the caller,
290 	 * write the VID only once, when the entry is given as invalid.
291 	 */
292 	if (!entry->valid) {
293 		err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
294 		if (err)
295 			return err;
296 	}
297 
298 	err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
299 	if (err)
300 		return err;
301 
302 	return mv88e6xxx_g1_vtu_vid_read(chip, entry);
303 }
304 
305 int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
306 			     struct mv88e6xxx_vtu_entry *entry)
307 {
308 	u16 val;
309 	int err;
310 
311 	err = mv88e6xxx_g1_vtu_getnext(chip, entry);
312 	if (err)
313 		return err;
314 
315 	if (entry->valid) {
316 		err = mv88e6185_g1_vtu_data_read(chip, entry);
317 		if (err)
318 			return err;
319 
320 		/* VTU DBNum[3:0] are located in VTU Operation 3:0
321 		 * VTU DBNum[7:4] are located in VTU Operation 11:8
322 		 */
323 		err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val);
324 		if (err)
325 			return err;
326 
327 		entry->fid = val & 0x000f;
328 		entry->fid |= (val & 0x0f00) >> 4;
329 	}
330 
331 	return 0;
332 }
333 
334 int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
335 			     struct mv88e6xxx_vtu_entry *entry)
336 {
337 	int err;
338 
339 	/* Fetch VLAN MemberTag data from the VTU */
340 	err = mv88e6xxx_g1_vtu_getnext(chip, entry);
341 	if (err)
342 		return err;
343 
344 	if (entry->valid) {
345 		/* Fetch (and mask) VLAN PortState data from the STU */
346 		err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
347 		if (err)
348 			return err;
349 
350 		err = mv88e6185_g1_vtu_data_read(chip, entry);
351 		if (err)
352 			return err;
353 
354 		err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
355 		if (err)
356 			return err;
357 	}
358 
359 	return 0;
360 }
361 
362 int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
363 			     struct mv88e6xxx_vtu_entry *entry)
364 {
365 	int err;
366 
367 	/* Fetch VLAN MemberTag data from the VTU */
368 	err = mv88e6xxx_g1_vtu_getnext(chip, entry);
369 	if (err)
370 		return err;
371 
372 	if (entry->valid) {
373 		err = mv88e6390_g1_vtu_data_read(chip, entry->member);
374 		if (err)
375 			return err;
376 
377 		/* Fetch VLAN PortState data from the STU */
378 		err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
379 		if (err)
380 			return err;
381 
382 		err = mv88e6390_g1_vtu_data_read(chip, entry->state);
383 		if (err)
384 			return err;
385 
386 		err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
387 		if (err)
388 			return err;
389 	}
390 
391 	return 0;
392 }
393 
394 int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
395 			       struct mv88e6xxx_vtu_entry *entry)
396 {
397 	u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE;
398 	int err;
399 
400 	err = mv88e6xxx_g1_vtu_op_wait(chip);
401 	if (err)
402 		return err;
403 
404 	err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
405 	if (err)
406 		return err;
407 
408 	if (entry->valid) {
409 		err = mv88e6185_g1_vtu_data_write(chip, entry);
410 		if (err)
411 			return err;
412 
413 		/* VTU DBNum[3:0] are located in VTU Operation 3:0
414 		 * VTU DBNum[7:4] are located in VTU Operation 11:8
415 		 */
416 		op |= entry->fid & 0x000f;
417 		op |= (entry->fid & 0x00f0) << 8;
418 	}
419 
420 	return mv88e6xxx_g1_vtu_op(chip, op);
421 }
422 
423 int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
424 			       struct mv88e6xxx_vtu_entry *entry)
425 {
426 	int err;
427 
428 	err = mv88e6xxx_g1_vtu_op_wait(chip);
429 	if (err)
430 		return err;
431 
432 	err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
433 	if (err)
434 		return err;
435 
436 	if (entry->valid) {
437 		/* Write MemberTag and PortState data */
438 		err = mv88e6185_g1_vtu_data_write(chip, entry);
439 		if (err)
440 			return err;
441 
442 		err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
443 		if (err)
444 			return err;
445 
446 		/* Load STU entry */
447 		err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
448 		if (err)
449 			return err;
450 
451 		err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
452 		if (err)
453 			return err;
454 	}
455 
456 	/* Load/Purge VTU entry */
457 	return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
458 }
459 
460 int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
461 			       struct mv88e6xxx_vtu_entry *entry)
462 {
463 	int err;
464 
465 	err = mv88e6xxx_g1_vtu_op_wait(chip);
466 	if (err)
467 		return err;
468 
469 	err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
470 	if (err)
471 		return err;
472 
473 	if (entry->valid) {
474 		/* Write PortState data */
475 		err = mv88e6390_g1_vtu_data_write(chip, entry->state);
476 		if (err)
477 			return err;
478 
479 		err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
480 		if (err)
481 			return err;
482 
483 		/* Load STU entry */
484 		err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
485 		if (err)
486 			return err;
487 
488 		/* Write MemberTag data */
489 		err = mv88e6390_g1_vtu_data_write(chip, entry->member);
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, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
500 }
501 
502 int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip)
503 {
504 	int err;
505 
506 	err = mv88e6xxx_g1_vtu_op_wait(chip);
507 	if (err)
508 		return err;
509 
510 	return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_FLUSH_ALL);
511 }
512