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