Linux Audio

Check our new training course

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