chip.c 193.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3 4
 * Marvell 88e6xxx Ethernet switch single-chip support
 *
5 6
 * Copyright (c) 2008 Marvell Semiconductor
 *
7 8
 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
 *
V
Vivien Didelot 已提交
9 10
 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
11 12
 */

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

35
#include "chip.h"
36
#include "devlink.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
#include "smi.h"
45

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

54
int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
55 56 57
{
	int err;

58
	assert_reg_lock(chip);
59

60
	err = mv88e6xxx_smi_read(chip, addr, reg, val);
61 62 63
	if (err)
		return err;

64
	dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
65 66 67 68 69
		addr, reg, *val);

	return 0;
}

70
int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
71
{
72 73
	int err;

74
	assert_reg_lock(chip);
75

76
	err = mv88e6xxx_smi_write(chip, addr, reg, val);
77 78 79
	if (err)
		return err;

80
	dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
81 82
		addr, reg, val);

83 84 85
	return 0;
}

86 87 88
int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
			u16 mask, u16 val)
{
89
	const unsigned long timeout = jiffies + msecs_to_jiffies(50);
90 91 92 93
	u16 data;
	int err;
	int i;

94 95 96 97 98
	/* There's no bus specific operation to wait for a mask. Even
	 * if the initial poll takes longer than 50ms, always do at
	 * least one more attempt.
	 */
	for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {
99 100 101 102 103 104 105
		err = mv88e6xxx_read(chip, addr, reg, &data);
		if (err)
			return err;

		if ((data & mask) == val)
			return 0;

106 107 108 109
		if (i < 2)
			cpu_relax();
		else
			usleep_range(1000, 2000);
110 111 112 113 114 115
	}

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

116 117 118 119 120 121 122
int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
		       int bit, int val)
{
	return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
				   val ? BIT(bit) : 0x0000);
}

123
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
124 125 126 127 128 129 130 131 132 133 134
{
	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;
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
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);
}

151
static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
152 153 154 155 156
{
	unsigned int nhandled = 0;
	unsigned int sub_irq;
	unsigned int n;
	u16 reg;
157
	u16 ctl1;
158 159
	int err;

160
	mv88e6xxx_reg_lock(chip);
161
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
162
	mv88e6xxx_reg_unlock(chip);
163 164 165 166

	if (err)
		goto out;

167 168 169 170 171 172 173 174
	do {
		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;
			}
175
		}
176

177
		mv88e6xxx_reg_lock(chip);
178 179 180 181 182
		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
		if (err)
			goto unlock;
		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
unlock:
183
		mv88e6xxx_reg_unlock(chip);
184 185 186 187 188
		if (err)
			goto out;
		ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
	} while (reg & ctl1);

189 190 191 192
out:
	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}

193 194 195 196 197 198 199
static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
{
	struct mv88e6xxx_chip *chip = dev_id;

	return mv88e6xxx_g1_irq_thread_work(chip);
}

200 201 202 203
static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);

204
	mv88e6xxx_reg_lock(chip);
205 206 207 208 209 210 211 212 213
}

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;

214
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &reg);
215 216 217 218 219 220
	if (err)
		goto out;

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

221
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg);
222 223 224 225
	if (err)
		goto out;

out:
226
	mv88e6xxx_reg_unlock(chip);
227 228
}

229
static const struct irq_chip mv88e6xxx_g1_irq_chip = {
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
	.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,
};

255
/* To be called with reg_lock held */
256
static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
257 258
{
	int irq, virq;
259 260
	u16 mask;

261
	mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
262
	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
263
	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
264

265
	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
266
		virq = irq_find_mapping(chip->g1_irq.domain, irq);
267 268 269
		irq_dispose_mapping(virq);
	}

270
	irq_domain_remove(chip->g1_irq.domain);
271 272
}

273 274
static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
{
275 276 277 278
	/*
	 * free_irq must be called without reg_lock taken because the irq
	 * handler takes this lock, too.
	 */
279
	free_irq(chip->irq, chip);
280

281
	mv88e6xxx_reg_lock(chip);
282
	mv88e6xxx_g1_irq_free_common(chip);
283
	mv88e6xxx_reg_unlock(chip);
284 285 286
}

static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
287
{
288 289
	int err, irq, virq;
	u16 reg, mask;
290 291 292 293 294 295 296 297 298 299 300 301 302 303

	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;

304
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask);
305
	if (err)
306
		goto out_mapping;
307

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

310
	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
311
	if (err)
312
		goto out_disable;
313 314

	/* Reading the interrupt status clears (most of) them */
315
	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
316
	if (err)
317
		goto out_disable;
318 319 320

	return 0;

321
out_disable:
322
	mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
323
	mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
324 325 326 327 328 329 330 331

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);
332 333 334 335

	return err;
}

336 337
static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
{
338 339
	static struct lock_class_key lock_key;
	static struct lock_class_key request_key;
340 341 342 343 344 345
	int err;

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

346 347 348 349 350 351
	/* These lock classes tells lockdep that global 1 irqs are in
	 * a different category than their parent GPIO, so it won't
	 * report false recursion.
	 */
	irq_set_lockdep_class(chip->irq, &lock_key, &request_key);

352 353 354
	snprintf(chip->irq_name, sizeof(chip->irq_name),
		 "mv88e6xxx-%s", dev_name(chip->dev));

355
	mv88e6xxx_reg_unlock(chip);
356 357
	err = request_threaded_irq(chip->irq, NULL,
				   mv88e6xxx_g1_irq_thread_fn,
358
				   IRQF_ONESHOT | IRQF_SHARED,
359
				   chip->irq_name, chip);
360
	mv88e6xxx_reg_lock(chip);
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
	if (err)
		mv88e6xxx_g1_irq_free_common(chip);

	return err;
}

static void mv88e6xxx_irq_poll(struct kthread_work *work)
{
	struct mv88e6xxx_chip *chip = container_of(work,
						   struct mv88e6xxx_chip,
						   irq_poll_work.work);
	mv88e6xxx_g1_irq_thread_work(chip);

	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
				   msecs_to_jiffies(100));
}

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

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

	kthread_init_delayed_work(&chip->irq_poll_work,
				  mv88e6xxx_irq_poll);

389
	chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
390 391 392 393 394 395 396 397 398 399 400 401 402
	if (IS_ERR(chip->kworker))
		return PTR_ERR(chip->kworker);

	kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
				   msecs_to_jiffies(100));

	return 0;
}

static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
{
	kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
	kthread_destroy_worker(chip->kworker);
403

404
	mv88e6xxx_reg_lock(chip);
405
	mv88e6xxx_g1_irq_free_common(chip);
406
	mv88e6xxx_reg_unlock(chip);
407 408
}

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip,
					   int port, phy_interface_t interface)
{
	int err;

	if (chip->info->ops->port_set_rgmii_delay) {
		err = chip->info->ops->port_set_rgmii_delay(chip, port,
							    interface);
		if (err && err != -EOPNOTSUPP)
			return err;
	}

	if (chip->info->ops->port_set_cmode) {
		err = chip->info->ops->port_set_cmode(chip, port,
						      interface);
		if (err && err != -EOPNOTSUPP)
			return err;
	}

	return 0;
}

431 432 433
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
				    int link, int speed, int duplex, int pause,
				    phy_interface_t mode)
434 435 436 437 438 439 440
{
	int err;

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

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

445 446 447
	if (chip->info->ops->port_set_speed_duplex) {
		err = chip->info->ops->port_set_speed_duplex(chip, port,
							     speed, duplex);
448 449 450 451
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

452 453 454
	if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
		mode = chip->info->ops->port_max_speed_mode(port);

455 456 457 458 459 460
	if (chip->info->ops->port_set_pause) {
		err = chip->info->ops->port_set_pause(chip, port, pause);
		if (err)
			goto restore_link;
	}

461
	err = mv88e6xxx_port_config_interface(chip, port, mode);
462 463
restore_link:
	if (chip->info->ops->port_set_link(chip, port, link))
464
		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
465 466 467 468

	return err;
}

469 470 471 472 473 474 475
static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;

	return port < chip->info->num_internal_phys;
}

476 477 478 479 480
static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
{
	u16 reg;
	int err;

481 482 483 484 485 486
	/* The 88e6250 family does not have the PHY detect bit. Instead,
	 * report whether the port is internal.
	 */
	if (chip->info->family == MV88E6XXX_FAMILY_6250)
		return port < chip->info->num_internal_phys;

487 488 489 490 491 492 493 494 495 496 497
	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
	if (err) {
		dev_err(chip->dev,
			"p%d: %s: failed to read port status\n",
			port, __func__);
		return err;
	}

	return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
}

498 499 500 501
static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
					  struct phylink_link_state *state)
{
	struct mv88e6xxx_chip *chip = ds->priv;
502
	int lane;
503 504 505 506
	int err;

	mv88e6xxx_reg_lock(chip);
	lane = mv88e6xxx_serdes_get_lane(chip, port);
507
	if (lane >= 0 && chip->info->ops->serdes_pcs_get_state)
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
		err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
							    state);
	else
		err = -EOPNOTSUPP;
	mv88e6xxx_reg_unlock(chip);

	return err;
}

static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
				       unsigned int mode,
				       phy_interface_t interface,
				       const unsigned long *advertise)
{
	const struct mv88e6xxx_ops *ops = chip->info->ops;
523
	int lane;
524 525 526

	if (ops->serdes_pcs_config) {
		lane = mv88e6xxx_serdes_get_lane(chip, port);
527
		if (lane >= 0)
528 529 530 531 532 533 534 535 536 537 538 539
			return ops->serdes_pcs_config(chip, port, lane, mode,
						      interface, advertise);
	}

	return 0;
}

static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	const struct mv88e6xxx_ops *ops;
	int err = 0;
540
	int lane;
541 542 543 544 545 546

	ops = chip->info->ops;

	if (ops->serdes_pcs_an_restart) {
		mv88e6xxx_reg_lock(chip);
		lane = mv88e6xxx_serdes_get_lane(chip, port);
547
		if (lane >= 0)
548 549 550 551 552 553 554 555 556 557 558 559 560
			err = ops->serdes_pcs_an_restart(chip, port, lane);
		mv88e6xxx_reg_unlock(chip);

		if (err)
			dev_err(ds->dev, "p%d: failed to restart AN\n", port);
	}
}

static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
					unsigned int mode,
					int speed, int duplex)
{
	const struct mv88e6xxx_ops *ops = chip->info->ops;
561
	int lane;
562 563 564

	if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
		lane = mv88e6xxx_serdes_get_lane(chip, port);
565
		if (lane >= 0)
566 567 568 569 570 571 572
			return ops->serdes_pcs_link_up(chip, port, lane,
						       speed, duplex);
	}

	return 0;
}

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
static const u8 mv88e6185_phy_interface_modes[] = {
	[MV88E6185_PORT_STS_CMODE_GMII_FD]	 = PHY_INTERFACE_MODE_GMII,
	[MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII,
	[MV88E6185_PORT_STS_CMODE_MII_100]	 = PHY_INTERFACE_MODE_MII,
	[MV88E6185_PORT_STS_CMODE_MII_10]	 = PHY_INTERFACE_MODE_MII,
	[MV88E6185_PORT_STS_CMODE_SERDES]	 = PHY_INTERFACE_MODE_1000BASEX,
	[MV88E6185_PORT_STS_CMODE_1000BASE_X]	 = PHY_INTERFACE_MODE_1000BASEX,
	[MV88E6185_PORT_STS_CMODE_PHY]		 = PHY_INTERFACE_MODE_SGMII,
};

static void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
				       struct phylink_config *config)
{
	u8 cmode = chip->ports[port].cmode;

	if (cmode <= ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
	    mv88e6185_phy_interface_modes[cmode])
		__set_bit(mv88e6185_phy_interface_modes[cmode],
			  config->supported_interfaces);
592

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
				   MAC_1000FD;
}

static const u8 mv88e6xxx_phy_interface_modes[] = {
	[MV88E6XXX_PORT_STS_CMODE_MII_PHY]	= PHY_INTERFACE_MODE_MII,
	[MV88E6XXX_PORT_STS_CMODE_MII]		= PHY_INTERFACE_MODE_MII,
	[MV88E6XXX_PORT_STS_CMODE_GMII]		= PHY_INTERFACE_MODE_GMII,
	[MV88E6XXX_PORT_STS_CMODE_RMII_PHY]	= PHY_INTERFACE_MODE_RMII,
	[MV88E6XXX_PORT_STS_CMODE_RMII]		= PHY_INTERFACE_MODE_RMII,
	[MV88E6XXX_PORT_STS_CMODE_100BASEX]	= PHY_INTERFACE_MODE_100BASEX,
	[MV88E6XXX_PORT_STS_CMODE_1000BASEX]	= PHY_INTERFACE_MODE_1000BASEX,
	[MV88E6XXX_PORT_STS_CMODE_SGMII]	= PHY_INTERFACE_MODE_SGMII,
	/* higher interface modes are not needed here, since ports supporting
	 * them are writable, and so the supported interfaces are filled in the
	 * corresponding .phylink_set_interfaces() implementation below
609
	 */
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
};

static void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported)
{
	if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) &&
	    mv88e6xxx_phy_interface_modes[cmode])
		__set_bit(mv88e6xxx_phy_interface_modes[cmode], supported);
	else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII)
		phy_interface_set_rgmii(supported);
}

static void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
				       struct phylink_config *config)
{
	unsigned long *supported = config->supported_interfaces;

	/* Translate the default cmode */
	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);

	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
}

static int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip)
{
	u16 reg, val;
	int err;

	err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &reg);
	if (err)
		return err;

	/* If PHY_DETECT is zero, then we are not in auto-media mode */
	if (!(reg & MV88E6XXX_PORT_STS_PHY_DETECT))
		return 0xf;

	val = reg & ~MV88E6XXX_PORT_STS_PHY_DETECT;
	err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, val);
	if (err)
		return err;

	err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &val);
	if (err)
		return err;

	/* Restore PHY_DETECT value */
	err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, reg);
	if (err)
		return err;

	return val & MV88E6XXX_PORT_STS_CMODE_MASK;
}

static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
				       struct phylink_config *config)
{
	unsigned long *supported = config->supported_interfaces;
	int err, cmode;

	/* Translate the default cmode */
	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);

	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
				   MAC_1000FD;

	/* Port 4 supports automedia if the serdes is associated with it. */
	if (port == 4) {
		mv88e6xxx_reg_lock(chip);
		err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
		if (err < 0)
			dev_err(chip->dev, "p%d: failed to read scratch\n",
				port);
		if (err <= 0)
			goto unlock;

		cmode = mv88e6352_get_port4_serdes_cmode(chip);
		if (cmode < 0)
			dev_err(chip->dev, "p%d: failed to read serdes cmode\n",
				port);
		else
			mv88e6xxx_translate_cmode(cmode, supported);
unlock:
		mv88e6xxx_reg_unlock(chip);
	}
}

static void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
				       struct phylink_config *config)
{
	unsigned long *supported = config->supported_interfaces;

	/* Translate the default cmode */
	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);

	/* No ethtool bits for 200Mbps */
	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
				   MAC_1000FD;

	/* The C_Mode field is programmable on port 5 */
	if (port == 5) {
		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);

		config->mac_capabilities |= MAC_2500FD;
	}
}

static void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
				       struct phylink_config *config)
{
	unsigned long *supported = config->supported_interfaces;

	/* Translate the default cmode */
	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);

	/* No ethtool bits for 200Mbps */
	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
				   MAC_1000FD;

	/* The C_Mode field is programmable on ports 9 and 10 */
	if (port == 9 || port == 10) {
		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);

		config->mac_capabilities |= MAC_2500FD;
	}
}

static void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
					struct phylink_config *config)
{
	unsigned long *supported = config->supported_interfaces;

	mv88e6390_phylink_get_caps(chip, port, config);

	/* For the 6x90X, ports 2-7 can be in automedia mode.
	 * (Note that 6x90 doesn't support RXAUI nor XAUI).
	 *
	 * Port 2 can also support 1000BASE-X in automedia mode if port 9 is
	 * configured for 1000BASE-X, SGMII or 2500BASE-X.
	 * Port 3-4 can also support 1000BASE-X in automedia mode if port 9 is
	 * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X.
	 *
	 * Port 5 can also support 1000BASE-X in automedia mode if port 10 is
	 * configured for 1000BASE-X, SGMII or 2500BASE-X.
	 * Port 6-7 can also support 1000BASE-X in automedia mode if port 10 is
	 * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X.
	 *
	 * For now, be permissive (as the old code was) and allow 1000BASE-X
	 * on ports 2..7.
	 */
	if (port >= 2 && port <= 7)
		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);

	/* The C_Mode field can also be programmed for 10G speeds */
	if (port == 9 || port == 10) {
		__set_bit(PHY_INTERFACE_MODE_XAUI, supported);
		__set_bit(PHY_INTERFACE_MODE_RXAUI, supported);

		config->mac_capabilities |= MAC_10000FD;
	}
}

static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
					struct phylink_config *config)
{
	unsigned long *supported = config->supported_interfaces;
	bool is_6191x =
		chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;

	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);

	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
				   MAC_1000FD;

	/* The C_Mode field can be programmed for ports 0, 9 and 10 */
	if (port == 0 || port == 9 || port == 10) {
		__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);

		/* 6191X supports >1G modes only on port 10 */
		if (!is_6191x || port == 10) {
			__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
			__set_bit(PHY_INTERFACE_MODE_5GBASER, supported);
			__set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
			/* FIXME: USXGMII is not supported yet */
			/* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */

			config->mac_capabilities |= MAC_2500FD | MAC_5000FD |
				MAC_10000FD;
		}
	}
}

static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
			       struct phylink_config *config)
{
	struct mv88e6xxx_chip *chip = ds->priv;

	chip->info->ops->phylink_get_caps(chip, port, config);

	/* Internal ports need GMII for PHYLIB */
	if (mv88e6xxx_phy_is_internal(ds, port))
		__set_bit(PHY_INTERFACE_MODE_GMII,
			  config->supported_interfaces);
816 817 818 819 820 821 822
}

static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
				 unsigned int mode,
				 const struct phylink_link_state *state)
{
	struct mv88e6xxx_chip *chip = ds->priv;
823
	struct mv88e6xxx_port *p;
824
	int err = 0;
825

826 827
	p = &chip->ports[port];

828
	mv88e6xxx_reg_lock(chip);
829

830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
	if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) {
		/* In inband mode, the link may come up at any time while the
		 * link is not forced down. Force the link down while we
		 * reconfigure the interface mode.
		 */
		if (mode == MLO_AN_INBAND &&
		    p->interface != state->interface &&
		    chip->info->ops->port_set_link)
			chip->info->ops->port_set_link(chip, port,
						       LINK_FORCED_DOWN);

		err = mv88e6xxx_port_config_interface(chip, port,
						      state->interface);
		if (err && err != -EOPNOTSUPP)
			goto err_unlock;

		err = mv88e6xxx_serdes_pcs_config(chip, port, mode,
						  state->interface,
						  state->advertising);
		/* FIXME: we should restart negotiation if something changed -
		 * which is something we get if we convert to using phylinks
		 * PCS operations.
		 */
		if (err > 0)
			err = 0;
	}
856

857
	/* Undo the forced down state above after completing configuration
858 859 860 861
	 * irrespective of its state on entry, which allows the link to come
	 * up in the in-band case where there is no separate SERDES. Also
	 * ensure that the link can come up if the PPU is in use and we are
	 * in PHY mode (we treat the PPU as an effective in-band mechanism.)
862
	 */
863 864 865
	if (chip->info->ops->port_set_link &&
	    ((mode == MLO_AN_INBAND && p->interface != state->interface) ||
	     (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port))))
866 867 868 869
		chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);

	p->interface = state->interface;

870
err_unlock:
871
	mv88e6xxx_reg_unlock(chip);
872 873

	if (err && err != -EOPNOTSUPP)
874
		dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port);
875 876
}

877 878 879
static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
				    unsigned int mode,
				    phy_interface_t interface)
880 881
{
	struct mv88e6xxx_chip *chip = ds->priv;
882 883
	const struct mv88e6xxx_ops *ops;
	int err = 0;
884

885
	ops = chip->info->ops;
886

887
	mv88e6xxx_reg_lock(chip);
888 889
	/* Force the link down if we know the port may not be automatically
	 * updated by the switch or if we are using fixed-link mode.
890
	 */
891
	if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
892 893
	     mode == MLO_AN_FIXED) && ops->port_sync_link)
		err = ops->port_sync_link(chip, port, mode, false);
894 895 896 897

	if (!err && ops->port_set_speed_duplex)
		err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED,
						 DUPLEX_UNFORCED);
898
	mv88e6xxx_reg_unlock(chip);
899

900 901 902
	if (err)
		dev_err(chip->dev,
			"p%d: failed to force MAC link down\n", port);
903 904 905 906
}

static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
				  unsigned int mode, phy_interface_t interface,
907 908 909
				  struct phy_device *phydev,
				  int speed, int duplex,
				  bool tx_pause, bool rx_pause)
910
{
911 912 913 914 915 916
	struct mv88e6xxx_chip *chip = ds->priv;
	const struct mv88e6xxx_ops *ops;
	int err = 0;

	ops = chip->info->ops;

917
	mv88e6xxx_reg_lock(chip);
918 919 920
	/* Configure and force the link up if we know that the port may not
	 * automatically updated by the switch or if we are using fixed-link
	 * mode.
921
	 */
922
	if (!mv88e6xxx_port_ppu_updates(chip, port) ||
923
	    mode == MLO_AN_FIXED) {
924 925 926
		/* FIXME: for an automedia port, should we force the link
		 * down here - what if the link comes up due to "other" media
		 * while we're bringing the port up, how is the exclusivity
927
		 * handled in the Marvell hardware? E.g. port 2 on 88E6390
928 929
		 * shared between internal PHY and Serdes.
		 */
930 931 932 933 934
		err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
						   duplex);
		if (err)
			goto error;

935 936 937
		if (ops->port_set_speed_duplex) {
			err = ops->port_set_speed_duplex(chip, port,
							 speed, duplex);
938 939 940 941
			if (err && err != -EOPNOTSUPP)
				goto error;
		}

942 943
		if (ops->port_sync_link)
			err = ops->port_sync_link(chip, port, mode, true);
944
	}
945
error:
946
	mv88e6xxx_reg_unlock(chip);
947

948 949 950
	if (err && err != -EOPNOTSUPP)
		dev_err(ds->dev,
			"p%d: failed to configure MAC link up\n", port);
951 952
}

953
static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
954
{
955 956
	if (!chip->info->ops->stats_snapshot)
		return -EOPNOTSUPP;
957

958
	return chip->info->ops->stats_snapshot(chip, port);
959 960
}

961
static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
	{ "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, },
1021 1022
};

1023
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
1024
					    struct mv88e6xxx_hw_stat *s,
1025 1026
					    int port, u16 bank1_select,
					    u16 histogram)
1027 1028 1029
{
	u32 low;
	u32 high = 0;
1030
	u16 reg = 0;
1031
	int err;
1032 1033
	u64 value;

1034
	switch (s->type) {
1035
	case STATS_TYPE_PORT:
1036 1037
		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
		if (err)
1038
			return U64_MAX;
1039

1040
		low = reg;
1041
		if (s->size == 4) {
1042 1043
			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
			if (err)
1044
				return U64_MAX;
1045
			low |= ((u32)reg) << 16;
1046
		}
1047
		break;
1048
	case STATS_TYPE_BANK1:
1049
		reg = bank1_select;
1050
		fallthrough;
1051
	case STATS_TYPE_BANK0:
1052
		reg |= s->reg | histogram;
1053
		mv88e6xxx_g1_stats_read(chip, reg, &low);
1054
		if (s->size == 8)
1055
			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
1056 1057
		break;
	default:
1058
		return U64_MAX;
1059
	}
1060
	value = (((u64)high) << 32) | low;
1061 1062 1063
	return value;
}

1064 1065
static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
				       uint8_t *data, int types)
1066
{
1067 1068
	struct mv88e6xxx_hw_stat *stat;
	int i, j;
1069

1070 1071
	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
		stat = &mv88e6xxx_hw_stats[i];
1072
		if (stat->type & types) {
1073 1074 1075 1076
			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
			       ETH_GSTRING_LEN);
			j++;
		}
1077
	}
1078 1079

	return j;
1080 1081
}

1082 1083
static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
				       uint8_t *data)
1084
{
1085 1086
	return mv88e6xxx_stats_get_strings(chip, data,
					   STATS_TYPE_BANK0 | STATS_TYPE_PORT);
1087 1088
}

1089 1090 1091 1092 1093 1094
static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
				       uint8_t *data)
{
	return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
}

1095 1096
static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
				       uint8_t *data)
1097
{
1098 1099
	return mv88e6xxx_stats_get_strings(chip, data,
					   STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
1100 1101
}

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
	"atu_member_violation",
	"atu_miss_violation",
	"atu_full_violation",
	"vtu_member_violation",
	"vtu_miss_violation",
};

static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
		strlcpy(data + i * ETH_GSTRING_LEN,
			mv88e6xxx_atu_vtu_stats_strings[i],
			ETH_GSTRING_LEN);
}

1120
static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
1121
				  u32 stringset, uint8_t *data)
1122
{
V
Vivien Didelot 已提交
1123
	struct mv88e6xxx_chip *chip = ds->priv;
1124
	int count = 0;
1125

1126 1127 1128
	if (stringset != ETH_SS_STATS)
		return;

1129
	mv88e6xxx_reg_lock(chip);
1130

1131
	if (chip->info->ops->stats_get_strings)
1132 1133 1134 1135
		count = chip->info->ops->stats_get_strings(chip, data);

	if (chip->info->ops->serdes_get_strings) {
		data += count * ETH_GSTRING_LEN;
1136
		count = chip->info->ops->serdes_get_strings(chip, port, data);
1137
	}
1138

1139 1140 1141
	data += count * ETH_GSTRING_LEN;
	mv88e6xxx_atu_vtu_get_strings(data);

1142
	mv88e6xxx_reg_unlock(chip);
1143 1144 1145 1146 1147
}

static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
					  int types)
{
1148 1149 1150 1151 1152
	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];
1153
		if (stat->type & types)
1154 1155 1156
			j++;
	}
	return j;
1157 1158
}

1159 1160 1161 1162 1163 1164
static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
					      STATS_TYPE_PORT);
}

1165 1166 1167 1168 1169
static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
}

1170 1171 1172 1173 1174 1175
static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
					      STATS_TYPE_BANK1);
}

1176
static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
1177 1178
{
	struct mv88e6xxx_chip *chip = ds->priv;
1179 1180
	int serdes_count = 0;
	int count = 0;
1181

1182 1183 1184
	if (sset != ETH_SS_STATS)
		return 0;

1185
	mv88e6xxx_reg_lock(chip);
1186
	if (chip->info->ops->stats_get_sset_count)
1187 1188 1189 1190 1191 1192 1193
		count = chip->info->ops->stats_get_sset_count(chip);
	if (count < 0)
		goto out;

	if (chip->info->ops->serdes_get_sset_count)
		serdes_count = chip->info->ops->serdes_get_sset_count(chip,
								      port);
1194
	if (serdes_count < 0) {
1195
		count = serdes_count;
1196 1197 1198 1199 1200
		goto out;
	}
	count += serdes_count;
	count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);

1201
out:
1202
	mv88e6xxx_reg_unlock(chip);
1203

1204
	return count;
1205 1206
}

1207 1208 1209
static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				     uint64_t *data, int types,
				     u16 bank1_select, u16 histogram)
1210 1211 1212 1213 1214 1215 1216
{
	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) {
1217
			mv88e6xxx_reg_lock(chip);
1218 1219 1220
			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
							      bank1_select,
							      histogram);
1221
			mv88e6xxx_reg_unlock(chip);
1222

1223 1224 1225
			j++;
		}
	}
1226
	return j;
1227 1228
}

1229 1230
static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				     uint64_t *data)
1231 1232
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
1233
					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
1234
					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1235 1236
}

1237 1238 1239 1240 1241 1242 1243
static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				     uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
					 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
}

1244 1245
static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				     uint64_t *data)
1246 1247
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
1248
					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
1249 1250
					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
					 MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
1251 1252
}

1253 1254
static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				     uint64_t *data)
1255 1256 1257
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
1258 1259
					 MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
					 0);
1260 1261
}

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
					uint64_t *data)
{
	*data++ = chip->ports[port].atu_member_violation;
	*data++ = chip->ports[port].atu_miss_violation;
	*data++ = chip->ports[port].atu_full_violation;
	*data++ = chip->ports[port].vtu_member_violation;
	*data++ = chip->ports[port].vtu_miss_violation;
}

1272 1273 1274
static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
				uint64_t *data)
{
1275 1276
	int count = 0;

1277
	if (chip->info->ops->stats_get_stats)
1278 1279
		count = chip->info->ops->stats_get_stats(chip, port, data);

1280
	mv88e6xxx_reg_lock(chip);
1281 1282
	if (chip->info->ops->serdes_get_stats) {
		data += count;
1283
		count = chip->info->ops->serdes_get_stats(chip, port, data);
1284
	}
1285 1286
	data += count;
	mv88e6xxx_atu_vtu_get_stats(chip, port, data);
1287
	mv88e6xxx_reg_unlock(chip);
1288 1289
}

1290 1291
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
					uint64_t *data)
1292
{
V
Vivien Didelot 已提交
1293
	struct mv88e6xxx_chip *chip = ds->priv;
1294 1295
	int ret;

1296
	mv88e6xxx_reg_lock(chip);
1297

1298
	ret = mv88e6xxx_stats_snapshot(chip, port);
1299
	mv88e6xxx_reg_unlock(chip);
1300 1301

	if (ret < 0)
1302
		return;
1303 1304

	mv88e6xxx_get_stats(chip, port, data);
1305

1306 1307
}

1308
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1309
{
1310 1311 1312 1313 1314 1315 1316 1317
	struct mv88e6xxx_chip *chip = ds->priv;
	int len;

	len = 32 * sizeof(u16);
	if (chip->info->ops->serdes_get_regs_len)
		len += chip->info->ops->serdes_get_regs_len(chip, port);

	return len;
1318 1319
}

1320 1321
static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
			       struct ethtool_regs *regs, void *_p)
1322
{
V
Vivien Didelot 已提交
1323
	struct mv88e6xxx_chip *chip = ds->priv;
1324 1325
	int err;
	u16 reg;
1326 1327 1328
	u16 *p = _p;
	int i;

1329
	regs->version = chip->info->prod_num;
1330 1331 1332

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

1333
	mv88e6xxx_reg_lock(chip);
1334

1335 1336
	for (i = 0; i < 32; i++) {

1337 1338 1339
		err = mv88e6xxx_port_read(chip, port, i, &reg);
		if (!err)
			p[i] = reg;
1340
	}
1341

1342 1343 1344
	if (chip->info->ops->serdes_get_regs)
		chip->info->ops->serdes_get_regs(chip, port, &p[i]);

1345
	mv88e6xxx_reg_unlock(chip);
1346 1347
}

V
Vivien Didelot 已提交
1348 1349
static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
				 struct ethtool_eee *e)
1350
{
1351 1352
	/* Nothing to do on the port's MAC */
	return 0;
1353 1354
}

V
Vivien Didelot 已提交
1355 1356
static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port,
				 struct ethtool_eee *e)
1357
{
1358 1359
	/* Nothing to do on the port's MAC */
	return 0;
1360 1361
}

1362
/* Mask of the local ports allowed to receive frames from a given fabric port */
1363
static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
1364
{
1365 1366
	struct dsa_switch *ds = chip->ds;
	struct dsa_switch_tree *dst = ds->dst;
1367
	struct dsa_port *dp, *other_dp;
1368
	bool found = false;
1369
	u16 pvlan;
1370

1371 1372 1373 1374 1375
	/* dev is a physical switch */
	if (dev <= dst->last_switch) {
		list_for_each_entry(dp, &dst->ports, list) {
			if (dp->ds->index == dev && dp->index == port) {
				/* dp might be a DSA link or a user port, so it
1376 1377
				 * might or might not have a bridge.
				 * Use the "found" variable for both cases.
1378 1379 1380 1381 1382 1383 1384 1385
				 */
				found = true;
				break;
			}
		}
	/* dev is a virtual bridge */
	} else {
		list_for_each_entry(dp, &dst->ports, list) {
1386 1387 1388
			unsigned int bridge_num = dsa_port_bridge_num_get(dp);

			if (!bridge_num)
1389 1390
				continue;

1391
			if (bridge_num + dst->last_switch != dev)
1392 1393
				continue;

1394 1395 1396 1397
			found = true;
			break;
		}
	}
1398

1399
	/* Prevent frames from unknown switch or virtual bridge */
1400
	if (!found)
1401 1402 1403
		return 0;

	/* Frames from DSA links and CPU ports can egress any local port */
1404
	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA)
1405 1406 1407 1408
		return mv88e6xxx_port_mask(chip);

	pvlan = 0;

1409 1410 1411 1412 1413 1414 1415 1416 1417
	/* Frames from standalone user ports can only egress on the
	 * upstream port.
	 */
	if (!dsa_port_bridge_dev_get(dp))
		return BIT(dsa_switch_upstream_port(ds));

	/* Frames from bridged user ports can egress any local DSA
	 * links and CPU ports, as well as any local member of their
	 * bridge group.
1418
	 */
1419 1420 1421
	dsa_switch_for_each_port(other_dp, ds)
		if (other_dp->type == DSA_PORT_TYPE_CPU ||
		    other_dp->type == DSA_PORT_TYPE_DSA ||
1422
		    dsa_port_bridge_same(dp, other_dp))
1423
			pvlan |= BIT(other_dp->index);
1424 1425 1426 1427

	return pvlan;
}

1428
static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port)
1429 1430
{
	u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port);
1431 1432 1433

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

1435
	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1436 1437
}

1438 1439
static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
					 u8 state)
1440
{
V
Vivien Didelot 已提交
1441
	struct mv88e6xxx_chip *chip = ds->priv;
1442
	int err;
1443

1444
	mv88e6xxx_reg_lock(chip);
1445
	err = mv88e6xxx_port_set_state(chip, port, state);
1446
	mv88e6xxx_reg_unlock(chip);
1447 1448

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

1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470
static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
{
	int err;

	if (chip->info->ops->ieee_pri_map) {
		err = chip->info->ops->ieee_pri_map(chip);
		if (err)
			return err;
	}

	if (chip->info->ops->ip_pri_map) {
		err = chip->info->ops->ip_pri_map(chip);
		if (err)
			return err;
	}

	return 0;
}

1471 1472
static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
{
1473
	struct dsa_switch *ds = chip->ds;
1474 1475 1476 1477 1478 1479 1480 1481
	int target, port;
	int err;

	if (!chip->info->global2_addr)
		return 0;

	/* Initialize the routing port to the 32 possible target devices */
	for (target = 0; target < 32; target++) {
1482 1483 1484
		port = dsa_routing_port(ds, target);
		if (port == ds->num_ports)
			port = 0x1f;
1485 1486 1487 1488 1489 1490

		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
		if (err)
			return err;
	}

1491 1492 1493 1494 1495 1496 1497
	if (chip->info->ops->set_cascade_port) {
		port = MV88E6XXX_CASCADE_PORT_MULTIPLE;
		err = chip->info->ops->set_cascade_port(chip, port);
		if (err)
			return err;
	}

1498 1499 1500 1501
	err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index);
	if (err)
		return err;

1502 1503 1504
	return 0;
}

1505 1506 1507 1508 1509 1510 1511 1512 1513
static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip)
{
	/* Clear all trunk masks and mapping */
	if (chip->info->global2_addr)
		return mv88e6xxx_g2_trunk_clear(chip);

	return 0;
}

1514 1515 1516 1517 1518 1519 1520 1521
static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->rmu_disable)
		return chip->info->ops->rmu_disable(chip);

	return 0;
}

1522 1523 1524 1525 1526 1527 1528 1529
static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->pot_clear)
		return chip->info->ops->pot_clear(chip);

	return 0;
}

1530 1531 1532 1533 1534 1535 1536 1537
static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->mgmt_rsvd2cpu)
		return chip->info->ops->mgmt_rsvd2cpu(chip);

	return 0;
}

1538 1539
static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
{
1540 1541
	int err;

1542 1543 1544 1545
	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
	if (err)
		return err;

1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
	/* The chips that have a "learn2all" bit in Global1, ATU
	 * Control are precisely those whose port registers have a
	 * Message Port bit in Port Control 1 and hence implement
	 * ->port_setup_message_port.
	 */
	if (chip->info->ops->port_setup_message_port) {
		err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
		if (err)
			return err;
	}
1556

1557 1558 1559
	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
}

1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
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;
}

1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
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;
}

1593 1594
static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port)
{
1595 1596 1597
	struct dsa_switch_tree *dst = chip->ds->dst;
	struct dsa_switch *ds;
	struct dsa_port *dp;
1598 1599 1600
	u16 pvlan = 0;

	if (!mv88e6xxx_has_pvt(chip))
1601
		return 0;
1602 1603

	/* Skip the local source device, which uses in-chip port VLAN */
1604
	if (dev != chip->ds->index) {
1605
		pvlan = mv88e6xxx_port_vlan(chip, dev, port);
1606

1607 1608 1609 1610 1611 1612 1613 1614 1615
		ds = dsa_switch_find(dst->index, dev);
		dp = ds ? dsa_to_port(ds, port) : NULL;
		if (dp && dp->lag_dev) {
			/* As the PVT is used to limit flooding of
			 * FORWARD frames, which use the LAG ID as the
			 * source port, we must translate dev/port to
			 * the special "LAG device" in the PVT, using
			 * the LAG ID as the port number.
			 */
1616
			dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK;
1617 1618 1619 1620
			port = dsa_lag_id(dst, dp->lag_dev);
		}
	}

1621 1622 1623
	return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan);
}

1624 1625
static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip)
{
1626 1627 1628
	int dev, port;
	int err;

1629 1630 1631 1632 1633 1634
	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.
	 */
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
	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;
1648 1649
}

1650 1651 1652 1653 1654
static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

1655 1656 1657 1658 1659 1660 1661
	if (dsa_to_port(ds, port)->lag_dev)
		/* Hardware is incapable of fast-aging a LAG through a
		 * regular ATU move operation. Until we have something
		 * more fancy in place this is a no-op.
		 */
		return;

1662
	mv88e6xxx_reg_lock(chip);
1663
	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1664
	mv88e6xxx_reg_unlock(chip);
1665 1666

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

1670 1671
static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip)
{
1672
	if (!mv88e6xxx_max_vid(chip))
1673 1674 1675 1676 1677
		return 0;

	return mv88e6xxx_g1_vtu_flush(chip);
}

1678 1679
static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
			     struct mv88e6xxx_vtu_entry *entry)
1680
{
1681 1682
	int err;

1683 1684 1685
	if (!chip->info->ops->vtu_getnext)
		return -EOPNOTSUPP;

1686 1687 1688 1689 1690 1691 1692 1693 1694
	entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip);
	entry->valid = false;

	err = chip->info->ops->vtu_getnext(chip, entry);

	if (entry->vid != vid)
		entry->valid = false;

	return err;
1695 1696
}

1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
			      int (*cb)(struct mv88e6xxx_chip *chip,
					const struct mv88e6xxx_vtu_entry *entry,
					void *priv),
			      void *priv)
{
	struct mv88e6xxx_vtu_entry entry = {
		.vid = mv88e6xxx_max_vid(chip),
		.valid = false,
	};
	int err;

	if (!chip->info->ops->vtu_getnext)
		return -EOPNOTSUPP;

	do {
		err = chip->info->ops->vtu_getnext(chip, &entry);
		if (err)
			return err;

		if (!entry.valid)
			break;

		err = cb(chip, &entry, priv);
		if (err)
			return err;
	} while (entry.vid < mv88e6xxx_max_vid(chip));

	return 0;
}

1728 1729 1730 1731 1732 1733 1734 1735 1736
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);
}

1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
static int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip,
				  const struct mv88e6xxx_vtu_entry *entry,
				  void *_fid_bitmap)
{
	unsigned long *fid_bitmap = _fid_bitmap;

	set_bit(entry->fid, fid_bitmap);
	return 0;
}

1747
int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap)
1748 1749 1750
{
	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);

1751 1752 1753
	/* Every FID has an associated VID, so walking the VTU
	 * will discover the full set of FIDs in use.
	 */
1754
	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap);
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
}

static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
{
	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
	int err;

	err = mv88e6xxx_fid_map(chip, fid_bitmap);
	if (err)
		return err;

1766
	*fid = find_first_zero_bit(fid_bitmap, MV88E6XXX_N_FID);
1767
	if (unlikely(*fid >= mv88e6xxx_num_databases(chip)))
1768 1769 1770
		return -ENOSPC;

	/* Clear the database */
1771
	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1772 1773
}

1774
static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
1775
					u16 vid)
1776
{
1777
	struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
V
Vivien Didelot 已提交
1778
	struct mv88e6xxx_chip *chip = ds->priv;
1779
	struct mv88e6xxx_vtu_entry vlan;
1780
	int err;
1781

1782
	/* DSA and CPU ports have to be members of multiple vlans */
1783
	if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
1784 1785
		return 0;

1786
	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
1787 1788
	if (err)
		return err;
1789

1790 1791
	if (!vlan.valid)
		return 0;
1792

1793
	dsa_switch_for_each_user_port(other_dp, ds) {
1794 1795
		struct net_device *other_br;

1796
		if (vlan.member[other_dp->index] ==
1797 1798
		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
			continue;
1799

1800
		if (dsa_port_bridge_same(dp, other_dp))
1801
			break; /* same bridge, check next VLAN */
1802

1803 1804
		other_br = dsa_port_bridge_dev_get(other_dp);
		if (!other_br)
1805
			continue;
1806

1807
		dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1808
			port, vlan.vid, other_dp->index, netdev_name(other_br));
1809 1810
		return -EOPNOTSUPP;
	}
1811

1812
	return 0;
1813 1814
}

1815 1816 1817
static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
{
	struct dsa_port *dp = dsa_to_port(chip->ds, port);
1818
	struct net_device *br = dsa_port_bridge_dev_get(dp);
1819
	struct mv88e6xxx_port *p = &chip->ports[port];
1820
	u16 pvid = MV88E6XXX_VID_STANDALONE;
1821 1822 1823
	bool drop_untagged = false;
	int err;

1824 1825
	if (br) {
		if (br_vlan_enabled(br)) {
1826 1827 1828 1829 1830
			pvid = p->bridge_pvid.vid;
			drop_untagged = !p->bridge_pvid.valid;
		} else {
			pvid = MV88E6XXX_VID_BRIDGED;
		}
1831 1832 1833 1834 1835 1836 1837 1838 1839
	}

	err = mv88e6xxx_port_set_pvid(chip, port, pvid);
	if (err)
		return err;

	return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
}

1840
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
1841 1842
					 bool vlan_filtering,
					 struct netlink_ext_ack *extack)
1843
{
V
Vivien Didelot 已提交
1844
	struct mv88e6xxx_chip *chip = ds->priv;
1845 1846
	u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
		MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
1847
	int err;
1848

1849 1850
	if (!mv88e6xxx_max_vid(chip))
		return -EOPNOTSUPP;
1851

1852
	mv88e6xxx_reg_lock(chip);
1853

1854
	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1855 1856 1857 1858 1859 1860 1861 1862
	if (err)
		goto unlock;

	err = mv88e6xxx_port_commit_pvid(chip, port);
	if (err)
		goto unlock;

unlock:
1863
	mv88e6xxx_reg_unlock(chip);
1864

1865
	return err;
1866 1867
}

1868 1869
static int
mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
1870
			    const struct switchdev_obj_port_vlan *vlan)
1871
{
V
Vivien Didelot 已提交
1872
	struct mv88e6xxx_chip *chip = ds->priv;
1873 1874
	int err;

1875
	if (!mv88e6xxx_max_vid(chip))
1876 1877
		return -EOPNOTSUPP;

1878 1879 1880
	/* 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.
	 */
1881
	mv88e6xxx_reg_lock(chip);
1882
	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid);
1883
	mv88e6xxx_reg_unlock(chip);
1884

1885
	return err;
1886 1887
}

1888 1889 1890 1891 1892
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
					const unsigned char *addr, u16 vid,
					u8 state)
{
	struct mv88e6xxx_atu_entry entry;
1893 1894
	struct mv88e6xxx_vtu_entry vlan;
	u16 fid;
1895 1896
	int err;

1897 1898 1899 1900 1901 1902 1903
	/* Ports have two private address databases: one for when the port is
	 * standalone and one for when the port is under a bridge and the
	 * 802.1Q mode is disabled. When the port is standalone, DSA wants its
	 * address database to remain 100% empty, so we never load an ATU entry
	 * into a standalone port's database. Therefore, translate the null
	 * VLAN ID into the port's database used for VLAN-unaware bridging.
	 */
1904
	if (vid == 0) {
1905
		fid = MV88E6XXX_FID_BRIDGED;
1906
	} else {
1907
		err = mv88e6xxx_vtu_get(chip, vid, &vlan);
1908 1909 1910 1911
		if (err)
			return err;

		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
1912
		if (!vlan.valid)
1913 1914 1915 1916
			return -EOPNOTSUPP;

		fid = vlan.fid;
	}
1917

1918
	entry.state = 0;
1919 1920 1921
	ether_addr_copy(entry.mac, addr);
	eth_addr_dec(entry.mac);

1922
	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
1923 1924 1925 1926
	if (err)
		return err;

	/* Initialize a fresh ATU entry if it isn't found */
1927
	if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
1928 1929 1930 1931 1932
		memset(&entry, 0, sizeof(entry));
		ether_addr_copy(entry.mac, addr);
	}

	/* Purge the ATU entry only if no port is using it anymore */
1933
	if (!state) {
1934 1935
		entry.portvec &= ~BIT(port);
		if (!entry.portvec)
1936
			entry.state = 0;
1937
	} else {
1938 1939 1940 1941 1942
		if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
			entry.portvec = BIT(port);
		else
			entry.portvec |= BIT(port);

1943 1944 1945
		entry.state = state;
	}

1946
	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
1947 1948
}

1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
				  const struct mv88e6xxx_policy *policy)
{
	enum mv88e6xxx_policy_mapping mapping = policy->mapping;
	enum mv88e6xxx_policy_action action = policy->action;
	const u8 *addr = policy->addr;
	u16 vid = policy->vid;
	u8 state;
	int err;
	int id;

	if (!chip->info->ops->port_set_policy)
		return -EOPNOTSUPP;

	switch (mapping) {
	case MV88E6XXX_POLICY_MAPPING_DA:
	case MV88E6XXX_POLICY_MAPPING_SA:
		if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
			state = 0; /* Dissociate the port and address */
		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
			 is_multicast_ether_addr(addr))
			state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
		else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
			 is_unicast_ether_addr(addr))
			state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
		else
			return -EOPNOTSUPP;

		err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
						   state);
		if (err)
			return err;
		break;
	default:
		return -EOPNOTSUPP;
	}

	/* Skip the port's policy clearing if the mapping is still in use */
	if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
		idr_for_each_entry(&chip->policies, policy, id)
			if (policy->port == port &&
			    policy->mapping == mapping &&
			    policy->action != action)
				return 0;

	return chip->info->ops->port_set_policy(chip, port, mapping, action);
}

static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
				   struct ethtool_rx_flow_spec *fs)
{
	struct ethhdr *mac_entry = &fs->h_u.ether_spec;
	struct ethhdr *mac_mask = &fs->m_u.ether_spec;
	enum mv88e6xxx_policy_mapping mapping;
	enum mv88e6xxx_policy_action action;
	struct mv88e6xxx_policy *policy;
	u16 vid = 0;
	u8 *addr;
	int err;
	int id;

	if (fs->location != RX_CLS_LOC_ANY)
		return -EINVAL;

	if (fs->ring_cookie == RX_CLS_FLOW_DISC)
		action = MV88E6XXX_POLICY_ACTION_DISCARD;
	else
		return -EOPNOTSUPP;

	switch (fs->flow_type & ~FLOW_EXT) {
	case ETHER_FLOW:
		if (!is_zero_ether_addr(mac_mask->h_dest) &&
		    is_zero_ether_addr(mac_mask->h_source)) {
			mapping = MV88E6XXX_POLICY_MAPPING_DA;
			addr = mac_entry->h_dest;
		} else if (is_zero_ether_addr(mac_mask->h_dest) &&
		    !is_zero_ether_addr(mac_mask->h_source)) {
			mapping = MV88E6XXX_POLICY_MAPPING_SA;
			addr = mac_entry->h_source;
		} else {
			/* Cannot support DA and SA mapping in the same rule */
			return -EOPNOTSUPP;
		}
		break;
	default:
		return -EOPNOTSUPP;
	}

	if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
2038
		if (fs->m_ext.vlan_tci != htons(0xffff))
2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158
			return -EOPNOTSUPP;
		vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
	}

	idr_for_each_entry(&chip->policies, policy, id) {
		if (policy->port == port && policy->mapping == mapping &&
		    policy->action == action && policy->vid == vid &&
		    ether_addr_equal(policy->addr, addr))
			return -EEXIST;
	}

	policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
	if (!policy)
		return -ENOMEM;

	fs->location = 0;
	err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
			    GFP_KERNEL);
	if (err) {
		devm_kfree(chip->dev, policy);
		return err;
	}

	memcpy(&policy->fs, fs, sizeof(*fs));
	ether_addr_copy(policy->addr, addr);
	policy->mapping = mapping;
	policy->action = action;
	policy->port = port;
	policy->vid = vid;

	err = mv88e6xxx_policy_apply(chip, port, policy);
	if (err) {
		idr_remove(&chip->policies, fs->location);
		devm_kfree(chip->dev, policy);
		return err;
	}

	return 0;
}

static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
			       struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
{
	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
	struct mv88e6xxx_chip *chip = ds->priv;
	struct mv88e6xxx_policy *policy;
	int err;
	int id;

	mv88e6xxx_reg_lock(chip);

	switch (rxnfc->cmd) {
	case ETHTOOL_GRXCLSRLCNT:
		rxnfc->data = 0;
		rxnfc->data |= RX_CLS_LOC_SPECIAL;
		rxnfc->rule_cnt = 0;
		idr_for_each_entry(&chip->policies, policy, id)
			if (policy->port == port)
				rxnfc->rule_cnt++;
		err = 0;
		break;
	case ETHTOOL_GRXCLSRULE:
		err = -ENOENT;
		policy = idr_find(&chip->policies, fs->location);
		if (policy) {
			memcpy(fs, &policy->fs, sizeof(*fs));
			err = 0;
		}
		break;
	case ETHTOOL_GRXCLSRLALL:
		rxnfc->data = 0;
		rxnfc->rule_cnt = 0;
		idr_for_each_entry(&chip->policies, policy, id)
			if (policy->port == port)
				rule_locs[rxnfc->rule_cnt++] = id;
		err = 0;
		break;
	default:
		err = -EOPNOTSUPP;
		break;
	}

	mv88e6xxx_reg_unlock(chip);

	return err;
}

static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
			       struct ethtool_rxnfc *rxnfc)
{
	struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
	struct mv88e6xxx_chip *chip = ds->priv;
	struct mv88e6xxx_policy *policy;
	int err;

	mv88e6xxx_reg_lock(chip);

	switch (rxnfc->cmd) {
	case ETHTOOL_SRXCLSRLINS:
		err = mv88e6xxx_policy_insert(chip, port, fs);
		break;
	case ETHTOOL_SRXCLSRLDEL:
		err = -ENOENT;
		policy = idr_remove(&chip->policies, fs->location);
		if (policy) {
			policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
			err = mv88e6xxx_policy_apply(chip, port, policy);
			devm_kfree(chip->dev, policy);
		}
		break;
	default:
		err = -EOPNOTSUPP;
		break;
	}

	mv88e6xxx_reg_unlock(chip);

	return err;
}

2159 2160 2161 2162
static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
					u16 vid)
{
	u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
2163 2164 2165
	u8 broadcast[ETH_ALEN];

	eth_broadcast_addr(broadcast);
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175

	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++) {
2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188
		struct dsa_port *dp = dsa_to_port(chip->ds, port);
		struct net_device *brport;

		if (dsa_is_unused_port(chip->ds, port))
			continue;

		brport = dsa_port_to_bridge_port(dp);
		if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD))
			/* Skip bridged user ports where broadcast
			 * flooding is disabled.
			 */
			continue;

2189 2190 2191 2192 2193 2194 2195 2196
		err = mv88e6xxx_port_add_broadcast(chip, port, vid);
		if (err)
			return err;
	}

	return 0;
}

2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243
struct mv88e6xxx_port_broadcast_sync_ctx {
	int port;
	bool flood;
};

static int
mv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip,
				   const struct mv88e6xxx_vtu_entry *vlan,
				   void *_ctx)
{
	struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx;
	u8 broadcast[ETH_ALEN];
	u8 state;

	if (ctx->flood)
		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
	else
		state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED;

	eth_broadcast_addr(broadcast);

	return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast,
					    vlan->vid, state);
}

static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port,
					 bool flood)
{
	struct mv88e6xxx_port_broadcast_sync_ctx ctx = {
		.port = port,
		.flood = flood,
	};
	struct mv88e6xxx_vtu_entry vid0 = {
		.vid = 0,
	};
	int err;

	/* Update the port's private database... */
	err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx);
	if (err)
		return err;

	/* ...and the database for all VLANs. */
	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan,
				  &ctx);
}

2244
static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
2245
				    u16 vid, u8 member, bool warn)
2246
{
2247
	const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2248
	struct mv88e6xxx_vtu_entry vlan;
2249
	int i, err;
2250

2251
	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2252 2253 2254
	if (err)
		return err;

2255
	if (!vlan.valid) {
2256 2257
		memset(&vlan, 0, sizeof(vlan));

2258 2259 2260
		if (vid == MV88E6XXX_VID_STANDALONE)
			vlan.policy = true;

2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286
		err = mv88e6xxx_atu_new(chip, &vlan.fid);
		if (err)
			return err;

		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
			if (i == port)
				vlan.member[i] = member;
			else
				vlan.member[i] = non_member;

		vlan.vid = vid;
		vlan.valid = true;

		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
		if (err)
			return err;

		err = mv88e6xxx_broadcast_setup(chip, vlan.vid);
		if (err)
			return err;
	} else if (vlan.member[port] != member) {
		vlan.member[port] = member;

		err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
		if (err)
			return err;
2287
	} else if (warn) {
2288 2289 2290 2291 2292
		dev_info(chip->dev, "p%d: already a member of VLAN %d\n",
			 port, vid);
	}

	return 0;
2293 2294
}

2295
static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
2296 2297
				   const struct switchdev_obj_port_vlan *vlan,
				   struct netlink_ext_ack *extack)
2298
{
V
Vivien Didelot 已提交
2299
	struct mv88e6xxx_chip *chip = ds->priv;
2300 2301
	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
2302
	struct mv88e6xxx_port *p = &chip->ports[port];
2303
	bool warn;
2304
	u8 member;
2305
	int err;
2306

2307 2308 2309
	if (!vlan->vid)
		return 0;

2310 2311 2312
	err = mv88e6xxx_port_vlan_prepare(ds, port, vlan);
	if (err)
		return err;
2313

2314
	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
2315
		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED;
2316
	else if (untagged)
2317
		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED;
2318
	else
2319
		member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
2320

2321 2322 2323 2324 2325
	/* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port
	 * and then the CPU port. Do not warn for duplicates for the CPU port.
	 */
	warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port);

2326
	mv88e6xxx_reg_lock(chip);
2327

2328 2329
	err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn);
	if (err) {
2330 2331
		dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
			vlan->vid, untagged ? 'u' : 't');
2332 2333
		goto out;
	}
2334

2335
	if (pvid) {
2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347
		p->bridge_pvid.vid = vlan->vid;
		p->bridge_pvid.valid = true;

		err = mv88e6xxx_port_commit_pvid(chip, port);
		if (err)
			goto out;
	} else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) {
		/* The old pvid was reinstalled as a non-pvid VLAN */
		p->bridge_pvid.valid = false;

		err = mv88e6xxx_port_commit_pvid(chip, port);
		if (err)
2348 2349
			goto out;
	}
2350

2351
out:
2352
	mv88e6xxx_reg_unlock(chip);
2353 2354

	return err;
2355 2356
}

2357 2358
static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
				     int port, u16 vid)
2359
{
2360
	struct mv88e6xxx_vtu_entry vlan;
2361 2362
	int i, err;

2363
	if (!vid)
2364
		return 0;
2365

2366
	err = mv88e6xxx_vtu_get(chip, vid, &vlan);
2367
	if (err)
2368
		return err;
2369

2370 2371 2372
	/* If the VLAN doesn't exist in hardware or the port isn't a member,
	 * tell switchdev that this VLAN is likely handled in software.
	 */
2373
	if (!vlan.valid ||
2374
	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
2375
		return -EOPNOTSUPP;
2376

2377
	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
2378 2379

	/* keep the VLAN unless all ports are excluded */
2380
	vlan.valid = false;
2381
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
2382 2383
		if (vlan.member[i] !=
		    MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
2384
			vlan.valid = true;
2385 2386 2387 2388
			break;
		}
	}

2389
	err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
2390 2391 2392
	if (err)
		return err;

2393
	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
2394 2395
}

2396 2397
static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
				   const struct switchdev_obj_port_vlan *vlan)
2398
{
V
Vivien Didelot 已提交
2399
	struct mv88e6xxx_chip *chip = ds->priv;
2400
	struct mv88e6xxx_port *p = &chip->ports[port];
2401
	int err = 0;
2402
	u16 pvid;
2403

2404
	if (!mv88e6xxx_max_vid(chip))
2405 2406
		return -EOPNOTSUPP;

2407
	mv88e6xxx_reg_lock(chip);
2408

2409
	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
2410 2411 2412
	if (err)
		goto unlock;

2413 2414 2415 2416 2417
	err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid);
	if (err)
		goto unlock;

	if (vlan->vid == pvid) {
2418 2419 2420
		p->bridge_pvid.valid = false;

		err = mv88e6xxx_port_commit_pvid(chip, port);
2421 2422 2423 2424
		if (err)
			goto unlock;
	}

2425
unlock:
2426
	mv88e6xxx_reg_unlock(chip);
2427 2428 2429 2430

	return err;
}

2431 2432
static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
				  const unsigned char *addr, u16 vid)
2433
{
V
Vivien Didelot 已提交
2434
	struct mv88e6xxx_chip *chip = ds->priv;
2435
	int err;
2436

2437
	mv88e6xxx_reg_lock(chip);
2438 2439
	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2440
	mv88e6xxx_reg_unlock(chip);
2441 2442

	return err;
2443 2444
}

2445
static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
2446
				  const unsigned char *addr, u16 vid)
2447
{
V
Vivien Didelot 已提交
2448
	struct mv88e6xxx_chip *chip = ds->priv;
2449
	int err;
2450

2451
	mv88e6xxx_reg_lock(chip);
2452
	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
2453
	mv88e6xxx_reg_unlock(chip);
2454

2455
	return err;
2456 2457
}

2458 2459
static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
				      u16 fid, u16 vid, int port,
2460
				      dsa_fdb_dump_cb_t *cb, void *data)
2461
{
2462
	struct mv88e6xxx_atu_entry addr;
2463
	bool is_static;
2464 2465
	int err;

2466
	addr.state = 0;
2467
	eth_broadcast_addr(addr.mac);
2468 2469

	do {
2470
		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
2471
		if (err)
2472
			return err;
2473

2474
		if (!addr.state)
2475 2476
			break;

2477
		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
2478 2479
			continue;

2480 2481
		if (!is_unicast_ether_addr(addr.mac))
			continue;
2482

2483 2484 2485
		is_static = (addr.state ==
			     MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
		err = cb(addr.mac, vid, is_static, data);
2486 2487
		if (err)
			return err;
2488 2489 2490 2491 2492
	} while (!is_broadcast_ether_addr(addr.mac));

	return err;
}

2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508
struct mv88e6xxx_port_db_dump_vlan_ctx {
	int port;
	dsa_fdb_dump_cb_t *cb;
	void *data;
};

static int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip,
				       const struct mv88e6xxx_vtu_entry *entry,
				       void *_data)
{
	struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data;

	return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid,
					  ctx->port, ctx->cb, ctx->data);
}

2509
static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
2510
				  dsa_fdb_dump_cb_t *cb, void *data)
2511
{
2512 2513 2514 2515 2516
	struct mv88e6xxx_port_db_dump_vlan_ctx ctx = {
		.port = port,
		.cb = cb,
		.data = data,
	};
2517
	u16 fid;
2518 2519
	int err;

2520
	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2521
	err = mv88e6xxx_port_get_fid(chip, port, &fid);
2522
	if (err)
2523
		return err;
2524

2525
	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data);
2526
	if (err)
2527
		return err;
2528

2529
	return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx);
2530 2531 2532
}

static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
2533
				   dsa_fdb_dump_cb_t *cb, void *data)
2534
{
V
Vivien Didelot 已提交
2535
	struct mv88e6xxx_chip *chip = ds->priv;
2536 2537
	int err;

2538
	mv88e6xxx_reg_lock(chip);
2539
	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
2540
	mv88e6xxx_reg_unlock(chip);
2541

2542
	return err;
2543 2544
}

2545
static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
2546
				struct dsa_bridge bridge)
2547
{
2548 2549 2550
	struct dsa_switch *ds = chip->ds;
	struct dsa_switch_tree *dst = ds->dst;
	struct dsa_port *dp;
2551
	int err;
2552

2553
	list_for_each_entry(dp, &dst->ports, list) {
2554
		if (dsa_port_offloads_bridge(dp, &bridge)) {
2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
			if (dp->ds == ds) {
				/* This is a local bridge group member,
				 * remap its Port VLAN Map.
				 */
				err = mv88e6xxx_port_vlan_map(chip, dp->index);
				if (err)
					return err;
			} else {
				/* This is an external bridge group member,
				 * remap its cross-chip Port VLAN Table entry.
				 */
				err = mv88e6xxx_pvt_map(chip, dp->ds->index,
							dp->index);
2568 2569 2570 2571 2572 2573
				if (err)
					return err;
			}
		}
	}

2574 2575 2576
	return 0;
}

2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
/* Treat the software bridge as a virtual single-port switch behind the
 * CPU and map in the PVT. First dst->last_switch elements are taken by
 * physical switches, so start from beyond that range.
 */
static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
					       unsigned int bridge_num)
{
	u8 dev = bridge_num + ds->dst->last_switch;
	struct mv88e6xxx_chip *chip = ds->priv;

	return mv88e6xxx_pvt_map(chip, dev, 0);
}

2590
static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2591 2592
				      struct dsa_bridge bridge,
				      bool *tx_fwd_offload)
2593 2594 2595 2596
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

2597
	mv88e6xxx_reg_lock(chip);
2598

2599
	err = mv88e6xxx_bridge_map(chip, bridge);
2600 2601 2602
	if (err)
		goto unlock;

2603 2604 2605 2606
	err = mv88e6xxx_port_set_map_da(chip, port, true);
	if (err)
		return err;

2607 2608 2609 2610
	err = mv88e6xxx_port_commit_pvid(chip, port);
	if (err)
		goto unlock;

2611 2612 2613 2614 2615 2616 2617 2618
	if (mv88e6xxx_has_pvt(chip)) {
		err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
		if (err)
			goto unlock;

		*tx_fwd_offload = true;
	}

2619
unlock:
2620
	mv88e6xxx_reg_unlock(chip);
2621

2622
	return err;
2623 2624
}

2625
static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
2626
					struct dsa_bridge bridge)
2627
{
V
Vivien Didelot 已提交
2628
	struct mv88e6xxx_chip *chip = ds->priv;
2629
	int err;
2630

2631
	mv88e6xxx_reg_lock(chip);
2632

2633 2634 2635 2636
	if (bridge.tx_fwd_offload &&
	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");

2637
	if (mv88e6xxx_bridge_map(chip, bridge) ||
2638 2639
	    mv88e6xxx_port_vlan_map(chip, port))
		dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2640

2641 2642 2643 2644 2645 2646
	err = mv88e6xxx_port_set_map_da(chip, port, false);
	if (err)
		dev_err(ds->dev,
			"port %d failed to restore map-DA: %pe\n",
			port, ERR_PTR(err));

2647 2648 2649 2650 2651 2652
	err = mv88e6xxx_port_commit_pvid(chip, port);
	if (err)
		dev_err(ds->dev,
			"port %d failed to restore standalone pvid: %pe\n",
			port, ERR_PTR(err));

2653
	mv88e6xxx_reg_unlock(chip);
2654 2655
}

2656 2657
static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
					   int tree_index, int sw_index,
2658
					   int port, struct dsa_bridge bridge)
2659 2660 2661 2662
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

2663 2664 2665
	if (tree_index != ds->dst->index)
		return 0;

2666
	mv88e6xxx_reg_lock(chip);
2667
	err = mv88e6xxx_pvt_map(chip, sw_index, port);
2668
	err = err ? : mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
2669
	mv88e6xxx_reg_unlock(chip);
2670 2671 2672 2673

	return err;
}

2674 2675
static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
					     int tree_index, int sw_index,
2676
					     int port, struct dsa_bridge bridge)
2677 2678 2679
{
	struct mv88e6xxx_chip *chip = ds->priv;

2680 2681 2682
	if (tree_index != ds->dst->index)
		return;

2683
	mv88e6xxx_reg_lock(chip);
2684 2685
	if (mv88e6xxx_pvt_map(chip, sw_index, port) ||
	    mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num))
2686
		dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
2687
	mv88e6xxx_reg_unlock(chip);
2688 2689
}

2690 2691 2692 2693 2694 2695 2696 2697
static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->reset)
		return chip->info->ops->reset(chip);

	return 0;
}

2698 2699 2700 2701 2702 2703 2704 2705 2706 2707
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);
2708 2709

		mv88e6xxx_g1_wait_eeprom_done(chip);
2710 2711 2712
	}
}

2713
static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
2714
{
2715
	int i, err;
2716

2717
	/* Set all ports to the Disabled state */
2718
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2719
		err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED);
2720 2721
		if (err)
			return err;
2722 2723
	}

2724 2725 2726
	/* Wait for transmit queues to drain,
	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
	 */
2727 2728
	usleep_range(2000, 4000);

2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
	return 0;
}

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

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

2740
	mv88e6xxx_hardware_reset(chip);
2741

2742
	return mv88e6xxx_software_reset(chip);
2743 2744
}

2745
static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
2746 2747
				   enum mv88e6xxx_frame_mode frame,
				   enum mv88e6xxx_egress_mode egress, u16 etype)
2748 2749 2750
{
	int err;

2751 2752 2753 2754
	if (!chip->info->ops->port_set_frame_mode)
		return -EOPNOTSUPP;

	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
2755 2756 2757
	if (err)
		return err;

2758 2759 2760 2761 2762 2763 2764 2765
	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;
2766 2767
}

2768
static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
2769
{
2770
	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
2771
				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2772
				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
2773
}
2774

2775 2776 2777
static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
{
	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
2778
				       MV88E6XXX_EGRESS_MODE_UNMODIFIED,
2779
				       MV88E6XXX_PORT_ETH_TYPE_DEFAULT);
2780
}
2781

2782 2783 2784 2785
static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
{
	return mv88e6xxx_set_port_mode(chip, port,
				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
2786 2787
				       MV88E6XXX_EGRESS_MODE_ETHERTYPE,
				       ETH_P_EDSA);
2788
}
2789

2790 2791 2792 2793
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);
2794

2795
	if (dsa_is_user_port(chip->ds, port))
2796
		return mv88e6xxx_set_port_mode_normal(chip, port);
2797

2798
	/* Setup CPU port mode depending on its supported tag format */
2799
	if (chip->tag_protocol == DSA_TAG_PROTO_DSA)
2800
		return mv88e6xxx_set_port_mode_dsa(chip, port);
2801

2802
	if (chip->tag_protocol == DSA_TAG_PROTO_EDSA)
2803
		return mv88e6xxx_set_port_mode_edsa(chip, port);
2804

2805
	return -EINVAL;
2806 2807
}

2808
static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2809
{
2810
	bool message = dsa_is_dsa_port(chip->ds, port);
2811

2812
	return mv88e6xxx_port_set_message_port(chip, port, message);
2813
}
2814

2815
static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2816
{
2817
	int err;
2818

2819
	if (chip->info->ops->port_set_ucast_flood) {
2820
		err = chip->info->ops->port_set_ucast_flood(chip, port, true);
2821 2822 2823 2824
		if (err)
			return err;
	}
	if (chip->info->ops->port_set_mcast_flood) {
2825
		err = chip->info->ops->port_set_mcast_flood(chip, port, true);
2826 2827 2828
		if (err)
			return err;
	}
2829

2830
	return 0;
2831 2832
}

2833 2834 2835 2836 2837 2838
static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
{
	struct mv88e6xxx_port *mvp = dev_id;
	struct mv88e6xxx_chip *chip = mvp->chip;
	irqreturn_t ret = IRQ_NONE;
	int port = mvp->port;
2839
	int lane;
2840 2841 2842

	mv88e6xxx_reg_lock(chip);
	lane = mv88e6xxx_serdes_get_lane(chip, port);
2843
	if (lane >= 0)
2844 2845 2846 2847 2848 2849 2850
		ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
	mv88e6xxx_reg_unlock(chip);

	return ret;
}

static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
2851
					int lane)
2852 2853 2854 2855 2856 2857 2858 2859 2860 2861
{
	struct mv88e6xxx_port *dev_id = &chip->ports[port];
	unsigned int irq;
	int err;

	/* Nothing to request if this SERDES port has no IRQ */
	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
	if (!irq)
		return 0;

2862 2863 2864
	snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
		 "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);

2865 2866 2867
	/* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
	mv88e6xxx_reg_unlock(chip);
	err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2868 2869
				   IRQF_ONESHOT, dev_id->serdes_irq_name,
				   dev_id);
2870 2871 2872 2873 2874 2875 2876 2877 2878 2879
	mv88e6xxx_reg_lock(chip);
	if (err)
		return err;

	dev_id->serdes_irq = irq;

	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
}

static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
2880
				     int lane)
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
{
	struct mv88e6xxx_port *dev_id = &chip->ports[port];
	unsigned int irq = dev_id->serdes_irq;
	int err;

	/* Nothing to free if no IRQ has been requested */
	if (!irq)
		return 0;

	err = mv88e6xxx_serdes_irq_disable(chip, port, lane);

	/* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
	mv88e6xxx_reg_unlock(chip);
	free_irq(irq, dev_id);
	mv88e6xxx_reg_lock(chip);

	dev_id->serdes_irq = 0;

	return err;
}

2902 2903 2904
static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
				  bool on)
{
2905
	int lane;
2906
	int err;
2907

2908
	lane = mv88e6xxx_serdes_get_lane(chip, port);
2909
	if (lane < 0)
2910 2911 2912
		return 0;

	if (on) {
2913
		err = mv88e6xxx_serdes_power_up(chip, port, lane);
2914 2915 2916
		if (err)
			return err;

2917
		err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2918
	} else {
2919 2920 2921
		err = mv88e6xxx_serdes_irq_free(chip, port, lane);
		if (err)
			return err;
2922

2923
		err = mv88e6xxx_serdes_power_down(chip, port, lane);
2924 2925 2926
	}

	return err;
2927 2928
}

2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949
static int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip,
				     enum mv88e6xxx_egress_direction direction,
				     int port)
{
	int err;

	if (!chip->info->ops->set_egress_port)
		return -EOPNOTSUPP;

	err = chip->info->ops->set_egress_port(chip, direction, port);
	if (err)
		return err;

	if (direction == MV88E6XXX_EGRESS_DIR_INGRESS)
		chip->ingress_dest_port = port;
	else
		chip->egress_dest_port = port;

	return 0;
}

2950 2951 2952 2953 2954 2955
static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
{
	struct dsa_switch *ds = chip->ds;
	int upstream_port;
	int err;

2956
	upstream_port = dsa_upstream_port(ds, port);
2957 2958 2959 2960 2961 2962 2963
	if (chip->info->ops->port_set_upstream_port) {
		err = chip->info->ops->port_set_upstream_port(chip, port,
							      upstream_port);
		if (err)
			return err;
	}

2964 2965 2966 2967 2968 2969 2970 2971
	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;
		}

2972
		err = mv88e6xxx_set_egress_port(chip,
2973 2974
						MV88E6XXX_EGRESS_DIR_INGRESS,
						upstream_port);
2975 2976
		if (err && err != -EOPNOTSUPP)
			return err;
2977

2978
		err = mv88e6xxx_set_egress_port(chip,
2979 2980
						MV88E6XXX_EGRESS_DIR_EGRESS,
						upstream_port);
2981 2982
		if (err && err != -EOPNOTSUPP)
			return err;
2983 2984
	}

2985 2986 2987
	return 0;
}

2988
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2989
{
2990
	struct dsa_switch *ds = chip->ds;
2991
	int err;
2992
	u16 reg;
2993

2994 2995 2996
	chip->ports[port].chip = chip;
	chip->ports[port].port = port;

2997 2998 2999 3000 3001 3002 3003
	/* 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,
3004
					       PAUSE_OFF,
3005 3006 3007 3008
					       PHY_INTERFACE_MODE_NA);
	else
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
					       SPEED_UNFORCED, DUPLEX_UNFORCED,
3009
					       PAUSE_ON,
3010 3011 3012
					       PHY_INTERFACE_MODE_NA);
	if (err)
		return err;
3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027

	/* 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.
	 */
3028 3029 3030 3031
	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);
3032 3033
	if (err)
		return err;
3034

3035
	err = mv88e6xxx_setup_port_mode(chip, port);
3036 3037
	if (err)
		return err;
3038

3039
	err = mv88e6xxx_setup_egress_floods(chip, port);
3040 3041 3042
	if (err)
		return err;

A
Andrew Lunn 已提交
3043
	/* Port Control 2: don't force a good FCS, set the MTU size to
3044 3045 3046 3047 3048
	 * 10222 bytes, disable 802.1q tags checking, don't discard
	 * tagged or untagged frames on this port, skip destination
	 * address lookup on user ports, disable ARP mirroring and don't
	 * send a copy of all transmitted/received frames on this port
	 * to the CPU.
3049
	 */
3050
	err = mv88e6xxx_port_set_map_da(chip, port, !dsa_is_user_port(ds, port));
3051 3052
	if (err)
		return err;
3053

3054 3055 3056
	err = mv88e6xxx_setup_upstream_port(chip, port);
	if (err)
		return err;
3057

3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078
	/* On chips that support it, set all downstream DSA ports'
	 * VLAN policy to TRAP. In combination with loading
	 * MV88E6XXX_VID_STANDALONE as a policy entry in the VTU, this
	 * provides a better isolation barrier between standalone
	 * ports, as the ATU is bypassed on any intermediate switches
	 * between the incoming port and the CPU.
	 */
	if (dsa_is_downstream_port(ds, port) &&
	    chip->info->ops->port_set_policy) {
		err = chip->info->ops->port_set_policy(chip, port,
						MV88E6XXX_POLICY_MAPPING_VTU,
						MV88E6XXX_POLICY_ACTION_TRAP);
		if (err)
			return err;
	}

	/* User ports start out in standalone mode and 802.1Q is
	 * therefore disabled. On DSA ports, all valid VIDs are always
	 * loaded in the VTU - therefore, enable 802.1Q in order to take
	 * advantage of VLAN policy on chips that supports it.
	 */
3079
	err = mv88e6xxx_port_set_8021q_mode(chip, port,
3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095
				dsa_is_user_port(ds, port) ?
				MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED :
				MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE);
	if (err)
		return err;

	/* Bind MV88E6XXX_VID_STANDALONE to MV88E6XXX_FID_STANDALONE by
	 * virtue of the fact that mv88e6xxx_atu_new() will pick it as
	 * the first free FID. This will be used as the private PVID for
	 * unbridged ports. Shared (DSA and CPU) ports must also be
	 * members of this VID, in order to trap all frames assigned to
	 * it to the CPU.
	 */
	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_STANDALONE,
				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
				       false);
3096 3097 3098
	if (err)
		return err;

3099 3100 3101 3102 3103 3104 3105 3106 3107
	/* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the
	 * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as
	 * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used
	 * as the private PVID on ports under a VLAN-unaware bridge.
	 * Shared (DSA and CPU) ports must also be members of it, to translate
	 * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of
	 * relying on their port default FID.
	 */
	err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED,
3108
				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
3109 3110 3111 3112
				       false);
	if (err)
		return err;

3113
	if (chip->info->ops->port_set_jumbo_size) {
A
Andrew Lunn 已提交
3114
		err = chip->info->ops->port_set_jumbo_size(chip, port, 10218);
3115 3116 3117 3118
		if (err)
			return err;
	}

3119 3120 3121 3122 3123 3124 3125 3126 3127
	/* Port Association Vector: disable automatic address learning
	 * on all user ports since they start out in standalone
	 * mode. When joining a bridge, learning will be configured to
	 * match the bridge port settings. Enable learning on all
	 * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the
	 * learning process.
	 *
	 * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData,
	 * and RefreshLocked. I.e. setup standard automatic learning.
3128
	 */
3129
	if (dsa_is_user_port(ds, port))
3130
		reg = 0;
3131 3132
	else
		reg = 1 << port;
3133

3134 3135
	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
				   reg);
3136 3137
	if (err)
		return err;
3138 3139

	/* Egress rate control 2: disable egress rate control. */
3140 3141
	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2,
				   0x0000);
3142 3143
	if (err)
		return err;
3144

3145 3146
	if (chip->info->ops->port_pause_limit) {
		err = chip->info->ops->port_pause_limit(chip, port, 0, 0);
3147 3148
		if (err)
			return err;
3149
	}
3150

3151 3152 3153 3154 3155 3156
	if (chip->info->ops->port_disable_learn_limit) {
		err = chip->info->ops->port_disable_learn_limit(chip, port);
		if (err)
			return err;
	}

3157 3158
	if (chip->info->ops->port_disable_pri_override) {
		err = chip->info->ops->port_disable_pri_override(chip, port);
3159 3160
		if (err)
			return err;
3161
	}
3162

3163 3164
	if (chip->info->ops->port_tag_remap) {
		err = chip->info->ops->port_tag_remap(chip, port);
3165 3166
		if (err)
			return err;
3167 3168
	}

3169 3170
	if (chip->info->ops->port_egress_rate_limiting) {
		err = chip->info->ops->port_egress_rate_limiting(chip, port);
3171 3172
		if (err)
			return err;
3173 3174
	}

3175 3176 3177 3178 3179
	if (chip->info->ops->port_setup_message_port) {
		err = chip->info->ops->port_setup_message_port(chip, port);
		if (err)
			return err;
	}
3180

3181
	/* Port based VLAN map: give each port the same default address
3182 3183
	 * database, and allow bidirectional communication between the
	 * CPU and DSA port(s), and the other ports.
3184
	 */
3185
	err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE);
3186 3187
	if (err)
		return err;
3188

3189
	err = mv88e6xxx_port_vlan_map(chip, port);
3190 3191
	if (err)
		return err;
3192 3193 3194 3195

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

3199 3200 3201 3202 3203
static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;

	if (chip->info->ops->port_set_jumbo_size)
3204
		return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
3205
	else if (chip->info->ops->set_max_frame_size)
3206 3207
		return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
	return 1522 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN;
3208 3209 3210 3211 3212 3213 3214
}

static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int ret = 0;

3215 3216 3217
	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
		new_mtu += EDSA_HLEN;

3218 3219 3220
	mv88e6xxx_reg_lock(chip);
	if (chip->info->ops->port_set_jumbo_size)
		ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu);
3221 3222
	else if (chip->info->ops->set_max_frame_size)
		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);
3223 3224 3225 3226 3227 3228 3229 3230
	else
		if (new_mtu > 1522)
			ret = -EINVAL;
	mv88e6xxx_reg_unlock(chip);

	return ret;
}

3231 3232 3233 3234
static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
				 struct phy_device *phydev)
{
	struct mv88e6xxx_chip *chip = ds->priv;
3235
	int err;
3236

3237
	mv88e6xxx_reg_lock(chip);
3238
	err = mv88e6xxx_serdes_power(chip, port, true);
3239
	mv88e6xxx_reg_unlock(chip);
3240 3241 3242 3243

	return err;
}

3244
static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
3245 3246 3247
{
	struct mv88e6xxx_chip *chip = ds->priv;

3248
	mv88e6xxx_reg_lock(chip);
3249 3250
	if (mv88e6xxx_serdes_power(chip, port, false))
		dev_err(chip->dev, "failed to power off SERDES\n");
3251
	mv88e6xxx_reg_unlock(chip);
3252 3253
}

3254 3255 3256
static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
				     unsigned int ageing_time)
{
V
Vivien Didelot 已提交
3257
	struct mv88e6xxx_chip *chip = ds->priv;
3258 3259
	int err;

3260
	mv88e6xxx_reg_lock(chip);
3261
	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
3262
	mv88e6xxx_reg_unlock(chip);
3263 3264 3265 3266

	return err;
}

3267
static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
3268
{
3269
	int err;
3270

3271
	/* Initialize the statistics unit */
3272 3273 3274 3275 3276
	if (chip->info->ops->stats_set_histogram) {
		err = chip->info->ops->stats_set_histogram(chip);
		if (err)
			return err;
	}
3277

3278
	return mv88e6xxx_g1_stats_clear(chip);
3279 3280
}

3281 3282 3283 3284 3285 3286 3287 3288
/* Check if the errata has already been applied. */
static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
{
	int port;
	int err;
	u16 val;

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
3289
		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
		if (err) {
			dev_err(chip->dev,
				"Error reading hidden register: %d\n", err);
			return false;
		}
		if (val != 0x01c0)
			return false;
	}

	return true;
}

/* The 6390 copper ports have an errata which require poking magic
 * values into undocumented hidden registers and then performing a
 * software reset.
 */
static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
{
	int port;
	int err;

	if (mv88e6390_setup_errata_applied(chip))
		return 0;

	/* Set the ports into blocking mode */
	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
		err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED);
		if (err)
			return err;
	}

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
3322
		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
3323 3324 3325 3326 3327 3328 3329
		if (err)
			return err;
	}

	return mv88e6xxx_software_reset(chip);
}

3330 3331 3332
static void mv88e6xxx_teardown(struct dsa_switch *ds)
{
	mv88e6xxx_teardown_devlink_params(ds);
3333
	dsa_devlink_resources_unregister(ds);
3334
	mv88e6xxx_teardown_devlink_regions_global(ds);
3335 3336
}

3337
static int mv88e6xxx_setup(struct dsa_switch *ds)
3338
{
V
Vivien Didelot 已提交
3339
	struct mv88e6xxx_chip *chip = ds->priv;
3340
	u8 cmode;
3341
	int err;
3342 3343
	int i;

3344
	chip->ds = ds;
3345
	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
3346

3347 3348 3349 3350 3351 3352
	/* Since virtual bridges are mapped in the PVT, the number we support
	 * depends on the physical switch topology. We need to let DSA figure
	 * that out and therefore we cannot set this at dsa_register_switch()
	 * time.
	 */
	if (mv88e6xxx_has_pvt(chip))
3353 3354
		ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES -
				      ds->dst->last_switch - 1;
3355

3356
	mv88e6xxx_reg_lock(chip);
3357

3358 3359 3360 3361 3362 3363
	if (chip->info->ops->setup_errata) {
		err = chip->info->ops->setup_errata(chip);
		if (err)
			goto unlock;
	}

3364 3365 3366 3367 3368
	/* Cache the cmode of each port. */
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
		if (chip->info->ops->port_get_cmode) {
			err = chip->info->ops->port_get_cmode(chip, i, &cmode);
			if (err)
3369
				goto unlock;
3370 3371 3372 3373 3374

			chip->ports[i].cmode = cmode;
		}
	}

3375 3376 3377 3378
	err = mv88e6xxx_vtu_setup(chip);
	if (err)
		goto unlock;

3379
	/* Setup Switch Port Registers */
3380
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
3381 3382 3383
		if (dsa_is_unused_port(ds, i))
			continue;

3384
		/* Prevent the use of an invalid port. */
3385
		if (mv88e6xxx_is_invalid_port(chip, i)) {
3386 3387 3388 3389 3390
			dev_err(chip->dev, "port %d is invalid\n", i);
			err = -EINVAL;
			goto unlock;
		}

3391 3392 3393 3394 3395
		err = mv88e6xxx_setup_port(chip, i);
		if (err)
			goto unlock;
	}

3396 3397 3398 3399
	err = mv88e6xxx_irl_setup(chip);
	if (err)
		goto unlock;

3400 3401 3402 3403
	err = mv88e6xxx_mac_setup(chip);
	if (err)
		goto unlock;

3404 3405 3406 3407
	err = mv88e6xxx_phy_setup(chip);
	if (err)
		goto unlock;

3408 3409 3410 3411
	err = mv88e6xxx_pvt_setup(chip);
	if (err)
		goto unlock;

3412 3413 3414 3415
	err = mv88e6xxx_atu_setup(chip);
	if (err)
		goto unlock;

3416 3417 3418 3419
	err = mv88e6xxx_broadcast_setup(chip, 0);
	if (err)
		goto unlock;

3420 3421 3422 3423
	err = mv88e6xxx_pot_setup(chip);
	if (err)
		goto unlock;

3424 3425 3426 3427
	err = mv88e6xxx_rmu_setup(chip);
	if (err)
		goto unlock;

3428 3429 3430
	err = mv88e6xxx_rsvd2cpu_setup(chip);
	if (err)
		goto unlock;
3431

3432 3433 3434 3435
	err = mv88e6xxx_trunk_setup(chip);
	if (err)
		goto unlock;

3436 3437 3438 3439
	err = mv88e6xxx_devmap_setup(chip);
	if (err)
		goto unlock;

3440 3441 3442 3443
	err = mv88e6xxx_pri_setup(chip);
	if (err)
		goto unlock;

3444
	/* Setup PTP Hardware Clock and timestamping */
3445 3446 3447 3448
	if (chip->info->ptp_support) {
		err = mv88e6xxx_ptp_setup(chip);
		if (err)
			goto unlock;
3449 3450 3451 3452

		err = mv88e6xxx_hwtstamp_setup(chip);
		if (err)
			goto unlock;
3453 3454
	}

3455 3456 3457 3458
	err = mv88e6xxx_stats_setup(chip);
	if (err)
		goto unlock;

3459
unlock:
3460
	mv88e6xxx_reg_unlock(chip);
3461

3462 3463 3464 3465 3466 3467 3468
	if (err)
		return err;

	/* Have to be called without holding the register lock, since
	 * they take the devlink lock, and we later take the locks in
	 * the reverse order when getting/setting parameters or
	 * resource occupancy.
3469
	 */
3470 3471 3472 3473 3474 3475
	err = mv88e6xxx_setup_devlink_resources(ds);
	if (err)
		return err;

	err = mv88e6xxx_setup_devlink_params(ds);
	if (err)
3476 3477
		goto out_resources;

3478
	err = mv88e6xxx_setup_devlink_regions_global(ds);
3479 3480 3481 3482 3483 3484 3485 3486 3487
	if (err)
		goto out_params;

	return 0;

out_params:
	mv88e6xxx_teardown_devlink_params(ds);
out_resources:
	dsa_devlink_resources_unregister(ds);
3488 3489

	return err;
3490 3491
}

3492 3493 3494 3495 3496 3497 3498 3499 3500 3501
static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
{
	return mv88e6xxx_setup_devlink_regions_port(ds, port);
}

static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
{
	mv88e6xxx_teardown_devlink_regions_port(ds, port);
}

3502 3503 3504 3505
/* prod_id for switch families which do not have a PHY model number */
static const u16 family_prod_id_table[] = {
	[MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
	[MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
3506
	[MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
3507 3508
};

3509
static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
3510
{
3511 3512
	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3513
	u16 prod_id;
3514 3515
	u16 val;
	int err;
3516

3517 3518 3519
	if (!chip->info->ops->phy_read)
		return -EOPNOTSUPP;

3520
	mv88e6xxx_reg_lock(chip);
3521
	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
3522
	mv88e6xxx_reg_unlock(chip);
3523

3524 3525 3526 3527 3528 3529
	/* Some internal PHYs don't have a model number. */
	if (reg == MII_PHYSID2 && !(val & 0x3f0) &&
	    chip->info->family < ARRAY_SIZE(family_prod_id_table)) {
		prod_id = family_prod_id_table[chip->info->family];
		if (prod_id)
			val |= prod_id >> 4;
3530 3531
	}

3532
	return err ? err : val;
3533 3534
}

3535
static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
3536
{
3537 3538
	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
	struct mv88e6xxx_chip *chip = mdio_bus->chip;
3539
	int err;
3540

3541 3542 3543
	if (!chip->info->ops->phy_write)
		return -EOPNOTSUPP;

3544
	mv88e6xxx_reg_lock(chip);
3545
	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
3546
	mv88e6xxx_reg_unlock(chip);
3547 3548

	return err;
3549 3550
}

3551
static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
3552 3553
				   struct device_node *np,
				   bool external)
3554 3555
{
	static int index;
3556
	struct mv88e6xxx_mdio_bus *mdio_bus;
3557 3558 3559
	struct mii_bus *bus;
	int err;

3560
	if (external) {
3561
		mv88e6xxx_reg_lock(chip);
3562
		err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
3563
		mv88e6xxx_reg_unlock(chip);
3564 3565 3566 3567 3568

		if (err)
			return err;
	}

3569
	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
3570 3571 3572
	if (!bus)
		return -ENOMEM;

3573
	mdio_bus = bus->priv;
3574
	mdio_bus->bus = bus;
3575
	mdio_bus->chip = chip;
3576 3577
	INIT_LIST_HEAD(&mdio_bus->list);
	mdio_bus->external = external;
3578

3579 3580
	if (np) {
		bus->name = np->full_name;
3581
		snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np);
3582 3583 3584 3585 3586 3587 3588
	} 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;
3589
	bus->parent = chip->dev;
3590

3591 3592 3593 3594 3595 3596
	if (!external) {
		err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
		if (err)
			return err;
	}

3597
	err = of_mdiobus_register(bus, np);
3598
	if (err) {
3599
		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
3600
		mv88e6xxx_g2_irq_mdio_free(chip, bus);
3601
		return err;
3602
	}
3603 3604 3605 3606 3607

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

	return 0;
3610
}
3611

3612 3613 3614 3615 3616 3617 3618 3619 3620
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;

3621 3622 3623
		if (!mdio_bus->external)
			mv88e6xxx_g2_irq_mdio_free(chip, bus);

3624 3625 3626 3627
		mdiobus_unregister(bus);
	}
}

3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647
static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
				    struct device_node *np)
{
	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) {
3648 3649
		if (of_device_is_compatible(
			    child, "marvell,mv88e6xxx-mdio-external")) {
3650
			err = mv88e6xxx_mdio_register(chip, child, true);
3651 3652
			if (err) {
				mv88e6xxx_mdios_unregister(chip);
3653
				of_node_put(child);
3654
				return err;
3655
			}
3656 3657 3658 3659
		}
	}

	return 0;
3660 3661
}

3662 3663
static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
{
V
Vivien Didelot 已提交
3664
	struct mv88e6xxx_chip *chip = ds->priv;
3665 3666 3667 3668 3669 3670 3671

	return chip->eeprom_len;
}

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

3675 3676
	if (!chip->info->ops->get_eeprom)
		return -EOPNOTSUPP;
3677

3678
	mv88e6xxx_reg_lock(chip);
3679
	err = chip->info->ops->get_eeprom(chip, eeprom, data);
3680
	mv88e6xxx_reg_unlock(chip);
3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692

	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 已提交
3693
	struct mv88e6xxx_chip *chip = ds->priv;
3694 3695
	int err;

3696 3697 3698
	if (!chip->info->ops->set_eeprom)
		return -EOPNOTSUPP;

3699 3700 3701
	if (eeprom->magic != 0xc3ec4951)
		return -EINVAL;

3702
	mv88e6xxx_reg_lock(chip);
3703
	err = chip->info->ops->set_eeprom(chip, eeprom, data);
3704
	mv88e6xxx_reg_unlock(chip);
3705 3706 3707 3708

	return err;
}

3709
static const struct mv88e6xxx_ops mv88e6085_ops = {
3710
	/* MV88E6XXX_FAMILY_6097 */
3711 3712
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3713
	.irl_init_all = mv88e6352_g2_irl_init_all,
3714
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
3715 3716
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
3717
	.port_set_link = mv88e6xxx_port_set_link,
3718
	.port_sync_link = mv88e6xxx_port_sync_link,
3719
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3720
	.port_tag_remap = mv88e6095_port_tag_remap,
3721
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3722 3723
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3724
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3725
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3726
	.port_pause_limit = mv88e6097_port_pause_limit,
3727
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3728
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3729
	.port_get_cmode = mv88e6185_port_get_cmode,
3730
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3731
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3732
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3733 3734
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3735
	.stats_get_stats = mv88e6095_stats_get_stats,
3736 3737
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3738
	.watchdog_ops = &mv88e6097_watchdog_ops,
3739
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3740
	.pot_clear = mv88e6xxx_g2_pot_clear,
3741 3742
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
3743
	.reset = mv88e6185_g1_reset,
3744
	.rmu_disable = mv88e6085_g1_rmu_disable,
3745
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3746
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3747
	.phylink_get_caps = mv88e6185_phylink_get_caps,
3748
	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3749 3750 3751
};

static const struct mv88e6xxx_ops mv88e6095_ops = {
3752
	/* MV88E6XXX_FAMILY_6095 */
3753 3754
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3755
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
3756 3757
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
3758
	.port_set_link = mv88e6xxx_port_set_link,
3759
	.port_sync_link = mv88e6185_port_sync_link,
3760
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3761
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3762 3763
	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
3764
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3765
	.port_get_cmode = mv88e6185_port_get_cmode,
3766
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3767
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3768
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3769 3770
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3771
	.stats_get_stats = mv88e6095_stats_get_stats,
3772
	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3773 3774 3775
	.serdes_power = mv88e6185_serdes_power,
	.serdes_get_lane = mv88e6185_serdes_get_lane,
	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
3776 3777
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
3778
	.reset = mv88e6185_g1_reset,
3779
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
3780
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3781
	.phylink_get_caps = mv88e6185_phylink_get_caps,
3782
	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3783 3784
};

3785
static const struct mv88e6xxx_ops mv88e6097_ops = {
3786
	/* MV88E6XXX_FAMILY_6097 */
3787 3788
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3789
	.irl_init_all = mv88e6352_g2_irl_init_all,
3790 3791 3792 3793
	.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,
3794
	.port_sync_link = mv88e6185_port_sync_link,
3795
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3796
	.port_tag_remap = mv88e6095_port_tag_remap,
3797
	.port_set_policy = mv88e6352_port_set_policy,
3798
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3799 3800
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3801
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3802
	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3803
	.port_pause_limit = mv88e6097_port_pause_limit,
3804
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3805
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3806
	.port_get_cmode = mv88e6185_port_get_cmode,
3807
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3808
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3809
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3810 3811 3812
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
	.stats_get_stats = mv88e6095_stats_get_stats,
3813 3814
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3815
	.watchdog_ops = &mv88e6097_watchdog_ops,
3816
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3817 3818 3819
	.serdes_power = mv88e6185_serdes_power,
	.serdes_get_lane = mv88e6185_serdes_get_lane,
	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
3820 3821 3822
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6097_serdes_irq_enable,
	.serdes_irq_status = mv88e6097_serdes_irq_status,
3823
	.pot_clear = mv88e6xxx_g2_pot_clear,
3824
	.reset = mv88e6352_g1_reset,
3825
	.rmu_disable = mv88e6085_g1_rmu_disable,
3826
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3827
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3828
	.phylink_get_caps = mv88e6185_phylink_get_caps,
3829
	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3830 3831
};

3832
static const struct mv88e6xxx_ops mv88e6123_ops = {
3833
	/* MV88E6XXX_FAMILY_6165 */
3834 3835
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3836
	.irl_init_all = mv88e6352_g2_irl_init_all,
3837
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3838 3839
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3840
	.port_set_link = mv88e6xxx_port_set_link,
3841
	.port_sync_link = mv88e6xxx_port_sync_link,
3842
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3843
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3844 3845
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3846
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3847
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3848
	.port_get_cmode = mv88e6185_port_get_cmode,
3849
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3850
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3851
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3852 3853
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3854
	.stats_get_stats = mv88e6095_stats_get_stats,
3855 3856
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3857
	.watchdog_ops = &mv88e6097_watchdog_ops,
3858
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
3859
	.pot_clear = mv88e6xxx_g2_pot_clear,
3860
	.reset = mv88e6352_g1_reset,
3861 3862
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3863
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3864
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3865
	.phylink_get_caps = mv88e6185_phylink_get_caps,
3866
	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
3867 3868 3869
};

static const struct mv88e6xxx_ops mv88e6131_ops = {
3870
	/* MV88E6XXX_FAMILY_6185 */
3871 3872
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3873
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
3874 3875
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
3876
	.port_set_link = mv88e6xxx_port_set_link,
3877
	.port_sync_link = mv88e6xxx_port_sync_link,
3878
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3879
	.port_tag_remap = mv88e6095_port_tag_remap,
3880
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3881 3882
	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
3883
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3884
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3885
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3886
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3887
	.port_pause_limit = mv88e6097_port_pause_limit,
3888
	.port_set_pause = mv88e6185_port_set_pause,
3889
	.port_get_cmode = mv88e6185_port_get_cmode,
3890
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3891
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3892
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3893 3894
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3895
	.stats_get_stats = mv88e6095_stats_get_stats,
3896 3897
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
3898
	.watchdog_ops = &mv88e6097_watchdog_ops,
3899
	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
3900
	.ppu_enable = mv88e6185_g1_ppu_enable,
3901
	.set_cascade_port = mv88e6185_g1_set_cascade_port,
3902
	.ppu_disable = mv88e6185_g1_ppu_disable,
3903
	.reset = mv88e6185_g1_reset,
3904
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
3905
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
3906
	.phylink_get_caps = mv88e6185_phylink_get_caps,
3907 3908
};

3909 3910
static const struct mv88e6xxx_ops mv88e6141_ops = {
	/* MV88E6XXX_FAMILY_6341 */
3911 3912
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3913
	.irl_init_all = mv88e6352_g2_irl_init_all,
3914 3915 3916 3917 3918 3919
	.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,
3920
	.port_sync_link = mv88e6xxx_port_sync_link,
3921
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
3922
	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
3923
	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
3924
	.port_tag_remap = mv88e6095_port_tag_remap,
3925
	.port_set_policy = mv88e6352_port_set_policy,
3926
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3927 3928
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3929
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3930
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
3931
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3932
	.port_pause_limit = mv88e6097_port_pause_limit,
3933 3934
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3935
	.port_get_cmode = mv88e6352_port_get_cmode,
3936
	.port_set_cmode = mv88e6341_port_set_cmode,
3937
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3938
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3939
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3940 3941 3942
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
3943 3944
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
3945 3946
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
3947
	.pot_clear = mv88e6xxx_g2_pot_clear,
3948
	.reset = mv88e6352_g1_reset,
3949
	.rmu_disable = mv88e6390_g1_rmu_disable,
3950 3951
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
3952
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
3953
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3954 3955
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6341_serdes_get_lane,
3956 3957 3958 3959 3960
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
3961
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3962
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
3963
	.serdes_irq_status = mv88e6390_serdes_irq_status,
3964
	.gpio_ops = &mv88e6352_gpio_ops,
3965 3966 3967
	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
3968 3969
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
3970
	.phylink_get_caps = mv88e6341_phylink_get_caps,
3971 3972
};

3973
static const struct mv88e6xxx_ops mv88e6161_ops = {
3974
	/* MV88E6XXX_FAMILY_6165 */
3975 3976
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
3977
	.irl_init_all = mv88e6352_g2_irl_init_all,
3978
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3979 3980
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3981
	.port_set_link = mv88e6xxx_port_set_link,
3982
	.port_sync_link = mv88e6xxx_port_sync_link,
3983
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
3984
	.port_tag_remap = mv88e6095_port_tag_remap,
3985
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3986 3987
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
3988
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3989
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3990
	.port_pause_limit = mv88e6097_port_pause_limit,
3991
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3992
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3993
	.port_get_cmode = mv88e6185_port_get_cmode,
3994
	.port_setup_message_port = mv88e6xxx_setup_message_port,
3995
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3996
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
3997 3998
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3999
	.stats_get_stats = mv88e6095_stats_get_stats,
4000 4001
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4002
	.watchdog_ops = &mv88e6097_watchdog_ops,
4003
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4004
	.pot_clear = mv88e6xxx_g2_pot_clear,
4005
	.reset = mv88e6352_g1_reset,
4006 4007
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4008
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4009
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4010
	.avb_ops = &mv88e6165_avb_ops,
4011
	.ptp_ops = &mv88e6165_ptp_ops,
4012
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4013
	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4014 4015 4016
};

static const struct mv88e6xxx_ops mv88e6165_ops = {
4017
	/* MV88E6XXX_FAMILY_6165 */
4018 4019
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4020
	.irl_init_all = mv88e6352_g2_irl_init_all,
4021
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4022 4023
	.phy_read = mv88e6165_phy_read,
	.phy_write = mv88e6165_phy_write,
4024
	.port_set_link = mv88e6xxx_port_set_link,
4025
	.port_sync_link = mv88e6xxx_port_sync_link,
4026
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4027
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4028
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4029
	.port_get_cmode = mv88e6185_port_get_cmode,
4030
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4031
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
4032
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4033 4034
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4035
	.stats_get_stats = mv88e6095_stats_get_stats,
4036 4037
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4038
	.watchdog_ops = &mv88e6097_watchdog_ops,
4039
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4040
	.pot_clear = mv88e6xxx_g2_pot_clear,
4041
	.reset = mv88e6352_g1_reset,
4042 4043
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4044
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4045
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4046
	.avb_ops = &mv88e6165_avb_ops,
4047
	.ptp_ops = &mv88e6165_ptp_ops,
4048
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4049 4050 4051
};

static const struct mv88e6xxx_ops mv88e6171_ops = {
4052
	/* MV88E6XXX_FAMILY_6351 */
4053 4054
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4055
	.irl_init_all = mv88e6352_g2_irl_init_all,
4056
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4057 4058
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4059
	.port_set_link = mv88e6xxx_port_set_link,
4060
	.port_sync_link = mv88e6xxx_port_sync_link,
4061
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4062
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4063
	.port_tag_remap = mv88e6095_port_tag_remap,
4064
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4065 4066
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4067
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4068
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4069
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4070
	.port_pause_limit = mv88e6097_port_pause_limit,
4071
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4072
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4073
	.port_get_cmode = mv88e6352_port_get_cmode,
4074
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4075
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4076
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4077 4078
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4079
	.stats_get_stats = mv88e6095_stats_get_stats,
4080 4081
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4082
	.watchdog_ops = &mv88e6097_watchdog_ops,
4083
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4084
	.pot_clear = mv88e6xxx_g2_pot_clear,
4085
	.reset = mv88e6352_g1_reset,
4086 4087
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4088
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4089
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4090
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4091 4092 4093
};

static const struct mv88e6xxx_ops mv88e6172_ops = {
4094
	/* MV88E6XXX_FAMILY_6352 */
4095 4096
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4097
	.irl_init_all = mv88e6352_g2_irl_init_all,
4098 4099
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4100
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4101 4102
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4103
	.port_set_link = mv88e6xxx_port_set_link,
4104
	.port_sync_link = mv88e6xxx_port_sync_link,
4105
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4106
	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4107
	.port_tag_remap = mv88e6095_port_tag_remap,
4108
	.port_set_policy = mv88e6352_port_set_policy,
4109
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4110 4111
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4112
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4113
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4114
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4115
	.port_pause_limit = mv88e6097_port_pause_limit,
4116
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4117
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4118
	.port_get_cmode = mv88e6352_port_get_cmode,
4119
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4120
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4121
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4122 4123
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4124
	.stats_get_stats = mv88e6095_stats_get_stats,
4125 4126
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4127
	.watchdog_ops = &mv88e6097_watchdog_ops,
4128
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4129
	.pot_clear = mv88e6xxx_g2_pot_clear,
4130
	.reset = mv88e6352_g1_reset,
4131
	.rmu_disable = mv88e6352_g1_rmu_disable,
4132 4133
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4134
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4135
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4136
	.serdes_get_lane = mv88e6352_serdes_get_lane,
4137 4138 4139 4140
	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
4141
	.serdes_power = mv88e6352_serdes_power,
4142 4143
	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
	.serdes_get_regs = mv88e6352_serdes_get_regs,
4144
	.gpio_ops = &mv88e6352_gpio_ops,
4145
	.phylink_get_caps = mv88e6352_phylink_get_caps,
4146 4147 4148
};

static const struct mv88e6xxx_ops mv88e6175_ops = {
4149
	/* MV88E6XXX_FAMILY_6351 */
4150 4151
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4152
	.irl_init_all = mv88e6352_g2_irl_init_all,
4153
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4154 4155
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4156
	.port_set_link = mv88e6xxx_port_set_link,
4157
	.port_sync_link = mv88e6xxx_port_sync_link,
4158
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4159
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4160
	.port_tag_remap = mv88e6095_port_tag_remap,
4161
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4162 4163
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4164
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4165
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4166
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4167
	.port_pause_limit = mv88e6097_port_pause_limit,
4168
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4169
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4170
	.port_get_cmode = mv88e6352_port_get_cmode,
4171
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4172
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4173
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4174 4175
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4176
	.stats_get_stats = mv88e6095_stats_get_stats,
4177 4178
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4179
	.watchdog_ops = &mv88e6097_watchdog_ops,
4180
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4181
	.pot_clear = mv88e6xxx_g2_pot_clear,
4182
	.reset = mv88e6352_g1_reset,
4183 4184
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4185
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4186
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4187
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4188 4189 4190
};

static const struct mv88e6xxx_ops mv88e6176_ops = {
4191
	/* MV88E6XXX_FAMILY_6352 */
4192 4193
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4194
	.irl_init_all = mv88e6352_g2_irl_init_all,
4195 4196
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4197
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4198 4199
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4200
	.port_set_link = mv88e6xxx_port_set_link,
4201
	.port_sync_link = mv88e6xxx_port_sync_link,
4202
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4203
	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4204
	.port_tag_remap = mv88e6095_port_tag_remap,
4205
	.port_set_policy = mv88e6352_port_set_policy,
4206
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4207 4208
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4209
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4210
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4211
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4212
	.port_pause_limit = mv88e6097_port_pause_limit,
4213
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4214
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4215
	.port_get_cmode = mv88e6352_port_get_cmode,
4216
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4217
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4218
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4219 4220
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4221
	.stats_get_stats = mv88e6095_stats_get_stats,
4222 4223
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4224
	.watchdog_ops = &mv88e6097_watchdog_ops,
4225
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4226
	.pot_clear = mv88e6xxx_g2_pot_clear,
4227
	.reset = mv88e6352_g1_reset,
4228
	.rmu_disable = mv88e6352_g1_rmu_disable,
4229 4230
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4231
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4232
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4233
	.serdes_get_lane = mv88e6352_serdes_get_lane,
4234 4235 4236 4237
	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
4238
	.serdes_power = mv88e6352_serdes_power,
4239
	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
4240
	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4241
	.serdes_irq_status = mv88e6352_serdes_irq_status,
4242 4243
	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
	.serdes_get_regs = mv88e6352_serdes_get_regs,
4244
	.gpio_ops = &mv88e6352_gpio_ops,
4245
	.phylink_get_caps = mv88e6352_phylink_get_caps,
4246 4247 4248
};

static const struct mv88e6xxx_ops mv88e6185_ops = {
4249
	/* MV88E6XXX_FAMILY_6185 */
4250 4251
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4252
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
4253 4254
	.phy_read = mv88e6185_phy_ppu_read,
	.phy_write = mv88e6185_phy_ppu_write,
4255
	.port_set_link = mv88e6xxx_port_set_link,
4256
	.port_sync_link = mv88e6185_port_sync_link,
4257
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4258
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
4259 4260
	.port_set_ucast_flood = mv88e6185_port_set_forward_unknown,
	.port_set_mcast_flood = mv88e6185_port_set_default_forward,
4261
	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
4262
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
4263
	.port_set_pause = mv88e6185_port_set_pause,
4264
	.port_get_cmode = mv88e6185_port_get_cmode,
4265
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4266
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
4267
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4268 4269
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4270
	.stats_get_stats = mv88e6095_stats_get_stats,
4271 4272
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4273
	.watchdog_ops = &mv88e6097_watchdog_ops,
4274
	.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4275 4276 4277
	.serdes_power = mv88e6185_serdes_power,
	.serdes_get_lane = mv88e6185_serdes_get_lane,
	.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
4278
	.set_cascade_port = mv88e6185_g1_set_cascade_port,
4279 4280
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
4281
	.reset = mv88e6185_g1_reset,
4282
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
4283
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4284
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4285
	.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
4286 4287
};

4288
static const struct mv88e6xxx_ops mv88e6190_ops = {
4289
	/* MV88E6XXX_FAMILY_6390 */
4290
	.setup_errata = mv88e6390_setup_errata,
4291
	.irl_init_all = mv88e6390_g2_irl_init_all,
4292 4293
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4294 4295 4296 4297
	.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,
4298
	.port_sync_link = mv88e6xxx_port_sync_link,
4299
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4300
	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
4301
	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4302
	.port_tag_remap = mv88e6390_port_tag_remap,
4303
	.port_set_policy = mv88e6352_port_set_policy,
4304
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4305 4306
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4307
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4308
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4309
	.port_pause_limit = mv88e6390_port_pause_limit,
4310
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4311
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4312
	.port_get_cmode = mv88e6352_port_get_cmode,
4313
	.port_set_cmode = mv88e6390_port_set_cmode,
4314
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4315
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4316
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4317 4318
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4319
	.stats_get_stats = mv88e6390_stats_get_stats,
4320 4321
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
4322
	.watchdog_ops = &mv88e6390_watchdog_ops,
4323
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
4324
	.pot_clear = mv88e6xxx_g2_pot_clear,
4325
	.reset = mv88e6352_g1_reset,
4326
	.rmu_disable = mv88e6390_g1_rmu_disable,
4327 4328
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4329 4330
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4331
	.serdes_power = mv88e6390_serdes_power,
4332
	.serdes_get_lane = mv88e6390_serdes_get_lane,
4333 4334 4335 4336 4337
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4338
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4339
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4340
	.serdes_irq_status = mv88e6390_serdes_irq_status,
4341 4342
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
4343 4344
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
4345
	.gpio_ops = &mv88e6352_gpio_ops,
4346
	.phylink_get_caps = mv88e6390_phylink_get_caps,
4347 4348 4349
};

static const struct mv88e6xxx_ops mv88e6190x_ops = {
4350
	/* MV88E6XXX_FAMILY_6390 */
4351
	.setup_errata = mv88e6390_setup_errata,
4352
	.irl_init_all = mv88e6390_g2_irl_init_all,
4353 4354
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4355 4356 4357 4358
	.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,
4359
	.port_sync_link = mv88e6xxx_port_sync_link,
4360
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4361
	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
4362
	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
4363
	.port_tag_remap = mv88e6390_port_tag_remap,
4364
	.port_set_policy = mv88e6352_port_set_policy,
4365
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4366 4367
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4368
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4369
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4370
	.port_pause_limit = mv88e6390_port_pause_limit,
4371
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4372
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4373
	.port_get_cmode = mv88e6352_port_get_cmode,
4374
	.port_set_cmode = mv88e6390x_port_set_cmode,
4375
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4376
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4377
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4378 4379
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4380
	.stats_get_stats = mv88e6390_stats_get_stats,
4381 4382
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
4383
	.watchdog_ops = &mv88e6390_watchdog_ops,
4384
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
4385
	.pot_clear = mv88e6xxx_g2_pot_clear,
4386
	.reset = mv88e6352_g1_reset,
4387
	.rmu_disable = mv88e6390_g1_rmu_disable,
4388 4389
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4390 4391
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4392
	.serdes_power = mv88e6390_serdes_power,
4393
	.serdes_get_lane = mv88e6390x_serdes_get_lane,
4394 4395 4396 4397 4398
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4399
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4400
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4401
	.serdes_irq_status = mv88e6390_serdes_irq_status,
4402 4403
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
4404 4405
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
4406
	.gpio_ops = &mv88e6352_gpio_ops,
4407
	.phylink_get_caps = mv88e6390x_phylink_get_caps,
4408 4409 4410
};

static const struct mv88e6xxx_ops mv88e6191_ops = {
4411
	/* MV88E6XXX_FAMILY_6390 */
4412
	.setup_errata = mv88e6390_setup_errata,
4413
	.irl_init_all = mv88e6390_g2_irl_init_all,
4414 4415
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4416 4417 4418 4419
	.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,
4420
	.port_sync_link = mv88e6xxx_port_sync_link,
4421
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4422
	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
4423
	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4424
	.port_tag_remap = mv88e6390_port_tag_remap,
4425
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4426 4427
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4428
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4429
	.port_pause_limit = mv88e6390_port_pause_limit,
4430
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4431
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4432
	.port_get_cmode = mv88e6352_port_get_cmode,
4433
	.port_set_cmode = mv88e6390_port_set_cmode,
4434
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4435
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4436
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4437 4438
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4439
	.stats_get_stats = mv88e6390_stats_get_stats,
4440 4441
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
4442
	.watchdog_ops = &mv88e6390_watchdog_ops,
4443
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
4444
	.pot_clear = mv88e6xxx_g2_pot_clear,
4445
	.reset = mv88e6352_g1_reset,
4446
	.rmu_disable = mv88e6390_g1_rmu_disable,
4447 4448
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4449 4450
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4451
	.serdes_power = mv88e6390_serdes_power,
4452
	.serdes_get_lane = mv88e6390_serdes_get_lane,
4453 4454 4455 4456 4457
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4458
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4459
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4460
	.serdes_irq_status = mv88e6390_serdes_irq_status,
4461 4462
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
4463 4464
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
4465 4466
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
4467
	.phylink_get_caps = mv88e6390_phylink_get_caps,
4468 4469
};

4470
static const struct mv88e6xxx_ops mv88e6240_ops = {
4471
	/* MV88E6XXX_FAMILY_6352 */
4472 4473
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4474
	.irl_init_all = mv88e6352_g2_irl_init_all,
4475 4476
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4477
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4478 4479
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4480
	.port_set_link = mv88e6xxx_port_set_link,
4481
	.port_sync_link = mv88e6xxx_port_sync_link,
4482
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4483
	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4484
	.port_tag_remap = mv88e6095_port_tag_remap,
4485
	.port_set_policy = mv88e6352_port_set_policy,
4486
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4487 4488
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4489
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4490
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4491
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4492
	.port_pause_limit = mv88e6097_port_pause_limit,
4493
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4494
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4495
	.port_get_cmode = mv88e6352_port_get_cmode,
4496
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4497
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4498
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4499 4500
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4501
	.stats_get_stats = mv88e6095_stats_get_stats,
4502 4503
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4504
	.watchdog_ops = &mv88e6097_watchdog_ops,
4505
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4506
	.pot_clear = mv88e6xxx_g2_pot_clear,
4507
	.reset = mv88e6352_g1_reset,
4508
	.rmu_disable = mv88e6352_g1_rmu_disable,
4509 4510
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4511
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4512
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4513
	.serdes_get_lane = mv88e6352_serdes_get_lane,
4514 4515 4516 4517
	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
4518
	.serdes_power = mv88e6352_serdes_power,
4519
	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
4520
	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4521
	.serdes_irq_status = mv88e6352_serdes_irq_status,
4522 4523
	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
	.serdes_get_regs = mv88e6352_serdes_get_regs,
4524
	.gpio_ops = &mv88e6352_gpio_ops,
4525
	.avb_ops = &mv88e6352_avb_ops,
4526
	.ptp_ops = &mv88e6352_ptp_ops,
4527
	.phylink_get_caps = mv88e6352_phylink_get_caps,
4528 4529
};

4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540
static const struct mv88e6xxx_ops mv88e6250_ops = {
	/* MV88E6XXX_FAMILY_6250 */
	.ieee_pri_map = mv88e6250_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
	.irl_init_all = mv88e6352_g2_irl_init_all,
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
	.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,
4541
	.port_sync_link = mv88e6xxx_port_sync_link,
4542
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4543
	.port_set_speed_duplex = mv88e6250_port_set_speed_duplex,
4544 4545
	.port_tag_remap = mv88e6095_port_tag_remap,
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4546 4547
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562
	.port_set_ether_type = mv88e6351_port_set_ether_type,
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
	.port_pause_limit = mv88e6097_port_pause_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
	.stats_get_sset_count = mv88e6250_stats_get_sset_count,
	.stats_get_strings = mv88e6250_stats_get_strings,
	.stats_get_stats = mv88e6250_stats_get_stats,
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
	.watchdog_ops = &mv88e6250_watchdog_ops,
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
	.pot_clear = mv88e6xxx_g2_pot_clear,
	.reset = mv88e6250_g1_reset,
4563
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
4564
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4565 4566
	.avb_ops = &mv88e6352_avb_ops,
	.ptp_ops = &mv88e6250_ptp_ops,
4567
	.phylink_get_caps = mv88e6250_phylink_get_caps,
4568 4569
};

4570
static const struct mv88e6xxx_ops mv88e6290_ops = {
4571
	/* MV88E6XXX_FAMILY_6390 */
4572
	.setup_errata = mv88e6390_setup_errata,
4573
	.irl_init_all = mv88e6390_g2_irl_init_all,
4574 4575
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4576 4577 4578 4579
	.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,
4580
	.port_sync_link = mv88e6xxx_port_sync_link,
4581
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4582
	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
4583
	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4584
	.port_tag_remap = mv88e6390_port_tag_remap,
4585
	.port_set_policy = mv88e6352_port_set_policy,
4586
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4587 4588
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4589
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4590
	.port_pause_limit = mv88e6390_port_pause_limit,
4591
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4592
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4593
	.port_get_cmode = mv88e6352_port_get_cmode,
4594
	.port_set_cmode = mv88e6390_port_set_cmode,
4595
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4596
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4597
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4598 4599
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4600
	.stats_get_stats = mv88e6390_stats_get_stats,
4601 4602
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
4603
	.watchdog_ops = &mv88e6390_watchdog_ops,
4604
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
4605
	.pot_clear = mv88e6xxx_g2_pot_clear,
4606
	.reset = mv88e6352_g1_reset,
4607
	.rmu_disable = mv88e6390_g1_rmu_disable,
4608 4609
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4610 4611
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4612
	.serdes_power = mv88e6390_serdes_power,
4613
	.serdes_get_lane = mv88e6390_serdes_get_lane,
4614 4615 4616 4617 4618
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4619
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4620
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4621
	.serdes_irq_status = mv88e6390_serdes_irq_status,
4622 4623
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
4624 4625
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
4626
	.gpio_ops = &mv88e6352_gpio_ops,
4627
	.avb_ops = &mv88e6390_avb_ops,
4628
	.ptp_ops = &mv88e6352_ptp_ops,
4629
	.phylink_get_caps = mv88e6390_phylink_get_caps,
4630 4631
};

4632
static const struct mv88e6xxx_ops mv88e6320_ops = {
4633
	/* MV88E6XXX_FAMILY_6320 */
4634 4635
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4636
	.irl_init_all = mv88e6352_g2_irl_init_all,
4637 4638
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4639
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4640 4641
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4642
	.port_set_link = mv88e6xxx_port_set_link,
4643
	.port_sync_link = mv88e6xxx_port_sync_link,
4644
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4645
	.port_tag_remap = mv88e6095_port_tag_remap,
4646
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4647 4648
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4649
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4650
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4651
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4652
	.port_pause_limit = mv88e6097_port_pause_limit,
4653
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4654
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4655
	.port_get_cmode = mv88e6352_port_get_cmode,
4656
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4657
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4658
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4659 4660
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4661
	.stats_get_stats = mv88e6320_stats_get_stats,
4662 4663
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4664
	.watchdog_ops = &mv88e6390_watchdog_ops,
4665
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4666
	.pot_clear = mv88e6xxx_g2_pot_clear,
4667
	.reset = mv88e6352_g1_reset,
4668
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
4669
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4670
	.gpio_ops = &mv88e6352_gpio_ops,
4671
	.avb_ops = &mv88e6352_avb_ops,
4672
	.ptp_ops = &mv88e6352_ptp_ops,
4673
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4674 4675 4676
};

static const struct mv88e6xxx_ops mv88e6321_ops = {
4677
	/* MV88E6XXX_FAMILY_6320 */
4678 4679
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4680
	.irl_init_all = mv88e6352_g2_irl_init_all,
4681 4682
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4683
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4684 4685
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4686
	.port_set_link = mv88e6xxx_port_set_link,
4687
	.port_sync_link = mv88e6xxx_port_sync_link,
4688
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4689
	.port_tag_remap = mv88e6095_port_tag_remap,
4690
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4691 4692
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4693
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4694
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4695
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4696
	.port_pause_limit = mv88e6097_port_pause_limit,
4697
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4698
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4699
	.port_get_cmode = mv88e6352_port_get_cmode,
4700
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4701
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4702
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4703 4704
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4705
	.stats_get_stats = mv88e6320_stats_get_stats,
4706 4707
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4708
	.watchdog_ops = &mv88e6390_watchdog_ops,
4709
	.reset = mv88e6352_g1_reset,
4710
	.vtu_getnext = mv88e6185_g1_vtu_getnext,
4711
	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
4712
	.gpio_ops = &mv88e6352_gpio_ops,
4713
	.avb_ops = &mv88e6352_avb_ops,
4714
	.ptp_ops = &mv88e6352_ptp_ops,
4715
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4716 4717
};

4718 4719
static const struct mv88e6xxx_ops mv88e6341_ops = {
	/* MV88E6XXX_FAMILY_6341 */
4720 4721
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4722
	.irl_init_all = mv88e6352_g2_irl_init_all,
4723 4724 4725 4726 4727 4728
	.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,
4729
	.port_sync_link = mv88e6xxx_port_sync_link,
4730
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4731
	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
4732
	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
4733
	.port_tag_remap = mv88e6095_port_tag_remap,
4734
	.port_set_policy = mv88e6352_port_set_policy,
4735
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4736 4737
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4738
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4739
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4740
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4741
	.port_pause_limit = mv88e6097_port_pause_limit,
4742 4743
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4744
	.port_get_cmode = mv88e6352_port_get_cmode,
4745
	.port_set_cmode = mv88e6341_port_set_cmode,
4746
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4747
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4748
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4749 4750 4751
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
4752 4753
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
4754 4755
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
4756
	.pot_clear = mv88e6xxx_g2_pot_clear,
4757
	.reset = mv88e6352_g1_reset,
4758
	.rmu_disable = mv88e6390_g1_rmu_disable,
4759 4760
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4761
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4762
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4763 4764
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6341_serdes_get_lane,
4765 4766 4767 4768 4769
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4770
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4771
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4772
	.serdes_irq_status = mv88e6390_serdes_irq_status,
4773
	.gpio_ops = &mv88e6352_gpio_ops,
4774
	.avb_ops = &mv88e6390_avb_ops,
4775
	.ptp_ops = &mv88e6352_ptp_ops,
4776 4777 4778
	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
4779 4780
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
4781
	.phylink_get_caps = mv88e6341_phylink_get_caps,
4782 4783
};

4784
static const struct mv88e6xxx_ops mv88e6350_ops = {
4785
	/* MV88E6XXX_FAMILY_6351 */
4786 4787
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4788
	.irl_init_all = mv88e6352_g2_irl_init_all,
4789
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4790 4791
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4792
	.port_set_link = mv88e6xxx_port_set_link,
4793
	.port_sync_link = mv88e6xxx_port_sync_link,
4794
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4795
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4796
	.port_tag_remap = mv88e6095_port_tag_remap,
4797
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4798 4799
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4800
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4801
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4802
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4803
	.port_pause_limit = mv88e6097_port_pause_limit,
4804
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4805
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4806
	.port_get_cmode = mv88e6352_port_get_cmode,
4807
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4808
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4809
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4810 4811
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4812
	.stats_get_stats = mv88e6095_stats_get_stats,
4813 4814
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4815
	.watchdog_ops = &mv88e6097_watchdog_ops,
4816
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4817
	.pot_clear = mv88e6xxx_g2_pot_clear,
4818
	.reset = mv88e6352_g1_reset,
4819 4820
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4821
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4822
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4823
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4824 4825 4826
};

static const struct mv88e6xxx_ops mv88e6351_ops = {
4827
	/* MV88E6XXX_FAMILY_6351 */
4828 4829
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4830
	.irl_init_all = mv88e6352_g2_irl_init_all,
4831
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4832 4833
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4834
	.port_set_link = mv88e6xxx_port_set_link,
4835
	.port_sync_link = mv88e6xxx_port_sync_link,
4836
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4837
	.port_set_speed_duplex = mv88e6185_port_set_speed_duplex,
4838
	.port_tag_remap = mv88e6095_port_tag_remap,
4839
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4840 4841
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4842
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4843
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4844
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4845
	.port_pause_limit = mv88e6097_port_pause_limit,
4846
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4847
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4848
	.port_get_cmode = mv88e6352_port_get_cmode,
4849
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4850
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4851
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4852 4853
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4854
	.stats_get_stats = mv88e6095_stats_get_stats,
4855 4856
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4857
	.watchdog_ops = &mv88e6097_watchdog_ops,
4858
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4859
	.pot_clear = mv88e6xxx_g2_pot_clear,
4860
	.reset = mv88e6352_g1_reset,
4861 4862
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4863
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4864
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4865
	.avb_ops = &mv88e6352_avb_ops,
4866
	.ptp_ops = &mv88e6352_ptp_ops,
4867
	.phylink_get_caps = mv88e6185_phylink_get_caps,
4868 4869 4870
};

static const struct mv88e6xxx_ops mv88e6352_ops = {
4871
	/* MV88E6XXX_FAMILY_6352 */
4872 4873
	.ieee_pri_map = mv88e6085_g1_ieee_pri_map,
	.ip_pri_map = mv88e6085_g1_ip_pri_map,
4874
	.irl_init_all = mv88e6352_g2_irl_init_all,
4875 4876
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
4877
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
4878 4879
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
4880
	.port_set_link = mv88e6xxx_port_set_link,
4881
	.port_sync_link = mv88e6xxx_port_sync_link,
4882
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
4883
	.port_set_speed_duplex = mv88e6352_port_set_speed_duplex,
4884
	.port_tag_remap = mv88e6095_port_tag_remap,
4885
	.port_set_policy = mv88e6352_port_set_policy,
4886
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4887 4888
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4889
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4890
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4891
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4892
	.port_pause_limit = mv88e6097_port_pause_limit,
4893
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4894
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4895
	.port_get_cmode = mv88e6352_port_get_cmode,
4896
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4897
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
4898
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
4899 4900
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
4901
	.stats_get_stats = mv88e6095_stats_get_stats,
4902 4903
	.set_cpu_port = mv88e6095_g1_set_cpu_port,
	.set_egress_port = mv88e6095_g1_set_egress_port,
4904
	.watchdog_ops = &mv88e6097_watchdog_ops,
4905
	.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4906
	.pot_clear = mv88e6xxx_g2_pot_clear,
4907
	.reset = mv88e6352_g1_reset,
4908
	.rmu_disable = mv88e6352_g1_rmu_disable,
4909 4910
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4911
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
4912
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
4913
	.serdes_get_lane = mv88e6352_serdes_get_lane,
4914 4915 4916 4917
	.serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6352_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
4918
	.serdes_power = mv88e6352_serdes_power,
4919
	.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
4920
	.serdes_irq_enable = mv88e6352_serdes_irq_enable,
4921
	.serdes_irq_status = mv88e6352_serdes_irq_status,
4922
	.gpio_ops = &mv88e6352_gpio_ops,
4923
	.avb_ops = &mv88e6352_avb_ops,
4924
	.ptp_ops = &mv88e6352_ptp_ops,
4925 4926 4927
	.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
	.serdes_get_strings = mv88e6352_serdes_get_strings,
	.serdes_get_stats = mv88e6352_serdes_get_stats,
4928 4929
	.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
	.serdes_get_regs = mv88e6352_serdes_get_regs,
4930
	.phylink_get_caps = mv88e6352_phylink_get_caps,
4931 4932
};

4933
static const struct mv88e6xxx_ops mv88e6390_ops = {
4934
	/* MV88E6XXX_FAMILY_6390 */
4935
	.setup_errata = mv88e6390_setup_errata,
4936
	.irl_init_all = mv88e6390_g2_irl_init_all,
4937 4938
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
4939 4940 4941 4942
	.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,
4943
	.port_sync_link = mv88e6xxx_port_sync_link,
4944
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
4945
	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
4946
	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
4947
	.port_tag_remap = mv88e6390_port_tag_remap,
4948
	.port_set_policy = mv88e6352_port_set_policy,
4949
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
4950 4951
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
4952
	.port_set_ether_type = mv88e6351_port_set_ether_type,
4953
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
4954
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
4955
	.port_pause_limit = mv88e6390_port_pause_limit,
4956
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
4957
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
4958
	.port_get_cmode = mv88e6352_port_get_cmode,
4959
	.port_set_cmode = mv88e6390_port_set_cmode,
4960
	.port_setup_message_port = mv88e6xxx_setup_message_port,
4961
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
4962
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
4963 4964
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
4965
	.stats_get_stats = mv88e6390_stats_get_stats,
4966 4967
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
4968
	.watchdog_ops = &mv88e6390_watchdog_ops,
4969
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
4970
	.pot_clear = mv88e6xxx_g2_pot_clear,
4971
	.reset = mv88e6352_g1_reset,
4972
	.rmu_disable = mv88e6390_g1_rmu_disable,
4973 4974
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
4975 4976
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
4977
	.serdes_power = mv88e6390_serdes_power,
4978
	.serdes_get_lane = mv88e6390_serdes_get_lane,
4979 4980 4981 4982 4983
	/* Check status register pause & lpa register */
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
4984
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4985
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
4986
	.serdes_irq_status = mv88e6390_serdes_irq_status,
4987
	.gpio_ops = &mv88e6352_gpio_ops,
4988
	.avb_ops = &mv88e6390_avb_ops,
4989
	.ptp_ops = &mv88e6352_ptp_ops,
4990 4991 4992
	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
4993 4994
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
4995
	.phylink_get_caps = mv88e6390_phylink_get_caps,
4996 4997 4998
};

static const struct mv88e6xxx_ops mv88e6390x_ops = {
4999
	/* MV88E6XXX_FAMILY_6390 */
5000
	.setup_errata = mv88e6390_setup_errata,
5001
	.irl_init_all = mv88e6390_g2_irl_init_all,
5002 5003
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
5004 5005 5006 5007
	.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,
5008
	.port_sync_link = mv88e6xxx_port_sync_link,
5009
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
5010
	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
5011
	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
5012
	.port_tag_remap = mv88e6390_port_tag_remap,
5013
	.port_set_policy = mv88e6352_port_set_policy,
5014
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
5015 5016
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
5017
	.port_set_ether_type = mv88e6351_port_set_ether_type,
5018
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
5019
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
5020
	.port_pause_limit = mv88e6390_port_pause_limit,
5021
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
5022
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
5023
	.port_get_cmode = mv88e6352_port_get_cmode,
5024
	.port_set_cmode = mv88e6390x_port_set_cmode,
5025
	.port_setup_message_port = mv88e6xxx_setup_message_port,
5026
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
5027
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
5028 5029
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
5030
	.stats_get_stats = mv88e6390_stats_get_stats,
5031 5032
	.set_cpu_port = mv88e6390_g1_set_cpu_port,
	.set_egress_port = mv88e6390_g1_set_egress_port,
5033
	.watchdog_ops = &mv88e6390_watchdog_ops,
5034
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
5035
	.pot_clear = mv88e6xxx_g2_pot_clear,
5036
	.reset = mv88e6352_g1_reset,
5037
	.rmu_disable = mv88e6390_g1_rmu_disable,
5038 5039
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
5040 5041
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
5042
	.serdes_power = mv88e6390_serdes_power,
5043
	.serdes_get_lane = mv88e6390x_serdes_get_lane,
5044 5045 5046 5047
	.serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
5048
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
5049
	.serdes_irq_enable = mv88e6390_serdes_irq_enable,
5050
	.serdes_irq_status = mv88e6390_serdes_irq_status,
5051 5052 5053
	.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
	.serdes_get_strings = mv88e6390_serdes_get_strings,
	.serdes_get_stats = mv88e6390_serdes_get_stats,
5054 5055
	.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
	.serdes_get_regs = mv88e6390_serdes_get_regs,
5056
	.gpio_ops = &mv88e6352_gpio_ops,
5057
	.avb_ops = &mv88e6390_avb_ops,
5058
	.ptp_ops = &mv88e6352_ptp_ops,
5059
	.phylink_get_caps = mv88e6390x_phylink_get_caps,
5060 5061
};

5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076
static const struct mv88e6xxx_ops mv88e6393x_ops = {
	/* MV88E6XXX_FAMILY_6393 */
	.setup_errata = mv88e6393x_serdes_setup_errata,
	.irl_init_all = mv88e6390_g2_irl_init_all,
	.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_sync_link = mv88e6xxx_port_sync_link,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
	.port_max_speed_mode = mv88e6393x_port_max_speed_mode,
	.port_tag_remap = mv88e6390_port_tag_remap,
5077
	.port_set_policy = mv88e6393x_port_set_policy,
5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
	.port_set_ether_type = mv88e6393x_port_set_ether_type,
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
	.port_pause_limit = mv88e6390_port_pause_limit,
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.port_get_cmode = mv88e6352_port_get_cmode,
	.port_set_cmode = mv88e6393x_port_set_cmode,
	.port_setup_message_port = mv88e6xxx_setup_message_port,
	.port_set_upstream_port = mv88e6393x_port_set_upstream_port,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
	/* .set_cpu_port is missing because this family does not support a global
	 * CPU port, only per port CPU port which is set via
	 * .port_set_upstream_port method.
	 */
	.set_egress_port = mv88e6393x_set_egress_port,
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
	.pot_clear = mv88e6xxx_g2_pot_clear,
	.reset = mv88e6352_g1_reset,
	.rmu_disable = mv88e6390_g1_rmu_disable,
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6393x_serdes_power,
	.serdes_get_lane = mv88e6393x_serdes_get_lane,
	.serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6393x_serdes_irq_enable,
	.serdes_irq_status = mv88e6393x_serdes_irq_status,
	/* TODO: serdes stats */
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
5123
	.phylink_get_caps = mv88e6393x_phylink_get_caps,
5124 5125
};

5126 5127
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
	[MV88E6085] = {
5128
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
5129 5130 5131
		.family = MV88E6XXX_FAMILY_6097,
		.name = "Marvell 88E6085",
		.num_databases = 4096,
5132
		.num_macs = 8192,
5133
		.num_ports = 10,
5134
		.num_internal_phys = 5,
5135
		.max_vid = 4095,
5136
		.port_base_addr = 0x10,
5137
		.phy_base_addr = 0x0,
5138
		.global1_addr = 0x1b,
5139
		.global2_addr = 0x1c,
5140
		.age_time_coeff = 15000,
5141
		.g1_irqs = 8,
5142
		.g2_irqs = 10,
5143
		.atu_move_port_mask = 0xf,
5144
		.pvt = true,
5145
		.multi_chip = true,
5146
		.ops = &mv88e6085_ops,
5147 5148 5149
	},

	[MV88E6095] = {
5150
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
5151 5152 5153
		.family = MV88E6XXX_FAMILY_6095,
		.name = "Marvell 88E6095/88E6095F",
		.num_databases = 256,
5154
		.num_macs = 8192,
5155
		.num_ports = 11,
5156
		.num_internal_phys = 0,
5157
		.max_vid = 4095,
5158
		.port_base_addr = 0x10,
5159
		.phy_base_addr = 0x0,
5160
		.global1_addr = 0x1b,
5161
		.global2_addr = 0x1c,
5162
		.age_time_coeff = 15000,
5163
		.g1_irqs = 8,
5164
		.atu_move_port_mask = 0xf,
5165
		.multi_chip = true,
5166
		.ops = &mv88e6095_ops,
5167 5168
	},

5169
	[MV88E6097] = {
5170
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
5171 5172 5173
		.family = MV88E6XXX_FAMILY_6097,
		.name = "Marvell 88E6097/88E6097F",
		.num_databases = 4096,
5174
		.num_macs = 8192,
5175
		.num_ports = 11,
5176
		.num_internal_phys = 8,
5177
		.max_vid = 4095,
5178
		.port_base_addr = 0x10,
5179
		.phy_base_addr = 0x0,
5180
		.global1_addr = 0x1b,
5181
		.global2_addr = 0x1c,
5182
		.age_time_coeff = 15000,
5183
		.g1_irqs = 8,
5184
		.g2_irqs = 10,
5185
		.atu_move_port_mask = 0xf,
5186
		.pvt = true,
5187
		.multi_chip = true,
5188
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5189 5190 5191
		.ops = &mv88e6097_ops,
	},

5192
	[MV88E6123] = {
5193
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
5194 5195 5196
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6123",
		.num_databases = 4096,
5197
		.num_macs = 1024,
5198
		.num_ports = 3,
5199
		.num_internal_phys = 5,
5200
		.max_vid = 4095,
5201
		.port_base_addr = 0x10,
5202
		.phy_base_addr = 0x0,
5203
		.global1_addr = 0x1b,
5204
		.global2_addr = 0x1c,
5205
		.age_time_coeff = 15000,
5206
		.g1_irqs = 9,
5207
		.g2_irqs = 10,
5208
		.atu_move_port_mask = 0xf,
5209
		.pvt = true,
5210
		.multi_chip = true,
5211
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5212
		.ops = &mv88e6123_ops,
5213 5214 5215
	},

	[MV88E6131] = {
5216
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
5217 5218 5219
		.family = MV88E6XXX_FAMILY_6185,
		.name = "Marvell 88E6131",
		.num_databases = 256,
5220
		.num_macs = 8192,
5221
		.num_ports = 8,
5222
		.num_internal_phys = 0,
5223
		.max_vid = 4095,
5224
		.port_base_addr = 0x10,
5225
		.phy_base_addr = 0x0,
5226
		.global1_addr = 0x1b,
5227
		.global2_addr = 0x1c,
5228
		.age_time_coeff = 15000,
5229
		.g1_irqs = 9,
5230
		.atu_move_port_mask = 0xf,
5231
		.multi_chip = true,
5232
		.ops = &mv88e6131_ops,
5233 5234
	},

5235
	[MV88E6141] = {
5236
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
5237
		.family = MV88E6XXX_FAMILY_6341,
5238
		.name = "Marvell 88E6141",
5239
		.num_databases = 4096,
5240
		.num_macs = 2048,
5241
		.num_ports = 6,
5242
		.num_internal_phys = 5,
5243
		.num_gpio = 11,
5244
		.max_vid = 4095,
5245
		.port_base_addr = 0x10,
5246
		.phy_base_addr = 0x10,
5247
		.global1_addr = 0x1b,
5248
		.global2_addr = 0x1c,
5249 5250
		.age_time_coeff = 3750,
		.atu_move_port_mask = 0x1f,
5251
		.g1_irqs = 9,
5252
		.g2_irqs = 10,
5253
		.pvt = true,
5254
		.multi_chip = true,
5255
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5256 5257 5258
		.ops = &mv88e6141_ops,
	},

5259
	[MV88E6161] = {
5260
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
5261 5262 5263
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6161",
		.num_databases = 4096,
5264
		.num_macs = 1024,
5265
		.num_ports = 6,
5266
		.num_internal_phys = 5,
5267
		.max_vid = 4095,
5268
		.port_base_addr = 0x10,
5269
		.phy_base_addr = 0x0,
5270
		.global1_addr = 0x1b,
5271
		.global2_addr = 0x1c,
5272
		.age_time_coeff = 15000,
5273
		.g1_irqs = 9,
5274
		.g2_irqs = 10,
5275
		.atu_move_port_mask = 0xf,
5276
		.pvt = true,
5277
		.multi_chip = true,
5278
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5279
		.ptp_support = true,
5280
		.ops = &mv88e6161_ops,
5281 5282 5283
	},

	[MV88E6165] = {
5284
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
5285 5286 5287
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6165",
		.num_databases = 4096,
5288
		.num_macs = 8192,
5289
		.num_ports = 6,
5290
		.num_internal_phys = 0,
5291
		.max_vid = 4095,
5292
		.port_base_addr = 0x10,
5293
		.phy_base_addr = 0x0,
5294
		.global1_addr = 0x1b,
5295
		.global2_addr = 0x1c,
5296
		.age_time_coeff = 15000,
5297
		.g1_irqs = 9,
5298
		.g2_irqs = 10,
5299
		.atu_move_port_mask = 0xf,
5300
		.pvt = true,
5301
		.multi_chip = true,
5302
		.ptp_support = true,
5303
		.ops = &mv88e6165_ops,
5304 5305 5306
	},

	[MV88E6171] = {
5307
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
5308 5309 5310
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6171",
		.num_databases = 4096,
5311
		.num_macs = 8192,
5312
		.num_ports = 7,
5313
		.num_internal_phys = 5,
5314
		.max_vid = 4095,
5315
		.port_base_addr = 0x10,
5316
		.phy_base_addr = 0x0,
5317
		.global1_addr = 0x1b,
5318
		.global2_addr = 0x1c,
5319
		.age_time_coeff = 15000,
5320
		.g1_irqs = 9,
5321
		.g2_irqs = 10,
5322
		.atu_move_port_mask = 0xf,
5323
		.pvt = true,
5324
		.multi_chip = true,
5325
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5326
		.ops = &mv88e6171_ops,
5327 5328 5329
	},

	[MV88E6172] = {
5330
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
5331 5332 5333
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6172",
		.num_databases = 4096,
5334
		.num_macs = 8192,
5335
		.num_ports = 7,
5336
		.num_internal_phys = 5,
5337
		.num_gpio = 15,
5338
		.max_vid = 4095,
5339
		.port_base_addr = 0x10,
5340
		.phy_base_addr = 0x0,
5341
		.global1_addr = 0x1b,
5342
		.global2_addr = 0x1c,
5343
		.age_time_coeff = 15000,
5344
		.g1_irqs = 9,
5345
		.g2_irqs = 10,
5346
		.atu_move_port_mask = 0xf,
5347
		.pvt = true,
5348
		.multi_chip = true,
5349
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5350
		.ops = &mv88e6172_ops,
5351 5352 5353
	},

	[MV88E6175] = {
5354
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
5355 5356 5357
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6175",
		.num_databases = 4096,
5358
		.num_macs = 8192,
5359
		.num_ports = 7,
5360
		.num_internal_phys = 5,
5361
		.max_vid = 4095,
5362
		.port_base_addr = 0x10,
5363
		.phy_base_addr = 0x0,
5364
		.global1_addr = 0x1b,
5365
		.global2_addr = 0x1c,
5366
		.age_time_coeff = 15000,
5367
		.g1_irqs = 9,
5368
		.g2_irqs = 10,
5369
		.atu_move_port_mask = 0xf,
5370
		.pvt = true,
5371
		.multi_chip = true,
5372
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5373
		.ops = &mv88e6175_ops,
5374 5375 5376
	},

	[MV88E6176] = {
5377
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
5378 5379 5380
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6176",
		.num_databases = 4096,
5381
		.num_macs = 8192,
5382
		.num_ports = 7,
5383
		.num_internal_phys = 5,
5384
		.num_gpio = 15,
5385
		.max_vid = 4095,
5386
		.port_base_addr = 0x10,
5387
		.phy_base_addr = 0x0,
5388
		.global1_addr = 0x1b,
5389
		.global2_addr = 0x1c,
5390
		.age_time_coeff = 15000,
5391
		.g1_irqs = 9,
5392
		.g2_irqs = 10,
5393
		.atu_move_port_mask = 0xf,
5394
		.pvt = true,
5395
		.multi_chip = true,
5396
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5397
		.ops = &mv88e6176_ops,
5398 5399 5400
	},

	[MV88E6185] = {
5401
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
5402 5403 5404
		.family = MV88E6XXX_FAMILY_6185,
		.name = "Marvell 88E6185",
		.num_databases = 256,
5405
		.num_macs = 8192,
5406
		.num_ports = 10,
5407
		.num_internal_phys = 0,
5408
		.max_vid = 4095,
5409
		.port_base_addr = 0x10,
5410
		.phy_base_addr = 0x0,
5411
		.global1_addr = 0x1b,
5412
		.global2_addr = 0x1c,
5413
		.age_time_coeff = 15000,
5414
		.g1_irqs = 8,
5415
		.atu_move_port_mask = 0xf,
5416
		.multi_chip = true,
5417
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5418
		.ops = &mv88e6185_ops,
5419 5420
	},

5421
	[MV88E6190] = {
5422
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
5423 5424 5425
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6190",
		.num_databases = 4096,
5426
		.num_macs = 16384,
5427
		.num_ports = 11,	/* 10 + Z80 */
5428
		.num_internal_phys = 9,
5429
		.num_gpio = 16,
5430
		.max_vid = 8191,
5431
		.port_base_addr = 0x0,
5432
		.phy_base_addr = 0x0,
5433
		.global1_addr = 0x1b,
5434
		.global2_addr = 0x1c,
5435
		.age_time_coeff = 3750,
5436
		.g1_irqs = 9,
5437
		.g2_irqs = 14,
5438
		.pvt = true,
5439
		.multi_chip = true,
5440
		.atu_move_port_mask = 0x1f,
5441 5442 5443 5444
		.ops = &mv88e6190_ops,
	},

	[MV88E6190X] = {
5445
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
5446 5447 5448
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6190X",
		.num_databases = 4096,
5449
		.num_macs = 16384,
5450
		.num_ports = 11,	/* 10 + Z80 */
5451
		.num_internal_phys = 9,
5452
		.num_gpio = 16,
5453
		.max_vid = 8191,
5454
		.port_base_addr = 0x0,
5455
		.phy_base_addr = 0x0,
5456
		.global1_addr = 0x1b,
5457
		.global2_addr = 0x1c,
5458
		.age_time_coeff = 3750,
5459
		.g1_irqs = 9,
5460
		.g2_irqs = 14,
5461
		.atu_move_port_mask = 0x1f,
5462
		.pvt = true,
5463
		.multi_chip = true,
5464 5465 5466 5467
		.ops = &mv88e6190x_ops,
	},

	[MV88E6191] = {
5468
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
5469 5470 5471
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6191",
		.num_databases = 4096,
5472
		.num_macs = 16384,
5473
		.num_ports = 11,	/* 10 + Z80 */
5474
		.num_internal_phys = 9,
5475
		.max_vid = 8191,
5476
		.port_base_addr = 0x0,
5477
		.phy_base_addr = 0x0,
5478
		.global1_addr = 0x1b,
5479
		.global2_addr = 0x1c,
5480
		.age_time_coeff = 3750,
5481
		.g1_irqs = 9,
5482
		.g2_irqs = 14,
5483
		.atu_move_port_mask = 0x1f,
5484
		.pvt = true,
5485
		.multi_chip = true,
5486
		.ptp_support = true,
5487
		.ops = &mv88e6191_ops,
5488 5489
	},

5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533
	[MV88E6191X] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
		.family = MV88E6XXX_FAMILY_6393,
		.name = "Marvell 88E6191X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.num_internal_phys = 9,
		.max_vid = 8191,
		.port_base_addr = 0x0,
		.phy_base_addr = 0x0,
		.global1_addr = 0x1b,
		.global2_addr = 0x1c,
		.age_time_coeff = 3750,
		.g1_irqs = 10,
		.g2_irqs = 14,
		.atu_move_port_mask = 0x1f,
		.pvt = true,
		.multi_chip = true,
		.ptp_support = true,
		.ops = &mv88e6393x_ops,
	},

	[MV88E6193X] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
		.family = MV88E6XXX_FAMILY_6393,
		.name = "Marvell 88E6193X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.num_internal_phys = 9,
		.max_vid = 8191,
		.port_base_addr = 0x0,
		.phy_base_addr = 0x0,
		.global1_addr = 0x1b,
		.global2_addr = 0x1c,
		.age_time_coeff = 3750,
		.g1_irqs = 10,
		.g2_irqs = 14,
		.atu_move_port_mask = 0x1f,
		.pvt = true,
		.multi_chip = true,
		.ptp_support = true,
		.ops = &mv88e6393x_ops,
	},

5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544
	[MV88E6220] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
		.family = MV88E6XXX_FAMILY_6250,
		.name = "Marvell 88E6220",
		.num_databases = 64,

		/* Ports 2-4 are not routed to pins
		 * => usable ports 0, 1, 5, 6
		 */
		.num_ports = 7,
		.num_internal_phys = 2,
5545
		.invalid_port_mask = BIT(2) | BIT(3) | BIT(4),
5546 5547 5548 5549 5550 5551 5552 5553 5554 5555
		.max_vid = 4095,
		.port_base_addr = 0x08,
		.phy_base_addr = 0x00,
		.global1_addr = 0x0f,
		.global2_addr = 0x07,
		.age_time_coeff = 15000,
		.g1_irqs = 9,
		.g2_irqs = 10,
		.atu_move_port_mask = 0xf,
		.dual_chip = true,
5556
		.ptp_support = true,
5557 5558 5559
		.ops = &mv88e6250_ops,
	},

5560
	[MV88E6240] = {
5561
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
5562 5563 5564
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6240",
		.num_databases = 4096,
5565
		.num_macs = 8192,
5566
		.num_ports = 7,
5567
		.num_internal_phys = 5,
5568
		.num_gpio = 15,
5569
		.max_vid = 4095,
5570
		.port_base_addr = 0x10,
5571
		.phy_base_addr = 0x0,
5572
		.global1_addr = 0x1b,
5573
		.global2_addr = 0x1c,
5574
		.age_time_coeff = 15000,
5575
		.g1_irqs = 9,
5576
		.g2_irqs = 10,
5577
		.atu_move_port_mask = 0xf,
5578
		.pvt = true,
5579
		.multi_chip = true,
5580
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5581
		.ptp_support = true,
5582
		.ops = &mv88e6240_ops,
5583 5584
	},

5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601
	[MV88E6250] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
		.family = MV88E6XXX_FAMILY_6250,
		.name = "Marvell 88E6250",
		.num_databases = 64,
		.num_ports = 7,
		.num_internal_phys = 5,
		.max_vid = 4095,
		.port_base_addr = 0x08,
		.phy_base_addr = 0x00,
		.global1_addr = 0x0f,
		.global2_addr = 0x07,
		.age_time_coeff = 15000,
		.g1_irqs = 9,
		.g2_irqs = 10,
		.atu_move_port_mask = 0xf,
		.dual_chip = true,
5602
		.ptp_support = true,
5603 5604 5605
		.ops = &mv88e6250_ops,
	},

5606
	[MV88E6290] = {
5607
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
5608 5609 5610 5611
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6290",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
5612
		.num_internal_phys = 9,
5613
		.num_gpio = 16,
5614
		.max_vid = 8191,
5615
		.port_base_addr = 0x0,
5616
		.phy_base_addr = 0x0,
5617
		.global1_addr = 0x1b,
5618
		.global2_addr = 0x1c,
5619
		.age_time_coeff = 3750,
5620
		.g1_irqs = 9,
5621
		.g2_irqs = 14,
5622
		.atu_move_port_mask = 0x1f,
5623
		.pvt = true,
5624
		.multi_chip = true,
5625
		.ptp_support = true,
5626 5627 5628
		.ops = &mv88e6290_ops,
	},

5629
	[MV88E6320] = {
5630
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
5631 5632 5633
		.family = MV88E6XXX_FAMILY_6320,
		.name = "Marvell 88E6320",
		.num_databases = 4096,
5634
		.num_macs = 8192,
5635
		.num_ports = 7,
5636
		.num_internal_phys = 5,
5637
		.num_gpio = 15,
5638
		.max_vid = 4095,
5639
		.port_base_addr = 0x10,
5640
		.phy_base_addr = 0x0,
5641
		.global1_addr = 0x1b,
5642
		.global2_addr = 0x1c,
5643
		.age_time_coeff = 15000,
5644
		.g1_irqs = 8,
5645
		.g2_irqs = 10,
5646
		.atu_move_port_mask = 0xf,
5647
		.pvt = true,
5648
		.multi_chip = true,
5649
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5650
		.ptp_support = true,
5651
		.ops = &mv88e6320_ops,
5652 5653 5654
	},

	[MV88E6321] = {
5655
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
5656 5657 5658
		.family = MV88E6XXX_FAMILY_6320,
		.name = "Marvell 88E6321",
		.num_databases = 4096,
5659
		.num_macs = 8192,
5660
		.num_ports = 7,
5661
		.num_internal_phys = 5,
5662
		.num_gpio = 15,
5663
		.max_vid = 4095,
5664
		.port_base_addr = 0x10,
5665
		.phy_base_addr = 0x0,
5666
		.global1_addr = 0x1b,
5667
		.global2_addr = 0x1c,
5668
		.age_time_coeff = 15000,
5669
		.g1_irqs = 8,
5670
		.g2_irqs = 10,
5671
		.atu_move_port_mask = 0xf,
5672
		.multi_chip = true,
5673
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5674
		.ptp_support = true,
5675
		.ops = &mv88e6321_ops,
5676 5677
	},

5678
	[MV88E6341] = {
5679
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
5680 5681 5682
		.family = MV88E6XXX_FAMILY_6341,
		.name = "Marvell 88E6341",
		.num_databases = 4096,
5683
		.num_macs = 2048,
5684
		.num_internal_phys = 5,
5685
		.num_ports = 6,
5686
		.num_gpio = 11,
5687
		.max_vid = 4095,
5688
		.port_base_addr = 0x10,
5689
		.phy_base_addr = 0x10,
5690
		.global1_addr = 0x1b,
5691
		.global2_addr = 0x1c,
5692
		.age_time_coeff = 3750,
5693
		.atu_move_port_mask = 0x1f,
5694
		.g1_irqs = 9,
5695
		.g2_irqs = 10,
5696
		.pvt = true,
5697
		.multi_chip = true,
5698
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5699
		.ptp_support = true,
5700 5701 5702
		.ops = &mv88e6341_ops,
	},

5703
	[MV88E6350] = {
5704
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
5705 5706 5707
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6350",
		.num_databases = 4096,
5708
		.num_macs = 8192,
5709
		.num_ports = 7,
5710
		.num_internal_phys = 5,
5711
		.max_vid = 4095,
5712
		.port_base_addr = 0x10,
5713
		.phy_base_addr = 0x0,
5714
		.global1_addr = 0x1b,
5715
		.global2_addr = 0x1c,
5716
		.age_time_coeff = 15000,
5717
		.g1_irqs = 9,
5718
		.g2_irqs = 10,
5719
		.atu_move_port_mask = 0xf,
5720
		.pvt = true,
5721
		.multi_chip = true,
5722
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5723
		.ops = &mv88e6350_ops,
5724 5725 5726
	},

	[MV88E6351] = {
5727
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
5728 5729 5730
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6351",
		.num_databases = 4096,
5731
		.num_macs = 8192,
5732
		.num_ports = 7,
5733
		.num_internal_phys = 5,
5734
		.max_vid = 4095,
5735
		.port_base_addr = 0x10,
5736
		.phy_base_addr = 0x0,
5737
		.global1_addr = 0x1b,
5738
		.global2_addr = 0x1c,
5739
		.age_time_coeff = 15000,
5740
		.g1_irqs = 9,
5741
		.g2_irqs = 10,
5742
		.atu_move_port_mask = 0xf,
5743
		.pvt = true,
5744
		.multi_chip = true,
5745
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5746
		.ops = &mv88e6351_ops,
5747 5748 5749
	},

	[MV88E6352] = {
5750
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
5751 5752 5753
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6352",
		.num_databases = 4096,
5754
		.num_macs = 8192,
5755
		.num_ports = 7,
5756
		.num_internal_phys = 5,
5757
		.num_gpio = 15,
5758
		.max_vid = 4095,
5759
		.port_base_addr = 0x10,
5760
		.phy_base_addr = 0x0,
5761
		.global1_addr = 0x1b,
5762
		.global2_addr = 0x1c,
5763
		.age_time_coeff = 15000,
5764
		.g1_irqs = 9,
5765
		.g2_irqs = 10,
5766
		.atu_move_port_mask = 0xf,
5767
		.pvt = true,
5768
		.multi_chip = true,
5769
		.edsa_support = MV88E6XXX_EDSA_SUPPORTED,
5770
		.ptp_support = true,
5771
		.ops = &mv88e6352_ops,
5772
	},
5773
	[MV88E6390] = {
5774
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
5775 5776 5777
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6390",
		.num_databases = 4096,
5778
		.num_macs = 16384,
5779
		.num_ports = 11,	/* 10 + Z80 */
5780
		.num_internal_phys = 9,
5781
		.num_gpio = 16,
5782
		.max_vid = 8191,
5783
		.port_base_addr = 0x0,
5784
		.phy_base_addr = 0x0,
5785
		.global1_addr = 0x1b,
5786
		.global2_addr = 0x1c,
5787
		.age_time_coeff = 3750,
5788
		.g1_irqs = 9,
5789
		.g2_irqs = 14,
5790
		.atu_move_port_mask = 0x1f,
5791
		.pvt = true,
5792
		.multi_chip = true,
5793
		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
5794
		.ptp_support = true,
5795 5796 5797
		.ops = &mv88e6390_ops,
	},
	[MV88E6390X] = {
5798
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
5799 5800 5801
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6390X",
		.num_databases = 4096,
5802
		.num_macs = 16384,
5803
		.num_ports = 11,	/* 10 + Z80 */
5804
		.num_internal_phys = 9,
5805
		.num_gpio = 16,
5806
		.max_vid = 8191,
5807
		.port_base_addr = 0x0,
5808
		.phy_base_addr = 0x0,
5809
		.global1_addr = 0x1b,
5810
		.global2_addr = 0x1c,
5811
		.age_time_coeff = 3750,
5812
		.g1_irqs = 9,
5813
		.g2_irqs = 14,
5814
		.atu_move_port_mask = 0x1f,
5815
		.pvt = true,
5816
		.multi_chip = true,
5817
		.edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED,
5818
		.ptp_support = true,
5819 5820
		.ops = &mv88e6390x_ops,
	},
5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842

	[MV88E6393X] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
		.family = MV88E6XXX_FAMILY_6393,
		.name = "Marvell 88E6393X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.num_internal_phys = 9,
		.max_vid = 8191,
		.port_base_addr = 0x0,
		.phy_base_addr = 0x0,
		.global1_addr = 0x1b,
		.global2_addr = 0x1c,
		.age_time_coeff = 3750,
		.g1_irqs = 10,
		.g2_irqs = 14,
		.atu_move_port_mask = 0x1f,
		.pvt = true,
		.multi_chip = true,
		.ptp_support = true,
		.ops = &mv88e6393x_ops,
	},
5843 5844
};

5845
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
5846
{
5847
	int i;
5848

5849 5850 5851
	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
		if (mv88e6xxx_table[i].prod_num == prod_num)
			return &mv88e6xxx_table[i];
5852 5853 5854 5855

	return NULL;
}

5856
static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
5857 5858
{
	const struct mv88e6xxx_info *info;
5859 5860 5861
	unsigned int prod_num, rev;
	u16 id;
	int err;
5862

5863
	mv88e6xxx_reg_lock(chip);
5864
	err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
5865
	mv88e6xxx_reg_unlock(chip);
5866 5867
	if (err)
		return err;
5868

5869 5870
	prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
	rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
5871 5872 5873 5874 5875

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

5876
	/* Update the compatible info with the probed one */
5877
	chip->info = info;
5878

5879 5880
	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
		 chip->info->prod_num, chip->info->name, rev);
5881 5882 5883 5884

	return 0;
}

5885
static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
5886
{
5887
	struct mv88e6xxx_chip *chip;
5888

5889 5890
	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
5891 5892
		return NULL;

5893
	chip->dev = dev;
5894

5895
	mutex_init(&chip->reg_lock);
5896
	INIT_LIST_HEAD(&chip->mdios);
5897
	idr_init(&chip->policies);
5898

5899
	return chip;
5900 5901
}

5902
static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
5903 5904
							int port,
							enum dsa_tag_protocol m)
5905
{
V
Vivien Didelot 已提交
5906
	struct mv88e6xxx_chip *chip = ds->priv;
5907

5908
	return chip->tag_protocol;
5909 5910
}

5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948
static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds, int port,
					 enum dsa_tag_protocol proto)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	enum dsa_tag_protocol old_protocol;
	int err;

	switch (proto) {
	case DSA_TAG_PROTO_EDSA:
		switch (chip->info->edsa_support) {
		case MV88E6XXX_EDSA_UNSUPPORTED:
			return -EPROTONOSUPPORT;
		case MV88E6XXX_EDSA_UNDOCUMENTED:
			dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n");
			fallthrough;
		case MV88E6XXX_EDSA_SUPPORTED:
			break;
		}
		break;
	case DSA_TAG_PROTO_DSA:
		break;
	default:
		return -EPROTONOSUPPORT;
	}

	old_protocol = chip->tag_protocol;
	chip->tag_protocol = proto;

	mv88e6xxx_reg_lock(chip);
	err = mv88e6xxx_setup_port_mode(chip, port);
	mv88e6xxx_reg_unlock(chip);

	if (err)
		chip->tag_protocol = old_protocol;

	return err;
}

5949 5950
static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
				  const struct switchdev_obj_port_mdb *mdb)
5951
{
V
Vivien Didelot 已提交
5952
	struct mv88e6xxx_chip *chip = ds->priv;
5953
	int err;
5954

5955
	mv88e6xxx_reg_lock(chip);
5956 5957
	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
					   MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC);
5958
	mv88e6xxx_reg_unlock(chip);
5959 5960

	return err;
5961 5962 5963 5964 5965
}

static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
				  const struct switchdev_obj_port_mdb *mdb)
{
V
Vivien Didelot 已提交
5966
	struct mv88e6xxx_chip *chip = ds->priv;
5967 5968
	int err;

5969
	mv88e6xxx_reg_lock(chip);
5970
	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
5971
	mv88e6xxx_reg_unlock(chip);
5972 5973 5974 5975

	return err;
}

5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001
static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
				     struct dsa_mall_mirror_tc_entry *mirror,
				     bool ingress)
{
	enum mv88e6xxx_egress_direction direction = ingress ?
						MV88E6XXX_EGRESS_DIR_INGRESS :
						MV88E6XXX_EGRESS_DIR_EGRESS;
	struct mv88e6xxx_chip *chip = ds->priv;
	bool other_mirrors = false;
	int i;
	int err;

	mutex_lock(&chip->reg_lock);
	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
	    mirror->to_local_port) {
		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
			other_mirrors |= ingress ?
					 chip->ports[i].mirror_ingress :
					 chip->ports[i].mirror_egress;

		/* Can't change egress port when other mirror is active */
		if (other_mirrors) {
			err = -EBUSY;
			goto out;
		}

6002 6003
		err = mv88e6xxx_set_egress_port(chip, direction,
						mirror->to_local_port);
6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035
		if (err)
			goto out;
	}

	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
out:
	mutex_unlock(&chip->reg_lock);

	return err;
}

static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
				      struct dsa_mall_mirror_tc_entry *mirror)
{
	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
						MV88E6XXX_EGRESS_DIR_INGRESS :
						MV88E6XXX_EGRESS_DIR_EGRESS;
	struct mv88e6xxx_chip *chip = ds->priv;
	bool other_mirrors = false;
	int i;

	mutex_lock(&chip->reg_lock);
	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);

	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
		other_mirrors |= mirror->ingress ?
				 chip->ports[i].mirror_ingress :
				 chip->ports[i].mirror_egress;

	/* Reset egress port when no other mirror is active */
	if (!other_mirrors) {
6036 6037
		if (mv88e6xxx_set_egress_port(chip, direction,
					      dsa_upstream_port(ds, port)))
6038 6039 6040 6041 6042 6043
			dev_err(ds->dev, "failed to set egress port\n");
	}

	mutex_unlock(&chip->reg_lock);
}

6044 6045 6046 6047 6048 6049 6050
static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
					   struct switchdev_brport_flags flags,
					   struct netlink_ext_ack *extack)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	const struct mv88e6xxx_ops *ops;

6051 6052
	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
			   BR_BCAST_FLOOD))
6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068
		return -EINVAL;

	ops = chip->info->ops;

	if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood)
		return -EINVAL;

	if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood)
		return -EINVAL;

	return 0;
}

static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
				       struct switchdev_brport_flags flags,
				       struct netlink_ext_ack *extack)
6069 6070 6071 6072
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err = -EOPNOTSUPP;

6073
	mv88e6xxx_reg_lock(chip);
6074

6075 6076 6077 6078 6079 6080 6081 6082 6083
	if (flags.mask & BR_LEARNING) {
		bool learning = !!(flags.val & BR_LEARNING);
		u16 pav = learning ? (1 << port) : 0;

		err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
		if (err)
			goto out;
	}

6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101
	if (flags.mask & BR_FLOOD) {
		bool unicast = !!(flags.val & BR_FLOOD);

		err = chip->info->ops->port_set_ucast_flood(chip, port,
							    unicast);
		if (err)
			goto out;
	}

	if (flags.mask & BR_MCAST_FLOOD) {
		bool multicast = !!(flags.val & BR_MCAST_FLOOD);

		err = chip->info->ops->port_set_mcast_flood(chip, port,
							    multicast);
		if (err)
			goto out;
	}

6102 6103 6104 6105 6106 6107 6108 6109
	if (flags.mask & BR_BCAST_FLOOD) {
		bool broadcast = !!(flags.val & BR_BCAST_FLOOD);

		err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast);
		if (err)
			goto out;
	}

6110 6111 6112 6113 6114 6115
out:
	mv88e6xxx_reg_unlock(chip);

	return err;
}

6116 6117 6118 6119
static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
				      struct net_device *lag,
				      struct netdev_lag_upper_info *info)
{
6120
	struct mv88e6xxx_chip *chip = ds->priv;
6121 6122 6123
	struct dsa_port *dp;
	int id, members = 0;

6124 6125 6126
	if (!mv88e6xxx_has_lag(chip))
		return false;

6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384
	id = dsa_lag_id(ds->dst, lag);
	if (id < 0 || id >= ds->num_lag_ids)
		return false;

	dsa_lag_foreach_port(dp, ds->dst, lag)
		/* Includes the port joining the LAG */
		members++;

	if (members > 8)
		return false;

	/* We could potentially relax this to include active
	 * backup in the future.
	 */
	if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
		return false;

	/* Ideally we would also validate that the hash type matches
	 * the hardware. Alas, this is always set to unknown on team
	 * interfaces.
	 */
	return true;
}

static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct net_device *lag)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	struct dsa_port *dp;
	u16 map = 0;
	int id;

	id = dsa_lag_id(ds->dst, lag);

	/* Build the map of all ports to distribute flows destined for
	 * this LAG. This can be either a local user port, or a DSA
	 * port if the LAG port is on a remote chip.
	 */
	dsa_lag_foreach_port(dp, ds->dst, lag)
		map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index));

	return mv88e6xxx_g2_trunk_mapping_write(chip, id, map);
}

static const u8 mv88e6xxx_lag_mask_table[8][8] = {
	/* Row number corresponds to the number of active members in a
	 * LAG. Each column states which of the eight hash buckets are
	 * mapped to the column:th port in the LAG.
	 *
	 * Example: In a LAG with three active ports, the second port
	 * ([2][1]) would be selected for traffic mapped to buckets
	 * 3,4,5 (0x38).
	 */
	{ 0xff,    0,    0,    0,    0,    0,    0,    0 },
	{ 0x0f, 0xf0,    0,    0,    0,    0,    0,    0 },
	{ 0x07, 0x38, 0xc0,    0,    0,    0,    0,    0 },
	{ 0x03, 0x0c, 0x30, 0xc0,    0,    0,    0,    0 },
	{ 0x03, 0x0c, 0x30, 0x40, 0x80,    0,    0,    0 },
	{ 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80,    0,    0 },
	{ 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,    0 },
	{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
};

static void mv88e6xxx_lag_set_port_mask(u16 *mask, int port,
					int num_tx, int nth)
{
	u8 active = 0;
	int i;

	num_tx = num_tx <= 8 ? num_tx : 8;
	if (nth < num_tx)
		active = mv88e6xxx_lag_mask_table[num_tx - 1][nth];

	for (i = 0; i < 8; i++) {
		if (BIT(i) & active)
			mask[i] |= BIT(port);
	}
}

static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	unsigned int id, num_tx;
	struct net_device *lag;
	struct dsa_port *dp;
	int i, err, nth;
	u16 mask[8];
	u16 ivec;

	/* Assume no port is a member of any LAG. */
	ivec = BIT(mv88e6xxx_num_ports(chip)) - 1;

	/* Disable all masks for ports that _are_ members of a LAG. */
	list_for_each_entry(dp, &ds->dst->ports, list) {
		if (!dp->lag_dev || dp->ds != ds)
			continue;

		ivec &= ~BIT(dp->index);
	}

	for (i = 0; i < 8; i++)
		mask[i] = ivec;

	/* Enable the correct subset of masks for all LAG ports that
	 * are in the Tx set.
	 */
	dsa_lags_foreach_id(id, ds->dst) {
		lag = dsa_lag_dev(ds->dst, id);
		if (!lag)
			continue;

		num_tx = 0;
		dsa_lag_foreach_port(dp, ds->dst, lag) {
			if (dp->lag_tx_enabled)
				num_tx++;
		}

		if (!num_tx)
			continue;

		nth = 0;
		dsa_lag_foreach_port(dp, ds->dst, lag) {
			if (!dp->lag_tx_enabled)
				continue;

			if (dp->ds == ds)
				mv88e6xxx_lag_set_port_mask(mask, dp->index,
							    num_tx, nth);

			nth++;
		}
	}

	for (i = 0; i < 8; i++) {
		err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]);
		if (err)
			return err;
	}

	return 0;
}

static int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds,
					struct net_device *lag)
{
	int err;

	err = mv88e6xxx_lag_sync_masks(ds);

	if (!err)
		err = mv88e6xxx_lag_sync_map(ds, lag);

	return err;
}

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

	mv88e6xxx_reg_lock(chip);
	err = mv88e6xxx_lag_sync_masks(ds);
	mv88e6xxx_reg_unlock(chip);
	return err;
}

static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
				   struct net_device *lag,
				   struct netdev_lag_upper_info *info)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err, id;

	if (!mv88e6xxx_lag_can_offload(ds, lag, info))
		return -EOPNOTSUPP;

	id = dsa_lag_id(ds->dst, lag);

	mv88e6xxx_reg_lock(chip);

	err = mv88e6xxx_port_set_trunk(chip, port, true, id);
	if (err)
		goto err_unlock;

	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
	if (err)
		goto err_clear_trunk;

	mv88e6xxx_reg_unlock(chip);
	return 0;

err_clear_trunk:
	mv88e6xxx_port_set_trunk(chip, port, false, 0);
err_unlock:
	mv88e6xxx_reg_unlock(chip);
	return err;
}

static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port,
				    struct net_device *lag)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err_sync, err_trunk;

	mv88e6xxx_reg_lock(chip);
	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
	err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0);
	mv88e6xxx_reg_unlock(chip);
	return err_sync ? : err_trunk;
}

static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,
					  int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

	mv88e6xxx_reg_lock(chip);
	err = mv88e6xxx_lag_sync_masks(ds);
	mv88e6xxx_reg_unlock(chip);
	return err;
}

static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index,
					int port, struct net_device *lag,
					struct netdev_lag_upper_info *info)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

	if (!mv88e6xxx_lag_can_offload(ds, lag, info))
		return -EOPNOTSUPP;

	mv88e6xxx_reg_lock(chip);

	err = mv88e6xxx_lag_sync_masks_map(ds, lag);
	if (err)
		goto unlock;

	err = mv88e6xxx_pvt_map(chip, sw_index, port);

unlock:
	mv88e6xxx_reg_unlock(chip);
	return err;
}

static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index,
					 int port, struct net_device *lag)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err_sync, err_pvt;

	mv88e6xxx_reg_lock(chip);
	err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
	err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port);
	mv88e6xxx_reg_unlock(chip);
	return err_sync ? : err_pvt;
}

6385
static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
6386
	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
6387
	.change_tag_protocol	= mv88e6xxx_change_tag_protocol,
6388
	.setup			= mv88e6xxx_setup,
6389
	.teardown		= mv88e6xxx_teardown,
6390 6391
	.port_setup		= mv88e6xxx_port_setup,
	.port_teardown		= mv88e6xxx_port_teardown,
6392
	.phylink_get_caps	= mv88e6xxx_get_caps,
6393
	.phylink_mac_link_state	= mv88e6xxx_serdes_pcs_get_state,
6394
	.phylink_mac_config	= mv88e6xxx_mac_config,
6395
	.phylink_mac_an_restart	= mv88e6xxx_serdes_pcs_an_restart,
6396 6397
	.phylink_mac_link_down	= mv88e6xxx_mac_link_down,
	.phylink_mac_link_up	= mv88e6xxx_mac_link_up,
6398 6399 6400
	.get_strings		= mv88e6xxx_get_strings,
	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
	.get_sset_count		= mv88e6xxx_get_sset_count,
6401 6402
	.port_enable		= mv88e6xxx_port_enable,
	.port_disable		= mv88e6xxx_port_disable,
6403 6404
	.port_max_mtu		= mv88e6xxx_get_max_mtu,
	.port_change_mtu	= mv88e6xxx_change_mtu,
V
Vivien Didelot 已提交
6405 6406
	.get_mac_eee		= mv88e6xxx_get_mac_eee,
	.set_mac_eee		= mv88e6xxx_set_mac_eee,
6407
	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
6408 6409 6410 6411
	.get_eeprom		= mv88e6xxx_get_eeprom,
	.set_eeprom		= mv88e6xxx_set_eeprom,
	.get_regs_len		= mv88e6xxx_get_regs_len,
	.get_regs		= mv88e6xxx_get_regs,
6412 6413
	.get_rxnfc		= mv88e6xxx_get_rxnfc,
	.set_rxnfc		= mv88e6xxx_set_rxnfc,
6414
	.set_ageing_time	= mv88e6xxx_set_ageing_time,
6415 6416
	.port_bridge_join	= mv88e6xxx_port_bridge_join,
	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
6417 6418
	.port_pre_bridge_flags	= mv88e6xxx_port_pre_bridge_flags,
	.port_bridge_flags	= mv88e6xxx_port_bridge_flags,
6419
	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
6420
	.port_fast_age		= mv88e6xxx_port_fast_age,
6421 6422 6423 6424 6425 6426
	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
	.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,
6427 6428
	.port_mdb_add           = mv88e6xxx_port_mdb_add,
	.port_mdb_del           = mv88e6xxx_port_mdb_del,
6429 6430
	.port_mirror_add	= mv88e6xxx_port_mirror_add,
	.port_mirror_del	= mv88e6xxx_port_mirror_del,
6431 6432
	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
6433 6434 6435 6436 6437
	.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,
6438 6439
	.devlink_param_get	= mv88e6xxx_devlink_param_get,
	.devlink_param_set	= mv88e6xxx_devlink_param_set,
6440
	.devlink_info_get	= mv88e6xxx_devlink_info_get,
6441 6442 6443 6444 6445 6446
	.port_lag_change	= mv88e6xxx_port_lag_change,
	.port_lag_join		= mv88e6xxx_port_lag_join,
	.port_lag_leave		= mv88e6xxx_port_lag_leave,
	.crosschip_lag_change	= mv88e6xxx_crosschip_lag_change,
	.crosschip_lag_join	= mv88e6xxx_crosschip_lag_join,
	.crosschip_lag_leave	= mv88e6xxx_crosschip_lag_leave,
6447 6448
};

6449
static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
6450
{
6451
	struct device *dev = chip->dev;
6452 6453
	struct dsa_switch *ds;

6454
	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
6455 6456 6457
	if (!ds)
		return -ENOMEM;

6458 6459
	ds->dev = dev;
	ds->num_ports = mv88e6xxx_num_ports(chip);
6460
	ds->priv = chip;
6461
	ds->dev = dev;
6462
	ds->ops = &mv88e6xxx_switch_ops;
6463 6464
	ds->ageing_time_min = chip->info->age_time_coeff;
	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
6465

6466 6467 6468 6469
	/* Some chips support up to 32, but that requires enabling the
	 * 5-bit port mode, which we do not support. 640k^W16 ought to
	 * be enough for anyone.
	 */
6470
	ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0;
6471

6472 6473
	dev_set_drvdata(dev, ds);

6474
	return dsa_register_switch(ds);
6475 6476
}

6477
static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
6478
{
6479
	dsa_unregister_switch(chip->ds);
6480 6481
}

6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494
static const void *pdata_device_get_match_data(struct device *dev)
{
	const struct of_device_id *matches = dev->driver->of_match_table;
	const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data;

	for (; matches->name[0] || matches->type[0] || matches->compatible[0];
	     matches++) {
		if (!strcmp(pdata->compatible, matches->compatible))
			return matches->data;
	}
	return NULL;
}

6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509
/* There is no suspend to RAM support at DSA level yet, the switch configuration
 * would be lost after a power cycle so prevent it to be suspended.
 */
static int __maybe_unused mv88e6xxx_suspend(struct device *dev)
{
	return -EOPNOTSUPP;
}

static int __maybe_unused mv88e6xxx_resume(struct device *dev)
{
	return 0;
}

static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume);

6510
static int mv88e6xxx_probe(struct mdio_device *mdiodev)
6511
{
6512
	struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data;
6513
	const struct mv88e6xxx_info *compat_info = NULL;
6514
	struct device *dev = &mdiodev->dev;
6515
	struct device_node *np = dev->of_node;
6516
	struct mv88e6xxx_chip *chip;
6517
	int port;
6518
	int err;
6519

6520 6521 6522
	if (!np && !pdata)
		return -EINVAL;

6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541
	if (np)
		compat_info = of_device_get_match_data(dev);

	if (pdata) {
		compat_info = pdata_device_get_match_data(dev);

		if (!pdata->netdev)
			return -EINVAL;

		for (port = 0; port < DSA_MAX_PORTS; port++) {
			if (!(pdata->enabled_ports & (1 << port)))
				continue;
			if (strcmp(pdata->cd.port_names[port], "cpu"))
				continue;
			pdata->cd.netdev[port] = &pdata->netdev->dev;
			break;
		}
	}

6542 6543 6544
	if (!compat_info)
		return -EINVAL;

6545
	chip = mv88e6xxx_alloc_chip(dev);
6546 6547 6548 6549
	if (!chip) {
		err = -ENOMEM;
		goto out;
	}
6550

6551
	chip->info = compat_info;
6552

6553
	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
6554
	if (err)
6555
		goto out;
6556

6557
	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
6558 6559 6560 6561
	if (IS_ERR(chip->reset)) {
		err = PTR_ERR(chip->reset);
		goto out;
	}
6562 6563
	if (chip->reset)
		usleep_range(1000, 2000);
6564

6565
	err = mv88e6xxx_detect(chip);
6566
	if (err)
6567
		goto out;
6568

6569 6570 6571 6572 6573
	if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED)
		chip->tag_protocol = DSA_TAG_PROTO_EDSA;
	else
		chip->tag_protocol = DSA_TAG_PROTO_DSA;

6574 6575
	mv88e6xxx_phy_init(chip);

6576 6577 6578 6579 6580 6581 6582
	if (chip->info->ops->get_eeprom) {
		if (np)
			of_property_read_u32(np, "eeprom-length",
					     &chip->eeprom_len);
		else
			chip->eeprom_len = pdata->eeprom_len;
	}
6583

6584
	mv88e6xxx_reg_lock(chip);
6585
	err = mv88e6xxx_switch_reset(chip);
6586
	mv88e6xxx_reg_unlock(chip);
6587 6588 6589
	if (err)
		goto out;

6590 6591 6592 6593 6594 6595
	if (np) {
		chip->irq = of_irq_get(np, 0);
		if (chip->irq == -EPROBE_DEFER) {
			err = chip->irq;
			goto out;
		}
6596 6597
	}

6598 6599 6600
	if (pdata)
		chip->irq = pdata->irq;

6601
	/* Has to be performed before the MDIO bus is created, because
6602
	 * the PHYs will link their interrupts to these interrupt
6603 6604
	 * controllers
	 */
6605
	mv88e6xxx_reg_lock(chip);
6606
	if (chip->irq > 0)
6607
		err = mv88e6xxx_g1_irq_setup(chip);
6608 6609
	else
		err = mv88e6xxx_irq_poll_setup(chip);
6610
	mv88e6xxx_reg_unlock(chip);
6611

6612 6613
	if (err)
		goto out;
6614

6615 6616
	if (chip->info->g2_irqs > 0) {
		err = mv88e6xxx_g2_irq_setup(chip);
6617
		if (err)
6618
			goto out_g1_irq;
6619 6620
	}

6621 6622 6623 6624 6625 6626 6627 6628
	err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
	if (err)
		goto out_g2_irq;

	err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
	if (err)
		goto out_g1_atu_prob_irq;

6629
	err = mv88e6xxx_mdios_register(chip, np);
6630
	if (err)
6631
		goto out_g1_vtu_prob_irq;
6632

6633
	err = mv88e6xxx_register_switch(chip);
6634 6635
	if (err)
		goto out_mdio;
6636

6637
	return 0;
6638 6639

out_mdio:
6640
	mv88e6xxx_mdios_unregister(chip);
6641
out_g1_vtu_prob_irq:
6642
	mv88e6xxx_g1_vtu_prob_irq_free(chip);
6643
out_g1_atu_prob_irq:
6644
	mv88e6xxx_g1_atu_prob_irq_free(chip);
6645
out_g2_irq:
6646
	if (chip->info->g2_irqs > 0)
6647 6648
		mv88e6xxx_g2_irq_free(chip);
out_g1_irq:
6649
	if (chip->irq > 0)
6650
		mv88e6xxx_g1_irq_free(chip);
6651 6652
	else
		mv88e6xxx_irq_poll_free(chip);
6653
out:
6654 6655 6656
	if (pdata)
		dev_put(pdata->netdev);

6657
	return err;
6658
}
6659 6660 6661 6662

static void mv88e6xxx_remove(struct mdio_device *mdiodev)
{
	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
6663 6664 6665 6666 6667 6668
	struct mv88e6xxx_chip *chip;

	if (!ds)
		return;

	chip = ds->priv;
6669

6670 6671
	if (chip->info->ptp_support) {
		mv88e6xxx_hwtstamp_free(chip);
6672
		mv88e6xxx_ptp_free(chip);
6673
	}
6674

6675
	mv88e6xxx_phy_destroy(chip);
6676
	mv88e6xxx_unregister_switch(chip);
6677
	mv88e6xxx_mdios_unregister(chip);
6678

6679 6680 6681 6682 6683 6684 6685
	mv88e6xxx_g1_vtu_prob_irq_free(chip);
	mv88e6xxx_g1_atu_prob_irq_free(chip);

	if (chip->info->g2_irqs > 0)
		mv88e6xxx_g2_irq_free(chip);

	if (chip->irq > 0)
6686
		mv88e6xxx_g1_irq_free(chip);
6687 6688
	else
		mv88e6xxx_irq_poll_free(chip);
6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702

	dev_set_drvdata(&mdiodev->dev, NULL);
}

static void mv88e6xxx_shutdown(struct mdio_device *mdiodev)
{
	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);

	if (!ds)
		return;

	dsa_switch_shutdown(ds);

	dev_set_drvdata(&mdiodev->dev, NULL);
6703 6704 6705
}

static const struct of_device_id mv88e6xxx_of_match[] = {
6706 6707 6708 6709
	{
		.compatible = "marvell,mv88e6085",
		.data = &mv88e6xxx_table[MV88E6085],
	},
6710 6711 6712 6713
	{
		.compatible = "marvell,mv88e6190",
		.data = &mv88e6xxx_table[MV88E6190],
	},
6714 6715 6716 6717
	{
		.compatible = "marvell,mv88e6250",
		.data = &mv88e6xxx_table[MV88E6250],
	},
6718 6719 6720 6721 6722 6723 6724 6725
	{ /* sentinel */ },
};

MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);

static struct mdio_driver mv88e6xxx_driver = {
	.probe	= mv88e6xxx_probe,
	.remove = mv88e6xxx_remove,
6726
	.shutdown = mv88e6xxx_shutdown,
6727 6728 6729
	.mdiodrv.driver = {
		.name = "mv88e6085",
		.of_match_table = mv88e6xxx_of_match,
6730
		.pm = &mv88e6xxx_pm_ops,
6731 6732 6733
	},
};

6734
mdio_module_driver(mv88e6xxx_driver);
6735 6736 6737 6738

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