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

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

40
#include "mv88e6xxx.h"
41
#include "global1.h"
42
#include "global2.h"
43
#include "port.h"
44

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

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

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

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

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

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

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

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

	*val = ret & 0xffff;

	return 0;
}

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

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

	return 0;
}

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

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

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

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

	return -ETIMEDOUT;
}

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

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

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

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

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

157
	*val = ret & 0xffff;
158

159
	return 0;
160 161
}

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

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

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

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

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

	return 0;
}

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

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

200
	assert_reg_lock(chip);
201

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

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

	return 0;
}

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

216
	assert_reg_lock(chip);
217

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

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

225 226 227
	return 0;
}

228 229 230
static int mv88e6165_phy_read(struct mv88e6xxx_chip *chip,
			      struct mii_bus *bus,
			      int addr, int reg, u16 *val)
231 232 233 234
{
	return mv88e6xxx_read(chip, addr, reg, val);
}

235 236 237
static int mv88e6165_phy_write(struct mv88e6xxx_chip *chip,
			       struct mii_bus *bus,
			       int addr, int reg, u16 val)
238 239 240 241
{
	return mv88e6xxx_write(chip, addr, reg, val);
}

242 243 244 245 246 247 248 249 250 251 252 253
static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
{
	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;
}

254 255 256 257
static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
			      int reg, u16 *val)
{
	int addr = phy; /* PHY devices addresses start at 0x0 */
258
	struct mii_bus *bus;
259

260 261
	bus = mv88e6xxx_default_mdio_bus(chip);
	if (!bus)
262 263
		return -EOPNOTSUPP;

264
	if (!chip->info->ops->phy_read)
265 266 267
		return -EOPNOTSUPP;

	return chip->info->ops->phy_read(chip, bus, addr, reg, val);
268 269 270 271 272 273
}

static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
			       int reg, u16 val)
{
	int addr = phy; /* PHY devices addresses start at 0x0 */
274
	struct mii_bus *bus;
275

276 277
	bus = mv88e6xxx_default_mdio_bus(chip);
	if (!bus)
278 279
		return -EOPNOTSUPP;

280
	if (!chip->info->ops->phy_write)
281 282 283
		return -EOPNOTSUPP;

	return chip->info->ops->phy_write(chip, bus, addr, reg, val);
284 285
}

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
{
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
		return -EOPNOTSUPP;

	return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
}

static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
{
	int err;

	/* Restore PHY page Copper 0x0 for access via the registered MDIO bus */
	err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
	if (unlikely(err)) {
		dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n",
			phy, err);
	}
}

static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
				   u8 page, int reg, u16 *val)
{
	int err;

	/* There is no paging for registers 22 */
	if (reg == PHY_PAGE)
		return -EINVAL;

	err = mv88e6xxx_phy_page_get(chip, phy, page);
	if (!err) {
		err = mv88e6xxx_phy_read(chip, phy, reg, val);
		mv88e6xxx_phy_page_put(chip, phy);
	}

	return err;
}

static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
				    u8 page, int reg, u16 val)
{
	int err;

	/* There is no paging for registers 22 */
	if (reg == PHY_PAGE)
		return -EINVAL;

	err = mv88e6xxx_phy_page_get(chip, phy, page);
	if (!err) {
		err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
		mv88e6xxx_phy_page_put(chip, phy);
	}

	return err;
}

static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
{
	return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
				       reg, val);
}

static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
{
	return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
					reg, val);
}

354 355 356 357 358 359 360 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 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
{
	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
	unsigned int n = d->hwirq;

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

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

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

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

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &reg);
	mutex_unlock(&chip->reg_lock);

	if (err)
		goto out;

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

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

	mutex_lock(&chip->reg_lock);
}

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

	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &reg);
	if (err)
		goto out;

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

	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg);
	if (err)
		goto out;

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

static struct irq_chip mv88e6xxx_g1_irq_chip = {
	.name			= "mv88e6xxx-g1",
	.irq_mask		= mv88e6xxx_g1_irq_mask,
	.irq_unmask		= mv88e6xxx_g1_irq_unmask,
	.irq_bus_lock		= mv88e6xxx_g1_irq_bus_lock,
	.irq_bus_sync_unlock	= mv88e6xxx_g1_irq_bus_sync_unlock,
};

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

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

	return 0;
}

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

static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
{
	int irq, virq;
455 456 457 458 459 460 461
	u16 mask;

	mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask);
	mask |= GENMASK(chip->g1_irq.nirqs, 0);
	mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);

	free_irq(chip->irq, chip);
462

463
	for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
464
		virq = irq_find_mapping(chip->g1_irq.domain, irq);
465 466 467
		irq_dispose_mapping(virq);
	}

468
	irq_domain_remove(chip->g1_irq.domain);
469 470 471 472
}

static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
{
473 474
	int err, irq, virq;
	u16 reg, mask;
475 476 477 478 479 480 481 482 483 484 485 486 487 488

	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;

489
	err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask);
490
	if (err)
491
		goto out_mapping;
492

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

495
	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);
496
	if (err)
497
		goto out_disable;
498 499 500 501

	/* Reading the interrupt status clears (most of) them */
	err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &reg);
	if (err)
502
		goto out_disable;
503 504 505 506 507 508

	err = request_threaded_irq(chip->irq, NULL,
				   mv88e6xxx_g1_irq_thread_fn,
				   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
				   dev_name(chip->dev), chip);
	if (err)
509
		goto out_disable;
510 511 512

	return 0;

513 514 515 516 517 518 519 520 521 522 523
out_disable:
	mask |= GENMASK(chip->g1_irq.nirqs, 0);
	mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask);

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);
524 525 526 527

	return err;
}

528
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
529
{
530
	int i;
531

532
	for (i = 0; i < 16; i++) {
533 534 535 536 537 538 539 540 541 542 543 544 545
		u16 val;
		int err;

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

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

		usleep_range(1000, 2000);
	}

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

550
/* Indirect write to single pointer-data register with an Update bit */
551
int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
552 553
{
	u16 val;
554
	int err;
555 556

	/* Wait until the previous operation is completed */
557 558 559
	err = mv88e6xxx_wait(chip, addr, reg, BIT(15));
	if (err)
		return err;
560 561 562 563 564 565 566

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

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

567
static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
568
{
569 570
	if (!chip->info->ops->ppu_disable)
		return 0;
571

572
	return chip->info->ops->ppu_disable(chip);
573 574
}

575
static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
576
{
577 578
	if (!chip->info->ops->ppu_enable)
		return 0;
579

580
	return chip->info->ops->ppu_enable(chip);
581 582 583 584
}

static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
{
585
	struct mv88e6xxx_chip *chip;
586

587
	chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
588

589
	mutex_lock(&chip->reg_lock);
590

591 592 593 594
	if (mutex_trylock(&chip->ppu_mutex)) {
		if (mv88e6xxx_ppu_enable(chip) == 0)
			chip->ppu_disabled = 0;
		mutex_unlock(&chip->ppu_mutex);
595
	}
596

597
	mutex_unlock(&chip->reg_lock);
598 599 600 601
}

static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
{
602
	struct mv88e6xxx_chip *chip = (void *)_ps;
603

604
	schedule_work(&chip->ppu_work);
605 606
}

607
static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip)
608 609 610
{
	int ret;

611
	mutex_lock(&chip->ppu_mutex);
612

613
	/* If the PHY polling unit is enabled, disable it so that
614 615 616 617
	 * we can access the PHY registers.  If it was already
	 * disabled, cancel the timer that is going to re-enable
	 * it.
	 */
618 619
	if (!chip->ppu_disabled) {
		ret = mv88e6xxx_ppu_disable(chip);
620
		if (ret < 0) {
621
			mutex_unlock(&chip->ppu_mutex);
622 623
			return ret;
		}
624
		chip->ppu_disabled = 1;
625
	} else {
626
		del_timer(&chip->ppu_timer);
627
		ret = 0;
628 629 630 631 632
	}

	return ret;
}

633
static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip)
634
{
635
	/* Schedule a timer to re-enable the PHY polling unit. */
636 637
	mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
	mutex_unlock(&chip->ppu_mutex);
638 639
}

640
static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
641
{
642 643
	mutex_init(&chip->ppu_mutex);
	INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work);
644 645
	setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer,
		    (unsigned long)chip);
646 647
}

648 649 650 651 652
static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip)
{
	del_timer_sync(&chip->ppu_timer);
}

653 654 655
static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip,
				  struct mii_bus *bus,
				  int addr, int reg, u16 *val)
656
{
657
	int err;
658

659 660 661
	err = mv88e6xxx_ppu_access_get(chip);
	if (!err) {
		err = mv88e6xxx_read(chip, addr, reg, val);
662
		mv88e6xxx_ppu_access_put(chip);
663 664
	}

665
	return err;
666 667
}

668 669 670
static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip,
				   struct mii_bus *bus,
				   int addr, int reg, u16 val)
671
{
672
	int err;
673

674 675 676
	err = mv88e6xxx_ppu_access_get(chip);
	if (!err) {
		err = mv88e6xxx_write(chip, addr, reg, val);
677
		mv88e6xxx_ppu_access_put(chip);
678 679
	}

680
	return err;
681 682
}

683
static bool mv88e6xxx_6097_family(struct mv88e6xxx_chip *chip)
684
{
685
	return chip->info->family == MV88E6XXX_FAMILY_6097;
686 687
}

688
static bool mv88e6xxx_6165_family(struct mv88e6xxx_chip *chip)
689
{
690
	return chip->info->family == MV88E6XXX_FAMILY_6165;
691 692
}

693 694 695 696 697
static bool mv88e6xxx_6341_family(struct mv88e6xxx_chip *chip)
{
	return chip->info->family == MV88E6XXX_FAMILY_6341;
}

698
static bool mv88e6xxx_6351_family(struct mv88e6xxx_chip *chip)
699
{
700
	return chip->info->family == MV88E6XXX_FAMILY_6351;
701 702
}

703
static bool mv88e6xxx_6352_family(struct mv88e6xxx_chip *chip)
704
{
705
	return chip->info->family == MV88E6XXX_FAMILY_6352;
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
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
				    int link, int speed, int duplex,
				    phy_interface_t mode)
{
	int err;

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

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

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

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

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

740 741 742 743 744 745
	if (chip->info->ops->port_set_cmode) {
		err = chip->info->ops->port_set_cmode(chip, port, mode);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

746 747 748 749 750 751 752 753 754
	err = 0;
restore_link:
	if (chip->info->ops->port_set_link(chip, port, link))
		netdev_err(chip->ds->ports[port].netdev,
			   "failed to restore MAC's link\n");

	return err;
}

755 756 757 758
/* We expect the switch to perform auto negotiation if there is a real
 * phy. However, in the case of a fixed link phy, we force the port
 * settings from the fixed link settings.
 */
759 760
static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
				  struct phy_device *phydev)
761
{
V
Vivien Didelot 已提交
762
	struct mv88e6xxx_chip *chip = ds->priv;
763
	int err;
764 765 766 767

	if (!phy_is_pseudo_fixed_link(phydev))
		return;

768
	mutex_lock(&chip->reg_lock);
769 770
	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
				       phydev->duplex, phydev->interface);
771
	mutex_unlock(&chip->reg_lock);
772 773 774

	if (err && err != -EOPNOTSUPP)
		netdev_err(ds->ports[port].netdev, "failed to configure MAC\n");
775 776
}

777
static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
778
{
779 780
	if (!chip->info->ops->stats_snapshot)
		return -EOPNOTSUPP;
781

782
	return chip->info->ops->stats_snapshot(chip, port);
783 784
}

785
static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
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 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
	{ "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, },
845 846
};

847
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
848
					    struct mv88e6xxx_hw_stat *s,
849 850
					    int port, u16 bank1_select,
					    u16 histogram)
851 852 853
{
	u32 low;
	u32 high = 0;
854
	u16 reg = 0;
855
	int err;
856 857
	u64 value;

858
	switch (s->type) {
859
	case STATS_TYPE_PORT:
860 861
		err = mv88e6xxx_port_read(chip, port, s->reg, &reg);
		if (err)
862 863
			return UINT64_MAX;

864
		low = reg;
865
		if (s->sizeof_stat == 4) {
866 867
			err = mv88e6xxx_port_read(chip, port, s->reg + 1, &reg);
			if (err)
868
				return UINT64_MAX;
869
			high = reg;
870
		}
871
		break;
872
	case STATS_TYPE_BANK1:
873
		reg = bank1_select;
874 875
		/* fall through */
	case STATS_TYPE_BANK0:
876
		reg |= s->reg | histogram;
877
		mv88e6xxx_g1_stats_read(chip, reg, &low);
878
		if (s->sizeof_stat == 8)
879
			mv88e6xxx_g1_stats_read(chip, reg + 1, &high);
880 881 882 883 884
	}
	value = (((u64)high) << 16) | low;
	return value;
}

885 886
static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
					uint8_t *data, int types)
887
{
888 889
	struct mv88e6xxx_hw_stat *stat;
	int i, j;
890

891 892
	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
		stat = &mv88e6xxx_hw_stats[i];
893
		if (stat->type & types) {
894 895 896 897
			memcpy(data + j * ETH_GSTRING_LEN, stat->string,
			       ETH_GSTRING_LEN);
			j++;
		}
898
	}
899 900
}

901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
					uint8_t *data)
{
	mv88e6xxx_stats_get_strings(chip, data,
				    STATS_TYPE_BANK0 | STATS_TYPE_PORT);
}

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

static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
				  uint8_t *data)
917
{
V
Vivien Didelot 已提交
918
	struct mv88e6xxx_chip *chip = ds->priv;
919 920 921 922 923 924 925 926

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

static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
					  int types)
{
927 928 929 930 931
	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];
932
		if (stat->type & types)
933 934 935
			j++;
	}
	return j;
936 937
}

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
	return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
					      STATS_TYPE_PORT);
}

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

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

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

	return 0;
}

960
static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
961 962
				      uint64_t *data, int types,
				      u16 bank1_select, u16 histogram)
963 964 965 966 967 968 969
{
	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) {
970 971 972
			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
							      bank1_select,
							      histogram);
973 974 975 976 977 978 979 980 981
			j++;
		}
	}
}

static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				      uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
982 983
					 STATS_TYPE_BANK0 | STATS_TYPE_PORT,
					 0, GLOBAL_STATS_OP_HIST_RX_TX);
984 985 986 987 988 989
}

static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				      uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
990 991 992 993 994 995 996 997 998 999 1000
					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
					 GLOBAL_STATS_OP_BANK_1_BIT_9,
					 GLOBAL_STATS_OP_HIST_RX_TX);
}

static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
				      uint64_t *data)
{
	return mv88e6xxx_stats_get_stats(chip, port, data,
					 STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
					 GLOBAL_STATS_OP_BANK_1_BIT_10, 0);
1001 1002 1003 1004 1005 1006 1007 1008 1009
}

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

1010 1011
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
					uint64_t *data)
1012
{
V
Vivien Didelot 已提交
1013
	struct mv88e6xxx_chip *chip = ds->priv;
1014 1015
	int ret;

1016
	mutex_lock(&chip->reg_lock);
1017

1018
	ret = mv88e6xxx_stats_snapshot(chip, port);
1019
	if (ret < 0) {
1020
		mutex_unlock(&chip->reg_lock);
1021 1022
		return;
	}
1023 1024

	mv88e6xxx_get_stats(chip, port, data);
1025

1026
	mutex_unlock(&chip->reg_lock);
1027 1028
}

1029 1030 1031 1032 1033 1034 1035 1036
static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->stats_set_histogram)
		return chip->info->ops->stats_set_histogram(chip);

	return 0;
}

1037
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
1038 1039 1040 1041
{
	return 32 * sizeof(u16);
}

1042 1043
static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
			       struct ethtool_regs *regs, void *_p)
1044
{
V
Vivien Didelot 已提交
1045
	struct mv88e6xxx_chip *chip = ds->priv;
1046 1047
	int err;
	u16 reg;
1048 1049 1050 1051 1052 1053 1054
	u16 *p = _p;
	int i;

	regs->version = 0;

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

1055
	mutex_lock(&chip->reg_lock);
1056

1057 1058
	for (i = 0; i < 32; i++) {

1059 1060 1061
		err = mv88e6xxx_port_read(chip, port, i, &reg);
		if (!err)
			p[i] = reg;
1062
	}
1063

1064
	mutex_unlock(&chip->reg_lock);
1065 1066
}

1067 1068
static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port,
			     struct ethtool_eee *e)
1069
{
V
Vivien Didelot 已提交
1070
	struct mv88e6xxx_chip *chip = ds->priv;
1071 1072
	u16 reg;
	int err;
1073

1074
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
1075 1076
		return -EOPNOTSUPP;

1077
	mutex_lock(&chip->reg_lock);
1078

1079 1080
	err = mv88e6xxx_phy_read(chip, port, 16, &reg);
	if (err)
1081
		goto out;
1082 1083 1084 1085

	e->eee_enabled = !!(reg & 0x0200);
	e->tx_lpi_enabled = !!(reg & 0x0100);

1086
	err = mv88e6xxx_port_read(chip, port, PORT_STATUS, &reg);
1087
	if (err)
1088
		goto out;
1089

1090
	e->eee_active = !!(reg & PORT_STATUS_EEE);
1091
out:
1092
	mutex_unlock(&chip->reg_lock);
1093 1094

	return err;
1095 1096
}

1097 1098
static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
			     struct phy_device *phydev, struct ethtool_eee *e)
1099
{
V
Vivien Didelot 已提交
1100
	struct mv88e6xxx_chip *chip = ds->priv;
1101 1102
	u16 reg;
	int err;
1103

1104
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEE))
1105 1106
		return -EOPNOTSUPP;

1107
	mutex_lock(&chip->reg_lock);
1108

1109 1110
	err = mv88e6xxx_phy_read(chip, port, 16, &reg);
	if (err)
1111 1112
		goto out;

1113
	reg &= ~0x0300;
1114 1115 1116 1117 1118
	if (e->eee_enabled)
		reg |= 0x0200;
	if (e->tx_lpi_enabled)
		reg |= 0x0100;

1119
	err = mv88e6xxx_phy_write(chip, port, 16, reg);
1120
out:
1121
	mutex_unlock(&chip->reg_lock);
1122

1123
	return err;
1124 1125
}

1126
static int _mv88e6xxx_port_based_vlan_map(struct mv88e6xxx_chip *chip, int port)
1127
{
1128
	struct dsa_switch *ds = chip->ds;
1129
	struct net_device *bridge = ds->ports[port].bridge_dev;
1130 1131 1132 1133 1134
	u16 output_ports = 0;
	int i;

	/* allow CPU port or DSA link(s) to send frames to every port */
	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
1135
		output_ports = ~0;
1136
	} else {
1137
		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1138
			/* allow sending frames to every group member */
1139
			if (bridge && ds->ports[i].bridge_dev == bridge)
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
				output_ports |= BIT(i);

			/* allow sending frames to CPU port and DSA link(s) */
			if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
				output_ports |= BIT(i);
		}
	}

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

1151
	return mv88e6xxx_port_set_vlan_map(chip, port, output_ports);
1152 1153
}

1154 1155
static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
					 u8 state)
1156
{
V
Vivien Didelot 已提交
1157
	struct mv88e6xxx_chip *chip = ds->priv;
1158
	int stp_state;
1159
	int err;
1160 1161 1162

	switch (state) {
	case BR_STATE_DISABLED:
1163
		stp_state = PORT_CONTROL_STATE_DISABLED;
1164 1165 1166
		break;
	case BR_STATE_BLOCKING:
	case BR_STATE_LISTENING:
1167
		stp_state = PORT_CONTROL_STATE_BLOCKING;
1168 1169
		break;
	case BR_STATE_LEARNING:
1170
		stp_state = PORT_CONTROL_STATE_LEARNING;
1171 1172 1173
		break;
	case BR_STATE_FORWARDING:
	default:
1174
		stp_state = PORT_CONTROL_STATE_FORWARDING;
1175 1176 1177
		break;
	}

1178
	mutex_lock(&chip->reg_lock);
1179
	err = mv88e6xxx_port_set_state(chip, port, stp_state);
1180
	mutex_unlock(&chip->reg_lock);
1181 1182

	if (err)
1183
		netdev_err(ds->ports[port].netdev, "failed to update state\n");
1184 1185
}

1186 1187
static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip)
{
1188 1189
	int err;

1190 1191 1192 1193
	err = mv88e6xxx_g1_atu_flush(chip, 0, true);
	if (err)
		return err;

1194 1195 1196 1197
	err = mv88e6xxx_g1_atu_set_learn2all(chip, true);
	if (err)
		return err;

1198 1199 1200
	return mv88e6xxx_g1_atu_set_age_time(chip, 300000);
}

1201 1202 1203 1204 1205 1206
static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

	mutex_lock(&chip->reg_lock);
1207
	err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
1208 1209 1210 1211 1212 1213
	mutex_unlock(&chip->reg_lock);

	if (err)
		netdev_err(ds->ports[port].netdev, "failed to flush ATU\n");
}

1214
static int _mv88e6xxx_vtu_wait(struct mv88e6xxx_chip *chip)
1215
{
1216
	return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY);
1217 1218
}

1219
static int _mv88e6xxx_vtu_cmd(struct mv88e6xxx_chip *chip, u16 op)
1220
{
1221
	int err;
1222

1223 1224 1225
	err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op);
	if (err)
		return err;
1226

1227
	return _mv88e6xxx_vtu_wait(chip);
1228 1229
}

1230
static int _mv88e6xxx_vtu_stu_flush(struct mv88e6xxx_chip *chip)
1231 1232 1233
{
	int ret;

1234
	ret = _mv88e6xxx_vtu_wait(chip);
1235 1236 1237
	if (ret < 0)
		return ret;

1238
	return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_FLUSH_ALL);
1239 1240
}

1241
static int _mv88e6xxx_vtu_stu_data_read(struct mv88e6xxx_chip *chip,
1242
					struct mv88e6xxx_vtu_entry *entry,
1243 1244 1245
					unsigned int nibble_offset)
{
	u16 regs[3];
1246
	int i, err;
1247 1248

	for (i = 0; i < 3; ++i) {
1249
		u16 *reg = &regs[i];
1250

1251 1252 1253
		err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
		if (err)
			return err;
1254 1255
	}

1256
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1257 1258 1259 1260 1261 1262 1263 1264 1265
		unsigned int shift = (i % 4) * 4 + nibble_offset;
		u16 reg = regs[i / 4];

		entry->data[i] = (reg >> shift) & GLOBAL_VTU_STU_DATA_MASK;
	}

	return 0;
}

1266
static int mv88e6xxx_vtu_data_read(struct mv88e6xxx_chip *chip,
1267
				   struct mv88e6xxx_vtu_entry *entry)
1268
{
1269
	return _mv88e6xxx_vtu_stu_data_read(chip, entry, 0);
1270 1271
}

1272
static int mv88e6xxx_stu_data_read(struct mv88e6xxx_chip *chip,
1273
				   struct mv88e6xxx_vtu_entry *entry)
1274
{
1275
	return _mv88e6xxx_vtu_stu_data_read(chip, entry, 2);
1276 1277
}

1278
static int _mv88e6xxx_vtu_stu_data_write(struct mv88e6xxx_chip *chip,
1279
					 struct mv88e6xxx_vtu_entry *entry,
1280 1281 1282
					 unsigned int nibble_offset)
{
	u16 regs[3] = { 0 };
1283
	int i, err;
1284

1285
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1286 1287 1288 1289 1290 1291 1292
		unsigned int shift = (i % 4) * 4 + nibble_offset;
		u8 data = entry->data[i];

		regs[i / 4] |= (data & GLOBAL_VTU_STU_DATA_MASK) << shift;
	}

	for (i = 0; i < 3; ++i) {
1293 1294 1295 1296 1297
		u16 reg = regs[i];

		err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg);
		if (err)
			return err;
1298 1299 1300 1301 1302
	}

	return 0;
}

1303
static int mv88e6xxx_vtu_data_write(struct mv88e6xxx_chip *chip,
1304
				    struct mv88e6xxx_vtu_entry *entry)
1305
{
1306
	return _mv88e6xxx_vtu_stu_data_write(chip, entry, 0);
1307 1308
}

1309
static int mv88e6xxx_stu_data_write(struct mv88e6xxx_chip *chip,
1310
				    struct mv88e6xxx_vtu_entry *entry)
1311
{
1312
	return _mv88e6xxx_vtu_stu_data_write(chip, entry, 2);
1313 1314
}

1315
static int _mv88e6xxx_vtu_vid_write(struct mv88e6xxx_chip *chip, u16 vid)
1316
{
1317 1318
	return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID,
				  vid & GLOBAL_VTU_VID_MASK);
1319 1320
}

1321
static int _mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip,
1322
				  struct mv88e6xxx_vtu_entry *entry)
1323
{
1324
	struct mv88e6xxx_vtu_entry next = { 0 };
1325 1326
	u16 val;
	int err;
1327

1328 1329 1330
	err = _mv88e6xxx_vtu_wait(chip);
	if (err)
		return err;
1331

1332 1333 1334
	err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_VTU_GET_NEXT);
	if (err)
		return err;
1335

1336 1337 1338
	err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
	if (err)
		return err;
1339

1340 1341
	next.vid = val & GLOBAL_VTU_VID_MASK;
	next.valid = !!(val & GLOBAL_VTU_VID_VALID);
1342 1343

	if (next.valid) {
1344 1345 1346
		err = mv88e6xxx_vtu_data_read(chip, &next);
		if (err)
			return err;
1347

1348
		if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
1349 1350 1351
			err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val);
			if (err)
				return err;
1352

1353
			next.fid = val & GLOBAL_VTU_FID_MASK;
1354
		} else if (mv88e6xxx_num_databases(chip) == 256) {
1355 1356 1357
			/* VTU DBNum[7:4] are located in VTU Operation 11:8, and
			 * VTU DBNum[3:0] are located in VTU Operation 3:0
			 */
1358 1359 1360
			err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val);
			if (err)
				return err;
1361

1362 1363
			next.fid = (val & 0xf00) >> 4;
			next.fid |= val & 0xf;
1364
		}
1365

1366
		if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
1367 1368 1369
			err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
			if (err)
				return err;
1370

1371
			next.sid = val & GLOBAL_VTU_SID_MASK;
1372 1373 1374 1375 1376 1377 1378
		}
	}

	*entry = next;
	return 0;
}

1379 1380 1381
static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
				    struct switchdev_obj_port_vlan *vlan,
				    int (*cb)(struct switchdev_obj *obj))
1382
{
V
Vivien Didelot 已提交
1383
	struct mv88e6xxx_chip *chip = ds->priv;
1384
	struct mv88e6xxx_vtu_entry next;
1385 1386 1387
	u16 pvid;
	int err;

1388
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
1389 1390
		return -EOPNOTSUPP;

1391
	mutex_lock(&chip->reg_lock);
1392

1393
	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1394 1395 1396
	if (err)
		goto unlock;

1397
	err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
1398 1399 1400 1401
	if (err)
		goto unlock;

	do {
1402
		err = _mv88e6xxx_vtu_getnext(chip, &next);
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412
		if (err)
			break;

		if (!next.valid)
			break;

		if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
			continue;

		/* reinit and dump this VLAN obj */
1413 1414
		vlan->vid_begin = next.vid;
		vlan->vid_end = next.vid;
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
		vlan->flags = 0;

		if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
			vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;

		if (next.vid == pvid)
			vlan->flags |= BRIDGE_VLAN_INFO_PVID;

		err = cb(&vlan->obj);
		if (err)
			break;
	} while (next.vid < GLOBAL_VTU_VID_MASK);

unlock:
1429
	mutex_unlock(&chip->reg_lock);
1430 1431 1432 1433

	return err;
}

1434
static int _mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
1435
				    struct mv88e6xxx_vtu_entry *entry)
1436
{
1437
	u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE;
1438
	u16 reg = 0;
1439
	int err;
1440

1441 1442 1443
	err = _mv88e6xxx_vtu_wait(chip);
	if (err)
		return err;
1444 1445 1446 1447 1448

	if (!entry->valid)
		goto loadpurge;

	/* Write port member tags */
1449 1450 1451
	err = mv88e6xxx_vtu_data_write(chip, entry);
	if (err)
		return err;
1452

1453
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_STU)) {
1454
		reg = entry->sid & GLOBAL_VTU_SID_MASK;
1455 1456 1457
		err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
		if (err)
			return err;
1458
	}
1459

1460
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G1_VTU_FID)) {
1461
		reg = entry->fid & GLOBAL_VTU_FID_MASK;
1462 1463 1464
		err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, reg);
		if (err)
			return err;
1465
	} else if (mv88e6xxx_num_databases(chip) == 256) {
1466 1467 1468 1469 1470
		/* VTU DBNum[7:4] are located in VTU Operation 11:8, and
		 * VTU DBNum[3:0] are located in VTU Operation 3:0
		 */
		op |= (entry->fid & 0xf0) << 8;
		op |= entry->fid & 0xf;
1471 1472 1473 1474 1475
	}

	reg = GLOBAL_VTU_VID_VALID;
loadpurge:
	reg |= entry->vid & GLOBAL_VTU_VID_MASK;
1476 1477 1478
	err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
	if (err)
		return err;
1479

1480
	return _mv88e6xxx_vtu_cmd(chip, op);
1481 1482
}

1483
static int _mv88e6xxx_stu_getnext(struct mv88e6xxx_chip *chip, u8 sid,
1484
				  struct mv88e6xxx_vtu_entry *entry)
1485
{
1486
	struct mv88e6xxx_vtu_entry next = { 0 };
1487 1488
	u16 val;
	int err;
1489

1490 1491 1492
	err = _mv88e6xxx_vtu_wait(chip);
	if (err)
		return err;
1493

1494 1495 1496 1497
	err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID,
				 sid & GLOBAL_VTU_SID_MASK);
	if (err)
		return err;
1498

1499 1500 1501
	err = _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_GET_NEXT);
	if (err)
		return err;
1502

1503 1504 1505
	err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val);
	if (err)
		return err;
1506

1507
	next.sid = val & GLOBAL_VTU_SID_MASK;
1508

1509 1510 1511
	err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val);
	if (err)
		return err;
1512

1513
	next.valid = !!(val & GLOBAL_VTU_VID_VALID);
1514 1515

	if (next.valid) {
1516 1517 1518
		err = mv88e6xxx_stu_data_read(chip, &next);
		if (err)
			return err;
1519 1520 1521 1522 1523 1524
	}

	*entry = next;
	return 0;
}

1525
static int _mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip,
1526
				    struct mv88e6xxx_vtu_entry *entry)
1527 1528
{
	u16 reg = 0;
1529
	int err;
1530

1531 1532 1533
	err = _mv88e6xxx_vtu_wait(chip);
	if (err)
		return err;
1534 1535 1536 1537 1538

	if (!entry->valid)
		goto loadpurge;

	/* Write port states */
1539 1540 1541
	err = mv88e6xxx_stu_data_write(chip, entry);
	if (err)
		return err;
1542 1543 1544

	reg = GLOBAL_VTU_VID_VALID;
loadpurge:
1545 1546 1547
	err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, reg);
	if (err)
		return err;
1548 1549

	reg = entry->sid & GLOBAL_VTU_SID_MASK;
1550 1551 1552
	err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, reg);
	if (err)
		return err;
1553

1554
	return _mv88e6xxx_vtu_cmd(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE);
1555 1556
}

1557
static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
1558 1559
{
	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
1560
	struct mv88e6xxx_vtu_entry vlan;
1561
	int i, err;
1562 1563 1564

	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);

1565
	/* Set every FID bit used by the (un)bridged ports */
1566
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1567
		err = mv88e6xxx_port_get_fid(chip, i, fid);
1568 1569 1570 1571 1572 1573
		if (err)
			return err;

		set_bit(*fid, fid_bitmap);
	}

1574
	/* Set every FID bit used by the VLAN entries */
1575
	err = _mv88e6xxx_vtu_vid_write(chip, GLOBAL_VTU_VID_MASK);
1576 1577 1578 1579
	if (err)
		return err;

	do {
1580
		err = _mv88e6xxx_vtu_getnext(chip, &vlan);
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
		if (err)
			return err;

		if (!vlan.valid)
			break;

		set_bit(vlan.fid, fid_bitmap);
	} while (vlan.vid < GLOBAL_VTU_VID_MASK);

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

	/* Clear the database */
1598
	return mv88e6xxx_g1_atu_flush(chip, *fid, true);
1599 1600
}

1601
static int _mv88e6xxx_vtu_new(struct mv88e6xxx_chip *chip, u16 vid,
1602
			      struct mv88e6xxx_vtu_entry *entry)
1603
{
1604
	struct dsa_switch *ds = chip->ds;
1605
	struct mv88e6xxx_vtu_entry vlan = {
1606 1607 1608
		.valid = true,
		.vid = vid,
	};
1609 1610
	int i, err;

1611
	err = mv88e6xxx_atu_new(chip, &vlan.fid);
1612 1613
	if (err)
		return err;
1614

1615
	/* exclude all ports except the CPU and DSA ports */
1616
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1617 1618 1619
		vlan.data[i] = dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)
			? GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED
			: GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
1620

1621
	if (mv88e6xxx_6097_family(chip) || mv88e6xxx_6165_family(chip) ||
1622 1623
	    mv88e6xxx_6351_family(chip) || mv88e6xxx_6352_family(chip) ||
	    mv88e6xxx_6341_family(chip)) {
1624
		struct mv88e6xxx_vtu_entry vstp;
1625 1626 1627 1628 1629 1630

		/* Adding a VTU entry requires a valid STU entry. As VSTP is not
		 * implemented, only one STU entry is needed to cover all VTU
		 * entries. Thus, validate the SID 0.
		 */
		vlan.sid = 0;
1631
		err = _mv88e6xxx_stu_getnext(chip, GLOBAL_VTU_SID_MASK, &vstp);
1632 1633 1634 1635 1636 1637 1638 1639
		if (err)
			return err;

		if (vstp.sid != vlan.sid || !vstp.valid) {
			memset(&vstp, 0, sizeof(vstp));
			vstp.valid = true;
			vstp.sid = vlan.sid;

1640
			err = _mv88e6xxx_stu_loadpurge(chip, &vstp);
1641 1642 1643 1644 1645 1646 1647 1648 1649
			if (err)
				return err;
		}
	}

	*entry = vlan;
	return 0;
}

1650
static int _mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
1651
			      struct mv88e6xxx_vtu_entry *entry, bool creat)
1652 1653 1654 1655 1656 1657
{
	int err;

	if (!vid)
		return -EINVAL;

1658
	err = _mv88e6xxx_vtu_vid_write(chip, vid - 1);
1659 1660 1661
	if (err)
		return err;

1662
	err = _mv88e6xxx_vtu_getnext(chip, entry);
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
	if (err)
		return err;

	if (entry->vid != vid || !entry->valid) {
		if (!creat)
			return -EOPNOTSUPP;
		/* -ENOENT would've been more appropriate, but switchdev expects
		 * -EOPNOTSUPP to inform bridge about an eventual software VLAN.
		 */

1673
		err = _mv88e6xxx_vtu_new(chip, vid, entry);
1674 1675 1676 1677 1678
	}

	return err;
}

1679 1680 1681
static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
					u16 vid_begin, u16 vid_end)
{
V
Vivien Didelot 已提交
1682
	struct mv88e6xxx_chip *chip = ds->priv;
1683
	struct mv88e6xxx_vtu_entry vlan;
1684 1685 1686 1687 1688
	int i, err;

	if (!vid_begin)
		return -EOPNOTSUPP;

1689
	mutex_lock(&chip->reg_lock);
1690

1691
	err = _mv88e6xxx_vtu_vid_write(chip, vid_begin - 1);
1692 1693 1694 1695
	if (err)
		goto unlock;

	do {
1696
		err = _mv88e6xxx_vtu_getnext(chip, &vlan);
1697 1698 1699 1700 1701 1702 1703 1704 1705
		if (err)
			goto unlock;

		if (!vlan.valid)
			break;

		if (vlan.vid > vid_end)
			break;

1706
		for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1707 1708 1709
			if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
				continue;

1710 1711 1712
			if (!ds->ports[port].netdev)
				continue;

1713 1714 1715 1716
			if (vlan.data[i] ==
			    GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
				continue;

1717 1718
			if (ds->ports[i].bridge_dev ==
			    ds->ports[port].bridge_dev)
1719 1720
				break; /* same bridge, check next VLAN */

1721
			if (!ds->ports[i].bridge_dev)
1722 1723
				continue;

1724
			netdev_warn(ds->ports[port].netdev,
1725 1726
				    "hardware VLAN %d already used by %s\n",
				    vlan.vid,
1727
				    netdev_name(ds->ports[i].bridge_dev));
1728 1729 1730 1731 1732 1733
			err = -EOPNOTSUPP;
			goto unlock;
		}
	} while (vlan.vid < vid_end);

unlock:
1734
	mutex_unlock(&chip->reg_lock);
1735 1736 1737 1738

	return err;
}

1739 1740
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
					 bool vlan_filtering)
1741
{
V
Vivien Didelot 已提交
1742
	struct mv88e6xxx_chip *chip = ds->priv;
1743
	u16 mode = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE :
1744
		PORT_CONTROL_2_8021Q_DISABLED;
1745
	int err;
1746

1747
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
1748 1749
		return -EOPNOTSUPP;

1750
	mutex_lock(&chip->reg_lock);
1751
	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1752
	mutex_unlock(&chip->reg_lock);
1753

1754
	return err;
1755 1756
}

1757 1758 1759 1760
static int
mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
			    const struct switchdev_obj_port_vlan *vlan,
			    struct switchdev_trans *trans)
1761
{
V
Vivien Didelot 已提交
1762
	struct mv88e6xxx_chip *chip = ds->priv;
1763 1764
	int err;

1765
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
1766 1767
		return -EOPNOTSUPP;

1768 1769 1770 1771 1772 1773 1774 1775
	/* If the requested port doesn't belong to the same bridge as the VLAN
	 * members, do not support it (yet) and fallback to software VLAN.
	 */
	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
					   vlan->vid_end);
	if (err)
		return err;

1776 1777 1778 1779 1780 1781
	/* We don't need any dynamic resource from the kernel (yet),
	 * so skip the prepare phase.
	 */
	return 0;
}

1782
static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
1783
				    u16 vid, bool untagged)
1784
{
1785
	struct mv88e6xxx_vtu_entry vlan;
1786 1787
	int err;

1788
	err = _mv88e6xxx_vtu_get(chip, vid, &vlan, true);
1789
	if (err)
1790
		return err;
1791 1792 1793 1794 1795

	vlan.data[port] = untagged ?
		GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
		GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;

1796
	return _mv88e6xxx_vtu_loadpurge(chip, &vlan);
1797 1798
}

1799 1800 1801
static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
				    const struct switchdev_obj_port_vlan *vlan,
				    struct switchdev_trans *trans)
1802
{
V
Vivien Didelot 已提交
1803
	struct mv88e6xxx_chip *chip = ds->priv;
1804 1805 1806 1807
	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
	u16 vid;

1808
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
1809 1810
		return;

1811
	mutex_lock(&chip->reg_lock);
1812

1813
	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1814
		if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
1815 1816
			netdev_err(ds->ports[port].netdev,
				   "failed to add VLAN %d%c\n",
1817
				   vid, untagged ? 'u' : 't');
1818

1819
	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
1820
		netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n",
1821
			   vlan->vid_end);
1822

1823
	mutex_unlock(&chip->reg_lock);
1824 1825
}

1826
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
1827
				    int port, u16 vid)
1828
{
1829
	struct dsa_switch *ds = chip->ds;
1830
	struct mv88e6xxx_vtu_entry vlan;
1831 1832
	int i, err;

1833
	err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1834
	if (err)
1835
		return err;
1836

1837 1838
	/* Tell switchdev if this VLAN is handled in software */
	if (vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
1839
		return -EOPNOTSUPP;
1840 1841 1842 1843

	vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;

	/* keep the VLAN unless all ports are excluded */
1844
	vlan.valid = false;
1845
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1846
		if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
1847 1848 1849
			continue;

		if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
1850
			vlan.valid = true;
1851 1852 1853 1854
			break;
		}
	}

1855
	err = _mv88e6xxx_vtu_loadpurge(chip, &vlan);
1856 1857 1858
	if (err)
		return err;

1859
	return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false);
1860 1861
}

1862 1863
static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
				   const struct switchdev_obj_port_vlan *vlan)
1864
{
V
Vivien Didelot 已提交
1865
	struct mv88e6xxx_chip *chip = ds->priv;
1866 1867 1868
	u16 pvid, vid;
	int err = 0;

1869
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_VTU))
1870 1871
		return -EOPNOTSUPP;

1872
	mutex_lock(&chip->reg_lock);
1873

1874
	err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
1875 1876 1877
	if (err)
		goto unlock;

1878
	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1879
		err = _mv88e6xxx_port_vlan_del(chip, port, vid);
1880 1881 1882 1883
		if (err)
			goto unlock;

		if (vid == pvid) {
1884
			err = mv88e6xxx_port_set_pvid(chip, port, 0);
1885 1886 1887 1888 1889
			if (err)
				goto unlock;
		}
	}

1890
unlock:
1891
	mutex_unlock(&chip->reg_lock);
1892 1893 1894 1895

	return err;
}

1896 1897 1898
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
					const unsigned char *addr, u16 vid,
					u8 state)
1899
{
1900
	struct mv88e6xxx_vtu_entry vlan;
1901
	struct mv88e6xxx_atu_entry entry;
1902 1903
	int err;

1904 1905
	/* Null VLAN ID corresponds to the port private database */
	if (vid == 0)
1906
		err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
1907
	else
1908
		err = _mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1909 1910
	if (err)
		return err;
1911

1912 1913 1914 1915 1916
	entry.state = GLOBAL_ATU_DATA_STATE_UNUSED;
	ether_addr_copy(entry.mac, addr);
	eth_addr_dec(entry.mac);

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

1920 1921 1922 1923 1924 1925 1926
	/* Initialize a fresh ATU entry if it isn't found */
	if (entry.state == GLOBAL_ATU_DATA_STATE_UNUSED ||
	    !ether_addr_equal(entry.mac, addr)) {
		memset(&entry, 0, sizeof(entry));
		ether_addr_copy(entry.mac, addr);
	}

1927 1928
	/* Purge the ATU entry only if no port is using it anymore */
	if (state == GLOBAL_ATU_DATA_STATE_UNUSED) {
1929 1930
		entry.portvec &= ~BIT(port);
		if (!entry.portvec)
1931 1932
			entry.state = GLOBAL_ATU_DATA_STATE_UNUSED;
	} else {
1933
		entry.portvec |= BIT(port);
1934
		entry.state = state;
1935 1936
	}

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

1940 1941 1942
static int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
				      const struct switchdev_obj_port_fdb *fdb,
				      struct switchdev_trans *trans)
V
Vivien Didelot 已提交
1943 1944 1945 1946 1947 1948 1949
{
	/* We don't need any dynamic resource from the kernel (yet),
	 * so skip the prepare phase.
	 */
	return 0;
}

1950 1951 1952
static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
				   const struct switchdev_obj_port_fdb *fdb,
				   struct switchdev_trans *trans)
1953
{
V
Vivien Didelot 已提交
1954
	struct mv88e6xxx_chip *chip = ds->priv;
1955

1956
	mutex_lock(&chip->reg_lock);
1957 1958 1959
	if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid,
					 GLOBAL_ATU_DATA_STATE_UC_STATIC))
		netdev_err(ds->ports[port].netdev, "failed to load unicast MAC address\n");
1960
	mutex_unlock(&chip->reg_lock);
1961 1962
}

1963 1964
static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
				  const struct switchdev_obj_port_fdb *fdb)
1965
{
V
Vivien Didelot 已提交
1966
	struct mv88e6xxx_chip *chip = ds->priv;
1967
	int err;
1968

1969
	mutex_lock(&chip->reg_lock);
1970 1971
	err = mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid,
					   GLOBAL_ATU_DATA_STATE_UNUSED);
1972
	mutex_unlock(&chip->reg_lock);
1973

1974
	return err;
1975 1976
}

1977 1978 1979 1980
static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
				      u16 fid, u16 vid, int port,
				      struct switchdev_obj *obj,
				      int (*cb)(struct switchdev_obj *obj))
1981
{
1982
	struct mv88e6xxx_atu_entry addr;
1983 1984
	int err;

1985 1986
	addr.state = GLOBAL_ATU_DATA_STATE_UNUSED;
	eth_broadcast_addr(addr.mac);
1987 1988

	do {
1989
		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
1990
		if (err)
1991
			return err;
1992 1993 1994 1995

		if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
			break;

1996
		if (addr.trunk || (addr.portvec & BIT(port)) == 0)
1997 1998 1999 2000
			continue;

		if (obj->id == SWITCHDEV_OBJ_ID_PORT_FDB) {
			struct switchdev_obj_port_fdb *fdb;
2001

2002 2003 2004 2005
			if (!is_unicast_ether_addr(addr.mac))
				continue;

			fdb = SWITCHDEV_OBJ_PORT_FDB(obj);
2006 2007
			fdb->vid = vid;
			ether_addr_copy(fdb->addr, addr.mac);
2008 2009 2010 2011
			if (addr.state == GLOBAL_ATU_DATA_STATE_UC_STATIC)
				fdb->ndm_state = NUD_NOARP;
			else
				fdb->ndm_state = NUD_REACHABLE;
2012 2013 2014 2015 2016 2017 2018 2019 2020
		} else if (obj->id == SWITCHDEV_OBJ_ID_PORT_MDB) {
			struct switchdev_obj_port_mdb *mdb;

			if (!is_multicast_ether_addr(addr.mac))
				continue;

			mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
			mdb->vid = vid;
			ether_addr_copy(mdb->addr, addr.mac);
2021 2022
		} else {
			return -EOPNOTSUPP;
2023
		}
2024 2025 2026 2027

		err = cb(obj);
		if (err)
			return err;
2028 2029 2030 2031 2032
	} while (!is_broadcast_ether_addr(addr.mac));

	return err;
}

2033 2034 2035
static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
				  struct switchdev_obj *obj,
				  int (*cb)(struct switchdev_obj *obj))
2036
{
2037
	struct mv88e6xxx_vtu_entry vlan = {
2038 2039
		.vid = GLOBAL_VTU_VID_MASK, /* all ones */
	};
2040
	u16 fid;
2041 2042
	int err;

2043
	/* Dump port's default Filtering Information Database (VLAN ID 0) */
2044
	err = mv88e6xxx_port_get_fid(chip, port, &fid);
2045
	if (err)
2046
		return err;
2047

2048
	err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, obj, cb);
2049
	if (err)
2050
		return err;
2051

2052
	/* Dump VLANs' Filtering Information Databases */
2053
	err = _mv88e6xxx_vtu_vid_write(chip, vlan.vid);
2054
	if (err)
2055
		return err;
2056 2057

	do {
2058
		err = _mv88e6xxx_vtu_getnext(chip, &vlan);
2059
		if (err)
2060
			return err;
2061 2062 2063 2064

		if (!vlan.valid)
			break;

2065 2066
		err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port,
						 obj, cb);
2067
		if (err)
2068
			return err;
2069 2070
	} while (vlan.vid < GLOBAL_VTU_VID_MASK);

2071 2072 2073 2074 2075 2076 2077
	return err;
}

static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
				   struct switchdev_obj_port_fdb *fdb,
				   int (*cb)(struct switchdev_obj *obj))
{
V
Vivien Didelot 已提交
2078
	struct mv88e6xxx_chip *chip = ds->priv;
2079 2080 2081 2082
	int err;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_port_db_dump(chip, port, &fdb->obj, cb);
2083
	mutex_unlock(&chip->reg_lock);
2084 2085 2086 2087

	return err;
}

2088
static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
2089
				      struct net_device *br)
2090
{
V
Vivien Didelot 已提交
2091
	struct mv88e6xxx_chip *chip = ds->priv;
2092
	int i, err = 0;
2093

2094
	mutex_lock(&chip->reg_lock);
2095

2096
	/* Remap each port's VLANTable */
2097
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
2098
		if (ds->ports[i].bridge_dev == br) {
2099
			err = _mv88e6xxx_port_based_vlan_map(chip, i);
2100 2101 2102 2103 2104
			if (err)
				break;
		}
	}

2105
	mutex_unlock(&chip->reg_lock);
2106

2107
	return err;
2108 2109
}

2110 2111
static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
					struct net_device *br)
2112
{
V
Vivien Didelot 已提交
2113
	struct mv88e6xxx_chip *chip = ds->priv;
2114
	int i;
2115

2116
	mutex_lock(&chip->reg_lock);
2117

2118
	/* Remap each port's VLANTable */
2119
	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
2120
		if (i == port || ds->ports[i].bridge_dev == br)
2121
			if (_mv88e6xxx_port_based_vlan_map(chip, i))
2122 2123
				netdev_warn(ds->ports[i].netdev,
					    "failed to remap\n");
2124

2125
	mutex_unlock(&chip->reg_lock);
2126 2127
}

2128 2129 2130 2131 2132 2133 2134 2135
static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
{
	if (chip->info->ops->reset)
		return chip->info->ops->reset(chip);

	return 0;
}

2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
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);
	}
}

2149
static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip)
2150
{
2151
	int i, err;
2152

2153
	/* Set all ports to the Disabled state */
2154
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2155 2156
		err = mv88e6xxx_port_set_state(chip, i,
					       PORT_CONTROL_STATE_DISABLED);
2157 2158
		if (err)
			return err;
2159 2160
	}

2161 2162 2163
	/* Wait for transmit queues to drain,
	 * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps.
	 */
2164 2165
	usleep_range(2000, 4000);

2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
	return 0;
}

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

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

2177
	mv88e6xxx_hardware_reset(chip);
2178

2179
	return mv88e6xxx_software_reset(chip);
2180 2181
}

2182
static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
2183
{
2184 2185
	u16 val;
	int err;
2186

2187 2188 2189 2190
	/* Clear Power Down bit */
	err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val);
	if (err)
		return err;
2191

2192 2193 2194
	if (val & BMCR_PDOWN) {
		val &= ~BMCR_PDOWN;
		err = mv88e6xxx_serdes_write(chip, MII_BMCR, val);
2195 2196
	}

2197
	return err;
2198 2199
}

2200 2201 2202
static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
				   enum mv88e6xxx_frame_mode frame, u16 egress,
				   u16 etype)
2203 2204 2205
{
	int err;

2206 2207 2208 2209
	if (!chip->info->ops->port_set_frame_mode)
		return -EOPNOTSUPP;

	err = mv88e6xxx_port_set_egress_mode(chip, port, egress);
2210 2211 2212
	if (err)
		return err;

2213 2214 2215 2216 2217 2218 2219 2220
	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;
2221 2222
}

2223
static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port)
2224
{
2225 2226 2227 2228
	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL,
				       PORT_CONTROL_EGRESS_UNMODIFIED,
				       PORT_ETH_TYPE_DEFAULT);
}
2229

2230 2231 2232 2233 2234 2235
static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port)
{
	return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA,
				       PORT_CONTROL_EGRESS_UNMODIFIED,
				       PORT_ETH_TYPE_DEFAULT);
}
2236

2237 2238 2239 2240 2241 2242
static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port)
{
	return mv88e6xxx_set_port_mode(chip, port,
				       MV88E6XXX_FRAME_MODE_ETHERTYPE,
				       PORT_CONTROL_EGRESS_ADD_TAG, ETH_P_EDSA);
}
2243

2244 2245 2246 2247
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);
2248

2249 2250
	if (dsa_is_normal_port(chip->ds, port))
		return mv88e6xxx_set_port_mode_normal(chip, port);
2251

2252 2253 2254
	/* Setup CPU port mode depending on its supported tag format */
	if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA)
		return mv88e6xxx_set_port_mode_dsa(chip, port);
2255

2256 2257
	if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
		return mv88e6xxx_set_port_mode_edsa(chip, port);
2258

2259
	return -EINVAL;
2260 2261
}

2262
static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port)
2263
{
2264
	bool message = dsa_is_dsa_port(chip->ds, port);
2265

2266
	return mv88e6xxx_port_set_message_port(chip, port, message);
2267
}
2268

2269
static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2270
{
2271
	bool flood = port == dsa_upstream_port(chip->ds);
2272

2273 2274 2275 2276
	/* Upstream ports flood frames with unknown unicast or multicast DA */
	if (chip->info->ops->port_set_egress_floods)
		return chip->info->ops->port_set_egress_floods(chip, port,
							       flood, flood);
2277

2278
	return 0;
2279 2280
}

2281
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
2282
{
2283
	struct dsa_switch *ds = chip->ds;
2284
	int err;
2285
	u16 reg;
2286

2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300
	/* MAC Forcing register: don't force link, speed, duplex or flow control
	 * state to any particular values on physical ports, but force the CPU
	 * port and all DSA ports to their maximum bandwidth and full duplex.
	 */
	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
					       SPEED_MAX, DUPLEX_FULL,
					       PHY_INTERFACE_MODE_NA);
	else
		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
					       SPEED_UNFORCED, DUPLEX_UNFORCED,
					       PHY_INTERFACE_MODE_NA);
	if (err)
		return err;
2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315

	/* 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.
	 */
2316
	reg = PORT_CONTROL_IGMP_MLD_SNOOP |
2317 2318
		PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
		PORT_CONTROL_STATE_FORWARDING;
2319 2320 2321
	err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
	if (err)
		return err;
2322

2323
	err = mv88e6xxx_setup_port_mode(chip, port);
2324 2325
	if (err)
		return err;
2326

2327
	err = mv88e6xxx_setup_egress_floods(chip, port);
2328 2329 2330
	if (err)
		return err;

2331 2332 2333
	/* If this port is connected to a SerDes, make sure the SerDes is not
	 * powered down.
	 */
2334
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) {
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344
		err = mv88e6xxx_port_read(chip, port, PORT_STATUS, &reg);
		if (err)
			return err;
		reg &= PORT_STATUS_CMODE_MASK;
		if ((reg == PORT_STATUS_CMODE_100BASE_X) ||
		    (reg == PORT_STATUS_CMODE_1000BASE_X) ||
		    (reg == PORT_STATUS_CMODE_SGMII)) {
			err = mv88e6xxx_serdes_power_on(chip);
			if (err < 0)
				return err;
2345 2346 2347
		}
	}

2348
	/* Port Control 2: don't force a good FCS, set the maximum frame size to
2349
	 * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
2350 2351 2352
	 * untagged frames on this port, do a destination address lookup on all
	 * received packets as usual, disable ARP mirroring and don't send a
	 * copy of all transmitted/received frames on this port to the CPU.
2353
	 */
2354 2355 2356
	err = mv88e6xxx_port_set_map_da(chip, port);
	if (err)
		return err;
2357

2358 2359 2360 2361
	reg = 0;
	if (chip->info->ops->port_set_upstream_port) {
		err = chip->info->ops->port_set_upstream_port(
			chip, port, dsa_upstream_port(ds));
2362 2363
		if (err)
			return err;
2364 2365
	}

2366 2367 2368 2369 2370
	err = mv88e6xxx_port_set_8021q_mode(chip, port,
					    PORT_CONTROL_2_8021Q_DISABLED);
	if (err)
		return err;

2371 2372 2373 2374 2375 2376
	if (chip->info->ops->port_jumbo_config) {
		err = chip->info->ops->port_jumbo_config(chip, port);
		if (err)
			return err;
	}

2377 2378 2379 2380 2381
	/* Port Association Vector: when learning source addresses
	 * of packets, add the address to the address database using
	 * a port bitmap that has only the bit for this port set and
	 * the other bits clear.
	 */
2382
	reg = 1 << port;
2383 2384
	/* Disable learning for CPU port */
	if (dsa_is_cpu_port(ds, port))
2385
		reg = 0;
2386

2387 2388 2389
	err = mv88e6xxx_port_write(chip, port, PORT_ASSOC_VECTOR, reg);
	if (err)
		return err;
2390 2391

	/* Egress rate control 2: disable egress rate control. */
2392 2393 2394
	err = mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL_2, 0x0000);
	if (err)
		return err;
2395

2396 2397
	if (chip->info->ops->port_pause_config) {
		err = chip->info->ops->port_pause_config(chip, port);
2398 2399
		if (err)
			return err;
2400
	}
2401

2402 2403 2404 2405 2406 2407
	if (chip->info->ops->port_disable_learn_limit) {
		err = chip->info->ops->port_disable_learn_limit(chip, port);
		if (err)
			return err;
	}

2408 2409
	if (chip->info->ops->port_disable_pri_override) {
		err = chip->info->ops->port_disable_pri_override(chip, port);
2410 2411
		if (err)
			return err;
2412
	}
2413

2414 2415
	if (chip->info->ops->port_tag_remap) {
		err = chip->info->ops->port_tag_remap(chip, port);
2416 2417
		if (err)
			return err;
2418 2419
	}

2420 2421
	if (chip->info->ops->port_egress_rate_limiting) {
		err = chip->info->ops->port_egress_rate_limiting(chip, port);
2422 2423
		if (err)
			return err;
2424 2425
	}

2426
	err = mv88e6xxx_setup_message_port(chip, port);
2427 2428
	if (err)
		return err;
2429

2430
	/* Port based VLAN map: give each port the same default address
2431 2432
	 * database, and allow bidirectional communication between the
	 * CPU and DSA port(s), and the other ports.
2433
	 */
2434
	err = mv88e6xxx_port_set_fid(chip, port, 0);
2435 2436
	if (err)
		return err;
2437

2438 2439 2440
	err = _mv88e6xxx_port_based_vlan_map(chip, port);
	if (err)
		return err;
2441 2442 2443 2444

	/* Default VLAN ID and priority: don't set a default VLAN
	 * ID, and set the default packet priority to zero.
	 */
2445
	return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000);
2446 2447
}

2448
static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
2449 2450 2451
{
	int err;

2452
	err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]);
2453 2454 2455
	if (err)
		return err;

2456
	err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
2457 2458 2459
	if (err)
		return err;

2460 2461 2462 2463 2464
	err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
	if (err)
		return err;

	return 0;
2465 2466
}

2467 2468 2469
static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
				     unsigned int ageing_time)
{
V
Vivien Didelot 已提交
2470
	struct mv88e6xxx_chip *chip = ds->priv;
2471 2472 2473
	int err;

	mutex_lock(&chip->reg_lock);
2474
	err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
2475 2476 2477 2478 2479
	mutex_unlock(&chip->reg_lock);

	return err;
}

2480
static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
2481
{
2482
	struct dsa_switch *ds = chip->ds;
2483
	u32 upstream_port = dsa_upstream_port(ds);
2484
	int err;
2485

2486 2487 2488
	/* Enable the PHY Polling Unit if present, don't discard any packets,
	 * and mask all interrupt sources.
	 */
2489
	err = mv88e6xxx_ppu_enable(chip);
2490 2491 2492
	if (err)
		return err;

2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
	if (chip->info->ops->g1_set_cpu_port) {
		err = chip->info->ops->g1_set_cpu_port(chip, upstream_port);
		if (err)
			return err;
	}

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

2505
	/* Disable remote management, and set the switch's DSA device number. */
2506 2507 2508
	err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2,
				 GLOBAL_CONTROL_2_MULTIPLE_CASCADE |
				 (ds->index & 0x1f));
2509 2510 2511
	if (err)
		return err;

2512 2513 2514 2515 2516
	/* Clear all the VTU and STU entries */
	err = _mv88e6xxx_vtu_stu_flush(chip);
	if (err < 0)
		return err;

2517
	/* Configure the IP ToS mapping registers. */
2518
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000);
2519
	if (err)
2520
		return err;
2521
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_1, 0x0000);
2522
	if (err)
2523
		return err;
2524
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_2, 0x5555);
2525
	if (err)
2526
		return err;
2527
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_3, 0x5555);
2528
	if (err)
2529
		return err;
2530
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_4, 0xaaaa);
2531
	if (err)
2532
		return err;
2533
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_5, 0xaaaa);
2534
	if (err)
2535
		return err;
2536
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_6, 0xffff);
2537
	if (err)
2538
		return err;
2539
	err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_7, 0xffff);
2540
	if (err)
2541
		return err;
2542 2543

	/* Configure the IEEE 802.1p priority mapping register. */
2544
	err = mv88e6xxx_g1_write(chip, GLOBAL_IEEE_PRI, 0xfa41);
2545
	if (err)
2546
		return err;
2547

2548 2549 2550 2551 2552
	/* Initialize the statistics unit */
	err = mv88e6xxx_stats_set_histogram(chip);
	if (err)
		return err;

2553
	/* Clear the statistics counters for all ports */
2554 2555
	err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
				 GLOBAL_STATS_OP_FLUSH_ALL);
2556 2557 2558 2559
	if (err)
		return err;

	/* Wait for the flush to complete. */
2560
	err = mv88e6xxx_g1_stats_wait(chip);
2561 2562 2563 2564 2565 2566
	if (err)
		return err;

	return 0;
}

2567
static int mv88e6xxx_setup(struct dsa_switch *ds)
2568
{
V
Vivien Didelot 已提交
2569
	struct mv88e6xxx_chip *chip = ds->priv;
2570
	int err;
2571 2572
	int i;

2573
	chip->ds = ds;
2574
	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
2575

2576
	mutex_lock(&chip->reg_lock);
2577

2578
	/* Setup Switch Port Registers */
2579
	for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
2580 2581 2582 2583 2584 2585 2586
		err = mv88e6xxx_setup_port(chip, i);
		if (err)
			goto unlock;
	}

	/* Setup Switch Global 1 Registers */
	err = mv88e6xxx_g1_setup(chip);
2587 2588 2589
	if (err)
		goto unlock;

2590 2591 2592
	/* Setup Switch Global 2 Registers */
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_GLOBAL2)) {
		err = mv88e6xxx_g2_setup(chip);
2593 2594 2595
		if (err)
			goto unlock;
	}
2596

2597 2598 2599 2600
	err = mv88e6xxx_atu_setup(chip);
	if (err)
		goto unlock;

2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611
	/* Some generations have the configuration of sending reserved
	 * management frames to the CPU in global2, others in
	 * global1. Hence it does not fit the two setup functions
	 * above.
	 */
	if (chip->info->ops->mgmt_rsvd2cpu) {
		err = chip->info->ops->mgmt_rsvd2cpu(chip);
		if (err)
			goto unlock;
	}

2612
unlock:
2613
	mutex_unlock(&chip->reg_lock);
2614

2615
	return err;
2616 2617
}

2618 2619
static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr)
{
V
Vivien Didelot 已提交
2620
	struct mv88e6xxx_chip *chip = ds->priv;
2621 2622
	int err;

2623 2624
	if (!chip->info->ops->set_switch_mac)
		return -EOPNOTSUPP;
2625

2626 2627
	mutex_lock(&chip->reg_lock);
	err = chip->info->ops->set_switch_mac(chip, addr);
2628 2629 2630 2631 2632
	mutex_unlock(&chip->reg_lock);

	return err;
}

2633
static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
2634
{
2635 2636
	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2637 2638
	u16 val;
	int err;
2639

2640 2641 2642
	if (!chip->info->ops->phy_read)
		return -EOPNOTSUPP;

2643
	mutex_lock(&chip->reg_lock);
2644
	err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
2645
	mutex_unlock(&chip->reg_lock);
2646

2647 2648 2649 2650 2651 2652 2653 2654
	if (reg == MII_PHYSID2) {
		/* Some internal PHYS don't have a model number.  Use
		 * the mv88e6390 family model number instead.
		 */
		if (!(val & 0x3f0))
			val |= PORT_SWITCH_ID_PROD_NUM_6390;
	}

2655
	return err ? err : val;
2656 2657
}

2658
static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
2659
{
2660 2661
	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
	struct mv88e6xxx_chip *chip = mdio_bus->chip;
2662
	int err;
2663

2664 2665 2666
	if (!chip->info->ops->phy_write)
		return -EOPNOTSUPP;

2667
	mutex_lock(&chip->reg_lock);
2668
	err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
2669
	mutex_unlock(&chip->reg_lock);
2670 2671

	return err;
2672 2673
}

2674
static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
2675 2676
				   struct device_node *np,
				   bool external)
2677 2678
{
	static int index;
2679
	struct mv88e6xxx_mdio_bus *mdio_bus;
2680 2681 2682
	struct mii_bus *bus;
	int err;

2683
	bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
2684 2685 2686
	if (!bus)
		return -ENOMEM;

2687
	mdio_bus = bus->priv;
2688
	mdio_bus->bus = bus;
2689
	mdio_bus->chip = chip;
2690 2691
	INIT_LIST_HEAD(&mdio_bus->list);
	mdio_bus->external = external;
2692

2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
	if (np) {
		bus->name = np->full_name;
		snprintf(bus->id, MII_BUS_ID_SIZE, "%s", np->full_name);
	} 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;
2703
	bus->parent = chip->dev;
2704

2705 2706
	if (np)
		err = of_mdiobus_register(bus, np);
2707 2708 2709
	else
		err = mdiobus_register(bus);
	if (err) {
2710
		dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
2711
		return err;
2712
	}
2713 2714 2715 2716 2717

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

	return 0;
2720
}
2721

2722 2723 2724 2725 2726
static const struct of_device_id mv88e6xxx_mdio_external_match[] = {
	{ .compatible = "marvell,mv88e6xxx-mdio-external",
	  .data = (void *)true },
	{ },
};
2727

2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757
static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
				    struct device_node *np)
{
	const struct of_device_id *match;
	struct device_node *child;
	int err;

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

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

	return 0;
2758 2759
}

2760
static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
2761 2762

{
2763 2764
	struct mv88e6xxx_mdio_bus *mdio_bus;
	struct mii_bus *bus;
2765

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

2769 2770
		mdiobus_unregister(bus);
	}
2771 2772
}

2773 2774
static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
{
V
Vivien Didelot 已提交
2775
	struct mv88e6xxx_chip *chip = ds->priv;
2776 2777 2778 2779 2780 2781 2782

	return chip->eeprom_len;
}

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

2786 2787
	if (!chip->info->ops->get_eeprom)
		return -EOPNOTSUPP;
2788

2789 2790
	mutex_lock(&chip->reg_lock);
	err = chip->info->ops->get_eeprom(chip, eeprom, data);
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
	mutex_unlock(&chip->reg_lock);

	if (err)
		return err;

	eeprom->magic = 0xc3ec4951;

	return 0;
}

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

2807 2808 2809
	if (!chip->info->ops->set_eeprom)
		return -EOPNOTSUPP;

2810 2811 2812 2813
	if (eeprom->magic != 0xc3ec4951)
		return -EINVAL;

	mutex_lock(&chip->reg_lock);
2814
	err = chip->info->ops->set_eeprom(chip, eeprom, data);
2815 2816 2817 2818 2819
	mutex_unlock(&chip->reg_lock);

	return err;
}

2820
static const struct mv88e6xxx_ops mv88e6085_ops = {
2821
	/* MV88E6XXX_FAMILY_6097 */
2822
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2823 2824
	.phy_read = mv88e6xxx_phy_ppu_read,
	.phy_write = mv88e6xxx_phy_ppu_write,
2825
	.port_set_link = mv88e6xxx_port_set_link,
2826
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2827
	.port_set_speed = mv88e6185_port_set_speed,
2828
	.port_tag_remap = mv88e6095_port_tag_remap,
2829
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2830
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2831
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2832
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2833
	.port_pause_config = mv88e6097_port_pause_config,
2834
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2835
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2836
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2837 2838
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2839
	.stats_get_stats = mv88e6095_stats_get_stats,
2840 2841
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
2842
	.watchdog_ops = &mv88e6097_watchdog_ops,
2843
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
2844 2845
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2846
	.reset = mv88e6185_g1_reset,
2847 2848 2849
};

static const struct mv88e6xxx_ops mv88e6095_ops = {
2850
	/* MV88E6XXX_FAMILY_6095 */
2851
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2852 2853
	.phy_read = mv88e6xxx_phy_ppu_read,
	.phy_write = mv88e6xxx_phy_ppu_write,
2854
	.port_set_link = mv88e6xxx_port_set_link,
2855
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2856
	.port_set_speed = mv88e6185_port_set_speed,
2857
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2858
	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2859
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
2860
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2861 2862
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2863
	.stats_get_stats = mv88e6095_stats_get_stats,
2864
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
2865 2866
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2867
	.reset = mv88e6185_g1_reset,
2868 2869
};

2870
static const struct mv88e6xxx_ops mv88e6097_ops = {
2871
	/* MV88E6XXX_FAMILY_6097 */
2872 2873 2874 2875 2876 2877
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_speed = mv88e6185_port_set_speed,
2878
	.port_tag_remap = mv88e6095_port_tag_remap,
2879
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2880
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2881
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2882
	.port_jumbo_config = mv88e6165_port_jumbo_config,
2883
	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
2884
	.port_pause_config = mv88e6097_port_pause_config,
2885
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2886
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2887 2888 2889 2890
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
	.stats_get_stats = mv88e6095_stats_get_stats,
2891 2892
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
2893
	.watchdog_ops = &mv88e6097_watchdog_ops,
2894
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
2895
	.reset = mv88e6352_g1_reset,
2896 2897
};

2898
static const struct mv88e6xxx_ops mv88e6123_ops = {
2899
	/* MV88E6XXX_FAMILY_6165 */
2900
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2901 2902
	.phy_read = mv88e6165_phy_read,
	.phy_write = mv88e6165_phy_write,
2903
	.port_set_link = mv88e6xxx_port_set_link,
2904
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2905
	.port_set_speed = mv88e6185_port_set_speed,
2906
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
2907
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2908
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2909
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2910
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2911 2912
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2913
	.stats_get_stats = mv88e6095_stats_get_stats,
2914 2915
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
2916
	.watchdog_ops = &mv88e6097_watchdog_ops,
2917
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
2918
	.reset = mv88e6352_g1_reset,
2919 2920 2921
};

static const struct mv88e6xxx_ops mv88e6131_ops = {
2922
	/* MV88E6XXX_FAMILY_6185 */
2923
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
2924 2925
	.phy_read = mv88e6xxx_phy_ppu_read,
	.phy_write = mv88e6xxx_phy_ppu_write,
2926
	.port_set_link = mv88e6xxx_port_set_link,
2927
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2928
	.port_set_speed = mv88e6185_port_set_speed,
2929
	.port_tag_remap = mv88e6095_port_tag_remap,
2930
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2931
	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
2932
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2933
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
2934
	.port_jumbo_config = mv88e6165_port_jumbo_config,
2935
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2936
	.port_pause_config = mv88e6097_port_pause_config,
2937
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2938 2939
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
2940
	.stats_get_stats = mv88e6095_stats_get_stats,
2941 2942
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
2943
	.watchdog_ops = &mv88e6097_watchdog_ops,
2944
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
2945 2946
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
2947
	.reset = mv88e6185_g1_reset,
2948 2949
};

2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980
static const struct mv88e6xxx_ops mv88e6141_ops = {
	/* MV88E6XXX_FAMILY_6341 */
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
	.port_tag_remap = mv88e6095_port_tag_remap,
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
	.port_set_ether_type = mv88e6351_port_set_ether_type,
	.port_jumbo_config = mv88e6165_port_jumbo_config,
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
	.port_pause_config = mv88e6097_port_pause_config,
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
	.reset = mv88e6352_g1_reset,
};

2981
static const struct mv88e6xxx_ops mv88e6161_ops = {
2982
	/* MV88E6XXX_FAMILY_6165 */
2983
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
2984 2985
	.phy_read = mv88e6165_phy_read,
	.phy_write = mv88e6165_phy_write,
2986
	.port_set_link = mv88e6xxx_port_set_link,
2987
	.port_set_duplex = mv88e6xxx_port_set_duplex,
2988
	.port_set_speed = mv88e6185_port_set_speed,
2989
	.port_tag_remap = mv88e6095_port_tag_remap,
2990
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
2991
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
2992
	.port_set_ether_type = mv88e6351_port_set_ether_type,
2993
	.port_jumbo_config = mv88e6165_port_jumbo_config,
2994
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
2995
	.port_pause_config = mv88e6097_port_pause_config,
2996
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
2997
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
2998
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
2999 3000
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3001
	.stats_get_stats = mv88e6095_stats_get_stats,
3002 3003
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3004
	.watchdog_ops = &mv88e6097_watchdog_ops,
3005
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3006
	.reset = mv88e6352_g1_reset,
3007 3008 3009
};

static const struct mv88e6xxx_ops mv88e6165_ops = {
3010
	/* MV88E6XXX_FAMILY_6165 */
3011
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3012 3013
	.phy_read = mv88e6165_phy_read,
	.phy_write = mv88e6165_phy_write,
3014
	.port_set_link = mv88e6xxx_port_set_link,
3015
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3016
	.port_set_speed = mv88e6185_port_set_speed,
3017
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3018
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3019
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3020 3021
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3022
	.stats_get_stats = mv88e6095_stats_get_stats,
3023 3024
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3025
	.watchdog_ops = &mv88e6097_watchdog_ops,
3026
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3027
	.reset = mv88e6352_g1_reset,
3028 3029 3030
};

static const struct mv88e6xxx_ops mv88e6171_ops = {
3031
	/* MV88E6XXX_FAMILY_6351 */
3032
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3033 3034
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3035
	.port_set_link = mv88e6xxx_port_set_link,
3036
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3037
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3038
	.port_set_speed = mv88e6185_port_set_speed,
3039
	.port_tag_remap = mv88e6095_port_tag_remap,
3040
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3041
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3042
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3043
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3044
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3045
	.port_pause_config = mv88e6097_port_pause_config,
3046
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3047
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3048
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3049 3050
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3051
	.stats_get_stats = mv88e6095_stats_get_stats,
3052 3053
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3054
	.watchdog_ops = &mv88e6097_watchdog_ops,
3055
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3056
	.reset = mv88e6352_g1_reset,
3057 3058 3059
};

static const struct mv88e6xxx_ops mv88e6172_ops = {
3060
	/* MV88E6XXX_FAMILY_6352 */
3061 3062
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3063
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3064 3065
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3066
	.port_set_link = mv88e6xxx_port_set_link,
3067
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3068
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3069
	.port_set_speed = mv88e6352_port_set_speed,
3070
	.port_tag_remap = mv88e6095_port_tag_remap,
3071
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3072
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3073
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3074
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3075
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3076
	.port_pause_config = mv88e6097_port_pause_config,
3077
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3078
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3079
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3080 3081
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3082
	.stats_get_stats = mv88e6095_stats_get_stats,
3083 3084
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3085
	.watchdog_ops = &mv88e6097_watchdog_ops,
3086
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3087
	.reset = mv88e6352_g1_reset,
3088 3089 3090
};

static const struct mv88e6xxx_ops mv88e6175_ops = {
3091
	/* MV88E6XXX_FAMILY_6351 */
3092
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3093 3094
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3095
	.port_set_link = mv88e6xxx_port_set_link,
3096
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3097
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3098
	.port_set_speed = mv88e6185_port_set_speed,
3099
	.port_tag_remap = mv88e6095_port_tag_remap,
3100
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3101
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3102
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3103
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3104
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3105
	.port_pause_config = mv88e6097_port_pause_config,
3106
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3107
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3108
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3109 3110
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3111
	.stats_get_stats = mv88e6095_stats_get_stats,
3112 3113
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3114
	.watchdog_ops = &mv88e6097_watchdog_ops,
3115
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3116
	.reset = mv88e6352_g1_reset,
3117 3118 3119
};

static const struct mv88e6xxx_ops mv88e6176_ops = {
3120
	/* MV88E6XXX_FAMILY_6352 */
3121 3122
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3123
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3124 3125
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3126
	.port_set_link = mv88e6xxx_port_set_link,
3127
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3128
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3129
	.port_set_speed = mv88e6352_port_set_speed,
3130
	.port_tag_remap = mv88e6095_port_tag_remap,
3131
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3132
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3133
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3134
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3135
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3136
	.port_pause_config = mv88e6097_port_pause_config,
3137
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3138
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3139
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3140 3141
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3142
	.stats_get_stats = mv88e6095_stats_get_stats,
3143 3144
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3145
	.watchdog_ops = &mv88e6097_watchdog_ops,
3146
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3147
	.reset = mv88e6352_g1_reset,
3148 3149 3150
};

static const struct mv88e6xxx_ops mv88e6185_ops = {
3151
	/* MV88E6XXX_FAMILY_6185 */
3152
	.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
3153 3154
	.phy_read = mv88e6xxx_phy_ppu_read,
	.phy_write = mv88e6xxx_phy_ppu_write,
3155
	.port_set_link = mv88e6xxx_port_set_link,
3156
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3157
	.port_set_speed = mv88e6185_port_set_speed,
3158
	.port_set_frame_mode = mv88e6085_port_set_frame_mode,
3159
	.port_set_egress_floods = mv88e6185_port_set_egress_floods,
3160
	.port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting,
3161
	.port_set_upstream_port = mv88e6095_port_set_upstream_port,
3162
	.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
3163 3164
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3165
	.stats_get_stats = mv88e6095_stats_get_stats,
3166 3167
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3168
	.watchdog_ops = &mv88e6097_watchdog_ops,
3169
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3170 3171
	.ppu_enable = mv88e6185_g1_ppu_enable,
	.ppu_disable = mv88e6185_g1_ppu_disable,
3172
	.reset = mv88e6185_g1_reset,
3173 3174
};

3175
static const struct mv88e6xxx_ops mv88e6190_ops = {
3176
	/* MV88E6XXX_FAMILY_6390 */
3177 3178
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3179 3180 3181 3182 3183 3184 3185
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
3186
	.port_tag_remap = mv88e6390_port_tag_remap,
3187
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3188
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3189
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3190
	.port_pause_config = mv88e6390_port_pause_config,
3191
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3192
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3193
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3194
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3195 3196
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3197
	.stats_get_stats = mv88e6390_stats_get_stats,
3198 3199
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
3200
	.watchdog_ops = &mv88e6390_watchdog_ops,
3201
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3202
	.reset = mv88e6352_g1_reset,
3203 3204 3205
};

static const struct mv88e6xxx_ops mv88e6190x_ops = {
3206
	/* MV88E6XXX_FAMILY_6390 */
3207 3208
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3209 3210 3211 3212 3213 3214 3215
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390x_port_set_speed,
3216
	.port_tag_remap = mv88e6390_port_tag_remap,
3217
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3218
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3219
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3220
	.port_pause_config = mv88e6390_port_pause_config,
3221
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3222
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3223
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3224
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3225 3226
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3227
	.stats_get_stats = mv88e6390_stats_get_stats,
3228 3229
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
3230
	.watchdog_ops = &mv88e6390_watchdog_ops,
3231
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3232
	.reset = mv88e6352_g1_reset,
3233 3234 3235
};

static const struct mv88e6xxx_ops mv88e6191_ops = {
3236
	/* MV88E6XXX_FAMILY_6390 */
3237 3238
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3239 3240 3241 3242 3243 3244 3245
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
3246
	.port_tag_remap = mv88e6390_port_tag_remap,
3247
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3248
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3249
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3250
	.port_pause_config = mv88e6390_port_pause_config,
3251
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3252
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3253
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3254
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3255 3256
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3257
	.stats_get_stats = mv88e6390_stats_get_stats,
3258 3259
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
3260
	.watchdog_ops = &mv88e6390_watchdog_ops,
3261
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3262
	.reset = mv88e6352_g1_reset,
3263 3264
};

3265
static const struct mv88e6xxx_ops mv88e6240_ops = {
3266
	/* MV88E6XXX_FAMILY_6352 */
3267 3268
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3269
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3270 3271
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3272
	.port_set_link = mv88e6xxx_port_set_link,
3273
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3274
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3275
	.port_set_speed = mv88e6352_port_set_speed,
3276
	.port_tag_remap = mv88e6095_port_tag_remap,
3277
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3278
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3279
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3280
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3281
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3282
	.port_pause_config = mv88e6097_port_pause_config,
3283
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3284
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3285
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3286 3287
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3288
	.stats_get_stats = mv88e6095_stats_get_stats,
3289 3290
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3291
	.watchdog_ops = &mv88e6097_watchdog_ops,
3292
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3293
	.reset = mv88e6352_g1_reset,
3294 3295
};

3296
static const struct mv88e6xxx_ops mv88e6290_ops = {
3297
	/* MV88E6XXX_FAMILY_6390 */
3298 3299
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3300 3301 3302 3303 3304 3305 3306
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
3307
	.port_tag_remap = mv88e6390_port_tag_remap,
3308
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3309
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3310
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3311
	.port_pause_config = mv88e6390_port_pause_config,
3312
	.port_set_cmode = mv88e6390x_port_set_cmode,
3313
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3314
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3315
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3316
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3317 3318
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3319
	.stats_get_stats = mv88e6390_stats_get_stats,
3320 3321
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
3322
	.watchdog_ops = &mv88e6390_watchdog_ops,
3323
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3324
	.reset = mv88e6352_g1_reset,
3325 3326
};

3327
static const struct mv88e6xxx_ops mv88e6320_ops = {
3328
	/* MV88E6XXX_FAMILY_6320 */
3329 3330
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3331
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3332 3333
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3334
	.port_set_link = mv88e6xxx_port_set_link,
3335
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3336
	.port_set_speed = mv88e6185_port_set_speed,
3337
	.port_tag_remap = mv88e6095_port_tag_remap,
3338
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3339
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3340
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3341
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3342
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3343
	.port_pause_config = mv88e6097_port_pause_config,
3344
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3345
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3346
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3347 3348
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3349
	.stats_get_stats = mv88e6320_stats_get_stats,
3350 3351
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3352
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3353
	.reset = mv88e6352_g1_reset,
3354 3355 3356
};

static const struct mv88e6xxx_ops mv88e6321_ops = {
3357
	/* MV88E6XXX_FAMILY_6321 */
3358 3359
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3360
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3361 3362
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3363
	.port_set_link = mv88e6xxx_port_set_link,
3364
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3365
	.port_set_speed = mv88e6185_port_set_speed,
3366
	.port_tag_remap = mv88e6095_port_tag_remap,
3367
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3368
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3369
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3370
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3371
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3372
	.port_pause_config = mv88e6097_port_pause_config,
3373
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3374
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3375
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3376 3377
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3378
	.stats_get_stats = mv88e6320_stats_get_stats,
3379 3380
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3381
	.reset = mv88e6352_g1_reset,
3382 3383
};

3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414
static const struct mv88e6xxx_ops mv88e6341_ops = {
	/* MV88E6XXX_FAMILY_6341 */
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
	.port_tag_remap = mv88e6095_port_tag_remap,
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
	.port_set_ether_type = mv88e6351_port_set_ether_type,
	.port_jumbo_config = mv88e6165_port_jumbo_config,
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
	.port_pause_config = mv88e6097_port_pause_config,
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu =  mv88e6390_g1_mgmt_rsvd2cpu,
	.reset = mv88e6352_g1_reset,
};

3415
static const struct mv88e6xxx_ops mv88e6350_ops = {
3416
	/* MV88E6XXX_FAMILY_6351 */
3417
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3418 3419
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3420
	.port_set_link = mv88e6xxx_port_set_link,
3421
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3422
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3423
	.port_set_speed = mv88e6185_port_set_speed,
3424
	.port_tag_remap = mv88e6095_port_tag_remap,
3425
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3426
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3427
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3428
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3429
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3430
	.port_pause_config = mv88e6097_port_pause_config,
3431
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3432
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3433
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3434 3435
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3436
	.stats_get_stats = mv88e6095_stats_get_stats,
3437 3438
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3439
	.watchdog_ops = &mv88e6097_watchdog_ops,
3440
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3441
	.reset = mv88e6352_g1_reset,
3442 3443 3444
};

static const struct mv88e6xxx_ops mv88e6351_ops = {
3445
	/* MV88E6XXX_FAMILY_6351 */
3446
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3447 3448
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3449
	.port_set_link = mv88e6xxx_port_set_link,
3450
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3451
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3452
	.port_set_speed = mv88e6185_port_set_speed,
3453
	.port_tag_remap = mv88e6095_port_tag_remap,
3454
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3455
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3456
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3457
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3458
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3459
	.port_pause_config = mv88e6097_port_pause_config,
3460
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3461
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3462
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3463 3464
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3465
	.stats_get_stats = mv88e6095_stats_get_stats,
3466 3467
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3468
	.watchdog_ops = &mv88e6097_watchdog_ops,
3469
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3470
	.reset = mv88e6352_g1_reset,
3471 3472 3473
};

static const struct mv88e6xxx_ops mv88e6352_ops = {
3474
	/* MV88E6XXX_FAMILY_6352 */
3475 3476
	.get_eeprom = mv88e6xxx_g2_get_eeprom16,
	.set_eeprom = mv88e6xxx_g2_set_eeprom16,
3477
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
3478 3479
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
3480
	.port_set_link = mv88e6xxx_port_set_link,
3481
	.port_set_duplex = mv88e6xxx_port_set_duplex,
3482
	.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
3483
	.port_set_speed = mv88e6352_port_set_speed,
3484
	.port_tag_remap = mv88e6095_port_tag_remap,
3485
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3486
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3487
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3488
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3489
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3490
	.port_pause_config = mv88e6097_port_pause_config,
3491
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3492
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3493
	.stats_snapshot = mv88e6320_g1_stats_snapshot,
3494 3495
	.stats_get_sset_count = mv88e6095_stats_get_sset_count,
	.stats_get_strings = mv88e6095_stats_get_strings,
3496
	.stats_get_stats = mv88e6095_stats_get_stats,
3497 3498
	.g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6095_g1_set_egress_port,
3499
	.watchdog_ops = &mv88e6097_watchdog_ops,
3500
	.mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu,
3501
	.reset = mv88e6352_g1_reset,
3502 3503
};

3504
static const struct mv88e6xxx_ops mv88e6390_ops = {
3505
	/* MV88E6XXX_FAMILY_6390 */
3506 3507
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3508 3509 3510 3511 3512 3513 3514
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390_port_set_speed,
3515
	.port_tag_remap = mv88e6390_port_tag_remap,
3516
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3517
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3518
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3519
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3520
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3521
	.port_pause_config = mv88e6390_port_pause_config,
3522
	.port_set_cmode = mv88e6390x_port_set_cmode,
3523
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3524
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3525
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3526
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3527 3528
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3529
	.stats_get_stats = mv88e6390_stats_get_stats,
3530 3531
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
3532
	.watchdog_ops = &mv88e6390_watchdog_ops,
3533
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3534
	.reset = mv88e6352_g1_reset,
3535 3536 3537
};

static const struct mv88e6xxx_ops mv88e6390x_ops = {
3538
	/* MV88E6XXX_FAMILY_6390 */
3539 3540
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
3541 3542 3543 3544 3545 3546 3547
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_set_duplex = mv88e6xxx_port_set_duplex,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed = mv88e6390x_port_set_speed,
3548
	.port_tag_remap = mv88e6390_port_tag_remap,
3549
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
3550
	.port_set_egress_floods = mv88e6352_port_set_egress_floods,
3551
	.port_set_ether_type = mv88e6351_port_set_ether_type,
3552
	.port_jumbo_config = mv88e6165_port_jumbo_config,
3553
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
3554
	.port_pause_config = mv88e6390_port_pause_config,
3555
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
3556
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
3557
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
3558
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
3559 3560
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
3561
	.stats_get_stats = mv88e6390_stats_get_stats,
3562 3563
	.g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
	.g1_set_egress_port = mv88e6390_g1_set_egress_port,
3564
	.watchdog_ops = &mv88e6390_watchdog_ops,
3565
	.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
3566
	.reset = mv88e6352_g1_reset,
3567 3568
};

3569 3570 3571 3572 3573 3574 3575
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
	[MV88E6085] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6085,
		.family = MV88E6XXX_FAMILY_6097,
		.name = "Marvell 88E6085",
		.num_databases = 4096,
		.num_ports = 10,
3576
		.port_base_addr = 0x10,
3577
		.global1_addr = 0x1b,
3578
		.age_time_coeff = 15000,
3579
		.g1_irqs = 8,
3580
		.atu_move_port_mask = 0xf,
3581
		.tag_protocol = DSA_TAG_PROTO_DSA,
3582
		.flags = MV88E6XXX_FLAGS_FAMILY_6097,
3583
		.ops = &mv88e6085_ops,
3584 3585 3586 3587 3588 3589 3590 3591
	},

	[MV88E6095] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6095,
		.family = MV88E6XXX_FAMILY_6095,
		.name = "Marvell 88E6095/88E6095F",
		.num_databases = 256,
		.num_ports = 11,
3592
		.port_base_addr = 0x10,
3593
		.global1_addr = 0x1b,
3594
		.age_time_coeff = 15000,
3595
		.g1_irqs = 8,
3596
		.atu_move_port_mask = 0xf,
3597
		.tag_protocol = DSA_TAG_PROTO_DSA,
3598
		.flags = MV88E6XXX_FLAGS_FAMILY_6095,
3599
		.ops = &mv88e6095_ops,
3600 3601
	},

3602 3603 3604 3605 3606 3607 3608 3609 3610
	[MV88E6097] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6097,
		.family = MV88E6XXX_FAMILY_6097,
		.name = "Marvell 88E6097/88E6097F",
		.num_databases = 4096,
		.num_ports = 11,
		.port_base_addr = 0x10,
		.global1_addr = 0x1b,
		.age_time_coeff = 15000,
3611
		.g1_irqs = 8,
3612
		.atu_move_port_mask = 0xf,
3613
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3614 3615 3616 3617
		.flags = MV88E6XXX_FLAGS_FAMILY_6097,
		.ops = &mv88e6097_ops,
	},

3618 3619 3620 3621 3622 3623
	[MV88E6123] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6123,
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6123",
		.num_databases = 4096,
		.num_ports = 3,
3624
		.port_base_addr = 0x10,
3625
		.global1_addr = 0x1b,
3626
		.age_time_coeff = 15000,
3627
		.g1_irqs = 9,
3628
		.atu_move_port_mask = 0xf,
3629
		.tag_protocol = DSA_TAG_PROTO_DSA,
3630
		.flags = MV88E6XXX_FLAGS_FAMILY_6165,
3631
		.ops = &mv88e6123_ops,
3632 3633 3634 3635 3636 3637 3638 3639
	},

	[MV88E6131] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6131,
		.family = MV88E6XXX_FAMILY_6185,
		.name = "Marvell 88E6131",
		.num_databases = 256,
		.num_ports = 8,
3640
		.port_base_addr = 0x10,
3641
		.global1_addr = 0x1b,
3642
		.age_time_coeff = 15000,
3643
		.g1_irqs = 9,
3644
		.atu_move_port_mask = 0xf,
3645
		.tag_protocol = DSA_TAG_PROTO_DSA,
3646
		.flags = MV88E6XXX_FLAGS_FAMILY_6185,
3647
		.ops = &mv88e6131_ops,
3648 3649
	},

3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664
	[MV88E6141] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6141,
		.family = MV88E6XXX_FAMILY_6341,
		.name = "Marvell 88E6341",
		.num_databases = 4096,
		.num_ports = 6,
		.port_base_addr = 0x10,
		.global1_addr = 0x1b,
		.age_time_coeff = 3750,
		.atu_move_port_mask = 0x1f,
		.tag_protocol = DSA_TAG_PROTO_EDSA,
		.flags = MV88E6XXX_FLAGS_FAMILY_6341,
		.ops = &mv88e6141_ops,
	},

3665 3666 3667 3668 3669 3670
	[MV88E6161] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6161,
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6161",
		.num_databases = 4096,
		.num_ports = 6,
3671
		.port_base_addr = 0x10,
3672
		.global1_addr = 0x1b,
3673
		.age_time_coeff = 15000,
3674
		.g1_irqs = 9,
3675
		.atu_move_port_mask = 0xf,
3676
		.tag_protocol = DSA_TAG_PROTO_DSA,
3677
		.flags = MV88E6XXX_FLAGS_FAMILY_6165,
3678
		.ops = &mv88e6161_ops,
3679 3680 3681 3682 3683 3684 3685 3686
	},

	[MV88E6165] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6165,
		.family = MV88E6XXX_FAMILY_6165,
		.name = "Marvell 88E6165",
		.num_databases = 4096,
		.num_ports = 6,
3687
		.port_base_addr = 0x10,
3688
		.global1_addr = 0x1b,
3689
		.age_time_coeff = 15000,
3690
		.g1_irqs = 9,
3691
		.atu_move_port_mask = 0xf,
3692
		.tag_protocol = DSA_TAG_PROTO_DSA,
3693
		.flags = MV88E6XXX_FLAGS_FAMILY_6165,
3694
		.ops = &mv88e6165_ops,
3695 3696 3697 3698 3699 3700 3701 3702
	},

	[MV88E6171] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6171,
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6171",
		.num_databases = 4096,
		.num_ports = 7,
3703
		.port_base_addr = 0x10,
3704
		.global1_addr = 0x1b,
3705
		.age_time_coeff = 15000,
3706
		.g1_irqs = 9,
3707
		.atu_move_port_mask = 0xf,
3708
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3709
		.flags = MV88E6XXX_FLAGS_FAMILY_6351,
3710
		.ops = &mv88e6171_ops,
3711 3712 3713 3714 3715 3716 3717 3718
	},

	[MV88E6172] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6172,
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6172",
		.num_databases = 4096,
		.num_ports = 7,
3719
		.port_base_addr = 0x10,
3720
		.global1_addr = 0x1b,
3721
		.age_time_coeff = 15000,
3722
		.g1_irqs = 9,
3723
		.atu_move_port_mask = 0xf,
3724
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3725
		.flags = MV88E6XXX_FLAGS_FAMILY_6352,
3726
		.ops = &mv88e6172_ops,
3727 3728 3729 3730 3731 3732 3733 3734
	},

	[MV88E6175] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6175,
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6175",
		.num_databases = 4096,
		.num_ports = 7,
3735
		.port_base_addr = 0x10,
3736
		.global1_addr = 0x1b,
3737
		.age_time_coeff = 15000,
3738
		.g1_irqs = 9,
3739
		.atu_move_port_mask = 0xf,
3740
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3741
		.flags = MV88E6XXX_FLAGS_FAMILY_6351,
3742
		.ops = &mv88e6175_ops,
3743 3744 3745 3746 3747 3748 3749 3750
	},

	[MV88E6176] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6176,
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6176",
		.num_databases = 4096,
		.num_ports = 7,
3751
		.port_base_addr = 0x10,
3752
		.global1_addr = 0x1b,
3753
		.age_time_coeff = 15000,
3754
		.g1_irqs = 9,
3755
		.atu_move_port_mask = 0xf,
3756
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3757
		.flags = MV88E6XXX_FLAGS_FAMILY_6352,
3758
		.ops = &mv88e6176_ops,
3759 3760 3761 3762 3763 3764 3765 3766
	},

	[MV88E6185] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6185,
		.family = MV88E6XXX_FAMILY_6185,
		.name = "Marvell 88E6185",
		.num_databases = 256,
		.num_ports = 10,
3767
		.port_base_addr = 0x10,
3768
		.global1_addr = 0x1b,
3769
		.age_time_coeff = 15000,
3770
		.g1_irqs = 8,
3771
		.atu_move_port_mask = 0xf,
3772
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3773
		.flags = MV88E6XXX_FLAGS_FAMILY_6185,
3774
		.ops = &mv88e6185_ops,
3775 3776
	},

3777 3778 3779 3780 3781 3782 3783 3784
	[MV88E6190] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6190,
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6190",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3785
		.tag_protocol = DSA_TAG_PROTO_DSA,
3786
		.age_time_coeff = 3750,
3787
		.g1_irqs = 9,
3788
		.atu_move_port_mask = 0x1f,
3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800
		.flags = MV88E6XXX_FLAGS_FAMILY_6390,
		.ops = &mv88e6190_ops,
	},

	[MV88E6190X] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6190X,
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6190X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3801
		.age_time_coeff = 3750,
3802
		.g1_irqs = 9,
3803
		.atu_move_port_mask = 0x1f,
3804
		.tag_protocol = DSA_TAG_PROTO_DSA,
3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816
		.flags = MV88E6XXX_FLAGS_FAMILY_6390,
		.ops = &mv88e6190x_ops,
	},

	[MV88E6191] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6191,
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6191",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3817
		.age_time_coeff = 3750,
3818
		.g1_irqs = 9,
3819
		.atu_move_port_mask = 0x1f,
3820
		.tag_protocol = DSA_TAG_PROTO_DSA,
3821
		.flags = MV88E6XXX_FLAGS_FAMILY_6390,
3822
		.ops = &mv88e6191_ops,
3823 3824
	},

3825 3826 3827 3828 3829 3830
	[MV88E6240] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6240,
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6240",
		.num_databases = 4096,
		.num_ports = 7,
3831
		.port_base_addr = 0x10,
3832
		.global1_addr = 0x1b,
3833
		.age_time_coeff = 15000,
3834
		.g1_irqs = 9,
3835
		.atu_move_port_mask = 0xf,
3836
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3837
		.flags = MV88E6XXX_FLAGS_FAMILY_6352,
3838
		.ops = &mv88e6240_ops,
3839 3840
	},

3841 3842 3843 3844 3845 3846 3847 3848
	[MV88E6290] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6290,
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6290",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3849
		.age_time_coeff = 3750,
3850
		.g1_irqs = 9,
3851
		.atu_move_port_mask = 0x1f,
3852
		.tag_protocol = DSA_TAG_PROTO_DSA,
3853 3854 3855 3856
		.flags = MV88E6XXX_FLAGS_FAMILY_6390,
		.ops = &mv88e6290_ops,
	},

3857 3858 3859 3860 3861 3862
	[MV88E6320] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6320,
		.family = MV88E6XXX_FAMILY_6320,
		.name = "Marvell 88E6320",
		.num_databases = 4096,
		.num_ports = 7,
3863
		.port_base_addr = 0x10,
3864
		.global1_addr = 0x1b,
3865
		.age_time_coeff = 15000,
3866
		.g1_irqs = 8,
3867
		.atu_move_port_mask = 0xf,
3868
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3869
		.flags = MV88E6XXX_FLAGS_FAMILY_6320,
3870
		.ops = &mv88e6320_ops,
3871 3872 3873 3874 3875 3876 3877 3878
	},

	[MV88E6321] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6321,
		.family = MV88E6XXX_FAMILY_6320,
		.name = "Marvell 88E6321",
		.num_databases = 4096,
		.num_ports = 7,
3879
		.port_base_addr = 0x10,
3880
		.global1_addr = 0x1b,
3881
		.age_time_coeff = 15000,
3882
		.g1_irqs = 8,
3883
		.atu_move_port_mask = 0xf,
3884
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3885
		.flags = MV88E6XXX_FLAGS_FAMILY_6320,
3886
		.ops = &mv88e6321_ops,
3887 3888
	},

3889 3890 3891 3892 3893 3894 3895 3896 3897
	[MV88E6341] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6341,
		.family = MV88E6XXX_FAMILY_6341,
		.name = "Marvell 88E6341",
		.num_databases = 4096,
		.num_ports = 6,
		.port_base_addr = 0x10,
		.global1_addr = 0x1b,
		.age_time_coeff = 3750,
3898
		.atu_move_port_mask = 0x1f,
3899 3900 3901 3902 3903
		.tag_protocol = DSA_TAG_PROTO_EDSA,
		.flags = MV88E6XXX_FLAGS_FAMILY_6341,
		.ops = &mv88e6341_ops,
	},

3904 3905 3906 3907 3908 3909
	[MV88E6350] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6350,
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6350",
		.num_databases = 4096,
		.num_ports = 7,
3910
		.port_base_addr = 0x10,
3911
		.global1_addr = 0x1b,
3912
		.age_time_coeff = 15000,
3913
		.g1_irqs = 9,
3914
		.atu_move_port_mask = 0xf,
3915
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3916
		.flags = MV88E6XXX_FLAGS_FAMILY_6351,
3917
		.ops = &mv88e6350_ops,
3918 3919 3920 3921 3922 3923 3924 3925
	},

	[MV88E6351] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6351,
		.family = MV88E6XXX_FAMILY_6351,
		.name = "Marvell 88E6351",
		.num_databases = 4096,
		.num_ports = 7,
3926
		.port_base_addr = 0x10,
3927
		.global1_addr = 0x1b,
3928
		.age_time_coeff = 15000,
3929
		.g1_irqs = 9,
3930
		.atu_move_port_mask = 0xf,
3931
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3932
		.flags = MV88E6XXX_FLAGS_FAMILY_6351,
3933
		.ops = &mv88e6351_ops,
3934 3935 3936 3937 3938 3939 3940 3941
	},

	[MV88E6352] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6352,
		.family = MV88E6XXX_FAMILY_6352,
		.name = "Marvell 88E6352",
		.num_databases = 4096,
		.num_ports = 7,
3942
		.port_base_addr = 0x10,
3943
		.global1_addr = 0x1b,
3944
		.age_time_coeff = 15000,
3945
		.g1_irqs = 9,
3946
		.atu_move_port_mask = 0xf,
3947
		.tag_protocol = DSA_TAG_PROTO_EDSA,
3948
		.flags = MV88E6XXX_FLAGS_FAMILY_6352,
3949
		.ops = &mv88e6352_ops,
3950
	},
3951 3952 3953 3954 3955 3956 3957 3958
	[MV88E6390] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6390,
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6390",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3959
		.age_time_coeff = 3750,
3960
		.g1_irqs = 9,
3961
		.atu_move_port_mask = 0x1f,
3962
		.tag_protocol = DSA_TAG_PROTO_DSA,
3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973
		.flags = MV88E6XXX_FLAGS_FAMILY_6390,
		.ops = &mv88e6390_ops,
	},
	[MV88E6390X] = {
		.prod_num = PORT_SWITCH_ID_PROD_NUM_6390X,
		.family = MV88E6XXX_FAMILY_6390,
		.name = "Marvell 88E6390X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.port_base_addr = 0x0,
		.global1_addr = 0x1b,
3974
		.age_time_coeff = 3750,
3975
		.g1_irqs = 9,
3976
		.atu_move_port_mask = 0x1f,
3977
		.tag_protocol = DSA_TAG_PROTO_DSA,
3978 3979 3980
		.flags = MV88E6XXX_FLAGS_FAMILY_6390,
		.ops = &mv88e6390x_ops,
	},
3981 3982
};

3983
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
3984
{
3985
	int i;
3986

3987 3988 3989
	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
		if (mv88e6xxx_table[i].prod_num == prod_num)
			return &mv88e6xxx_table[i];
3990 3991 3992 3993

	return NULL;
}

3994
static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
3995 3996
{
	const struct mv88e6xxx_info *info;
3997 3998 3999
	unsigned int prod_num, rev;
	u16 id;
	int err;
4000

4001 4002 4003 4004 4005
	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_port_read(chip, 0, PORT_SWITCH_ID, &id);
	mutex_unlock(&chip->reg_lock);
	if (err)
		return err;
4006 4007 4008 4009 4010 4011 4012 4013

	prod_num = (id & 0xfff0) >> 4;
	rev = id & 0x000f;

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

4014
	/* Update the compatible info with the probed one */
4015
	chip->info = info;
4016

4017 4018 4019 4020
	err = mv88e6xxx_g2_require(chip);
	if (err)
		return err;

4021 4022
	dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
		 chip->info->prod_num, chip->info->name, rev);
4023 4024 4025 4026

	return 0;
}

4027
static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
4028
{
4029
	struct mv88e6xxx_chip *chip;
4030

4031 4032
	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
4033 4034
		return NULL;

4035
	chip->dev = dev;
4036

4037
	mutex_init(&chip->reg_lock);
4038
	INIT_LIST_HEAD(&chip->mdios);
4039

4040
	return chip;
4041 4042
}

4043 4044
static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
{
4045
	if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
4046 4047 4048
		mv88e6xxx_ppu_state_init(chip);
}

4049 4050
static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
{
4051
	if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
4052 4053 4054
		mv88e6xxx_ppu_state_destroy(chip);
}

4055
static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
4056 4057
			      struct mii_bus *bus, int sw_addr)
{
4058
	if (sw_addr == 0)
4059
		chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
4060
	else if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_MULTI_CHIP))
4061
		chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
4062 4063 4064
	else
		return -EINVAL;

4065 4066
	chip->bus = bus;
	chip->sw_addr = sw_addr;
4067 4068 4069 4070

	return 0;
}

4071 4072
static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds)
{
V
Vivien Didelot 已提交
4073
	struct mv88e6xxx_chip *chip = ds->priv;
4074

4075
	return chip->info->tag_protocol;
4076 4077
}

4078 4079 4080
static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
				       struct device *host_dev, int sw_addr,
				       void **priv)
4081
{
4082
	struct mv88e6xxx_chip *chip;
4083
	struct mii_bus *bus;
4084
	int err;
4085

4086
	bus = dsa_host_dev_to_mii_bus(host_dev);
4087 4088 4089
	if (!bus)
		return NULL;

4090 4091
	chip = mv88e6xxx_alloc_chip(dsa_dev);
	if (!chip)
4092 4093
		return NULL;

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

4097
	err = mv88e6xxx_smi_init(chip, bus, sw_addr);
4098 4099 4100
	if (err)
		goto free;

4101
	err = mv88e6xxx_detect(chip);
4102
	if (err)
4103
		goto free;
4104

4105 4106 4107 4108 4109 4110
	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_switch_reset(chip);
	mutex_unlock(&chip->reg_lock);
	if (err)
		goto free;

4111 4112
	mv88e6xxx_phy_init(chip);

4113
	err = mv88e6xxx_mdios_register(chip, NULL);
4114
	if (err)
4115
		goto free;
4116

4117
	*priv = chip;
4118

4119
	return chip->info->name;
4120
free:
4121
	devm_kfree(dsa_dev, chip);
4122 4123

	return NULL;
4124 4125
}

4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140
static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port,
				      const struct switchdev_obj_port_mdb *mdb,
				      struct switchdev_trans *trans)
{
	/* We don't need any dynamic resource from the kernel (yet),
	 * so skip the prepare phase.
	 */

	return 0;
}

static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
				   const struct switchdev_obj_port_mdb *mdb,
				   struct switchdev_trans *trans)
{
V
Vivien Didelot 已提交
4141
	struct mv88e6xxx_chip *chip = ds->priv;
4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152

	mutex_lock(&chip->reg_lock);
	if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
					 GLOBAL_ATU_DATA_STATE_MC_STATIC))
		netdev_err(ds->ports[port].netdev, "failed to load multicast MAC address\n");
	mutex_unlock(&chip->reg_lock);
}

static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
				  const struct switchdev_obj_port_mdb *mdb)
{
V
Vivien Didelot 已提交
4153
	struct mv88e6xxx_chip *chip = ds->priv;
4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167
	int err;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
					   GLOBAL_ATU_DATA_STATE_UNUSED);
	mutex_unlock(&chip->reg_lock);

	return err;
}

static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port,
				   struct switchdev_obj_port_mdb *mdb,
				   int (*cb)(struct switchdev_obj *obj))
{
V
Vivien Didelot 已提交
4168
	struct mv88e6xxx_chip *chip = ds->priv;
4169 4170 4171 4172 4173 4174 4175 4176 4177
	int err;

	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_port_db_dump(chip, port, &mdb->obj, cb);
	mutex_unlock(&chip->reg_lock);

	return err;
}

4178
static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
4179
	.probe			= mv88e6xxx_drv_probe,
4180
	.get_tag_protocol	= mv88e6xxx_get_tag_protocol,
4181 4182 4183 4184 4185 4186 4187 4188
	.setup			= mv88e6xxx_setup,
	.set_addr		= mv88e6xxx_set_addr,
	.adjust_link		= mv88e6xxx_adjust_link,
	.get_strings		= mv88e6xxx_get_strings,
	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
	.get_sset_count		= mv88e6xxx_get_sset_count,
	.set_eee		= mv88e6xxx_set_eee,
	.get_eee		= mv88e6xxx_get_eee,
4189
	.get_eeprom_len		= mv88e6xxx_get_eeprom_len,
4190 4191 4192 4193
	.get_eeprom		= mv88e6xxx_get_eeprom,
	.set_eeprom		= mv88e6xxx_set_eeprom,
	.get_regs_len		= mv88e6xxx_get_regs_len,
	.get_regs		= mv88e6xxx_get_regs,
4194
	.set_ageing_time	= mv88e6xxx_set_ageing_time,
4195 4196 4197
	.port_bridge_join	= mv88e6xxx_port_bridge_join,
	.port_bridge_leave	= mv88e6xxx_port_bridge_leave,
	.port_stp_state_set	= mv88e6xxx_port_stp_state_set,
4198
	.port_fast_age		= mv88e6xxx_port_fast_age,
4199 4200 4201 4202 4203 4204 4205 4206 4207
	.port_vlan_filtering	= mv88e6xxx_port_vlan_filtering,
	.port_vlan_prepare	= mv88e6xxx_port_vlan_prepare,
	.port_vlan_add		= mv88e6xxx_port_vlan_add,
	.port_vlan_del		= mv88e6xxx_port_vlan_del,
	.port_vlan_dump		= mv88e6xxx_port_vlan_dump,
	.port_fdb_prepare       = mv88e6xxx_port_fdb_prepare,
	.port_fdb_add           = mv88e6xxx_port_fdb_add,
	.port_fdb_del           = mv88e6xxx_port_fdb_del,
	.port_fdb_dump          = mv88e6xxx_port_fdb_dump,
4208 4209 4210 4211
	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
	.port_mdb_add           = mv88e6xxx_port_mdb_add,
	.port_mdb_del           = mv88e6xxx_port_mdb_del,
	.port_mdb_dump          = mv88e6xxx_port_mdb_dump,
4212 4213
};

4214 4215 4216 4217
static struct dsa_switch_driver mv88e6xxx_switch_drv = {
	.ops			= &mv88e6xxx_switch_ops,
};

4218
static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
4219
{
4220
	struct device *dev = chip->dev;
4221 4222
	struct dsa_switch *ds;

4223
	ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);
4224 4225 4226
	if (!ds)
		return -ENOMEM;

4227
	ds->priv = chip;
4228
	ds->ops = &mv88e6xxx_switch_ops;
4229 4230
	ds->ageing_time_min = chip->info->age_time_coeff;
	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
4231 4232 4233

	dev_set_drvdata(dev, ds);

4234
	return dsa_register_switch(ds, dev);
4235 4236
}

4237
static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
4238
{
4239
	dsa_unregister_switch(chip->ds);
4240 4241
}

4242
static int mv88e6xxx_probe(struct mdio_device *mdiodev)
4243
{
4244
	struct device *dev = &mdiodev->dev;
4245
	struct device_node *np = dev->of_node;
4246
	const struct mv88e6xxx_info *compat_info;
4247
	struct mv88e6xxx_chip *chip;
4248
	u32 eeprom_len;
4249
	int err;
4250

4251 4252 4253 4254
	compat_info = of_device_get_match_data(dev);
	if (!compat_info)
		return -EINVAL;

4255 4256
	chip = mv88e6xxx_alloc_chip(dev);
	if (!chip)
4257 4258
		return -ENOMEM;

4259
	chip->info = compat_info;
4260

4261
	err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr);
4262 4263
	if (err)
		return err;
4264

4265 4266 4267 4268
	chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
	if (IS_ERR(chip->reset))
		return PTR_ERR(chip->reset);

4269
	err = mv88e6xxx_detect(chip);
4270 4271
	if (err)
		return err;
4272

4273 4274
	mv88e6xxx_phy_init(chip);

4275
	if (chip->info->ops->get_eeprom &&
4276
	    !of_property_read_u32(np, "eeprom-length", &eeprom_len))
4277
		chip->eeprom_len = eeprom_len;
4278

4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309
	mutex_lock(&chip->reg_lock);
	err = mv88e6xxx_switch_reset(chip);
	mutex_unlock(&chip->reg_lock);
	if (err)
		goto out;

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

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

		if (err)
			goto out;

		if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) {
			err = mv88e6xxx_g2_irq_setup(chip);
			if (err)
				goto out_g1_irq;
		}
	}

4310
	err = mv88e6xxx_mdios_register(chip, np);
4311
	if (err)
4312
		goto out_g2_irq;
4313

4314
	err = mv88e6xxx_register_switch(chip);
4315 4316
	if (err)
		goto out_mdio;
4317

4318
	return 0;
4319 4320

out_mdio:
4321
	mv88e6xxx_mdios_unregister(chip);
4322
out_g2_irq:
4323
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT) && chip->irq > 0)
4324 4325
		mv88e6xxx_g2_irq_free(chip);
out_g1_irq:
4326 4327
	if (chip->irq > 0) {
		mutex_lock(&chip->reg_lock);
4328
		mv88e6xxx_g1_irq_free(chip);
4329 4330
		mutex_unlock(&chip->reg_lock);
	}
4331 4332
out:
	return err;
4333
}
4334 4335 4336 4337

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

4340
	mv88e6xxx_phy_destroy(chip);
4341
	mv88e6xxx_unregister_switch(chip);
4342
	mv88e6xxx_mdios_unregister(chip);
4343

4344 4345 4346 4347 4348
	if (chip->irq > 0) {
		if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT))
			mv88e6xxx_g2_irq_free(chip);
		mv88e6xxx_g1_irq_free(chip);
	}
4349 4350 4351
}

static const struct of_device_id mv88e6xxx_of_match[] = {
4352 4353 4354 4355
	{
		.compatible = "marvell,mv88e6085",
		.data = &mv88e6xxx_table[MV88E6085],
	},
4356 4357 4358 4359
	{
		.compatible = "marvell,mv88e6190",
		.data = &mv88e6xxx_table[MV88E6190],
	},
4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375
	{ /* sentinel */ },
};

MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match);

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

static int __init mv88e6xxx_init(void)
{
4376
	register_switch_driver(&mv88e6xxx_switch_drv);
4377 4378
	return mdio_driver_register(&mv88e6xxx_driver);
}
4379 4380 4381 4382
module_init(mv88e6xxx_init);

static void __exit mv88e6xxx_cleanup(void)
{
4383
	mdio_driver_unregister(&mv88e6xxx_driver);
4384
	unregister_switch_driver(&mv88e6xxx_switch_drv);
4385 4386
}
module_exit(mv88e6xxx_cleanup);
4387 4388 4389 4390

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