chip.c 116.3 KB
Newer Older
1
/*
2 3
 * Marvell 88e6xxx Ethernet switch single-chip support
 *
4 5
 * Copyright (c) 2008 Marvell Semiconductor
 *
6 7
 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
 *
V
Vivien Didelot 已提交
8 9 10
 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
 *
11 12 13 14 15 16
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

17
#include <linux/delay.h>
18
#include <linux/etherdevice.h>
19
#include <linux/ethtool.h>
20
#include <linux/if_bridge.h>
21 22 23
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
24
#include <linux/jiffies.h>
25
#include <linux/list.h>
26
#include <linux/mdio.h>
27
#include <linux/module.h>
28
#include <linux/of_device.h>
29
#include <linux/of_irq.h>
30
#include <linux/of_mdio.h>
31
#include <linux/netdevice.h>
32
#include <linux/gpio/consumer.h>
33
#include <linux/phy.h>
34
#include <net/dsa.h>
35

36
#include "chip.h"
37
#include "global1.h"
38
#include "global2.h"
39
#include "hwtstamp.h"
40
#include "phy.h"
41
#include "port.h"
42
#include "ptp.h"
43
#include "serdes.h"
44

45
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
46
{
47 48
	if (unlikely(!mutex_is_locked(&chip->reg_lock))) {
		dev_err(chip->dev, "Switch registers lock not held!\n");
49 50 51 52
		dump_stack();
	}
}

53 54 55 56 57 58 59 60 61 62
/* The switch ADDR[4:1] configuration pins define the chip SMI device address
 * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
 *
 * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
 * is the only device connected to the SMI master. In this mode it responds to
 * all 32 possible SMI addresses, and thus maps directly the internal devices.
 *
 * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
 * multiple devices to share the SMI interface. In this mode it responds to only
 * 2 registers, used to indirectly access the internal SMI devices.
63
 */
64

65
static int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip,
66 67
			      int addr, int reg, u16 *val)
{
68
	if (!chip->smi_ops)
69 70
		return -EOPNOTSUPP;

71
	return chip->smi_ops->read(chip, addr, reg, val);
72 73
}

74
static int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip,
75 76
			       int addr, int reg, u16 val)
{
77
	if (!chip->smi_ops)
78 79
		return -EOPNOTSUPP;

80
	return chip->smi_ops->write(chip, addr, reg, val);
81 82
}

83
static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_chip *chip,
84 85 86 87
					  int addr, int reg, u16 *val)
{
	int ret;

88
	ret = mdiobus_read_nested(chip->bus, addr, reg);
89 90 91 92 93 94 95 96
	if (ret < 0)
		return ret;

	*val = ret & 0xffff;

	return 0;
}

97
static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_chip *chip,
98 99 100 101
					   int addr, int reg, u16 val)
{
	int ret;

102
	ret = mdiobus_write_nested(chip->bus, addr, reg, val);
103 104 105 106 107 108
	if (ret < 0)
		return ret;

	return 0;
}

109
static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_single_chip_ops = {
110 111 112 113
	.read = mv88e6xxx_smi_single_chip_read,
	.write = mv88e6xxx_smi_single_chip_write,
};

114
static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_chip *chip)
115 116 117 118 119
{
	int ret;
	int i;

	for (i = 0; i < 16; i++) {
120
		ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_CMD);
121 122 123
		if (ret < 0)
			return ret;

124
		if ((ret & SMI_CMD_BUSY) == 0)
125 126 127 128 129 130
			return 0;
	}

	return -ETIMEDOUT;
}

131
static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_chip *chip,
132
					 int addr, int reg, u16 *val)
133 134 135
{
	int ret;

136
	/* Wait for the bus to become free. */
137
	ret = mv88e6xxx_smi_multi_chip_wait(chip);
138 139 140
	if (ret < 0)
		return ret;

141
	/* Transmit the read command. */
142
	ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
143
				   SMI_CMD_OP_22_READ | (addr << 5) | reg);
144 145 146
	if (ret < 0)
		return ret;

147
	/* Wait for the read command to complete. */
148
	ret = mv88e6xxx_smi_multi_chip_wait(chip);
149 150 151
	if (ret < 0)
		return ret;

152
	/* Read the data. */
153
	ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_DATA);
154 155 156
	if (ret < 0)
		return ret;

157
	*val = ret & 0xffff;
158

159
	return 0;
160 161
}

162
static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_chip *chip,
163
					  int addr, int reg, u16 val)
164 165 166
{
	int ret;

167
	/* Wait for the bus to become free. */
168
	ret = mv88e6xxx_smi_multi_chip_wait(chip);
169 170 171
	if (ret < 0)
		return ret;

172
	/* Transmit the data to write. */
173
	ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_DATA, val);
174 175 176
	if (ret < 0)
		return ret;

177
	/* Transmit the write command. */
178
	ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
179
				   SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
180 181 182
	if (ret < 0)
		return ret;

183
	/* Wait for the write command to complete. */
184
	ret = mv88e6xxx_smi_multi_chip_wait(chip);
185 186 187 188 189 190
	if (ret < 0)
		return ret;

	return 0;
}

191
static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_multi_chip_ops = {
192 193 194 195
	.read = mv88e6xxx_smi_multi_chip_read,
	.write = mv88e6xxx_smi_multi_chip_write,
};

196
int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
197 198 199
{
	int err;

200
	assert_reg_lock(chip);
201

202
	err = mv88e6xxx_smi_read(chip, addr, reg, val);
203 204 205
	if (err)
		return err;

206
	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
207 208 209 210 211
		addr, reg, *val);

	return 0;
}

212
int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
213
{
214 215
	int err;

216
	assert_reg_lock(chip);
217

218
	err = mv88e6xxx_smi_write(chip, addr, reg, val);
219 220 221
	if (err)
		return err;

222
	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
223 224
		addr, reg, val);

225 226 227
	return 0;
}

228
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
229 230 231 232 233 234 235 236 237 238 239
{
	struct mv88e6xxx_mdio_bus *mdio_bus;

	mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus,
				    list);
	if (!mdio_bus)
		return NULL;

	return mdio_bus->bus;
}

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
	unsigned int n = d->hwirq;

	chip->g1_irq.masked |= (1 << n);
}

static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
	unsigned int n = d->hwirq;

	chip->g1_irq.masked &= ~(1 << n);
}

static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
{
	struct mv88e6xxx_chip *chip = dev_id;
	unsigned int nhandled = 0;
	unsigned int sub_irq;
	unsigned int n;
	u16 reg;
	int err;

	mutex_lock(&chip->reg_lock);
266
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
	mutex_unlock(&chip->reg_lock);

	if (err)
		goto out;

	for (n = 0; n < chip->g1_irq.nirqs; ++n) {
		if (reg & (1 << n)) {
			sub_irq = irq_find_mapping(chip->g1_irq.domain, n);
			handle_nested_irq(sub_irq);
			++nhandled;
		}
	}
out:
	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}

static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);

	mutex_lock(&chip->reg_lock);
}

static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
	u16 mask = GENMASK(chip->g1_irq.nirqs, 0);
	u16 reg;
	int err;

297
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
298 299 300 301 302 303
	if (err)
		goto out;

	reg &= ~mask;
	reg |= (~chip->g1_irq.masked & mask);

304
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
305 306 307 308 309 310 311
	if (err)
		goto out;

out:
	mutex_unlock(&chip->reg_lock);
}

312
static const struct irq_chip mv88e6xxx_g1_irq_chip = {
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	.name			= "mv88e6xxx-g1",
	.irq_mask		= mv88e6xxx_g1_irq_mask,
	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
};

static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d,
				       unsigned int irq,
				       irq_hw_number_t hwirq)
{
	struct mv88e6xxx_chip *chip = d->host_data;

	irq_set_chip_data(irq, d->host_data);
	irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq);
	irq_set_noprobe(irq);

	return 0;
}

static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
	.map	= mv88e6xxx_g1_irq_domain_map,
	.xlate	= irq_domain_xlate_twocell,
};

static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
{
	int irq, virq;
341 342
	u16 mask;

343
	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
344
	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
345
	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
346 347

	free_irq(chip->irq, chip);
348

349
	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
350
		virq = irq_find_mapping(chip->g1_irq.domain, irq);
351 352 353
		irq_dispose_mapping(virq);
	}

354
	irq_domain_remove(chip->g1_irq.domain);
355 356 357 358
}

static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
{
359 360
	int err, irq, virq;
	u16 reg, mask;
361 362 363 364 365 366 367 368 369 370 371 372 373 374

	chip->g1_irq.nirqs = chip->info->g1_irqs;
	chip->g1_irq.domain = irq_domain_add_simple(
		NULL, chip->g1_irq.nirqs, 0,
		&mv88e6xxx_g1_irq_domain_ops, chip);
	if (!chip->g1_irq.domain)
		return -ENOMEM;

	for (irq = 0; irq < chip->g1_irq.nirqs; irq++)
		irq_create_mapping(chip->g1_irq.domain, irq);

	chip->g1_irq.chip = mv88e6xxx_g1_irq_chip;
	chip->g1_irq.masked = ~0;

375
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
376
	if (err)
377
		goto out_mapping;
378

379
	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
380

381
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
382
	if (err)
383
		goto out_disable;
384 385

	/* Reading the interrupt status clears (most of) them */
386
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
387
	if (err)
388
		goto out_disable;
389 390 391 392 393 394

	err = request_threaded_irq(chip->irq, NULL,
				   mv88e6xxx_g1_irq_thread_fn,
				   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
				   dev_name(chip->dev), chip);
	if (err)
395
		goto out_disable;
396 397 398

	return 0;

399
out_disable:
400
	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
401
	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
402 403 404 405 406 407 408 409

out_mapping:
	for (irq = 0; irq < 16; irq++) {
		virq = irq_find_mapping(chip->g1_irq.domain, irq);
		irq_dispose_mapping(virq);
	}

	irq_domain_remove(chip->g1_irq.domain);
410 411 412 413

	return err;
}

414
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
415
{
416
	int i;
417

418
	for (i = 0; i < 16; i++) {
419 420 421 422 423 424 425 426 427 428 429 430 431
		u16 val;
		int err;

		err = mv88e6xxx_read(chip, addr, reg, &val);
		if (err)
			return err;

		if (!(val & mask))
			return 0;

		usleep_range(1000, 2000);
	}

432
	dev_err(chip->dev, "Timeout while waiting for switch\n");
433 434 435
	return -ETIMEDOUT;
}

436
/* Indirect write to single pointer-data register with an Update bit */
437
int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
438 439
{
	u16 val;
440
	int err;
441 442

	/* Wait until the previous operation is completed */
443 444 445
	err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
	if (err)
		return err;
446 447 448 449 450 451 452

	/* Set the Update bit to trigger a write operation */
	val = BIT(15) | update;

	return mv88e6xxx_write(chip, addr, reg, val);
}

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
				    int link, int speed, int duplex,
				    phy_interface_t mode)
{
	int err;

	if (!chip->info->ops->port_set_link)
		return 0;

	/* Port's MAC control must not be changed unless the link is down */
	err = chip->info->ops->port_set_link(chip, port, 0);
	if (err)
		return err;

	if (chip->info->ops->port_set_speed) {
		err = chip->info->ops->port_set_speed(chip, port, speed);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

	if (chip->info->ops->port_set_duplex) {
		err = chip->info->ops->port_set_duplex(chip, port, duplex);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

	if (chip->info->ops->port_set_rgmii_delay) {
		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

485 486 487 488 489 490
	if (chip->info->ops->port_set_cmode) {
		err = chip->info->ops->port_set_cmode(chip, port, mode);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

491 492 493
	err = 0;
restore_link:
	if (chip->info->ops->port_set_link(chip, port, link))
494
		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
495 496 497 498

	return err;
}

499 500 501 502
/* We expect the switch to perform auto negotiation if there is a real
 * phy. However, in the case of a fixed link phy, we force the port
 * settings from the fixed link settings.
 */
503 504
static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
				  struct phy_device *phydev)
505
{
V
Vivien Didelot 已提交
506
	struct mv88e6xxx_chip *chip = ds->priv;
507
	int err;
508 509 510 511

	if (!phy_is_pseudo_fixed_link(phydev))
		return;

512
	mutex_lock(&chip->reg_lock);
513 514
	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
				       phydev->duplex, phydev->interface);
515
	mutex_unlock(&chip->reg_lock);
516 517

	if (err && err != -EOPNOTSUPP)
518
		dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
519 520
}

521
static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
522
{
523 524
	if (!chip->info->ops->stats_snapshot)
		return -EOPNOTSUPP;
525

526
	return chip->info->ops->stats_snapshot(chip, port);
527 528
}

529
static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
	{ "in_good_octets",		8, 0x00, STATS_TYPE_BANK0, },
	{ "in_bad_octets",		4, 0x02, STATS_TYPE_BANK0, },
	{ "in_unicast",			4, 0x04, STATS_TYPE_BANK0, },
	{ "in_broadcasts",		4, 0x06, STATS_TYPE_BANK0, },
	{ "in_multicasts",		4, 0x07, STATS_TYPE_BANK0, },
	{ "in_pause",			4, 0x16, STATS_TYPE_BANK0, },
	{ "in_undersize",		4, 0x18, STATS_TYPE_BANK0, },
	{ "in_fragments",		4, 0x19, STATS_TYPE_BANK0, },
	{ "in_oversize",		4, 0x1a, STATS_TYPE_BANK0, },
	{ "in_jabber",			4, 0x1b, STATS_TYPE_BANK0, },
	{ "in_rx_error",		4, 0x1c, STATS_TYPE_BANK0, },
	{ "in_fcs_error",		4, 0x1d, STATS_TYPE_BANK0, },
	{ "out_octets",			8, 0x0e, STATS_TYPE_BANK0, },
	{ "out_unicast",		4, 0x10, STATS_TYPE_BANK0, },
	{ "out_broadcasts",		4, 0x13, STATS_TYPE_BANK0, },
	{ "out_multicasts",		4, 0x12, STATS_TYPE_BANK0, },
	{ "out_pause",			4, 0x15, STATS_TYPE_BANK0, },
	{ "excessive",			4, 0x11, STATS_TYPE_BANK0, },
	{ "collisions",			4, 0x1e, STATS_TYPE_BANK0, },
	{ "deferred",			4, 0x05, STATS_TYPE_BANK0, },
	{ "single",			4, 0x14, STATS_TYPE_BANK0, },
	{ "multiple",			4, 0x17, STATS_TYPE_BANK0, },
	{ "out_fcs_error",		4, 0x03, STATS_TYPE_BANK0, },
	{ "late",			4, 0x1f, STATS_TYPE_BANK0, },
	{ "hist_64bytes",		4, 0x08, STATS_TYPE_BANK0, },
	{ "hist_65_127bytes",		4, 0x09, STATS_TYPE_BANK0, },
	{ "hist_128_255bytes",		4, 0x0a, STATS_TYPE_BANK0, },
	{ "hist_256_511bytes",		4, 0x0b, STATS_TYPE_BANK0, },
	{ "hist_512_1023bytes",		4, 0x0c, STATS_TYPE_BANK0, },
	{ "hist_1024_max_bytes",	4, 0x0d, STATS_TYPE_BANK0, },
	{ "sw_in_discards",		4, 0x10, STATS_TYPE_PORT, },
	{ "sw_in_filtered",		2, 0x12, STATS_TYPE_PORT, },
	{ "sw_out_filtered",		2, 0x13, STATS_TYPE_PORT, },
	{ "in_discards",		4, 0x00, STATS_TYPE_BANK1, },
	{ "in_filtered",		4, 0x01, STATS_TYPE_BANK1, },
	{ "in_accepted",		4, 0x02, STATS_TYPE_BANK1, },
	{ "in_bad_accepted",		4, 0x03, STATS_TYPE_BANK1, },
	{ "in_good_avb_class_a",	4, 0x04, STATS_TYPE_BANK1, },
	{ "in_good_avb_class_b",	4, 0x05, STATS_TYPE_BANK1, },
	{ "in_bad_avb_class_a",		4, 0x06, STATS_TYPE_BANK1, },
	{ "in_bad_avb_class_b",		4, 0x07, STATS_TYPE_BANK1, },
	{ "tcam_counter_0",		4, 0x08, STATS_TYPE_BANK1, },
	{ "tcam_counter_1",		4, 0x09, STATS_TYPE_BANK1, },
	{ "tcam_counter_2",		4, 0x0a, STATS_TYPE_BANK1, },
	{ "tcam_counter_3",		4, 0x0b, STATS_TYPE_BANK1, },
	{ "in_da_unknown",		4, 0x0e, STATS_TYPE_BANK1, },
	{ "in_management",		4, 0x0f, STATS_TYPE_BANK1, },
	{ "out_queue_0",		4, 0x10, STATS_TYPE_BANK1, },
	{ "out_queue_1",		4, 0x11, STATS_TYPE_BANK1, },
	{ "out_queue_2",		4, 0x12, STATS_TYPE_BANK1, },
	{ "out_queue_3",		4, 0x13, STATS_TYPE_BANK1, },
	{ "out_queue_4",		4, 0x14, STATS_TYPE_BANK1, },
	{ "out_queue_5",		4, 0x15, STATS_TYPE_BANK1, },
	{ "out_queue_6",		4, 0x16, STATS_TYPE_BANK1, },
	{ "out_queue_7",		4, 0x17, STATS_TYPE_BANK1, },
	{ "out_cut_through",		4, 0x18, STATS_TYPE_BANK1, },
	{ "out_octets_a",		4, 0x1a, STATS_TYPE_BANK1, },
	{ "out_octets_b",		4, 0x1b, STATS_TYPE_BANK1, },
	{ "out_management",		4, 0x1f, STATS_TYPE_BANK1, },
589 590
};

591
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
592
					    struct mv88e6xxx_hw_stat *s,
593 594
					    int port, u16 bank1_select,
					    u16 histogram)
595 596 597
{
	u32 low;
	u32 high = 0;
598
	u16 reg = 0;
599
	int err;
600 601
	u64 value;

602
	switch (s->type) {
603
	case STATS_TYPE_PORT:
604 605
		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
		if (err)
606 607
			return UINT64_MAX;

608
		low = reg;
609
		if (s->sizeof_stat == 4) {
610 611
			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
			if (err)
612
				return UINT64_MAX;
613
			high = reg;
614
		}
615
		break;
616
	case STATS_TYPE_BANK1:
617
		reg = bank1_select;
618 619
		/* fall through */
	case STATS_TYPE_BANK0:
620
		reg |= s->reg | histogram;
621
		mv88e6xxx_g1_stats_read(chip, reg, &low);
622
		if (s->sizeof_stat == 8)
623
			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
624 625 626
		break;
	default:
		return UINT64_MAX;
627 628 629 630 631
	}
	value = (((u64)high) << 16) | low;
	return value;
}

632 633
static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
					uint8_t *data, int types)
634
{
635 636
	struct mv88e6xxx_hw_stat *stat;
	int i, j;
637

638 639
	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
		stat = &mv88e6xxx_hw_stats[i];
640
		if (stat->type & types) {
641 642 643 644
			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
			       ETH_GSTRING_LEN);
			j++;
		}
645
	}
646 647
}

648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
					uint8_t *data)
{
	mv88e6xxx_stats_get_strings(chip, data,
				    STATS_TYPE_BANK0 | STATS_TYPE_PORT);
}

static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
					uint8_t *data)
{
	mv88e6xxx_stats_get_strings(chip, data,
				    STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
}

static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
				  uint8_t *data)
664
{
V
Vivien Didelot 已提交
665
	struct mv88e6xxx_chip *chip = ds->priv;
666 667 668 669 670 671 672 673

	if (chip->info->ops->stats_get_strings)
		chip->info->ops->stats_get_strings(chip, data);
}

static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
					  int types)
{
674 675 676 677 678
	struct mv88e6xxx_hw_stat *stat;
	int i, j;

	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
		stat = &mv88e6xxx_hw_stats[i];
679
		if (stat->type & types)
680 681 682
			j++;
	}
	return j;
683 684
}

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
					      STATS_TYPE_PORT);
}

static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
					      STATS_TYPE_BANK1);
}

static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
{
	struct mv88e6xxx_chip *chip = ds->priv;

	if (chip->info->ops->stats_get_sset_count)
		return chip->info->ops->stats_get_sset_count(chip);

	return 0;
}

707
static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
708 709
				      uint64_t *data, int types,
				      u16 bank1_select, u16 histogram)
710 711 712 713 714 715 716
{
	struct mv88e6xxx_hw_stat *stat;
	int i, j;

	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
		stat = &mv88e6xxx_hw_stats[i];
		if (stat->type & types) {
717 718 719
			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
							      bank1_select,
							      histogram);
720 721 722 723 724 725 726 727 728
			j++;
		}
	}
}

static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				      uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
729
					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
730
					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
731 732 733 734 735 736
}

static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				      uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
737
					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
738 739
					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
740 741 742 743 744 745 746
}

static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				      uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
747 748
					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
					 0);
749 750 751 752 753 754 755 756 757
}

static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
				uint64_t *data)
{
	if (chip->info->ops->stats_get_stats)
		chip->info->ops->stats_get_stats(chip, port, data);
}

758 759
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
					uint64_t *data)
760
{
V
Vivien Didelot 已提交
761
	struct mv88e6xxx_chip *chip = ds->priv;
762 763
	int ret;

764
	mutex_lock(&chip->reg_lock);
765

766
	ret = mv88e6xxx_stats_snapshot(chip, port);
767
	if (ret < 0) {
768
		mutex_unlock(&chip->reg_lock);
769 770
		return;
	}
771 772

	mv88e6xxx_get_stats(chip, port, data);
773

774
	mutex_unlock(&chip->reg_lock);
775 776
}

777 778 779 780 781 782 783 784
static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->stats_set_histogram)
		return chip->info->ops->stats_set_histogram(chip);

	return 0;
}

785
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
786 787 788 789
{
	return 32 * sizeof(u16);
}

790 791
static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
			       struct ethtool_regs *regs, void *_p)
792
{
V
Vivien Didelot 已提交
793
	struct mv88e6xxx_chip *chip = ds->priv;
794 795
	int err;
	u16 reg;
796 797 798 799 800 801 802
	u16 *p = _p;
	int i;

	regs->version = 0;

	memset(p, 0xff, 32 * sizeof(u16));

803
	mutex_lock(&chip->reg_lock);
804

805 806
	for (i = 0; i < 32; i++) {

807 808 809
		err = mv88e6xxx_port_read(chip, port, i, &reg);
		if (!err)
			p[i] = reg;
810
	}
811

812
	mutex_unlock(&chip->reg_lock);
813 814
}

V
Vivien Didelot 已提交
815 816
static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
				 struct ethtool_eee *e)
817
{
818 819
	/* Nothing to do on the port's MAC */
	return 0;
820 821
}

V
Vivien Didelot 已提交
822 823
static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
				 struct ethtool_eee *e)
824
{
825 826
	/* Nothing to do on the port's MAC */
	return 0;
827 828
}

829
static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
830
{
831 832 833
	struct dsa_switch *ds = NULL;
	struct net_device *br;
	u16 pvlan;
834 835
	int i;

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
	if (dev < DSA_MAX_SWITCHES)
		ds = chip->ds->dst->ds[dev];

	/* Prevent frames from unknown switch or port */
	if (!ds || port >= ds->num_ports)
		return 0;

	/* Frames from DSA links and CPU ports can egress any local port */
	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
		return mv88e6xxx_port_mask(chip);

	br = ds->ports[port].bridge_dev;
	pvlan = 0;

	/* Frames from user ports can egress any local DSA links and CPU ports,
	 * as well as any local member of their bridge group.
	 */
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
		if (dsa_is_cpu_port(chip->ds, i) ||
		    dsa_is_dsa_port(chip->ds, i) ||
V
Vivien Didelot 已提交
856
		    (br && dsa_to_port(chip->ds, i)->bridge_dev == br))
857 858 859 860 861
			pvlan |= BIT(i);

	return pvlan;
}

862
static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
863 864
{
	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
865 866 867

	/* prevent frames from going back out of the port they came in on */
	output_ports &= ~BIT(port);
868

869
	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
870 871
}

872 873
static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
					 u8 state)
874
{
V
Vivien Didelot 已提交
875
	struct mv88e6xxx_chip *chip = ds->priv;
876
	int err;
877

878
	mutex_lock(&chip->reg_lock);
879
	err = mv88e6xxx_port_set_state(chip, port, state);
880
	mutex_unlock(&chip->reg_lock);
881 882

	if (err)
883
		dev_err(ds->dev, "p%d: failed to update state\n", port);
884 885
}

886 887 888 889 890 891 892 893
static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->pot_clear)
		return chip->info->ops->pot_clear(chip);

	return 0;
}

894 895 896 897 898 899 900 901
static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->mgmt_rsvd2cpu)
		return chip->info->ops->mgmt_rsvd2cpu(chip);

	return 0;
}

902 903
static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
{
904 905
	int err;

906 907 908 909
	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
	if (err)
		return err;

910 911 912 913
	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
	if (err)
		return err;

914 915 916
	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
}

917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip)
{
	int port;
	int err;

	if (!chip->info->ops->irl_init_all)
		return 0;

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
		/* Disable ingress rate limiting by resetting all per port
		 * ingress rate limit resources to their initial state.
		 */
		err = chip->info->ops->irl_init_all(chip, port);
		if (err)
			return err;
	}

	return 0;
}

937 938 939 940 941 942 943 944 945 946 947 948 949
static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->set_switch_mac) {
		u8 addr[ETH_ALEN];

		eth_random_addr(addr);

		return chip->info->ops->set_switch_mac(chip, addr);
	}

	return 0;
}

950 951 952 953 954 955 956 957 958
static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
{
	u16 pvlan = 0;

	if (!mv88e6xxx_has_pvt(chip))
		return -EOPNOTSUPP;

	/* Skip the local source device, which uses in-chip port VLAN */
	if (dev != chip->ds->index)
959
		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
960 961 962 963

	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
}

964 965
static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
{
966 967 968
	int dev, port;
	int err;

969 970 971 972 973 974
	if (!mv88e6xxx_has_pvt(chip))
		return 0;

	/* Clear 5 Bit Port for usage with Marvell Link Street devices:
	 * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev.
	 */
975 976 977 978 979 980 981 982 983 984 985 986 987
	err = mv88e6xxx_g2_misc_4_bit_port(chip);
	if (err)
		return err;

	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) {
		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) {
			err = mv88e6xxx_pvt_map(chip, dev, port);
			if (err)
				return err;
		}
	}

	return 0;
988 989
}

990 991 992 993 994 995
static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

	mutex_lock(&chip->reg_lock);
996
	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
997 998 999
	mutex_unlock(&chip->reg_lock);

	if (err)
1000
		dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
1001 1002
}

1003 1004 1005 1006 1007 1008 1009 1010
static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
{
	if (!chip->info->max_vid)
		return 0;

	return mv88e6xxx_g1_vtu_flush(chip);
}

1011 1012 1013 1014 1015 1016 1017 1018 1019
static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
				 struct mv88e6xxx_vtu_entry *entry)
{
	if (!chip->info->ops->vtu_getnext)
		return -EOPNOTSUPP;

	return chip->info->ops->vtu_getnext(chip, entry);
}

1020 1021 1022 1023 1024 1025 1026 1027 1028
static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
				   struct mv88e6xxx_vtu_entry *entry)
{
	if (!chip->info->ops->vtu_loadpurge)
		return -EOPNOTSUPP;

	return chip->info->ops->vtu_loadpurge(chip, entry);
}

1029
static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1030 1031
{
	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
1032 1033 1034
	struct mv88e6xxx_vtu_entry vlan = {
		.vid = chip->info->max_vid,
	};
1035
	int i, err;
1036 1037 1038

	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);

1039
	/* Set every FID bit used by the (un)bridged ports */
1040
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1041
		err = mv88e6xxx_port_get_fid(chip, i, fid);
1042 1043 1044 1045 1046 1047
		if (err)
			return err;

		set_bit(*fid, fid_bitmap);
	}

1048 1049
	/* Set every FID bit used by the VLAN entries */
	do {
1050
		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1051 1052 1053 1054 1055 1056 1057
		if (err)
			return err;

		if (!vlan.valid)
			break;

		set_bit(vlan.fid, fid_bitmap);
1058
	} while (vlan.vid < chip->info->max_vid);
1059 1060 1061 1062 1063

	/* The reset value 0x000 is used to indicate that multiple address
	 * databases are not needed. Return the next positive available.
	 */
	*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
1064
	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1065 1066 1067
		return -ENOSPC;

	/* Clear the database */
1068
	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1069 1070
}

1071 1072
static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
			     struct mv88e6xxx_vtu_entry *entry, bool new)
1073 1074 1075 1076 1077 1078
{
	int err;

	if (!vid)
		return -EINVAL;

1079 1080
	entry->vid = vid - 1;
	entry->valid = false;
1081

1082
	err = mv88e6xxx_vtu_getnext(chip, entry);
1083 1084 1085
	if (err)
		return err;

1086 1087
	if (entry->vid == vid && entry->valid)
		return 0;
1088

1089 1090 1091 1092 1093 1094 1095 1096
	if (new) {
		int i;

		/* Initialize a fresh VLAN entry */
		memset(entry, 0, sizeof(*entry));
		entry->valid = true;
		entry->vid = vid;

1097
		/* Exclude all ports */
1098
		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1099
			entry->member[i] =
1100
				MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1101 1102

		return mv88e6xxx_atu_new(chip, &entry->fid);
1103 1104
	}

1105 1106
	/* switchdev expects -EOPNOTSUPP to honor software VLANs */
	return -EOPNOTSUPP;
1107 1108
}

1109 1110 1111
static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
					u16 vid_begin, u16 vid_end)
{
V
Vivien Didelot 已提交
1112
	struct mv88e6xxx_chip *chip = ds->priv;
1113 1114 1115
	struct mv88e6xxx_vtu_entry vlan = {
		.vid = vid_begin - 1,
	};
1116 1117
	int i, err;

1118 1119 1120 1121
	/* DSA and CPU ports have to be members of multiple vlans */
	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
		return 0;

1122 1123 1124
	if (!vid_begin)
		return -EOPNOTSUPP;

1125
	mutex_lock(&chip->reg_lock);
1126 1127

	do {
1128
		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1129 1130 1131 1132 1133 1134 1135 1136 1137
		if (err)
			goto unlock;

		if (!vlan.valid)
			break;

		if (vlan.vid > vid_end)
			break;

1138
		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1139 1140 1141
			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
				continue;

1142
			if (!ds->ports[i].slave)
1143 1144
				continue;

1145
			if (vlan.member[i] ==
1146
			    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1147 1148
				continue;

V
Vivien Didelot 已提交
1149
			if (dsa_to_port(ds, i)->bridge_dev ==
1150
			    ds->ports[port].bridge_dev)
1151 1152
				break; /* same bridge, check next VLAN */

V
Vivien Didelot 已提交
1153
			if (!dsa_to_port(ds, i)->bridge_dev)
1154 1155
				continue;

1156 1157
			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
				port, vlan.vid, i,
V
Vivien Didelot 已提交
1158
				netdev_name(dsa_to_port(ds, i)->bridge_dev));
1159 1160 1161 1162 1163 1164
			err = -EOPNOTSUPP;
			goto unlock;
		}
	} while (vlan.vid < vid_end);

unlock:
1165
	mutex_unlock(&chip->reg_lock);
1166 1167 1168 1169

	return err;
}

1170 1171
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
					 bool vlan_filtering)
1172
{
V
Vivien Didelot 已提交
1173
	struct mv88e6xxx_chip *chip = ds->priv;
1174 1175
	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
1176
	int err;
1177

1178
	if (!chip->info->max_vid)
1179 1180
		return -EOPNOTSUPP;

1181
	mutex_lock(&chip->reg_lock);
1182
	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1183
	mutex_unlock(&chip->reg_lock);
1184

1185
	return err;
1186 1187
}

1188 1189
static int
mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
1190
			    const struct switchdev_obj_port_vlan *vlan)
1191
{
V
Vivien Didelot 已提交
1192
	struct mv88e6xxx_chip *chip = ds->priv;
1193 1194
	int err;

1195
	if (!chip->info->max_vid)
1196 1197
		return -EOPNOTSUPP;

1198 1199 1200 1201 1202 1203 1204 1205
	/* If the requested port doesn't belong to the same bridge as the VLAN
	 * members, do not support it (yet) and fallback to software VLAN.
	 */
	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
					   vlan->vid_end);
	if (err)
		return err;

1206 1207 1208 1209 1210 1211
	/* We don't need any dynamic resource from the kernel (yet),
	 * so skip the prepare phase.
	 */
	return 0;
}

1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
					const unsigned char *addr, u16 vid,
					u8 state)
{
	struct mv88e6xxx_vtu_entry vlan;
	struct mv88e6xxx_atu_entry entry;
	int err;

	/* Null VLAN ID corresponds to the port private database */
	if (vid == 0)
		err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
	else
		err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
	if (err)
		return err;

	entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
	ether_addr_copy(entry.mac, addr);
	eth_addr_dec(entry.mac);

	err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
	if (err)
		return err;

	/* Initialize a fresh ATU entry if it isn't found */
	if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
	    !ether_addr_equal(entry.mac, addr)) {
		memset(&entry, 0, sizeof(entry));
		ether_addr_copy(entry.mac, addr);
	}

	/* Purge the ATU entry only if no port is using it anymore */
	if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
		entry.portvec &= ~BIT(port);
		if (!entry.portvec)
			entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
	} else {
		entry.portvec |= BIT(port);
		entry.state = state;
	}

	return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
}

1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
					u16 vid)
{
	const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;

	return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
}

static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
{
	int port;
	int err;

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
		if (err)
			return err;
	}

	return 0;
}

1279
static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
1280
				    u16 vid, u8 member)
1281
{
1282
	struct mv88e6xxx_vtu_entry vlan;
1283 1284
	int err;

1285
	err = mv88e6xxx_vtu_get(chip, vid, &vlan, true);
1286
	if (err)
1287
		return err;
1288

1289
	vlan.member[port] = member;
1290

1291 1292 1293 1294 1295
	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
	if (err)
		return err;

	return mv88e6xxx_broadcast_setup(chip, vid);
1296 1297
}

1298
static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
1299
				    const struct switchdev_obj_port_vlan *vlan)
1300
{
V
Vivien Didelot 已提交
1301
	struct mv88e6xxx_chip *chip = ds->priv;
1302 1303
	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1304
	u8 member;
1305 1306
	u16 vid;

1307
	if (!chip->info->max_vid)
1308 1309
		return;

1310
	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1311
		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1312
	else if (untagged)
1313
		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
1314
	else
1315
		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
1316

1317
	mutex_lock(&chip->reg_lock);
1318

1319
	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1320
		if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
1321 1322
			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
				vid, untagged ? 'u' : 't');
1323

1324
	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1325 1326
		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
			vlan->vid_end);
1327

1328
	mutex_unlock(&chip->reg_lock);
1329 1330
}

1331
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
1332
				    int port, u16 vid)
1333
{
1334
	struct mv88e6xxx_vtu_entry vlan;
1335 1336
	int i, err;

1337
	err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1338
	if (err)
1339
		return err;
1340

1341
	/* Tell switchdev if this VLAN is handled in software */
1342
	if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1343
		return -EOPNOTSUPP;
1344

1345
	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1346 1347

	/* keep the VLAN unless all ports are excluded */
1348
	vlan.valid = false;
1349
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1350 1351
		if (vlan.member[i] !=
		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1352
			vlan.valid = true;
1353 1354 1355 1356
			break;
		}
	}

1357
	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1358 1359 1360
	if (err)
		return err;

1361
	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1362 1363
}

1364 1365
static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
				   const struct switchdev_obj_port_vlan *vlan)
1366
{
V
Vivien Didelot 已提交
1367
	struct mv88e6xxx_chip *chip = ds->priv;
1368 1369 1370
	u16 pvid, vid;
	int err = 0;

1371
	if (!chip->info->max_vid)
1372 1373
		return -EOPNOTSUPP;

1374
	mutex_lock(&chip->reg_lock);
1375

1376
	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1377 1378 1379
	if (err)
		goto unlock;

1380
	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1381
		err = _mv88e6xxx_port_vlan_del(chip, port, vid);
1382 1383 1384 1385
		if (err)
			goto unlock;

		if (vid == pvid) {
1386
			err = mv88e6xxx_port_set_pvid(chip, port, 0);
1387 1388 1389 1390 1391
			if (err)
				goto unlock;
		}
	}

1392
unlock:
1393
	mutex_unlock(&chip->reg_lock);
1394 1395 1396 1397

	return err;
}

1398 1399
static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
				  const unsigned char *addr, u16 vid)
1400
{
V
Vivien Didelot 已提交
1401
	struct mv88e6xxx_chip *chip = ds->priv;
1402
	int err;
1403

1404
	mutex_lock(&chip->reg_lock);
1405 1406
	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
1407
	mutex_unlock(&chip->reg_lock);
1408 1409

	return err;
1410 1411
}

1412
static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
1413
				  const unsigned char *addr, u16 vid)
1414
{
V
Vivien Didelot 已提交
1415
	struct mv88e6xxx_chip *chip = ds->priv;
1416
	int err;
1417

1418
	mutex_lock(&chip->reg_lock);
1419
	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
1420
					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
1421
	mutex_unlock(&chip->reg_lock);
1422

1423
	return err;
1424 1425
}

1426 1427
static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
				      u16 fid, u16 vid, int port,
1428
				      dsa_fdb_dump_cb_t *cb, void *data)
1429
{
1430
	struct mv88e6xxx_atu_entry addr;
1431
	bool is_static;
1432 1433
	int err;

1434
	addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1435
	eth_broadcast_addr(addr.mac);
1436 1437

	do {
1438
		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
1439
		if (err)
1440
			return err;
1441

1442
		if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
1443 1444
			break;

1445
		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
1446 1447
			continue;

1448 1449
		if (!is_unicast_ether_addr(addr.mac))
			continue;
1450

1451 1452 1453
		is_static = (addr.state ==
			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
		err = cb(addr.mac, vid, is_static, data);
1454 1455
		if (err)
			return err;
1456 1457 1458 1459 1460
	} while (!is_broadcast_ether_addr(addr.mac));

	return err;
}

1461
static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
1462
				  dsa_fdb_dump_cb_t *cb, void *data)
1463
{
1464
	struct mv88e6xxx_vtu_entry vlan = {
1465
		.vid = chip->info->max_vid,
1466
	};
1467
	u16 fid;
1468 1469
	int err;

1470
	/* Dump port's default Filtering Information Database (VLAN ID 0) */
1471
	err = mv88e6xxx_port_get_fid(chip, port, &fid);
1472
	if (err)
1473
		return err;
1474

1475
	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
1476
	if (err)
1477
		return err;
1478

1479
	/* Dump VLANs' Filtering Information Databases */
1480
	do {
1481
		err = mv88e6xxx_vtu_getnext(chip, &vlan);
1482
		if (err)
1483
			return err;
1484 1485 1486 1487

		if (!vlan.valid)
			break;

1488
		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
1489
						 cb, data);
1490
		if (err)
1491
			return err;
1492
	} while (vlan.vid < chip->info->max_vid);
1493

1494 1495 1496 1497
	return err;
}

static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
1498
				   dsa_fdb_dump_cb_t *cb, void *data)
1499
{
V
Vivien Didelot 已提交
1500
	struct mv88e6xxx_chip *chip = ds->priv;
1501 1502 1503
	int err;

	mutex_lock(&chip->reg_lock);
1504
	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
1505
	mutex_unlock(&chip->reg_lock);
1506 1507 1508 1509

	return err;
}

1510 1511
static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
				struct net_device *br)
1512
{
1513
	struct dsa_switch *ds;
1514
	int port;
1515
	int dev;
1516
	int err;
1517

1518 1519 1520 1521
	/* Remap the Port VLAN of each local bridge group member */
	for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) {
		if (chip->ds->ports[port].bridge_dev == br) {
			err = mv88e6xxx_port_vlan_map(chip, port);
1522
			if (err)
1523
				return err;
1524 1525 1526
		}
	}

1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
	if (!mv88e6xxx_has_pvt(chip))
		return 0;

	/* Remap the Port VLAN of each cross-chip bridge group member */
	for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) {
		ds = chip->ds->dst->ds[dev];
		if (!ds)
			break;

		for (port = 0; port < ds->num_ports; ++port) {
			if (ds->ports[port].bridge_dev == br) {
				err = mv88e6xxx_pvt_map(chip, dev, port);
				if (err)
					return err;
			}
		}
	}

1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
	return 0;
}

static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
				      struct net_device *br)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_bridge_map(chip, br);
1556
	mutex_unlock(&chip->reg_lock);
1557

1558
	return err;
1559 1560
}

1561 1562
static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
					struct net_device *br)
1563
{
V
Vivien Didelot 已提交
1564
	struct mv88e6xxx_chip *chip = ds->priv;
1565

1566
	mutex_lock(&chip->reg_lock);
1567 1568 1569
	if (mv88e6xxx_bridge_map(chip, br) ||
	    mv88e6xxx_port_vlan_map(chip, port))
		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
1570
	mutex_unlock(&chip->reg_lock);
1571 1572
}

1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
					   int port, struct net_device *br)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

	if (!mv88e6xxx_has_pvt(chip))
		return 0;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_pvt_map(chip, dev, port);
	mutex_unlock(&chip->reg_lock);

	return err;
}

static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
					     int port, struct net_device *br)
{
	struct mv88e6xxx_chip *chip = ds->priv;

	if (!mv88e6xxx_has_pvt(chip))
		return;

	mutex_lock(&chip->reg_lock);
	if (mv88e6xxx_pvt_map(chip, dev, port))
		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
	mutex_unlock(&chip->reg_lock);
}

1603 1604 1605 1606 1607 1608 1609 1610
static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->reset)
		return chip->info->ops->reset(chip);

	return 0;
}

1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
{
	struct gpio_desc *gpiod = chip->reset;

	/* If there is a GPIO connected to the reset pin, toggle it */
	if (gpiod) {
		gpiod_set_value_cansleep(gpiod, 1);
		usleep_range(10000, 20000);
		gpiod_set_value_cansleep(gpiod, 0);
		usleep_range(10000, 20000);
	}
}

1624
static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
1625
{
1626
	int i, err;
1627

1628
	/* Set all ports to the Disabled state */
1629
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
1630
		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
1631 1632
		if (err)
			return err;
1633 1634
	}

1635 1636 1637
	/* Wait for transmit queues to drain,
	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
	 */
1638 1639
	usleep_range(2000, 4000);

1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
	return 0;
}

static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
{
	int err;

	err = mv88e6xxx_disable_ports(chip);
	if (err)
		return err;

1651
	mv88e6xxx_hardware_reset(chip);
1652

1653
	return mv88e6xxx_software_reset(chip);
1654 1655
}

1656
static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
1657 1658
				   enum mv88e6xxx_frame_mode frame,
				   enum mv88e6xxx_egress_mode egress, u16 etype)
1659 1660 1661
{
	int err;

1662 1663 1664 1665
	if (!chip->info->ops->port_set_frame_mode)
		return -EOPNOTSUPP;

	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
1666 1667 1668
	if (err)
		return err;

1669 1670 1671 1672 1673 1674 1675 1676
	err = chip->info->ops->port_set_frame_mode(chip, port, frame);
	if (err)
		return err;

	if (chip->info->ops->port_set_ether_type)
		return chip->info->ops->port_set_ether_type(chip, port, etype);

	return 0;
1677 1678
}

1679
static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
1680
{
1681
	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
1682
				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
1683
				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
1684
}
1685

1686 1687 1688
static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
{
	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
1689
				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
1690
				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
1691
}
1692

1693 1694 1695 1696
static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
{
	return mv88e6xxx_set_port_mode(chip, port,
				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
1697 1698
				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
				       ETH_P_EDSA);
1699
}
1700

1701 1702 1703 1704
static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)
{
	if (dsa_is_dsa_port(chip->ds, port))
		return mv88e6xxx_set_port_mode_dsa(chip, port);
1705

1706
	if (dsa_is_user_port(chip->ds, port))
1707
		return mv88e6xxx_set_port_mode_normal(chip, port);
1708

1709 1710 1711
	/* Setup CPU port mode depending on its supported tag format */
	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
		return mv88e6xxx_set_port_mode_dsa(chip, port);
1712

1713 1714
	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
		return mv88e6xxx_set_port_mode_edsa(chip, port);
1715

1716
	return -EINVAL;
1717 1718
}

1719
static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
1720
{
1721
	bool message = dsa_is_dsa_port(chip->ds, port);
1722

1723
	return mv88e6xxx_port_set_message_port(chip, port, message);
1724
}
1725

1726
static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
1727
{
1728 1729
	struct dsa_switch *ds = chip->ds;
	bool flood;
1730

1731
	/* Upstream ports flood frames with unknown unicast or multicast DA */
1732
	flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port);
1733 1734 1735
	if (chip->info->ops->port_set_egress_floods)
		return chip->info->ops->port_set_egress_floods(chip, port,
							       flood, flood);
1736

1737
	return 0;
1738 1739
}

1740 1741 1742
static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
				  bool on)
{
1743 1744
	if (chip->info->ops->serdes_power)
		return chip->info->ops->serdes_power(chip, port, on);
1745

1746
	return 0;
1747 1748
}

1749 1750 1751 1752 1753 1754
static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
{
	struct dsa_switch *ds = chip->ds;
	int upstream_port;
	int err;

1755
	upstream_port = dsa_upstream_port(ds, port);
1756 1757 1758 1759 1760 1761 1762
	if (chip->info->ops->port_set_upstream_port) {
		err = chip->info->ops->port_set_upstream_port(chip, port,
							      upstream_port);
		if (err)
			return err;
	}

1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
	if (port == upstream_port) {
		if (chip->info->ops->set_cpu_port) {
			err = chip->info->ops->set_cpu_port(chip,
							    upstream_port);
			if (err)
				return err;
		}

		if (chip->info->ops->set_egress_port) {
			err = chip->info->ops->set_egress_port(chip,
							       upstream_port);
			if (err)
				return err;
		}
	}

1779 1780 1781
	return 0;
}

1782
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
1783
{
1784
	struct dsa_switch *ds = chip->ds;
1785
	int err;
1786
	u16 reg;
1787

1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801
	/* MAC Forcing register: don't force link, speed, duplex or flow control
	 * state to any particular values on physical ports, but force the CPU
	 * port and all DSA ports to their maximum bandwidth and full duplex.
	 */
	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
					       SPEED_MAX, DUPLEX_FULL,
					       PHY_INTERFACE_MODE_NA);
	else
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
					       SPEED_UNFORCED, DUPLEX_UNFORCED,
					       PHY_INTERFACE_MODE_NA);
	if (err)
		return err;
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816

	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
	 * tunneling, determine priority by looking at 802.1p and IP
	 * priority fields (IP prio has precedence), and set STP state
	 * to Forwarding.
	 *
	 * If this is the CPU link, use DSA or EDSA tagging depending
	 * on which tagging mode was configured.
	 *
	 * If this is a link to another switch, use DSA tagging mode.
	 *
	 * If this is the upstream port for this switch, enable
	 * forwarding of unknown unicasts and multicasts.
	 */
1817 1818 1819 1820
	reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
		MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
		MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
1821 1822
	if (err)
		return err;
1823

1824
	err = mv88e6xxx_setup_port_mode(chip, port);
1825 1826
	if (err)
		return err;
1827

1828
	err = mv88e6xxx_setup_egress_floods(chip, port);
1829 1830 1831
	if (err)
		return err;

1832 1833 1834
	/* Enable the SERDES interface for DSA and CPU ports. Normal
	 * ports SERDES are enabled when the port is enabled, thus
	 * saving a bit of power.
1835
	 */
1836 1837 1838 1839 1840
	if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) {
		err = mv88e6xxx_serdes_power(chip, port, true);
		if (err)
			return err;
	}
1841

1842
	/* Port Control 2: don't force a good FCS, set the maximum frame size to
1843
	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
1844 1845 1846
	 * untagged frames on this port, do a destination address lookup on all
	 * received packets as usual, disable ARP mirroring and don't send a
	 * copy of all transmitted/received frames on this port to the CPU.
1847
	 */
1848 1849 1850
	err = mv88e6xxx_port_set_map_da(chip, port);
	if (err)
		return err;
1851

1852 1853 1854
	err = mv88e6xxx_setup_upstream_port(chip, port);
	if (err)
		return err;
1855

1856
	err = mv88e6xxx_port_set_8021q_mode(chip, port,
1857
				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED);
1858 1859 1860
	if (err)
		return err;

1861 1862
	if (chip->info->ops->port_set_jumbo_size) {
		err = chip->info->ops->port_set_jumbo_size(chip, port, 10240);
1863 1864 1865 1866
		if (err)
			return err;
	}

1867 1868 1869 1870 1871
	/* Port Association Vector: when learning source addresses
	 * of packets, add the address to the address database using
	 * a port bitmap that has only the bit for this port set and
	 * the other bits clear.
	 */
1872
	reg = 1 << port;
1873 1874
	/* Disable learning for CPU port */
	if (dsa_is_cpu_port(ds, port))
1875
		reg = 0;
1876

1877 1878
	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
				   reg);
1879 1880
	if (err)
		return err;
1881 1882

	/* Egress rate control 2: disable egress rate control. */
1883 1884
	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
				   0x0000);
1885 1886
	if (err)
		return err;
1887

1888 1889
	if (chip->info->ops->port_pause_limit) {
		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
1890 1891
		if (err)
			return err;
1892
	}
1893

1894 1895 1896 1897 1898 1899
	if (chip->info->ops->port_disable_learn_limit) {
		err = chip->info->ops->port_disable_learn_limit(chip, port);
		if (err)
			return err;
	}

1900 1901
	if (chip->info->ops->port_disable_pri_override) {
		err = chip->info->ops->port_disable_pri_override(chip, port);
1902 1903
		if (err)
			return err;
1904
	}
1905

1906 1907
	if (chip->info->ops->port_tag_remap) {
		err = chip->info->ops->port_tag_remap(chip, port);
1908 1909
		if (err)
			return err;
1910 1911
	}

1912 1913
	if (chip->info->ops->port_egress_rate_limiting) {
		err = chip->info->ops->port_egress_rate_limiting(chip, port);
1914 1915
		if (err)
			return err;
1916 1917
	}

1918
	err = mv88e6xxx_setup_message_port(chip, port);
1919 1920
	if (err)
		return err;
1921

1922
	/* Port based VLAN map: give each port the same default address
1923 1924
	 * database, and allow bidirectional communication between the
	 * CPU and DSA port(s), and the other ports.
1925
	 */
1926
	err = mv88e6xxx_port_set_fid(chip, port, 0);
1927 1928
	if (err)
		return err;
1929

1930
	err = mv88e6xxx_port_vlan_map(chip, port);
1931 1932
	if (err)
		return err;
1933 1934 1935 1936

	/* Default VLAN ID and priority: don't set a default VLAN
	 * ID, and set the default packet priority to zero.
	 */
1937
	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0);
1938 1939
}

1940 1941 1942 1943
static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
				 struct phy_device *phydev)
{
	struct mv88e6xxx_chip *chip = ds->priv;
1944
	int err;
1945 1946

	mutex_lock(&chip->reg_lock);
1947
	err = mv88e6xxx_serdes_power(chip, port, true);
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
	mutex_unlock(&chip->reg_lock);

	return err;
}

static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port,
				   struct phy_device *phydev)
{
	struct mv88e6xxx_chip *chip = ds->priv;

	mutex_lock(&chip->reg_lock);
1959 1960
	if (mv88e6xxx_serdes_power(chip, port, false))
		dev_err(chip->dev, "failed to power off SERDES\n");
1961 1962 1963
	mutex_unlock(&chip->reg_lock);
}

1964 1965 1966
static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
				     unsigned int ageing_time)
{
V
Vivien Didelot 已提交
1967
	struct mv88e6xxx_chip *chip = ds->priv;
1968 1969 1970
	int err;

	mutex_lock(&chip->reg_lock);
1971
	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
1972 1973 1974 1975 1976
	mutex_unlock(&chip->reg_lock);

	return err;
}

1977
static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
1978
{
1979
	struct dsa_switch *ds = chip->ds;
1980
	int err;
1981

1982
	/* Disable remote management, and set the switch's DSA device number. */
1983 1984
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL2,
				 MV88E6XXX_G1_CTL2_MULTIPLE_CASCADE |
1985
				 (ds->index & 0x1f));
1986 1987 1988
	if (err)
		return err;

1989
	/* Configure the IP ToS mapping registers. */
1990
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_0, 0x0000);
1991
	if (err)
1992
		return err;
1993
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_1, 0x0000);
1994
	if (err)
1995
		return err;
1996
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_2, 0x5555);
1997
	if (err)
1998
		return err;
1999
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_3, 0x5555);
2000
	if (err)
2001
		return err;
2002
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_4, 0xaaaa);
2003
	if (err)
2004
		return err;
2005
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_5, 0xaaaa);
2006
	if (err)
2007
		return err;
2008
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_6, 0xffff);
2009
	if (err)
2010
		return err;
2011
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_7, 0xffff);
2012
	if (err)
2013
		return err;
2014 2015

	/* Configure the IEEE 802.1p priority mapping register. */
2016
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa41);
2017
	if (err)
2018
		return err;
2019

2020 2021 2022 2023 2024
	/* Initialize the statistics unit */
	err = mv88e6xxx_stats_set_histogram(chip);
	if (err)
		return err;

2025
	return mv88e6xxx_g1_stats_clear(chip);
2026 2027
}

2028
static int mv88e6xxx_setup(struct dsa_switch *ds)
2029
{
V
Vivien Didelot 已提交
2030
	struct mv88e6xxx_chip *chip = ds->priv;
2031
	int err;
2032 2033
	int i;

2034
	chip->ds = ds;
2035
	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2036

2037
	mutex_lock(&chip->reg_lock);
2038

2039
	/* Setup Switch Port Registers */
2040
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2041 2042 2043
		if (dsa_is_unused_port(ds, i))
			continue;

2044 2045 2046 2047 2048 2049 2050
		err = mv88e6xxx_setup_port(chip, i);
		if (err)
			goto unlock;
	}

	/* Setup Switch Global 1 Registers */
	err = mv88e6xxx_g1_setup(chip);
2051 2052 2053
	if (err)
		goto unlock;

2054
	/* Setup Switch Global 2 Registers */
2055
	if (chip->info->global2_addr) {
2056
		err = mv88e6xxx_g2_setup(chip);
2057 2058 2059
		if (err)
			goto unlock;
	}
2060

2061 2062 2063 2064
	err = mv88e6xxx_irl_setup(chip);
	if (err)
		goto unlock;

2065 2066 2067 2068
	err = mv88e6xxx_mac_setup(chip);
	if (err)
		goto unlock;

2069 2070 2071 2072
	err = mv88e6xxx_phy_setup(chip);
	if (err)
		goto unlock;

2073 2074 2075 2076
	err = mv88e6xxx_vtu_setup(chip);
	if (err)
		goto unlock;

2077 2078 2079 2080
	err = mv88e6xxx_pvt_setup(chip);
	if (err)
		goto unlock;

2081 2082 2083 2084
	err = mv88e6xxx_atu_setup(chip);
	if (err)
		goto unlock;

2085 2086 2087 2088
	err = mv88e6xxx_broadcast_setup(chip, 0);
	if (err)
		goto unlock;

2089 2090 2091 2092
	err = mv88e6xxx_pot_setup(chip);
	if (err)
		goto unlock;

2093 2094 2095
	err = mv88e6xxx_rsvd2cpu_setup(chip);
	if (err)
		goto unlock;
2096

2097
	/* Setup PTP Hardware Clock and timestamping */
2098 2099 2100 2101
	if (chip->info->ptp_support) {
		err = mv88e6xxx_ptp_setup(chip);
		if (err)
			goto unlock;
2102 2103 2104 2105

		err = mv88e6xxx_hwtstamp_setup(chip);
		if (err)
			goto unlock;
2106 2107
	}

2108
unlock:
2109
	mutex_unlock(&chip->reg_lock);
2110

2111
	return err;
2112 2113
}

2114
static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
2115
{
2116 2117
	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2118 2119
	u16 val;
	int err;
2120

2121 2122 2123
	if (!chip->info->ops->phy_read)
		return -EOPNOTSUPP;

2124
	mutex_lock(&chip->reg_lock);
2125
	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
2126
	mutex_unlock(&chip->reg_lock);
2127

2128 2129 2130 2131 2132
	if (reg == MII_PHYSID2) {
		/* Some internal PHYS don't have a model number.  Use
		 * the mv88e6390 family model number instead.
		 */
		if (!(val & 0x3f0))
2133
			val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
2134 2135
	}

2136
	return err ? err : val;
2137 2138
}

2139
static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
2140
{
2141 2142
	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2143
	int err;
2144

2145 2146 2147
	if (!chip->info->ops->phy_write)
		return -EOPNOTSUPP;

2148
	mutex_lock(&chip->reg_lock);
2149
	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
2150
	mutex_unlock(&chip->reg_lock);
2151 2152

	return err;
2153 2154
}

2155
static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
2156 2157
				   struct device_node *np,
				   bool external)
2158 2159
{
	static int index;
2160
	struct mv88e6xxx_mdio_bus *mdio_bus;
2161 2162 2163
	struct mii_bus *bus;
	int err;

2164
	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
2165 2166 2167
	if (!bus)
		return -ENOMEM;

2168
	mdio_bus = bus->priv;
2169
	mdio_bus->bus = bus;
2170
	mdio_bus->chip = chip;
2171 2172
	INIT_LIST_HEAD(&mdio_bus->list);
	mdio_bus->external = external;
2173

2174 2175
	if (np) {
		bus->name = np->full_name;
2176
		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
2177 2178 2179 2180 2181 2182 2183
	} else {
		bus->name = "mv88e6xxx SMI";
		snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++);
	}

	bus->read = mv88e6xxx_mdio_read;
	bus->write = mv88e6xxx_mdio_write;
2184
	bus->parent = chip->dev;
2185

2186 2187
	if (np)
		err = of_mdiobus_register(bus, np);
2188 2189 2190
	else
		err = mdiobus_register(bus);
	if (err) {
2191
		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
2192
		return err;
2193
	}
2194 2195 2196 2197 2198

	if (external)
		list_add_tail(&mdio_bus->list, &chip->mdios);
	else
		list_add(&mdio_bus->list, &chip->mdios);
2199 2200

	return 0;
2201
}
2202

2203 2204 2205 2206 2207
static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
	{ .compatible = "marvell,mv88e6xxx-mdio-external",
	  .data = (void *)true },
	{ },
};
2208

2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)

{
	struct mv88e6xxx_mdio_bus *mdio_bus;
	struct mii_bus *bus;

	list_for_each_entry(mdio_bus, &chip->mdios, list) {
		bus = mdio_bus->bus;

		mdiobus_unregister(bus);
	}
}

2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245
static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
				    struct device_node *np)
{
	const struct of_device_id *match;
	struct device_node *child;
	int err;

	/* Always register one mdio bus for the internal/default mdio
	 * bus. This maybe represented in the device tree, but is
	 * optional.
	 */
	child = of_get_child_by_name(np, "mdio");
	err = mv88e6xxx_mdio_register(chip, child, false);
	if (err)
		return err;

	/* Walk the device tree, and see if there are any other nodes
	 * which say they are compatible with the external mdio
	 * bus.
	 */
	for_each_available_child_of_node(np, child) {
		match = of_match_node(mv88e6xxx_mdio_external_match, child);
		if (match) {
			err = mv88e6xxx_mdio_register(chip, child, true);
2246 2247
			if (err) {
				mv88e6xxx_mdios_unregister(chip);
2248
				return err;
2249
			}
2250 2251 2252 2253
		}
	}

	return 0;
2254 2255
}

2256 2257
static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
{
V
Vivien Didelot 已提交
2258
	struct mv88e6xxx_chip *chip = ds->priv;
2259 2260 2261 2262 2263 2264 2265

	return chip->eeprom_len;
}

static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
				struct ethtool_eeprom *eeprom, u8 *data)
{
V
Vivien Didelot 已提交
2266
	struct mv88e6xxx_chip *chip = ds->priv;
2267 2268
	int err;

2269 2270
	if (!chip->info->ops->get_eeprom)
		return -EOPNOTSUPP;
2271

2272 2273
	mutex_lock(&chip->reg_lock);
	err = chip->info->ops->get_eeprom(chip, eeprom, data);
2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286
	mutex_unlock(&chip->reg_lock);

	if (err)
		return err;

	eeprom->magic = 0xc3ec4951;

	return 0;
}

static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
				struct ethtool_eeprom *eeprom, u8 *data)
{
V
Vivien Didelot 已提交
2287
	struct mv88e6xxx_chip *chip = ds->priv;
2288 2289
	int err;

2290 2291 2292
	if (!chip->info->ops->set_eeprom)
		return -EOPNOTSUPP;

2293 2294 2295 2296
	if (eeprom->magic != 0xc3ec4951)
		return -EINVAL;

	mutex_lock(&chip->reg_lock);
2297
	err = chip->info->ops->set_eeprom(chip, eeprom, data);
2298 2299 2300 2301 2302
	mutex_unlock(&chip->reg_lock);

	return err;
}

2303
static const struct mv88e6xxx_ops mv88e6085_ops = {
2304
	/* MV88E6XXX_FAMILY_6097 */
2305
	.irl_init_all = mv88e6352_g2_irl_init_all,
2306
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2307 2308
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
2309
	.port_set_link = mv88e6xxx_port_set_link,
2310
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2311
	.port_set_speed = mv88e6185_port_set_speed,
2312
	.port_tag_remap = mv88e6095_port_tag_remap,
2313
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2314
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2315
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2316
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2317
	.port_pause_limit = mv88e6097_port_pause_limit,
2318
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2319
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2320
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2321
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2322 2323
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2324
	.stats_get_stats = mv88e6095_stats_get_stats,
2325 2326
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2327
	.watchdog_ops = &mv88e6097_watchdog_ops,
2328
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2329
	.pot_clear = mv88e6xxx_g2_pot_clear,
2330 2331
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2332
	.reset = mv88e6185_g1_reset,
2333
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2334
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2335 2336 2337
};

static const struct mv88e6xxx_ops mv88e6095_ops = {
2338
	/* MV88E6XXX_FAMILY_6095 */
2339
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2340 2341
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
2342
	.port_set_link = mv88e6xxx_port_set_link,
2343
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2344
	.port_set_speed = mv88e6185_port_set_speed,
2345
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2346
	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2347
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
2348
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2349
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2350 2351
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2352
	.stats_get_stats = mv88e6095_stats_get_stats,
2353
	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2354 2355
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2356
	.reset = mv88e6185_g1_reset,
2357
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
2358
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2359 2360
};

2361
static const struct mv88e6xxx_ops mv88e6097_ops = {
2362
	/* MV88E6XXX_FAMILY_6097 */
2363
	.irl_init_all = mv88e6352_g2_irl_init_all,
2364 2365 2366 2367 2368 2369
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_speed = mv88e6185_port_set_speed,
2370
	.port_tag_remap = mv88e6095_port_tag_remap,
2371
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2372
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2373
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2374
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2375
	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
2376
	.port_pause_limit = mv88e6097_port_pause_limit,
2377
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2378
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2379
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2380
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2381 2382 2383
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
	.stats_get_stats = mv88e6095_stats_get_stats,
2384 2385
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2386
	.watchdog_ops = &mv88e6097_watchdog_ops,
2387
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2388
	.pot_clear = mv88e6xxx_g2_pot_clear,
2389
	.reset = mv88e6352_g1_reset,
2390
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2391
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2392 2393
};

2394
static const struct mv88e6xxx_ops mv88e6123_ops = {
2395
	/* MV88E6XXX_FAMILY_6165 */
2396
	.irl_init_all = mv88e6352_g2_irl_init_all,
2397
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2398 2399
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2400
	.port_set_link = mv88e6xxx_port_set_link,
2401
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2402
	.port_set_speed = mv88e6185_port_set_speed,
2403
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2404
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2405
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2406
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2407
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2408
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2409 2410
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2411
	.stats_get_stats = mv88e6095_stats_get_stats,
2412 2413
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2414
	.watchdog_ops = &mv88e6097_watchdog_ops,
2415
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2416
	.pot_clear = mv88e6xxx_g2_pot_clear,
2417
	.reset = mv88e6352_g1_reset,
2418
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2419
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2420 2421 2422
};

static const struct mv88e6xxx_ops mv88e6131_ops = {
2423
	/* MV88E6XXX_FAMILY_6185 */
2424
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2425 2426
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
2427
	.port_set_link = mv88e6xxx_port_set_link,
2428
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2429
	.port_set_speed = mv88e6185_port_set_speed,
2430
	.port_tag_remap = mv88e6095_port_tag_remap,
2431
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2432
	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2433
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2434
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
2435
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2436
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2437
	.port_pause_limit = mv88e6097_port_pause_limit,
2438
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2439
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2440 2441
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2442
	.stats_get_stats = mv88e6095_stats_get_stats,
2443 2444
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2445
	.watchdog_ops = &mv88e6097_watchdog_ops,
2446
	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2447 2448
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2449
	.reset = mv88e6185_g1_reset,
2450
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
2451
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2452 2453
};

2454 2455
static const struct mv88e6xxx_ops mv88e6141_ops = {
	/* MV88E6XXX_FAMILY_6341 */
2456
	.irl_init_all = mv88e6352_g2_irl_init_all,
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
	.port_tag_remap = mv88e6095_port_tag_remap,
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2470
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2471
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2472
	.port_pause_limit = mv88e6097_port_pause_limit,
2473 2474 2475
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
2476
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2477 2478 2479
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
2480 2481
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
2482 2483
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
2484
	.pot_clear = mv88e6xxx_g2_pot_clear,
2485
	.reset = mv88e6352_g1_reset,
2486
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2487
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2488
	.gpio_ops = &mv88e6352_gpio_ops,
2489 2490
};

2491
static const struct mv88e6xxx_ops mv88e6161_ops = {
2492
	/* MV88E6XXX_FAMILY_6165 */
2493
	.irl_init_all = mv88e6352_g2_irl_init_all,
2494
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2495 2496
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2497
	.port_set_link = mv88e6xxx_port_set_link,
2498
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2499
	.port_set_speed = mv88e6185_port_set_speed,
2500
	.port_tag_remap = mv88e6095_port_tag_remap,
2501
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2502
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2503
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2504
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2505
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2506
	.port_pause_limit = mv88e6097_port_pause_limit,
2507
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2508
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2509
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2510
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2511 2512
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2513
	.stats_get_stats = mv88e6095_stats_get_stats,
2514 2515
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2516
	.watchdog_ops = &mv88e6097_watchdog_ops,
2517
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2518
	.pot_clear = mv88e6xxx_g2_pot_clear,
2519
	.reset = mv88e6352_g1_reset,
2520
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2521
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2522 2523 2524
};

static const struct mv88e6xxx_ops mv88e6165_ops = {
2525
	/* MV88E6XXX_FAMILY_6165 */
2526
	.irl_init_all = mv88e6352_g2_irl_init_all,
2527
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2528 2529
	.phy_read = mv88e6165_phy_read,
	.phy_write = mv88e6165_phy_write,
2530
	.port_set_link = mv88e6xxx_port_set_link,
2531
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2532
	.port_set_speed = mv88e6185_port_set_speed,
2533
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2534
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2535
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2536
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2537 2538
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2539
	.stats_get_stats = mv88e6095_stats_get_stats,
2540 2541
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2542
	.watchdog_ops = &mv88e6097_watchdog_ops,
2543
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2544
	.pot_clear = mv88e6xxx_g2_pot_clear,
2545
	.reset = mv88e6352_g1_reset,
2546
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2547
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2548 2549 2550
};

static const struct mv88e6xxx_ops mv88e6171_ops = {
2551
	/* MV88E6XXX_FAMILY_6351 */
2552
	.irl_init_all = mv88e6352_g2_irl_init_all,
2553
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2554 2555
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2556
	.port_set_link = mv88e6xxx_port_set_link,
2557
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2558
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
2559
	.port_set_speed = mv88e6185_port_set_speed,
2560
	.port_tag_remap = mv88e6095_port_tag_remap,
2561
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2562
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2563
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2564
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2565
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2566
	.port_pause_limit = mv88e6097_port_pause_limit,
2567
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2568
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2569
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2570
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2571 2572
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2573
	.stats_get_stats = mv88e6095_stats_get_stats,
2574 2575
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2576
	.watchdog_ops = &mv88e6097_watchdog_ops,
2577
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2578
	.pot_clear = mv88e6xxx_g2_pot_clear,
2579
	.reset = mv88e6352_g1_reset,
2580
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2581
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2582 2583 2584
};

static const struct mv88e6xxx_ops mv88e6172_ops = {
2585
	/* MV88E6XXX_FAMILY_6352 */
2586
	.irl_init_all = mv88e6352_g2_irl_init_all,
2587 2588
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
2589
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2590 2591
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2592
	.port_set_link = mv88e6xxx_port_set_link,
2593
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2594
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
2595
	.port_set_speed = mv88e6352_port_set_speed,
2596
	.port_tag_remap = mv88e6095_port_tag_remap,
2597
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2598
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2599
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2600
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2601
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2602
	.port_pause_limit = mv88e6097_port_pause_limit,
2603
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2604
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2605
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2606
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2607 2608
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2609
	.stats_get_stats = mv88e6095_stats_get_stats,
2610 2611
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2612
	.watchdog_ops = &mv88e6097_watchdog_ops,
2613
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2614
	.pot_clear = mv88e6xxx_g2_pot_clear,
2615
	.reset = mv88e6352_g1_reset,
2616
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2617
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2618
	.serdes_power = mv88e6352_serdes_power,
2619
	.gpio_ops = &mv88e6352_gpio_ops,
2620 2621 2622
};

static const struct mv88e6xxx_ops mv88e6175_ops = {
2623
	/* MV88E6XXX_FAMILY_6351 */
2624
	.irl_init_all = mv88e6352_g2_irl_init_all,
2625
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2626 2627
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2628
	.port_set_link = mv88e6xxx_port_set_link,
2629
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2630
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
2631
	.port_set_speed = mv88e6185_port_set_speed,
2632
	.port_tag_remap = mv88e6095_port_tag_remap,
2633
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2634
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2635
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2636
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2637
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2638
	.port_pause_limit = mv88e6097_port_pause_limit,
2639
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2640
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2641
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2642
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2643 2644
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2645
	.stats_get_stats = mv88e6095_stats_get_stats,
2646 2647
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2648
	.watchdog_ops = &mv88e6097_watchdog_ops,
2649
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2650
	.pot_clear = mv88e6xxx_g2_pot_clear,
2651
	.reset = mv88e6352_g1_reset,
2652
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2653
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2654 2655 2656
};

static const struct mv88e6xxx_ops mv88e6176_ops = {
2657
	/* MV88E6XXX_FAMILY_6352 */
2658
	.irl_init_all = mv88e6352_g2_irl_init_all,
2659 2660
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
2661
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2662 2663
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2664
	.port_set_link = mv88e6xxx_port_set_link,
2665
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2666
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
2667
	.port_set_speed = mv88e6352_port_set_speed,
2668
	.port_tag_remap = mv88e6095_port_tag_remap,
2669
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2670
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2671
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2672
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2673
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2674
	.port_pause_limit = mv88e6097_port_pause_limit,
2675
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2676
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2677
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2678
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2679 2680
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2681
	.stats_get_stats = mv88e6095_stats_get_stats,
2682 2683
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2684
	.watchdog_ops = &mv88e6097_watchdog_ops,
2685
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2686
	.pot_clear = mv88e6xxx_g2_pot_clear,
2687
	.reset = mv88e6352_g1_reset,
2688
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2689
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2690
	.serdes_power = mv88e6352_serdes_power,
2691
	.gpio_ops = &mv88e6352_gpio_ops,
2692 2693 2694
};

static const struct mv88e6xxx_ops mv88e6185_ops = {
2695
	/* MV88E6XXX_FAMILY_6185 */
2696
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2697 2698
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
2699
	.port_set_link = mv88e6xxx_port_set_link,
2700
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2701
	.port_set_speed = mv88e6185_port_set_speed,
2702
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2703
	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2704
	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
2705
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
2706
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2707
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2708 2709
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2710
	.stats_get_stats = mv88e6095_stats_get_stats,
2711 2712
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2713
	.watchdog_ops = &mv88e6097_watchdog_ops,
2714
	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
2715 2716
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2717
	.reset = mv88e6185_g1_reset,
2718
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
2719
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2720 2721
};

2722
static const struct mv88e6xxx_ops mv88e6190_ops = {
2723
	/* MV88E6XXX_FAMILY_6390 */
2724
	.irl_init_all = mv88e6390_g2_irl_init_all,
2725 2726
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
2727 2728 2729 2730 2731 2732 2733
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
2734
	.port_tag_remap = mv88e6390_port_tag_remap,
2735
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2736
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2737
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2738
	.port_pause_limit = mv88e6390_port_pause_limit,
2739
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2740
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2741
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
2742
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
2743 2744
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
2745
	.stats_get_stats = mv88e6390_stats_get_stats,
2746 2747
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
2748
	.watchdog_ops = &mv88e6390_watchdog_ops,
2749
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
2750
	.pot_clear = mv88e6xxx_g2_pot_clear,
2751
	.reset = mv88e6352_g1_reset,
2752 2753
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2754
	.serdes_power = mv88e6390_serdes_power,
2755
	.gpio_ops = &mv88e6352_gpio_ops,
2756 2757 2758
};

static const struct mv88e6xxx_ops mv88e6190x_ops = {
2759
	/* MV88E6XXX_FAMILY_6390 */
2760
	.irl_init_all = mv88e6390_g2_irl_init_all,
2761 2762
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
2763 2764 2765 2766 2767 2768 2769
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390x_port_set_speed,
2770
	.port_tag_remap = mv88e6390_port_tag_remap,
2771
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2772
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2773
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2774
	.port_pause_limit = mv88e6390_port_pause_limit,
2775
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2776
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2777
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
2778
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
2779 2780
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
2781
	.stats_get_stats = mv88e6390_stats_get_stats,
2782 2783
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
2784
	.watchdog_ops = &mv88e6390_watchdog_ops,
2785
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
2786
	.pot_clear = mv88e6xxx_g2_pot_clear,
2787
	.reset = mv88e6352_g1_reset,
2788 2789
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2790
	.serdes_power = mv88e6390_serdes_power,
2791
	.gpio_ops = &mv88e6352_gpio_ops,
2792 2793 2794
};

static const struct mv88e6xxx_ops mv88e6191_ops = {
2795
	/* MV88E6XXX_FAMILY_6390 */
2796
	.irl_init_all = mv88e6390_g2_irl_init_all,
2797 2798
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
2799 2800 2801 2802 2803 2804 2805
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
2806
	.port_tag_remap = mv88e6390_port_tag_remap,
2807
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2808
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2809
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2810
	.port_pause_limit = mv88e6390_port_pause_limit,
2811
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2812
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2813
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
2814
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
2815 2816
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
2817
	.stats_get_stats = mv88e6390_stats_get_stats,
2818 2819
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
2820
	.watchdog_ops = &mv88e6390_watchdog_ops,
2821
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
2822
	.pot_clear = mv88e6xxx_g2_pot_clear,
2823
	.reset = mv88e6352_g1_reset,
2824 2825
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2826
	.serdes_power = mv88e6390_serdes_power,
2827 2828
};

2829
static const struct mv88e6xxx_ops mv88e6240_ops = {
2830
	/* MV88E6XXX_FAMILY_6352 */
2831
	.irl_init_all = mv88e6352_g2_irl_init_all,
2832 2833
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
2834
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2835 2836
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2837
	.port_set_link = mv88e6xxx_port_set_link,
2838
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2839
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
2840
	.port_set_speed = mv88e6352_port_set_speed,
2841
	.port_tag_remap = mv88e6095_port_tag_remap,
2842
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2843
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2844
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2845
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2846
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2847
	.port_pause_limit = mv88e6097_port_pause_limit,
2848
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2849
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2850
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2851
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2852 2853
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2854
	.stats_get_stats = mv88e6095_stats_get_stats,
2855 2856
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2857
	.watchdog_ops = &mv88e6097_watchdog_ops,
2858
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2859
	.pot_clear = mv88e6xxx_g2_pot_clear,
2860
	.reset = mv88e6352_g1_reset,
2861
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
2862
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2863
	.serdes_power = mv88e6352_serdes_power,
2864
	.gpio_ops = &mv88e6352_gpio_ops,
2865
	.avb_ops = &mv88e6352_avb_ops,
2866 2867
};

2868
static const struct mv88e6xxx_ops mv88e6290_ops = {
2869
	/* MV88E6XXX_FAMILY_6390 */
2870
	.irl_init_all = mv88e6390_g2_irl_init_all,
2871 2872
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
2873 2874 2875 2876 2877 2878 2879
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
2880
	.port_tag_remap = mv88e6390_port_tag_remap,
2881
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2882
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2883
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2884
	.port_pause_limit = mv88e6390_port_pause_limit,
2885
	.port_set_cmode = mv88e6390x_port_set_cmode,
2886
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2887
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2888
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
2889
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
2890 2891
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
2892
	.stats_get_stats = mv88e6390_stats_get_stats,
2893 2894
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
2895
	.watchdog_ops = &mv88e6390_watchdog_ops,
2896
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
2897
	.pot_clear = mv88e6xxx_g2_pot_clear,
2898
	.reset = mv88e6352_g1_reset,
2899 2900
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
2901
	.serdes_power = mv88e6390_serdes_power,
2902
	.gpio_ops = &mv88e6352_gpio_ops,
2903
	.avb_ops = &mv88e6390_avb_ops,
2904 2905
};

2906
static const struct mv88e6xxx_ops mv88e6320_ops = {
2907
	/* MV88E6XXX_FAMILY_6320 */
2908
	.irl_init_all = mv88e6352_g2_irl_init_all,
2909 2910
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
2911
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2912 2913
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2914
	.port_set_link = mv88e6xxx_port_set_link,
2915
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2916
	.port_set_speed = mv88e6185_port_set_speed,
2917
	.port_tag_remap = mv88e6095_port_tag_remap,
2918
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2919
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2920
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2921
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2922
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2923
	.port_pause_limit = mv88e6097_port_pause_limit,
2924
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2925
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2926
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2927
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2928 2929
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
2930
	.stats_get_stats = mv88e6320_stats_get_stats,
2931 2932
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2933
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
2934
	.pot_clear = mv88e6xxx_g2_pot_clear,
2935
	.reset = mv88e6352_g1_reset,
2936
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
2937
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2938
	.gpio_ops = &mv88e6352_gpio_ops,
2939
	.avb_ops = &mv88e6352_avb_ops,
2940 2941 2942
};

static const struct mv88e6xxx_ops mv88e6321_ops = {
2943
	/* MV88E6XXX_FAMILY_6320 */
2944
	.irl_init_all = mv88e6352_g2_irl_init_all,
2945 2946
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
2947
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2948 2949
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
2950
	.port_set_link = mv88e6xxx_port_set_link,
2951
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2952
	.port_set_speed = mv88e6185_port_set_speed,
2953
	.port_tag_remap = mv88e6095_port_tag_remap,
2954
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2955
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2956
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2957
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2958
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2959
	.port_pause_limit = mv88e6097_port_pause_limit,
2960
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2961
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2962
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
2963
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2964 2965
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
2966
	.stats_get_stats = mv88e6320_stats_get_stats,
2967 2968
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
2969
	.reset = mv88e6352_g1_reset,
2970
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
2971
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
2972
	.gpio_ops = &mv88e6352_gpio_ops,
2973
	.avb_ops = &mv88e6352_avb_ops,
2974 2975
};

2976 2977
static const struct mv88e6xxx_ops mv88e6341_ops = {
	/* MV88E6XXX_FAMILY_6341 */
2978
	.irl_init_all = mv88e6352_g2_irl_init_all,
2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
	.port_tag_remap = mv88e6095_port_tag_remap,
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2992
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
2993
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2994
	.port_pause_limit = mv88e6097_port_pause_limit,
2995 2996 2997
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
2998
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
2999 3000 3001
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
3002 3003
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
3004 3005
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
3006
	.pot_clear = mv88e6xxx_g2_pot_clear,
3007
	.reset = mv88e6352_g1_reset,
3008
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3009
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3010
	.gpio_ops = &mv88e6352_gpio_ops,
3011
	.avb_ops = &mv88e6390_avb_ops,
3012 3013
};

3014
static const struct mv88e6xxx_ops mv88e6350_ops = {
3015
	/* MV88E6XXX_FAMILY_6351 */
3016
	.irl_init_all = mv88e6352_g2_irl_init_all,
3017
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3018 3019
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3020
	.port_set_link = mv88e6xxx_port_set_link,
3021
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3022
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3023
	.port_set_speed = mv88e6185_port_set_speed,
3024
	.port_tag_remap = mv88e6095_port_tag_remap,
3025
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3026
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3027
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3028
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3029
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3030
	.port_pause_limit = mv88e6097_port_pause_limit,
3031
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3032
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3033
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3034
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3035 3036
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3037
	.stats_get_stats = mv88e6095_stats_get_stats,
3038 3039
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3040
	.watchdog_ops = &mv88e6097_watchdog_ops,
3041
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3042
	.pot_clear = mv88e6xxx_g2_pot_clear,
3043
	.reset = mv88e6352_g1_reset,
3044
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3045
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3046 3047 3048
};

static const struct mv88e6xxx_ops mv88e6351_ops = {
3049
	/* MV88E6XXX_FAMILY_6351 */
3050
	.irl_init_all = mv88e6352_g2_irl_init_all,
3051
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3052 3053
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3054
	.port_set_link = mv88e6xxx_port_set_link,
3055
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3056
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3057
	.port_set_speed = mv88e6185_port_set_speed,
3058
	.port_tag_remap = mv88e6095_port_tag_remap,
3059
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3060
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3061
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3062
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3063
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3064
	.port_pause_limit = mv88e6097_port_pause_limit,
3065
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3066
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3067
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3068
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3069 3070
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3071
	.stats_get_stats = mv88e6095_stats_get_stats,
3072 3073
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3074
	.watchdog_ops = &mv88e6097_watchdog_ops,
3075
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3076
	.pot_clear = mv88e6xxx_g2_pot_clear,
3077
	.reset = mv88e6352_g1_reset,
3078
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3079
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3080
	.avb_ops = &mv88e6352_avb_ops,
3081 3082 3083
};

static const struct mv88e6xxx_ops mv88e6352_ops = {
3084
	/* MV88E6XXX_FAMILY_6352 */
3085
	.irl_init_all = mv88e6352_g2_irl_init_all,
3086 3087
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3088
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3089 3090
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3091
	.port_set_link = mv88e6xxx_port_set_link,
3092
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3093
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3094
	.port_set_speed = mv88e6352_port_set_speed,
3095
	.port_tag_remap = mv88e6095_port_tag_remap,
3096
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3097
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3098
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3099
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3100
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3101
	.port_pause_limit = mv88e6097_port_pause_limit,
3102
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3103
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3104
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3105
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3106 3107
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3108
	.stats_get_stats = mv88e6095_stats_get_stats,
3109 3110
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3111
	.watchdog_ops = &mv88e6097_watchdog_ops,
3112
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3113
	.pot_clear = mv88e6xxx_g2_pot_clear,
3114
	.reset = mv88e6352_g1_reset,
3115
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3116
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3117
	.serdes_power = mv88e6352_serdes_power,
3118
	.gpio_ops = &mv88e6352_gpio_ops,
3119
	.avb_ops = &mv88e6352_avb_ops,
3120 3121
};

3122
static const struct mv88e6xxx_ops mv88e6390_ops = {
3123
	/* MV88E6XXX_FAMILY_6390 */
3124
	.irl_init_all = mv88e6390_g2_irl_init_all,
3125 3126
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3127 3128 3129 3130 3131 3132 3133
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
3134
	.port_tag_remap = mv88e6390_port_tag_remap,
3135
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3136
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3137
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3138
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3139
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3140
	.port_pause_limit = mv88e6390_port_pause_limit,
3141
	.port_set_cmode = mv88e6390x_port_set_cmode,
3142
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3143
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3144
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3145
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3146 3147
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3148
	.stats_get_stats = mv88e6390_stats_get_stats,
3149 3150
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
3151
	.watchdog_ops = &mv88e6390_watchdog_ops,
3152
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3153
	.pot_clear = mv88e6xxx_g2_pot_clear,
3154
	.reset = mv88e6352_g1_reset,
3155 3156
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3157
	.serdes_power = mv88e6390_serdes_power,
3158
	.gpio_ops = &mv88e6352_gpio_ops,
3159
	.avb_ops = &mv88e6390_avb_ops,
3160 3161 3162
};

static const struct mv88e6xxx_ops mv88e6390x_ops = {
3163
	/* MV88E6XXX_FAMILY_6390 */
3164
	.irl_init_all = mv88e6390_g2_irl_init_all,
3165 3166
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3167 3168 3169 3170 3171 3172 3173
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390x_port_set_speed,
3174
	.port_tag_remap = mv88e6390_port_tag_remap,
3175
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3176
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3177
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3178
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3179
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3180
	.port_pause_limit = mv88e6390_port_pause_limit,
3181
	.port_set_cmode = mv88e6390x_port_set_cmode,
3182
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3183
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3184
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3185
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3186 3187
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3188
	.stats_get_stats = mv88e6390_stats_get_stats,
3189 3190
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
3191
	.watchdog_ops = &mv88e6390_watchdog_ops,
3192
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3193
	.pot_clear = mv88e6xxx_g2_pot_clear,
3194
	.reset = mv88e6352_g1_reset,
3195 3196
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3197
	.serdes_power = mv88e6390_serdes_power,
3198
	.gpio_ops = &mv88e6352_gpio_ops,
3199
	.avb_ops = &mv88e6390_avb_ops,
3200 3201
};

3202 3203
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
	[MV88E6085] = {
3204
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
3205 3206 3207 3208
		.family = MV88E6XXX_FAMILY_6097,
		.name = "Marvell 88E6085",
		.num_databases = 4096,
		.num_ports = 10,
3209
		.max_vid = 4095,
3210
		.port_base_addr = 0x10,
3211
		.global1_addr = 0x1b,
3212
		.global2_addr = 0x1c,
3213
		.age_time_coeff = 15000,
3214
		.g1_irqs = 8,
3215
		.g2_irqs = 10,
3216
		.atu_move_port_mask = 0xf,
3217
		.pvt = true,
3218
		.multi_chip = true,
3219
		.tag_protocol = DSA_TAG_PROTO_DSA,
3220
		.ops = &mv88e6085_ops,
3221 3222 3223
	},

	[MV88E6095] = {
3224
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
3225 3226 3227 3228
		.family = MV88E6XXX_FAMILY_6095,
		.name = "Marvell 88E6095/88E6095F",
		.num_databases = 256,
		.num_ports = 11,
3229
		.max_vid = 4095,
3230
		.port_base_addr = 0x10,
3231
		.global1_addr = 0x1b,
3232
		.global2_addr = 0x1c,
3233
		.age_time_coeff = 15000,
3234
		.g1_irqs = 8,
3235
		.atu_move_port_mask = 0xf,
3236
		.multi_chip = true,
3237
		.tag_protocol = DSA_TAG_PROTO_DSA,
3238
		.ops = &mv88e6095_ops,
3239 3240
	},

3241
	[MV88E6097] = {
3242
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
3243 3244 3245 3246
		.family = MV88E6XXX_FAMILY_6097,
		.name = "Marvell 88E6097/88E6097F",
		.num_databases = 4096,
		.num_ports = 11,
3247
		.max_vid = 4095,
3248 3249
		.port_base_addr = 0x10,
		.global1_addr = 0x1b,
3250
		.global2_addr = 0x1c,
3251
		.age_time_coeff = 15000,
3252
		.g1_irqs = 8,
3253
		.g2_irqs = 10,
3254
		.atu_move_port_mask = 0xf,
3255
		.pvt = true,
3256
		.multi_chip = true,
3257
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3258 3259 3260
		.ops = &mv88e6097_ops,
	},

3261
	[MV88E6123] = {
3262
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
3263 3264 3265 3266
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6123",
		.num_databases = 4096,
		.num_ports = 3,
3267
		.max_vid = 4095,
3268
		.port_base_addr = 0x10,
3269
		.global1_addr = 0x1b,
3270
		.global2_addr = 0x1c,
3271
		.age_time_coeff = 15000,
3272
		.g1_irqs = 9,
3273
		.g2_irqs = 10,
3274
		.atu_move_port_mask = 0xf,
3275
		.pvt = true,
3276
		.multi_chip = true,
3277
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3278
		.ops = &mv88e6123_ops,
3279 3280 3281
	},

	[MV88E6131] = {
3282
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
3283 3284 3285 3286
		.family = MV88E6XXX_FAMILY_6185,
		.name = "Marvell 88E6131",
		.num_databases = 256,
		.num_ports = 8,
3287
		.max_vid = 4095,
3288
		.port_base_addr = 0x10,
3289
		.global1_addr = 0x1b,
3290
		.global2_addr = 0x1c,
3291
		.age_time_coeff = 15000,
3292
		.g1_irqs = 9,
3293
		.atu_move_port_mask = 0xf,
3294
		.multi_chip = true,
3295
		.tag_protocol = DSA_TAG_PROTO_DSA,
3296
		.ops = &mv88e6131_ops,
3297 3298
	},

3299
	[MV88E6141] = {
3300
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
3301 3302 3303 3304
		.family = MV88E6XXX_FAMILY_6341,
		.name = "Marvell 88E6341",
		.num_databases = 4096,
		.num_ports = 6,
3305
		.num_gpio = 11,
3306
		.max_vid = 4095,
3307 3308
		.port_base_addr = 0x10,
		.global1_addr = 0x1b,
3309
		.global2_addr = 0x1c,
3310 3311
		.age_time_coeff = 3750,
		.atu_move_port_mask = 0x1f,
3312
		.g2_irqs = 10,
3313
		.pvt = true,
3314
		.multi_chip = true,
3315 3316 3317 3318
		.tag_protocol = DSA_TAG_PROTO_EDSA,
		.ops = &mv88e6141_ops,
	},

3319
	[MV88E6161] = {
3320
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
3321 3322 3323 3324
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6161",
		.num_databases = 4096,
		.num_ports = 6,
3325
		.max_vid = 4095,
3326
		.port_base_addr = 0x10,
3327
		.global1_addr = 0x1b,
3328
		.global2_addr = 0x1c,
3329
		.age_time_coeff = 15000,
3330
		.g1_irqs = 9,
3331
		.g2_irqs = 10,
3332
		.atu_move_port_mask = 0xf,
3333
		.pvt = true,
3334
		.multi_chip = true,
3335
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3336
		.ops = &mv88e6161_ops,
3337 3338 3339
	},

	[MV88E6165] = {
3340
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
3341 3342 3343 3344
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6165",
		.num_databases = 4096,
		.num_ports = 6,
3345
		.max_vid = 4095,
3346
		.port_base_addr = 0x10,
3347
		.global1_addr = 0x1b,
3348
		.global2_addr = 0x1c,
3349
		.age_time_coeff = 15000,
3350
		.g1_irqs = 9,
3351
		.g2_irqs = 10,
3352
		.atu_move_port_mask = 0xf,
3353
		.pvt = true,
3354
		.multi_chip = true,
3355
		.tag_protocol = DSA_TAG_PROTO_DSA,
3356
		.ops = &mv88e6165_ops,
3357 3358 3359
	},

	[MV88E6171] = {
3360
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
3361 3362 3363 3364
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6171",
		.num_databases = 4096,
		.num_ports = 7,
3365
		.max_vid = 4095,
3366
		.port_base_addr = 0x10,
3367
		.global1_addr = 0x1b,
3368
		.global2_addr = 0x1c,
3369
		.age_time_coeff = 15000,
3370
		.g1_irqs = 9,
3371
		.g2_irqs = 10,
3372
		.atu_move_port_mask = 0xf,
3373
		.pvt = true,
3374
		.multi_chip = true,
3375
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3376
		.ops = &mv88e6171_ops,
3377 3378 3379
	},

	[MV88E6172] = {
3380
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
3381 3382 3383 3384
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6172",
		.num_databases = 4096,
		.num_ports = 7,
3385
		.num_gpio = 15,
3386
		.max_vid = 4095,
3387
		.port_base_addr = 0x10,
3388
		.global1_addr = 0x1b,
3389
		.global2_addr = 0x1c,
3390
		.age_time_coeff = 15000,
3391
		.g1_irqs = 9,
3392
		.g2_irqs = 10,
3393
		.atu_move_port_mask = 0xf,
3394
		.pvt = true,
3395
		.multi_chip = true,
3396
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3397
		.ops = &mv88e6172_ops,
3398 3399 3400
	},

	[MV88E6175] = {
3401
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
3402 3403 3404 3405
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6175",
		.num_databases = 4096,
		.num_ports = 7,
3406
		.max_vid = 4095,
3407
		.port_base_addr = 0x10,
3408
		.global1_addr = 0x1b,
3409
		.global2_addr = 0x1c,
3410
		.age_time_coeff = 15000,
3411
		.g1_irqs = 9,
3412
		.g2_irqs = 10,
3413
		.atu_move_port_mask = 0xf,
3414
		.pvt = true,
3415
		.multi_chip = true,
3416
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3417
		.ops = &mv88e6175_ops,
3418 3419 3420
	},

	[MV88E6176] = {
3421
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
3422 3423 3424 3425
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6176",
		.num_databases = 4096,
		.num_ports = 7,
3426
		.num_gpio = 15,
3427
		.max_vid = 4095,
3428
		.port_base_addr = 0x10,
3429
		.global1_addr = 0x1b,
3430
		.global2_addr = 0x1c,
3431
		.age_time_coeff = 15000,
3432
		.g1_irqs = 9,
3433
		.g2_irqs = 10,
3434
		.atu_move_port_mask = 0xf,
3435
		.pvt = true,
3436
		.multi_chip = true,
3437
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3438
		.ops = &mv88e6176_ops,
3439 3440 3441
	},

	[MV88E6185] = {
3442
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
3443 3444 3445 3446
		.family = MV88E6XXX_FAMILY_6185,
		.name = "Marvell 88E6185",
		.num_databases = 256,
		.num_ports = 10,
3447
		.max_vid = 4095,
3448
		.port_base_addr = 0x10,
3449
		.global1_addr = 0x1b,
3450
		.global2_addr = 0x1c,
3451
		.age_time_coeff = 15000,
3452
		.g1_irqs = 8,
3453
		.atu_move_port_mask = 0xf,
3454
		.multi_chip = true,
3455
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3456
		.ops = &mv88e6185_ops,
3457 3458
	},

3459
	[MV88E6190] = {
3460
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
3461 3462 3463 3464
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6190",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
3465
		.num_gpio = 16,
3466
		.max_vid = 8191,
3467 3468
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3469
		.global2_addr = 0x1c,
3470
		.tag_protocol = DSA_TAG_PROTO_DSA,
3471
		.age_time_coeff = 3750,
3472
		.g1_irqs = 9,
3473
		.g2_irqs = 14,
3474
		.pvt = true,
3475
		.multi_chip = true,
3476
		.atu_move_port_mask = 0x1f,
3477 3478 3479 3480
		.ops = &mv88e6190_ops,
	},

	[MV88E6190X] = {
3481
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
3482 3483 3484 3485
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6190X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
3486
		.num_gpio = 16,
3487
		.max_vid = 8191,
3488 3489
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3490
		.global2_addr = 0x1c,
3491
		.age_time_coeff = 3750,
3492
		.g1_irqs = 9,
3493
		.g2_irqs = 14,
3494
		.atu_move_port_mask = 0x1f,
3495
		.pvt = true,
3496
		.multi_chip = true,
3497
		.tag_protocol = DSA_TAG_PROTO_DSA,
3498 3499 3500 3501
		.ops = &mv88e6190x_ops,
	},

	[MV88E6191] = {
3502
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
3503 3504 3505 3506
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6191",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
3507
		.max_vid = 8191,
3508 3509
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3510
		.global2_addr = 0x1c,
3511
		.age_time_coeff = 3750,
3512
		.g1_irqs = 9,
3513
		.g2_irqs = 14,
3514
		.atu_move_port_mask = 0x1f,
3515
		.pvt = true,
3516
		.multi_chip = true,
3517
		.tag_protocol = DSA_TAG_PROTO_DSA,
3518
		.ptp_support = true,
3519
		.ops = &mv88e6191_ops,
3520 3521
	},

3522
	[MV88E6240] = {
3523
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
3524 3525 3526 3527
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6240",
		.num_databases = 4096,
		.num_ports = 7,
3528
		.num_gpio = 15,
3529
		.max_vid = 4095,
3530
		.port_base_addr = 0x10,
3531
		.global1_addr = 0x1b,
3532
		.global2_addr = 0x1c,
3533
		.age_time_coeff = 15000,
3534
		.g1_irqs = 9,
3535
		.g2_irqs = 10,
3536
		.atu_move_port_mask = 0xf,
3537
		.pvt = true,
3538
		.multi_chip = true,
3539
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3540
		.ptp_support = true,
3541
		.ops = &mv88e6240_ops,
3542 3543
	},

3544
	[MV88E6290] = {
3545
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
3546 3547 3548 3549
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6290",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
3550
		.num_gpio = 16,
3551
		.max_vid = 8191,
3552 3553
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3554
		.global2_addr = 0x1c,
3555
		.age_time_coeff = 3750,
3556
		.g1_irqs = 9,
3557
		.g2_irqs = 14,
3558
		.atu_move_port_mask = 0x1f,
3559
		.pvt = true,
3560
		.multi_chip = true,
3561
		.tag_protocol = DSA_TAG_PROTO_DSA,
3562
		.ptp_support = true,
3563 3564 3565
		.ops = &mv88e6290_ops,
	},

3566
	[MV88E6320] = {
3567
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
3568 3569 3570 3571
		.family = MV88E6XXX_FAMILY_6320,
		.name = "Marvell 88E6320",
		.num_databases = 4096,
		.num_ports = 7,
3572
		.num_gpio = 15,
3573
		.max_vid = 4095,
3574
		.port_base_addr = 0x10,
3575
		.global1_addr = 0x1b,
3576
		.global2_addr = 0x1c,
3577
		.age_time_coeff = 15000,
3578
		.g1_irqs = 8,
3579
		.atu_move_port_mask = 0xf,
3580
		.pvt = true,
3581
		.multi_chip = true,
3582
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3583
		.ptp_support = true,
3584
		.ops = &mv88e6320_ops,
3585 3586 3587
	},

	[MV88E6321] = {
3588
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
3589 3590 3591 3592
		.family = MV88E6XXX_FAMILY_6320,
		.name = "Marvell 88E6321",
		.num_databases = 4096,
		.num_ports = 7,
3593
		.num_gpio = 15,
3594
		.max_vid = 4095,
3595
		.port_base_addr = 0x10,
3596
		.global1_addr = 0x1b,
3597
		.global2_addr = 0x1c,
3598
		.age_time_coeff = 15000,
3599
		.g1_irqs = 8,
3600
		.atu_move_port_mask = 0xf,
3601
		.multi_chip = true,
3602
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3603
		.ptp_support = true,
3604
		.ops = &mv88e6321_ops,
3605 3606
	},

3607
	[MV88E6341] = {
3608
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
3609 3610 3611 3612
		.family = MV88E6XXX_FAMILY_6341,
		.name = "Marvell 88E6341",
		.num_databases = 4096,
		.num_ports = 6,
3613
		.num_gpio = 11,
3614
		.max_vid = 4095,
3615 3616
		.port_base_addr = 0x10,
		.global1_addr = 0x1b,
3617
		.global2_addr = 0x1c,
3618
		.age_time_coeff = 3750,
3619
		.atu_move_port_mask = 0x1f,
3620
		.g2_irqs = 10,
3621
		.pvt = true,
3622
		.multi_chip = true,
3623
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3624
		.ptp_support = true,
3625 3626 3627
		.ops = &mv88e6341_ops,
	},

3628
	[MV88E6350] = {
3629
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
3630 3631 3632 3633
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6350",
		.num_databases = 4096,
		.num_ports = 7,
3634
		.max_vid = 4095,
3635
		.port_base_addr = 0x10,
3636
		.global1_addr = 0x1b,
3637
		.global2_addr = 0x1c,
3638
		.age_time_coeff = 15000,
3639
		.g1_irqs = 9,
3640
		.g2_irqs = 10,
3641
		.atu_move_port_mask = 0xf,
3642
		.pvt = true,
3643
		.multi_chip = true,
3644
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3645
		.ops = &mv88e6350_ops,
3646 3647 3648
	},

	[MV88E6351] = {
3649
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
3650 3651 3652 3653
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6351",
		.num_databases = 4096,
		.num_ports = 7,
3654
		.max_vid = 4095,
3655
		.port_base_addr = 0x10,
3656
		.global1_addr = 0x1b,
3657
		.global2_addr = 0x1c,
3658
		.age_time_coeff = 15000,
3659
		.g1_irqs = 9,
3660
		.g2_irqs = 10,
3661
		.atu_move_port_mask = 0xf,
3662
		.pvt = true,
3663
		.multi_chip = true,
3664
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3665
		.ops = &mv88e6351_ops,
3666 3667 3668
	},

	[MV88E6352] = {
3669
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
3670 3671 3672 3673
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6352",
		.num_databases = 4096,
		.num_ports = 7,
3674
		.num_gpio = 15,
3675
		.max_vid = 4095,
3676
		.port_base_addr = 0x10,
3677
		.global1_addr = 0x1b,
3678
		.global2_addr = 0x1c,
3679
		.age_time_coeff = 15000,
3680
		.g1_irqs = 9,
3681
		.g2_irqs = 10,
3682
		.atu_move_port_mask = 0xf,
3683
		.pvt = true,
3684
		.multi_chip = true,
3685
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3686
		.ptp_support = true,
3687
		.ops = &mv88e6352_ops,
3688
	},
3689
	[MV88E6390] = {
3690
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
3691 3692 3693 3694
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6390",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
3695
		.num_gpio = 16,
3696
		.max_vid = 8191,
3697 3698
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3699
		.global2_addr = 0x1c,
3700
		.age_time_coeff = 3750,
3701
		.g1_irqs = 9,
3702
		.g2_irqs = 14,
3703
		.atu_move_port_mask = 0x1f,
3704
		.pvt = true,
3705
		.multi_chip = true,
3706
		.tag_protocol = DSA_TAG_PROTO_DSA,
3707
		.ptp_support = true,
3708 3709 3710
		.ops = &mv88e6390_ops,
	},
	[MV88E6390X] = {
3711
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
3712 3713 3714 3715
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6390X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
3716
		.num_gpio = 16,
3717
		.max_vid = 8191,
3718 3719
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3720
		.global2_addr = 0x1c,
3721
		.age_time_coeff = 3750,
3722
		.g1_irqs = 9,
3723
		.g2_irqs = 14,
3724
		.atu_move_port_mask = 0x1f,
3725
		.pvt = true,
3726
		.multi_chip = true,
3727
		.tag_protocol = DSA_TAG_PROTO_DSA,
3728
		.ptp_support = true,
3729 3730
		.ops = &mv88e6390x_ops,
	},
3731 3732
};

3733
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
3734
{
3735
	int i;
3736

3737 3738 3739
	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
		if (mv88e6xxx_table[i].prod_num == prod_num)
			return &mv88e6xxx_table[i];
3740 3741 3742 3743

	return NULL;
}

3744
static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
3745 3746
{
	const struct mv88e6xxx_info *info;
3747 3748 3749
	unsigned int prod_num, rev;
	u16 id;
	int err;
3750

3751
	mutex_lock(&chip->reg_lock);
3752
	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
3753 3754 3755
	mutex_unlock(&chip->reg_lock);
	if (err)
		return err;
3756

3757 3758
	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
3759 3760 3761 3762 3763

	info = mv88e6xxx_lookup_info(prod_num);
	if (!info)
		return -ENODEV;

3764
	/* Update the compatible info with the probed one */
3765
	chip->info = info;
3766

3767 3768 3769 3770
	err = mv88e6xxx_g2_require(chip);
	if (err)
		return err;

3771 3772
	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
		 chip->info->prod_num, chip->info->name, rev);
3773 3774 3775 3776

	return 0;
}

3777
static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
3778
{
3779
	struct mv88e6xxx_chip *chip;
3780

3781 3782
	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
3783 3784
		return NULL;

3785
	chip->dev = dev;
3786

3787
	mutex_init(&chip->reg_lock);
3788
	INIT_LIST_HEAD(&chip->mdios);
3789

3790
	return chip;
3791 3792
}

3793
static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
3794 3795
			      struct mii_bus *bus, int sw_addr)
{
3796
	if (sw_addr == 0)
3797
		chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
3798
	else if (chip->info->multi_chip)
3799
		chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
3800 3801 3802
	else
		return -EINVAL;

3803 3804
	chip->bus = bus;
	chip->sw_addr = sw_addr;
3805 3806 3807 3808

	return 0;
}

3809 3810
static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
							int port)
3811
{
V
Vivien Didelot 已提交
3812
	struct mv88e6xxx_chip *chip = ds->priv;
3813

3814
	return chip->info->tag_protocol;
3815 3816
}

3817
#if IS_ENABLED(CONFIG_NET_DSA_LEGACY)
3818 3819 3820
static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
				       struct device *host_dev, int sw_addr,
				       void **priv)
3821
{
3822
	struct mv88e6xxx_chip *chip;
3823
	struct mii_bus *bus;
3824
	int err;
3825

3826
	bus = dsa_host_dev_to_mii_bus(host_dev);
3827 3828 3829
	if (!bus)
		return NULL;

3830 3831
	chip = mv88e6xxx_alloc_chip(dsa_dev);
	if (!chip)
3832 3833
		return NULL;

3834
	/* Legacy SMI probing will only support chips similar to 88E6085 */
3835
	chip->info = &mv88e6xxx_table[MV88E6085];
3836

3837
	err = mv88e6xxx_smi_init(chip, bus, sw_addr);
3838 3839 3840
	if (err)
		goto free;

3841
	err = mv88e6xxx_detect(chip);
3842
	if (err)
3843
		goto free;
3844

3845 3846 3847 3848 3849 3850
	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_switch_reset(chip);
	mutex_unlock(&chip->reg_lock);
	if (err)
		goto free;

3851 3852
	mv88e6xxx_phy_init(chip);

3853
	err = mv88e6xxx_mdios_register(chip, NULL);
3854
	if (err)
3855
		goto free;
3856

3857
	*priv = chip;
3858

3859
	return chip->info->name;
3860
free:
3861
	devm_kfree(dsa_dev, chip);
3862 3863

	return NULL;
3864
}
3865
#endif
3866

3867
static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
3868
				      const struct switchdev_obj_port_mdb *mdb)
3869 3870 3871 3872 3873 3874 3875 3876 3877
{
	/* We don't need any dynamic resource from the kernel (yet),
	 * so skip the prepare phase.
	 */

	return 0;
}

static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
3878
				   const struct switchdev_obj_port_mdb *mdb)
3879
{
V
Vivien Didelot 已提交
3880
	struct mv88e6xxx_chip *chip = ds->priv;
3881 3882 3883

	mutex_lock(&chip->reg_lock);
	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
3884
					 MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
3885 3886
		dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
			port);
3887 3888 3889 3890 3891 3892
	mutex_unlock(&chip->reg_lock);
}

static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
				  const struct switchdev_obj_port_mdb *mdb)
{
V
Vivien Didelot 已提交
3893
	struct mv88e6xxx_chip *chip = ds->priv;
3894 3895 3896 3897
	int err;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
3898
					   MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
3899 3900 3901 3902 3903
	mutex_unlock(&chip->reg_lock);

	return err;
}

3904
static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
3905
#if IS_ENABLED(CONFIG_NET_DSA_LEGACY)
3906
	.probe			= mv88e6xxx_drv_probe,
3907
#endif
3908
	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
3909 3910 3911 3912 3913
	.setup			= mv88e6xxx_setup,
	.adjust_link		= mv88e6xxx_adjust_link,
	.get_strings		= mv88e6xxx_get_strings,
	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
	.get_sset_count		= mv88e6xxx_get_sset_count,
3914 3915
	.port_enable		= mv88e6xxx_port_enable,
	.port_disable		= mv88e6xxx_port_disable,
V
Vivien Didelot 已提交
3916 3917
	.get_mac_eee		= mv88e6xxx_get_mac_eee,
	.set_mac_eee		= mv88e6xxx_set_mac_eee,
3918
	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
3919 3920 3921 3922
	.get_eeprom		= mv88e6xxx_get_eeprom,
	.set_eeprom		= mv88e6xxx_set_eeprom,
	.get_regs_len		= mv88e6xxx_get_regs_len,
	.get_regs		= mv88e6xxx_get_regs,
3923
	.set_ageing_time	= mv88e6xxx_set_ageing_time,
3924 3925 3926
	.port_bridge_join	= mv88e6xxx_port_bridge_join,
	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
3927
	.port_fast_age		= mv88e6xxx_port_fast_age,
3928 3929 3930 3931 3932 3933 3934
	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
	.port_vlan_add		= mv88e6xxx_port_vlan_add,
	.port_vlan_del		= mv88e6xxx_port_vlan_del,
	.port_fdb_add           = mv88e6xxx_port_fdb_add,
	.port_fdb_del           = mv88e6xxx_port_fdb_del,
	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
3935 3936 3937
	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
	.port_mdb_add           = mv88e6xxx_port_mdb_add,
	.port_mdb_del           = mv88e6xxx_port_mdb_del,
3938 3939
	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
3940 3941 3942 3943 3944
	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
	.port_txtstamp		= mv88e6xxx_port_txtstamp,
	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
	.get_ts_info		= mv88e6xxx_get_ts_info,
3945 3946
};

3947 3948 3949 3950
static struct dsa_switch_driver mv88e6xxx_switch_drv = {
	.ops			= &mv88e6xxx_switch_ops,
};

3951
static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
3952
{
3953
	struct device *dev = chip->dev;
3954 3955
	struct dsa_switch *ds;

3956
	ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip));
3957 3958 3959
	if (!ds)
		return -ENOMEM;

3960
	ds->priv = chip;
3961
	ds->ops = &mv88e6xxx_switch_ops;
3962 3963
	ds->ageing_time_min = chip->info->age_time_coeff;
	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
3964 3965 3966

	dev_set_drvdata(dev, ds);

3967
	return dsa_register_switch(ds);
3968 3969
}

3970
static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
3971
{
3972
	dsa_unregister_switch(chip->ds);
3973 3974
}

3975
static int mv88e6xxx_probe(struct mdio_device *mdiodev)
3976
{
3977
	struct device *dev = &mdiodev->dev;
3978
	struct device_node *np = dev->of_node;
3979
	const struct mv88e6xxx_info *compat_info;
3980
	struct mv88e6xxx_chip *chip;
3981
	u32 eeprom_len;
3982
	int err;
3983

3984 3985 3986 3987
	compat_info = of_device_get_match_data(dev);
	if (!compat_info)
		return -EINVAL;

3988 3989
	chip = mv88e6xxx_alloc_chip(dev);
	if (!chip)
3990 3991
		return -ENOMEM;

3992
	chip->info = compat_info;
3993

3994
	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
3995 3996
	if (err)
		return err;
3997

3998 3999 4000 4001
	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
	if (IS_ERR(chip->reset))
		return PTR_ERR(chip->reset);

4002
	err = mv88e6xxx_detect(chip);
4003 4004
	if (err)
		return err;
4005

4006 4007
	mv88e6xxx_phy_init(chip);

4008
	if (chip->info->ops->get_eeprom &&
4009
	    !of_property_read_u32(np, "eeprom-length", &eeprom_len))
4010
		chip->eeprom_len = eeprom_len;
4011

4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035
	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_switch_reset(chip);
	mutex_unlock(&chip->reg_lock);
	if (err)
		goto out;

	chip->irq = of_irq_get(np, 0);
	if (chip->irq == -EPROBE_DEFER) {
		err = chip->irq;
		goto out;
	}

	if (chip->irq > 0) {
		/* Has to be performed before the MDIO bus is created,
		 * because the PHYs will link there interrupts to these
		 * interrupt controllers
		 */
		mutex_lock(&chip->reg_lock);
		err = mv88e6xxx_g1_irq_setup(chip);
		mutex_unlock(&chip->reg_lock);

		if (err)
			goto out;

4036
		if (chip->info->g2_irqs > 0) {
4037 4038 4039 4040
			err = mv88e6xxx_g2_irq_setup(chip);
			if (err)
				goto out_g1_irq;
		}
4041 4042 4043 4044

		err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
		if (err)
			goto out_g2_irq;
4045 4046 4047 4048

		err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
		if (err)
			goto out_g1_atu_prob_irq;
4049 4050
	}

4051
	err = mv88e6xxx_mdios_register(chip, np);
4052
	if (err)
4053
		goto out_g1_vtu_prob_irq;
4054

4055
	err = mv88e6xxx_register_switch(chip);
4056 4057
	if (err)
		goto out_mdio;
4058

4059
	return 0;
4060 4061

out_mdio:
4062
	mv88e6xxx_mdios_unregister(chip);
4063
out_g1_vtu_prob_irq:
4064 4065
	if (chip->irq > 0)
		mv88e6xxx_g1_vtu_prob_irq_free(chip);
4066
out_g1_atu_prob_irq:
4067 4068
	if (chip->irq > 0)
		mv88e6xxx_g1_atu_prob_irq_free(chip);
4069
out_g2_irq:
4070
	if (chip->info->g2_irqs > 0 && chip->irq > 0)
4071 4072
		mv88e6xxx_g2_irq_free(chip);
out_g1_irq:
4073 4074
	if (chip->irq > 0) {
		mutex_lock(&chip->reg_lock);
4075
		mv88e6xxx_g1_irq_free(chip);
4076 4077
		mutex_unlock(&chip->reg_lock);
	}
4078 4079
out:
	return err;
4080
}
4081 4082 4083 4084

static void mv88e6xxx_remove(struct mdio_device *mdiodev)
{
	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
V
Vivien Didelot 已提交
4085
	struct mv88e6xxx_chip *chip = ds->priv;
4086

4087 4088
	if (chip->info->ptp_support) {
		mv88e6xxx_hwtstamp_free(chip);
4089
		mv88e6xxx_ptp_free(chip);
4090
	}
4091

4092
	mv88e6xxx_phy_destroy(chip);
4093
	mv88e6xxx_unregister_switch(chip);
4094
	mv88e6xxx_mdios_unregister(chip);
4095

4096
	if (chip->irq > 0) {
4097
		mv88e6xxx_g1_vtu_prob_irq_free(chip);
4098
		mv88e6xxx_g1_atu_prob_irq_free(chip);
4099
		if (chip->info->g2_irqs > 0)
4100
			mv88e6xxx_g2_irq_free(chip);
4101
		mutex_lock(&chip->reg_lock);
4102
		mv88e6xxx_g1_irq_free(chip);
4103
		mutex_unlock(&chip->reg_lock);
4104
	}
4105 4106 4107
}

static const struct of_device_id mv88e6xxx_of_match[] = {
4108 4109 4110 4111
	{
		.compatible = "marvell,mv88e6085",
		.data = &mv88e6xxx_table[MV88E6085],
	},
4112 4113 4114 4115
	{
		.compatible = "marvell,mv88e6190",
		.data = &mv88e6xxx_table[MV88E6190],
	},
4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131
	{ /* sentinel */ },
};

MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);

static struct mdio_driver mv88e6xxx_driver = {
	.probe	= mv88e6xxx_probe,
	.remove = mv88e6xxx_remove,
	.mdiodrv.driver = {
		.name = "mv88e6085",
		.of_match_table = mv88e6xxx_of_match,
	},
};

static int __init mv88e6xxx_init(void)
{
4132
	register_switch_driver(&mv88e6xxx_switch_drv);
4133 4134
	return mdio_driver_register(&mv88e6xxx_driver);
}
4135 4136 4137 4138
module_init(mv88e6xxx_init);

static void __exit mv88e6xxx_cleanup(void)
{
4139
	mdio_driver_unregister(&mv88e6xxx_driver);
4140
	unregister_switch_driver(&mv88e6xxx_switch_drv);
4141 4142
}
module_exit(mv88e6xxx_cleanup);
4143 4144 4145 4146

MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips");
MODULE_LICENSE("GPL");