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 
128 static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip,
129 				      struct mv88e6xxx_vtu_entry *entry)
130 {
131 	u16 regs[3];
132 	int i;
133 
134 	/* Read all 3 VTU/STU Data registers */
135 	for (i = 0; i < 3; ++i) {
136 		u16 *reg = &regs[i];
137 		int err;
138 
139 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
140 		if (err)
141 			return err;
142 	}
143 
144 	/* Extract MemberTag and PortState data */
145 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
146 		unsigned int member_offset = (i % 4) * 4;
147 		unsigned int state_offset = member_offset + 2;
148 
149 		entry->member[i] = (regs[i / 4] >> member_offset) & 0x3;
150 		entry->state[i] = (regs[i / 4] >> state_offset) & 0x3;
151 	}
152 
153 	return 0;
154 }
155 
156 static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip,
157 				       struct mv88e6xxx_vtu_entry *entry)
158 {
159 	u16 regs[3] = { 0 };
160 	int i;
161 
162 	/* Insert MemberTag and PortState data */
163 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
164 		unsigned int member_offset = (i % 4) * 4;
165 		unsigned int state_offset = member_offset + 2;
166 
167 		regs[i / 4] |= (entry->member[i] & 0x3) << member_offset;
168 		regs[i / 4] |= (entry->state[i] & 0x3) << state_offset;
169 	}
170 
171 	/* Write all 3 VTU/STU Data registers */
172 	for (i = 0; i < 3; ++i) {
173 		u16 reg = regs[i];
174 		int err;
175 
176 		err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
177 		if (err)
178 			return err;
179 	}
180 
181 	return 0;
182 }
183 
184 static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data)
185 {
186 	u16 regs[2];
187 	int i;
188 
189 	/* Read the 2 VTU/STU Data registers */
190 	for (i = 0; i < 2; ++i) {
191 		u16 *reg = &regs[i];
192 		int err;
193 
194 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
195 		if (err)
196 			return err;
197 	}
198 
199 	/* Extract data */
200 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
201 		unsigned int offset = (i % 8) * 2;
202 
203 		data[i] = (regs[i / 8] >> offset) & 0x3;
204 	}
205 
206 	return 0;
207 }
208 
209 static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data)
210 {
211 	u16 regs[2] = { 0 };
212 	int i;
213 
214 	/* Insert data */
215 	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
216 		unsigned int offset = (i % 8) * 2;
217 
218 		regs[i / 8] |= (data[i] & 0x3) << offset;
219 	}
220 
221 	/* Write the 2 VTU/STU Data registers */
222 	for (i = 0; i < 2; ++i) {
223 		u16 reg = regs[i];
224 		int err;
225 
226 		err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
227 		if (err)
228 			return err;
229 	}
230 
231 	return 0;
232 }
233 
234 /* VLAN Translation Unit Operations */
235 
236 static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip,
237 					struct mv88e6xxx_vtu_entry *entry)
238 {
239 	int err;
240 
241 	err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
242 	if (err)
243 		return err;
244 
245 	err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT);
246 	if (err)
247 		return err;
248 
249 	err = mv88e6xxx_g1_vtu_sid_read(chip, entry);
250 	if (err)
251 		return err;
252 
253 	return mv88e6xxx_g1_vtu_vid_read(chip, entry);
254 }
255 
256 static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip,
257 				    struct mv88e6xxx_vtu_entry *vtu)
258 {
259 	struct mv88e6xxx_vtu_entry stu;
260 	int err;
261 
262 	err = mv88e6xxx_g1_vtu_sid_read(chip, vtu);
263 	if (err)
264 		return err;
265 
266 	stu.sid = vtu->sid - 1;
267 
268 	err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu);
269 	if (err)
270 		return err;
271 
272 	if (stu.sid != vtu->sid || !stu.valid)
273 		return -EINVAL;
274 
275 	return 0;
276 }
277 
278 static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
279 				    struct mv88e6xxx_vtu_entry *entry)
280 {
281 	int err;
282 
283 	err = mv88e6xxx_g1_vtu_op_wait(chip);
284 	if (err)
285 		return err;
286 
287 	/* To get the next higher active VID, the VTU GetNext operation can be
288 	 * started again without setting the VID registers since it already
289 	 * contains the last VID.
290 	 *
291 	 * To save a few hardware accesses and abstract this to the caller,
292 	 * write the VID only once, when the entry is given as invalid.
293 	 */
294 	if (!entry->valid) {
295 		err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
296 		if (err)
297 			return err;
298 	}
299 
300 	err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT);
301 	if (err)
302 		return err;
303 
304 	return mv88e6xxx_g1_vtu_vid_read(chip, entry);
305 }
306 
307 int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
308 			     struct mv88e6xxx_vtu_entry *entry)
309 {
310 	u16 val;
311 	int err;
312 
313 	err = mv88e6xxx_g1_vtu_getnext(chip, entry);
314 	if (err)
315 		return err;
316 
317 	if (entry->valid) {
318 		err = mv88e6185_g1_vtu_data_read(chip, entry);
319 		if (err)
320 			return err;
321 
322 		/* VTU DBNum[3:0] are located in VTU Operation 3:0
323 		 * VTU DBNum[7:4] are located in VTU Operation 11:8
324 		 */
325 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val);
326 		if (err)
327 			return err;
328 
329 		entry->fid = val & 0x000f;
330 		entry->fid |= (val & 0x0f00) >> 4;
331 	}
332 
333 	return 0;
334 }
335 
336 int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
337 			     struct mv88e6xxx_vtu_entry *entry)
338 {
339 	int err;
340 
341 	/* Fetch VLAN MemberTag data from the VTU */
342 	err = mv88e6xxx_g1_vtu_getnext(chip, entry);
343 	if (err)
344 		return err;
345 
346 	if (entry->valid) {
347 		/* Fetch (and mask) VLAN PortState data from the STU */
348 		err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
349 		if (err)
350 			return err;
351 
352 		err = mv88e6185_g1_vtu_data_read(chip, entry);
353 		if (err)
354 			return err;
355 
356 		err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
357 		if (err)
358 			return err;
359 	}
360 
361 	return 0;
362 }
363 
364 int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
365 			     struct mv88e6xxx_vtu_entry *entry)
366 {
367 	int err;
368 
369 	/* Fetch VLAN MemberTag data from the VTU */
370 	err = mv88e6xxx_g1_vtu_getnext(chip, entry);
371 	if (err)
372 		return err;
373 
374 	if (entry->valid) {
375 		err = mv88e6390_g1_vtu_data_read(chip, entry->member);
376 		if (err)
377 			return err;
378 
379 		/* Fetch VLAN PortState data from the STU */
380 		err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
381 		if (err)
382 			return err;
383 
384 		err = mv88e6390_g1_vtu_data_read(chip, entry->state);
385 		if (err)
386 			return err;
387 
388 		err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
389 		if (err)
390 			return err;
391 	}
392 
393 	return 0;
394 }
395 
396 int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
397 			       struct mv88e6xxx_vtu_entry *entry)
398 {
399 	u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE;
400 	int err;
401 
402 	err = mv88e6xxx_g1_vtu_op_wait(chip);
403 	if (err)
404 		return err;
405 
406 	err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
407 	if (err)
408 		return err;
409 
410 	if (entry->valid) {
411 		err = mv88e6185_g1_vtu_data_write(chip, entry);
412 		if (err)
413 			return err;
414 
415 		/* VTU DBNum[3:0] are located in VTU Operation 3:0
416 		 * VTU DBNum[7:4] are located in VTU Operation 11:8
417 		 */
418 		op |= entry->fid & 0x000f;
419 		op |= (entry->fid & 0x00f0) << 8;
420 	}
421 
422 	return mv88e6xxx_g1_vtu_op(chip, op);
423 }
424 
425 int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
426 			       struct mv88e6xxx_vtu_entry *entry)
427 {
428 	int err;
429 
430 	err = mv88e6xxx_g1_vtu_op_wait(chip);
431 	if (err)
432 		return err;
433 
434 	err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
435 	if (err)
436 		return err;
437 
438 	if (entry->valid) {
439 		/* Write MemberTag and PortState data */
440 		err = mv88e6185_g1_vtu_data_write(chip, entry);
441 		if (err)
442 			return err;
443 
444 		err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
445 		if (err)
446 			return err;
447 
448 		/* Load STU entry */
449 		err = mv88e6xxx_g1_vtu_op(chip,
450 					  MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE);
451 		if (err)
452 			return err;
453 
454 		err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
455 		if (err)
456 			return err;
457 	}
458 
459 	/* Load/Purge VTU entry */
460 	return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE);
461 }
462 
463 int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
464 			       struct mv88e6xxx_vtu_entry *entry)
465 {
466 	int err;
467 
468 	err = mv88e6xxx_g1_vtu_op_wait(chip);
469 	if (err)
470 		return err;
471 
472 	err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
473 	if (err)
474 		return err;
475 
476 	if (entry->valid) {
477 		/* Write PortState data */
478 		err = mv88e6390_g1_vtu_data_write(chip, entry->state);
479 		if (err)
480 			return err;
481 
482 		err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
483 		if (err)
484 			return err;
485 
486 		/* Load STU entry */
487 		err = mv88e6xxx_g1_vtu_op(chip,
488 					  MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE);
489 		if (err)
490 			return err;
491 
492 		/* Write MemberTag data */
493 		err = mv88e6390_g1_vtu_data_write(chip, entry->member);
494 		if (err)
495 			return err;
496 
497 		err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
498 		if (err)
499 			return err;
500 	}
501 
502 	/* Load/Purge VTU entry */
503 	return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE);
504 }
505 
506 int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip)
507 {
508 	int err;
509 
510 	err = mv88e6xxx_g1_vtu_op_wait(chip);
511 	if (err)
512 		return err;
513 
514 	return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL);
515 }
516