]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/net/dsa/mv88e6xxx/chip.c
net: dsa: mv88e6xxx: Abstract mv88e6165 PHY operations
[mirror_ubuntu-bionic-kernel.git] / drivers / net / dsa / mv88e6xxx / chip.c
CommitLineData
91da11f8 1/*
0d3cd4b6
VD
2 * Marvell 88e6xxx Ethernet switch single-chip support
3 *
91da11f8
LB
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
b8fee957
VD
6 * Copyright (c) 2015 CMC Electronics, Inc.
7 * Added support for VLAN Table Unit operations
8 *
14c7b3c3
AL
9 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
10 *
91da11f8
LB
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
19b2f97e 17#include <linux/delay.h>
defb05b9 18#include <linux/etherdevice.h>
dea87024 19#include <linux/ethtool.h>
facd95b2 20#include <linux/if_bridge.h>
dc30c35b
AL
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/irqdomain.h>
19b2f97e 24#include <linux/jiffies.h>
91da11f8 25#include <linux/list.h>
14c7b3c3 26#include <linux/mdio.h>
2bbba277 27#include <linux/module.h>
caac8545 28#include <linux/of_device.h>
dc30c35b 29#include <linux/of_irq.h>
b516d453 30#include <linux/of_mdio.h>
91da11f8 31#include <linux/netdevice.h>
c8c1b39a 32#include <linux/gpio/consumer.h>
91da11f8 33#include <linux/phy.h>
c8f0b869 34#include <net/dsa.h>
1f36faf2 35#include <net/switchdev.h>
ec561276 36
91da11f8 37#include "mv88e6xxx.h"
a935c052 38#include "global1.h"
ec561276 39#include "global2.h"
18abed21 40#include "port.h"
91da11f8 41
fad09c73 42static void assert_reg_lock(struct mv88e6xxx_chip *chip)
3996a4ff 43{
fad09c73
VD
44 if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
45 dev_err(chip->dev, "Switch registers lock not held!\n");
3996a4ff
VD
46 dump_stack();
47 }
48}
49
914b32f6
VD
50/* The switch ADDR[4:1] configuration pins define the chip SMI device address
51 * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
52 *
53 * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
54 * is the only device connected to the SMI master. In this mode it responds to
55 * all 32 possible SMI addresses, and thus maps directly the internal devices.
56 *
57 * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
58 * multiple devices to share the SMI interface. In this mode it responds to only
59 * 2 registers, used to indirectly access the internal SMI devices.
91da11f8 60 */
914b32f6 61
fad09c73 62static int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip,
914b32f6
VD
63 int addr, int reg, u16 *val)
64{
fad09c73 65 if (!chip->smi_ops)
914b32f6
VD
66 return -EOPNOTSUPP;
67
fad09c73 68 return chip->smi_ops->read(chip, addr, reg, val);
914b32f6
VD
69}
70
fad09c73 71static int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip,
914b32f6
VD
72 int addr, int reg, u16 val)
73{
fad09c73 74 if (!chip->smi_ops)
914b32f6
VD
75 return -EOPNOTSUPP;
76
fad09c73 77 return chip->smi_ops->write(chip, addr, reg, val);
914b32f6
VD
78}
79
fad09c73 80static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_chip *chip,
914b32f6
VD
81 int addr, int reg, u16 *val)
82{
83 int ret;
84
fad09c73 85 ret = mdiobus_read_nested(chip->bus, addr, reg);
914b32f6
VD
86 if (ret < 0)
87 return ret;
88
89 *val = ret & 0xffff;
90
91 return 0;
92}
93
fad09c73 94static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_chip *chip,
914b32f6
VD
95 int addr, int reg, u16 val)
96{
97 int ret;
98
fad09c73 99 ret = mdiobus_write_nested(chip->bus, addr, reg, val);
914b32f6
VD
100 if (ret < 0)
101 return ret;
102
103 return 0;
104}
105
c08026ab 106static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_single_chip_ops = {
914b32f6
VD
107 .read = mv88e6xxx_smi_single_chip_read,
108 .write = mv88e6xxx_smi_single_chip_write,
109};
110
fad09c73 111static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_chip *chip)
91da11f8
LB
112{
113 int ret;
114 int i;
115
116 for (i = 0; i < 16; i++) {
fad09c73 117 ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_CMD);
91da11f8
LB
118 if (ret < 0)
119 return ret;
120
cca8b133 121 if ((ret & SMI_CMD_BUSY) == 0)
91da11f8
LB
122 return 0;
123 }
124
125 return -ETIMEDOUT;
126}
127
fad09c73 128static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_chip *chip,
914b32f6 129 int addr, int reg, u16 *val)
91da11f8
LB
130{
131 int ret;
132
3675c8d7 133 /* Wait for the bus to become free. */
fad09c73 134 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
135 if (ret < 0)
136 return ret;
137
3675c8d7 138 /* Transmit the read command. */
fad09c73 139 ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
6e899e6c 140 SMI_CMD_OP_22_READ | (addr << 5) | reg);
91da11f8
LB
141 if (ret < 0)
142 return ret;
143
3675c8d7 144 /* Wait for the read command to complete. */
fad09c73 145 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
146 if (ret < 0)
147 return ret;
148
3675c8d7 149 /* Read the data. */
fad09c73 150 ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_DATA);
bb92ea5e
VD
151 if (ret < 0)
152 return ret;
153
914b32f6 154 *val = ret & 0xffff;
91da11f8 155
914b32f6 156 return 0;
8d6d09e7
GR
157}
158
fad09c73 159static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_chip *chip,
914b32f6 160 int addr, int reg, u16 val)
91da11f8
LB
161{
162 int ret;
163
3675c8d7 164 /* Wait for the bus to become free. */
fad09c73 165 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
166 if (ret < 0)
167 return ret;
168
3675c8d7 169 /* Transmit the data to write. */
fad09c73 170 ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_DATA, val);
91da11f8
LB
171 if (ret < 0)
172 return ret;
173
3675c8d7 174 /* Transmit the write command. */
fad09c73 175 ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
6e899e6c 176 SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
91da11f8
LB
177 if (ret < 0)
178 return ret;
179
3675c8d7 180 /* Wait for the write command to complete. */
fad09c73 181 ret = mv88e6xxx_smi_multi_chip_wait(chip);
91da11f8
LB
182 if (ret < 0)
183 return ret;
184
185 return 0;
186}
187
c08026ab 188static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_multi_chip_ops = {
914b32f6
VD
189 .read = mv88e6xxx_smi_multi_chip_read,
190 .write = mv88e6xxx_smi_multi_chip_write,
191};
192
ec561276 193int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
914b32f6
VD
194{
195 int err;
196
fad09c73 197 assert_reg_lock(chip);
914b32f6 198
fad09c73 199 err = mv88e6xxx_smi_read(chip, addr, reg, val);
914b32f6
VD
200 if (err)
201 return err;
202
fad09c73 203 dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
914b32f6
VD
204 addr, reg, *val);
205
206 return 0;
207}
208
ec561276 209int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
91da11f8 210{
914b32f6
VD
211 int err;
212
fad09c73 213 assert_reg_lock(chip);
91da11f8 214
fad09c73 215 err = mv88e6xxx_smi_write(chip, addr, reg, val);
914b32f6
VD
216 if (err)
217 return err;
218
fad09c73 219 dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
bb92ea5e
VD
220 addr, reg, val);
221
914b32f6
VD
222 return 0;
223}
224
efb3e74d
AL
225static int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, int addr,
226 int reg, u16 *val)
227{
228 return mv88e6xxx_read(chip, addr, reg, val);
229}
230
231static int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, int addr,
232 int reg, u16 val)
233{
234 return mv88e6xxx_write(chip, addr, reg, val);
235}
236
e57e5e77
VD
237static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
238 int reg, u16 *val)
239{
240 int addr = phy; /* PHY devices addresses start at 0x0 */
241
b3469dd8 242 if (!chip->info->ops->phy_read)
e57e5e77
VD
243 return -EOPNOTSUPP;
244
b3469dd8 245 return chip->info->ops->phy_read(chip, addr, reg, val);
e57e5e77
VD
246}
247
248static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
249 int reg, u16 val)
250{
251 int addr = phy; /* PHY devices addresses start at 0x0 */
252
b3469dd8 253 if (!chip->info->ops->phy_write)
e57e5e77
VD
254 return -EOPNOTSUPP;
255
b3469dd8 256 return chip->info->ops->phy_write(chip, addr, reg, val);
e57e5e77
VD
257}
258
09cb7dfd
VD
259static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
260{
261 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
262 return -EOPNOTSUPP;
263
264 return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
265}
266
267static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
268{
269 int err;
270
271 /* Restore PHY page Copper 0x0 for access via the registered MDIO bus */
272 err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
273 if (unlikely(err)) {
274 dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n",
275 phy, err);
276 }
277}
278
279static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
280 u8 page, int reg, u16 *val)
281{
282 int err;
283
284 /* There is no paging for registers 22 */
285 if (reg == PHY_PAGE)
286 return -EINVAL;
287
288 err = mv88e6xxx_phy_page_get(chip, phy, page);
289 if (!err) {
290 err = mv88e6xxx_phy_read(chip, phy, reg, val);
291 mv88e6xxx_phy_page_put(chip, phy);
292 }
293
294 return err;
295}
296
297static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
298 u8 page, int reg, u16 val)
299{
300 int err;
301
302 /* There is no paging for registers 22 */
303 if (reg == PHY_PAGE)
304 return -EINVAL;
305
306 err = mv88e6xxx_phy_page_get(chip, phy, page);
307 if (!err) {
308 err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
309 mv88e6xxx_phy_page_put(chip, phy);
310 }
311
312 return err;
313}
314
315static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
316{
317 return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
318 reg, val);
319}
320
321static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
322{
323 return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
324 reg, val);
325}
326
dc30c35b
AL
327static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
328{
329 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
330 unsigned int n = d->hwirq;
331
332 chip->g1_irq.masked |= (1 << n);
333}
334
335static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
336{
337 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
338 unsigned int n = d->hwirq;
339
340 chip->g1_irq.masked &= ~(1 << n);
341}
342
343static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
344{
345 struct mv88e6xxx_chip *chip = dev_id;
346 unsigned int nhandled = 0;
347 unsigned int sub_irq;
348 unsigned int n;
349 u16 reg;
350 int err;
351
352 mutex_lock(&chip->reg_lock);
353 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &reg);
354 mutex_unlock(&chip->reg_lock);
355
356 if (err)
357 goto out;
358
359 for (n = 0; n < chip->g1_irq.nirqs; ++n) {
360 if (reg & (1 << n)) {
361 sub_irq = irq_find_mapping(chip->g1_irq.domain, n);
362 handle_nested_irq(sub_irq);
363 ++nhandled;
364 }
365 }
366out:
367 return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
368}
369
370static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
371{
372 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
373
374 mutex_lock(&chip->reg_lock);
375}
376
377static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
378{
379 struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
380 u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
381 u16 reg;
382 int err;
383
384 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &reg);
385 if (err)
386 goto out;
387
388 reg &= ~mask;
389 reg |= (~chip->g1_irq.masked & mask);
390
391 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg);
392 if (err)
393 goto out;
394
395out:
396 mutex_unlock(&chip->reg_lock);
397}
398
399static struct irq_chip mv88e6xxx_g1_irq_chip = {
400 .name = "mv88e6xxx-g1",
401 .irq_mask = mv88e6xxx_g1_irq_mask,
402 .irq_unmask = mv88e6xxx_g1_irq_unmask,
403 .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock,
404 .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock,
405};
406
407static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
408 unsigned int irq,
409 irq_hw_number_t hwirq)
410{
411 struct mv88e6xxx_chip *chip = d->host_data;
412
413 irq_set_chip_data(irq, d->host_data);
414 irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
415 irq_set_noprobe(irq);
416
417 return 0;
418}
419
420static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
421 .map = mv88e6xxx_g1_irq_domain_map,
422 .xlate = irq_domain_xlate_twocell,
423};
424
425static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
426{
427 int irq, virq;
3460a577
AL
428 u16 mask;
429
430 mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask);
431 mask |= GENMASK(chip->g1_irq.nirqs, 0);
432 mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
433
434 free_irq(chip->irq, chip);
dc30c35b 435
5edef2f2 436 for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
a3db3d3a 437 virq = irq_find_mapping(chip->g1_irq.domain, irq);
dc30c35b
AL
438 irq_dispose_mapping(virq);
439 }
440
a3db3d3a 441 irq_domain_remove(chip->g1_irq.domain);
dc30c35b
AL
442}
443
444static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
445{
3dd0ef05
AL
446 int err, irq, virq;
447 u16 reg, mask;
dc30c35b
AL
448
449 chip->g1_irq.nirqs = chip->info->g1_irqs;
450 chip->g1_irq.domain = irq_domain_add_simple(
451 NULL, chip->g1_irq.nirqs, 0,
452 &mv88e6xxx_g1_irq_domain_ops, chip);
453 if (!chip->g1_irq.domain)
454 return -ENOMEM;
455
456 for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
457 irq_create_mapping(chip->g1_irq.domain, irq);
458
459 chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
460 chip->g1_irq.masked = ~0;
461
3dd0ef05 462 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask);
dc30c35b 463 if (err)
3dd0ef05 464 goto out_mapping;
dc30c35b 465
3dd0ef05 466 mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
dc30c35b 467
3dd0ef05 468 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
dc30c35b 469 if (err)
3dd0ef05 470 goto out_disable;
dc30c35b
AL
471
472 /* Reading the interrupt status clears (most of) them */
473 err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &reg);
474 if (err)
3dd0ef05 475 goto out_disable;
dc30c35b
AL
476
477 err = request_threaded_irq(chip->irq, NULL,
478 mv88e6xxx_g1_irq_thread_fn,
479 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
480 dev_name(chip->dev), chip);
481 if (err)
3dd0ef05 482 goto out_disable;
dc30c35b
AL
483
484 return 0;
485
3dd0ef05
AL
486out_disable:
487 mask |= GENMASK(chip->g1_irq.nirqs, 0);
488 mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
489
490out_mapping:
491 for (irq = 0; irq < 16; irq++) {
492 virq = irq_find_mapping(chip->g1_irq.domain, irq);
493 irq_dispose_mapping(virq);
494 }
495
496 irq_domain_remove(chip->g1_irq.domain);
dc30c35b
AL
497
498 return err;
499}
500
ec561276 501int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
2d79af6e 502{
6441e669 503 int i;
2d79af6e 504
6441e669 505 for (i = 0; i < 16; i++) {
2d79af6e
VD
506 u16 val;
507 int err;
508
509 err = mv88e6xxx_read(chip, addr, reg, &val);
510 if (err)
511 return err;
512
513 if (!(val & mask))
514 return 0;
515
516 usleep_range(1000, 2000);
517 }
518
30853553 519 dev_err(chip->dev, "Timeout while waiting for switch\n");
2d79af6e
VD
520 return -ETIMEDOUT;
521}
522
f22ab641 523/* Indirect write to single pointer-data register with an Update bit */
ec561276 524int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
f22ab641
VD
525{
526 u16 val;
0f02b4f7 527 int err;
f22ab641
VD
528
529 /* Wait until the previous operation is completed */
0f02b4f7
AL
530 err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
531 if (err)
532 return err;
f22ab641
VD
533
534 /* Set the Update bit to trigger a write operation */
535 val = BIT(15) | update;
536
537 return mv88e6xxx_write(chip, addr, reg, val);
538}
539
a935c052 540static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
914b32f6 541{
a199d8b6
VD
542 if (!chip->info->ops->ppu_disable)
543 return 0;
2e5f0320 544
a199d8b6 545 return chip->info->ops->ppu_disable(chip);
2e5f0320
LB
546}
547
fad09c73 548static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
2e5f0320 549{
a199d8b6
VD
550 if (!chip->info->ops->ppu_enable)
551 return 0;
2e5f0320 552
a199d8b6 553 return chip->info->ops->ppu_enable(chip);
2e5f0320
LB
554}
555
556static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
557{
fad09c73 558 struct mv88e6xxx_chip *chip;
2e5f0320 559
fad09c73 560 chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
762eb67b 561
fad09c73 562 mutex_lock(&chip->reg_lock);
762eb67b 563
fad09c73
VD
564 if (mutex_trylock(&chip->ppu_mutex)) {
565 if (mv88e6xxx_ppu_enable(chip) == 0)
566 chip->ppu_disabled = 0;
567 mutex_unlock(&chip->ppu_mutex);
2e5f0320 568 }
762eb67b 569
fad09c73 570 mutex_unlock(&chip->reg_lock);
2e5f0320
LB
571}
572
573static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
574{
fad09c73 575 struct mv88e6xxx_chip *chip = (void *)_ps;
2e5f0320 576
fad09c73 577 schedule_work(&chip->ppu_work);
2e5f0320
LB
578}
579
fad09c73 580static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip)
2e5f0320 581{
2e5f0320
LB
582 int ret;
583
fad09c73 584 mutex_lock(&chip->ppu_mutex);
2e5f0320 585
3675c8d7 586 /* If the PHY polling unit is enabled, disable it so that
2e5f0320
LB
587 * we can access the PHY registers. If it was already
588 * disabled, cancel the timer that is going to re-enable
589 * it.
590 */
fad09c73
VD
591 if (!chip->ppu_disabled) {
592 ret = mv88e6xxx_ppu_disable(chip);
85686581 593 if (ret < 0) {
fad09c73 594 mutex_unlock(&chip->ppu_mutex);
85686581
BG
595 return ret;
596 }
fad09c73 597 chip->ppu_disabled = 1;
2e5f0320 598 } else {
fad09c73 599 del_timer(&chip->ppu_timer);
85686581 600 ret = 0;
2e5f0320
LB
601 }
602
603 return ret;
604}
605
fad09c73 606static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip)
2e5f0320 607{
3675c8d7 608 /* Schedule a timer to re-enable the PHY polling unit. */
fad09c73
VD
609 mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
610 mutex_unlock(&chip->ppu_mutex);
2e5f0320
LB
611}
612
fad09c73 613static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
2e5f0320 614{
fad09c73
VD
615 mutex_init(&chip->ppu_mutex);
616 INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work);
68497a87
WY
617 setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer,
618 (unsigned long)chip);
2e5f0320
LB
619}
620
930188ce
AL
621static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip)
622{
623 del_timer_sync(&chip->ppu_timer);
624}
625
e57e5e77
VD
626static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, int addr,
627 int reg, u16 *val)
2e5f0320 628{
e57e5e77 629 int err;
2e5f0320 630
e57e5e77
VD
631 err = mv88e6xxx_ppu_access_get(chip);
632 if (!err) {
633 err = mv88e6xxx_read(chip, addr, reg, val);
fad09c73 634 mv88e6xxx_ppu_access_put(chip);
2e5f0320
LB
635 }
636
e57e5e77 637 return err;
2e5f0320
LB
638}
639
e57e5e77
VD
640static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, int addr,
641 int reg, u16 val)
2e5f0320 642{
e57e5e77 643 int err;
2e5f0320 644
e57e5e77
VD
645 err = mv88e6xxx_ppu_access_get(chip);
646 if (!err) {
647 err = mv88e6xxx_write(chip, addr, reg, val);
fad09c73 648 mv88e6xxx_ppu_access_put(chip);
2e5f0320
LB
649 }
650
e57e5e77 651 return err;
2e5f0320 652}
2e5f0320 653
fad09c73 654static bool mv88e6xxx_6095_family(struct mv88e6xxx_chip *chip)
54d792f2 655{
fad09c73 656 return chip->info->family == MV88E6XXX_FAMILY_6095;
54d792f2
AL
657}
658
fad09c73 659static bool mv88e6xxx_6097_family(struct mv88e6xxx_chip *chip)
54d792f2 660{
fad09c73 661 return chip->info->family == MV88E6XXX_FAMILY_6097;
54d792f2
AL
662}
663
fad09c73 664static bool mv88e6xxx_6165_family(struct mv88e6xxx_chip *chip)
54d792f2 665{
fad09c73 666 return chip->info->family == MV88E6XXX_FAMILY_6165;
54d792f2
AL
667}
668
fad09c73 669static bool mv88e6xxx_6185_family(struct mv88e6xxx_chip *chip)
54d792f2 670{
fad09c73 671 return chip->info->family == MV88E6XXX_FAMILY_6185;
54d792f2
AL
672}
673
fad09c73 674static bool mv88e6xxx_6320_family(struct mv88e6xxx_chip *chip)
7c3d0d67 675{
fad09c73 676 return chip->info->family == MV88E6XXX_FAMILY_6320;
7c3d0d67
AK
677}
678
fad09c73 679static bool mv88e6xxx_6351_family(struct mv88e6xxx_chip *chip)
54d792f2 680{
fad09c73 681 return chip->info->family == MV88E6XXX_FAMILY_6351;
54d792f2
AL
682}
683
fad09c73 684static bool mv88e6xxx_6352_family(struct mv88e6xxx_chip *chip)
f3a8b6b6 685{
fad09c73 686 return chip->info->family == MV88E6XXX_FAMILY_6352;
f3a8b6b6
AL
687}
688
d78343d2
VD
689static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
690 int link, int speed, int duplex,
691 phy_interface_t mode)
692{
693 int err;
694
695 if (!chip->info->ops->port_set_link)
696 return 0;
697
698 /* Port's MAC control must not be changed unless the link is down */
699 err = chip->info->ops->port_set_link(chip, port, 0);
700 if (err)
701 return err;
702
703 if (chip->info->ops->port_set_speed) {
704 err = chip->info->ops->port_set_speed(chip, port, speed);
705 if (err && err != -EOPNOTSUPP)
706 goto restore_link;
707 }
708
709 if (chip->info->ops->port_set_duplex) {
710 err = chip->info->ops->port_set_duplex(chip, port, duplex);
711 if (err && err != -EOPNOTSUPP)
712 goto restore_link;
713 }
714
715 if (chip->info->ops->port_set_rgmii_delay) {
716 err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
717 if (err && err != -EOPNOTSUPP)
718 goto restore_link;
719 }
720
721 err = 0;
722restore_link:
723 if (chip->info->ops->port_set_link(chip, port, link))
724 netdev_err(chip->ds->ports[port].netdev,
725 "failed to restore MAC's link\n");
726
727 return err;
728}
729
dea87024
AL
730/* We expect the switch to perform auto negotiation if there is a real
731 * phy. However, in the case of a fixed link phy, we force the port
732 * settings from the fixed link settings.
733 */
f81ec90f
VD
734static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
735 struct phy_device *phydev)
dea87024 736{
04bed143 737 struct mv88e6xxx_chip *chip = ds->priv;
0e7b9925 738 int err;
dea87024
AL
739
740 if (!phy_is_pseudo_fixed_link(phydev))
741 return;
742
fad09c73 743 mutex_lock(&chip->reg_lock);
d78343d2
VD
744 err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
745 phydev->duplex, phydev->interface);
fad09c73 746 mutex_unlock(&chip->reg_lock);
d78343d2
VD
747
748 if (err && err != -EOPNOTSUPP)
749 netdev_err(ds->ports[port].netdev, "failed to configure MAC\n");
dea87024
AL
750}
751
a605a0fe 752static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
91da11f8 753{
a605a0fe
AL
754 if (!chip->info->ops->stats_snapshot)
755 return -EOPNOTSUPP;
91da11f8 756
a605a0fe 757 return chip->info->ops->stats_snapshot(chip, port);
91da11f8
LB
758}
759
e413e7e1 760static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
dfafe449
AL
761 { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, },
762 { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, },
763 { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, },
764 { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, },
765 { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, },
766 { "in_pause", 4, 0x16, STATS_TYPE_BANK0, },
767 { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, },
768 { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, },
769 { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, },
770 { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, },
771 { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, },
772 { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, },
773 { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, },
774 { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, },
775 { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, },
776 { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, },
777 { "out_pause", 4, 0x15, STATS_TYPE_BANK0, },
778 { "excessive", 4, 0x11, STATS_TYPE_BANK0, },
779 { "collisions", 4, 0x1e, STATS_TYPE_BANK0, },
780 { "deferred", 4, 0x05, STATS_TYPE_BANK0, },
781 { "single", 4, 0x14, STATS_TYPE_BANK0, },
782 { "multiple", 4, 0x17, STATS_TYPE_BANK0, },
783 { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, },
784 { "late", 4, 0x1f, STATS_TYPE_BANK0, },
785 { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, },
786 { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, },
787 { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, },
788 { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, },
789 { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, },
790 { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, },
791 { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, },
792 { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, },
793 { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, },
794 { "in_discards", 4, 0x00, STATS_TYPE_BANK1, },
795 { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, },
796 { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, },
797 { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, },
798 { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, },
799 { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, },
800 { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, },
801 { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, },
802 { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, },
803 { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, },
804 { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, },
805 { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, },
806 { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, },
807 { "in_management", 4, 0x0f, STATS_TYPE_BANK1, },
808 { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, },
809 { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, },
810 { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, },
811 { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, },
812 { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, },
813 { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, },
814 { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, },
815 { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, },
816 { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, },
817 { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, },
818 { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, },
819 { "out_management", 4, 0x1f, STATS_TYPE_BANK1, },
e413e7e1
AL
820};
821
fad09c73 822static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
f5e2ed02 823 struct mv88e6xxx_hw_stat *s,
e0d8b615
AL
824 int port, u16 bank1_select,
825 u16 histogram)
80c4627b 826{
80c4627b
AL
827 u32 low;
828 u32 high = 0;
dfafe449 829 u16 reg = 0;
0e7b9925 830 int err;
80c4627b
AL
831 u64 value;
832
f5e2ed02 833 switch (s->type) {
dfafe449 834 case STATS_TYPE_PORT:
0e7b9925
AL
835 err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
836 if (err)
80c4627b
AL
837 return UINT64_MAX;
838
0e7b9925 839 low = reg;
80c4627b 840 if (s->sizeof_stat == 4) {
0e7b9925
AL
841 err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
842 if (err)
80c4627b 843 return UINT64_MAX;
0e7b9925 844 high = reg;
80c4627b 845 }
f5e2ed02 846 break;
dfafe449 847 case STATS_TYPE_BANK1:
e0d8b615 848 reg = bank1_select;
dfafe449
AL
849 /* fall through */
850 case STATS_TYPE_BANK0:
e0d8b615 851 reg |= s->reg | histogram;
7f9ef3af 852 mv88e6xxx_g1_stats_read(chip, reg, &low);
80c4627b 853 if (s->sizeof_stat == 8)
7f9ef3af 854 mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
80c4627b
AL
855 }
856 value = (((u64)high) << 16) | low;
857 return value;
858}
859
dfafe449
AL
860static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
861 uint8_t *data, int types)
91da11f8 862{
f5e2ed02
AL
863 struct mv88e6xxx_hw_stat *stat;
864 int i, j;
91da11f8 865
f5e2ed02
AL
866 for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
867 stat = &mv88e6xxx_hw_stats[i];
dfafe449 868 if (stat->type & types) {
f5e2ed02
AL
869 memcpy(data + j * ETH_GSTRING_LEN, stat->string,
870 ETH_GSTRING_LEN);
871 j++;
872 }
91da11f8 873 }
e413e7e1
AL
874}
875
dfafe449
AL
876static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
877 uint8_t *data)
878{
879 mv88e6xxx_stats_get_strings(chip, data,
880 STATS_TYPE_BANK0 | STATS_TYPE_PORT);
881}
882
883static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
884 uint8_t *data)
885{
886 mv88e6xxx_stats_get_strings(chip, data,
887 STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
888}
889
890static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
891 uint8_t *data)
e413e7e1 892{
04bed143 893 struct mv88e6xxx_chip *chip = ds->priv;
dfafe449
AL
894
895 if (chip->info->ops->stats_get_strings)
896 chip->info->ops->stats_get_strings(chip, data);
897}
898
899static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
900 int types)
901{
f5e2ed02
AL
902 struct mv88e6xxx_hw_stat *stat;
903 int i, j;
904
905 for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
906 stat = &mv88e6xxx_hw_stats[i];
dfafe449 907 if (stat->type & types)
f5e2ed02
AL
908 j++;
909 }
910 return j;
e413e7e1
AL
911}
912
dfafe449
AL
913static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
914{
915 return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
916 STATS_TYPE_PORT);
917}
918
919static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
920{
921 return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
922 STATS_TYPE_BANK1);
923}
924
925static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
926{
927 struct mv88e6xxx_chip *chip = ds->priv;
928
929 if (chip->info->ops->stats_get_sset_count)
930 return chip->info->ops->stats_get_sset_count(chip);
931
932 return 0;
933}
934
052f947f 935static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
e0d8b615
AL
936 uint64_t *data, int types,
937 u16 bank1_select, u16 histogram)
052f947f
AL
938{
939 struct mv88e6xxx_hw_stat *stat;
940 int i, j;
941
942 for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
943 stat = &mv88e6xxx_hw_stats[i];
944 if (stat->type & types) {
e0d8b615
AL
945 data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
946 bank1_select,
947 histogram);
052f947f
AL
948 j++;
949 }
950 }
951}
952
953static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
954 uint64_t *data)
955{
956 return mv88e6xxx_stats_get_stats(chip, port, data,
e0d8b615
AL
957 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
958 0, GLOBAL_STATS_OP_HIST_RX_TX);
052f947f
AL
959}
960
961static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
962 uint64_t *data)
963{
964 return mv88e6xxx_stats_get_stats(chip, port, data,
e0d8b615
AL
965 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
966 GLOBAL_STATS_OP_BANK_1_BIT_9,
967 GLOBAL_STATS_OP_HIST_RX_TX);
968}
969
970static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
971 uint64_t *data)
972{
973 return mv88e6xxx_stats_get_stats(chip, port, data,
974 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
975 GLOBAL_STATS_OP_BANK_1_BIT_10, 0);
052f947f
AL
976}
977
978static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
979 uint64_t *data)
980{
981 if (chip->info->ops->stats_get_stats)
982 chip->info->ops->stats_get_stats(chip, port, data);
983}
984
f81ec90f
VD
985static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
986 uint64_t *data)
e413e7e1 987{
04bed143 988 struct mv88e6xxx_chip *chip = ds->priv;
f5e2ed02 989 int ret;
f5e2ed02 990
fad09c73 991 mutex_lock(&chip->reg_lock);
f5e2ed02 992
a605a0fe 993 ret = mv88e6xxx_stats_snapshot(chip, port);
f5e2ed02 994 if (ret < 0) {
fad09c73 995 mutex_unlock(&chip->reg_lock);
f5e2ed02
AL
996 return;
997 }
052f947f
AL
998
999 mv88e6xxx_get_stats(chip, port, data);
f5e2ed02 1000
fad09c73 1001 mutex_unlock(&chip->reg_lock);
e413e7e1
AL
1002}
1003
de227387
AL
1004static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip)
1005{
1006 if (chip->info->ops->stats_set_histogram)
1007 return chip->info->ops->stats_set_histogram(chip);
1008
1009 return 0;
1010}
1011
f81ec90f 1012static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
a1ab91f3
GR
1013{
1014 return 32 * sizeof(u16);
1015}
1016
f81ec90f
VD
1017static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
1018 struct ethtool_regs *regs, void *_p)
a1ab91f3 1019{
04bed143 1020 struct mv88e6xxx_chip *chip = ds->priv;
0e7b9925
AL
1021 int err;
1022 u16 reg;
a1ab91f3
GR
1023 u16 *p = _p;
1024 int i;
1025
1026 regs->version = 0;
1027
1028 memset(p, 0xff, 32 * sizeof(u16));
1029
fad09c73 1030 mutex_lock(&chip->reg_lock);
23062513 1031
a1ab91f3 1032 for (i = 0; i < 32; i++) {
a1ab91f3 1033
0e7b9925
AL
1034 err = mv88e6xxx_port_read(chip, port, i, &reg);
1035 if (!err)
1036 p[i] = reg;
a1ab91f3 1037 }
23062513 1038
fad09c73 1039 mutex_unlock(&chip->reg_lock);
a1ab91f3
GR
1040}
1041
fad09c73 1042static int _mv88e6xxx_atu_wait(struct mv88e6xxx_chip *chip)
facd95b2 1043{
a935c052 1044 return mv88e6xxx_g1_wait(chip, GLOBAL_ATU_OP, GLOBAL_ATU_OP_BUSY);
facd95b2
GR
1045}
1046
f81ec90f
VD
1047static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port,
1048 struct ethtool_eee *e)
11b3b45d 1049{
04bed143 1050 struct mv88e6xxx_chip *chip = ds->priv;
9c93829c
VD
1051 u16 reg;
1052 int err;
11b3b45d 1053
fad09c73 1054 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
aadbdb8a
VD
1055 return -EOPNOTSUPP;
1056
fad09c73 1057 mutex_lock(&chip->reg_lock);
2f40c698 1058
9c93829c
VD
1059 err = mv88e6xxx_phy_read(chip, port, 16, &reg);
1060 if (err)
2f40c698 1061 goto out;
11b3b45d
GR
1062
1063 e->eee_enabled = !!(reg & 0x0200);
1064 e->tx_lpi_enabled = !!(reg & 0x0100);
1065
0e7b9925 1066 err = mv88e6xxx_port_read(chip, port, PORT_STATUS, &reg);
9c93829c 1067 if (err)
2f40c698 1068 goto out;
11b3b45d 1069
cca8b133 1070 e->eee_active = !!(reg & PORT_STATUS_EEE);
2f40c698 1071out:
fad09c73 1072 mutex_unlock(&chip->reg_lock);
9c93829c
VD
1073
1074 return err;
11b3b45d
GR
1075}
1076
f81ec90f
VD
1077static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
1078 struct phy_device *phydev, struct ethtool_eee *e)
11b3b45d 1079{
04bed143 1080 struct mv88e6xxx_chip *chip = ds->priv;
9c93829c
VD
1081 u16 reg;
1082 int err;
11b3b45d 1083
fad09c73 1084 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
aadbdb8a
VD
1085 return -EOPNOTSUPP;
1086
fad09c73 1087 mutex_lock(&chip->reg_lock);
11b3b45d 1088
9c93829c
VD
1089 err = mv88e6xxx_phy_read(chip, port, 16, &reg);
1090 if (err)
2f40c698
AL
1091 goto out;
1092
9c93829c 1093 reg &= ~0x0300;
2f40c698
AL
1094 if (e->eee_enabled)
1095 reg |= 0x0200;
1096 if (e->tx_lpi_enabled)
1097 reg |= 0x0100;
1098
9c93829c 1099 err = mv88e6xxx_phy_write(chip, port, 16, reg);
2f40c698 1100out:
fad09c73 1101 mutex_unlock(&chip->reg_lock);
2f40c698 1102
9c93829c 1103 return err;
11b3b45d
GR
1104}
1105
fad09c73 1106static int _mv88e6xxx_atu_cmd(struct mv88e6xxx_chip *chip, u16 fid, u16 cmd)
facd95b2 1107{
a935c052
VD
1108 u16 val;
1109 int err;
facd95b2 1110
6dc10bbc 1111 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_ATU_FID)) {
a935c052
VD
1112 err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_FID, fid);
1113 if (err)
1114 return err;
fad09c73 1115 } else if (mv88e6xxx_num_databases(chip) == 256) {
11ea809f 1116 /* ATU DBNum[7:4] are located in ATU Control 15:12 */
a935c052
VD
1117 err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
1118 if (err)
1119 return err;
11ea809f 1120
a935c052
VD
1121 err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL,
1122 (val & 0xfff) | ((fid << 8) & 0xf000));
1123 if (err)
1124 return err;
11ea809f
VD
1125
1126 /* ATU DBNum[3:0] are located in ATU Operation 3:0 */
1127 cmd |= fid & 0xf;
b426e5f7
VD
1128 }
1129
a935c052
VD
1130 err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_OP, cmd);
1131 if (err)
1132 return err;
facd95b2 1133
fad09c73 1134 return _mv88e6xxx_atu_wait(chip);
facd95b2
GR
1135}
1136
fad09c73 1137static int _mv88e6xxx_atu_data_write(struct mv88e6xxx_chip *chip,
37705b73
VD
1138 struct mv88e6xxx_atu_entry *entry)
1139{
1140 u16 data = entry->state & GLOBAL_ATU_DATA_STATE_MASK;
1141
1142 if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1143 unsigned int mask, shift;
1144
1145 if (entry->trunk) {
1146 data |= GLOBAL_ATU_DATA_TRUNK;
1147 mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
1148 shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
1149 } else {
1150 mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
1151 shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
1152 }
1153
1154 data |= (entry->portv_trunkid << shift) & mask;
1155 }
1156
a935c052 1157 return mv88e6xxx_g1_write(chip, GLOBAL_ATU_DATA, data);
37705b73
VD
1158}
1159
fad09c73 1160static int _mv88e6xxx_atu_flush_move(struct mv88e6xxx_chip *chip,
7fb5e755
VD
1161 struct mv88e6xxx_atu_entry *entry,
1162 bool static_too)
facd95b2 1163{
7fb5e755
VD
1164 int op;
1165 int err;
facd95b2 1166
fad09c73 1167 err = _mv88e6xxx_atu_wait(chip);
7fb5e755
VD
1168 if (err)
1169 return err;
facd95b2 1170
fad09c73 1171 err = _mv88e6xxx_atu_data_write(chip, entry);
7fb5e755
VD
1172 if (err)
1173 return err;
1174
1175 if (entry->fid) {
7fb5e755
VD
1176 op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB :
1177 GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
1178 } else {
1179 op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL :
1180 GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC;
1181 }
1182
fad09c73 1183 return _mv88e6xxx_atu_cmd(chip, entry->fid, op);
7fb5e755
VD
1184}
1185
fad09c73 1186static int _mv88e6xxx_atu_flush(struct mv88e6xxx_chip *chip,
158bc065 1187 u16 fid, bool static_too)
7fb5e755
VD
1188{
1189 struct mv88e6xxx_atu_entry entry = {
1190 .fid = fid,
1191 .state = 0, /* EntryState bits must be 0 */
1192 };
70cc99d1 1193
fad09c73 1194 return _mv88e6xxx_atu_flush_move(chip, &entry, static_too);
7fb5e755
VD
1195}
1196
fad09c73 1197static int _mv88e6xxx_atu_move(struct mv88e6xxx_chip *chip, u16 fid,
158bc065 1198 int from_port, int to_port, bool static_too)
9f4d55d2
VD
1199{
1200 struct mv88e6xxx_atu_entry entry = {
1201 .trunk = false,
1202 .fid = fid,
1203 };
1204
1205 /* EntryState bits must be 0xF */
1206 entry.state = GLOBAL_ATU_DATA_STATE_MASK;
1207
1208 /* ToPort and FromPort are respectively in PortVec bits 7:4 and 3:0 */
1209 entry.portv_trunkid = (to_port & 0x0f) << 4;
1210 entry.portv_trunkid |= from_port & 0x0f;
1211
fad09c73 1212 return _mv88e6xxx_atu_flush_move(chip, &entry, static_too);
9f4d55d2
VD
1213}
1214
fad09c73 1215static int _mv88e6xxx_atu_remove(struct mv88e6xxx_chip *chip, u16 fid,
158bc065 1216 int port, bool static_too)
9f4d55d2
VD
1217{
1218 /* Destination port 0xF means remove the entries */
fad09c73 1219 return _mv88e6xxx_atu_move(chip, fid, port, 0x0f, static_too);
9f4d55d2
VD
1220}
1221
fad09c73 1222static int _mv88e6xxx_port_based_vlan_map(struct mv88e6xxx_chip *chip, int port)
facd95b2 1223{
fad09c73 1224 struct net_device *bridge = chip->ports[port].bridge_dev;
fad09c73 1225 struct dsa_switch *ds = chip->ds;
b7666efe 1226 u16 output_ports = 0;
b7666efe
VD
1227 int i;
1228
1229 /* allow CPU port or DSA link(s) to send frames to every port */
1230 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
5a7921f4 1231 output_ports = ~0;
b7666efe 1232 } else {
370b4ffb 1233 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
b7666efe 1234 /* allow sending frames to every group member */
fad09c73 1235 if (bridge && chip->ports[i].bridge_dev == bridge)
b7666efe
VD
1236 output_ports |= BIT(i);
1237
1238 /* allow sending frames to CPU port and DSA link(s) */
1239 if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
1240 output_ports |= BIT(i);
1241 }
1242 }
1243
1244 /* prevent frames from going back out of the port they came in on */
1245 output_ports &= ~BIT(port);
facd95b2 1246
5a7921f4 1247 return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
facd95b2
GR
1248}
1249
f81ec90f
VD
1250static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
1251 u8 state)
facd95b2 1252{
04bed143 1253 struct mv88e6xxx_chip *chip = ds->priv;
facd95b2 1254 int stp_state;
553eb544 1255 int err;
facd95b2
GR
1256
1257 switch (state) {
1258 case BR_STATE_DISABLED:
cca8b133 1259 stp_state = PORT_CONTROL_STATE_DISABLED;
facd95b2
GR
1260 break;
1261 case BR_STATE_BLOCKING:
1262 case BR_STATE_LISTENING:
cca8b133 1263 stp_state = PORT_CONTROL_STATE_BLOCKING;
facd95b2
GR
1264 break;
1265 case BR_STATE_LEARNING:
cca8b133 1266 stp_state = PORT_CONTROL_STATE_LEARNING;
facd95b2
GR
1267 break;
1268 case BR_STATE_FORWARDING:
1269 default:
cca8b133 1270 stp_state = PORT_CONTROL_STATE_FORWARDING;
facd95b2
GR
1271 break;
1272 }
1273
fad09c73 1274 mutex_lock(&chip->reg_lock);
e28def33 1275 err = mv88e6xxx_port_set_state(chip, port, stp_state);
fad09c73 1276 mutex_unlock(&chip->reg_lock);
553eb544
VD
1277
1278 if (err)
e28def33 1279 netdev_err(ds->ports[port].netdev, "failed to update state\n");
facd95b2
GR
1280}
1281
749efcb8
VD
1282static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1283{
1284 struct mv88e6xxx_chip *chip = ds->priv;
1285 int err;
1286
1287 mutex_lock(&chip->reg_lock);
1288 err = _mv88e6xxx_atu_remove(chip, 0, port, false);
1289 mutex_unlock(&chip->reg_lock);
1290
1291 if (err)
1292 netdev_err(ds->ports[port].netdev, "failed to flush ATU\n");
1293}
1294
fad09c73 1295static int _mv88e6xxx_vtu_wait(struct mv88e6xxx_chip *chip)
6b17e864 1296{
a935c052 1297 return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY);
6b17e864
VD
1298}
1299
fad09c73 1300static int _mv88e6xxx_vtu_cmd(struct mv88e6xxx_chip *chip, u16 op)
6b17e864 1301{
a935c052 1302 int err;
6b17e864 1303
a935c052
VD
1304 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op);
1305 if (err)
1306 return err;
6b17e864 1307
fad09c73 1308 return _mv88e6xxx_vtu_wait(chip);
6b17e864
VD
1309}
1310
fad09c73 1311static int _mv88e6xxx_vtu_stu_flush(struct mv88e6xxx_chip *chip)
6b17e864
VD
1312{
1313 int ret;
1314
fad09c73 1315 ret = _mv88e6xxx_vtu_wait(chip);
6b17e864
VD
1316 if (ret < 0)
1317 return ret;
1318
fad09c73 1319 return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_FLUSH_ALL);
6b17e864
VD
1320}
1321
fad09c73 1322static int _mv88e6xxx_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
b4e47c0f 1323 struct mv88e6xxx_vtu_entry *entry,
b8fee957
VD
1324 unsigned int nibble_offset)
1325{
b8fee957 1326 u16 regs[3];
a935c052 1327 int i, err;
b8fee957
VD
1328
1329 for (i = 0; i < 3; ++i) {
a935c052 1330 u16 *reg = &regs[i];
b8fee957 1331
a935c052
VD
1332 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
1333 if (err)
1334 return err;
b8fee957
VD
1335 }
1336
370b4ffb 1337 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
b8fee957
VD
1338 unsigned int shift = (i % 4) * 4 + nibble_offset;
1339 u16 reg = regs[i / 4];
1340
1341 entry->data[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK;
1342 }
1343
1344 return 0;
1345}
1346
fad09c73 1347static int mv88e6xxx_vtu_data_read(struct mv88e6xxx_chip *chip,
b4e47c0f 1348 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1349{
fad09c73 1350 return _mv88e6xxx_vtu_stu_data_read(chip, entry, 0);
15d7d7d4
VD
1351}
1352
fad09c73 1353static int mv88e6xxx_stu_data_read(struct mv88e6xxx_chip *chip,
b4e47c0f 1354 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1355{
fad09c73 1356 return _mv88e6xxx_vtu_stu_data_read(chip, entry, 2);
15d7d7d4
VD
1357}
1358
fad09c73 1359static int _mv88e6xxx_vtu_stu_data_write(struct mv88e6xxx_chip *chip,
b4e47c0f 1360 struct mv88e6xxx_vtu_entry *entry,
7dad08d7
VD
1361 unsigned int nibble_offset)
1362{
7dad08d7 1363 u16 regs[3] = { 0 };
a935c052 1364 int i, err;
7dad08d7 1365
370b4ffb 1366 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
7dad08d7
VD
1367 unsigned int shift = (i % 4) * 4 + nibble_offset;
1368 u8 data = entry->data[i];
1369
1370 regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift;
1371 }
1372
1373 for (i = 0; i < 3; ++i) {
a935c052
VD
1374 u16 reg = regs[i];
1375
1376 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
1377 if (err)
1378 return err;
7dad08d7
VD
1379 }
1380
1381 return 0;
1382}
1383
fad09c73 1384static int mv88e6xxx_vtu_data_write(struct mv88e6xxx_chip *chip,
b4e47c0f 1385 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1386{
fad09c73 1387 return _mv88e6xxx_vtu_stu_data_write(chip, entry, 0);
15d7d7d4
VD
1388}
1389
fad09c73 1390static int mv88e6xxx_stu_data_write(struct mv88e6xxx_chip *chip,
b4e47c0f 1391 struct mv88e6xxx_vtu_entry *entry)
15d7d7d4 1392{
fad09c73 1393 return _mv88e6xxx_vtu_stu_data_write(chip, entry, 2);
15d7d7d4
VD
1394}
1395
fad09c73 1396static int _mv88e6xxx_vtu_vid_write(struct mv88e6xxx_chip *chip, u16 vid)
36d04ba1 1397{
a935c052
VD
1398 return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID,
1399 vid & GLOBAL_VTU_VID_MASK);
36d04ba1
VD
1400}
1401
fad09c73 1402static int _mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
b4e47c0f 1403 struct mv88e6xxx_vtu_entry *entry)
b8fee957 1404{
b4e47c0f 1405 struct mv88e6xxx_vtu_entry next = { 0 };
a935c052
VD
1406 u16 val;
1407 int err;
b8fee957 1408
a935c052
VD
1409 err = _mv88e6xxx_vtu_wait(chip);
1410 if (err)
1411 return err;
b8fee957 1412
a935c052
VD
1413 err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
1414 if (err)
1415 return err;
b8fee957 1416
a935c052
VD
1417 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
1418 if (err)
1419 return err;
b8fee957 1420
a935c052
VD
1421 next.vid = val & GLOBAL_VTU_VID_MASK;
1422 next.valid = !!(val & GLOBAL_VTU_VID_VALID);
b8fee957
VD
1423
1424 if (next.valid) {
a935c052
VD
1425 err = mv88e6xxx_vtu_data_read(chip, &next);
1426 if (err)
1427 return err;
b8fee957 1428
6dc10bbc 1429 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
a935c052
VD
1430 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val);
1431 if (err)
1432 return err;
b8fee957 1433
a935c052 1434 next.fid = val & GLOBAL_VTU_FID_MASK;
fad09c73 1435 } else if (mv88e6xxx_num_databases(chip) == 256) {
11ea809f
VD
1436 /* VTU DBNum[7:4] are located in VTU Operation 11:8, and
1437 * VTU DBNum[3:0] are located in VTU Operation 3:0
1438 */
a935c052
VD
1439 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val);
1440 if (err)
1441 return err;
11ea809f 1442
a935c052
VD
1443 next.fid = (val & 0xf00) >> 4;
1444 next.fid |= val & 0xf;
2e7bd5ef 1445 }
b8fee957 1446
fad09c73 1447 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
a935c052
VD
1448 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
1449 if (err)
1450 return err;
b8fee957 1451
a935c052 1452 next.sid = val & GLOBAL_VTU_SID_MASK;
b8fee957
VD
1453 }
1454 }
1455
1456 *entry = next;
1457 return 0;
1458}
1459
f81ec90f
VD
1460static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
1461 struct switchdev_obj_port_vlan *vlan,
1462 int (*cb)(struct switchdev_obj *obj))
ceff5eff 1463{
04bed143 1464 struct mv88e6xxx_chip *chip = ds->priv;
b4e47c0f 1465 struct mv88e6xxx_vtu_entry next;
ceff5eff
VD
1466 u16 pvid;
1467 int err;
1468
fad09c73 1469 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1470 return -EOPNOTSUPP;
1471
fad09c73 1472 mutex_lock(&chip->reg_lock);
ceff5eff 1473
77064f37 1474 err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
ceff5eff
VD
1475 if (err)
1476 goto unlock;
1477
fad09c73 1478 err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
ceff5eff
VD
1479 if (err)
1480 goto unlock;
1481
1482 do {
fad09c73 1483 err = _mv88e6xxx_vtu_getnext(chip, &next);
ceff5eff
VD
1484 if (err)
1485 break;
1486
1487 if (!next.valid)
1488 break;
1489
1490 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1491 continue;
1492
1493 /* reinit and dump this VLAN obj */
57d32310
VD
1494 vlan->vid_begin = next.vid;
1495 vlan->vid_end = next.vid;
ceff5eff
VD
1496 vlan->flags = 0;
1497
1498 if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
1499 vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
1500
1501 if (next.vid == pvid)
1502 vlan->flags |= BRIDGE_VLAN_INFO_PVID;
1503
1504 err = cb(&vlan->obj);
1505 if (err)
1506 break;
1507 } while (next.vid < GLOBAL_VTU_VID_MASK);
1508
1509unlock:
fad09c73 1510 mutex_unlock(&chip->reg_lock);
ceff5eff
VD
1511
1512 return err;
1513}
1514
fad09c73 1515static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
b4e47c0f 1516 struct mv88e6xxx_vtu_entry *entry)
7dad08d7 1517{
11ea809f 1518 u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE;
7dad08d7 1519 u16 reg = 0;
a935c052 1520 int err;
7dad08d7 1521
a935c052
VD
1522 err = _mv88e6xxx_vtu_wait(chip);
1523 if (err)
1524 return err;
7dad08d7
VD
1525
1526 if (!entry->valid)
1527 goto loadpurge;
1528
1529 /* Write port member tags */
a935c052
VD
1530 err = mv88e6xxx_vtu_data_write(chip, entry);
1531 if (err)
1532 return err;
7dad08d7 1533
fad09c73 1534 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
7dad08d7 1535 reg = entry->sid & GLOBAL_VTU_SID_MASK;
a935c052
VD
1536 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
1537 if (err)
1538 return err;
b426e5f7 1539 }
7dad08d7 1540
6dc10bbc 1541 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
7dad08d7 1542 reg = entry->fid & GLOBAL_VTU_FID_MASK;
a935c052
VD
1543 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, reg);
1544 if (err)
1545 return err;
fad09c73 1546 } else if (mv88e6xxx_num_databases(chip) == 256) {
11ea809f
VD
1547 /* VTU DBNum[7:4] are located in VTU Operation 11:8, and
1548 * VTU DBNum[3:0] are located in VTU Operation 3:0
1549 */
1550 op |= (entry->fid & 0xf0) << 8;
1551 op |= entry->fid & 0xf;
7dad08d7
VD
1552 }
1553
1554 reg = GLOBAL_VTU_VID_VALID;
1555loadpurge:
1556 reg |= entry->vid & GLOBAL_VTU_VID_MASK;
a935c052
VD
1557 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
1558 if (err)
1559 return err;
7dad08d7 1560
fad09c73 1561 return _mv88e6xxx_vtu_cmd(chip, op);
7dad08d7
VD
1562}
1563
fad09c73 1564static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip *chip, u8 sid,
b4e47c0f 1565 struct mv88e6xxx_vtu_entry *entry)
0d3b33e6 1566{
b4e47c0f 1567 struct mv88e6xxx_vtu_entry next = { 0 };
a935c052
VD
1568 u16 val;
1569 int err;
0d3b33e6 1570
a935c052
VD
1571 err = _mv88e6xxx_vtu_wait(chip);
1572 if (err)
1573 return err;
0d3b33e6 1574
a935c052
VD
1575 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID,
1576 sid & GLOBAL_VTU_SID_MASK);
1577 if (err)
1578 return err;
0d3b33e6 1579
a935c052
VD
1580 err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
1581 if (err)
1582 return err;
0d3b33e6 1583
a935c052
VD
1584 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
1585 if (err)
1586 return err;
0d3b33e6 1587
a935c052 1588 next.sid = val & GLOBAL_VTU_SID_MASK;
0d3b33e6 1589
a935c052
VD
1590 err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
1591 if (err)
1592 return err;
0d3b33e6 1593
a935c052 1594 next.valid = !!(val & GLOBAL_VTU_VID_VALID);
0d3b33e6
VD
1595
1596 if (next.valid) {
a935c052
VD
1597 err = mv88e6xxx_stu_data_read(chip, &next);
1598 if (err)
1599 return err;
0d3b33e6
VD
1600 }
1601
1602 *entry = next;
1603 return 0;
1604}
1605
fad09c73 1606static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip,
b4e47c0f 1607 struct mv88e6xxx_vtu_entry *entry)
0d3b33e6
VD
1608{
1609 u16 reg = 0;
a935c052 1610 int err;
0d3b33e6 1611
a935c052
VD
1612 err = _mv88e6xxx_vtu_wait(chip);
1613 if (err)
1614 return err;
0d3b33e6
VD
1615
1616 if (!entry->valid)
1617 goto loadpurge;
1618
1619 /* Write port states */
a935c052
VD
1620 err = mv88e6xxx_stu_data_write(chip, entry);
1621 if (err)
1622 return err;
0d3b33e6
VD
1623
1624 reg = GLOBAL_VTU_VID_VALID;
1625loadpurge:
a935c052
VD
1626 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
1627 if (err)
1628 return err;
0d3b33e6
VD
1629
1630 reg = entry->sid & GLOBAL_VTU_SID_MASK;
a935c052
VD
1631 err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
1632 if (err)
1633 return err;
0d3b33e6 1634
fad09c73 1635 return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
0d3b33e6
VD
1636}
1637
fad09c73 1638static int _mv88e6xxx_fid_new(struct mv88e6xxx_chip *chip, u16 *fid)
3285f9e8
VD
1639{
1640 DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
b4e47c0f 1641 struct mv88e6xxx_vtu_entry vlan;
2db9ce1f 1642 int i, err;
3285f9e8
VD
1643
1644 bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
1645
2db9ce1f 1646 /* Set every FID bit used by the (un)bridged ports */
370b4ffb 1647 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
b4e48c50 1648 err = mv88e6xxx_port_get_fid(chip, i, fid);
2db9ce1f
VD
1649 if (err)
1650 return err;
1651
1652 set_bit(*fid, fid_bitmap);
1653 }
1654
3285f9e8 1655 /* Set every FID bit used by the VLAN entries */
fad09c73 1656 err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
3285f9e8
VD
1657 if (err)
1658 return err;
1659
1660 do {
fad09c73 1661 err = _mv88e6xxx_vtu_getnext(chip, &vlan);
3285f9e8
VD
1662 if (err)
1663 return err;
1664
1665 if (!vlan.valid)
1666 break;
1667
1668 set_bit(vlan.fid, fid_bitmap);
1669 } while (vlan.vid < GLOBAL_VTU_VID_MASK);
1670
1671 /* The reset value 0x000 is used to indicate that multiple address
1672 * databases are not needed. Return the next positive available.
1673 */
1674 *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
fad09c73 1675 if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
3285f9e8
VD
1676 return -ENOSPC;
1677
1678 /* Clear the database */
fad09c73 1679 return _mv88e6xxx_atu_flush(chip, *fid, true);
3285f9e8
VD
1680}
1681
fad09c73 1682static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid,
b4e47c0f 1683 struct mv88e6xxx_vtu_entry *entry)
0d3b33e6 1684{
fad09c73 1685 struct dsa_switch *ds = chip->ds;
b4e47c0f 1686 struct mv88e6xxx_vtu_entry vlan = {
0d3b33e6
VD
1687 .valid = true,
1688 .vid = vid,
1689 };
3285f9e8
VD
1690 int i, err;
1691
fad09c73 1692 err = _mv88e6xxx_fid_new(chip, &vlan.fid);
3285f9e8
VD
1693 if (err)
1694 return err;
0d3b33e6 1695
3d131f07 1696 /* exclude all ports except the CPU and DSA ports */
370b4ffb 1697 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
3d131f07
VD
1698 vlan.data[i] = dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)
1699 ? GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED
1700 : GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
0d3b33e6 1701
fad09c73
VD
1702 if (mv88e6xxx_6097_family(chip) || mv88e6xxx_6165_family(chip) ||
1703 mv88e6xxx_6351_family(chip) || mv88e6xxx_6352_family(chip)) {
b4e47c0f 1704 struct mv88e6xxx_vtu_entry vstp;
0d3b33e6
VD
1705
1706 /* Adding a VTU entry requires a valid STU entry. As VSTP is not
1707 * implemented, only one STU entry is needed to cover all VTU
1708 * entries. Thus, validate the SID 0.
1709 */
1710 vlan.sid = 0;
fad09c73 1711 err = _mv88e6xxx_stu_getnext(chip, GLOBAL_VTU_SID_MASK, &vstp);
0d3b33e6
VD
1712 if (err)
1713 return err;
1714
1715 if (vstp.sid != vlan.sid || !vstp.valid) {
1716 memset(&vstp, 0, sizeof(vstp));
1717 vstp.valid = true;
1718 vstp.sid = vlan.sid;
1719
fad09c73 1720 err = _mv88e6xxx_stu_loadpurge(chip, &vstp);
0d3b33e6
VD
1721 if (err)
1722 return err;
1723 }
0d3b33e6
VD
1724 }
1725
1726 *entry = vlan;
1727 return 0;
1728}
1729
fad09c73 1730static int _mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
b4e47c0f 1731 struct mv88e6xxx_vtu_entry *entry, bool creat)
2fb5ef09
VD
1732{
1733 int err;
1734
1735 if (!vid)
1736 return -EINVAL;
1737
fad09c73 1738 err = _mv88e6xxx_vtu_vid_write(chip, vid - 1);
2fb5ef09
VD
1739 if (err)
1740 return err;
1741
fad09c73 1742 err = _mv88e6xxx_vtu_getnext(chip, entry);
2fb5ef09
VD
1743 if (err)
1744 return err;
1745
1746 if (entry->vid != vid || !entry->valid) {
1747 if (!creat)
1748 return -EOPNOTSUPP;
1749 /* -ENOENT would've been more appropriate, but switchdev expects
1750 * -EOPNOTSUPP to inform bridge about an eventual software VLAN.
1751 */
1752
fad09c73 1753 err = _mv88e6xxx_vtu_new(chip, vid, entry);
2fb5ef09
VD
1754 }
1755
1756 return err;
1757}
1758
da9c359e
VD
1759static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1760 u16 vid_begin, u16 vid_end)
1761{
04bed143 1762 struct mv88e6xxx_chip *chip = ds->priv;
b4e47c0f 1763 struct mv88e6xxx_vtu_entry vlan;
da9c359e
VD
1764 int i, err;
1765
1766 if (!vid_begin)
1767 return -EOPNOTSUPP;
1768
fad09c73 1769 mutex_lock(&chip->reg_lock);
da9c359e 1770
fad09c73 1771 err = _mv88e6xxx_vtu_vid_write(chip, vid_begin - 1);
da9c359e
VD
1772 if (err)
1773 goto unlock;
1774
1775 do {
fad09c73 1776 err = _mv88e6xxx_vtu_getnext(chip, &vlan);
da9c359e
VD
1777 if (err)
1778 goto unlock;
1779
1780 if (!vlan.valid)
1781 break;
1782
1783 if (vlan.vid > vid_end)
1784 break;
1785
370b4ffb 1786 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
da9c359e
VD
1787 if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
1788 continue;
1789
66e2809d
AL
1790 if (!ds->ports[port].netdev)
1791 continue;
1792
da9c359e
VD
1793 if (vlan.data[i] ==
1794 GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1795 continue;
1796
fad09c73
VD
1797 if (chip->ports[i].bridge_dev ==
1798 chip->ports[port].bridge_dev)
da9c359e
VD
1799 break; /* same bridge, check next VLAN */
1800
66e2809d
AL
1801 if (!chip->ports[i].bridge_dev)
1802 continue;
1803
c8b09808 1804 netdev_warn(ds->ports[port].netdev,
da9c359e
VD
1805 "hardware VLAN %d already used by %s\n",
1806 vlan.vid,
fad09c73 1807 netdev_name(chip->ports[i].bridge_dev));
da9c359e
VD
1808 err = -EOPNOTSUPP;
1809 goto unlock;
1810 }
1811 } while (vlan.vid < vid_end);
1812
1813unlock:
fad09c73 1814 mutex_unlock(&chip->reg_lock);
da9c359e
VD
1815
1816 return err;
1817}
1818
f81ec90f
VD
1819static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1820 bool vlan_filtering)
214cdb99 1821{
04bed143 1822 struct mv88e6xxx_chip *chip = ds->priv;
385a0995 1823 u16 mode = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE :
214cdb99 1824 PORT_CONTROL_2_8021Q_DISABLED;
0e7b9925 1825 int err;
214cdb99 1826
fad09c73 1827 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1828 return -EOPNOTSUPP;
1829
fad09c73 1830 mutex_lock(&chip->reg_lock);
385a0995 1831 err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
fad09c73 1832 mutex_unlock(&chip->reg_lock);
214cdb99 1833
0e7b9925 1834 return err;
214cdb99
VD
1835}
1836
57d32310
VD
1837static int
1838mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
1839 const struct switchdev_obj_port_vlan *vlan,
1840 struct switchdev_trans *trans)
76e398a6 1841{
04bed143 1842 struct mv88e6xxx_chip *chip = ds->priv;
da9c359e
VD
1843 int err;
1844
fad09c73 1845 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1846 return -EOPNOTSUPP;
1847
da9c359e
VD
1848 /* If the requested port doesn't belong to the same bridge as the VLAN
1849 * members, do not support it (yet) and fallback to software VLAN.
1850 */
1851 err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
1852 vlan->vid_end);
1853 if (err)
1854 return err;
1855
76e398a6
VD
1856 /* We don't need any dynamic resource from the kernel (yet),
1857 * so skip the prepare phase.
1858 */
1859 return 0;
1860}
1861
fad09c73 1862static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
158bc065 1863 u16 vid, bool untagged)
0d3b33e6 1864{
b4e47c0f 1865 struct mv88e6xxx_vtu_entry vlan;
0d3b33e6
VD
1866 int err;
1867
fad09c73 1868 err = _mv88e6xxx_vtu_get(chip, vid, &vlan, true);
0d3b33e6 1869 if (err)
76e398a6 1870 return err;
0d3b33e6 1871
0d3b33e6
VD
1872 vlan.data[port] = untagged ?
1873 GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
1874 GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
1875
fad09c73 1876 return _mv88e6xxx_vtu_loadpurge(chip, &vlan);
76e398a6
VD
1877}
1878
f81ec90f
VD
1879static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
1880 const struct switchdev_obj_port_vlan *vlan,
1881 struct switchdev_trans *trans)
76e398a6 1882{
04bed143 1883 struct mv88e6xxx_chip *chip = ds->priv;
76e398a6
VD
1884 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1885 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1886 u16 vid;
76e398a6 1887
fad09c73 1888 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1889 return;
1890
fad09c73 1891 mutex_lock(&chip->reg_lock);
76e398a6 1892
4d5770b3 1893 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
fad09c73 1894 if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
c8b09808
AL
1895 netdev_err(ds->ports[port].netdev,
1896 "failed to add VLAN %d%c\n",
4d5770b3 1897 vid, untagged ? 'u' : 't');
76e398a6 1898
77064f37 1899 if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
c8b09808 1900 netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n",
4d5770b3 1901 vlan->vid_end);
0d3b33e6 1902
fad09c73 1903 mutex_unlock(&chip->reg_lock);
0d3b33e6
VD
1904}
1905
fad09c73 1906static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
158bc065 1907 int port, u16 vid)
7dad08d7 1908{
fad09c73 1909 struct dsa_switch *ds = chip->ds;
b4e47c0f 1910 struct mv88e6xxx_vtu_entry vlan;
7dad08d7
VD
1911 int i, err;
1912
fad09c73 1913 err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
7dad08d7 1914 if (err)
76e398a6 1915 return err;
7dad08d7 1916
2fb5ef09
VD
1917 /* Tell switchdev if this VLAN is handled in software */
1918 if (vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
3c06f08b 1919 return -EOPNOTSUPP;
7dad08d7
VD
1920
1921 vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1922
1923 /* keep the VLAN unless all ports are excluded */
f02bdffc 1924 vlan.valid = false;
370b4ffb 1925 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
3d131f07 1926 if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
7dad08d7
VD
1927 continue;
1928
1929 if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
f02bdffc 1930 vlan.valid = true;
7dad08d7
VD
1931 break;
1932 }
1933 }
1934
fad09c73 1935 err = _mv88e6xxx_vtu_loadpurge(chip, &vlan);
76e398a6
VD
1936 if (err)
1937 return err;
1938
fad09c73 1939 return _mv88e6xxx_atu_remove(chip, vlan.fid, port, false);
76e398a6
VD
1940}
1941
f81ec90f
VD
1942static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
1943 const struct switchdev_obj_port_vlan *vlan)
76e398a6 1944{
04bed143 1945 struct mv88e6xxx_chip *chip = ds->priv;
76e398a6
VD
1946 u16 pvid, vid;
1947 int err = 0;
1948
fad09c73 1949 if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
54d77b5b
VD
1950 return -EOPNOTSUPP;
1951
fad09c73 1952 mutex_lock(&chip->reg_lock);
76e398a6 1953
77064f37 1954 err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
7dad08d7
VD
1955 if (err)
1956 goto unlock;
1957
76e398a6 1958 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
fad09c73 1959 err = _mv88e6xxx_port_vlan_del(chip, port, vid);
76e398a6
VD
1960 if (err)
1961 goto unlock;
1962
1963 if (vid == pvid) {
77064f37 1964 err = mv88e6xxx_port_set_pvid(chip, port, 0);
76e398a6
VD
1965 if (err)
1966 goto unlock;
1967 }
1968 }
1969
7dad08d7 1970unlock:
fad09c73 1971 mutex_unlock(&chip->reg_lock);
7dad08d7
VD
1972
1973 return err;
1974}
1975
fad09c73 1976static int _mv88e6xxx_atu_mac_write(struct mv88e6xxx_chip *chip,
c5723ac5 1977 const unsigned char *addr)
defb05b9 1978{
a935c052 1979 int i, err;
defb05b9
GR
1980
1981 for (i = 0; i < 3; i++) {
a935c052
VD
1982 err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_MAC_01 + i,
1983 (addr[i * 2] << 8) | addr[i * 2 + 1]);
1984 if (err)
1985 return err;
defb05b9
GR
1986 }
1987
1988 return 0;
1989}
1990
fad09c73 1991static int _mv88e6xxx_atu_mac_read(struct mv88e6xxx_chip *chip,
158bc065 1992 unsigned char *addr)
defb05b9 1993{
a935c052
VD
1994 u16 val;
1995 int i, err;
defb05b9
GR
1996
1997 for (i = 0; i < 3; i++) {
a935c052
VD
1998 err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_MAC_01 + i, &val);
1999 if (err)
2000 return err;
2001
2002 addr[i * 2] = val >> 8;
2003 addr[i * 2 + 1] = val & 0xff;
defb05b9
GR
2004 }
2005
2006 return 0;
2007}
2008
fad09c73 2009static int _mv88e6xxx_atu_load(struct mv88e6xxx_chip *chip,
fd231c82 2010 struct mv88e6xxx_atu_entry *entry)
defb05b9 2011{
6630e236
VD
2012 int ret;
2013
fad09c73 2014 ret = _mv88e6xxx_atu_wait(chip);
defb05b9
GR
2015 if (ret < 0)
2016 return ret;
2017
fad09c73 2018 ret = _mv88e6xxx_atu_mac_write(chip, entry->mac);
defb05b9
GR
2019 if (ret < 0)
2020 return ret;
2021
fad09c73 2022 ret = _mv88e6xxx_atu_data_write(chip, entry);
fd231c82 2023 if (ret < 0)
87820510
VD
2024 return ret;
2025
fad09c73 2026 return _mv88e6xxx_atu_cmd(chip, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
fd231c82 2027}
87820510 2028
88472939
VD
2029static int _mv88e6xxx_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
2030 struct mv88e6xxx_atu_entry *entry);
2031
2032static int mv88e6xxx_atu_get(struct mv88e6xxx_chip *chip, int fid,
2033 const u8 *addr, struct mv88e6xxx_atu_entry *entry)
2034{
2035 struct mv88e6xxx_atu_entry next;
2036 int err;
2037
59527581
AL
2038 memcpy(next.mac, addr, ETH_ALEN);
2039 eth_addr_dec(next.mac);
88472939
VD
2040
2041 err = _mv88e6xxx_atu_mac_write(chip, next.mac);
2042 if (err)
2043 return err;
2044
2045 do {
2046 err = _mv88e6xxx_atu_getnext(chip, fid, &next);
2047 if (err)
2048 return err;
2049
2050 if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
2051 break;
2052
2053 if (ether_addr_equal(next.mac, addr)) {
2054 *entry = next;
2055 return 0;
2056 }
59527581 2057 } while (ether_addr_greater(addr, next.mac));
88472939
VD
2058
2059 memset(entry, 0, sizeof(*entry));
2060 entry->fid = fid;
2061 ether_addr_copy(entry->mac, addr);
2062
2063 return 0;
2064}
2065
83dabd1f
VD
2066static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
2067 const unsigned char *addr, u16 vid,
2068 u8 state)
fd231c82 2069{
b4e47c0f 2070 struct mv88e6xxx_vtu_entry vlan;
88472939 2071 struct mv88e6xxx_atu_entry entry;
3285f9e8
VD
2072 int err;
2073
2db9ce1f
VD
2074 /* Null VLAN ID corresponds to the port private database */
2075 if (vid == 0)
b4e48c50 2076 err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
2db9ce1f 2077 else
fad09c73 2078 err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
3285f9e8
VD
2079 if (err)
2080 return err;
fd231c82 2081
88472939
VD
2082 err = mv88e6xxx_atu_get(chip, vlan.fid, addr, &entry);
2083 if (err)
2084 return err;
2085
2086 /* Purge the ATU entry only if no port is using it anymore */
2087 if (state == GLOBAL_ATU_DATA_STATE_UNUSED) {
2088 entry.portv_trunkid &= ~BIT(port);
2089 if (!entry.portv_trunkid)
2090 entry.state = GLOBAL_ATU_DATA_STATE_UNUSED;
2091 } else {
2092 entry.portv_trunkid |= BIT(port);
2093 entry.state = state;
fd231c82
VD
2094 }
2095
fad09c73 2096 return _mv88e6xxx_atu_load(chip, &entry);
87820510
VD
2097}
2098
f81ec90f
VD
2099static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
2100 const struct switchdev_obj_port_fdb *fdb,
2101 struct switchdev_trans *trans)
146a3206
VD
2102{
2103 /* We don't need any dynamic resource from the kernel (yet),
2104 * so skip the prepare phase.
2105 */
2106 return 0;
2107}
2108
f81ec90f
VD
2109static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
2110 const struct switchdev_obj_port_fdb *fdb,
2111 struct switchdev_trans *trans)
87820510 2112{
04bed143 2113 struct mv88e6xxx_chip *chip = ds->priv;
87820510 2114
fad09c73 2115 mutex_lock(&chip->reg_lock);
83dabd1f
VD
2116 if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid,
2117 GLOBAL_ATU_DATA_STATE_UC_STATIC))
2118 netdev_err(ds->ports[port].netdev, "failed to load unicast MAC address\n");
fad09c73 2119 mutex_unlock(&chip->reg_lock);
87820510
VD
2120}
2121
f81ec90f
VD
2122static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
2123 const struct switchdev_obj_port_fdb *fdb)
87820510 2124{
04bed143 2125 struct mv88e6xxx_chip *chip = ds->priv;
83dabd1f 2126 int err;
87820510 2127
fad09c73 2128 mutex_lock(&chip->reg_lock);
83dabd1f
VD
2129 err = mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid,
2130 GLOBAL_ATU_DATA_STATE_UNUSED);
fad09c73 2131 mutex_unlock(&chip->reg_lock);
87820510 2132
83dabd1f 2133 return err;
87820510
VD
2134}
2135
fad09c73 2136static int _mv88e6xxx_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
1d194046 2137 struct mv88e6xxx_atu_entry *entry)
6630e236 2138{
1d194046 2139 struct mv88e6xxx_atu_entry next = { 0 };
a935c052
VD
2140 u16 val;
2141 int err;
1d194046
VD
2142
2143 next.fid = fid;
defb05b9 2144
a935c052
VD
2145 err = _mv88e6xxx_atu_wait(chip);
2146 if (err)
2147 return err;
6630e236 2148
a935c052
VD
2149 err = _mv88e6xxx_atu_cmd(chip, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
2150 if (err)
2151 return err;
6630e236 2152
a935c052
VD
2153 err = _mv88e6xxx_atu_mac_read(chip, next.mac);
2154 if (err)
2155 return err;
6630e236 2156
a935c052
VD
2157 err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_DATA, &val);
2158 if (err)
2159 return err;
6630e236 2160
a935c052 2161 next.state = val & GLOBAL_ATU_DATA_STATE_MASK;
1d194046
VD
2162 if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) {
2163 unsigned int mask, shift;
2164
a935c052 2165 if (val & GLOBAL_ATU_DATA_TRUNK) {
1d194046
VD
2166 next.trunk = true;
2167 mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
2168 shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
2169 } else {
2170 next.trunk = false;
2171 mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
2172 shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
2173 }
2174
a935c052 2175 next.portv_trunkid = (val & mask) >> shift;
1d194046 2176 }
cdf09697 2177
1d194046 2178 *entry = next;
cdf09697
DM
2179 return 0;
2180}
2181
83dabd1f
VD
2182static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
2183 u16 fid, u16 vid, int port,
2184 struct switchdev_obj *obj,
2185 int (*cb)(struct switchdev_obj *obj))
74b6ba0d
VD
2186{
2187 struct mv88e6xxx_atu_entry addr = {
2188 .mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
2189 };
2190 int err;
2191
fad09c73 2192 err = _mv88e6xxx_atu_mac_write(chip, addr.mac);
74b6ba0d
VD
2193 if (err)
2194 return err;
2195
2196 do {
fad09c73 2197 err = _mv88e6xxx_atu_getnext(chip, fid, &addr);
74b6ba0d 2198 if (err)
83dabd1f 2199 return err;
74b6ba0d
VD
2200
2201 if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
2202 break;
2203
83dabd1f
VD
2204 if (addr.trunk || (addr.portv_trunkid & BIT(port)) == 0)
2205 continue;
2206
2207 if (obj->id == SWITCHDEV_OBJ_ID_PORT_FDB) {
2208 struct switchdev_obj_port_fdb *fdb;
74b6ba0d 2209
83dabd1f
VD
2210 if (!is_unicast_ether_addr(addr.mac))
2211 continue;
2212
2213 fdb = SWITCHDEV_OBJ_PORT_FDB(obj);
74b6ba0d
VD
2214 fdb->vid = vid;
2215 ether_addr_copy(fdb->addr, addr.mac);
83dabd1f
VD
2216 if (addr.state == GLOBAL_ATU_DATA_STATE_UC_STATIC)
2217 fdb->ndm_state = NUD_NOARP;
2218 else
2219 fdb->ndm_state = NUD_REACHABLE;
7df8fbdd
VD
2220 } else if (obj->id == SWITCHDEV_OBJ_ID_PORT_MDB) {
2221 struct switchdev_obj_port_mdb *mdb;
2222
2223 if (!is_multicast_ether_addr(addr.mac))
2224 continue;
2225
2226 mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
2227 mdb->vid = vid;
2228 ether_addr_copy(mdb->addr, addr.mac);
83dabd1f
VD
2229 } else {
2230 return -EOPNOTSUPP;
74b6ba0d 2231 }
83dabd1f
VD
2232
2233 err = cb(obj);
2234 if (err)
2235 return err;
74b6ba0d
VD
2236 } while (!is_broadcast_ether_addr(addr.mac));
2237
2238 return err;
2239}
2240
83dabd1f
VD
2241static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
2242 struct switchdev_obj *obj,
2243 int (*cb)(struct switchdev_obj *obj))
f33475bd 2244{
b4e47c0f 2245 struct mv88e6xxx_vtu_entry vlan = {
f33475bd
VD
2246 .vid = GLOBAL_VTU_VID_MASK, /* all ones */
2247 };
2db9ce1f 2248 u16 fid;
f33475bd
VD
2249 int err;
2250
2db9ce1f 2251 /* Dump port's default Filtering Information Database (VLAN ID 0) */
b4e48c50 2252 err = mv88e6xxx_port_get_fid(chip, port, &fid);
2db9ce1f 2253 if (err)
83dabd1f 2254 return err;
2db9ce1f 2255
83dabd1f 2256 err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, obj, cb);
2db9ce1f 2257 if (err)
83dabd1f 2258 return err;
2db9ce1f 2259
74b6ba0d 2260 /* Dump VLANs' Filtering Information Databases */
fad09c73 2261 err = _mv88e6xxx_vtu_vid_write(chip, vlan.vid);
f33475bd 2262 if (err)
83dabd1f 2263 return err;
f33475bd
VD
2264
2265 do {
fad09c73 2266 err = _mv88e6xxx_vtu_getnext(chip, &vlan);
f33475bd 2267 if (err)
83dabd1f 2268 return err;
f33475bd
VD
2269
2270 if (!vlan.valid)
2271 break;
2272
83dabd1f
VD
2273 err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
2274 obj, cb);
f33475bd 2275 if (err)
83dabd1f 2276 return err;
f33475bd
VD
2277 } while (vlan.vid < GLOBAL_VTU_VID_MASK);
2278
83dabd1f
VD
2279 return err;
2280}
2281
2282static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
2283 struct switchdev_obj_port_fdb *fdb,
2284 int (*cb)(struct switchdev_obj *obj))
2285{
04bed143 2286 struct mv88e6xxx_chip *chip = ds->priv;
83dabd1f
VD
2287 int err;
2288
2289 mutex_lock(&chip->reg_lock);
2290 err = mv88e6xxx_port_db_dump(chip, port, &fdb->obj, cb);
fad09c73 2291 mutex_unlock(&chip->reg_lock);
f33475bd
VD
2292
2293 return err;
2294}
2295
f81ec90f
VD
2296static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2297 struct net_device *bridge)
e79a8bcb 2298{
04bed143 2299 struct mv88e6xxx_chip *chip = ds->priv;
1d9619d5 2300 int i, err = 0;
466dfa07 2301
fad09c73 2302 mutex_lock(&chip->reg_lock);
466dfa07 2303
b7666efe 2304 /* Assign the bridge and remap each port's VLANTable */
fad09c73 2305 chip->ports[port].bridge_dev = bridge;
b7666efe 2306
370b4ffb 2307 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
fad09c73
VD
2308 if (chip->ports[i].bridge_dev == bridge) {
2309 err = _mv88e6xxx_port_based_vlan_map(chip, i);
b7666efe
VD
2310 if (err)
2311 break;
2312 }
2313 }
2314
fad09c73 2315 mutex_unlock(&chip->reg_lock);
a6692754 2316
466dfa07 2317 return err;
e79a8bcb
VD
2318}
2319
f81ec90f 2320static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
66d9cd0f 2321{
04bed143 2322 struct mv88e6xxx_chip *chip = ds->priv;
fad09c73 2323 struct net_device *bridge = chip->ports[port].bridge_dev;
16bfa702 2324 int i;
466dfa07 2325
fad09c73 2326 mutex_lock(&chip->reg_lock);
466dfa07 2327
b7666efe 2328 /* Unassign the bridge and remap each port's VLANTable */
fad09c73 2329 chip->ports[port].bridge_dev = NULL;
b7666efe 2330
370b4ffb 2331 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
fad09c73
VD
2332 if (i == port || chip->ports[i].bridge_dev == bridge)
2333 if (_mv88e6xxx_port_based_vlan_map(chip, i))
c8b09808
AL
2334 netdev_warn(ds->ports[i].netdev,
2335 "failed to remap\n");
b7666efe 2336
fad09c73 2337 mutex_unlock(&chip->reg_lock);
66d9cd0f
VD
2338}
2339
17e708ba
VD
2340static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
2341{
2342 if (chip->info->ops->reset)
2343 return chip->info->ops->reset(chip);
2344
2345 return 0;
2346}
2347
309eca6d
VD
2348static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
2349{
2350 struct gpio_desc *gpiod = chip->reset;
2351
2352 /* If there is a GPIO connected to the reset pin, toggle it */
2353 if (gpiod) {
2354 gpiod_set_value_cansleep(gpiod, 1);
2355 usleep_range(10000, 20000);
2356 gpiod_set_value_cansleep(gpiod, 0);
2357 usleep_range(10000, 20000);
2358 }
2359}
2360
4ac4b5a6 2361static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
552238b5 2362{
4ac4b5a6 2363 int i, err;
552238b5 2364
4ac4b5a6 2365 /* Set all ports to the Disabled state */
370b4ffb 2366 for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
e28def33
VD
2367 err = mv88e6xxx_port_set_state(chip, i,
2368 PORT_CONTROL_STATE_DISABLED);
0e7b9925
AL
2369 if (err)
2370 return err;
552238b5
VD
2371 }
2372
4ac4b5a6
VD
2373 /* Wait for transmit queues to drain,
2374 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
2375 */
552238b5
VD
2376 usleep_range(2000, 4000);
2377
4ac4b5a6
VD
2378 return 0;
2379}
2380
2381static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
2382{
4ac4b5a6
VD
2383 int err;
2384
2385 err = mv88e6xxx_disable_ports(chip);
2386 if (err)
2387 return err;
2388
309eca6d 2389 mv88e6xxx_hardware_reset(chip);
552238b5 2390
17e708ba 2391 return mv88e6xxx_software_reset(chip);
552238b5
VD
2392}
2393
09cb7dfd 2394static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
13a7ebb3 2395{
09cb7dfd
VD
2396 u16 val;
2397 int err;
13a7ebb3 2398
09cb7dfd
VD
2399 /* Clear Power Down bit */
2400 err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val);
2401 if (err)
2402 return err;
13a7ebb3 2403
09cb7dfd
VD
2404 if (val & BMCR_PDOWN) {
2405 val &= ~BMCR_PDOWN;
2406 err = mv88e6xxx_serdes_write(chip, MII_BMCR, val);
13a7ebb3
PU
2407 }
2408
09cb7dfd 2409 return err;
13a7ebb3
PU
2410}
2411
56995cbc
AL
2412static int mv88e6xxx_setup_port_dsa(struct mv88e6xxx_chip *chip, int port,
2413 int upstream_port)
2414{
2415 int err;
2416
2417 err = chip->info->ops->port_set_frame_mode(
2418 chip, port, MV88E6XXX_FRAME_MODE_DSA);
2419 if (err)
2420 return err;
2421
2422 return chip->info->ops->port_set_egress_unknowns(
2423 chip, port, port == upstream_port);
2424}
2425
2426static int mv88e6xxx_setup_port_cpu(struct mv88e6xxx_chip *chip, int port)
2427{
2428 int err;
2429
2430 switch (chip->info->tag_protocol) {
2431 case DSA_TAG_PROTO_EDSA:
2432 err = chip->info->ops->port_set_frame_mode(
2433 chip, port, MV88E6XXX_FRAME_MODE_ETHERTYPE);
2434 if (err)
2435 return err;
2436
2437 err = mv88e6xxx_port_set_egress_mode(
2438 chip, port, PORT_CONTROL_EGRESS_ADD_TAG);
2439 if (err)
2440 return err;
2441
2442 if (chip->info->ops->port_set_ether_type)
2443 err = chip->info->ops->port_set_ether_type(
2444 chip, port, ETH_P_EDSA);
2445 break;
2446
2447 case DSA_TAG_PROTO_DSA:
2448 err = chip->info->ops->port_set_frame_mode(
2449 chip, port, MV88E6XXX_FRAME_MODE_DSA);
2450 if (err)
2451 return err;
2452
2453 err = mv88e6xxx_port_set_egress_mode(
2454 chip, port, PORT_CONTROL_EGRESS_UNMODIFIED);
2455 break;
2456 default:
2457 err = -EINVAL;
2458 }
2459
2460 if (err)
2461 return err;
2462
2463 return chip->info->ops->port_set_egress_unknowns(chip, port, true);
2464}
2465
2466static int mv88e6xxx_setup_port_normal(struct mv88e6xxx_chip *chip, int port)
2467{
2468 int err;
2469
2470 err = chip->info->ops->port_set_frame_mode(
2471 chip, port, MV88E6XXX_FRAME_MODE_NORMAL);
2472 if (err)
2473 return err;
2474
2475 return chip->info->ops->port_set_egress_unknowns(chip, port, false);
2476}
2477
fad09c73 2478static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
d827e88a 2479{
fad09c73 2480 struct dsa_switch *ds = chip->ds;
0e7b9925 2481 int err;
54d792f2 2482 u16 reg;
d827e88a 2483
d78343d2
VD
2484 /* MAC Forcing register: don't force link, speed, duplex or flow control
2485 * state to any particular values on physical ports, but force the CPU
2486 * port and all DSA ports to their maximum bandwidth and full duplex.
2487 */
2488 if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
2489 err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
2490 SPEED_MAX, DUPLEX_FULL,
2491 PHY_INTERFACE_MODE_NA);
2492 else
2493 err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
2494 SPEED_UNFORCED, DUPLEX_UNFORCED,
2495 PHY_INTERFACE_MODE_NA);
2496 if (err)
2497 return err;
54d792f2
AL
2498
2499 /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
2500 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
2501 * tunneling, determine priority by looking at 802.1p and IP
2502 * priority fields (IP prio has precedence), and set STP state
2503 * to Forwarding.
2504 *
2505 * If this is the CPU link, use DSA or EDSA tagging depending
2506 * on which tagging mode was configured.
2507 *
2508 * If this is a link to another switch, use DSA tagging mode.
2509 *
2510 * If this is the upstream port for this switch, enable
2511 * forwarding of unknown unicasts and multicasts.
2512 */
56995cbc 2513 reg = PORT_CONTROL_IGMP_MLD_SNOOP |
54d792f2
AL
2514 PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
2515 PORT_CONTROL_STATE_FORWARDING;
56995cbc
AL
2516 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
2517 if (err)
2518 return err;
6083ce71 2519
56995cbc
AL
2520 if (dsa_is_cpu_port(ds, port)) {
2521 err = mv88e6xxx_setup_port_cpu(chip, port);
2522 } else if (dsa_is_dsa_port(ds, port)) {
2523 err = mv88e6xxx_setup_port_dsa(chip, port,
2524 dsa_upstream_port(ds));
2525 } else {
2526 err = mv88e6xxx_setup_port_normal(chip, port);
54d792f2 2527 }
56995cbc
AL
2528 if (err)
2529 return err;
54d792f2 2530
13a7ebb3
PU
2531 /* If this port is connected to a SerDes, make sure the SerDes is not
2532 * powered down.
2533 */
09cb7dfd 2534 if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) {
0e7b9925
AL
2535 err = mv88e6xxx_port_read(chip, port, PORT_STATUS, &reg);
2536 if (err)
2537 return err;
2538 reg &= PORT_STATUS_CMODE_MASK;
2539 if ((reg == PORT_STATUS_CMODE_100BASE_X) ||
2540 (reg == PORT_STATUS_CMODE_1000BASE_X) ||
2541 (reg == PORT_STATUS_CMODE_SGMII)) {
2542 err = mv88e6xxx_serdes_power_on(chip);
2543 if (err < 0)
2544 return err;
13a7ebb3
PU
2545 }
2546 }
2547
8efdda4a 2548 /* Port Control 2: don't force a good FCS, set the maximum frame size to
46fbe5e5 2549 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
8efdda4a
VD
2550 * untagged frames on this port, do a destination address lookup on all
2551 * received packets as usual, disable ARP mirroring and don't send a
2552 * copy of all transmitted/received frames on this port to the CPU.
54d792f2
AL
2553 */
2554 reg = 0;
fad09c73
VD
2555 if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) ||
2556 mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) ||
2557 mv88e6xxx_6095_family(chip) || mv88e6xxx_6320_family(chip) ||
2558 mv88e6xxx_6185_family(chip))
54d792f2
AL
2559 reg = PORT_CONTROL_2_MAP_DA;
2560
fad09c73 2561 if (mv88e6xxx_6095_family(chip) || mv88e6xxx_6185_family(chip)) {
54d792f2
AL
2562 /* Set the upstream port this port should use */
2563 reg |= dsa_upstream_port(ds);
2564 /* enable forwarding of unknown multicast addresses to
2565 * the upstream port
2566 */
2567 if (port == dsa_upstream_port(ds))
2568 reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
2569 }
2570
46fbe5e5 2571 reg |= PORT_CONTROL_2_8021Q_DISABLED;
8efdda4a 2572
54d792f2 2573 if (reg) {
0e7b9925
AL
2574 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg);
2575 if (err)
2576 return err;
54d792f2
AL
2577 }
2578
5f436666
AL
2579 if (chip->info->ops->port_jumbo_config) {
2580 err = chip->info->ops->port_jumbo_config(chip, port);
2581 if (err)
2582 return err;
2583 }
2584
54d792f2
AL
2585 /* Port Association Vector: when learning source addresses
2586 * of packets, add the address to the address database using
2587 * a port bitmap that has only the bit for this port set and
2588 * the other bits clear.
2589 */
4c7ea3c0 2590 reg = 1 << port;
996ecb82
VD
2591 /* Disable learning for CPU port */
2592 if (dsa_is_cpu_port(ds, port))
65fa4027 2593 reg = 0;
4c7ea3c0 2594
0e7b9925
AL
2595 err = mv88e6xxx_port_write(chip, port, PORT_ASSOC_VECTOR, reg);
2596 if (err)
2597 return err;
54d792f2
AL
2598
2599 /* Egress rate control 2: disable egress rate control. */
0e7b9925
AL
2600 err = mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL_2, 0x0000);
2601 if (err)
2602 return err;
54d792f2 2603
b35d322a
AL
2604 if (chip->info->ops->port_pause_config) {
2605 err = chip->info->ops->port_pause_config(chip, port);
0e7b9925
AL
2606 if (err)
2607 return err;
b35d322a 2608 }
54d792f2 2609
b35d322a
AL
2610 if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) ||
2611 mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) ||
2612 mv88e6xxx_6320_family(chip)) {
54d792f2
AL
2613 /* Port ATU control: disable limiting the number of
2614 * address database entries that this port is allowed
2615 * to use.
2616 */
0e7b9925
AL
2617 err = mv88e6xxx_port_write(chip, port, PORT_ATU_CONTROL,
2618 0x0000);
54d792f2
AL
2619 /* Priority Override: disable DA, SA and VTU priority
2620 * override.
2621 */
0e7b9925
AL
2622 err = mv88e6xxx_port_write(chip, port, PORT_PRI_OVERRIDE,
2623 0x0000);
2624 if (err)
2625 return err;
ef0a7318 2626 }
2bbb33be 2627
ef0a7318
AL
2628 if (chip->info->ops->port_tag_remap) {
2629 err = chip->info->ops->port_tag_remap(chip, port);
0e7b9925
AL
2630 if (err)
2631 return err;
54d792f2
AL
2632 }
2633
ef70b111
AL
2634 if (chip->info->ops->port_egress_rate_limiting) {
2635 err = chip->info->ops->port_egress_rate_limiting(chip, port);
0e7b9925
AL
2636 if (err)
2637 return err;
54d792f2
AL
2638 }
2639
366f0a0f
GR
2640 /* Port Control 1: disable trunking, disable sending
2641 * learning messages to this port.
d827e88a 2642 */
0e7b9925
AL
2643 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, 0x0000);
2644 if (err)
2645 return err;
d827e88a 2646
207afda1 2647 /* Port based VLAN map: give each port the same default address
b7666efe
VD
2648 * database, and allow bidirectional communication between the
2649 * CPU and DSA port(s), and the other ports.
d827e88a 2650 */
b4e48c50 2651 err = mv88e6xxx_port_set_fid(chip, port, 0);
0e7b9925
AL
2652 if (err)
2653 return err;
2db9ce1f 2654
0e7b9925
AL
2655 err = _mv88e6xxx_port_based_vlan_map(chip, port);
2656 if (err)
2657 return err;
d827e88a
GR
2658
2659 /* Default VLAN ID and priority: don't set a default VLAN
2660 * ID, and set the default packet priority to zero.
2661 */
0e7b9925 2662 return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000);
dbde9e66
AL
2663}
2664
aa0938c6 2665static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
3b4caa1b
VD
2666{
2667 int err;
2668
a935c052 2669 err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
3b4caa1b
VD
2670 if (err)
2671 return err;
2672
a935c052 2673 err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
3b4caa1b
VD
2674 if (err)
2675 return err;
2676
a935c052
VD
2677 err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
2678 if (err)
2679 return err;
2680
2681 return 0;
3b4caa1b
VD
2682}
2683
acddbd21
VD
2684static int mv88e6xxx_g1_set_age_time(struct mv88e6xxx_chip *chip,
2685 unsigned int msecs)
2686{
2687 const unsigned int coeff = chip->info->age_time_coeff;
2688 const unsigned int min = 0x01 * coeff;
2689 const unsigned int max = 0xff * coeff;
2690 u8 age_time;
2691 u16 val;
2692 int err;
2693
2694 if (msecs < min || msecs > max)
2695 return -ERANGE;
2696
2697 /* Round to nearest multiple of coeff */
2698 age_time = (msecs + coeff / 2) / coeff;
2699
a935c052 2700 err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
acddbd21
VD
2701 if (err)
2702 return err;
2703
2704 /* AgeTime is 11:4 bits */
2705 val &= ~0xff0;
2706 val |= age_time << 4;
2707
a935c052 2708 return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
acddbd21
VD
2709}
2710
2cfcd964
VD
2711static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
2712 unsigned int ageing_time)
2713{
04bed143 2714 struct mv88e6xxx_chip *chip = ds->priv;
2cfcd964
VD
2715 int err;
2716
2717 mutex_lock(&chip->reg_lock);
2718 err = mv88e6xxx_g1_set_age_time(chip, ageing_time);
2719 mutex_unlock(&chip->reg_lock);
2720
2721 return err;
2722}
2723
9729934c 2724static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
acdaffcc 2725{
fad09c73 2726 struct dsa_switch *ds = chip->ds;
b0745e87 2727 u32 upstream_port = dsa_upstream_port(ds);
552238b5 2728 int err;
54d792f2 2729
119477bd
VD
2730 /* Enable the PHY Polling Unit if present, don't discard any packets,
2731 * and mask all interrupt sources.
2732 */
a199d8b6 2733 err = mv88e6xxx_ppu_enable(chip);
119477bd
VD
2734 if (err)
2735 return err;
2736
33641994
AL
2737 if (chip->info->ops->g1_set_cpu_port) {
2738 err = chip->info->ops->g1_set_cpu_port(chip, upstream_port);
2739 if (err)
2740 return err;
2741 }
2742
2743 if (chip->info->ops->g1_set_egress_port) {
2744 err = chip->info->ops->g1_set_egress_port(chip, upstream_port);
2745 if (err)
2746 return err;
2747 }
b0745e87 2748
50484ff4 2749 /* Disable remote management, and set the switch's DSA device number. */
a935c052
VD
2750 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2,
2751 GLOBAL_CONTROL_2_MULTIPLE_CASCADE |
2752 (ds->index & 0x1f));
50484ff4
VD
2753 if (err)
2754 return err;
2755
acddbd21
VD
2756 /* Clear all the VTU and STU entries */
2757 err = _mv88e6xxx_vtu_stu_flush(chip);
2758 if (err < 0)
2759 return err;
2760
54d792f2
AL
2761 /* Set the default address aging time to 5 minutes, and
2762 * enable address learn messages to be sent to all message
2763 * ports.
2764 */
a935c052
VD
2765 err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL,
2766 GLOBAL_ATU_CONTROL_LEARN2ALL);
48ace4ef 2767 if (err)
08a01261 2768 return err;
54d792f2 2769
acddbd21
VD
2770 err = mv88e6xxx_g1_set_age_time(chip, 300000);
2771 if (err)
9729934c
VD
2772 return err;
2773
2774 /* Clear all ATU entries */
2775 err = _mv88e6xxx_atu_flush(chip, 0, true);
2776 if (err)
2777 return err;
2778
54d792f2 2779 /* Configure the IP ToS mapping registers. */
a935c052 2780 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000);
48ace4ef 2781 if (err)
08a01261 2782 return err;
a935c052 2783 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_1, 0x0000);
48ace4ef 2784 if (err)
08a01261 2785 return err;
a935c052 2786 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_2, 0x5555);
48ace4ef 2787 if (err)
08a01261 2788 return err;
a935c052 2789 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_3, 0x5555);
48ace4ef 2790 if (err)
08a01261 2791 return err;
a935c052 2792 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_4, 0xaaaa);
48ace4ef 2793 if (err)
08a01261 2794 return err;
a935c052 2795 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_5, 0xaaaa);
48ace4ef 2796 if (err)
08a01261 2797 return err;
a935c052 2798 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_6, 0xffff);
48ace4ef 2799 if (err)
08a01261 2800 return err;
a935c052 2801 err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_7, 0xffff);
48ace4ef 2802 if (err)
08a01261 2803 return err;
54d792f2
AL
2804
2805 /* Configure the IEEE 802.1p priority mapping register. */
a935c052 2806 err = mv88e6xxx_g1_write(chip, GLOBAL_IEEE_PRI, 0xfa41);
48ace4ef 2807 if (err)
08a01261 2808 return err;
54d792f2 2809
de227387
AL
2810 /* Initialize the statistics unit */
2811 err = mv88e6xxx_stats_set_histogram(chip);
2812 if (err)
2813 return err;
2814
9729934c 2815 /* Clear the statistics counters for all ports */
a935c052
VD
2816 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
2817 GLOBAL_STATS_OP_FLUSH_ALL);
9729934c
VD
2818 if (err)
2819 return err;
2820
2821 /* Wait for the flush to complete. */
7f9ef3af 2822 err = mv88e6xxx_g1_stats_wait(chip);
9729934c
VD
2823 if (err)
2824 return err;
2825
2826 return 0;
2827}
2828
f81ec90f 2829static int mv88e6xxx_setup(struct dsa_switch *ds)
08a01261 2830{
04bed143 2831 struct mv88e6xxx_chip *chip = ds->priv;
08a01261 2832 int err;
a1a6a4d1
VD
2833 int i;
2834
fad09c73
VD
2835 chip->ds = ds;
2836 ds->slave_mii_bus = chip->mdio_bus;
08a01261 2837
fad09c73 2838 mutex_lock(&chip->reg_lock);
08a01261 2839
9729934c 2840 /* Setup Switch Port Registers */
370b4ffb 2841 for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
9729934c
VD
2842 err = mv88e6xxx_setup_port(chip, i);
2843 if (err)
2844 goto unlock;
2845 }
2846
2847 /* Setup Switch Global 1 Registers */
2848 err = mv88e6xxx_g1_setup(chip);
a1a6a4d1
VD
2849 if (err)
2850 goto unlock;
2851
9729934c
VD
2852 /* Setup Switch Global 2 Registers */
2853 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) {
2854 err = mv88e6xxx_g2_setup(chip);
a1a6a4d1
VD
2855 if (err)
2856 goto unlock;
2857 }
08a01261 2858
6e55f698
AL
2859 /* Some generations have the configuration of sending reserved
2860 * management frames to the CPU in global2, others in
2861 * global1. Hence it does not fit the two setup functions
2862 * above.
2863 */
2864 if (chip->info->ops->mgmt_rsvd2cpu) {
2865 err = chip->info->ops->mgmt_rsvd2cpu(chip);
2866 if (err)
2867 goto unlock;
2868 }
2869
6b17e864 2870unlock:
fad09c73 2871 mutex_unlock(&chip->reg_lock);
db687a56 2872
48ace4ef 2873 return err;
54d792f2
AL
2874}
2875
3b4caa1b
VD
2876static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr)
2877{
04bed143 2878 struct mv88e6xxx_chip *chip = ds->priv;
3b4caa1b
VD
2879 int err;
2880
b073d4e2
VD
2881 if (!chip->info->ops->set_switch_mac)
2882 return -EOPNOTSUPP;
3b4caa1b 2883
b073d4e2
VD
2884 mutex_lock(&chip->reg_lock);
2885 err = chip->info->ops->set_switch_mac(chip, addr);
3b4caa1b
VD
2886 mutex_unlock(&chip->reg_lock);
2887
2888 return err;
2889}
2890
e57e5e77 2891static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
fd3a0ee4 2892{
fad09c73 2893 struct mv88e6xxx_chip *chip = bus->priv;
e57e5e77
VD
2894 u16 val;
2895 int err;
fd3a0ee4 2896
370b4ffb 2897 if (phy >= mv88e6xxx_num_ports(chip))
158bc065 2898 return 0xffff;
fd3a0ee4 2899
fad09c73 2900 mutex_lock(&chip->reg_lock);
e57e5e77 2901 err = mv88e6xxx_phy_read(chip, phy, reg, &val);
fad09c73 2902 mutex_unlock(&chip->reg_lock);
e57e5e77
VD
2903
2904 return err ? err : val;
fd3a0ee4
AL
2905}
2906
e57e5e77 2907static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
fd3a0ee4 2908{
fad09c73 2909 struct mv88e6xxx_chip *chip = bus->priv;
e57e5e77 2910 int err;
fd3a0ee4 2911
370b4ffb 2912 if (phy >= mv88e6xxx_num_ports(chip))
158bc065 2913 return 0xffff;
fd3a0ee4 2914
fad09c73 2915 mutex_lock(&chip->reg_lock);
e57e5e77 2916 err = mv88e6xxx_phy_write(chip, phy, reg, val);
fad09c73 2917 mutex_unlock(&chip->reg_lock);
e57e5e77
VD
2918
2919 return err;
fd3a0ee4
AL
2920}
2921
fad09c73 2922static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
b516d453
AL
2923 struct device_node *np)
2924{
2925 static int index;
2926 struct mii_bus *bus;
2927 int err;
2928
b516d453 2929 if (np)
fad09c73 2930 chip->mdio_np = of_get_child_by_name(np, "mdio");
b516d453 2931
fad09c73 2932 bus = devm_mdiobus_alloc(chip->dev);
b516d453
AL
2933 if (!bus)
2934 return -ENOMEM;
2935
fad09c73 2936 bus->priv = (void *)chip;
b516d453
AL
2937 if (np) {
2938 bus->name = np->full_name;
2939 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", np->full_name);
2940 } else {
2941 bus->name = "mv88e6xxx SMI";
2942 snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
2943 }
2944
2945 bus->read = mv88e6xxx_mdio_read;
2946 bus->write = mv88e6xxx_mdio_write;
fad09c73 2947 bus->parent = chip->dev;
b516d453 2948
fad09c73
VD
2949 if (chip->mdio_np)
2950 err = of_mdiobus_register(bus, chip->mdio_np);
b516d453
AL
2951 else
2952 err = mdiobus_register(bus);
2953 if (err) {
fad09c73 2954 dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
b516d453
AL
2955 goto out;
2956 }
fad09c73 2957 chip->mdio_bus = bus;
b516d453
AL
2958
2959 return 0;
2960
2961out:
fad09c73
VD
2962 if (chip->mdio_np)
2963 of_node_put(chip->mdio_np);
b516d453
AL
2964
2965 return err;
2966}
2967
fad09c73 2968static void mv88e6xxx_mdio_unregister(struct mv88e6xxx_chip *chip)
b516d453
AL
2969
2970{
fad09c73 2971 struct mii_bus *bus = chip->mdio_bus;
b516d453
AL
2972
2973 mdiobus_unregister(bus);
2974
fad09c73
VD
2975 if (chip->mdio_np)
2976 of_node_put(chip->mdio_np);
b516d453
AL
2977}
2978
855b1932
VD
2979static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
2980{
04bed143 2981 struct mv88e6xxx_chip *chip = ds->priv;
855b1932
VD
2982
2983 return chip->eeprom_len;
2984}
2985
855b1932
VD
2986static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
2987 struct ethtool_eeprom *eeprom, u8 *data)
2988{
04bed143 2989 struct mv88e6xxx_chip *chip = ds->priv;
855b1932
VD
2990 int err;
2991
ee4dc2e7
VD
2992 if (!chip->info->ops->get_eeprom)
2993 return -EOPNOTSUPP;
855b1932 2994
ee4dc2e7
VD
2995 mutex_lock(&chip->reg_lock);
2996 err = chip->info->ops->get_eeprom(chip, eeprom, data);
855b1932
VD
2997 mutex_unlock(&chip->reg_lock);
2998
2999 if (err)
3000 return err;
3001
3002 eeprom->magic = 0xc3ec4951;
3003
3004 return 0;
3005}
3006
855b1932
VD
3007static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
3008 struct ethtool_eeprom *eeprom, u8 *data)
3009{
04bed143 3010 struct mv88e6xxx_chip *chip = ds->priv;
855b1932
VD
3011 int err;
3012
ee4dc2e7
VD
3013 if (!chip->info->ops->set_eeprom)
3014 return -EOPNOTSUPP;
3015
855b1932
VD
3016 if (eeprom->magic != 0xc3ec4951)
3017 return -EINVAL;
3018
3019 mutex_lock(&chip->reg_lock);
ee4dc2e7 3020 err = chip->info->ops->set_eeprom(chip, eeprom, data);
855b1932
VD
3021 mutex_unlock(&chip->reg_lock);
3022
3023 return err;
3024}
3025
b3469dd8 3026static const struct mv88e6xxx_ops mv88e6085_ops = {
4b325d8c 3027 /* MV88E6XXX_FAMILY_6097 */
b073d4e2 3028 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
3029 .phy_read = mv88e6xxx_phy_ppu_read,
3030 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 3031 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3032 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3033 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3034 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3035 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3036 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3037 .port_set_ether_type = mv88e6351_port_set_ether_type,
ef70b111 3038 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3039 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3040 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3041 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3042 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3043 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3044 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3045 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3046 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
3047 .ppu_enable = mv88e6185_g1_ppu_enable,
3048 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 3049 .reset = mv88e6185_g1_reset,
b3469dd8
VD
3050};
3051
3052static const struct mv88e6xxx_ops mv88e6095_ops = {
4b325d8c 3053 /* MV88E6XXX_FAMILY_6095 */
b073d4e2 3054 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
3055 .phy_read = mv88e6xxx_phy_ppu_read,
3056 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 3057 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3058 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3059 .port_set_speed = mv88e6185_port_set_speed,
56995cbc
AL
3060 .port_set_frame_mode = mv88e6085_port_set_frame_mode,
3061 .port_set_egress_unknowns = mv88e6085_port_set_egress_unknowns,
a605a0fe 3062 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3063 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3064 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3065 .stats_get_stats = mv88e6095_stats_get_stats,
6e55f698 3066 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
3067 .ppu_enable = mv88e6185_g1_ppu_enable,
3068 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 3069 .reset = mv88e6185_g1_reset,
b3469dd8
VD
3070};
3071
7d381a02 3072static const struct mv88e6xxx_ops mv88e6097_ops = {
15da3cc8 3073 /* MV88E6XXX_FAMILY_6097 */
7d381a02
SE
3074 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3075 .phy_read = mv88e6xxx_g2_smi_phy_read,
3076 .phy_write = mv88e6xxx_g2_smi_phy_write,
3077 .port_set_link = mv88e6xxx_port_set_link,
3078 .port_set_duplex = mv88e6xxx_port_set_duplex,
3079 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3080 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3081 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3082 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3083 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3084 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3085 .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
b35d322a 3086 .port_pause_config = mv88e6097_port_pause_config,
7d381a02
SE
3087 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3088 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3089 .stats_get_strings = mv88e6095_stats_get_strings,
3090 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3091 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3092 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3093 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3094 .reset = mv88e6352_g1_reset,
7d381a02
SE
3095};
3096
b3469dd8 3097static const struct mv88e6xxx_ops mv88e6123_ops = {
4b325d8c 3098 /* MV88E6XXX_FAMILY_6165 */
b073d4e2 3099 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
efb3e74d
AL
3100 .phy_read = mv88e6165_phy_read,
3101 .phy_write = mv88e6165_phy_write,
08ef7f10 3102 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3103 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3104 .port_set_speed = mv88e6185_port_set_speed,
56995cbc
AL
3105 .port_set_frame_mode = mv88e6085_port_set_frame_mode,
3106 .port_set_egress_unknowns = mv88e6085_port_set_egress_unknowns,
a605a0fe 3107 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3108 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3109 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3110 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3111 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3112 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3113 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3114 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3115};
3116
3117static const struct mv88e6xxx_ops mv88e6131_ops = {
4b325d8c 3118 /* MV88E6XXX_FAMILY_6185 */
b073d4e2 3119 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
3120 .phy_read = mv88e6xxx_phy_ppu_read,
3121 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 3122 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3123 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3124 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3125 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3126 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3127 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3128 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3129 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3130 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3131 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3132 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3133 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3134 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3135 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3136 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3137 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3138 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
3139 .ppu_enable = mv88e6185_g1_ppu_enable,
3140 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 3141 .reset = mv88e6185_g1_reset,
b3469dd8
VD
3142};
3143
3144static const struct mv88e6xxx_ops mv88e6161_ops = {
4b325d8c 3145 /* MV88E6XXX_FAMILY_6165 */
b073d4e2 3146 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
efb3e74d
AL
3147 .phy_read = mv88e6165_phy_read,
3148 .phy_write = mv88e6165_phy_write,
08ef7f10 3149 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3150 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3151 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3152 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3153 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3154 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3155 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3156 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3157 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3158 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3159 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3160 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3161 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3162 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3163 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3164 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3165 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3166 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3167};
3168
3169static const struct mv88e6xxx_ops mv88e6165_ops = {
4b325d8c 3170 /* MV88E6XXX_FAMILY_6165 */
b073d4e2 3171 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
efb3e74d
AL
3172 .phy_read = mv88e6165_phy_read,
3173 .phy_write = mv88e6165_phy_write,
08ef7f10 3174 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3175 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3176 .port_set_speed = mv88e6185_port_set_speed,
a605a0fe 3177 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3178 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3179 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3180 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3181 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3182 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3183 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3184 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3185};
3186
3187static const struct mv88e6xxx_ops mv88e6171_ops = {
4b325d8c 3188 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3189 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3190 .phy_read = mv88e6xxx_g2_smi_phy_read,
3191 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3192 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3193 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3194 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3195 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3196 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3197 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3198 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3199 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3200 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3201 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3202 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3203 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3204 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3205 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3206 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3207 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3208 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3209 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3210 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3211};
3212
3213static const struct mv88e6xxx_ops mv88e6172_ops = {
4b325d8c 3214 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3215 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3216 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3217 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3218 .phy_read = mv88e6xxx_g2_smi_phy_read,
3219 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3220 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3221 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3222 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3223 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3224 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3225 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3226 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3227 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3228 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3229 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3230 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3231 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3232 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3233 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3234 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3235 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3236 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3237 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3238 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3239};
3240
3241static const struct mv88e6xxx_ops mv88e6175_ops = {
4b325d8c 3242 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3243 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3244 .phy_read = mv88e6xxx_g2_smi_phy_read,
3245 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3246 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3247 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3248 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3249 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3250 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3251 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3252 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3253 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3254 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3255 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3256 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3257 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3258 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3259 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3260 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3261 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3262 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3263 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3264 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3265};
3266
3267static const struct mv88e6xxx_ops mv88e6176_ops = {
4b325d8c 3268 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3269 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3270 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3271 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3272 .phy_read = mv88e6xxx_g2_smi_phy_read,
3273 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3274 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3275 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3276 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3277 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3278 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3279 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3280 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3281 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3282 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3283 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3284 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3285 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3286 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3287 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3288 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3289 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3290 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3291 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3292 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3293};
3294
3295static const struct mv88e6xxx_ops mv88e6185_ops = {
4b325d8c 3296 /* MV88E6XXX_FAMILY_6185 */
b073d4e2 3297 .set_switch_mac = mv88e6xxx_g1_set_switch_mac,
b3469dd8
VD
3298 .phy_read = mv88e6xxx_phy_ppu_read,
3299 .phy_write = mv88e6xxx_phy_ppu_write,
08ef7f10 3300 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3301 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3302 .port_set_speed = mv88e6185_port_set_speed,
56995cbc
AL
3303 .port_set_frame_mode = mv88e6085_port_set_frame_mode,
3304 .port_set_egress_unknowns = mv88e6085_port_set_egress_unknowns,
ef70b111 3305 .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
a605a0fe 3306 .stats_snapshot = mv88e6xxx_g1_stats_snapshot,
dfafe449
AL
3307 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3308 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3309 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3310 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3311 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3312 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
a199d8b6
VD
3313 .ppu_enable = mv88e6185_g1_ppu_enable,
3314 .ppu_disable = mv88e6185_g1_ppu_disable,
17e708ba 3315 .reset = mv88e6185_g1_reset,
b3469dd8
VD
3316};
3317
1a3b39ec 3318static const struct mv88e6xxx_ops mv88e6190_ops = {
4b325d8c 3319 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3320 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3321 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3322 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3323 .phy_read = mv88e6xxx_g2_smi_phy_read,
3324 .phy_write = mv88e6xxx_g2_smi_phy_write,
3325 .port_set_link = mv88e6xxx_port_set_link,
3326 .port_set_duplex = mv88e6xxx_port_set_duplex,
3327 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3328 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3329 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3330 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3331 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3332 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3333 .port_pause_config = mv88e6390_port_pause_config,
79523473 3334 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3335 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3336 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3337 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3338 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3339 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3340 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3341 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3342 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3343};
3344
3345static const struct mv88e6xxx_ops mv88e6190x_ops = {
4b325d8c 3346 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3347 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3348 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3349 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3350 .phy_read = mv88e6xxx_g2_smi_phy_read,
3351 .phy_write = mv88e6xxx_g2_smi_phy_write,
3352 .port_set_link = mv88e6xxx_port_set_link,
3353 .port_set_duplex = mv88e6xxx_port_set_duplex,
3354 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3355 .port_set_speed = mv88e6390x_port_set_speed,
ef0a7318 3356 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3357 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3358 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3359 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3360 .port_pause_config = mv88e6390_port_pause_config,
79523473 3361 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3362 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3363 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3364 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3365 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3366 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3367 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3368 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3369 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3370};
3371
3372static const struct mv88e6xxx_ops mv88e6191_ops = {
4b325d8c 3373 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3374 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3375 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3376 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3377 .phy_read = mv88e6xxx_g2_smi_phy_read,
3378 .phy_write = mv88e6xxx_g2_smi_phy_write,
3379 .port_set_link = mv88e6xxx_port_set_link,
3380 .port_set_duplex = mv88e6xxx_port_set_duplex,
3381 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3382 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3383 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3384 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3385 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3386 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3387 .port_pause_config = mv88e6390_port_pause_config,
79523473 3388 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3389 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3390 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3391 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3392 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3393 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3394 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3395 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3396 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3397};
3398
b3469dd8 3399static const struct mv88e6xxx_ops mv88e6240_ops = {
4b325d8c 3400 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3401 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3402 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3403 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3404 .phy_read = mv88e6xxx_g2_smi_phy_read,
3405 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3406 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3407 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3408 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3409 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3410 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3411 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3412 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3413 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3414 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3415 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3416 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3417 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3418 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3419 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3420 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3421 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3422 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3423 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3424 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3425};
3426
1a3b39ec 3427static const struct mv88e6xxx_ops mv88e6290_ops = {
4b325d8c 3428 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3429 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3430 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3431 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3432 .phy_read = mv88e6xxx_g2_smi_phy_read,
3433 .phy_write = mv88e6xxx_g2_smi_phy_write,
3434 .port_set_link = mv88e6xxx_port_set_link,
3435 .port_set_duplex = mv88e6xxx_port_set_duplex,
3436 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3437 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3438 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3439 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3440 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3441 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3442 .port_pause_config = mv88e6390_port_pause_config,
79523473 3443 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3444 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3445 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3446 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3447 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3448 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3449 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3450 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3451 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3452};
3453
b3469dd8 3454static const struct mv88e6xxx_ops mv88e6320_ops = {
4b325d8c 3455 /* MV88E6XXX_FAMILY_6320 */
ee4dc2e7
VD
3456 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3457 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3458 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3459 .phy_read = mv88e6xxx_g2_smi_phy_read,
3460 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3461 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3462 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3463 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3464 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3465 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3466 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3467 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3468 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3469 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3470 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3471 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3472 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3473 .stats_get_strings = mv88e6320_stats_get_strings,
052f947f 3474 .stats_get_stats = mv88e6320_stats_get_stats,
33641994
AL
3475 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3476 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3477 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3478 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3479};
3480
3481static const struct mv88e6xxx_ops mv88e6321_ops = {
4b325d8c 3482 /* MV88E6XXX_FAMILY_6321 */
ee4dc2e7
VD
3483 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3484 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3485 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3486 .phy_read = mv88e6xxx_g2_smi_phy_read,
3487 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3488 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3489 .port_set_duplex = mv88e6xxx_port_set_duplex,
96a2b40c 3490 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3491 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3492 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3493 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3494 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3495 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3496 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3497 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3498 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3499 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3500 .stats_get_strings = mv88e6320_stats_get_strings,
052f947f 3501 .stats_get_stats = mv88e6320_stats_get_stats,
33641994
AL
3502 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3503 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
17e708ba 3504 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3505};
3506
3507static const struct mv88e6xxx_ops mv88e6350_ops = {
4b325d8c 3508 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3509 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3510 .phy_read = mv88e6xxx_g2_smi_phy_read,
3511 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3512 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3513 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3514 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3515 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3516 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3517 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3518 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3519 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3520 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3521 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3522 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3523 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3524 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3525 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3526 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3527 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3528 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3529 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3530 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3531};
3532
3533static const struct mv88e6xxx_ops mv88e6351_ops = {
4b325d8c 3534 /* MV88E6XXX_FAMILY_6351 */
b073d4e2 3535 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3536 .phy_read = mv88e6xxx_g2_smi_phy_read,
3537 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3538 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3539 .port_set_duplex = mv88e6xxx_port_set_duplex,
94d66ae6 3540 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3541 .port_set_speed = mv88e6185_port_set_speed,
ef0a7318 3542 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3543 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3544 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3545 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3546 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3547 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3548 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3549 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3550 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3551 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3552 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3553 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3554 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3555 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3556 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3557};
3558
3559static const struct mv88e6xxx_ops mv88e6352_ops = {
4b325d8c 3560 /* MV88E6XXX_FAMILY_6352 */
ee4dc2e7
VD
3561 .get_eeprom = mv88e6xxx_g2_get_eeprom16,
3562 .set_eeprom = mv88e6xxx_g2_set_eeprom16,
b073d4e2 3563 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
b3469dd8
VD
3564 .phy_read = mv88e6xxx_g2_smi_phy_read,
3565 .phy_write = mv88e6xxx_g2_smi_phy_write,
08ef7f10 3566 .port_set_link = mv88e6xxx_port_set_link,
7f1ae07b 3567 .port_set_duplex = mv88e6xxx_port_set_duplex,
a0a0f622 3568 .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
96a2b40c 3569 .port_set_speed = mv88e6352_port_set_speed,
ef0a7318 3570 .port_tag_remap = mv88e6095_port_tag_remap,
56995cbc
AL
3571 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3572 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3573 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3574 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3575 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
b35d322a 3576 .port_pause_config = mv88e6097_port_pause_config,
a605a0fe 3577 .stats_snapshot = mv88e6320_g1_stats_snapshot,
dfafe449
AL
3578 .stats_get_sset_count = mv88e6095_stats_get_sset_count,
3579 .stats_get_strings = mv88e6095_stats_get_strings,
052f947f 3580 .stats_get_stats = mv88e6095_stats_get_stats,
33641994
AL
3581 .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
3582 .g1_set_egress_port = mv88e6095_g1_set_egress_port,
6e55f698 3583 .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
17e708ba 3584 .reset = mv88e6352_g1_reset,
b3469dd8
VD
3585};
3586
1a3b39ec 3587static const struct mv88e6xxx_ops mv88e6390_ops = {
4b325d8c 3588 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3589 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3590 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3591 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3592 .phy_read = mv88e6xxx_g2_smi_phy_read,
3593 .phy_write = mv88e6xxx_g2_smi_phy_write,
3594 .port_set_link = mv88e6xxx_port_set_link,
3595 .port_set_duplex = mv88e6xxx_port_set_duplex,
3596 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3597 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3598 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3599 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3600 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3601 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3602 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3603 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3ce0e65e 3604 .port_pause_config = mv88e6390_port_pause_config,
79523473 3605 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3606 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3607 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3608 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3609 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3610 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3611 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3612 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3613 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3614};
3615
3616static const struct mv88e6xxx_ops mv88e6390x_ops = {
4b325d8c 3617 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3618 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3619 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3620 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3621 .phy_read = mv88e6xxx_g2_smi_phy_read,
3622 .phy_write = mv88e6xxx_g2_smi_phy_write,
3623 .port_set_link = mv88e6xxx_port_set_link,
3624 .port_set_duplex = mv88e6xxx_port_set_duplex,
3625 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3626 .port_set_speed = mv88e6390x_port_set_speed,
ef0a7318 3627 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3628 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3629 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3630 .port_set_ether_type = mv88e6351_port_set_ether_type,
5f436666 3631 .port_jumbo_config = mv88e6165_port_jumbo_config,
ef70b111 3632 .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3ce0e65e 3633 .port_pause_config = mv88e6390_port_pause_config,
79523473 3634 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3635 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3636 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3637 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3638 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3639 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3640 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3641 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3642 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3643};
3644
3645static const struct mv88e6xxx_ops mv88e6391_ops = {
4b325d8c 3646 /* MV88E6XXX_FAMILY_6390 */
98fc3c6f
VD
3647 .get_eeprom = mv88e6xxx_g2_get_eeprom8,
3648 .set_eeprom = mv88e6xxx_g2_set_eeprom8,
1a3b39ec
AL
3649 .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3650 .phy_read = mv88e6xxx_g2_smi_phy_read,
3651 .phy_write = mv88e6xxx_g2_smi_phy_write,
3652 .port_set_link = mv88e6xxx_port_set_link,
3653 .port_set_duplex = mv88e6xxx_port_set_duplex,
3654 .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3655 .port_set_speed = mv88e6390_port_set_speed,
ef0a7318 3656 .port_tag_remap = mv88e6390_port_tag_remap,
56995cbc
AL
3657 .port_set_frame_mode = mv88e6351_port_set_frame_mode,
3658 .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
3659 .port_set_ether_type = mv88e6351_port_set_ether_type,
3ce0e65e 3660 .port_pause_config = mv88e6390_port_pause_config,
79523473 3661 .stats_snapshot = mv88e6390_g1_stats_snapshot,
de227387 3662 .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
dfafe449
AL
3663 .stats_get_sset_count = mv88e6320_stats_get_sset_count,
3664 .stats_get_strings = mv88e6320_stats_get_strings,
e0d8b615 3665 .stats_get_stats = mv88e6390_stats_get_stats,
33641994
AL
3666 .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
3667 .g1_set_egress_port = mv88e6390_g1_set_egress_port,
6e55f698 3668 .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
17e708ba 3669 .reset = mv88e6352_g1_reset,
1a3b39ec
AL
3670};
3671
56995cbc
AL
3672static int mv88e6xxx_verify_madatory_ops(struct mv88e6xxx_chip *chip,
3673 const struct mv88e6xxx_ops *ops)
3674{
3675 if (!ops->port_set_frame_mode) {
3676 dev_err(chip->dev, "Missing port_set_frame_mode");
3677 return -EINVAL;
3678 }
3679
3680 if (!ops->port_set_egress_unknowns) {
3681 dev_err(chip->dev, "Missing port_set_egress_mode");
3682 return -EINVAL;
3683 }
3684
3685 return 0;
3686}
3687
f81ec90f
VD
3688static const struct mv88e6xxx_info mv88e6xxx_table[] = {
3689 [MV88E6085] = {
3690 .prod_num = PORT_SWITCH_ID_PROD_NUM_6085,
3691 .family = MV88E6XXX_FAMILY_6097,
3692 .name = "Marvell 88E6085",
3693 .num_databases = 4096,
3694 .num_ports = 10,
9dddd478 3695 .port_base_addr = 0x10,
a935c052 3696 .global1_addr = 0x1b,
acddbd21 3697 .age_time_coeff = 15000,
dc30c35b 3698 .g1_irqs = 8,
443d5a1b 3699 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3700 .flags = MV88E6XXX_FLAGS_FAMILY_6097,
b3469dd8 3701 .ops = &mv88e6085_ops,
f81ec90f
VD
3702 },
3703
3704 [MV88E6095] = {
3705 .prod_num = PORT_SWITCH_ID_PROD_NUM_6095,
3706 .family = MV88E6XXX_FAMILY_6095,
3707 .name = "Marvell 88E6095/88E6095F",
3708 .num_databases = 256,
3709 .num_ports = 11,
9dddd478 3710 .port_base_addr = 0x10,
a935c052 3711 .global1_addr = 0x1b,
acddbd21 3712 .age_time_coeff = 15000,
dc30c35b 3713 .g1_irqs = 8,
443d5a1b 3714 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3715 .flags = MV88E6XXX_FLAGS_FAMILY_6095,
b3469dd8 3716 .ops = &mv88e6095_ops,
f81ec90f
VD
3717 },
3718
7d381a02
SE
3719 [MV88E6097] = {
3720 .prod_num = PORT_SWITCH_ID_PROD_NUM_6097,
3721 .family = MV88E6XXX_FAMILY_6097,
3722 .name = "Marvell 88E6097/88E6097F",
3723 .num_databases = 4096,
3724 .num_ports = 11,
3725 .port_base_addr = 0x10,
3726 .global1_addr = 0x1b,
3727 .age_time_coeff = 15000,
c534178b 3728 .g1_irqs = 8,
2bfcfcd3 3729 .tag_protocol = DSA_TAG_PROTO_EDSA,
7d381a02
SE
3730 .flags = MV88E6XXX_FLAGS_FAMILY_6097,
3731 .ops = &mv88e6097_ops,
3732 },
3733
f81ec90f
VD
3734 [MV88E6123] = {
3735 .prod_num = PORT_SWITCH_ID_PROD_NUM_6123,
3736 .family = MV88E6XXX_FAMILY_6165,
3737 .name = "Marvell 88E6123",
3738 .num_databases = 4096,
3739 .num_ports = 3,
9dddd478 3740 .port_base_addr = 0x10,
a935c052 3741 .global1_addr = 0x1b,
acddbd21 3742 .age_time_coeff = 15000,
dc30c35b 3743 .g1_irqs = 9,
443d5a1b 3744 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3745 .flags = MV88E6XXX_FLAGS_FAMILY_6165,
b3469dd8 3746 .ops = &mv88e6123_ops,
f81ec90f
VD
3747 },
3748
3749 [MV88E6131] = {
3750 .prod_num = PORT_SWITCH_ID_PROD_NUM_6131,
3751 .family = MV88E6XXX_FAMILY_6185,
3752 .name = "Marvell 88E6131",
3753 .num_databases = 256,
3754 .num_ports = 8,
9dddd478 3755 .port_base_addr = 0x10,
a935c052 3756 .global1_addr = 0x1b,
acddbd21 3757 .age_time_coeff = 15000,
dc30c35b 3758 .g1_irqs = 9,
443d5a1b 3759 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3760 .flags = MV88E6XXX_FLAGS_FAMILY_6185,
b3469dd8 3761 .ops = &mv88e6131_ops,
f81ec90f
VD
3762 },
3763
3764 [MV88E6161] = {
3765 .prod_num = PORT_SWITCH_ID_PROD_NUM_6161,
3766 .family = MV88E6XXX_FAMILY_6165,
3767 .name = "Marvell 88E6161",
3768 .num_databases = 4096,
3769 .num_ports = 6,
9dddd478 3770 .port_base_addr = 0x10,
a935c052 3771 .global1_addr = 0x1b,
acddbd21 3772 .age_time_coeff = 15000,
dc30c35b 3773 .g1_irqs = 9,
443d5a1b 3774 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3775 .flags = MV88E6XXX_FLAGS_FAMILY_6165,
b3469dd8 3776 .ops = &mv88e6161_ops,
f81ec90f
VD
3777 },
3778
3779 [MV88E6165] = {
3780 .prod_num = PORT_SWITCH_ID_PROD_NUM_6165,
3781 .family = MV88E6XXX_FAMILY_6165,
3782 .name = "Marvell 88E6165",
3783 .num_databases = 4096,
3784 .num_ports = 6,
9dddd478 3785 .port_base_addr = 0x10,
a935c052 3786 .global1_addr = 0x1b,
acddbd21 3787 .age_time_coeff = 15000,
dc30c35b 3788 .g1_irqs = 9,
443d5a1b 3789 .tag_protocol = DSA_TAG_PROTO_DSA,
f81ec90f 3790 .flags = MV88E6XXX_FLAGS_FAMILY_6165,
b3469dd8 3791 .ops = &mv88e6165_ops,
f81ec90f
VD
3792 },
3793
3794 [MV88E6171] = {
3795 .prod_num = PORT_SWITCH_ID_PROD_NUM_6171,
3796 .family = MV88E6XXX_FAMILY_6351,
3797 .name = "Marvell 88E6171",
3798 .num_databases = 4096,
3799 .num_ports = 7,
9dddd478 3800 .port_base_addr = 0x10,
a935c052 3801 .global1_addr = 0x1b,
acddbd21 3802 .age_time_coeff = 15000,
dc30c35b 3803 .g1_irqs = 9,
443d5a1b 3804 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3805 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3806 .ops = &mv88e6171_ops,
f81ec90f
VD
3807 },
3808
3809 [MV88E6172] = {
3810 .prod_num = PORT_SWITCH_ID_PROD_NUM_6172,
3811 .family = MV88E6XXX_FAMILY_6352,
3812 .name = "Marvell 88E6172",
3813 .num_databases = 4096,
3814 .num_ports = 7,
9dddd478 3815 .port_base_addr = 0x10,
a935c052 3816 .global1_addr = 0x1b,
acddbd21 3817 .age_time_coeff = 15000,
dc30c35b 3818 .g1_irqs = 9,
443d5a1b 3819 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3820 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 3821 .ops = &mv88e6172_ops,
f81ec90f
VD
3822 },
3823
3824 [MV88E6175] = {
3825 .prod_num = PORT_SWITCH_ID_PROD_NUM_6175,
3826 .family = MV88E6XXX_FAMILY_6351,
3827 .name = "Marvell 88E6175",
3828 .num_databases = 4096,
3829 .num_ports = 7,
9dddd478 3830 .port_base_addr = 0x10,
a935c052 3831 .global1_addr = 0x1b,
acddbd21 3832 .age_time_coeff = 15000,
dc30c35b 3833 .g1_irqs = 9,
443d5a1b 3834 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3835 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3836 .ops = &mv88e6175_ops,
f81ec90f
VD
3837 },
3838
3839 [MV88E6176] = {
3840 .prod_num = PORT_SWITCH_ID_PROD_NUM_6176,
3841 .family = MV88E6XXX_FAMILY_6352,
3842 .name = "Marvell 88E6176",
3843 .num_databases = 4096,
3844 .num_ports = 7,
9dddd478 3845 .port_base_addr = 0x10,
a935c052 3846 .global1_addr = 0x1b,
acddbd21 3847 .age_time_coeff = 15000,
dc30c35b 3848 .g1_irqs = 9,
443d5a1b 3849 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3850 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 3851 .ops = &mv88e6176_ops,
f81ec90f
VD
3852 },
3853
3854 [MV88E6185] = {
3855 .prod_num = PORT_SWITCH_ID_PROD_NUM_6185,
3856 .family = MV88E6XXX_FAMILY_6185,
3857 .name = "Marvell 88E6185",
3858 .num_databases = 256,
3859 .num_ports = 10,
9dddd478 3860 .port_base_addr = 0x10,
a935c052 3861 .global1_addr = 0x1b,
acddbd21 3862 .age_time_coeff = 15000,
dc30c35b 3863 .g1_irqs = 8,
443d5a1b 3864 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3865 .flags = MV88E6XXX_FLAGS_FAMILY_6185,
b3469dd8 3866 .ops = &mv88e6185_ops,
f81ec90f
VD
3867 },
3868
1a3b39ec
AL
3869 [MV88E6190] = {
3870 .prod_num = PORT_SWITCH_ID_PROD_NUM_6190,
3871 .family = MV88E6XXX_FAMILY_6390,
3872 .name = "Marvell 88E6190",
3873 .num_databases = 4096,
3874 .num_ports = 11, /* 10 + Z80 */
3875 .port_base_addr = 0x0,
3876 .global1_addr = 0x1b,
443d5a1b 3877 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
3878 .age_time_coeff = 15000,
3879 .g1_irqs = 9,
3880 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3881 .ops = &mv88e6190_ops,
3882 },
3883
3884 [MV88E6190X] = {
3885 .prod_num = PORT_SWITCH_ID_PROD_NUM_6190X,
3886 .family = MV88E6XXX_FAMILY_6390,
3887 .name = "Marvell 88E6190X",
3888 .num_databases = 4096,
3889 .num_ports = 11, /* 10 + Z80 */
3890 .port_base_addr = 0x0,
3891 .global1_addr = 0x1b,
3892 .age_time_coeff = 15000,
3893 .g1_irqs = 9,
443d5a1b 3894 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
3895 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3896 .ops = &mv88e6190x_ops,
3897 },
3898
3899 [MV88E6191] = {
3900 .prod_num = PORT_SWITCH_ID_PROD_NUM_6191,
3901 .family = MV88E6XXX_FAMILY_6390,
3902 .name = "Marvell 88E6191",
3903 .num_databases = 4096,
3904 .num_ports = 11, /* 10 + Z80 */
3905 .port_base_addr = 0x0,
3906 .global1_addr = 0x1b,
3907 .age_time_coeff = 15000,
443d5a1b
AL
3908 .g1_irqs = 9,
3909 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
3910 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3911 .ops = &mv88e6391_ops,
3912 },
3913
f81ec90f
VD
3914 [MV88E6240] = {
3915 .prod_num = PORT_SWITCH_ID_PROD_NUM_6240,
3916 .family = MV88E6XXX_FAMILY_6352,
3917 .name = "Marvell 88E6240",
3918 .num_databases = 4096,
3919 .num_ports = 7,
9dddd478 3920 .port_base_addr = 0x10,
a935c052 3921 .global1_addr = 0x1b,
acddbd21 3922 .age_time_coeff = 15000,
dc30c35b 3923 .g1_irqs = 9,
443d5a1b 3924 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3925 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 3926 .ops = &mv88e6240_ops,
f81ec90f
VD
3927 },
3928
1a3b39ec
AL
3929 [MV88E6290] = {
3930 .prod_num = PORT_SWITCH_ID_PROD_NUM_6290,
3931 .family = MV88E6XXX_FAMILY_6390,
3932 .name = "Marvell 88E6290",
3933 .num_databases = 4096,
3934 .num_ports = 11, /* 10 + Z80 */
3935 .port_base_addr = 0x0,
3936 .global1_addr = 0x1b,
3937 .age_time_coeff = 15000,
3938 .g1_irqs = 9,
443d5a1b 3939 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
3940 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
3941 .ops = &mv88e6290_ops,
3942 },
3943
f81ec90f
VD
3944 [MV88E6320] = {
3945 .prod_num = PORT_SWITCH_ID_PROD_NUM_6320,
3946 .family = MV88E6XXX_FAMILY_6320,
3947 .name = "Marvell 88E6320",
3948 .num_databases = 4096,
3949 .num_ports = 7,
9dddd478 3950 .port_base_addr = 0x10,
a935c052 3951 .global1_addr = 0x1b,
acddbd21 3952 .age_time_coeff = 15000,
dc30c35b 3953 .g1_irqs = 8,
443d5a1b 3954 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3955 .flags = MV88E6XXX_FLAGS_FAMILY_6320,
b3469dd8 3956 .ops = &mv88e6320_ops,
f81ec90f
VD
3957 },
3958
3959 [MV88E6321] = {
3960 .prod_num = PORT_SWITCH_ID_PROD_NUM_6321,
3961 .family = MV88E6XXX_FAMILY_6320,
3962 .name = "Marvell 88E6321",
3963 .num_databases = 4096,
3964 .num_ports = 7,
9dddd478 3965 .port_base_addr = 0x10,
a935c052 3966 .global1_addr = 0x1b,
acddbd21 3967 .age_time_coeff = 15000,
dc30c35b 3968 .g1_irqs = 8,
443d5a1b 3969 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3970 .flags = MV88E6XXX_FLAGS_FAMILY_6320,
b3469dd8 3971 .ops = &mv88e6321_ops,
f81ec90f
VD
3972 },
3973
3974 [MV88E6350] = {
3975 .prod_num = PORT_SWITCH_ID_PROD_NUM_6350,
3976 .family = MV88E6XXX_FAMILY_6351,
3977 .name = "Marvell 88E6350",
3978 .num_databases = 4096,
3979 .num_ports = 7,
9dddd478 3980 .port_base_addr = 0x10,
a935c052 3981 .global1_addr = 0x1b,
acddbd21 3982 .age_time_coeff = 15000,
dc30c35b 3983 .g1_irqs = 9,
443d5a1b 3984 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 3985 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 3986 .ops = &mv88e6350_ops,
f81ec90f
VD
3987 },
3988
3989 [MV88E6351] = {
3990 .prod_num = PORT_SWITCH_ID_PROD_NUM_6351,
3991 .family = MV88E6XXX_FAMILY_6351,
3992 .name = "Marvell 88E6351",
3993 .num_databases = 4096,
3994 .num_ports = 7,
9dddd478 3995 .port_base_addr = 0x10,
a935c052 3996 .global1_addr = 0x1b,
acddbd21 3997 .age_time_coeff = 15000,
dc30c35b 3998 .g1_irqs = 9,
443d5a1b 3999 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 4000 .flags = MV88E6XXX_FLAGS_FAMILY_6351,
b3469dd8 4001 .ops = &mv88e6351_ops,
f81ec90f
VD
4002 },
4003
4004 [MV88E6352] = {
4005 .prod_num = PORT_SWITCH_ID_PROD_NUM_6352,
4006 .family = MV88E6XXX_FAMILY_6352,
4007 .name = "Marvell 88E6352",
4008 .num_databases = 4096,
4009 .num_ports = 7,
9dddd478 4010 .port_base_addr = 0x10,
a935c052 4011 .global1_addr = 0x1b,
acddbd21 4012 .age_time_coeff = 15000,
dc30c35b 4013 .g1_irqs = 9,
443d5a1b 4014 .tag_protocol = DSA_TAG_PROTO_EDSA,
f81ec90f 4015 .flags = MV88E6XXX_FLAGS_FAMILY_6352,
b3469dd8 4016 .ops = &mv88e6352_ops,
f81ec90f 4017 },
1a3b39ec
AL
4018 [MV88E6390] = {
4019 .prod_num = PORT_SWITCH_ID_PROD_NUM_6390,
4020 .family = MV88E6XXX_FAMILY_6390,
4021 .name = "Marvell 88E6390",
4022 .num_databases = 4096,
4023 .num_ports = 11, /* 10 + Z80 */
4024 .port_base_addr = 0x0,
4025 .global1_addr = 0x1b,
4026 .age_time_coeff = 15000,
4027 .g1_irqs = 9,
443d5a1b 4028 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
4029 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
4030 .ops = &mv88e6390_ops,
4031 },
4032 [MV88E6390X] = {
4033 .prod_num = PORT_SWITCH_ID_PROD_NUM_6390X,
4034 .family = MV88E6XXX_FAMILY_6390,
4035 .name = "Marvell 88E6390X",
4036 .num_databases = 4096,
4037 .num_ports = 11, /* 10 + Z80 */
4038 .port_base_addr = 0x0,
4039 .global1_addr = 0x1b,
4040 .age_time_coeff = 15000,
4041 .g1_irqs = 9,
443d5a1b 4042 .tag_protocol = DSA_TAG_PROTO_DSA,
1a3b39ec
AL
4043 .flags = MV88E6XXX_FLAGS_FAMILY_6390,
4044 .ops = &mv88e6390x_ops,
4045 },
f81ec90f
VD
4046};
4047
5f7c0367 4048static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
b9b37713 4049{
a439c061 4050 int i;
b9b37713 4051
5f7c0367
VD
4052 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
4053 if (mv88e6xxx_table[i].prod_num == prod_num)
4054 return &mv88e6xxx_table[i];
b9b37713 4055
b9b37713
VD
4056 return NULL;
4057}
4058
fad09c73 4059static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
bc46a3d5
VD
4060{
4061 const struct mv88e6xxx_info *info;
8f6345b2
VD
4062 unsigned int prod_num, rev;
4063 u16 id;
4064 int err;
bc46a3d5 4065
8f6345b2
VD
4066 mutex_lock(&chip->reg_lock);
4067 err = mv88e6xxx_port_read(chip, 0, PORT_SWITCH_ID, &id);
4068 mutex_unlock(&chip->reg_lock);
4069 if (err)
4070 return err;
bc46a3d5
VD
4071
4072 prod_num = (id & 0xfff0) >> 4;
4073 rev = id & 0x000f;
4074
4075 info = mv88e6xxx_lookup_info(prod_num);
4076 if (!info)
4077 return -ENODEV;
4078
caac8545 4079 /* Update the compatible info with the probed one */
fad09c73 4080 chip->info = info;
bc46a3d5 4081
ca070c10
VD
4082 err = mv88e6xxx_g2_require(chip);
4083 if (err)
4084 return err;
4085
fad09c73
VD
4086 dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
4087 chip->info->prod_num, chip->info->name, rev);
bc46a3d5
VD
4088
4089 return 0;
4090}
4091
fad09c73 4092static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
469d729f 4093{
fad09c73 4094 struct mv88e6xxx_chip *chip;
469d729f 4095
fad09c73
VD
4096 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
4097 if (!chip)
469d729f
VD
4098 return NULL;
4099
fad09c73 4100 chip->dev = dev;
469d729f 4101
fad09c73 4102 mutex_init(&chip->reg_lock);
469d729f 4103
fad09c73 4104 return chip;
469d729f
VD
4105}
4106
e57e5e77
VD
4107static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
4108{
a199d8b6 4109 if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
e57e5e77 4110 mv88e6xxx_ppu_state_init(chip);
e57e5e77
VD
4111}
4112
930188ce
AL
4113static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
4114{
a199d8b6 4115 if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
930188ce 4116 mv88e6xxx_ppu_state_destroy(chip);
930188ce
AL
4117}
4118
fad09c73 4119static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
4a70c4ab
VD
4120 struct mii_bus *bus, int sw_addr)
4121{
914b32f6 4122 if (sw_addr == 0)
fad09c73 4123 chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
a0ffff24 4124 else if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_MULTI_CHIP))
fad09c73 4125 chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
914b32f6
VD
4126 else
4127 return -EINVAL;
4128
fad09c73
VD
4129 chip->bus = bus;
4130 chip->sw_addr = sw_addr;
4a70c4ab
VD
4131
4132 return 0;
4133}
4134
7b314362
AL
4135static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds)
4136{
04bed143 4137 struct mv88e6xxx_chip *chip = ds->priv;
2bbb33be 4138
443d5a1b 4139 return chip->info->tag_protocol;
7b314362
AL
4140}
4141
fcdce7d0
AL
4142static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
4143 struct device *host_dev, int sw_addr,
4144 void **priv)
a77d43f1 4145{
fad09c73 4146 struct mv88e6xxx_chip *chip;
a439c061 4147 struct mii_bus *bus;
b516d453 4148 int err;
a77d43f1 4149
a439c061 4150 bus = dsa_host_dev_to_mii_bus(host_dev);
c156913b
AL
4151 if (!bus)
4152 return NULL;
4153
fad09c73
VD
4154 chip = mv88e6xxx_alloc_chip(dsa_dev);
4155 if (!chip)
469d729f
VD
4156 return NULL;
4157
caac8545 4158 /* Legacy SMI probing will only support chips similar to 88E6085 */
fad09c73 4159 chip->info = &mv88e6xxx_table[MV88E6085];
caac8545 4160
fad09c73 4161 err = mv88e6xxx_smi_init(chip, bus, sw_addr);
4a70c4ab
VD
4162 if (err)
4163 goto free;
4164
fad09c73 4165 err = mv88e6xxx_detect(chip);
bc46a3d5 4166 if (err)
469d729f 4167 goto free;
a439c061 4168
dc30c35b
AL
4169 mutex_lock(&chip->reg_lock);
4170 err = mv88e6xxx_switch_reset(chip);
4171 mutex_unlock(&chip->reg_lock);
4172 if (err)
4173 goto free;
4174
e57e5e77
VD
4175 mv88e6xxx_phy_init(chip);
4176
fad09c73 4177 err = mv88e6xxx_mdio_register(chip, NULL);
b516d453 4178 if (err)
469d729f 4179 goto free;
b516d453 4180
fad09c73 4181 *priv = chip;
a439c061 4182
fad09c73 4183 return chip->info->name;
469d729f 4184free:
fad09c73 4185 devm_kfree(dsa_dev, chip);
469d729f
VD
4186
4187 return NULL;
a77d43f1
AL
4188}
4189
7df8fbdd
VD
4190static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
4191 const struct switchdev_obj_port_mdb *mdb,
4192 struct switchdev_trans *trans)
4193{
4194 /* We don't need any dynamic resource from the kernel (yet),
4195 * so skip the prepare phase.
4196 */
4197
4198 return 0;
4199}
4200
4201static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
4202 const struct switchdev_obj_port_mdb *mdb,
4203 struct switchdev_trans *trans)
4204{
04bed143 4205 struct mv88e6xxx_chip *chip = ds->priv;
7df8fbdd
VD
4206
4207 mutex_lock(&chip->reg_lock);
4208 if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
4209 GLOBAL_ATU_DATA_STATE_MC_STATIC))
4210 netdev_err(ds->ports[port].netdev, "failed to load multicast MAC address\n");
4211 mutex_unlock(&chip->reg_lock);
4212}
4213
4214static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
4215 const struct switchdev_obj_port_mdb *mdb)
4216{
04bed143 4217 struct mv88e6xxx_chip *chip = ds->priv;
7df8fbdd
VD
4218 int err;
4219
4220 mutex_lock(&chip->reg_lock);
4221 err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
4222 GLOBAL_ATU_DATA_STATE_UNUSED);
4223 mutex_unlock(&chip->reg_lock);
4224
4225 return err;
4226}
4227
4228static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port,
4229 struct switchdev_obj_port_mdb *mdb,
4230 int (*cb)(struct switchdev_obj *obj))
4231{
04bed143 4232 struct mv88e6xxx_chip *chip = ds->priv;
7df8fbdd
VD
4233 int err;
4234
4235 mutex_lock(&chip->reg_lock);
4236 err = mv88e6xxx_port_db_dump(chip, port, &mdb->obj, cb);
4237 mutex_unlock(&chip->reg_lock);
4238
4239 return err;
4240}
4241
a82f67af 4242static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
fcdce7d0 4243 .probe = mv88e6xxx_drv_probe,
7b314362 4244 .get_tag_protocol = mv88e6xxx_get_tag_protocol,
f81ec90f
VD
4245 .setup = mv88e6xxx_setup,
4246 .set_addr = mv88e6xxx_set_addr,
f81ec90f
VD
4247 .adjust_link = mv88e6xxx_adjust_link,
4248 .get_strings = mv88e6xxx_get_strings,
4249 .get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
4250 .get_sset_count = mv88e6xxx_get_sset_count,
4251 .set_eee = mv88e6xxx_set_eee,
4252 .get_eee = mv88e6xxx_get_eee,
f8cd8753 4253 .get_eeprom_len = mv88e6xxx_get_eeprom_len,
f81ec90f
VD
4254 .get_eeprom = mv88e6xxx_get_eeprom,
4255 .set_eeprom = mv88e6xxx_set_eeprom,
4256 .get_regs_len = mv88e6xxx_get_regs_len,
4257 .get_regs = mv88e6xxx_get_regs,
2cfcd964 4258 .set_ageing_time = mv88e6xxx_set_ageing_time,
f81ec90f
VD
4259 .port_bridge_join = mv88e6xxx_port_bridge_join,
4260 .port_bridge_leave = mv88e6xxx_port_bridge_leave,
4261 .port_stp_state_set = mv88e6xxx_port_stp_state_set,
749efcb8 4262 .port_fast_age = mv88e6xxx_port_fast_age,
f81ec90f
VD
4263 .port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
4264 .port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
4265 .port_vlan_add = mv88e6xxx_port_vlan_add,
4266 .port_vlan_del = mv88e6xxx_port_vlan_del,
4267 .port_vlan_dump = mv88e6xxx_port_vlan_dump,
4268 .port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
4269 .port_fdb_add = mv88e6xxx_port_fdb_add,
4270 .port_fdb_del = mv88e6xxx_port_fdb_del,
4271 .port_fdb_dump = mv88e6xxx_port_fdb_dump,
7df8fbdd
VD
4272 .port_mdb_prepare = mv88e6xxx_port_mdb_prepare,
4273 .port_mdb_add = mv88e6xxx_port_mdb_add,
4274 .port_mdb_del = mv88e6xxx_port_mdb_del,
4275 .port_mdb_dump = mv88e6xxx_port_mdb_dump,
f81ec90f
VD
4276};
4277
ab3d408d
FF
4278static struct dsa_switch_driver mv88e6xxx_switch_drv = {
4279 .ops = &mv88e6xxx_switch_ops,
4280};
4281
fad09c73 4282static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip,
b7e66a5f
VD
4283 struct device_node *np)
4284{
fad09c73 4285 struct device *dev = chip->dev;
b7e66a5f
VD
4286 struct dsa_switch *ds;
4287
4288 ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
4289 if (!ds)
4290 return -ENOMEM;
4291
4292 ds->dev = dev;
fad09c73 4293 ds->priv = chip;
9d490b4e 4294 ds->ops = &mv88e6xxx_switch_ops;
b7e66a5f
VD
4295
4296 dev_set_drvdata(dev, ds);
4297
4298 return dsa_register_switch(ds, np);
4299}
4300
fad09c73 4301static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
b7e66a5f 4302{
fad09c73 4303 dsa_unregister_switch(chip->ds);
b7e66a5f
VD
4304}
4305
57d32310 4306static int mv88e6xxx_probe(struct mdio_device *mdiodev)
98e67308 4307{
14c7b3c3 4308 struct device *dev = &mdiodev->dev;
f8cd8753 4309 struct device_node *np = dev->of_node;
caac8545 4310 const struct mv88e6xxx_info *compat_info;
fad09c73 4311 struct mv88e6xxx_chip *chip;
f8cd8753 4312 u32 eeprom_len;
52638f71 4313 int err;
14c7b3c3 4314
caac8545
VD
4315 compat_info = of_device_get_match_data(dev);
4316 if (!compat_info)
4317 return -EINVAL;
4318
fad09c73
VD
4319 chip = mv88e6xxx_alloc_chip(dev);
4320 if (!chip)
14c7b3c3
AL
4321 return -ENOMEM;
4322
fad09c73 4323 chip->info = compat_info;
caac8545 4324
56995cbc
AL
4325 err = mv88e6xxx_verify_madatory_ops(chip, chip->info->ops);
4326 if (err)
4327 return err;
4328
fad09c73 4329 err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
4a70c4ab
VD
4330 if (err)
4331 return err;
14c7b3c3 4332
b4308f04
AL
4333 chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
4334 if (IS_ERR(chip->reset))
4335 return PTR_ERR(chip->reset);
4336
fad09c73 4337 err = mv88e6xxx_detect(chip);
bc46a3d5
VD
4338 if (err)
4339 return err;
14c7b3c3 4340
e57e5e77
VD
4341 mv88e6xxx_phy_init(chip);
4342
ee4dc2e7 4343 if (chip->info->ops->get_eeprom &&
f8cd8753 4344 !of_property_read_u32(np, "eeprom-length", &eeprom_len))
fad09c73 4345 chip->eeprom_len = eeprom_len;
f8cd8753 4346
dc30c35b
AL
4347 mutex_lock(&chip->reg_lock);
4348 err = mv88e6xxx_switch_reset(chip);
4349 mutex_unlock(&chip->reg_lock);
4350 if (err)
4351 goto out;
4352
4353 chip->irq = of_irq_get(np, 0);
4354 if (chip->irq == -EPROBE_DEFER) {
4355 err = chip->irq;
4356 goto out;
4357 }
4358
4359 if (chip->irq > 0) {
4360 /* Has to be performed before the MDIO bus is created,
4361 * because the PHYs will link there interrupts to these
4362 * interrupt controllers
4363 */
4364 mutex_lock(&chip->reg_lock);
4365 err = mv88e6xxx_g1_irq_setup(chip);
4366 mutex_unlock(&chip->reg_lock);
4367
4368 if (err)
4369 goto out;
4370
4371 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) {
4372 err = mv88e6xxx_g2_irq_setup(chip);
4373 if (err)
4374 goto out_g1_irq;
4375 }
4376 }
4377
fad09c73 4378 err = mv88e6xxx_mdio_register(chip, np);
b516d453 4379 if (err)
dc30c35b 4380 goto out_g2_irq;
b516d453 4381
fad09c73 4382 err = mv88e6xxx_register_switch(chip, np);
dc30c35b
AL
4383 if (err)
4384 goto out_mdio;
83c0afae 4385
98e67308 4386 return 0;
dc30c35b
AL
4387
4388out_mdio:
4389 mv88e6xxx_mdio_unregister(chip);
4390out_g2_irq:
46712644 4391 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT) && chip->irq > 0)
dc30c35b
AL
4392 mv88e6xxx_g2_irq_free(chip);
4393out_g1_irq:
61f7c3f8
AL
4394 if (chip->irq > 0) {
4395 mutex_lock(&chip->reg_lock);
46712644 4396 mv88e6xxx_g1_irq_free(chip);
61f7c3f8
AL
4397 mutex_unlock(&chip->reg_lock);
4398 }
dc30c35b
AL
4399out:
4400 return err;
98e67308 4401}
14c7b3c3
AL
4402
4403static void mv88e6xxx_remove(struct mdio_device *mdiodev)
4404{
4405 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
04bed143 4406 struct mv88e6xxx_chip *chip = ds->priv;
14c7b3c3 4407
930188ce 4408 mv88e6xxx_phy_destroy(chip);
fad09c73
VD
4409 mv88e6xxx_unregister_switch(chip);
4410 mv88e6xxx_mdio_unregister(chip);
dc30c35b 4411
46712644
AL
4412 if (chip->irq > 0) {
4413 if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT))
4414 mv88e6xxx_g2_irq_free(chip);
4415 mv88e6xxx_g1_irq_free(chip);
4416 }
14c7b3c3
AL
4417}
4418
4419static const struct of_device_id mv88e6xxx_of_match[] = {
caac8545
VD
4420 {
4421 .compatible = "marvell,mv88e6085",
4422 .data = &mv88e6xxx_table[MV88E6085],
4423 },
1a3b39ec
AL
4424 {
4425 .compatible = "marvell,mv88e6190",
4426 .data = &mv88e6xxx_table[MV88E6190],
4427 },
14c7b3c3
AL
4428 { /* sentinel */ },
4429};
4430
4431MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);
4432
4433static struct mdio_driver mv88e6xxx_driver = {
4434 .probe = mv88e6xxx_probe,
4435 .remove = mv88e6xxx_remove,
4436 .mdiodrv.driver = {
4437 .name = "mv88e6085",
4438 .of_match_table = mv88e6xxx_of_match,
4439 },
4440};
4441
4442static int __init mv88e6xxx_init(void)
4443{
ab3d408d 4444 register_switch_driver(&mv88e6xxx_switch_drv);
14c7b3c3
AL
4445 return mdio_driver_register(&mv88e6xxx_driver);
4446}
98e67308
BH
4447module_init(mv88e6xxx_init);
4448
4449static void __exit mv88e6xxx_cleanup(void)
4450{
14c7b3c3 4451 mdio_driver_unregister(&mv88e6xxx_driver);
ab3d408d 4452 unregister_switch_driver(&mv88e6xxx_switch_drv);
98e67308
BH
4453}
4454module_exit(mv88e6xxx_cleanup);
3d825ede
BH
4455
4456MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
4457MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
4458MODULE_LICENSE("GPL");