12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2fad09c73SVivien Didelot /* 3fad09c73SVivien Didelot * Marvell 88e6xxx Ethernet switch single-chip support 4fad09c73SVivien Didelot * 5fad09c73SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 6fad09c73SVivien Didelot * 7fad09c73SVivien Didelot * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 8fad09c73SVivien Didelot * 94333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 104333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 11fad09c73SVivien Didelot */ 12fad09c73SVivien Didelot 1319fb7f69SVivien Didelot #include <linux/bitfield.h> 14fad09c73SVivien Didelot #include <linux/delay.h> 155bded825SVladimir Oltean #include <linux/dsa/mv88e6xxx.h> 16fad09c73SVivien Didelot #include <linux/etherdevice.h> 17fad09c73SVivien Didelot #include <linux/ethtool.h> 18fad09c73SVivien Didelot #include <linux/if_bridge.h> 19dc30c35bSAndrew Lunn #include <linux/interrupt.h> 20dc30c35bSAndrew Lunn #include <linux/irq.h> 21dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 22fad09c73SVivien Didelot #include <linux/jiffies.h> 23fad09c73SVivien Didelot #include <linux/list.h> 24fad09c73SVivien Didelot #include <linux/mdio.h> 25fad09c73SVivien Didelot #include <linux/module.h> 26fad09c73SVivien Didelot #include <linux/of_device.h> 27dc30c35bSAndrew Lunn #include <linux/of_irq.h> 28fad09c73SVivien Didelot #include <linux/of_mdio.h> 29877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h> 30fad09c73SVivien Didelot #include <linux/netdevice.h> 31fad09c73SVivien Didelot #include <linux/gpio/consumer.h> 32c9a2356fSRussell King #include <linux/phylink.h> 33fad09c73SVivien Didelot #include <net/dsa.h> 34ec561276SVivien Didelot 354d5f2ba7SVivien Didelot #include "chip.h" 369dd43aa2SAndrew Lunn #include "devlink.h" 37a935c052SVivien Didelot #include "global1.h" 38ec561276SVivien Didelot #include "global2.h" 39c6fe0ad2SBrandon Streiff #include "hwtstamp.h" 4010fa5bfcSAndrew Lunn #include "phy.h" 4118abed21SVivien Didelot #include "port.h" 422fa8d3afSBrandon Streiff #include "ptp.h" 436d91782fSAndrew Lunn #include "serdes.h" 44e7ba0fadSVivien Didelot #include "smi.h" 45fad09c73SVivien Didelot 46fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 47fad09c73SVivien Didelot { 48fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 49fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 50fad09c73SVivien Didelot dump_stack(); 51fad09c73SVivien Didelot } 52fad09c73SVivien Didelot } 53fad09c73SVivien Didelot 54ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 55fad09c73SVivien Didelot { 56fad09c73SVivien Didelot int err; 57fad09c73SVivien Didelot 58fad09c73SVivien Didelot assert_reg_lock(chip); 59fad09c73SVivien Didelot 60fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 61fad09c73SVivien Didelot if (err) 62fad09c73SVivien Didelot return err; 63fad09c73SVivien Didelot 64fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 65fad09c73SVivien Didelot addr, reg, *val); 66fad09c73SVivien Didelot 67fad09c73SVivien Didelot return 0; 68fad09c73SVivien Didelot } 69fad09c73SVivien Didelot 70ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 71fad09c73SVivien Didelot { 72fad09c73SVivien Didelot int err; 73fad09c73SVivien Didelot 74fad09c73SVivien Didelot assert_reg_lock(chip); 75fad09c73SVivien Didelot 76fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 77fad09c73SVivien Didelot if (err) 78fad09c73SVivien Didelot return err; 79fad09c73SVivien Didelot 80fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 81fad09c73SVivien Didelot addr, reg, val); 82fad09c73SVivien Didelot 83fad09c73SVivien Didelot return 0; 84fad09c73SVivien Didelot } 85fad09c73SVivien Didelot 86683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, 87683f2244SVivien Didelot u16 mask, u16 val) 88683f2244SVivien Didelot { 89683f2244SVivien Didelot u16 data; 90683f2244SVivien Didelot int err; 91683f2244SVivien Didelot int i; 92683f2244SVivien Didelot 93683f2244SVivien Didelot /* There's no bus specific operation to wait for a mask */ 94683f2244SVivien Didelot for (i = 0; i < 16; i++) { 95683f2244SVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &data); 96683f2244SVivien Didelot if (err) 97683f2244SVivien Didelot return err; 98683f2244SVivien Didelot 99683f2244SVivien Didelot if ((data & mask) == val) 100683f2244SVivien Didelot return 0; 101683f2244SVivien Didelot 102683f2244SVivien Didelot usleep_range(1000, 2000); 103683f2244SVivien Didelot } 104683f2244SVivien Didelot 105683f2244SVivien Didelot dev_err(chip->dev, "Timeout while waiting for switch\n"); 106683f2244SVivien Didelot return -ETIMEDOUT; 107683f2244SVivien Didelot } 108683f2244SVivien Didelot 10919fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, 11019fb7f69SVivien Didelot int bit, int val) 11119fb7f69SVivien Didelot { 11219fb7f69SVivien Didelot return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit), 11319fb7f69SVivien Didelot val ? BIT(bit) : 0x0000); 11419fb7f69SVivien Didelot } 11519fb7f69SVivien Didelot 11610fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 117a3c53be5SAndrew Lunn { 118a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 119a3c53be5SAndrew Lunn 120a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 121a3c53be5SAndrew Lunn list); 122a3c53be5SAndrew Lunn if (!mdio_bus) 123a3c53be5SAndrew Lunn return NULL; 124a3c53be5SAndrew Lunn 125a3c53be5SAndrew Lunn return mdio_bus->bus; 126a3c53be5SAndrew Lunn } 127a3c53be5SAndrew Lunn 128dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d) 129dc30c35bSAndrew Lunn { 130dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 131dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 132dc30c35bSAndrew Lunn 133dc30c35bSAndrew Lunn chip->g1_irq.masked |= (1 << n); 134dc30c35bSAndrew Lunn } 135dc30c35bSAndrew Lunn 136dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 137dc30c35bSAndrew Lunn { 138dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 139dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 140dc30c35bSAndrew Lunn 141dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 142dc30c35bSAndrew Lunn } 143dc30c35bSAndrew Lunn 144294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 145dc30c35bSAndrew Lunn { 146dc30c35bSAndrew Lunn unsigned int nhandled = 0; 147dc30c35bSAndrew Lunn unsigned int sub_irq; 148dc30c35bSAndrew Lunn unsigned int n; 149dc30c35bSAndrew Lunn u16 reg; 1507c0db24cSJohn David Anglin u16 ctl1; 151dc30c35bSAndrew Lunn int err; 152dc30c35bSAndrew Lunn 153c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 15482466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 155c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 156dc30c35bSAndrew Lunn 157dc30c35bSAndrew Lunn if (err) 158dc30c35bSAndrew Lunn goto out; 159dc30c35bSAndrew Lunn 1607c0db24cSJohn David Anglin do { 161dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 162dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1637c0db24cSJohn David Anglin sub_irq = irq_find_mapping(chip->g1_irq.domain, 1647c0db24cSJohn David Anglin n); 165dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 166dc30c35bSAndrew Lunn ++nhandled; 167dc30c35bSAndrew Lunn } 168dc30c35bSAndrew Lunn } 1697c0db24cSJohn David Anglin 170c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1717c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 1727c0db24cSJohn David Anglin if (err) 1737c0db24cSJohn David Anglin goto unlock; 1747c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 1757c0db24cSJohn David Anglin unlock: 176c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1777c0db24cSJohn David Anglin if (err) 1787c0db24cSJohn David Anglin goto out; 1797c0db24cSJohn David Anglin ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 1807c0db24cSJohn David Anglin } while (reg & ctl1); 1817c0db24cSJohn David Anglin 182dc30c35bSAndrew Lunn out: 183dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 184dc30c35bSAndrew Lunn } 185dc30c35bSAndrew Lunn 186294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 187294d711eSAndrew Lunn { 188294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 189294d711eSAndrew Lunn 190294d711eSAndrew Lunn return mv88e6xxx_g1_irq_thread_work(chip); 191294d711eSAndrew Lunn } 192294d711eSAndrew Lunn 193dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 194dc30c35bSAndrew Lunn { 195dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 196dc30c35bSAndrew Lunn 197c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 198dc30c35bSAndrew Lunn } 199dc30c35bSAndrew Lunn 200dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 201dc30c35bSAndrew Lunn { 202dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 203dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 204dc30c35bSAndrew Lunn u16 reg; 205dc30c35bSAndrew Lunn int err; 206dc30c35bSAndrew Lunn 207d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 208dc30c35bSAndrew Lunn if (err) 209dc30c35bSAndrew Lunn goto out; 210dc30c35bSAndrew Lunn 211dc30c35bSAndrew Lunn reg &= ~mask; 212dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 213dc30c35bSAndrew Lunn 214d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 215dc30c35bSAndrew Lunn if (err) 216dc30c35bSAndrew Lunn goto out; 217dc30c35bSAndrew Lunn 218dc30c35bSAndrew Lunn out: 219c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 220dc30c35bSAndrew Lunn } 221dc30c35bSAndrew Lunn 2226eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = { 223dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 224dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 225dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 226dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 227dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 228dc30c35bSAndrew Lunn }; 229dc30c35bSAndrew Lunn 230dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 231dc30c35bSAndrew Lunn unsigned int irq, 232dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 233dc30c35bSAndrew Lunn { 234dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 235dc30c35bSAndrew Lunn 236dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 237dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 238dc30c35bSAndrew Lunn irq_set_noprobe(irq); 239dc30c35bSAndrew Lunn 240dc30c35bSAndrew Lunn return 0; 241dc30c35bSAndrew Lunn } 242dc30c35bSAndrew Lunn 243dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 244dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 245dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 246dc30c35bSAndrew Lunn }; 247dc30c35bSAndrew Lunn 2483d82475aSUwe Kleine-König /* To be called with reg_lock held */ 249294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 250dc30c35bSAndrew Lunn { 251dc30c35bSAndrew Lunn int irq, virq; 2523460a577SAndrew Lunn u16 mask; 2533460a577SAndrew Lunn 254d77f4321SVivien Didelot mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 2553d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 256d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2573460a577SAndrew Lunn 2585edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 259a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 260dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 261dc30c35bSAndrew Lunn } 262dc30c35bSAndrew Lunn 263a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 264dc30c35bSAndrew Lunn } 265dc30c35bSAndrew Lunn 266294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 267294d711eSAndrew Lunn { 2683d82475aSUwe Kleine-König /* 2693d82475aSUwe Kleine-König * free_irq must be called without reg_lock taken because the irq 2703d82475aSUwe Kleine-König * handler takes this lock, too. 2713d82475aSUwe Kleine-König */ 272294d711eSAndrew Lunn free_irq(chip->irq, chip); 2733d82475aSUwe Kleine-König 274c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2753d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 276c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 277294d711eSAndrew Lunn } 278294d711eSAndrew Lunn 279294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 280dc30c35bSAndrew Lunn { 2813dd0ef05SAndrew Lunn int err, irq, virq; 2823dd0ef05SAndrew Lunn u16 reg, mask; 283dc30c35bSAndrew Lunn 284dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 285dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 286dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 287dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 288dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 289dc30c35bSAndrew Lunn return -ENOMEM; 290dc30c35bSAndrew Lunn 291dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 292dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 293dc30c35bSAndrew Lunn 294dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 295dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 296dc30c35bSAndrew Lunn 297d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 298dc30c35bSAndrew Lunn if (err) 2993dd0ef05SAndrew Lunn goto out_mapping; 300dc30c35bSAndrew Lunn 3013dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 302dc30c35bSAndrew Lunn 303d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 304dc30c35bSAndrew Lunn if (err) 3053dd0ef05SAndrew Lunn goto out_disable; 306dc30c35bSAndrew Lunn 307dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 30882466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 309dc30c35bSAndrew Lunn if (err) 3103dd0ef05SAndrew Lunn goto out_disable; 311dc30c35bSAndrew Lunn 312dc30c35bSAndrew Lunn return 0; 313dc30c35bSAndrew Lunn 3143dd0ef05SAndrew Lunn out_disable: 3153d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 316d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 3173dd0ef05SAndrew Lunn 3183dd0ef05SAndrew Lunn out_mapping: 3193dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 3203dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 3213dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 3223dd0ef05SAndrew Lunn } 3233dd0ef05SAndrew Lunn 3243dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 325dc30c35bSAndrew Lunn 326dc30c35bSAndrew Lunn return err; 327dc30c35bSAndrew Lunn } 328dc30c35bSAndrew Lunn 329294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 330294d711eSAndrew Lunn { 331f6d9758bSAndrew Lunn static struct lock_class_key lock_key; 332f6d9758bSAndrew Lunn static struct lock_class_key request_key; 333294d711eSAndrew Lunn int err; 334294d711eSAndrew Lunn 335294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 336294d711eSAndrew Lunn if (err) 337294d711eSAndrew Lunn return err; 338294d711eSAndrew Lunn 339f6d9758bSAndrew Lunn /* These lock classes tells lockdep that global 1 irqs are in 340f6d9758bSAndrew Lunn * a different category than their parent GPIO, so it won't 341f6d9758bSAndrew Lunn * report false recursion. 342f6d9758bSAndrew Lunn */ 343f6d9758bSAndrew Lunn irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 344f6d9758bSAndrew Lunn 3453095383aSAndrew Lunn snprintf(chip->irq_name, sizeof(chip->irq_name), 3463095383aSAndrew Lunn "mv88e6xxx-%s", dev_name(chip->dev)); 3473095383aSAndrew Lunn 348c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 349294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 350294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 3510340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 3523095383aSAndrew Lunn chip->irq_name, chip); 353c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 354294d711eSAndrew Lunn if (err) 355294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 356294d711eSAndrew Lunn 357294d711eSAndrew Lunn return err; 358294d711eSAndrew Lunn } 359294d711eSAndrew Lunn 360294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 361294d711eSAndrew Lunn { 362294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 363294d711eSAndrew Lunn struct mv88e6xxx_chip, 364294d711eSAndrew Lunn irq_poll_work.work); 365294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 366294d711eSAndrew Lunn 367294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 368294d711eSAndrew Lunn msecs_to_jiffies(100)); 369294d711eSAndrew Lunn } 370294d711eSAndrew Lunn 371294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 372294d711eSAndrew Lunn { 373294d711eSAndrew Lunn int err; 374294d711eSAndrew Lunn 375294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 376294d711eSAndrew Lunn if (err) 377294d711eSAndrew Lunn return err; 378294d711eSAndrew Lunn 379294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 380294d711eSAndrew Lunn mv88e6xxx_irq_poll); 381294d711eSAndrew Lunn 3823f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 383294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 384294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 385294d711eSAndrew Lunn 386294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 387294d711eSAndrew Lunn msecs_to_jiffies(100)); 388294d711eSAndrew Lunn 389294d711eSAndrew Lunn return 0; 390294d711eSAndrew Lunn } 391294d711eSAndrew Lunn 392294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 393294d711eSAndrew Lunn { 394294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 395294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 3963d82475aSUwe Kleine-König 397c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3983d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 399c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 400294d711eSAndrew Lunn } 401294d711eSAndrew Lunn 40264d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, 40364d47d50SRussell King int port, phy_interface_t interface) 40464d47d50SRussell King { 40564d47d50SRussell King int err; 40664d47d50SRussell King 40764d47d50SRussell King if (chip->info->ops->port_set_rgmii_delay) { 40864d47d50SRussell King err = chip->info->ops->port_set_rgmii_delay(chip, port, 40964d47d50SRussell King interface); 41064d47d50SRussell King if (err && err != -EOPNOTSUPP) 41164d47d50SRussell King return err; 41264d47d50SRussell King } 41364d47d50SRussell King 41464d47d50SRussell King if (chip->info->ops->port_set_cmode) { 41564d47d50SRussell King err = chip->info->ops->port_set_cmode(chip, port, 41664d47d50SRussell King interface); 41764d47d50SRussell King if (err && err != -EOPNOTSUPP) 41864d47d50SRussell King return err; 41964d47d50SRussell King } 42064d47d50SRussell King 42164d47d50SRussell King return 0; 42264d47d50SRussell King } 42364d47d50SRussell King 424a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, 425a5a6858bSRussell King int link, int speed, int duplex, int pause, 426d78343d2SVivien Didelot phy_interface_t mode) 427d78343d2SVivien Didelot { 428d78343d2SVivien Didelot int err; 429d78343d2SVivien Didelot 430d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 431d78343d2SVivien Didelot return 0; 432d78343d2SVivien Didelot 433d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 43443c8e0aeSHubert Feurstein err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 435d78343d2SVivien Didelot if (err) 436d78343d2SVivien Didelot return err; 437d78343d2SVivien Didelot 438f365c6f7SRussell King if (chip->info->ops->port_set_speed_duplex) { 439f365c6f7SRussell King err = chip->info->ops->port_set_speed_duplex(chip, port, 440f365c6f7SRussell King speed, duplex); 441d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 442d78343d2SVivien Didelot goto restore_link; 443d78343d2SVivien Didelot } 444d78343d2SVivien Didelot 4457cbbee05SAndrew Lunn if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode) 4467cbbee05SAndrew Lunn mode = chip->info->ops->port_max_speed_mode(port); 4477cbbee05SAndrew Lunn 44854186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 44954186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 45054186b91SAndrew Lunn if (err) 45154186b91SAndrew Lunn goto restore_link; 45254186b91SAndrew Lunn } 45354186b91SAndrew Lunn 45464d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, mode); 455d78343d2SVivien Didelot restore_link: 456d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 457774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 458d78343d2SVivien Didelot 459d78343d2SVivien Didelot return err; 460d78343d2SVivien Didelot } 461d78343d2SVivien Didelot 462d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 463d700ec41SMarek Vasut { 464d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 465d700ec41SMarek Vasut 466d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 467d700ec41SMarek Vasut } 468d700ec41SMarek Vasut 4695d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) 4705d5b231dSRussell King { 4715d5b231dSRussell King u16 reg; 4725d5b231dSRussell King int err; 4735d5b231dSRussell King 4745d5b231dSRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4755d5b231dSRussell King if (err) { 4765d5b231dSRussell King dev_err(chip->dev, 4775d5b231dSRussell King "p%d: %s: failed to read port status\n", 4785d5b231dSRussell King port, __func__); 4795d5b231dSRussell King return err; 4805d5b231dSRussell King } 4815d5b231dSRussell King 4825d5b231dSRussell King return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT); 4835d5b231dSRussell King } 4845d5b231dSRussell King 485a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, 486a5a6858bSRussell King struct phylink_link_state *state) 487a5a6858bSRussell King { 488a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 489193c5b26SPavana Sharma int lane; 490a5a6858bSRussell King int err; 491a5a6858bSRussell King 492a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 493a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 494193c5b26SPavana Sharma if (lane >= 0 && chip->info->ops->serdes_pcs_get_state) 495a5a6858bSRussell King err = chip->info->ops->serdes_pcs_get_state(chip, port, lane, 496a5a6858bSRussell King state); 497a5a6858bSRussell King else 498a5a6858bSRussell King err = -EOPNOTSUPP; 499a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 500a5a6858bSRussell King 501a5a6858bSRussell King return err; 502a5a6858bSRussell King } 503a5a6858bSRussell King 504a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, 505a5a6858bSRussell King unsigned int mode, 506a5a6858bSRussell King phy_interface_t interface, 507a5a6858bSRussell King const unsigned long *advertise) 508a5a6858bSRussell King { 509a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 510193c5b26SPavana Sharma int lane; 511a5a6858bSRussell King 512a5a6858bSRussell King if (ops->serdes_pcs_config) { 513a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 514193c5b26SPavana Sharma if (lane >= 0) 515a5a6858bSRussell King return ops->serdes_pcs_config(chip, port, lane, mode, 516a5a6858bSRussell King interface, advertise); 517a5a6858bSRussell King } 518a5a6858bSRussell King 519a5a6858bSRussell King return 0; 520a5a6858bSRussell King } 521a5a6858bSRussell King 522a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port) 523a5a6858bSRussell King { 524a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 525a5a6858bSRussell King const struct mv88e6xxx_ops *ops; 526a5a6858bSRussell King int err = 0; 527193c5b26SPavana Sharma int lane; 528a5a6858bSRussell King 529a5a6858bSRussell King ops = chip->info->ops; 530a5a6858bSRussell King 531a5a6858bSRussell King if (ops->serdes_pcs_an_restart) { 532a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 533a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 534193c5b26SPavana Sharma if (lane >= 0) 535a5a6858bSRussell King err = ops->serdes_pcs_an_restart(chip, port, lane); 536a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 537a5a6858bSRussell King 538a5a6858bSRussell King if (err) 539a5a6858bSRussell King dev_err(ds->dev, "p%d: failed to restart AN\n", port); 540a5a6858bSRussell King } 541a5a6858bSRussell King } 542a5a6858bSRussell King 543a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, 544a5a6858bSRussell King unsigned int mode, 545a5a6858bSRussell King int speed, int duplex) 546a5a6858bSRussell King { 547a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 548193c5b26SPavana Sharma int lane; 549a5a6858bSRussell King 550a5a6858bSRussell King if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) { 551a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 552193c5b26SPavana Sharma if (lane >= 0) 553a5a6858bSRussell King return ops->serdes_pcs_link_up(chip, port, lane, 554a5a6858bSRussell King speed, duplex); 555a5a6858bSRussell King } 556a5a6858bSRussell King 557a5a6858bSRussell King return 0; 558a5a6858bSRussell King } 559a5a6858bSRussell King 5606c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5616c422e34SRussell King unsigned long *mask, 5626c422e34SRussell King struct phylink_link_state *state) 5636c422e34SRussell King { 5646c422e34SRussell King if (!phy_interface_mode_is_8023z(state->interface)) { 5656c422e34SRussell King /* 10M and 100M are only supported in non-802.3z mode */ 5666c422e34SRussell King phylink_set(mask, 10baseT_Half); 5676c422e34SRussell King phylink_set(mask, 10baseT_Full); 5686c422e34SRussell King phylink_set(mask, 100baseT_Half); 5696c422e34SRussell King phylink_set(mask, 100baseT_Full); 5706c422e34SRussell King } 5716c422e34SRussell King } 5726c422e34SRussell King 5736c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5746c422e34SRussell King unsigned long *mask, 5756c422e34SRussell King struct phylink_link_state *state) 5766c422e34SRussell King { 5776c422e34SRussell King /* FIXME: if the port is in 1000Base-X mode, then it only supports 5786c422e34SRussell King * 1000M FD speeds. In this case, CMODE will indicate 5. 5796c422e34SRussell King */ 5806c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5816c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5826c422e34SRussell King 5836c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5846c422e34SRussell King } 5856c422e34SRussell King 586e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, 587e3af71a3SMarek Behún unsigned long *mask, 588e3af71a3SMarek Behún struct phylink_link_state *state) 589e3af71a3SMarek Behún { 590e3af71a3SMarek Behún if (port >= 5) 591e3af71a3SMarek Behún phylink_set(mask, 2500baseX_Full); 592e3af71a3SMarek Behún 593e3af71a3SMarek Behún /* No ethtool bits for 200Mbps */ 594e3af71a3SMarek Behún phylink_set(mask, 1000baseT_Full); 595e3af71a3SMarek Behún phylink_set(mask, 1000baseX_Full); 596e3af71a3SMarek Behún 597e3af71a3SMarek Behún mv88e6065_phylink_validate(chip, port, mask, state); 598e3af71a3SMarek Behún } 599e3af71a3SMarek Behún 6006c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6016c422e34SRussell King unsigned long *mask, 6026c422e34SRussell King struct phylink_link_state *state) 6036c422e34SRussell King { 6046c422e34SRussell King /* No ethtool bits for 200Mbps */ 6056c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6066c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6076c422e34SRussell King 6086c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6096c422e34SRussell King } 6106c422e34SRussell King 6116c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6126c422e34SRussell King unsigned long *mask, 6136c422e34SRussell King struct phylink_link_state *state) 6146c422e34SRussell King { 615ec26016bSAndrew Lunn if (port >= 9) { 6166c422e34SRussell King phylink_set(mask, 2500baseX_Full); 617ec26016bSAndrew Lunn phylink_set(mask, 2500baseT_Full); 618ec26016bSAndrew Lunn } 6196c422e34SRussell King 6206c422e34SRussell King /* No ethtool bits for 200Mbps */ 6216c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6226c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6236c422e34SRussell King 6246c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6256c422e34SRussell King } 6266c422e34SRussell King 6276c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6286c422e34SRussell King unsigned long *mask, 6296c422e34SRussell King struct phylink_link_state *state) 6306c422e34SRussell King { 6316c422e34SRussell King if (port >= 9) { 6326c422e34SRussell King phylink_set(mask, 10000baseT_Full); 6336c422e34SRussell King phylink_set(mask, 10000baseKR_Full); 6346c422e34SRussell King } 6356c422e34SRussell King 6366c422e34SRussell King mv88e6390_phylink_validate(chip, port, mask, state); 6376c422e34SRussell King } 6386c422e34SRussell King 639de776d0dSPavana Sharma static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 640de776d0dSPavana Sharma unsigned long *mask, 641de776d0dSPavana Sharma struct phylink_link_state *state) 642de776d0dSPavana Sharma { 643dc2fc9f0SMarek Behún bool is_6191x = 644dc2fc9f0SMarek Behún chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X; 645dc2fc9f0SMarek Behún 646dc2fc9f0SMarek Behún if (((port == 0 || port == 9) && !is_6191x) || port == 10) { 647de776d0dSPavana Sharma phylink_set(mask, 10000baseT_Full); 648de776d0dSPavana Sharma phylink_set(mask, 10000baseKR_Full); 649de776d0dSPavana Sharma phylink_set(mask, 10000baseCR_Full); 650de776d0dSPavana Sharma phylink_set(mask, 10000baseSR_Full); 651de776d0dSPavana Sharma phylink_set(mask, 10000baseLR_Full); 652de776d0dSPavana Sharma phylink_set(mask, 10000baseLRM_Full); 653de776d0dSPavana Sharma phylink_set(mask, 10000baseER_Full); 654de776d0dSPavana Sharma phylink_set(mask, 5000baseT_Full); 655de776d0dSPavana Sharma phylink_set(mask, 2500baseX_Full); 656de776d0dSPavana Sharma phylink_set(mask, 2500baseT_Full); 657de776d0dSPavana Sharma } 658de776d0dSPavana Sharma 659de776d0dSPavana Sharma phylink_set(mask, 1000baseT_Full); 660de776d0dSPavana Sharma phylink_set(mask, 1000baseX_Full); 661de776d0dSPavana Sharma 662de776d0dSPavana Sharma mv88e6065_phylink_validate(chip, port, mask, state); 663de776d0dSPavana Sharma } 664de776d0dSPavana Sharma 665c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port, 666c9a2356fSRussell King unsigned long *supported, 667c9a2356fSRussell King struct phylink_link_state *state) 668c9a2356fSRussell King { 6696c422e34SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 6706c422e34SRussell King struct mv88e6xxx_chip *chip = ds->priv; 6716c422e34SRussell King 6726c422e34SRussell King /* Allow all the expected bits */ 6736c422e34SRussell King phylink_set(mask, Autoneg); 6746c422e34SRussell King phylink_set(mask, Pause); 6756c422e34SRussell King phylink_set_port_modes(mask); 6766c422e34SRussell King 6776c422e34SRussell King if (chip->info->ops->phylink_validate) 6786c422e34SRussell King chip->info->ops->phylink_validate(chip, port, mask, state); 6796c422e34SRussell King 6804973056cSSean Anderson linkmode_and(supported, supported, mask); 6814973056cSSean Anderson linkmode_and(state->advertising, state->advertising, mask); 6826c422e34SRussell King 6836c422e34SRussell King /* We can only operate at 2500BaseX or 1000BaseX. If requested 6846c422e34SRussell King * to advertise both, only report advertising at 2500BaseX. 6856c422e34SRussell King */ 6866c422e34SRussell King phylink_helper_basex_speed(state); 687c9a2356fSRussell King } 688c9a2356fSRussell King 689c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 690c9a2356fSRussell King unsigned int mode, 691c9a2356fSRussell King const struct phylink_link_state *state) 692c9a2356fSRussell King { 693c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 694fad58190SRussell King struct mv88e6xxx_port *p; 69564d47d50SRussell King int err; 696c9a2356fSRussell King 697fad58190SRussell King p = &chip->ports[port]; 698fad58190SRussell King 69964d47d50SRussell King /* FIXME: is this the correct test? If we're in fixed mode on an 70064d47d50SRussell King * internal port, why should we process this any different from 70164d47d50SRussell King * PHY mode? On the other hand, the port may be automedia between 70264d47d50SRussell King * an internal PHY and the serdes... 70364d47d50SRussell King */ 704d700ec41SMarek Vasut if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) 705c9a2356fSRussell King return; 706c9a2356fSRussell King 707c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 708fad58190SRussell King /* In inband mode, the link may come up at any time while the link 709fad58190SRussell King * is not forced down. Force the link down while we reconfigure the 710fad58190SRussell King * interface mode. 71164d47d50SRussell King */ 712fad58190SRussell King if (mode == MLO_AN_INBAND && p->interface != state->interface && 713fad58190SRussell King chip->info->ops->port_set_link) 714fad58190SRussell King chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 715fad58190SRussell King 71664d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, state->interface); 717a5a6858bSRussell King if (err && err != -EOPNOTSUPP) 718a5a6858bSRussell King goto err_unlock; 719a5a6858bSRussell King 720a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface, 721a5a6858bSRussell King state->advertising); 722a5a6858bSRussell King /* FIXME: we should restart negotiation if something changed - which 723a5a6858bSRussell King * is something we get if we convert to using phylinks PCS operations. 724a5a6858bSRussell King */ 725a5a6858bSRussell King if (err > 0) 726a5a6858bSRussell King err = 0; 727a5a6858bSRussell King 728fad58190SRussell King /* Undo the forced down state above after completing configuration 729fad58190SRussell King * irrespective of its state on entry, which allows the link to come up. 730fad58190SRussell King */ 731fad58190SRussell King if (mode == MLO_AN_INBAND && p->interface != state->interface && 732fad58190SRussell King chip->info->ops->port_set_link) 733fad58190SRussell King chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); 734fad58190SRussell King 735fad58190SRussell King p->interface = state->interface; 736fad58190SRussell King 737a5a6858bSRussell King err_unlock: 738c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 739c9a2356fSRussell King 740c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 74164d47d50SRussell King dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); 742c9a2356fSRussell King } 743c9a2356fSRussell King 744c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 745c9a2356fSRussell King unsigned int mode, 746c9a2356fSRussell King phy_interface_t interface) 747c9a2356fSRussell King { 74830c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 74930c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 75030c4a5b0SRussell King int err = 0; 75130c4a5b0SRussell King 75230c4a5b0SRussell King ops = chip->info->ops; 75330c4a5b0SRussell King 75430c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 7554a3e0aedSMaarten Zanders /* Internal PHYs propagate their configuration directly to the MAC. 7564a3e0aedSMaarten Zanders * External PHYs depend on whether the PPU is enabled for this port. 7574a3e0aedSMaarten Zanders */ 7584a3e0aedSMaarten Zanders if (((!mv88e6xxx_phy_is_internal(ds, port) && 7594a3e0aedSMaarten Zanders !mv88e6xxx_port_ppu_updates(chip, port)) || 7604efe7662SChris Packham mode == MLO_AN_FIXED) && ops->port_sync_link) 7614efe7662SChris Packham err = ops->port_sync_link(chip, port, mode, false); 76230c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 76330c4a5b0SRussell King 76430c4a5b0SRussell King if (err) 76530c4a5b0SRussell King dev_err(chip->dev, 76630c4a5b0SRussell King "p%d: failed to force MAC link down\n", port); 76730c4a5b0SRussell King } 768c9a2356fSRussell King 769c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 770c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 7715b502a7bSRussell King struct phy_device *phydev, 7725b502a7bSRussell King int speed, int duplex, 7735b502a7bSRussell King bool tx_pause, bool rx_pause) 774c9a2356fSRussell King { 77530c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 77630c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 77730c4a5b0SRussell King int err = 0; 77830c4a5b0SRussell King 77930c4a5b0SRussell King ops = chip->info->ops; 78030c4a5b0SRussell King 78130c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 7824a3e0aedSMaarten Zanders /* Internal PHYs propagate their configuration directly to the MAC. 7834a3e0aedSMaarten Zanders * External PHYs depend on whether the PPU is enabled for this port. 7844a3e0aedSMaarten Zanders */ 7854a3e0aedSMaarten Zanders if ((!mv88e6xxx_phy_is_internal(ds, port) && 7864a3e0aedSMaarten Zanders !mv88e6xxx_port_ppu_updates(chip, port)) || 7874a3e0aedSMaarten Zanders mode == MLO_AN_FIXED) { 78830c4a5b0SRussell King /* FIXME: for an automedia port, should we force the link 78930c4a5b0SRussell King * down here - what if the link comes up due to "other" media 79030c4a5b0SRussell King * while we're bringing the port up, how is the exclusivity 791a5a6858bSRussell King * handled in the Marvell hardware? E.g. port 2 on 88E6390 79230c4a5b0SRussell King * shared between internal PHY and Serdes. 79330c4a5b0SRussell King */ 794a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed, 795a5a6858bSRussell King duplex); 796a5a6858bSRussell King if (err) 797a5a6858bSRussell King goto error; 798a5a6858bSRussell King 799f365c6f7SRussell King if (ops->port_set_speed_duplex) { 800f365c6f7SRussell King err = ops->port_set_speed_duplex(chip, port, 801f365c6f7SRussell King speed, duplex); 80230c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 80330c4a5b0SRussell King goto error; 80430c4a5b0SRussell King } 80530c4a5b0SRussell King 8064efe7662SChris Packham if (ops->port_sync_link) 8074efe7662SChris Packham err = ops->port_sync_link(chip, port, mode, true); 8085d5b231dSRussell King } 80930c4a5b0SRussell King error: 81030c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 81130c4a5b0SRussell King 81230c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 81330c4a5b0SRussell King dev_err(ds->dev, 81430c4a5b0SRussell King "p%d: failed to configure MAC link up\n", port); 81530c4a5b0SRussell King } 816c9a2356fSRussell King 817a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 818fad09c73SVivien Didelot { 819a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 820a605a0feSAndrew Lunn return -EOPNOTSUPP; 821fad09c73SVivien Didelot 822a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 823fad09c73SVivien Didelot } 824fad09c73SVivien Didelot 825fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 826dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 827dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 828dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 829dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 830dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 831dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 832dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 833dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 834dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 835dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 836dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 837dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 838dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 839dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 840dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 841dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 842dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 843dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 844dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 845dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 846dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 847dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 848dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 849dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 850dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 851dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 852dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 853dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 854dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 855dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 856dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 857dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 858dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 859dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 860dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 861dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 862dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 863dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 864dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 865dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 866dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 867dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 868dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 869dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 870dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 871dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 872dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 873dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 874dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 875dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 876dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 877dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 878dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 879dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 880dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 881dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 882dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 883dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 884dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 885fad09c73SVivien Didelot }; 886fad09c73SVivien Didelot 887fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 888fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 889e0d8b615SAndrew Lunn int port, u16 bank1_select, 890e0d8b615SAndrew Lunn u16 histogram) 891fad09c73SVivien Didelot { 892fad09c73SVivien Didelot u32 low; 893fad09c73SVivien Didelot u32 high = 0; 894dfafe449SAndrew Lunn u16 reg = 0; 8950e7b9925SAndrew Lunn int err; 896fad09c73SVivien Didelot u64 value; 897fad09c73SVivien Didelot 898fad09c73SVivien Didelot switch (s->type) { 899dfafe449SAndrew Lunn case STATS_TYPE_PORT: 9000e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 9010e7b9925SAndrew Lunn if (err) 9026c3442f5SJisheng Zhang return U64_MAX; 903fad09c73SVivien Didelot 9040e7b9925SAndrew Lunn low = reg; 905cda9f4aaSAndrew Lunn if (s->size == 4) { 9060e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 9070e7b9925SAndrew Lunn if (err) 9086c3442f5SJisheng Zhang return U64_MAX; 90984b3fd1fSRasmus Villemoes low |= ((u32)reg) << 16; 910fad09c73SVivien Didelot } 911fad09c73SVivien Didelot break; 912dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 913e0d8b615SAndrew Lunn reg = bank1_select; 914df561f66SGustavo A. R. Silva fallthrough; 915dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 916e0d8b615SAndrew Lunn reg |= s->reg | histogram; 9177f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 918cda9f4aaSAndrew Lunn if (s->size == 8) 9197f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 9209fc3e4dcSGustavo A. R. Silva break; 9219fc3e4dcSGustavo A. R. Silva default: 9226c3442f5SJisheng Zhang return U64_MAX; 923fad09c73SVivien Didelot } 9246e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 925fad09c73SVivien Didelot return value; 926fad09c73SVivien Didelot } 927fad09c73SVivien Didelot 928436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 929dfafe449SAndrew Lunn uint8_t *data, int types) 930fad09c73SVivien Didelot { 931fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 932fad09c73SVivien Didelot int i, j; 933fad09c73SVivien Didelot 934fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 935fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 936dfafe449SAndrew Lunn if (stat->type & types) { 937fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 938fad09c73SVivien Didelot ETH_GSTRING_LEN); 939fad09c73SVivien Didelot j++; 940fad09c73SVivien Didelot } 941fad09c73SVivien Didelot } 942436fe17dSAndrew Lunn 943436fe17dSAndrew Lunn return j; 944fad09c73SVivien Didelot } 945fad09c73SVivien Didelot 946436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 947dfafe449SAndrew Lunn uint8_t *data) 948dfafe449SAndrew Lunn { 949436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 950dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 951dfafe449SAndrew Lunn } 952dfafe449SAndrew Lunn 9531f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 9541f71836fSRasmus Villemoes uint8_t *data) 9551f71836fSRasmus Villemoes { 9561f71836fSRasmus Villemoes return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 9571f71836fSRasmus Villemoes } 9581f71836fSRasmus Villemoes 959436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 960dfafe449SAndrew Lunn uint8_t *data) 961dfafe449SAndrew Lunn { 962436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 963dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 964dfafe449SAndrew Lunn } 965dfafe449SAndrew Lunn 96665f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 96765f60e45SAndrew Lunn "atu_member_violation", 96865f60e45SAndrew Lunn "atu_miss_violation", 96965f60e45SAndrew Lunn "atu_full_violation", 97065f60e45SAndrew Lunn "vtu_member_violation", 97165f60e45SAndrew Lunn "vtu_miss_violation", 97265f60e45SAndrew Lunn }; 97365f60e45SAndrew Lunn 97465f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 97565f60e45SAndrew Lunn { 97665f60e45SAndrew Lunn unsigned int i; 97765f60e45SAndrew Lunn 97865f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 97965f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 98065f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 98165f60e45SAndrew Lunn ETH_GSTRING_LEN); 98265f60e45SAndrew Lunn } 98365f60e45SAndrew Lunn 984dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 98589f09048SFlorian Fainelli u32 stringset, uint8_t *data) 986fad09c73SVivien Didelot { 98704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 988436fe17dSAndrew Lunn int count = 0; 989dfafe449SAndrew Lunn 99089f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 99189f09048SFlorian Fainelli return; 99289f09048SFlorian Fainelli 993c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 994c6c8cd5eSAndrew Lunn 995dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 996436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 997436fe17dSAndrew Lunn 998436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 999436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 100065f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 1001436fe17dSAndrew Lunn } 1002c6c8cd5eSAndrew Lunn 100365f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 100465f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 100565f60e45SAndrew Lunn 1006c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1007dfafe449SAndrew Lunn } 1008dfafe449SAndrew Lunn 1009dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 1010dfafe449SAndrew Lunn int types) 1011dfafe449SAndrew Lunn { 1012fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 1013fad09c73SVivien Didelot int i, j; 1014fad09c73SVivien Didelot 1015fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1016fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 1017dfafe449SAndrew Lunn if (stat->type & types) 1018fad09c73SVivien Didelot j++; 1019fad09c73SVivien Didelot } 1020fad09c73SVivien Didelot return j; 1021fad09c73SVivien Didelot } 1022fad09c73SVivien Didelot 1023dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1024dfafe449SAndrew Lunn { 1025dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1026dfafe449SAndrew Lunn STATS_TYPE_PORT); 1027dfafe449SAndrew Lunn } 1028dfafe449SAndrew Lunn 10291f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 10301f71836fSRasmus Villemoes { 10311f71836fSRasmus Villemoes return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 10321f71836fSRasmus Villemoes } 10331f71836fSRasmus Villemoes 1034dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1035dfafe449SAndrew Lunn { 1036dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1037dfafe449SAndrew Lunn STATS_TYPE_BANK1); 1038dfafe449SAndrew Lunn } 1039dfafe449SAndrew Lunn 104089f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 1041dfafe449SAndrew Lunn { 1042dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 1043436fe17dSAndrew Lunn int serdes_count = 0; 1044436fe17dSAndrew Lunn int count = 0; 1045dfafe449SAndrew Lunn 104689f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 104789f09048SFlorian Fainelli return 0; 104889f09048SFlorian Fainelli 1049c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1050dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 1051436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 1052436fe17dSAndrew Lunn if (count < 0) 1053436fe17dSAndrew Lunn goto out; 1054436fe17dSAndrew Lunn 1055436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 1056436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 1057436fe17dSAndrew Lunn port); 105865f60e45SAndrew Lunn if (serdes_count < 0) { 1059436fe17dSAndrew Lunn count = serdes_count; 106065f60e45SAndrew Lunn goto out; 106165f60e45SAndrew Lunn } 1062436fe17dSAndrew Lunn count += serdes_count; 106365f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 106465f60e45SAndrew Lunn 1065436fe17dSAndrew Lunn out: 1066c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1067dfafe449SAndrew Lunn 1068436fe17dSAndrew Lunn return count; 1069dfafe449SAndrew Lunn } 1070dfafe449SAndrew Lunn 1071436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1072e0d8b615SAndrew Lunn uint64_t *data, int types, 1073e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 1074052f947fSAndrew Lunn { 1075052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 1076052f947fSAndrew Lunn int i, j; 1077052f947fSAndrew Lunn 1078052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1079052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 1080052f947fSAndrew Lunn if (stat->type & types) { 1081c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1082e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 1083e0d8b615SAndrew Lunn bank1_select, 1084e0d8b615SAndrew Lunn histogram); 1085c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1086377cda13SAndrew Lunn 1087052f947fSAndrew Lunn j++; 1088052f947fSAndrew Lunn } 1089052f947fSAndrew Lunn } 1090436fe17dSAndrew Lunn return j; 1091052f947fSAndrew Lunn } 1092052f947fSAndrew Lunn 1093436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1094052f947fSAndrew Lunn uint64_t *data) 1095052f947fSAndrew Lunn { 1096052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1097e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 109857d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1099052f947fSAndrew Lunn } 1100052f947fSAndrew Lunn 11011f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 11021f71836fSRasmus Villemoes uint64_t *data) 11031f71836fSRasmus Villemoes { 11041f71836fSRasmus Villemoes return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 11051f71836fSRasmus Villemoes 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 11061f71836fSRasmus Villemoes } 11071f71836fSRasmus Villemoes 1108436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1109052f947fSAndrew Lunn uint64_t *data) 1110052f947fSAndrew Lunn { 1111052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1112e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 111357d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 111457d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1115e0d8b615SAndrew Lunn } 1116e0d8b615SAndrew Lunn 1117436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1118e0d8b615SAndrew Lunn uint64_t *data) 1119e0d8b615SAndrew Lunn { 1120e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1121e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 112257d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 112357d1ef38SVivien Didelot 0); 1124052f947fSAndrew Lunn } 1125052f947fSAndrew Lunn 112665f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 112765f60e45SAndrew Lunn uint64_t *data) 112865f60e45SAndrew Lunn { 112965f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 113065f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 113165f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 113265f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 113365f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 113465f60e45SAndrew Lunn } 113565f60e45SAndrew Lunn 1136052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1137052f947fSAndrew Lunn uint64_t *data) 1138052f947fSAndrew Lunn { 1139436fe17dSAndrew Lunn int count = 0; 1140436fe17dSAndrew Lunn 1141052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1142436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1143436fe17dSAndrew Lunn 1144c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1145436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1146436fe17dSAndrew Lunn data += count; 114765f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1148436fe17dSAndrew Lunn } 114965f60e45SAndrew Lunn data += count; 115065f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 1151c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1152052f947fSAndrew Lunn } 1153052f947fSAndrew Lunn 1154fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1155fad09c73SVivien Didelot uint64_t *data) 1156fad09c73SVivien Didelot { 115704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1158fad09c73SVivien Didelot int ret; 1159fad09c73SVivien Didelot 1160c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1161fad09c73SVivien Didelot 1162a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1163c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1164377cda13SAndrew Lunn 1165377cda13SAndrew Lunn if (ret < 0) 1166fad09c73SVivien Didelot return; 1167052f947fSAndrew Lunn 1168052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1169fad09c73SVivien Didelot 1170fad09c73SVivien Didelot } 1171fad09c73SVivien Didelot 1172fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1173fad09c73SVivien Didelot { 11740d30bbd0SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 11750d30bbd0SAndrew Lunn int len; 11760d30bbd0SAndrew Lunn 11770d30bbd0SAndrew Lunn len = 32 * sizeof(u16); 11780d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs_len) 11790d30bbd0SAndrew Lunn len += chip->info->ops->serdes_get_regs_len(chip, port); 11800d30bbd0SAndrew Lunn 11810d30bbd0SAndrew Lunn return len; 1182fad09c73SVivien Didelot } 1183fad09c73SVivien Didelot 1184fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1185fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1186fad09c73SVivien Didelot { 118704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 11880e7b9925SAndrew Lunn int err; 11890e7b9925SAndrew Lunn u16 reg; 1190fad09c73SVivien Didelot u16 *p = _p; 1191fad09c73SVivien Didelot int i; 1192fad09c73SVivien Didelot 1193a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1194fad09c73SVivien Didelot 1195fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1196fad09c73SVivien Didelot 1197c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1198fad09c73SVivien Didelot 1199fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1200fad09c73SVivien Didelot 12010e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 12020e7b9925SAndrew Lunn if (!err) 12030e7b9925SAndrew Lunn p[i] = reg; 1204fad09c73SVivien Didelot } 1205fad09c73SVivien Didelot 12060d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs) 12070d30bbd0SAndrew Lunn chip->info->ops->serdes_get_regs(chip, port, &p[i]); 12080d30bbd0SAndrew Lunn 1209c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1210fad09c73SVivien Didelot } 1211fad09c73SVivien Didelot 121208f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1213fad09c73SVivien Didelot struct ethtool_eee *e) 1214fad09c73SVivien Didelot { 12155480db69SVivien Didelot /* Nothing to do on the port's MAC */ 12165480db69SVivien Didelot return 0; 1217fad09c73SVivien Didelot } 1218fad09c73SVivien Didelot 121908f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 122046587e4aSVivien Didelot struct ethtool_eee *e) 1221fad09c73SVivien Didelot { 12225480db69SVivien Didelot /* Nothing to do on the port's MAC */ 12235480db69SVivien Didelot return 0; 1224fad09c73SVivien Didelot } 1225fad09c73SVivien Didelot 12269dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */ 1227e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1228fad09c73SVivien Didelot { 12299dc8b13eSVivien Didelot struct dsa_switch *ds = chip->ds; 12309dc8b13eSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 1231*65144067SVladimir Oltean struct dsa_port *dp, *other_dp; 12329dc8b13eSVivien Didelot bool found = false; 1233e5887a2aSVivien Didelot u16 pvlan; 1234fad09c73SVivien Didelot 1235ce5df689SVladimir Oltean /* dev is a physical switch */ 1236ce5df689SVladimir Oltean if (dev <= dst->last_switch) { 12379dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 12389dc8b13eSVivien Didelot if (dp->ds->index == dev && dp->index == port) { 1239ce5df689SVladimir Oltean /* dp might be a DSA link or a user port, so it 1240*65144067SVladimir Oltean * might or might not have a bridge. 1241*65144067SVladimir Oltean * Use the "found" variable for both cases. 1242ce5df689SVladimir Oltean */ 1243ce5df689SVladimir Oltean found = true; 1244ce5df689SVladimir Oltean break; 1245ce5df689SVladimir Oltean } 1246ce5df689SVladimir Oltean } 1247ce5df689SVladimir Oltean /* dev is a virtual bridge */ 1248ce5df689SVladimir Oltean } else { 1249ce5df689SVladimir Oltean list_for_each_entry(dp, &dst->ports, list) { 12503f9bb030SVladimir Oltean if (!dp->bridge_num) 1251ce5df689SVladimir Oltean continue; 1252ce5df689SVladimir Oltean 12533f9bb030SVladimir Oltean if (dp->bridge_num + dst->last_switch != dev) 1254ce5df689SVladimir Oltean continue; 1255ce5df689SVladimir Oltean 12569dc8b13eSVivien Didelot found = true; 12579dc8b13eSVivien Didelot break; 12589dc8b13eSVivien Didelot } 12599dc8b13eSVivien Didelot } 1260fad09c73SVivien Didelot 1261ce5df689SVladimir Oltean /* Prevent frames from unknown switch or virtual bridge */ 12629dc8b13eSVivien Didelot if (!found) 1263e5887a2aSVivien Didelot return 0; 1264e5887a2aSVivien Didelot 1265e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 12669dc8b13eSVivien Didelot if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) 1267e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1268e5887a2aSVivien Didelot 1269e5887a2aSVivien Didelot pvlan = 0; 1270e5887a2aSVivien Didelot 1271e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 1272e5887a2aSVivien Didelot * as well as any local member of their bridge group. 1273e5887a2aSVivien Didelot */ 1274*65144067SVladimir Oltean dsa_switch_for_each_port(other_dp, ds) 1275*65144067SVladimir Oltean if (other_dp->type == DSA_PORT_TYPE_CPU || 1276*65144067SVladimir Oltean other_dp->type == DSA_PORT_TYPE_DSA || 1277*65144067SVladimir Oltean (dp->bridge_dev && dp->bridge_dev == other_dp->bridge_dev)) 1278*65144067SVladimir Oltean pvlan |= BIT(other_dp->index); 1279e5887a2aSVivien Didelot 1280e5887a2aSVivien Didelot return pvlan; 1281fad09c73SVivien Didelot } 1282e5887a2aSVivien Didelot 1283240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1284e5887a2aSVivien Didelot { 1285e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1286fad09c73SVivien Didelot 1287fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1288fad09c73SVivien Didelot output_ports &= ~BIT(port); 1289fad09c73SVivien Didelot 12905a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1291fad09c73SVivien Didelot } 1292fad09c73SVivien Didelot 1293fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1294fad09c73SVivien Didelot u8 state) 1295fad09c73SVivien Didelot { 129604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1297fad09c73SVivien Didelot int err; 1298fad09c73SVivien Didelot 1299c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1300f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1301c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1302fad09c73SVivien Didelot 1303fad09c73SVivien Didelot if (err) 1304774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1305fad09c73SVivien Didelot } 1306fad09c73SVivien Didelot 130793e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 130893e18d61SVivien Didelot { 130993e18d61SVivien Didelot int err; 131093e18d61SVivien Didelot 131193e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 131293e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 131393e18d61SVivien Didelot if (err) 131493e18d61SVivien Didelot return err; 131593e18d61SVivien Didelot } 131693e18d61SVivien Didelot 131793e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 131893e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 131993e18d61SVivien Didelot if (err) 132093e18d61SVivien Didelot return err; 132193e18d61SVivien Didelot } 132293e18d61SVivien Didelot 132393e18d61SVivien Didelot return 0; 132493e18d61SVivien Didelot } 132593e18d61SVivien Didelot 1326c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1327c7f047b6SVivien Didelot { 1328c5f51765SVivien Didelot struct dsa_switch *ds = chip->ds; 1329c7f047b6SVivien Didelot int target, port; 1330c7f047b6SVivien Didelot int err; 1331c7f047b6SVivien Didelot 1332c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1333c7f047b6SVivien Didelot return 0; 1334c7f047b6SVivien Didelot 1335c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1336c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1337c5f51765SVivien Didelot port = dsa_routing_port(ds, target); 1338c5f51765SVivien Didelot if (port == ds->num_ports) 1339c7f047b6SVivien Didelot port = 0x1f; 1340c7f047b6SVivien Didelot 1341c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1342c7f047b6SVivien Didelot if (err) 1343c7f047b6SVivien Didelot return err; 1344c7f047b6SVivien Didelot } 1345c7f047b6SVivien Didelot 134602317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 134702317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 134802317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 134902317e68SVivien Didelot if (err) 135002317e68SVivien Didelot return err; 135102317e68SVivien Didelot } 135202317e68SVivien Didelot 135323c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 135423c98919SVivien Didelot if (err) 135523c98919SVivien Didelot return err; 135623c98919SVivien Didelot 1357c7f047b6SVivien Didelot return 0; 1358c7f047b6SVivien Didelot } 1359c7f047b6SVivien Didelot 1360b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1361b28f872dSVivien Didelot { 1362b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1363b28f872dSVivien Didelot if (chip->info->global2_addr) 1364b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1365b28f872dSVivien Didelot 1366b28f872dSVivien Didelot return 0; 1367b28f872dSVivien Didelot } 1368b28f872dSVivien Didelot 13699e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 13709e5baf9bSVivien Didelot { 13719e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 13729e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 13739e5baf9bSVivien Didelot 13749e5baf9bSVivien Didelot return 0; 13759e5baf9bSVivien Didelot } 13769e5baf9bSVivien Didelot 13779e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 13789e907d73SVivien Didelot { 13799e907d73SVivien Didelot if (chip->info->ops->pot_clear) 13809e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 13819e907d73SVivien Didelot 13829e907d73SVivien Didelot return 0; 13839e907d73SVivien Didelot } 13849e907d73SVivien Didelot 138551c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 138651c901a7SVivien Didelot { 138751c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 138851c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 138951c901a7SVivien Didelot 139051c901a7SVivien Didelot return 0; 139151c901a7SVivien Didelot } 139251c901a7SVivien Didelot 1393a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1394a2ac29d2SVivien Didelot { 1395c3a7d4adSVivien Didelot int err; 1396c3a7d4adSVivien Didelot 1397daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1398daefc943SVivien Didelot if (err) 1399daefc943SVivien Didelot return err; 1400daefc943SVivien Didelot 140149506a9bSRasmus Villemoes /* The chips that have a "learn2all" bit in Global1, ATU 140249506a9bSRasmus Villemoes * Control are precisely those whose port registers have a 140349506a9bSRasmus Villemoes * Message Port bit in Port Control 1 and hence implement 140449506a9bSRasmus Villemoes * ->port_setup_message_port. 140549506a9bSRasmus Villemoes */ 140649506a9bSRasmus Villemoes if (chip->info->ops->port_setup_message_port) { 1407c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1408c3a7d4adSVivien Didelot if (err) 1409c3a7d4adSVivien Didelot return err; 141049506a9bSRasmus Villemoes } 1411c3a7d4adSVivien Didelot 1412a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1413a2ac29d2SVivien Didelot } 1414a2ac29d2SVivien Didelot 1415cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1416cd8da8bbSVivien Didelot { 1417cd8da8bbSVivien Didelot int port; 1418cd8da8bbSVivien Didelot int err; 1419cd8da8bbSVivien Didelot 1420cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1421cd8da8bbSVivien Didelot return 0; 1422cd8da8bbSVivien Didelot 1423cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1424cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1425cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1426cd8da8bbSVivien Didelot */ 1427cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1428cd8da8bbSVivien Didelot if (err) 1429cd8da8bbSVivien Didelot return err; 1430cd8da8bbSVivien Didelot } 1431cd8da8bbSVivien Didelot 1432cd8da8bbSVivien Didelot return 0; 1433cd8da8bbSVivien Didelot } 1434cd8da8bbSVivien Didelot 143504a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 143604a69a17SVivien Didelot { 143704a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 143804a69a17SVivien Didelot u8 addr[ETH_ALEN]; 143904a69a17SVivien Didelot 144004a69a17SVivien Didelot eth_random_addr(addr); 144104a69a17SVivien Didelot 144204a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 144304a69a17SVivien Didelot } 144404a69a17SVivien Didelot 144504a69a17SVivien Didelot return 0; 144604a69a17SVivien Didelot } 144704a69a17SVivien Didelot 144817a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 144917a1594eSVivien Didelot { 145057e661aaSTobias Waldekranz struct dsa_switch_tree *dst = chip->ds->dst; 145157e661aaSTobias Waldekranz struct dsa_switch *ds; 145257e661aaSTobias Waldekranz struct dsa_port *dp; 145317a1594eSVivien Didelot u16 pvlan = 0; 145417a1594eSVivien Didelot 145517a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1456d14939beSVivien Didelot return 0; 145717a1594eSVivien Didelot 145817a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 145957e661aaSTobias Waldekranz if (dev != chip->ds->index) { 1460aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 146117a1594eSVivien Didelot 146257e661aaSTobias Waldekranz ds = dsa_switch_find(dst->index, dev); 146357e661aaSTobias Waldekranz dp = ds ? dsa_to_port(ds, port) : NULL; 146457e661aaSTobias Waldekranz if (dp && dp->lag_dev) { 146557e661aaSTobias Waldekranz /* As the PVT is used to limit flooding of 146657e661aaSTobias Waldekranz * FORWARD frames, which use the LAG ID as the 146757e661aaSTobias Waldekranz * source port, we must translate dev/port to 146857e661aaSTobias Waldekranz * the special "LAG device" in the PVT, using 146957e661aaSTobias Waldekranz * the LAG ID as the port number. 147057e661aaSTobias Waldekranz */ 147178e70dbcSTobias Waldekranz dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK; 147257e661aaSTobias Waldekranz port = dsa_lag_id(dst, dp->lag_dev); 147357e661aaSTobias Waldekranz } 147457e661aaSTobias Waldekranz } 147557e661aaSTobias Waldekranz 147617a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 147717a1594eSVivien Didelot } 147817a1594eSVivien Didelot 147981228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 148081228996SVivien Didelot { 148117a1594eSVivien Didelot int dev, port; 148217a1594eSVivien Didelot int err; 148317a1594eSVivien Didelot 148481228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 148581228996SVivien Didelot return 0; 148681228996SVivien Didelot 148781228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 148881228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 148981228996SVivien Didelot */ 149017a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 149117a1594eSVivien Didelot if (err) 149217a1594eSVivien Didelot return err; 149317a1594eSVivien Didelot 149417a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 149517a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 149617a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 149717a1594eSVivien Didelot if (err) 149817a1594eSVivien Didelot return err; 149917a1594eSVivien Didelot } 150017a1594eSVivien Didelot } 150117a1594eSVivien Didelot 150217a1594eSVivien Didelot return 0; 150381228996SVivien Didelot } 150481228996SVivien Didelot 1505749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1506749efcb8SVivien Didelot { 1507749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1508749efcb8SVivien Didelot int err; 1509749efcb8SVivien Didelot 1510ffcec3f2STobias Waldekranz if (dsa_to_port(ds, port)->lag_dev) 1511ffcec3f2STobias Waldekranz /* Hardware is incapable of fast-aging a LAG through a 1512ffcec3f2STobias Waldekranz * regular ATU move operation. Until we have something 1513ffcec3f2STobias Waldekranz * more fancy in place this is a no-op. 1514ffcec3f2STobias Waldekranz */ 1515ffcec3f2STobias Waldekranz return; 1516ffcec3f2STobias Waldekranz 1517c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1518e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1519c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1520749efcb8SVivien Didelot 1521749efcb8SVivien Didelot if (err) 1522774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 1523749efcb8SVivien Didelot } 1524749efcb8SVivien Didelot 1525b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1526b486d7c9SVivien Didelot { 1527e545f865STobias Waldekranz if (!mv88e6xxx_max_vid(chip)) 1528b486d7c9SVivien Didelot return 0; 1529b486d7c9SVivien Didelot 1530b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1531b486d7c9SVivien Didelot } 1532b486d7c9SVivien Didelot 153334065c58STobias Waldekranz static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 1534f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1535f1394b78SVivien Didelot { 153634065c58STobias Waldekranz int err; 153734065c58STobias Waldekranz 1538f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1539f1394b78SVivien Didelot return -EOPNOTSUPP; 1540f1394b78SVivien Didelot 154134065c58STobias Waldekranz entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip); 154234065c58STobias Waldekranz entry->valid = false; 154334065c58STobias Waldekranz 154434065c58STobias Waldekranz err = chip->info->ops->vtu_getnext(chip, entry); 154534065c58STobias Waldekranz 154634065c58STobias Waldekranz if (entry->vid != vid) 154734065c58STobias Waldekranz entry->valid = false; 154834065c58STobias Waldekranz 154934065c58STobias Waldekranz return err; 1550f1394b78SVivien Didelot } 1551f1394b78SVivien Didelot 1552d89ef4b8STobias Waldekranz static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip, 1553d89ef4b8STobias Waldekranz int (*cb)(struct mv88e6xxx_chip *chip, 1554d89ef4b8STobias Waldekranz const struct mv88e6xxx_vtu_entry *entry, 1555d89ef4b8STobias Waldekranz void *priv), 1556d89ef4b8STobias Waldekranz void *priv) 1557d89ef4b8STobias Waldekranz { 1558d89ef4b8STobias Waldekranz struct mv88e6xxx_vtu_entry entry = { 1559d89ef4b8STobias Waldekranz .vid = mv88e6xxx_max_vid(chip), 1560d89ef4b8STobias Waldekranz .valid = false, 1561d89ef4b8STobias Waldekranz }; 1562d89ef4b8STobias Waldekranz int err; 1563d89ef4b8STobias Waldekranz 1564d89ef4b8STobias Waldekranz if (!chip->info->ops->vtu_getnext) 1565d89ef4b8STobias Waldekranz return -EOPNOTSUPP; 1566d89ef4b8STobias Waldekranz 1567d89ef4b8STobias Waldekranz do { 1568d89ef4b8STobias Waldekranz err = chip->info->ops->vtu_getnext(chip, &entry); 1569d89ef4b8STobias Waldekranz if (err) 1570d89ef4b8STobias Waldekranz return err; 1571d89ef4b8STobias Waldekranz 1572d89ef4b8STobias Waldekranz if (!entry.valid) 1573d89ef4b8STobias Waldekranz break; 1574d89ef4b8STobias Waldekranz 1575d89ef4b8STobias Waldekranz err = cb(chip, &entry, priv); 1576d89ef4b8STobias Waldekranz if (err) 1577d89ef4b8STobias Waldekranz return err; 1578d89ef4b8STobias Waldekranz } while (entry.vid < mv88e6xxx_max_vid(chip)); 1579d89ef4b8STobias Waldekranz 1580d89ef4b8STobias Waldekranz return 0; 1581d89ef4b8STobias Waldekranz } 1582d89ef4b8STobias Waldekranz 15830ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 15840ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 15850ad5daf6SVivien Didelot { 15860ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 15870ad5daf6SVivien Didelot return -EOPNOTSUPP; 15880ad5daf6SVivien Didelot 15890ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 15900ad5daf6SVivien Didelot } 15910ad5daf6SVivien Didelot 1592d89ef4b8STobias Waldekranz static int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip, 1593d89ef4b8STobias Waldekranz const struct mv88e6xxx_vtu_entry *entry, 1594d89ef4b8STobias Waldekranz void *_fid_bitmap) 1595d89ef4b8STobias Waldekranz { 1596d89ef4b8STobias Waldekranz unsigned long *fid_bitmap = _fid_bitmap; 1597d89ef4b8STobias Waldekranz 1598d89ef4b8STobias Waldekranz set_bit(entry->fid, fid_bitmap); 1599d89ef4b8STobias Waldekranz return 0; 1600d89ef4b8STobias Waldekranz } 1601d89ef4b8STobias Waldekranz 160290b6dbdfSAndrew Lunn int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap) 1603fad09c73SVivien Didelot { 1604fad09c73SVivien Didelot int i, err; 160590b6dbdfSAndrew Lunn u16 fid; 1606fad09c73SVivien Didelot 1607fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1608fad09c73SVivien Didelot 1609fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1610370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 161190b6dbdfSAndrew Lunn err = mv88e6xxx_port_get_fid(chip, i, &fid); 1612fad09c73SVivien Didelot if (err) 1613fad09c73SVivien Didelot return err; 1614fad09c73SVivien Didelot 161590b6dbdfSAndrew Lunn set_bit(fid, fid_bitmap); 1616fad09c73SVivien Didelot } 1617fad09c73SVivien Didelot 1618fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1619d89ef4b8STobias Waldekranz return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap); 162090b6dbdfSAndrew Lunn } 162190b6dbdfSAndrew Lunn 162290b6dbdfSAndrew Lunn static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 162390b6dbdfSAndrew Lunn { 162490b6dbdfSAndrew Lunn DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 162590b6dbdfSAndrew Lunn int err; 162690b6dbdfSAndrew Lunn 162790b6dbdfSAndrew Lunn err = mv88e6xxx_fid_map(chip, fid_bitmap); 162890b6dbdfSAndrew Lunn if (err) 162990b6dbdfSAndrew Lunn return err; 163090b6dbdfSAndrew Lunn 1631fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1632fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1633fad09c73SVivien Didelot */ 1634fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1635fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1636fad09c73SVivien Didelot return -ENOSPC; 1637fad09c73SVivien Didelot 1638fad09c73SVivien Didelot /* Clear the database */ 1639daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1640fad09c73SVivien Didelot } 1641fad09c73SVivien Didelot 1642fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1643b7a9e0daSVladimir Oltean u16 vid) 1644fad09c73SVivien Didelot { 16450493fa79SVladimir Oltean struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; 164604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1647425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 16480493fa79SVladimir Oltean int err; 1649fad09c73SVivien Didelot 1650db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 16510493fa79SVladimir Oltean if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) 1652db06ae41SAndrew Lunn return 0; 1653db06ae41SAndrew Lunn 165434065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 1655fad09c73SVivien Didelot if (err) 16567095a4c4SVivien Didelot return err; 1657fad09c73SVivien Didelot 1658fad09c73SVivien Didelot if (!vlan.valid) 1659b7a9e0daSVladimir Oltean return 0; 1660fad09c73SVivien Didelot 16610493fa79SVladimir Oltean dsa_switch_for_each_user_port(other_dp, ds) { 16620493fa79SVladimir Oltean if (vlan.member[other_dp->index] == 16637ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1664fad09c73SVivien Didelot continue; 1665fad09c73SVivien Didelot 16660493fa79SVladimir Oltean if (dp->bridge_dev == other_dp->bridge_dev) 1667fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1668fad09c73SVivien Didelot 16690493fa79SVladimir Oltean if (!other_dp->bridge_dev) 167066e2809dSAndrew Lunn continue; 167166e2809dSAndrew Lunn 1672743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 16730493fa79SVladimir Oltean port, vlan.vid, other_dp->index, 16740493fa79SVladimir Oltean netdev_name(other_dp->bridge_dev)); 16757095a4c4SVivien Didelot return -EOPNOTSUPP; 1676fad09c73SVivien Didelot } 1677fad09c73SVivien Didelot 16787095a4c4SVivien Didelot return 0; 1679fad09c73SVivien Didelot } 1680fad09c73SVivien Didelot 16818b6836d8SVladimir Oltean static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port) 16828b6836d8SVladimir Oltean { 16838b6836d8SVladimir Oltean struct dsa_port *dp = dsa_to_port(chip->ds, port); 16848b6836d8SVladimir Oltean struct mv88e6xxx_port *p = &chip->ports[port]; 16855bded825SVladimir Oltean u16 pvid = MV88E6XXX_VID_STANDALONE; 16868b6836d8SVladimir Oltean bool drop_untagged = false; 16878b6836d8SVladimir Oltean int err; 16888b6836d8SVladimir Oltean 16895bded825SVladimir Oltean if (dp->bridge_dev) { 16905bded825SVladimir Oltean if (br_vlan_enabled(dp->bridge_dev)) { 16918b6836d8SVladimir Oltean pvid = p->bridge_pvid.vid; 16928b6836d8SVladimir Oltean drop_untagged = !p->bridge_pvid.valid; 16935bded825SVladimir Oltean } else { 16945bded825SVladimir Oltean pvid = MV88E6XXX_VID_BRIDGED; 16955bded825SVladimir Oltean } 16968b6836d8SVladimir Oltean } 16978b6836d8SVladimir Oltean 16988b6836d8SVladimir Oltean err = mv88e6xxx_port_set_pvid(chip, port, pvid); 16998b6836d8SVladimir Oltean if (err) 17008b6836d8SVladimir Oltean return err; 17018b6836d8SVladimir Oltean 17028b6836d8SVladimir Oltean return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged); 17038b6836d8SVladimir Oltean } 17048b6836d8SVladimir Oltean 1705fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 170689153ed6SVladimir Oltean bool vlan_filtering, 170789153ed6SVladimir Oltean struct netlink_ext_ack *extack) 1708fad09c73SVivien Didelot { 170904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 171081c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 171181c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 17120e7b9925SAndrew Lunn int err; 1713fad09c73SVivien Didelot 1714bae33f2bSVladimir Oltean if (!mv88e6xxx_max_vid(chip)) 1715bae33f2bSVladimir Oltean return -EOPNOTSUPP; 1716fad09c73SVivien Didelot 1717c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 17188b6836d8SVladimir Oltean 1719385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 17208b6836d8SVladimir Oltean if (err) 17218b6836d8SVladimir Oltean goto unlock; 17228b6836d8SVladimir Oltean 17238b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 17248b6836d8SVladimir Oltean if (err) 17258b6836d8SVladimir Oltean goto unlock; 17268b6836d8SVladimir Oltean 17278b6836d8SVladimir Oltean unlock: 1728c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1729fad09c73SVivien Didelot 17300e7b9925SAndrew Lunn return err; 1731fad09c73SVivien Didelot } 1732fad09c73SVivien Didelot 1733fad09c73SVivien Didelot static int 1734fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 173580e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1736fad09c73SVivien Didelot { 173704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1738fad09c73SVivien Didelot int err; 1739fad09c73SVivien Didelot 1740e545f865STobias Waldekranz if (!mv88e6xxx_max_vid(chip)) 1741fad09c73SVivien Didelot return -EOPNOTSUPP; 1742fad09c73SVivien Didelot 1743fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1744fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1745fad09c73SVivien Didelot */ 17467095a4c4SVivien Didelot mv88e6xxx_reg_lock(chip); 1747b7a9e0daSVladimir Oltean err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid); 17487095a4c4SVivien Didelot mv88e6xxx_reg_unlock(chip); 1749fad09c73SVivien Didelot 17507095a4c4SVivien Didelot return err; 1751fad09c73SVivien Didelot } 1752fad09c73SVivien Didelot 1753a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1754a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 1755a4c93ae1SAndrew Lunn u8 state) 1756a4c93ae1SAndrew Lunn { 1757a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 17585ef8d249SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 17595ef8d249SVivien Didelot u16 fid; 1760a4c93ae1SAndrew Lunn int err; 1761a4c93ae1SAndrew Lunn 17625bded825SVladimir Oltean /* Ports have two private address databases: one for when the port is 17635bded825SVladimir Oltean * standalone and one for when the port is under a bridge and the 17645bded825SVladimir Oltean * 802.1Q mode is disabled. When the port is standalone, DSA wants its 17655bded825SVladimir Oltean * address database to remain 100% empty, so we never load an ATU entry 17665bded825SVladimir Oltean * into a standalone port's database. Therefore, translate the null 17675bded825SVladimir Oltean * VLAN ID into the port's database used for VLAN-unaware bridging. 17685bded825SVladimir Oltean */ 17695ef8d249SVivien Didelot if (vid == 0) { 17705bded825SVladimir Oltean fid = MV88E6XXX_FID_BRIDGED; 17715ef8d249SVivien Didelot } else { 177234065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 17735ef8d249SVivien Didelot if (err) 17745ef8d249SVivien Didelot return err; 17755ef8d249SVivien Didelot 17765ef8d249SVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 177734065c58STobias Waldekranz if (!vlan.valid) 17785ef8d249SVivien Didelot return -EOPNOTSUPP; 17795ef8d249SVivien Didelot 17805ef8d249SVivien Didelot fid = vlan.fid; 17815ef8d249SVivien Didelot } 1782a4c93ae1SAndrew Lunn 1783d8291a95SVivien Didelot entry.state = 0; 1784a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1785a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 1786a4c93ae1SAndrew Lunn 17875ef8d249SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry); 1788a4c93ae1SAndrew Lunn if (err) 1789a4c93ae1SAndrew Lunn return err; 1790a4c93ae1SAndrew Lunn 1791a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 1792d8291a95SVivien Didelot if (!entry.state || !ether_addr_equal(entry.mac, addr)) { 1793a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 1794a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1795a4c93ae1SAndrew Lunn } 1796a4c93ae1SAndrew Lunn 1797a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 1798d8291a95SVivien Didelot if (!state) { 1799a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 1800a4c93ae1SAndrew Lunn if (!entry.portvec) 1801d8291a95SVivien Didelot entry.state = 0; 1802a4c93ae1SAndrew Lunn } else { 1803f72f2fb8SDENG Qingfang if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC) 1804f72f2fb8SDENG Qingfang entry.portvec = BIT(port); 1805f72f2fb8SDENG Qingfang else 1806a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 1807f72f2fb8SDENG Qingfang 1808a4c93ae1SAndrew Lunn entry.state = state; 1809a4c93ae1SAndrew Lunn } 1810a4c93ae1SAndrew Lunn 18115ef8d249SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry); 1812a4c93ae1SAndrew Lunn } 1813a4c93ae1SAndrew Lunn 1814da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port, 1815da7dc875SVivien Didelot const struct mv88e6xxx_policy *policy) 1816da7dc875SVivien Didelot { 1817da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping = policy->mapping; 1818da7dc875SVivien Didelot enum mv88e6xxx_policy_action action = policy->action; 1819da7dc875SVivien Didelot const u8 *addr = policy->addr; 1820da7dc875SVivien Didelot u16 vid = policy->vid; 1821da7dc875SVivien Didelot u8 state; 1822da7dc875SVivien Didelot int err; 1823da7dc875SVivien Didelot int id; 1824da7dc875SVivien Didelot 1825da7dc875SVivien Didelot if (!chip->info->ops->port_set_policy) 1826da7dc875SVivien Didelot return -EOPNOTSUPP; 1827da7dc875SVivien Didelot 1828da7dc875SVivien Didelot switch (mapping) { 1829da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_DA: 1830da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_SA: 1831da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1832da7dc875SVivien Didelot state = 0; /* Dissociate the port and address */ 1833da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1834da7dc875SVivien Didelot is_multicast_ether_addr(addr)) 1835da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY; 1836da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1837da7dc875SVivien Didelot is_unicast_ether_addr(addr)) 1838da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY; 1839da7dc875SVivien Didelot else 1840da7dc875SVivien Didelot return -EOPNOTSUPP; 1841da7dc875SVivien Didelot 1842da7dc875SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 1843da7dc875SVivien Didelot state); 1844da7dc875SVivien Didelot if (err) 1845da7dc875SVivien Didelot return err; 1846da7dc875SVivien Didelot break; 1847da7dc875SVivien Didelot default: 1848da7dc875SVivien Didelot return -EOPNOTSUPP; 1849da7dc875SVivien Didelot } 1850da7dc875SVivien Didelot 1851da7dc875SVivien Didelot /* Skip the port's policy clearing if the mapping is still in use */ 1852da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1853da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1854da7dc875SVivien Didelot if (policy->port == port && 1855da7dc875SVivien Didelot policy->mapping == mapping && 1856da7dc875SVivien Didelot policy->action != action) 1857da7dc875SVivien Didelot return 0; 1858da7dc875SVivien Didelot 1859da7dc875SVivien Didelot return chip->info->ops->port_set_policy(chip, port, mapping, action); 1860da7dc875SVivien Didelot } 1861da7dc875SVivien Didelot 1862da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port, 1863da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs) 1864da7dc875SVivien Didelot { 1865da7dc875SVivien Didelot struct ethhdr *mac_entry = &fs->h_u.ether_spec; 1866da7dc875SVivien Didelot struct ethhdr *mac_mask = &fs->m_u.ether_spec; 1867da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping; 1868da7dc875SVivien Didelot enum mv88e6xxx_policy_action action; 1869da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1870da7dc875SVivien Didelot u16 vid = 0; 1871da7dc875SVivien Didelot u8 *addr; 1872da7dc875SVivien Didelot int err; 1873da7dc875SVivien Didelot int id; 1874da7dc875SVivien Didelot 1875da7dc875SVivien Didelot if (fs->location != RX_CLS_LOC_ANY) 1876da7dc875SVivien Didelot return -EINVAL; 1877da7dc875SVivien Didelot 1878da7dc875SVivien Didelot if (fs->ring_cookie == RX_CLS_FLOW_DISC) 1879da7dc875SVivien Didelot action = MV88E6XXX_POLICY_ACTION_DISCARD; 1880da7dc875SVivien Didelot else 1881da7dc875SVivien Didelot return -EOPNOTSUPP; 1882da7dc875SVivien Didelot 1883da7dc875SVivien Didelot switch (fs->flow_type & ~FLOW_EXT) { 1884da7dc875SVivien Didelot case ETHER_FLOW: 1885da7dc875SVivien Didelot if (!is_zero_ether_addr(mac_mask->h_dest) && 1886da7dc875SVivien Didelot is_zero_ether_addr(mac_mask->h_source)) { 1887da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_DA; 1888da7dc875SVivien Didelot addr = mac_entry->h_dest; 1889da7dc875SVivien Didelot } else if (is_zero_ether_addr(mac_mask->h_dest) && 1890da7dc875SVivien Didelot !is_zero_ether_addr(mac_mask->h_source)) { 1891da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_SA; 1892da7dc875SVivien Didelot addr = mac_entry->h_source; 1893da7dc875SVivien Didelot } else { 1894da7dc875SVivien Didelot /* Cannot support DA and SA mapping in the same rule */ 1895da7dc875SVivien Didelot return -EOPNOTSUPP; 1896da7dc875SVivien Didelot } 1897da7dc875SVivien Didelot break; 1898da7dc875SVivien Didelot default: 1899da7dc875SVivien Didelot return -EOPNOTSUPP; 1900da7dc875SVivien Didelot } 1901da7dc875SVivien Didelot 1902da7dc875SVivien Didelot if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) { 190304844280SAndrew Lunn if (fs->m_ext.vlan_tci != htons(0xffff)) 1904da7dc875SVivien Didelot return -EOPNOTSUPP; 1905da7dc875SVivien Didelot vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; 1906da7dc875SVivien Didelot } 1907da7dc875SVivien Didelot 1908da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) { 1909da7dc875SVivien Didelot if (policy->port == port && policy->mapping == mapping && 1910da7dc875SVivien Didelot policy->action == action && policy->vid == vid && 1911da7dc875SVivien Didelot ether_addr_equal(policy->addr, addr)) 1912da7dc875SVivien Didelot return -EEXIST; 1913da7dc875SVivien Didelot } 1914da7dc875SVivien Didelot 1915da7dc875SVivien Didelot policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL); 1916da7dc875SVivien Didelot if (!policy) 1917da7dc875SVivien Didelot return -ENOMEM; 1918da7dc875SVivien Didelot 1919da7dc875SVivien Didelot fs->location = 0; 1920da7dc875SVivien Didelot err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff, 1921da7dc875SVivien Didelot GFP_KERNEL); 1922da7dc875SVivien Didelot if (err) { 1923da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1924da7dc875SVivien Didelot return err; 1925da7dc875SVivien Didelot } 1926da7dc875SVivien Didelot 1927da7dc875SVivien Didelot memcpy(&policy->fs, fs, sizeof(*fs)); 1928da7dc875SVivien Didelot ether_addr_copy(policy->addr, addr); 1929da7dc875SVivien Didelot policy->mapping = mapping; 1930da7dc875SVivien Didelot policy->action = action; 1931da7dc875SVivien Didelot policy->port = port; 1932da7dc875SVivien Didelot policy->vid = vid; 1933da7dc875SVivien Didelot 1934da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1935da7dc875SVivien Didelot if (err) { 1936da7dc875SVivien Didelot idr_remove(&chip->policies, fs->location); 1937da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1938da7dc875SVivien Didelot return err; 1939da7dc875SVivien Didelot } 1940da7dc875SVivien Didelot 1941da7dc875SVivien Didelot return 0; 1942da7dc875SVivien Didelot } 1943da7dc875SVivien Didelot 1944da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, 1945da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 1946da7dc875SVivien Didelot { 1947da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1948da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1949da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1950da7dc875SVivien Didelot int err; 1951da7dc875SVivien Didelot int id; 1952da7dc875SVivien Didelot 1953da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1954da7dc875SVivien Didelot 1955da7dc875SVivien Didelot switch (rxnfc->cmd) { 1956da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLCNT: 1957da7dc875SVivien Didelot rxnfc->data = 0; 1958da7dc875SVivien Didelot rxnfc->data |= RX_CLS_LOC_SPECIAL; 1959da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1960da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1961da7dc875SVivien Didelot if (policy->port == port) 1962da7dc875SVivien Didelot rxnfc->rule_cnt++; 1963da7dc875SVivien Didelot err = 0; 1964da7dc875SVivien Didelot break; 1965da7dc875SVivien Didelot case ETHTOOL_GRXCLSRULE: 1966da7dc875SVivien Didelot err = -ENOENT; 1967da7dc875SVivien Didelot policy = idr_find(&chip->policies, fs->location); 1968da7dc875SVivien Didelot if (policy) { 1969da7dc875SVivien Didelot memcpy(fs, &policy->fs, sizeof(*fs)); 1970da7dc875SVivien Didelot err = 0; 1971da7dc875SVivien Didelot } 1972da7dc875SVivien Didelot break; 1973da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLALL: 1974da7dc875SVivien Didelot rxnfc->data = 0; 1975da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1976da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1977da7dc875SVivien Didelot if (policy->port == port) 1978da7dc875SVivien Didelot rule_locs[rxnfc->rule_cnt++] = id; 1979da7dc875SVivien Didelot err = 0; 1980da7dc875SVivien Didelot break; 1981da7dc875SVivien Didelot default: 1982da7dc875SVivien Didelot err = -EOPNOTSUPP; 1983da7dc875SVivien Didelot break; 1984da7dc875SVivien Didelot } 1985da7dc875SVivien Didelot 1986da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1987da7dc875SVivien Didelot 1988da7dc875SVivien Didelot return err; 1989da7dc875SVivien Didelot } 1990da7dc875SVivien Didelot 1991da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, 1992da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc) 1993da7dc875SVivien Didelot { 1994da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1995da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1996da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1997da7dc875SVivien Didelot int err; 1998da7dc875SVivien Didelot 1999da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 2000da7dc875SVivien Didelot 2001da7dc875SVivien Didelot switch (rxnfc->cmd) { 2002da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLINS: 2003da7dc875SVivien Didelot err = mv88e6xxx_policy_insert(chip, port, fs); 2004da7dc875SVivien Didelot break; 2005da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLDEL: 2006da7dc875SVivien Didelot err = -ENOENT; 2007da7dc875SVivien Didelot policy = idr_remove(&chip->policies, fs->location); 2008da7dc875SVivien Didelot if (policy) { 2009da7dc875SVivien Didelot policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; 2010da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 2011da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 2012da7dc875SVivien Didelot } 2013da7dc875SVivien Didelot break; 2014da7dc875SVivien Didelot default: 2015da7dc875SVivien Didelot err = -EOPNOTSUPP; 2016da7dc875SVivien Didelot break; 2017da7dc875SVivien Didelot } 2018da7dc875SVivien Didelot 2019da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 2020da7dc875SVivien Didelot 2021da7dc875SVivien Didelot return err; 2022da7dc875SVivien Didelot } 2023da7dc875SVivien Didelot 202487fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 202587fa886eSAndrew Lunn u16 vid) 202687fa886eSAndrew Lunn { 202787fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 20280806dd46STobias Waldekranz u8 broadcast[ETH_ALEN]; 20290806dd46STobias Waldekranz 20300806dd46STobias Waldekranz eth_broadcast_addr(broadcast); 203187fa886eSAndrew Lunn 203287fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 203387fa886eSAndrew Lunn } 203487fa886eSAndrew Lunn 203587fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 203687fa886eSAndrew Lunn { 203787fa886eSAndrew Lunn int port; 203887fa886eSAndrew Lunn int err; 203987fa886eSAndrew Lunn 204087fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 20418d1d8298STobias Waldekranz struct dsa_port *dp = dsa_to_port(chip->ds, port); 20428d1d8298STobias Waldekranz struct net_device *brport; 20438d1d8298STobias Waldekranz 20448d1d8298STobias Waldekranz if (dsa_is_unused_port(chip->ds, port)) 20458d1d8298STobias Waldekranz continue; 20468d1d8298STobias Waldekranz 20478d1d8298STobias Waldekranz brport = dsa_port_to_bridge_port(dp); 20488d1d8298STobias Waldekranz if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD)) 20498d1d8298STobias Waldekranz /* Skip bridged user ports where broadcast 20508d1d8298STobias Waldekranz * flooding is disabled. 20518d1d8298STobias Waldekranz */ 20528d1d8298STobias Waldekranz continue; 20538d1d8298STobias Waldekranz 205487fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 205587fa886eSAndrew Lunn if (err) 205687fa886eSAndrew Lunn return err; 205787fa886eSAndrew Lunn } 205887fa886eSAndrew Lunn 205987fa886eSAndrew Lunn return 0; 206087fa886eSAndrew Lunn } 206187fa886eSAndrew Lunn 20628d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx { 20638d1d8298STobias Waldekranz int port; 20648d1d8298STobias Waldekranz bool flood; 20658d1d8298STobias Waldekranz }; 20668d1d8298STobias Waldekranz 20678d1d8298STobias Waldekranz static int 20688d1d8298STobias Waldekranz mv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip, 20698d1d8298STobias Waldekranz const struct mv88e6xxx_vtu_entry *vlan, 20708d1d8298STobias Waldekranz void *_ctx) 20718d1d8298STobias Waldekranz { 20728d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx; 20738d1d8298STobias Waldekranz u8 broadcast[ETH_ALEN]; 20748d1d8298STobias Waldekranz u8 state; 20758d1d8298STobias Waldekranz 20768d1d8298STobias Waldekranz if (ctx->flood) 20778d1d8298STobias Waldekranz state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 20788d1d8298STobias Waldekranz else 20798d1d8298STobias Waldekranz state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED; 20808d1d8298STobias Waldekranz 20818d1d8298STobias Waldekranz eth_broadcast_addr(broadcast); 20828d1d8298STobias Waldekranz 20838d1d8298STobias Waldekranz return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast, 20848d1d8298STobias Waldekranz vlan->vid, state); 20858d1d8298STobias Waldekranz } 20868d1d8298STobias Waldekranz 20878d1d8298STobias Waldekranz static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port, 20888d1d8298STobias Waldekranz bool flood) 20898d1d8298STobias Waldekranz { 20908d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx ctx = { 20918d1d8298STobias Waldekranz .port = port, 20928d1d8298STobias Waldekranz .flood = flood, 20938d1d8298STobias Waldekranz }; 20948d1d8298STobias Waldekranz struct mv88e6xxx_vtu_entry vid0 = { 20958d1d8298STobias Waldekranz .vid = 0, 20968d1d8298STobias Waldekranz }; 20978d1d8298STobias Waldekranz int err; 20988d1d8298STobias Waldekranz 20998d1d8298STobias Waldekranz /* Update the port's private database... */ 21008d1d8298STobias Waldekranz err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx); 21018d1d8298STobias Waldekranz if (err) 21028d1d8298STobias Waldekranz return err; 21038d1d8298STobias Waldekranz 21048d1d8298STobias Waldekranz /* ...and the database for all VLANs. */ 21058d1d8298STobias Waldekranz return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan, 21068d1d8298STobias Waldekranz &ctx); 21078d1d8298STobias Waldekranz } 21088d1d8298STobias Waldekranz 2109b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, 2110933b4425SRussell King u16 vid, u8 member, bool warn) 2111fad09c73SVivien Didelot { 2112b1ac6fb4SVivien Didelot const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 2113b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 2114b1ac6fb4SVivien Didelot int i, err; 2115fad09c73SVivien Didelot 211634065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 2117fad09c73SVivien Didelot if (err) 2118fad09c73SVivien Didelot return err; 2119fad09c73SVivien Didelot 212034065c58STobias Waldekranz if (!vlan.valid) { 2121b1ac6fb4SVivien Didelot memset(&vlan, 0, sizeof(vlan)); 2122b1ac6fb4SVivien Didelot 2123b1ac6fb4SVivien Didelot err = mv88e6xxx_atu_new(chip, &vlan.fid); 2124b1ac6fb4SVivien Didelot if (err) 2125b1ac6fb4SVivien Didelot return err; 2126b1ac6fb4SVivien Didelot 2127b1ac6fb4SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 2128b1ac6fb4SVivien Didelot if (i == port) 2129b1ac6fb4SVivien Didelot vlan.member[i] = member; 2130b1ac6fb4SVivien Didelot else 2131b1ac6fb4SVivien Didelot vlan.member[i] = non_member; 2132b1ac6fb4SVivien Didelot 2133b1ac6fb4SVivien Didelot vlan.vid = vid; 21341cb9dfcaSRasmus Villemoes vlan.valid = true; 2135fad09c73SVivien Didelot 213687fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 213787fa886eSAndrew Lunn if (err) 213887fa886eSAndrew Lunn return err; 213987fa886eSAndrew Lunn 2140b1ac6fb4SVivien Didelot err = mv88e6xxx_broadcast_setup(chip, vlan.vid); 2141b1ac6fb4SVivien Didelot if (err) 2142b1ac6fb4SVivien Didelot return err; 2143b1ac6fb4SVivien Didelot } else if (vlan.member[port] != member) { 2144b1ac6fb4SVivien Didelot vlan.member[port] = member; 2145b1ac6fb4SVivien Didelot 2146b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2147b1ac6fb4SVivien Didelot if (err) 2148b1ac6fb4SVivien Didelot return err; 2149933b4425SRussell King } else if (warn) { 2150b1ac6fb4SVivien Didelot dev_info(chip->dev, "p%d: already a member of VLAN %d\n", 2151b1ac6fb4SVivien Didelot port, vid); 2152b1ac6fb4SVivien Didelot } 2153b1ac6fb4SVivien Didelot 2154b1ac6fb4SVivien Didelot return 0; 2155fad09c73SVivien Didelot } 2156fad09c73SVivien Didelot 21571958d581SVladimir Oltean static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 215831046a5fSVladimir Oltean const struct switchdev_obj_port_vlan *vlan, 215931046a5fSVladimir Oltean struct netlink_ext_ack *extack) 2160fad09c73SVivien Didelot { 216104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2162fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 2163fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 21648b6836d8SVladimir Oltean struct mv88e6xxx_port *p = &chip->ports[port]; 2165933b4425SRussell King bool warn; 2166c91498e1SVivien Didelot u8 member; 21671958d581SVladimir Oltean int err; 2168fad09c73SVivien Didelot 2169b8b79c41SEldar Gasanov if (!vlan->vid) 2170b8b79c41SEldar Gasanov return 0; 2171b8b79c41SEldar Gasanov 21721958d581SVladimir Oltean err = mv88e6xxx_port_vlan_prepare(ds, port, vlan); 21731958d581SVladimir Oltean if (err) 21741958d581SVladimir Oltean return err; 2175fad09c73SVivien Didelot 2176c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 21777ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 2178c91498e1SVivien Didelot else if (untagged) 21797ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 2180c91498e1SVivien Didelot else 21817ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 2182c91498e1SVivien Didelot 2183933b4425SRussell King /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port 2184933b4425SRussell King * and then the CPU port. Do not warn for duplicates for the CPU port. 2185933b4425SRussell King */ 2186933b4425SRussell King warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); 2187933b4425SRussell King 2188c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2189fad09c73SVivien Didelot 21901958d581SVladimir Oltean err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn); 21911958d581SVladimir Oltean if (err) { 2192774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 2193b7a9e0daSVladimir Oltean vlan->vid, untagged ? 'u' : 't'); 21941958d581SVladimir Oltean goto out; 21951958d581SVladimir Oltean } 2196fad09c73SVivien Didelot 21971958d581SVladimir Oltean if (pvid) { 21988b6836d8SVladimir Oltean p->bridge_pvid.vid = vlan->vid; 21998b6836d8SVladimir Oltean p->bridge_pvid.valid = true; 22008b6836d8SVladimir Oltean 22018b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 22028b6836d8SVladimir Oltean if (err) 22038b6836d8SVladimir Oltean goto out; 22048b6836d8SVladimir Oltean } else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) { 22058b6836d8SVladimir Oltean /* The old pvid was reinstalled as a non-pvid VLAN */ 22068b6836d8SVladimir Oltean p->bridge_pvid.valid = false; 22078b6836d8SVladimir Oltean 22088b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 22098b6836d8SVladimir Oltean if (err) 22101958d581SVladimir Oltean goto out; 22111958d581SVladimir Oltean } 22128b6836d8SVladimir Oltean 22131958d581SVladimir Oltean out: 2214c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 22151958d581SVladimir Oltean 22161958d581SVladimir Oltean return err; 2217fad09c73SVivien Didelot } 2218fad09c73SVivien Didelot 221952109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, 2220fad09c73SVivien Didelot int port, u16 vid) 2221fad09c73SVivien Didelot { 2222b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 2223fad09c73SVivien Didelot int i, err; 2224fad09c73SVivien Didelot 222552109892SVivien Didelot if (!vid) 2226c92c7413SVladimir Oltean return 0; 222752109892SVivien Didelot 222834065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 2229fad09c73SVivien Didelot if (err) 2230fad09c73SVivien Didelot return err; 2231fad09c73SVivien Didelot 223252109892SVivien Didelot /* If the VLAN doesn't exist in hardware or the port isn't a member, 223352109892SVivien Didelot * tell switchdev that this VLAN is likely handled in software. 223452109892SVivien Didelot */ 223534065c58STobias Waldekranz if (!vlan.valid || 223652109892SVivien Didelot vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 2237fad09c73SVivien Didelot return -EOPNOTSUPP; 2238fad09c73SVivien Didelot 22397ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 2240fad09c73SVivien Didelot 2241fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 2242fad09c73SVivien Didelot vlan.valid = false; 2243370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 22447ec60d6eSVivien Didelot if (vlan.member[i] != 22457ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 2246fad09c73SVivien Didelot vlan.valid = true; 2247fad09c73SVivien Didelot break; 2248fad09c73SVivien Didelot } 2249fad09c73SVivien Didelot } 2250fad09c73SVivien Didelot 22510ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2252fad09c73SVivien Didelot if (err) 2253fad09c73SVivien Didelot return err; 2254fad09c73SVivien Didelot 2255e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 2256fad09c73SVivien Didelot } 2257fad09c73SVivien Didelot 2258fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 2259fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 2260fad09c73SVivien Didelot { 226104bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 22628b6836d8SVladimir Oltean struct mv88e6xxx_port *p = &chip->ports[port]; 2263fad09c73SVivien Didelot int err = 0; 2264b7a9e0daSVladimir Oltean u16 pvid; 2265fad09c73SVivien Didelot 2266e545f865STobias Waldekranz if (!mv88e6xxx_max_vid(chip)) 2267fad09c73SVivien Didelot return -EOPNOTSUPP; 2268fad09c73SVivien Didelot 2269c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2270fad09c73SVivien Didelot 227177064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 2272fad09c73SVivien Didelot if (err) 2273fad09c73SVivien Didelot goto unlock; 2274fad09c73SVivien Didelot 2275b7a9e0daSVladimir Oltean err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid); 2276fad09c73SVivien Didelot if (err) 2277fad09c73SVivien Didelot goto unlock; 2278fad09c73SVivien Didelot 2279b7a9e0daSVladimir Oltean if (vlan->vid == pvid) { 22808b6836d8SVladimir Oltean p->bridge_pvid.valid = false; 22818b6836d8SVladimir Oltean 22828b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 2283fad09c73SVivien Didelot if (err) 2284fad09c73SVivien Didelot goto unlock; 2285fad09c73SVivien Didelot } 2286fad09c73SVivien Didelot 2287fad09c73SVivien Didelot unlock: 2288c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2289fad09c73SVivien Didelot 2290fad09c73SVivien Didelot return err; 2291fad09c73SVivien Didelot } 2292fad09c73SVivien Didelot 22931b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 22946c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2295fad09c73SVivien Didelot { 229604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 22971b6dd556SArkadi Sharshevsky int err; 2298fad09c73SVivien Didelot 2299c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 23001b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 23011b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 2302c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 23031b6dd556SArkadi Sharshevsky 23041b6dd556SArkadi Sharshevsky return err; 2305fad09c73SVivien Didelot } 2306fad09c73SVivien Didelot 2307fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 23086c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2309fad09c73SVivien Didelot { 231004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 231183dabd1fSVivien Didelot int err; 2312fad09c73SVivien Didelot 2313c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2314d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); 2315c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2316fad09c73SVivien Didelot 231783dabd1fSVivien Didelot return err; 2318fad09c73SVivien Didelot } 2319fad09c73SVivien Didelot 232083dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 2321fad09c73SVivien Didelot u16 fid, u16 vid, int port, 23222bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2323fad09c73SVivien Didelot { 2324dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 23252bedde1aSArkadi Sharshevsky bool is_static; 2326fad09c73SVivien Didelot int err; 2327fad09c73SVivien Didelot 2328d8291a95SVivien Didelot addr.state = 0; 2329dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 2330fad09c73SVivien Didelot 2331fad09c73SVivien Didelot do { 2332dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 2333fad09c73SVivien Didelot if (err) 233483dabd1fSVivien Didelot return err; 2335fad09c73SVivien Didelot 2336d8291a95SVivien Didelot if (!addr.state) 2337fad09c73SVivien Didelot break; 2338fad09c73SVivien Didelot 233901bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 234083dabd1fSVivien Didelot continue; 2341fad09c73SVivien Didelot 234283dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 234383dabd1fSVivien Didelot continue; 234483dabd1fSVivien Didelot 23452bedde1aSArkadi Sharshevsky is_static = (addr.state == 23462bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 23472bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 234883dabd1fSVivien Didelot if (err) 234983dabd1fSVivien Didelot return err; 2350fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 2351fad09c73SVivien Didelot 2352fad09c73SVivien Didelot return err; 2353fad09c73SVivien Didelot } 2354fad09c73SVivien Didelot 2355d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx { 2356d89ef4b8STobias Waldekranz int port; 2357d89ef4b8STobias Waldekranz dsa_fdb_dump_cb_t *cb; 2358d89ef4b8STobias Waldekranz void *data; 2359d89ef4b8STobias Waldekranz }; 2360d89ef4b8STobias Waldekranz 2361d89ef4b8STobias Waldekranz static int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip, 2362d89ef4b8STobias Waldekranz const struct mv88e6xxx_vtu_entry *entry, 2363d89ef4b8STobias Waldekranz void *_data) 2364d89ef4b8STobias Waldekranz { 2365d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data; 2366d89ef4b8STobias Waldekranz 2367d89ef4b8STobias Waldekranz return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid, 2368d89ef4b8STobias Waldekranz ctx->port, ctx->cb, ctx->data); 2369d89ef4b8STobias Waldekranz } 2370d89ef4b8STobias Waldekranz 237183dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 23722bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 237383dabd1fSVivien Didelot { 2374d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx ctx = { 2375d89ef4b8STobias Waldekranz .port = port, 2376d89ef4b8STobias Waldekranz .cb = cb, 2377d89ef4b8STobias Waldekranz .data = data, 2378d89ef4b8STobias Waldekranz }; 237983dabd1fSVivien Didelot u16 fid; 238083dabd1fSVivien Didelot int err; 238183dabd1fSVivien Didelot 238283dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 2383b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 238483dabd1fSVivien Didelot if (err) 238583dabd1fSVivien Didelot return err; 238683dabd1fSVivien Didelot 23872bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 238883dabd1fSVivien Didelot if (err) 238983dabd1fSVivien Didelot return err; 239083dabd1fSVivien Didelot 2391d89ef4b8STobias Waldekranz return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx); 239283dabd1fSVivien Didelot } 239383dabd1fSVivien Didelot 2394fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 23952bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2396fad09c73SVivien Didelot { 239704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2398fcf15367SVivien Didelot int err; 2399fad09c73SVivien Didelot 2400c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2401fcf15367SVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, cb, data); 2402c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2403fcf15367SVivien Didelot 2404fcf15367SVivien Didelot return err; 2405fad09c73SVivien Didelot } 2406fad09c73SVivien Didelot 2407240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 2408240ea3efSVivien Didelot struct net_device *br) 2409240ea3efSVivien Didelot { 2410ef2025ecSVivien Didelot struct dsa_switch *ds = chip->ds; 2411ef2025ecSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 2412ef2025ecSVivien Didelot struct dsa_port *dp; 2413240ea3efSVivien Didelot int err; 2414240ea3efSVivien Didelot 2415ef2025ecSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 2416ef2025ecSVivien Didelot if (dp->bridge_dev == br) { 2417ef2025ecSVivien Didelot if (dp->ds == ds) { 2418ef2025ecSVivien Didelot /* This is a local bridge group member, 2419ef2025ecSVivien Didelot * remap its Port VLAN Map. 2420ef2025ecSVivien Didelot */ 2421ef2025ecSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, dp->index); 2422240ea3efSVivien Didelot if (err) 2423240ea3efSVivien Didelot return err; 2424ef2025ecSVivien Didelot } else { 2425ef2025ecSVivien Didelot /* This is an external bridge group member, 2426ef2025ecSVivien Didelot * remap its cross-chip Port VLAN Table entry. 2427ef2025ecSVivien Didelot */ 2428ef2025ecSVivien Didelot err = mv88e6xxx_pvt_map(chip, dp->ds->index, 2429ef2025ecSVivien Didelot dp->index); 2430e96a6e02SVivien Didelot if (err) 2431e96a6e02SVivien Didelot return err; 2432e96a6e02SVivien Didelot } 2433e96a6e02SVivien Didelot } 2434e96a6e02SVivien Didelot } 2435e96a6e02SVivien Didelot 2436240ea3efSVivien Didelot return 0; 2437240ea3efSVivien Didelot } 2438240ea3efSVivien Didelot 2439fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 2440fae8a25eSVivien Didelot struct net_device *br) 2441fad09c73SVivien Didelot { 244204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2443240ea3efSVivien Didelot int err; 2444fad09c73SVivien Didelot 2445c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 24465bded825SVladimir Oltean 2447240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 24485bded825SVladimir Oltean if (err) 24495bded825SVladimir Oltean goto unlock; 24505bded825SVladimir Oltean 24515bded825SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 24525bded825SVladimir Oltean if (err) 24535bded825SVladimir Oltean goto unlock; 24545bded825SVladimir Oltean 24555bded825SVladimir Oltean unlock: 2456c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2457fad09c73SVivien Didelot 2458fad09c73SVivien Didelot return err; 2459fad09c73SVivien Didelot } 2460fad09c73SVivien Didelot 2461f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 2462f123f2fbSVivien Didelot struct net_device *br) 2463fad09c73SVivien Didelot { 246404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 24655bded825SVladimir Oltean int err; 2466fad09c73SVivien Didelot 2467c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 24685bded825SVladimir Oltean 2469240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 2470240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 2471240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 24725bded825SVladimir Oltean 24735bded825SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 24745bded825SVladimir Oltean if (err) 24755bded825SVladimir Oltean dev_err(ds->dev, 24765bded825SVladimir Oltean "port %d failed to restore standalone pvid: %pe\n", 24775bded825SVladimir Oltean port, ERR_PTR(err)); 24785bded825SVladimir Oltean 2479c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2480fad09c73SVivien Didelot } 2481fad09c73SVivien Didelot 2482f66a6a69SVladimir Oltean static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, 2483f66a6a69SVladimir Oltean int tree_index, int sw_index, 2484aec5ac88SVivien Didelot int port, struct net_device *br) 2485aec5ac88SVivien Didelot { 2486aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2487aec5ac88SVivien Didelot int err; 2488aec5ac88SVivien Didelot 2489f66a6a69SVladimir Oltean if (tree_index != ds->dst->index) 2490f66a6a69SVladimir Oltean return 0; 2491f66a6a69SVladimir Oltean 2492c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2493f66a6a69SVladimir Oltean err = mv88e6xxx_pvt_map(chip, sw_index, port); 2494c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2495aec5ac88SVivien Didelot 2496aec5ac88SVivien Didelot return err; 2497aec5ac88SVivien Didelot } 2498aec5ac88SVivien Didelot 2499f66a6a69SVladimir Oltean static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, 2500f66a6a69SVladimir Oltean int tree_index, int sw_index, 2501aec5ac88SVivien Didelot int port, struct net_device *br) 2502aec5ac88SVivien Didelot { 2503aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2504aec5ac88SVivien Didelot 2505f66a6a69SVladimir Oltean if (tree_index != ds->dst->index) 2506f66a6a69SVladimir Oltean return; 2507f66a6a69SVladimir Oltean 2508c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2509f66a6a69SVladimir Oltean if (mv88e6xxx_pvt_map(chip, sw_index, port)) 2510aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2511c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2512aec5ac88SVivien Didelot } 2513aec5ac88SVivien Didelot 2514ce5df689SVladimir Oltean /* Treat the software bridge as a virtual single-port switch behind the 2515ce5df689SVladimir Oltean * CPU and map in the PVT. First dst->last_switch elements are taken by 2516ce5df689SVladimir Oltean * physical switches, so start from beyond that range. 2517ce5df689SVladimir Oltean */ 2518ce5df689SVladimir Oltean static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds, 25193f9bb030SVladimir Oltean unsigned int bridge_num) 2520ce5df689SVladimir Oltean { 25213f9bb030SVladimir Oltean u8 dev = bridge_num + ds->dst->last_switch; 2522ce5df689SVladimir Oltean struct mv88e6xxx_chip *chip = ds->priv; 2523ce5df689SVladimir Oltean int err; 2524ce5df689SVladimir Oltean 2525ce5df689SVladimir Oltean mv88e6xxx_reg_lock(chip); 2526ce5df689SVladimir Oltean err = mv88e6xxx_pvt_map(chip, dev, 0); 2527ce5df689SVladimir Oltean mv88e6xxx_reg_unlock(chip); 2528ce5df689SVladimir Oltean 2529ce5df689SVladimir Oltean return err; 2530ce5df689SVladimir Oltean } 2531ce5df689SVladimir Oltean 2532ce5df689SVladimir Oltean static int mv88e6xxx_bridge_tx_fwd_offload(struct dsa_switch *ds, int port, 2533ce5df689SVladimir Oltean struct net_device *br, 25343f9bb030SVladimir Oltean unsigned int bridge_num) 2535ce5df689SVladimir Oltean { 2536ce5df689SVladimir Oltean return mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num); 2537ce5df689SVladimir Oltean } 2538ce5df689SVladimir Oltean 2539ce5df689SVladimir Oltean static void mv88e6xxx_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port, 2540ce5df689SVladimir Oltean struct net_device *br, 25413f9bb030SVladimir Oltean unsigned int bridge_num) 2542ce5df689SVladimir Oltean { 2543ce5df689SVladimir Oltean int err; 2544ce5df689SVladimir Oltean 2545ce5df689SVladimir Oltean err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num); 2546ce5df689SVladimir Oltean if (err) { 2547ce5df689SVladimir Oltean dev_err(ds->dev, "failed to remap cross-chip Port VLAN: %pe\n", 2548ce5df689SVladimir Oltean ERR_PTR(err)); 2549ce5df689SVladimir Oltean } 2550ce5df689SVladimir Oltean } 2551ce5df689SVladimir Oltean 255217e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 255317e708baSVivien Didelot { 255417e708baSVivien Didelot if (chip->info->ops->reset) 255517e708baSVivien Didelot return chip->info->ops->reset(chip); 255617e708baSVivien Didelot 255717e708baSVivien Didelot return 0; 255817e708baSVivien Didelot } 255917e708baSVivien Didelot 2560309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 2561309eca6dSVivien Didelot { 2562309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 2563309eca6dSVivien Didelot 2564309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 2565309eca6dSVivien Didelot if (gpiod) { 2566309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 2567309eca6dSVivien Didelot usleep_range(10000, 20000); 2568309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 2569309eca6dSVivien Didelot usleep_range(10000, 20000); 2570a3dcb3e7SAndrew Lunn 2571a3dcb3e7SAndrew Lunn mv88e6xxx_g1_wait_eeprom_done(chip); 2572309eca6dSVivien Didelot } 2573309eca6dSVivien Didelot } 2574309eca6dSVivien Didelot 25754ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 25764ac4b5a6SVivien Didelot { 25774ac4b5a6SVivien Didelot int i, err; 25784ac4b5a6SVivien Didelot 25794ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 25804ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2581f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 25824ac4b5a6SVivien Didelot if (err) 25834ac4b5a6SVivien Didelot return err; 25844ac4b5a6SVivien Didelot } 25854ac4b5a6SVivien Didelot 25864ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 25874ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 25884ac4b5a6SVivien Didelot */ 25894ac4b5a6SVivien Didelot usleep_range(2000, 4000); 25904ac4b5a6SVivien Didelot 25914ac4b5a6SVivien Didelot return 0; 25924ac4b5a6SVivien Didelot } 25934ac4b5a6SVivien Didelot 2594fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 2595fad09c73SVivien Didelot { 2596a935c052SVivien Didelot int err; 2597fad09c73SVivien Didelot 25984ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 25990e7b9925SAndrew Lunn if (err) 26000e7b9925SAndrew Lunn return err; 2601fad09c73SVivien Didelot 2602309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 2603fad09c73SVivien Didelot 260417e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 2605fad09c73SVivien Didelot } 2606fad09c73SVivien Didelot 26074314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 260831bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 260931bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 261056995cbcSAndrew Lunn { 261156995cbcSAndrew Lunn int err; 261256995cbcSAndrew Lunn 26134314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 26144314557cSVivien Didelot return -EOPNOTSUPP; 26154314557cSVivien Didelot 26164314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 261756995cbcSAndrew Lunn if (err) 261856995cbcSAndrew Lunn return err; 261956995cbcSAndrew Lunn 26204314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 26214314557cSVivien Didelot if (err) 26224314557cSVivien Didelot return err; 26234314557cSVivien Didelot 26244314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 26254314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 26264314557cSVivien Didelot 26274314557cSVivien Didelot return 0; 26284314557cSVivien Didelot } 26294314557cSVivien Didelot 26304314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 26314314557cSVivien Didelot { 26324314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 263331bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2634b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 26354314557cSVivien Didelot } 26364314557cSVivien Didelot 26374314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 26384314557cSVivien Didelot { 26394314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 264031bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2641b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 26424314557cSVivien Didelot } 26434314557cSVivien Didelot 26444314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 26454314557cSVivien Didelot { 26464314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 26474314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 264831bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 264931bef4e9SVivien Didelot ETH_P_EDSA); 26504314557cSVivien Didelot } 26514314557cSVivien Didelot 26524314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 26534314557cSVivien Didelot { 26544314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 26554314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 26564314557cSVivien Didelot 26572b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 26584314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 26594314557cSVivien Didelot 26604314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 2661670bb80fSTobias Waldekranz if (chip->tag_protocol == DSA_TAG_PROTO_DSA) 26624314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 26634314557cSVivien Didelot 2664670bb80fSTobias Waldekranz if (chip->tag_protocol == DSA_TAG_PROTO_EDSA) 26654314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 26664314557cSVivien Didelot 26674314557cSVivien Didelot return -EINVAL; 26684314557cSVivien Didelot } 26694314557cSVivien Didelot 2670ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 2671ea698f4fSVivien Didelot { 2672ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 2673ea698f4fSVivien Didelot 2674ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 2675ea698f4fSVivien Didelot } 2676ea698f4fSVivien Didelot 2677601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 2678601aeed3SVivien Didelot { 2679a8b659e7SVladimir Oltean int err; 2680601aeed3SVivien Didelot 2681a8b659e7SVladimir Oltean if (chip->info->ops->port_set_ucast_flood) { 26827b9f16feSTobias Waldekranz err = chip->info->ops->port_set_ucast_flood(chip, port, true); 2683a8b659e7SVladimir Oltean if (err) 2684a8b659e7SVladimir Oltean return err; 2685a8b659e7SVladimir Oltean } 2686a8b659e7SVladimir Oltean if (chip->info->ops->port_set_mcast_flood) { 26877b9f16feSTobias Waldekranz err = chip->info->ops->port_set_mcast_flood(chip, port, true); 2688a8b659e7SVladimir Oltean if (err) 2689a8b659e7SVladimir Oltean return err; 2690a8b659e7SVladimir Oltean } 2691407308f6SDavid S. Miller 2692601aeed3SVivien Didelot return 0; 2693601aeed3SVivien Didelot } 2694601aeed3SVivien Didelot 269545de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id) 269645de77ffSVivien Didelot { 269745de77ffSVivien Didelot struct mv88e6xxx_port *mvp = dev_id; 269845de77ffSVivien Didelot struct mv88e6xxx_chip *chip = mvp->chip; 269945de77ffSVivien Didelot irqreturn_t ret = IRQ_NONE; 270045de77ffSVivien Didelot int port = mvp->port; 2701193c5b26SPavana Sharma int lane; 270245de77ffSVivien Didelot 270345de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 270445de77ffSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 2705193c5b26SPavana Sharma if (lane >= 0) 270645de77ffSVivien Didelot ret = mv88e6xxx_serdes_irq_status(chip, port, lane); 270745de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 270845de77ffSVivien Didelot 270945de77ffSVivien Didelot return ret; 271045de77ffSVivien Didelot } 271145de77ffSVivien Didelot 271245de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port, 2713193c5b26SPavana Sharma int lane) 271445de77ffSVivien Didelot { 271545de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 271645de77ffSVivien Didelot unsigned int irq; 271745de77ffSVivien Didelot int err; 271845de77ffSVivien Didelot 271945de77ffSVivien Didelot /* Nothing to request if this SERDES port has no IRQ */ 272045de77ffSVivien Didelot irq = mv88e6xxx_serdes_irq_mapping(chip, port); 272145de77ffSVivien Didelot if (!irq) 272245de77ffSVivien Didelot return 0; 272345de77ffSVivien Didelot 2724e6f2f6b8SAndrew Lunn snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name), 2725e6f2f6b8SAndrew Lunn "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port); 2726e6f2f6b8SAndrew Lunn 272745de77ffSVivien Didelot /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */ 272845de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 272945de77ffSVivien Didelot err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn, 2730e6f2f6b8SAndrew Lunn IRQF_ONESHOT, dev_id->serdes_irq_name, 2731e6f2f6b8SAndrew Lunn dev_id); 273245de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 273345de77ffSVivien Didelot if (err) 273445de77ffSVivien Didelot return err; 273545de77ffSVivien Didelot 273645de77ffSVivien Didelot dev_id->serdes_irq = irq; 273745de77ffSVivien Didelot 273845de77ffSVivien Didelot return mv88e6xxx_serdes_irq_enable(chip, port, lane); 273945de77ffSVivien Didelot } 274045de77ffSVivien Didelot 274145de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port, 2742193c5b26SPavana Sharma int lane) 274345de77ffSVivien Didelot { 274445de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 274545de77ffSVivien Didelot unsigned int irq = dev_id->serdes_irq; 274645de77ffSVivien Didelot int err; 274745de77ffSVivien Didelot 274845de77ffSVivien Didelot /* Nothing to free if no IRQ has been requested */ 274945de77ffSVivien Didelot if (!irq) 275045de77ffSVivien Didelot return 0; 275145de77ffSVivien Didelot 275245de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 275345de77ffSVivien Didelot 275445de77ffSVivien Didelot /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */ 275545de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 275645de77ffSVivien Didelot free_irq(irq, dev_id); 275745de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 275845de77ffSVivien Didelot 275945de77ffSVivien Didelot dev_id->serdes_irq = 0; 276045de77ffSVivien Didelot 276145de77ffSVivien Didelot return err; 276245de77ffSVivien Didelot } 276345de77ffSVivien Didelot 27646d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 27656d91782fSAndrew Lunn bool on) 27666d91782fSAndrew Lunn { 2767193c5b26SPavana Sharma int lane; 2768fc0bc019SVivien Didelot int err; 27696d91782fSAndrew Lunn 2770dc272f60SVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 2771193c5b26SPavana Sharma if (lane < 0) 2772523a8904SVivien Didelot return 0; 2773fc0bc019SVivien Didelot 2774fc0bc019SVivien Didelot if (on) { 2775dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_up(chip, port, lane); 2776fc0bc019SVivien Didelot if (err) 2777fc0bc019SVivien Didelot return err; 2778fc0bc019SVivien Didelot 277945de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_request(chip, port, lane); 2780fc0bc019SVivien Didelot } else { 278145de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_free(chip, port, lane); 278245de77ffSVivien Didelot if (err) 278345de77ffSVivien Didelot return err; 2784fc0bc019SVivien Didelot 2785dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_down(chip, port, lane); 2786fc0bc019SVivien Didelot } 2787fc0bc019SVivien Didelot 2788fc0bc019SVivien Didelot return err; 27896d91782fSAndrew Lunn } 27906d91782fSAndrew Lunn 27912fda45f0SMarek Behún static int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip, 27922fda45f0SMarek Behún enum mv88e6xxx_egress_direction direction, 27932fda45f0SMarek Behún int port) 27942fda45f0SMarek Behún { 27952fda45f0SMarek Behún int err; 27962fda45f0SMarek Behún 27972fda45f0SMarek Behún if (!chip->info->ops->set_egress_port) 27982fda45f0SMarek Behún return -EOPNOTSUPP; 27992fda45f0SMarek Behún 28002fda45f0SMarek Behún err = chip->info->ops->set_egress_port(chip, direction, port); 28012fda45f0SMarek Behún if (err) 28022fda45f0SMarek Behún return err; 28032fda45f0SMarek Behún 28042fda45f0SMarek Behún if (direction == MV88E6XXX_EGRESS_DIR_INGRESS) 28052fda45f0SMarek Behún chip->ingress_dest_port = port; 28062fda45f0SMarek Behún else 28072fda45f0SMarek Behún chip->egress_dest_port = port; 28082fda45f0SMarek Behún 28092fda45f0SMarek Behún return 0; 28102fda45f0SMarek Behún } 28112fda45f0SMarek Behún 2812fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 2813fa371c80SVivien Didelot { 2814fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 2815fa371c80SVivien Didelot int upstream_port; 2816fa371c80SVivien Didelot int err; 2817fa371c80SVivien Didelot 281807073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 2819fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 2820fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 2821fa371c80SVivien Didelot upstream_port); 2822fa371c80SVivien Didelot if (err) 2823fa371c80SVivien Didelot return err; 2824fa371c80SVivien Didelot } 2825fa371c80SVivien Didelot 28260ea54ddaSVivien Didelot if (port == upstream_port) { 28270ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 28280ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 28290ea54ddaSVivien Didelot upstream_port); 28300ea54ddaSVivien Didelot if (err) 28310ea54ddaSVivien Didelot return err; 28320ea54ddaSVivien Didelot } 28330ea54ddaSVivien Didelot 28342fda45f0SMarek Behún err = mv88e6xxx_set_egress_port(chip, 28355c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS, 28365c74c54cSIwan R Timmer upstream_port); 28372fda45f0SMarek Behún if (err && err != -EOPNOTSUPP) 28385c74c54cSIwan R Timmer return err; 28395c74c54cSIwan R Timmer 28402fda45f0SMarek Behún err = mv88e6xxx_set_egress_port(chip, 28415c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS, 28420ea54ddaSVivien Didelot upstream_port); 28432fda45f0SMarek Behún if (err && err != -EOPNOTSUPP) 28440ea54ddaSVivien Didelot return err; 28450ea54ddaSVivien Didelot } 28460ea54ddaSVivien Didelot 2847fa371c80SVivien Didelot return 0; 2848fa371c80SVivien Didelot } 2849fa371c80SVivien Didelot 2850fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 2851fad09c73SVivien Didelot { 2852fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 28530e7b9925SAndrew Lunn int err; 2854fad09c73SVivien Didelot u16 reg; 2855fad09c73SVivien Didelot 28567b898469SAndrew Lunn chip->ports[port].chip = chip; 28577b898469SAndrew Lunn chip->ports[port].port = port; 28587b898469SAndrew Lunn 2859d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 2860d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 2861d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 2862fad09c73SVivien Didelot */ 2863d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 2864d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 2865d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 286654186b91SAndrew Lunn PAUSE_OFF, 2867d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 2868fad09c73SVivien Didelot else 2869d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 2870d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 287154186b91SAndrew Lunn PAUSE_ON, 2872d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 28730e7b9925SAndrew Lunn if (err) 28740e7b9925SAndrew Lunn return err; 2875fad09c73SVivien Didelot 2876fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 2877fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 2878fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 2879fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 2880fad09c73SVivien Didelot * to Forwarding. 2881fad09c73SVivien Didelot * 2882fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 2883fad09c73SVivien Didelot * on which tagging mode was configured. 2884fad09c73SVivien Didelot * 2885fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 2886fad09c73SVivien Didelot * 2887fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 2888fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 2889fad09c73SVivien Didelot */ 2890a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 2891a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 2892a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 2893a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 28940e7b9925SAndrew Lunn if (err) 28950e7b9925SAndrew Lunn return err; 289656995cbcSAndrew Lunn 2897601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 289856995cbcSAndrew Lunn if (err) 289956995cbcSAndrew Lunn return err; 2900fad09c73SVivien Didelot 2901601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 29024314557cSVivien Didelot if (err) 29034314557cSVivien Didelot return err; 29044314557cSVivien Didelot 2905b92ce2f5SAndrew Lunn /* Port Control 2: don't force a good FCS, set the MTU size to 2906b92ce2f5SAndrew Lunn * 10222 bytes, disable 802.1q tags checking, don't discard tagged or 2907fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 2908fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 2909fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 2910fad09c73SVivien Didelot */ 2911a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 2912a23b2961SAndrew Lunn if (err) 2913a23b2961SAndrew Lunn return err; 2914a23b2961SAndrew Lunn 2915fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 29160e7b9925SAndrew Lunn if (err) 29170e7b9925SAndrew Lunn return err; 2918fad09c73SVivien Didelot 2919a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 292081c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); 2921a23b2961SAndrew Lunn if (err) 2922a23b2961SAndrew Lunn return err; 2923a23b2961SAndrew Lunn 29245bded825SVladimir Oltean /* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the 29255bded825SVladimir Oltean * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as 29265bded825SVladimir Oltean * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used 29275bded825SVladimir Oltean * as the private PVID on ports under a VLAN-unaware bridge. 29285bded825SVladimir Oltean * Shared (DSA and CPU) ports must also be members of it, to translate 29295bded825SVladimir Oltean * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of 29305bded825SVladimir Oltean * relying on their port default FID. 29315bded825SVladimir Oltean */ 29325bded825SVladimir Oltean err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED, 29335bded825SVladimir Oltean MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED, 29345bded825SVladimir Oltean false); 29355bded825SVladimir Oltean if (err) 29365bded825SVladimir Oltean return err; 29375bded825SVladimir Oltean 2938cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 2939b92ce2f5SAndrew Lunn err = chip->info->ops->port_set_jumbo_size(chip, port, 10218); 29405f436666SAndrew Lunn if (err) 29415f436666SAndrew Lunn return err; 29425f436666SAndrew Lunn } 29435f436666SAndrew Lunn 2944041bd545STobias Waldekranz /* Port Association Vector: disable automatic address learning 2945041bd545STobias Waldekranz * on all user ports since they start out in standalone 2946041bd545STobias Waldekranz * mode. When joining a bridge, learning will be configured to 2947041bd545STobias Waldekranz * match the bridge port settings. Enable learning on all 2948041bd545STobias Waldekranz * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the 2949041bd545STobias Waldekranz * learning process. 2950041bd545STobias Waldekranz * 2951041bd545STobias Waldekranz * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData, 2952041bd545STobias Waldekranz * and RefreshLocked. I.e. setup standard automatic learning. 2953fad09c73SVivien Didelot */ 2954041bd545STobias Waldekranz if (dsa_is_user_port(ds, port)) 2955fad09c73SVivien Didelot reg = 0; 2956041bd545STobias Waldekranz else 2957041bd545STobias Waldekranz reg = 1 << port; 2958fad09c73SVivien Didelot 29592a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 29602a4614e4SVivien Didelot reg); 29610e7b9925SAndrew Lunn if (err) 29620e7b9925SAndrew Lunn return err; 2963fad09c73SVivien Didelot 2964fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 29652cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 29662cb8cb14SVivien Didelot 0x0000); 29670e7b9925SAndrew Lunn if (err) 29680e7b9925SAndrew Lunn return err; 2969fad09c73SVivien Didelot 29700898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 29710898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 2972b35d322aSAndrew Lunn if (err) 2973b35d322aSAndrew Lunn return err; 2974b35d322aSAndrew Lunn } 2975b35d322aSAndrew Lunn 2976c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 2977c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 2978c8c94891SVivien Didelot if (err) 2979c8c94891SVivien Didelot return err; 2980c8c94891SVivien Didelot } 2981c8c94891SVivien Didelot 29829dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 29839dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 29840e7b9925SAndrew Lunn if (err) 29850e7b9925SAndrew Lunn return err; 2986ef0a7318SAndrew Lunn } 29872bbb33beSAndrew Lunn 2988ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 2989ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 29900e7b9925SAndrew Lunn if (err) 29910e7b9925SAndrew Lunn return err; 2992fad09c73SVivien Didelot } 2993fad09c73SVivien Didelot 2994ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 2995ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 29960e7b9925SAndrew Lunn if (err) 29970e7b9925SAndrew Lunn return err; 2998fad09c73SVivien Didelot } 2999fad09c73SVivien Didelot 3000121b8fe2SHubert Feurstein if (chip->info->ops->port_setup_message_port) { 3001121b8fe2SHubert Feurstein err = chip->info->ops->port_setup_message_port(chip, port); 30020e7b9925SAndrew Lunn if (err) 30030e7b9925SAndrew Lunn return err; 3004121b8fe2SHubert Feurstein } 3005fad09c73SVivien Didelot 3006fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 3007fad09c73SVivien Didelot * database, and allow bidirectional communication between the 3008fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 3009fad09c73SVivien Didelot */ 30105bded825SVladimir Oltean err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE); 30110e7b9925SAndrew Lunn if (err) 30120e7b9925SAndrew Lunn return err; 3013fad09c73SVivien Didelot 3014240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 30150e7b9925SAndrew Lunn if (err) 30160e7b9925SAndrew Lunn return err; 3017fad09c73SVivien Didelot 3018fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 3019fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 3020fad09c73SVivien Didelot */ 3021b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 3022fad09c73SVivien Didelot } 3023fad09c73SVivien Didelot 30242a550aecSAndrew Lunn static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port) 30252a550aecSAndrew Lunn { 30262a550aecSAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 30272a550aecSAndrew Lunn 30282a550aecSAndrew Lunn if (chip->info->ops->port_set_jumbo_size) 3029b9c587feSAndrew Lunn return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 30301baf0facSChris Packham else if (chip->info->ops->set_max_frame_size) 3031b9c587feSAndrew Lunn return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 3032b9c587feSAndrew Lunn return 1522 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 30332a550aecSAndrew Lunn } 30342a550aecSAndrew Lunn 30352a550aecSAndrew Lunn static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 30362a550aecSAndrew Lunn { 30372a550aecSAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 30382a550aecSAndrew Lunn int ret = 0; 30392a550aecSAndrew Lunn 3040b9c587feSAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 3041b9c587feSAndrew Lunn new_mtu += EDSA_HLEN; 3042b9c587feSAndrew Lunn 30432a550aecSAndrew Lunn mv88e6xxx_reg_lock(chip); 30442a550aecSAndrew Lunn if (chip->info->ops->port_set_jumbo_size) 30452a550aecSAndrew Lunn ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu); 30461baf0facSChris Packham else if (chip->info->ops->set_max_frame_size) 30471baf0facSChris Packham ret = chip->info->ops->set_max_frame_size(chip, new_mtu); 30482a550aecSAndrew Lunn else 30492a550aecSAndrew Lunn if (new_mtu > 1522) 30502a550aecSAndrew Lunn ret = -EINVAL; 30512a550aecSAndrew Lunn mv88e6xxx_reg_unlock(chip); 30522a550aecSAndrew Lunn 30532a550aecSAndrew Lunn return ret; 30542a550aecSAndrew Lunn } 30552a550aecSAndrew Lunn 305604aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 305704aca993SAndrew Lunn struct phy_device *phydev) 305804aca993SAndrew Lunn { 305904aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 3060523a8904SVivien Didelot int err; 306104aca993SAndrew Lunn 3062c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3063523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 3064c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 306504aca993SAndrew Lunn 306604aca993SAndrew Lunn return err; 306704aca993SAndrew Lunn } 306804aca993SAndrew Lunn 306975104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 307004aca993SAndrew Lunn { 307104aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 307204aca993SAndrew Lunn 3073c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3074523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 3075523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 3076c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 307704aca993SAndrew Lunn } 307804aca993SAndrew Lunn 30792cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 30802cfcd964SVivien Didelot unsigned int ageing_time) 30812cfcd964SVivien Didelot { 308204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 30832cfcd964SVivien Didelot int err; 30842cfcd964SVivien Didelot 3085c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3086720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 3087c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 30882cfcd964SVivien Didelot 30892cfcd964SVivien Didelot return err; 30902cfcd964SVivien Didelot } 30912cfcd964SVivien Didelot 3092447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 3093fad09c73SVivien Didelot { 3094fad09c73SVivien Didelot int err; 3095fad09c73SVivien Didelot 3096de227387SAndrew Lunn /* Initialize the statistics unit */ 3097447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 3098447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 3099de227387SAndrew Lunn if (err) 3100de227387SAndrew Lunn return err; 3101447b1bb8SVivien Didelot } 3102de227387SAndrew Lunn 310340cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 31049729934cSVivien Didelot } 31059729934cSVivien Didelot 3106ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 3107ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 3108ea89098eSAndrew Lunn { 3109ea89098eSAndrew Lunn int port; 3110ea89098eSAndrew Lunn int err; 3111ea89098eSAndrew Lunn u16 val; 3112ea89098eSAndrew Lunn 3113ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 311460907013SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val); 3115ea89098eSAndrew Lunn if (err) { 3116ea89098eSAndrew Lunn dev_err(chip->dev, 3117ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 3118ea89098eSAndrew Lunn return false; 3119ea89098eSAndrew Lunn } 3120ea89098eSAndrew Lunn if (val != 0x01c0) 3121ea89098eSAndrew Lunn return false; 3122ea89098eSAndrew Lunn } 3123ea89098eSAndrew Lunn 3124ea89098eSAndrew Lunn return true; 3125ea89098eSAndrew Lunn } 3126ea89098eSAndrew Lunn 3127ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 3128ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 3129ea89098eSAndrew Lunn * software reset. 3130ea89098eSAndrew Lunn */ 3131ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 3132ea89098eSAndrew Lunn { 3133ea89098eSAndrew Lunn int port; 3134ea89098eSAndrew Lunn int err; 3135ea89098eSAndrew Lunn 3136ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 3137ea89098eSAndrew Lunn return 0; 3138ea89098eSAndrew Lunn 3139ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 3140ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 3141ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 3142ea89098eSAndrew Lunn if (err) 3143ea89098eSAndrew Lunn return err; 3144ea89098eSAndrew Lunn } 3145ea89098eSAndrew Lunn 3146ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 314760907013SMarek Behún err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0); 3148ea89098eSAndrew Lunn if (err) 3149ea89098eSAndrew Lunn return err; 3150ea89098eSAndrew Lunn } 3151ea89098eSAndrew Lunn 3152ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 3153ea89098eSAndrew Lunn } 3154ea89098eSAndrew Lunn 315523e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds) 315623e8b470SAndrew Lunn { 315723e8b470SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 3158e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3159fd292c18SVladimir Oltean mv88e6xxx_teardown_devlink_regions_global(ds); 316023e8b470SAndrew Lunn } 316123e8b470SAndrew Lunn 3162fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 3163fad09c73SVivien Didelot { 316404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 31652d2e1dd2SAndrew Lunn u8 cmode; 3166fad09c73SVivien Didelot int err; 3167fad09c73SVivien Didelot int i; 3168fad09c73SVivien Didelot 3169fad09c73SVivien Didelot chip->ds = ds; 3170a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 3171fad09c73SVivien Didelot 3172ce5df689SVladimir Oltean /* Since virtual bridges are mapped in the PVT, the number we support 3173ce5df689SVladimir Oltean * depends on the physical switch topology. We need to let DSA figure 3174ce5df689SVladimir Oltean * that out and therefore we cannot set this at dsa_register_switch() 3175ce5df689SVladimir Oltean * time. 3176ce5df689SVladimir Oltean */ 3177ce5df689SVladimir Oltean if (mv88e6xxx_has_pvt(chip)) 3178947c8746SVladimir Oltean ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES - 3179ce5df689SVladimir Oltean ds->dst->last_switch - 1; 3180ce5df689SVladimir Oltean 3181c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3182fad09c73SVivien Didelot 3183ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 3184ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 3185ea89098eSAndrew Lunn if (err) 3186ea89098eSAndrew Lunn goto unlock; 3187ea89098eSAndrew Lunn } 3188ea89098eSAndrew Lunn 31892d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 31902d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 31912d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 31922d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 31932d2e1dd2SAndrew Lunn if (err) 3194e29129fcSDan Carpenter goto unlock; 31952d2e1dd2SAndrew Lunn 31962d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 31972d2e1dd2SAndrew Lunn } 31982d2e1dd2SAndrew Lunn } 31992d2e1dd2SAndrew Lunn 32005bded825SVladimir Oltean err = mv88e6xxx_vtu_setup(chip); 32015bded825SVladimir Oltean if (err) 32025bded825SVladimir Oltean goto unlock; 32035bded825SVladimir Oltean 32049729934cSVivien Didelot /* Setup Switch Port Registers */ 3205370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 3206b759f528SVivien Didelot if (dsa_is_unused_port(ds, i)) 3207b759f528SVivien Didelot continue; 3208b759f528SVivien Didelot 3209c857486aSHubert Feurstein /* Prevent the use of an invalid port. */ 3210b759f528SVivien Didelot if (mv88e6xxx_is_invalid_port(chip, i)) { 3211c857486aSHubert Feurstein dev_err(chip->dev, "port %d is invalid\n", i); 3212c857486aSHubert Feurstein err = -EINVAL; 3213c857486aSHubert Feurstein goto unlock; 3214c857486aSHubert Feurstein } 3215c857486aSHubert Feurstein 32169729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 32179729934cSVivien Didelot if (err) 32189729934cSVivien Didelot goto unlock; 32199729934cSVivien Didelot } 32209729934cSVivien Didelot 3221cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 3222cd8da8bbSVivien Didelot if (err) 3223cd8da8bbSVivien Didelot goto unlock; 3224cd8da8bbSVivien Didelot 322504a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 322604a69a17SVivien Didelot if (err) 322704a69a17SVivien Didelot goto unlock; 322804a69a17SVivien Didelot 32291b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 32301b17aedfSVivien Didelot if (err) 32311b17aedfSVivien Didelot goto unlock; 32321b17aedfSVivien Didelot 323381228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 323481228996SVivien Didelot if (err) 323581228996SVivien Didelot goto unlock; 323681228996SVivien Didelot 3237a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 3238a2ac29d2SVivien Didelot if (err) 3239a2ac29d2SVivien Didelot goto unlock; 3240a2ac29d2SVivien Didelot 324187fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 324287fa886eSAndrew Lunn if (err) 324387fa886eSAndrew Lunn goto unlock; 324487fa886eSAndrew Lunn 32459e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 32469e907d73SVivien Didelot if (err) 32479e907d73SVivien Didelot goto unlock; 32489e907d73SVivien Didelot 32499e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 32509e5baf9bSVivien Didelot if (err) 32519e5baf9bSVivien Didelot goto unlock; 32529e5baf9bSVivien Didelot 325351c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 32546e55f698SAndrew Lunn if (err) 32556e55f698SAndrew Lunn goto unlock; 32566e55f698SAndrew Lunn 3257b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 3258b28f872dSVivien Didelot if (err) 3259b28f872dSVivien Didelot goto unlock; 3260b28f872dSVivien Didelot 3261c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 3262c7f047b6SVivien Didelot if (err) 3263c7f047b6SVivien Didelot goto unlock; 3264c7f047b6SVivien Didelot 326593e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 326693e18d61SVivien Didelot if (err) 326793e18d61SVivien Didelot goto unlock; 326893e18d61SVivien Didelot 3269c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 32702fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 32712fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 32722fa8d3afSBrandon Streiff if (err) 32732fa8d3afSBrandon Streiff goto unlock; 3274c6fe0ad2SBrandon Streiff 3275c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 3276c6fe0ad2SBrandon Streiff if (err) 3277c6fe0ad2SBrandon Streiff goto unlock; 32782fa8d3afSBrandon Streiff } 32792fa8d3afSBrandon Streiff 3280447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 3281447b1bb8SVivien Didelot if (err) 3282447b1bb8SVivien Didelot goto unlock; 3283447b1bb8SVivien Didelot 3284fad09c73SVivien Didelot unlock: 3285c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3286fad09c73SVivien Didelot 3287e0c69ca7SAndrew Lunn if (err) 3288e0c69ca7SAndrew Lunn return err; 3289e0c69ca7SAndrew Lunn 3290e0c69ca7SAndrew Lunn /* Have to be called without holding the register lock, since 3291e0c69ca7SAndrew Lunn * they take the devlink lock, and we later take the locks in 3292e0c69ca7SAndrew Lunn * the reverse order when getting/setting parameters or 3293e0c69ca7SAndrew Lunn * resource occupancy. 329423e8b470SAndrew Lunn */ 3295e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_resources(ds); 3296e0c69ca7SAndrew Lunn if (err) 3297e0c69ca7SAndrew Lunn return err; 3298e0c69ca7SAndrew Lunn 3299e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_params(ds); 3300e0c69ca7SAndrew Lunn if (err) 3301bfb25542SAndrew Lunn goto out_resources; 3302bfb25542SAndrew Lunn 3303fd292c18SVladimir Oltean err = mv88e6xxx_setup_devlink_regions_global(ds); 3304bfb25542SAndrew Lunn if (err) 3305bfb25542SAndrew Lunn goto out_params; 3306bfb25542SAndrew Lunn 3307bfb25542SAndrew Lunn return 0; 3308bfb25542SAndrew Lunn 3309bfb25542SAndrew Lunn out_params: 3310bfb25542SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 3311bfb25542SAndrew Lunn out_resources: 3312e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3313e0c69ca7SAndrew Lunn 3314e0c69ca7SAndrew Lunn return err; 3315fad09c73SVivien Didelot } 3316fad09c73SVivien Didelot 3317fd292c18SVladimir Oltean static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port) 3318fd292c18SVladimir Oltean { 3319fd292c18SVladimir Oltean return mv88e6xxx_setup_devlink_regions_port(ds, port); 3320fd292c18SVladimir Oltean } 3321fd292c18SVladimir Oltean 3322fd292c18SVladimir Oltean static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port) 3323fd292c18SVladimir Oltean { 3324fd292c18SVladimir Oltean mv88e6xxx_teardown_devlink_regions_port(ds, port); 3325fd292c18SVladimir Oltean } 3326fd292c18SVladimir Oltean 33271fe976d3SPali Rohár /* prod_id for switch families which do not have a PHY model number */ 33281fe976d3SPali Rohár static const u16 family_prod_id_table[] = { 33291fe976d3SPali Rohár [MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 33301fe976d3SPali Rohár [MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 3331c5d015b0SMarek Behún [MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, 33321fe976d3SPali Rohár }; 33331fe976d3SPali Rohár 3334e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 3335fad09c73SVivien Didelot { 33360dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 33370dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 33381fe976d3SPali Rohár u16 prod_id; 3339e57e5e77SVivien Didelot u16 val; 3340e57e5e77SVivien Didelot int err; 3341fad09c73SVivien Didelot 3342ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 3343ee26a228SAndrew Lunn return -EOPNOTSUPP; 3344ee26a228SAndrew Lunn 3345c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3346ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 3347c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3348e57e5e77SVivien Didelot 3349ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 33501fe976d3SPali Rohár if (reg == MII_PHYSID2 && !(val & 0x3f0) && 33511fe976d3SPali Rohár chip->info->family < ARRAY_SIZE(family_prod_id_table)) { 33521fe976d3SPali Rohár prod_id = family_prod_id_table[chip->info->family]; 33531fe976d3SPali Rohár if (prod_id) 33541fe976d3SPali Rohár val |= prod_id >> 4; 3355da9f3301SAndrew Lunn } 3356da9f3301SAndrew Lunn 3357e57e5e77SVivien Didelot return err ? err : val; 3358fad09c73SVivien Didelot } 3359fad09c73SVivien Didelot 3360e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 3361fad09c73SVivien Didelot { 33620dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 33630dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3364e57e5e77SVivien Didelot int err; 3365fad09c73SVivien Didelot 3366ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 3367ee26a228SAndrew Lunn return -EOPNOTSUPP; 3368ee26a228SAndrew Lunn 3369c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3370ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 3371c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3372e57e5e77SVivien Didelot 3373e57e5e77SVivien Didelot return err; 3374fad09c73SVivien Didelot } 3375fad09c73SVivien Didelot 3376fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 3377a3c53be5SAndrew Lunn struct device_node *np, 3378a3c53be5SAndrew Lunn bool external) 3379fad09c73SVivien Didelot { 3380fad09c73SVivien Didelot static int index; 33810dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 3382fad09c73SVivien Didelot struct mii_bus *bus; 3383fad09c73SVivien Didelot int err; 3384fad09c73SVivien Didelot 33852510babcSAndrew Lunn if (external) { 3386c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 33872510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 3388c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 33892510babcSAndrew Lunn 33902510babcSAndrew Lunn if (err) 33912510babcSAndrew Lunn return err; 33922510babcSAndrew Lunn } 33932510babcSAndrew Lunn 33940dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 3395fad09c73SVivien Didelot if (!bus) 3396fad09c73SVivien Didelot return -ENOMEM; 3397fad09c73SVivien Didelot 33980dd12d54SAndrew Lunn mdio_bus = bus->priv; 3399a3c53be5SAndrew Lunn mdio_bus->bus = bus; 34000dd12d54SAndrew Lunn mdio_bus->chip = chip; 3401a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 3402a3c53be5SAndrew Lunn mdio_bus->external = external; 34030dd12d54SAndrew Lunn 3404fad09c73SVivien Didelot if (np) { 3405fad09c73SVivien Didelot bus->name = np->full_name; 3406f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 3407fad09c73SVivien Didelot } else { 3408fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 3409fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 3410fad09c73SVivien Didelot } 3411fad09c73SVivien Didelot 3412fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 3413fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 3414fad09c73SVivien Didelot bus->parent = chip->dev; 3415fad09c73SVivien Didelot 34166f88284fSAndrew Lunn if (!external) { 34176f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 34186f88284fSAndrew Lunn if (err) 34196f88284fSAndrew Lunn return err; 34206f88284fSAndrew Lunn } 34216f88284fSAndrew Lunn 3422a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 3423fad09c73SVivien Didelot if (err) { 3424fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 34256f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 3426fad09c73SVivien Didelot return err; 3427fad09c73SVivien Didelot } 3428fad09c73SVivien Didelot 3429a3c53be5SAndrew Lunn if (external) 3430a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 3431a3c53be5SAndrew Lunn else 3432a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 3433a3c53be5SAndrew Lunn 3434a3c53be5SAndrew Lunn return 0; 3435a3c53be5SAndrew Lunn } 3436a3c53be5SAndrew Lunn 34373126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 34383126aeecSAndrew Lunn 34393126aeecSAndrew Lunn { 34403126aeecSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 34413126aeecSAndrew Lunn struct mii_bus *bus; 34423126aeecSAndrew Lunn 34433126aeecSAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 34443126aeecSAndrew Lunn bus = mdio_bus->bus; 34453126aeecSAndrew Lunn 34466f88284fSAndrew Lunn if (!mdio_bus->external) 34476f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 34486f88284fSAndrew Lunn 34493126aeecSAndrew Lunn mdiobus_unregister(bus); 34503126aeecSAndrew Lunn } 34513126aeecSAndrew Lunn } 34523126aeecSAndrew Lunn 3453a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 3454a3c53be5SAndrew Lunn struct device_node *np) 3455a3c53be5SAndrew Lunn { 3456a3c53be5SAndrew Lunn struct device_node *child; 3457a3c53be5SAndrew Lunn int err; 3458a3c53be5SAndrew Lunn 3459a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 3460a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 3461a3c53be5SAndrew Lunn * optional. 3462a3c53be5SAndrew Lunn */ 3463a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 3464a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 3465a3c53be5SAndrew Lunn if (err) 3466a3c53be5SAndrew Lunn return err; 3467a3c53be5SAndrew Lunn 3468a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 3469a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 3470a3c53be5SAndrew Lunn * bus. 3471a3c53be5SAndrew Lunn */ 3472a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 3473ceb96faeSAndrew Lunn if (of_device_is_compatible( 3474ceb96faeSAndrew Lunn child, "marvell,mv88e6xxx-mdio-external")) { 3475a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 34763126aeecSAndrew Lunn if (err) { 34773126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 347878e42040SNishka Dasgupta of_node_put(child); 3479a3c53be5SAndrew Lunn return err; 3480a3c53be5SAndrew Lunn } 3481a3c53be5SAndrew Lunn } 34823126aeecSAndrew Lunn } 3483a3c53be5SAndrew Lunn 3484a3c53be5SAndrew Lunn return 0; 3485a3c53be5SAndrew Lunn } 3486a3c53be5SAndrew Lunn 3487855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 3488855b1932SVivien Didelot { 348904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3490855b1932SVivien Didelot 3491855b1932SVivien Didelot return chip->eeprom_len; 3492855b1932SVivien Didelot } 3493855b1932SVivien Didelot 3494855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 3495855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3496855b1932SVivien Didelot { 349704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3498855b1932SVivien Didelot int err; 3499855b1932SVivien Didelot 3500ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 3501ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3502ee4dc2e7SVivien Didelot 3503c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3504ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 3505c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3506855b1932SVivien Didelot 3507855b1932SVivien Didelot if (err) 3508855b1932SVivien Didelot return err; 3509855b1932SVivien Didelot 3510855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 3511855b1932SVivien Didelot 3512855b1932SVivien Didelot return 0; 3513855b1932SVivien Didelot } 3514855b1932SVivien Didelot 3515855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 3516855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3517855b1932SVivien Didelot { 351804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3519855b1932SVivien Didelot int err; 3520855b1932SVivien Didelot 3521ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 3522ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3523ee4dc2e7SVivien Didelot 3524855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 3525855b1932SVivien Didelot return -EINVAL; 3526855b1932SVivien Didelot 3527c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3528ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 3529c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3530855b1932SVivien Didelot 3531855b1932SVivien Didelot return err; 3532855b1932SVivien Didelot } 3533855b1932SVivien Didelot 3534b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 35354b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 353693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 353793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3538cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3539b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 35407e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 35417e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 354208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 35434efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3544f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3545ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 354656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3547a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3548a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 354956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3550ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35510898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3552c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35539dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35542d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3555121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3556a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 355740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3558dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3559dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3560052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3561fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3562fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3563fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 356451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35659e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3566a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3567a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 356817e708baSVivien Didelot .reset = mv88e6185_g1_reset, 35699e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3570f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35710ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 35726c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 35731baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3574b3469dd8SVivien Didelot }; 3575b3469dd8SVivien Didelot 3576b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 35774b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 357893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 357993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3580b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 35817e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 35827e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 358308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 35844efe7662SChris Packham .port_sync_link = mv88e6185_port_sync_link, 3585f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 358656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3587a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 3588a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6185_port_set_default_forward, 3589a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 35902d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3591121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3592a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 359340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3594dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3595dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3596052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 359751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3598f5be107cSChris Packham .serdes_power = mv88e6185_serdes_power, 3599f5be107cSChris Packham .serdes_get_lane = mv88e6185_serdes_get_lane, 3600f5be107cSChris Packham .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state, 3601a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3602a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 360317e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3604f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 36050ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 36066c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 36071baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3608b3469dd8SVivien Didelot }; 3609b3469dd8SVivien Didelot 36107d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 361115da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 361293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 361393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3614cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 36157d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 36167d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 36177d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 36187d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 36194efe7662SChris Packham .port_sync_link = mv88e6185_port_sync_link, 3620f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3621ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 362256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3623a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3624a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 362556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3626ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 36270898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3628c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36299dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36302d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3631121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 36327d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 363340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 36347d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 36357d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 36367d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 3637fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3638fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 363991eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 364051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 3641f5be107cSChris Packham .serdes_power = mv88e6185_serdes_power, 3642f5be107cSChris Packham .serdes_get_lane = mv88e6185_serdes_get_lane, 3643f5be107cSChris Packham .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state, 36445c19bc8bSChris Packham .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 36455c19bc8bSChris Packham .serdes_irq_enable = mv88e6097_serdes_irq_enable, 36465c19bc8bSChris Packham .serdes_irq_status = mv88e6097_serdes_irq_status, 36479e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 364817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 36499e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3650f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36510ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 36526c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 36531baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 36547d381a02SStefan Eichenberger }; 36557d381a02SStefan Eichenberger 3656b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 36574b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 365893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 365993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3660cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3661b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3662ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3663ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 366408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 36654efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3666f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 366756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3668a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3669a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 3670c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36719dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36722d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3673121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 36740ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 367540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3676dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3677dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3678052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3679fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3680fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3681fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 368251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36839e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 368417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 368523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 368623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3687f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36880ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 36896c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 36901baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3691b3469dd8SVivien Didelot }; 3692b3469dd8SVivien Didelot 3693b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 36944b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 369593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 369693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3697b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 36987e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 36997e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 370008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37014efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3702f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3703ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 370456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3705a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 3706a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6185_port_set_default_forward, 370756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3708a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 3709cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3710ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37110898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 371254186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 37132d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3714121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3715a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 371640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3717dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3718dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3719052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3720fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3721fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3722fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 372351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3724a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 372502317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3726a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 372717e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3728f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 37290ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 37306c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3731b3469dd8SVivien Didelot }; 3732b3469dd8SVivien Didelot 3733990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 3734990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 373593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 373693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3737cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3738990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 3739990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 3740990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3741990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3742990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 3743990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 37444efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3745990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3746f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 37477cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 3748990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 37497da467d8SMarek Behún .port_set_policy = mv88e6352_port_set_policy, 3750990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3751a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3752a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 3753990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3754cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3755990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37560898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3757990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 3758990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37592d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 37607a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 3761121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3762990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 376311527f3cSMarek Behún .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3764990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3765990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 3766990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3767fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3768fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 3769990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 3770990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 37719e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3772990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 377337094887SMarek Behún .rmu_disable = mv88e6390_g1_rmu_disable, 3774c07fff34SMarek Behún .atu_get_hash = mv88e6165_g1_atu_get_hash, 3775c07fff34SMarek Behún .atu_set_hash = mv88e6165_g1_atu_set_hash, 3776f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37770ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3778d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 3779d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 3780a5a6858bSRussell King /* Check status register pause & lpa register */ 3781a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3782a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3783a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3784a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 37854241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 378661a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3787907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 3788a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 3789a03b98d6SMarek Behún .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 3790a03b98d6SMarek Behún .serdes_get_strings = mv88e6390_serdes_get_strings, 3791a03b98d6SMarek Behún .serdes_get_stats = mv88e6390_serdes_get_stats, 3792953b0dcbSMarek Behún .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3793953b0dcbSMarek Behún .serdes_get_regs = mv88e6390_serdes_get_regs, 3794e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 3795990e27b0SVivien Didelot }; 3796990e27b0SVivien Didelot 3797b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 37984b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 379993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 380093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3801cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3802b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3803ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3804ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 380508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 38064efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3807f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3808ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 380956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3810a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3811a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 381256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3813ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38140898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3815c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38169dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38172d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3818121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3819a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 382040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3821dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3822dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3823052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3824fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3825fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3826fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 382751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38289e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 382917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 383023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 383123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3832f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38330ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3834a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3835dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 38366c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3837fe230361SAndrew Lunn .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3838b3469dd8SVivien Didelot }; 3839b3469dd8SVivien Didelot 3840b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 38414b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 384293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 384393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3844cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3845b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3846efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 3847efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 384808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 38494efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3850f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3851c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38529dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38532d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3854121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3855a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 385640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3857dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3858dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3859052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3860fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3861fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3862fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 386351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38649e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 386517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 386623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 386723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3868f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38690ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3870a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3871dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 38726c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3873b3469dd8SVivien Didelot }; 3874b3469dd8SVivien Didelot 3875b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 38764b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 387793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 387893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3879cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3880b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3881b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3882b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 388308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 38844efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 388594d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3886f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3887ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 388856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3889a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3890a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 389156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3892cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3893ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38940898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3895c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38969dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38972d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3898121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3899a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 390040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3901dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3902dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3903052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3904fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3905fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3906fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 390751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 39089e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 390917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 391023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 391123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3912f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 39130ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 39146c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3915b3469dd8SVivien Didelot }; 3916b3469dd8SVivien Didelot 3917b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 39184b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 391993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 392093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3921cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3922ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3923ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3924b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3925b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3926b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 392708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 39284efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 3929a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3930f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 3931ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3932f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 393356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3934a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3935a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 393656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3937cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3938ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 39390898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3940c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39419dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39422d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3943121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3944a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 394540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3946dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3947dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3948052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3949fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3950fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3951fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 395251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 39539e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 395417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 39559e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 395623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 395723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3958f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 39590ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 39609db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 3961a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 3962a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 3963a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 3964a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 39656d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3966d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3967d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3968a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39696c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3970b3469dd8SVivien Didelot }; 3971b3469dd8SVivien Didelot 3972b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 39734b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 397493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 397593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3976cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3977b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3978b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3979b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 398008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 39814efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 398294d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3983f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3984ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 398556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3986a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 3987a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 398856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3989cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3990ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 39910898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3992c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39939dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39942d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3995121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3996a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 399740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3998dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3999dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4000052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4001fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4002fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4003fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 400451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 40059e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 400617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 400723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 400823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4009f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 40100ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 40116c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4012b3469dd8SVivien Didelot }; 4013b3469dd8SVivien Didelot 4014b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 40154b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 401693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 401793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4018cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4019ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4020ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4021b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4022b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4023b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 402408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 40254efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4026a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4027f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4028ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4029f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 403056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4031a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4032a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 403356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4034cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4035ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 40360898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4037c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40389dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40392d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4040121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4041a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 404240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4043dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4044dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4045052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4046fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4047fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4048fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 404951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 40509e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 405117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 40529e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 405323e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 405423e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4055f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 40560ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 40579db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4058a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4059a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4060a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4061a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 40626d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 40634241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 406461a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4065907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4066d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4067d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4068a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 40696c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4070b3469dd8SVivien Didelot }; 4071b3469dd8SVivien Didelot 4072b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 40734b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 407493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 407593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4076b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 40777e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 40787e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 407908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 40804efe7662SChris Packham .port_sync_link = mv88e6185_port_sync_link, 4081f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 408256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 4083a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 4084a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6185_port_set_default_forward, 4085ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 4086a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 408754186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 40882d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4089121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4090a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 409140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4092dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4093dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4094052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4095fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4096fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4097fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 409851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 4099f5be107cSChris Packham .serdes_power = mv88e6185_serdes_power, 4100f5be107cSChris Packham .serdes_get_lane = mv88e6185_serdes_get_lane, 4101f5be107cSChris Packham .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state, 410202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 4103a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 4104a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 410517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 4106f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 41070ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 41086c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 41091baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 4110b3469dd8SVivien Didelot }; 4111b3469dd8SVivien Didelot 41121a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 41134b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4114ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4115cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 411698fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 411798fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 41181a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41191a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 41201a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 41211a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 41224efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 41231a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4124f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 41257cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4126ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4127f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 412856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4129a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4130a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 413156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4132e8b34c67SChris Packham .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 41330898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4134c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41359dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41362d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4137fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4138121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 413979523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4140de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4141dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4142dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4143e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4144fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4145fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 414661303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 41476e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 41489e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 414917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 41509e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 415123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 415223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4153931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4154931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 41556335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 415617deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4157a5a6858bSRussell King /* Check status register pause & lpa register */ 4158a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4159a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4160a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4161a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 41624241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 416361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4164907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 41654262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 41664262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4167bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4168bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4169a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 41706c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 41711a3b39ecSAndrew Lunn }; 41721a3b39ecSAndrew Lunn 41731a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 41744b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4175ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4176cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 417798fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 417898fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 41791a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41801a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 41811a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 41821a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 41834efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 41841a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4185f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 41867cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 4187ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4188f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 418956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4190a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4191a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 419256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4193e8b34c67SChris Packham .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 41940898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4195c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41969dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41972d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4198fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 4199121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 420079523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4201de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4202dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4203dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4204e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4205fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4206fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 420761303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 42086e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 42099e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 421017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 42119e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 421223e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 421323e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4214931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4215931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4216d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 421717deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 4218a5a6858bSRussell King /* Check status register pause & lpa register */ 4219a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4220a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4221a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4222a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 42234241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 422461a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4225907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 42264262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 42274262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4228bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4229bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4230a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 42316c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 42321a3b39ecSAndrew Lunn }; 42331a3b39ecSAndrew Lunn 42341a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 42354b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4236ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4237cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 423898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 423998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 42401a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 42411a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 42421a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 42431a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 42444efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 42451a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4246f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 42477cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4248ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 424956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4250a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4251a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 425256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 42530898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4254c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42559dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42562d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4257fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4258121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 425979523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4260de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4261dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4262dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4263e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4264fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4265fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 426661303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 42676e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 42689e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 426917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 42709e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 427123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 427223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4273931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4274931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 42756335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 427617deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4277a5a6858bSRussell King /* Check status register pause & lpa register */ 4278a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4279a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4280a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4281a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 42824241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 428361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4284907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 42854262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 42864262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4287bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4288bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 42896d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 42906d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 42916c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 42921a3b39ecSAndrew Lunn }; 42931a3b39ecSAndrew Lunn 4294b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 42954b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 429693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 429793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4298cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4299ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4300ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4301b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4302b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4303b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 430408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 43054efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4306a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4307f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4308ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4309f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 431056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4311a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4312a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 431356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4314cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4315ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43160898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4317c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43189dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43192d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4320121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4321a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 432240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4323dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4324dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4325052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4326fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4327fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4328fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 432951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 43309e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 433117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 43329e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 433323e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 433423e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4335f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43360ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 43379db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4338a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4339a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4340a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4341a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 43426d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 43434241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 434461a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4345907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4346d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4347d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4348a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 43490d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 43506d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 43516c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4352b3469dd8SVivien Didelot }; 4353b3469dd8SVivien Didelot 43541f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = { 43551f71836fSRasmus Villemoes /* MV88E6XXX_FAMILY_6250 */ 43561f71836fSRasmus Villemoes .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 43571f71836fSRasmus Villemoes .ip_pri_map = mv88e6085_g1_ip_pri_map, 43581f71836fSRasmus Villemoes .irl_init_all = mv88e6352_g2_irl_init_all, 43591f71836fSRasmus Villemoes .get_eeprom = mv88e6xxx_g2_get_eeprom16, 43601f71836fSRasmus Villemoes .set_eeprom = mv88e6xxx_g2_set_eeprom16, 43611f71836fSRasmus Villemoes .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 43621f71836fSRasmus Villemoes .phy_read = mv88e6xxx_g2_smi_phy_read, 43631f71836fSRasmus Villemoes .phy_write = mv88e6xxx_g2_smi_phy_write, 43641f71836fSRasmus Villemoes .port_set_link = mv88e6xxx_port_set_link, 43654efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 43661f71836fSRasmus Villemoes .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4367f365c6f7SRussell King .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, 43681f71836fSRasmus Villemoes .port_tag_remap = mv88e6095_port_tag_remap, 43691f71836fSRasmus Villemoes .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4370a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4371a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 43721f71836fSRasmus Villemoes .port_set_ether_type = mv88e6351_port_set_ether_type, 43731f71836fSRasmus Villemoes .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43741f71836fSRasmus Villemoes .port_pause_limit = mv88e6097_port_pause_limit, 43751f71836fSRasmus Villemoes .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43761f71836fSRasmus Villemoes .stats_snapshot = mv88e6320_g1_stats_snapshot, 43771f71836fSRasmus Villemoes .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 43781f71836fSRasmus Villemoes .stats_get_sset_count = mv88e6250_stats_get_sset_count, 43791f71836fSRasmus Villemoes .stats_get_strings = mv88e6250_stats_get_strings, 43801f71836fSRasmus Villemoes .stats_get_stats = mv88e6250_stats_get_stats, 43811f71836fSRasmus Villemoes .set_cpu_port = mv88e6095_g1_set_cpu_port, 43821f71836fSRasmus Villemoes .set_egress_port = mv88e6095_g1_set_egress_port, 43831f71836fSRasmus Villemoes .watchdog_ops = &mv88e6250_watchdog_ops, 43841f71836fSRasmus Villemoes .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 43851f71836fSRasmus Villemoes .pot_clear = mv88e6xxx_g2_pot_clear, 43861f71836fSRasmus Villemoes .reset = mv88e6250_g1_reset, 438767c9ed1cSRasmus Villemoes .vtu_getnext = mv88e6185_g1_vtu_getnext, 4388b28f3f3cSRasmus Villemoes .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 438971509614SHubert Feurstein .avb_ops = &mv88e6352_avb_ops, 439071509614SHubert Feurstein .ptp_ops = &mv88e6250_ptp_ops, 43911f71836fSRasmus Villemoes .phylink_validate = mv88e6065_phylink_validate, 43921f71836fSRasmus Villemoes }; 43931f71836fSRasmus Villemoes 43941a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 43954b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4396ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4397cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 439898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 439998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 44001a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 44011a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 44021a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 44031a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 44044efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 44051a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4406f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 44077cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4408ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4409f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 441056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4411a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4412a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 441356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 44140898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4415c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44169dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44172d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4418fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4419121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 442079523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4421de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4422dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4423dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4424e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4425fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4426fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 442761303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 44286e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 44299e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 443017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 44319e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 443223e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 443323e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4434931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4435931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 44366335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 443717deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4438a5a6858bSRussell King /* Check status register pause & lpa register */ 4439a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4440a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4441a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4442a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 44434241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 444461a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4445907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 44464262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 44474262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4448bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4449bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4450a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 44510d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 44526d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 44536c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 44541a3b39ecSAndrew Lunn }; 44551a3b39ecSAndrew Lunn 4456b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 44574b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 445893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 445993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4460cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4461ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4462ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4463b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4464b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4465b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 446608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 44674efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4468f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4469ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 447056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4471a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4472a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 447356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4474cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4475ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44760898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4477c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44789dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44792d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4480121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4481a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 448240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4483dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4484dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4485052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4486fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4487fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 44889c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 448951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44909e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 449117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4492f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 44930ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4494a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 44950d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 44966d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 44976c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4498b3469dd8SVivien Didelot }; 4499b3469dd8SVivien Didelot 4500b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 4501bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 450293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 450393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4504cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4505ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4506ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4507b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4508b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4509b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 451008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 45114efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4512f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4513ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 451456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4515a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4516a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 451756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4518cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4519ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 45200898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4521c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 45229dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45232d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4524121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4525a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 452640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4527dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4528dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4529052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4530fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4531fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 45329c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 453317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4534f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 45350ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4536a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 45370d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 45386d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 45396c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4540b3469dd8SVivien Didelot }; 4541b3469dd8SVivien Didelot 454216e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 454316e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 454493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 454593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4546cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 454716e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 454816e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 454916e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 455016e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 455116e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 455216e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 45534efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 455416e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4555f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 45567cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 455716e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 45587da467d8SMarek Behún .port_set_policy = mv88e6352_port_set_policy, 455916e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4560a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4561a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 456216e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 4563cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 456416e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 45650898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 456616e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 456716e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45682d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 45697a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 4570121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 457116e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 457211527f3cSMarek Behún .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 457316e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 457416e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 457516e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 4576fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4577fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 457816e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 457916e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 45809e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 458116e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 458237094887SMarek Behún .rmu_disable = mv88e6390_g1_rmu_disable, 4583c07fff34SMarek Behún .atu_get_hash = mv88e6165_g1_atu_get_hash, 4584c07fff34SMarek Behún .atu_set_hash = mv88e6165_g1_atu_set_hash, 4585f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 45860ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4587d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 4588d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 4589a5a6858bSRussell King /* Check status register pause & lpa register */ 4590a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4591a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4592a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4593a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 45944241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 459561a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4596907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4597a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 45980d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 45996d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4600a03b98d6SMarek Behún .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 4601a03b98d6SMarek Behún .serdes_get_strings = mv88e6390_serdes_get_strings, 4602a03b98d6SMarek Behún .serdes_get_stats = mv88e6390_serdes_get_stats, 4603953b0dcbSMarek Behún .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4604953b0dcbSMarek Behún .serdes_get_regs = mv88e6390_serdes_get_regs, 4605e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 460616e329aeSVivien Didelot }; 460716e329aeSVivien Didelot 4608b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 46094b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 461093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 461193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4612cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4613b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4614b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4615b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 461608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 46174efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 461894d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4619f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4620ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 462156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4622a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4623a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 462456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4625cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4626ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 46270898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4628c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 46299dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 46302d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4631121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4632a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 463340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4634dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4635dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4636052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4637fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4638fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4639fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 464051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 46419e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 464217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 464323e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 464423e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4645f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 46460ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 46476c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4648b3469dd8SVivien Didelot }; 4649b3469dd8SVivien Didelot 4650b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 46514b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 465293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 465393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4654cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4655b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4656b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4657b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 465808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 46594efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 466094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4661f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4662ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 466356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4664a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4665a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 466656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4667cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4668ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 46690898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4670c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 46719dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 46722d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4673121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4674a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 467540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4676dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4677dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4678052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4679fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4680fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4681fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 468251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 46839e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 468417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 468523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 468623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4687f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 46880ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 46890d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 46906d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 46916c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4692b3469dd8SVivien Didelot }; 4693b3469dd8SVivien Didelot 4694b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 46954b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 469693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 469793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4698cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4699ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4700ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4701b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4702b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4703b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 470408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 47054efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4706a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4707f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4708ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4709f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 471056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4711a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4712a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 471356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4714cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4715ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 47160898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4717c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 47189dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 47192d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4720121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4721a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 472240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4723dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4724dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4725052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4726fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4727fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4728fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 472951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 47309e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 473117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 47329e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 473323e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 473423e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4735f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 47360ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 47379db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4738a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4739a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4740a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4741a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 47426d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 47434241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 474461a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4745907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4746a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 47470d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 47486d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4749cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 4750cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 4751cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 4752d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4753d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 47546c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4755b3469dd8SVivien Didelot }; 4756b3469dd8SVivien Didelot 47571a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 47584b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4759ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4760cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 476198fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 476298fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 47631a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 47641a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 47651a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 47661a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 47674efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 47681a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4769f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 47707cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4771ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4772f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 477356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4774a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4775a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 477656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4777cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4778ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 47790898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4780c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 47819dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 47822d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4783fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4784121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 478579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4786de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4787dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4788dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4789e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4790fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4791fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 479261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 47936e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 47949e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 479517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 47969e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 479723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 479823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4799931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4800931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 48016335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 480217deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4803a5a6858bSRussell King /* Check status register pause & lpa register */ 4804a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4805a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4806a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4807a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 48084241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 480961a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4810907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4811a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 48120d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 48136d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 48140df95287SNikita Yushchenko .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 48150df95287SNikita Yushchenko .serdes_get_strings = mv88e6390_serdes_get_strings, 48160df95287SNikita Yushchenko .serdes_get_stats = mv88e6390_serdes_get_stats, 4817bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4818bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 48196c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 48201a3b39ecSAndrew Lunn }; 48211a3b39ecSAndrew Lunn 48221a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 48234b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4824ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4825cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 482698fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 482798fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 48281a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 48291a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 48301a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 48311a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 48324efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 48331a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4834f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 48357cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 4836ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4837f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 483856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4839a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4840a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 484156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4842cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4843ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 48440898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4845c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 48469dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 48472d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4848b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 4849121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 485079523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4851de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4852dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4853dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4854e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4855fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4856fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 485761303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 48586e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 48599e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 486017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 48619e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 486223e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 486323e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4864931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4865931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4866d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 486717deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 4868a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4869a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4870a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4871a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 48724241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 487361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4874907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 48754262c38dSAndrew Lunn .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 48764262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 48774262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4878bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4879bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4880a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 48810d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 48826d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 48836c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 48841a3b39ecSAndrew Lunn }; 48851a3b39ecSAndrew Lunn 4886de776d0dSPavana Sharma static const struct mv88e6xxx_ops mv88e6393x_ops = { 4887de776d0dSPavana Sharma /* MV88E6XXX_FAMILY_6393 */ 4888de776d0dSPavana Sharma .setup_errata = mv88e6393x_serdes_setup_errata, 4889de776d0dSPavana Sharma .irl_init_all = mv88e6390_g2_irl_init_all, 4890de776d0dSPavana Sharma .get_eeprom = mv88e6xxx_g2_get_eeprom8, 4891de776d0dSPavana Sharma .set_eeprom = mv88e6xxx_g2_set_eeprom8, 4892de776d0dSPavana Sharma .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4893de776d0dSPavana Sharma .phy_read = mv88e6xxx_g2_smi_phy_read, 4894de776d0dSPavana Sharma .phy_write = mv88e6xxx_g2_smi_phy_write, 4895de776d0dSPavana Sharma .port_set_link = mv88e6xxx_port_set_link, 4896de776d0dSPavana Sharma .port_sync_link = mv88e6xxx_port_sync_link, 4897de776d0dSPavana Sharma .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4898de776d0dSPavana Sharma .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex, 4899de776d0dSPavana Sharma .port_max_speed_mode = mv88e6393x_port_max_speed_mode, 4900de776d0dSPavana Sharma .port_tag_remap = mv88e6390_port_tag_remap, 49016584b260SMarek Behún .port_set_policy = mv88e6393x_port_set_policy, 4902de776d0dSPavana Sharma .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4903de776d0dSPavana Sharma .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4904de776d0dSPavana Sharma .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 4905de776d0dSPavana Sharma .port_set_ether_type = mv88e6393x_port_set_ether_type, 4906de776d0dSPavana Sharma .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4907de776d0dSPavana Sharma .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 4908de776d0dSPavana Sharma .port_pause_limit = mv88e6390_port_pause_limit, 4909de776d0dSPavana Sharma .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 4910de776d0dSPavana Sharma .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 4911de776d0dSPavana Sharma .port_get_cmode = mv88e6352_port_get_cmode, 4912de776d0dSPavana Sharma .port_set_cmode = mv88e6393x_port_set_cmode, 4913de776d0dSPavana Sharma .port_setup_message_port = mv88e6xxx_setup_message_port, 4914de776d0dSPavana Sharma .port_set_upstream_port = mv88e6393x_port_set_upstream_port, 4915de776d0dSPavana Sharma .stats_snapshot = mv88e6390_g1_stats_snapshot, 4916de776d0dSPavana Sharma .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4917de776d0dSPavana Sharma .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4918de776d0dSPavana Sharma .stats_get_strings = mv88e6320_stats_get_strings, 4919de776d0dSPavana Sharma .stats_get_stats = mv88e6390_stats_get_stats, 4920de776d0dSPavana Sharma /* .set_cpu_port is missing because this family does not support a global 4921de776d0dSPavana Sharma * CPU port, only per port CPU port which is set via 4922de776d0dSPavana Sharma * .port_set_upstream_port method. 4923de776d0dSPavana Sharma */ 4924de776d0dSPavana Sharma .set_egress_port = mv88e6393x_set_egress_port, 4925de776d0dSPavana Sharma .watchdog_ops = &mv88e6390_watchdog_ops, 4926de776d0dSPavana Sharma .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, 4927de776d0dSPavana Sharma .pot_clear = mv88e6xxx_g2_pot_clear, 4928de776d0dSPavana Sharma .reset = mv88e6352_g1_reset, 4929de776d0dSPavana Sharma .rmu_disable = mv88e6390_g1_rmu_disable, 4930de776d0dSPavana Sharma .atu_get_hash = mv88e6165_g1_atu_get_hash, 4931de776d0dSPavana Sharma .atu_set_hash = mv88e6165_g1_atu_set_hash, 4932de776d0dSPavana Sharma .vtu_getnext = mv88e6390_g1_vtu_getnext, 4933de776d0dSPavana Sharma .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4934de776d0dSPavana Sharma .serdes_power = mv88e6393x_serdes_power, 4935de776d0dSPavana Sharma .serdes_get_lane = mv88e6393x_serdes_get_lane, 4936de776d0dSPavana Sharma .serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state, 4937de776d0dSPavana Sharma .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4938de776d0dSPavana Sharma .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4939de776d0dSPavana Sharma .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 4940de776d0dSPavana Sharma .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 4941de776d0dSPavana Sharma .serdes_irq_enable = mv88e6393x_serdes_irq_enable, 4942de776d0dSPavana Sharma .serdes_irq_status = mv88e6393x_serdes_irq_status, 4943de776d0dSPavana Sharma /* TODO: serdes stats */ 4944de776d0dSPavana Sharma .gpio_ops = &mv88e6352_gpio_ops, 4945de776d0dSPavana Sharma .avb_ops = &mv88e6390_avb_ops, 4946de776d0dSPavana Sharma .ptp_ops = &mv88e6352_ptp_ops, 4947de776d0dSPavana Sharma .phylink_validate = mv88e6393x_phylink_validate, 4948de776d0dSPavana Sharma }; 4949de776d0dSPavana Sharma 4950fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 4951fad09c73SVivien Didelot [MV88E6085] = { 4952107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 4953fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 4954fad09c73SVivien Didelot .name = "Marvell 88E6085", 4955fad09c73SVivien Didelot .num_databases = 4096, 4956d9ea5620SAndrew Lunn .num_macs = 8192, 4957fad09c73SVivien Didelot .num_ports = 10, 4958bc393155SAndrew Lunn .num_internal_phys = 5, 49593cf3c846SVivien Didelot .max_vid = 4095, 4960fad09c73SVivien Didelot .port_base_addr = 0x10, 49619255bacdSAndrew Lunn .phy_base_addr = 0x0, 4962a935c052SVivien Didelot .global1_addr = 0x1b, 49639069c13aSVivien Didelot .global2_addr = 0x1c, 4964acddbd21SVivien Didelot .age_time_coeff = 15000, 4965dc30c35bSAndrew Lunn .g1_irqs = 8, 4966d6c5e6afSVivien Didelot .g2_irqs = 10, 4967e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4968f3645652SVivien Didelot .pvt = true, 4969b3e05aa1SVivien Didelot .multi_chip = true, 4970b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 4971fad09c73SVivien Didelot }, 4972fad09c73SVivien Didelot 4973fad09c73SVivien Didelot [MV88E6095] = { 4974107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 4975fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 4976fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 4977fad09c73SVivien Didelot .num_databases = 256, 4978d9ea5620SAndrew Lunn .num_macs = 8192, 4979fad09c73SVivien Didelot .num_ports = 11, 4980bc393155SAndrew Lunn .num_internal_phys = 0, 49813cf3c846SVivien Didelot .max_vid = 4095, 4982fad09c73SVivien Didelot .port_base_addr = 0x10, 49839255bacdSAndrew Lunn .phy_base_addr = 0x0, 4984a935c052SVivien Didelot .global1_addr = 0x1b, 49859069c13aSVivien Didelot .global2_addr = 0x1c, 4986acddbd21SVivien Didelot .age_time_coeff = 15000, 4987dc30c35bSAndrew Lunn .g1_irqs = 8, 4988e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4989b3e05aa1SVivien Didelot .multi_chip = true, 4990b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 4991fad09c73SVivien Didelot }, 4992fad09c73SVivien Didelot 49937d381a02SStefan Eichenberger [MV88E6097] = { 4994107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 49957d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 49967d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 49977d381a02SStefan Eichenberger .num_databases = 4096, 4998d9ea5620SAndrew Lunn .num_macs = 8192, 49997d381a02SStefan Eichenberger .num_ports = 11, 5000bc393155SAndrew Lunn .num_internal_phys = 8, 50013cf3c846SVivien Didelot .max_vid = 4095, 50027d381a02SStefan Eichenberger .port_base_addr = 0x10, 50039255bacdSAndrew Lunn .phy_base_addr = 0x0, 50047d381a02SStefan Eichenberger .global1_addr = 0x1b, 50059069c13aSVivien Didelot .global2_addr = 0x1c, 50067d381a02SStefan Eichenberger .age_time_coeff = 15000, 5007c534178bSStefan Eichenberger .g1_irqs = 8, 5008d6c5e6afSVivien Didelot .g2_irqs = 10, 5009e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5010f3645652SVivien Didelot .pvt = true, 5011b3e05aa1SVivien Didelot .multi_chip = true, 5012670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 50137d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 50147d381a02SStefan Eichenberger }, 50157d381a02SStefan Eichenberger 5016fad09c73SVivien Didelot [MV88E6123] = { 5017107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 5018fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 5019fad09c73SVivien Didelot .name = "Marvell 88E6123", 5020fad09c73SVivien Didelot .num_databases = 4096, 5021d9ea5620SAndrew Lunn .num_macs = 1024, 5022fad09c73SVivien Didelot .num_ports = 3, 5023bc393155SAndrew Lunn .num_internal_phys = 5, 50243cf3c846SVivien Didelot .max_vid = 4095, 5025fad09c73SVivien Didelot .port_base_addr = 0x10, 50269255bacdSAndrew Lunn .phy_base_addr = 0x0, 5027a935c052SVivien Didelot .global1_addr = 0x1b, 50289069c13aSVivien Didelot .global2_addr = 0x1c, 5029acddbd21SVivien Didelot .age_time_coeff = 15000, 5030dc30c35bSAndrew Lunn .g1_irqs = 9, 5031d6c5e6afSVivien Didelot .g2_irqs = 10, 5032e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5033f3645652SVivien Didelot .pvt = true, 5034b3e05aa1SVivien Didelot .multi_chip = true, 5035670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5036b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 5037fad09c73SVivien Didelot }, 5038fad09c73SVivien Didelot 5039fad09c73SVivien Didelot [MV88E6131] = { 5040107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 5041fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 5042fad09c73SVivien Didelot .name = "Marvell 88E6131", 5043fad09c73SVivien Didelot .num_databases = 256, 5044d9ea5620SAndrew Lunn .num_macs = 8192, 5045fad09c73SVivien Didelot .num_ports = 8, 5046bc393155SAndrew Lunn .num_internal_phys = 0, 50473cf3c846SVivien Didelot .max_vid = 4095, 5048fad09c73SVivien Didelot .port_base_addr = 0x10, 50499255bacdSAndrew Lunn .phy_base_addr = 0x0, 5050a935c052SVivien Didelot .global1_addr = 0x1b, 50519069c13aSVivien Didelot .global2_addr = 0x1c, 5052acddbd21SVivien Didelot .age_time_coeff = 15000, 5053dc30c35bSAndrew Lunn .g1_irqs = 9, 5054e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5055b3e05aa1SVivien Didelot .multi_chip = true, 5056b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 5057fad09c73SVivien Didelot }, 5058fad09c73SVivien Didelot 5059990e27b0SVivien Didelot [MV88E6141] = { 5060107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 5061990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 506279a68b26SUwe Kleine-König .name = "Marvell 88E6141", 5063990e27b0SVivien Didelot .num_databases = 4096, 5064d9ea5620SAndrew Lunn .num_macs = 2048, 5065990e27b0SVivien Didelot .num_ports = 6, 5066bc393155SAndrew Lunn .num_internal_phys = 5, 5067a73ccd61SBrandon Streiff .num_gpio = 11, 50683cf3c846SVivien Didelot .max_vid = 4095, 5069990e27b0SVivien Didelot .port_base_addr = 0x10, 50709255bacdSAndrew Lunn .phy_base_addr = 0x10, 5071990e27b0SVivien Didelot .global1_addr = 0x1b, 50729069c13aSVivien Didelot .global2_addr = 0x1c, 5073990e27b0SVivien Didelot .age_time_coeff = 3750, 5074990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 5075adfccf11SAndrew Lunn .g1_irqs = 9, 5076d6c5e6afSVivien Didelot .g2_irqs = 10, 5077f3645652SVivien Didelot .pvt = true, 5078b3e05aa1SVivien Didelot .multi_chip = true, 5079670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5080990e27b0SVivien Didelot .ops = &mv88e6141_ops, 5081990e27b0SVivien Didelot }, 5082990e27b0SVivien Didelot 5083fad09c73SVivien Didelot [MV88E6161] = { 5084107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 5085fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 5086fad09c73SVivien Didelot .name = "Marvell 88E6161", 5087fad09c73SVivien Didelot .num_databases = 4096, 5088d9ea5620SAndrew Lunn .num_macs = 1024, 5089fad09c73SVivien Didelot .num_ports = 6, 5090bc393155SAndrew Lunn .num_internal_phys = 5, 50913cf3c846SVivien Didelot .max_vid = 4095, 5092fad09c73SVivien Didelot .port_base_addr = 0x10, 50939255bacdSAndrew Lunn .phy_base_addr = 0x0, 5094a935c052SVivien Didelot .global1_addr = 0x1b, 50959069c13aSVivien Didelot .global2_addr = 0x1c, 5096acddbd21SVivien Didelot .age_time_coeff = 15000, 5097dc30c35bSAndrew Lunn .g1_irqs = 9, 5098d6c5e6afSVivien Didelot .g2_irqs = 10, 5099e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5100f3645652SVivien Didelot .pvt = true, 5101b3e05aa1SVivien Didelot .multi_chip = true, 5102670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5103dfa54348SAndrew Lunn .ptp_support = true, 5104b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 5105fad09c73SVivien Didelot }, 5106fad09c73SVivien Didelot 5107fad09c73SVivien Didelot [MV88E6165] = { 5108107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 5109fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 5110fad09c73SVivien Didelot .name = "Marvell 88E6165", 5111fad09c73SVivien Didelot .num_databases = 4096, 5112d9ea5620SAndrew Lunn .num_macs = 8192, 5113fad09c73SVivien Didelot .num_ports = 6, 5114bc393155SAndrew Lunn .num_internal_phys = 0, 51153cf3c846SVivien Didelot .max_vid = 4095, 5116fad09c73SVivien Didelot .port_base_addr = 0x10, 51179255bacdSAndrew Lunn .phy_base_addr = 0x0, 5118a935c052SVivien Didelot .global1_addr = 0x1b, 51199069c13aSVivien Didelot .global2_addr = 0x1c, 5120acddbd21SVivien Didelot .age_time_coeff = 15000, 5121dc30c35bSAndrew Lunn .g1_irqs = 9, 5122d6c5e6afSVivien Didelot .g2_irqs = 10, 5123e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5124f3645652SVivien Didelot .pvt = true, 5125b3e05aa1SVivien Didelot .multi_chip = true, 5126dfa54348SAndrew Lunn .ptp_support = true, 5127b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 5128fad09c73SVivien Didelot }, 5129fad09c73SVivien Didelot 5130fad09c73SVivien Didelot [MV88E6171] = { 5131107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 5132fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5133fad09c73SVivien Didelot .name = "Marvell 88E6171", 5134fad09c73SVivien Didelot .num_databases = 4096, 5135d9ea5620SAndrew Lunn .num_macs = 8192, 5136fad09c73SVivien Didelot .num_ports = 7, 5137bc393155SAndrew Lunn .num_internal_phys = 5, 51383cf3c846SVivien Didelot .max_vid = 4095, 5139fad09c73SVivien Didelot .port_base_addr = 0x10, 51409255bacdSAndrew Lunn .phy_base_addr = 0x0, 5141a935c052SVivien Didelot .global1_addr = 0x1b, 51429069c13aSVivien Didelot .global2_addr = 0x1c, 5143acddbd21SVivien Didelot .age_time_coeff = 15000, 5144dc30c35bSAndrew Lunn .g1_irqs = 9, 5145d6c5e6afSVivien Didelot .g2_irqs = 10, 5146e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5147f3645652SVivien Didelot .pvt = true, 5148b3e05aa1SVivien Didelot .multi_chip = true, 5149670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5150b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 5151fad09c73SVivien Didelot }, 5152fad09c73SVivien Didelot 5153fad09c73SVivien Didelot [MV88E6172] = { 5154107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 5155fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5156fad09c73SVivien Didelot .name = "Marvell 88E6172", 5157fad09c73SVivien Didelot .num_databases = 4096, 5158d9ea5620SAndrew Lunn .num_macs = 8192, 5159fad09c73SVivien Didelot .num_ports = 7, 5160bc393155SAndrew Lunn .num_internal_phys = 5, 5161a73ccd61SBrandon Streiff .num_gpio = 15, 51623cf3c846SVivien Didelot .max_vid = 4095, 5163fad09c73SVivien Didelot .port_base_addr = 0x10, 51649255bacdSAndrew Lunn .phy_base_addr = 0x0, 5165a935c052SVivien Didelot .global1_addr = 0x1b, 51669069c13aSVivien Didelot .global2_addr = 0x1c, 5167acddbd21SVivien Didelot .age_time_coeff = 15000, 5168dc30c35bSAndrew Lunn .g1_irqs = 9, 5169d6c5e6afSVivien Didelot .g2_irqs = 10, 5170e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5171f3645652SVivien Didelot .pvt = true, 5172b3e05aa1SVivien Didelot .multi_chip = true, 5173670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5174b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 5175fad09c73SVivien Didelot }, 5176fad09c73SVivien Didelot 5177fad09c73SVivien Didelot [MV88E6175] = { 5178107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 5179fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5180fad09c73SVivien Didelot .name = "Marvell 88E6175", 5181fad09c73SVivien Didelot .num_databases = 4096, 5182d9ea5620SAndrew Lunn .num_macs = 8192, 5183fad09c73SVivien Didelot .num_ports = 7, 5184bc393155SAndrew Lunn .num_internal_phys = 5, 51853cf3c846SVivien Didelot .max_vid = 4095, 5186fad09c73SVivien Didelot .port_base_addr = 0x10, 51879255bacdSAndrew Lunn .phy_base_addr = 0x0, 5188a935c052SVivien Didelot .global1_addr = 0x1b, 51899069c13aSVivien Didelot .global2_addr = 0x1c, 5190acddbd21SVivien Didelot .age_time_coeff = 15000, 5191dc30c35bSAndrew Lunn .g1_irqs = 9, 5192d6c5e6afSVivien Didelot .g2_irqs = 10, 5193e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5194f3645652SVivien Didelot .pvt = true, 5195b3e05aa1SVivien Didelot .multi_chip = true, 5196670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5197b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 5198fad09c73SVivien Didelot }, 5199fad09c73SVivien Didelot 5200fad09c73SVivien Didelot [MV88E6176] = { 5201107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 5202fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5203fad09c73SVivien Didelot .name = "Marvell 88E6176", 5204fad09c73SVivien Didelot .num_databases = 4096, 5205d9ea5620SAndrew Lunn .num_macs = 8192, 5206fad09c73SVivien Didelot .num_ports = 7, 5207bc393155SAndrew Lunn .num_internal_phys = 5, 5208a73ccd61SBrandon Streiff .num_gpio = 15, 52093cf3c846SVivien Didelot .max_vid = 4095, 5210fad09c73SVivien Didelot .port_base_addr = 0x10, 52119255bacdSAndrew Lunn .phy_base_addr = 0x0, 5212a935c052SVivien Didelot .global1_addr = 0x1b, 52139069c13aSVivien Didelot .global2_addr = 0x1c, 5214acddbd21SVivien Didelot .age_time_coeff = 15000, 5215dc30c35bSAndrew Lunn .g1_irqs = 9, 5216d6c5e6afSVivien Didelot .g2_irqs = 10, 5217e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5218f3645652SVivien Didelot .pvt = true, 5219b3e05aa1SVivien Didelot .multi_chip = true, 5220670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5221b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 5222fad09c73SVivien Didelot }, 5223fad09c73SVivien Didelot 5224fad09c73SVivien Didelot [MV88E6185] = { 5225107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 5226fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 5227fad09c73SVivien Didelot .name = "Marvell 88E6185", 5228fad09c73SVivien Didelot .num_databases = 256, 5229d9ea5620SAndrew Lunn .num_macs = 8192, 5230fad09c73SVivien Didelot .num_ports = 10, 5231bc393155SAndrew Lunn .num_internal_phys = 0, 52323cf3c846SVivien Didelot .max_vid = 4095, 5233fad09c73SVivien Didelot .port_base_addr = 0x10, 52349255bacdSAndrew Lunn .phy_base_addr = 0x0, 5235a935c052SVivien Didelot .global1_addr = 0x1b, 52369069c13aSVivien Didelot .global2_addr = 0x1c, 5237acddbd21SVivien Didelot .age_time_coeff = 15000, 5238dc30c35bSAndrew Lunn .g1_irqs = 8, 5239e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5240b3e05aa1SVivien Didelot .multi_chip = true, 5241670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5242b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 5243fad09c73SVivien Didelot }, 5244fad09c73SVivien Didelot 52451a3b39ecSAndrew Lunn [MV88E6190] = { 5246107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 52471a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52481a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 52491a3b39ecSAndrew Lunn .num_databases = 4096, 5250d9ea5620SAndrew Lunn .num_macs = 16384, 52511a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 525295150f29SHeiner Kallweit .num_internal_phys = 9, 5253a73ccd61SBrandon Streiff .num_gpio = 16, 5254931d1822SVivien Didelot .max_vid = 8191, 52551a3b39ecSAndrew Lunn .port_base_addr = 0x0, 52569255bacdSAndrew Lunn .phy_base_addr = 0x0, 52571a3b39ecSAndrew Lunn .global1_addr = 0x1b, 52589069c13aSVivien Didelot .global2_addr = 0x1c, 5259b91e055cSAndrew Lunn .age_time_coeff = 3750, 52601a3b39ecSAndrew Lunn .g1_irqs = 9, 5261d6c5e6afSVivien Didelot .g2_irqs = 14, 5262f3645652SVivien Didelot .pvt = true, 5263b3e05aa1SVivien Didelot .multi_chip = true, 5264e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 52651a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 52661a3b39ecSAndrew Lunn }, 52671a3b39ecSAndrew Lunn 52681a3b39ecSAndrew Lunn [MV88E6190X] = { 5269107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 52701a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52711a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 52721a3b39ecSAndrew Lunn .num_databases = 4096, 5273d9ea5620SAndrew Lunn .num_macs = 16384, 52741a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 527595150f29SHeiner Kallweit .num_internal_phys = 9, 5276a73ccd61SBrandon Streiff .num_gpio = 16, 5277931d1822SVivien Didelot .max_vid = 8191, 52781a3b39ecSAndrew Lunn .port_base_addr = 0x0, 52799255bacdSAndrew Lunn .phy_base_addr = 0x0, 52801a3b39ecSAndrew Lunn .global1_addr = 0x1b, 52819069c13aSVivien Didelot .global2_addr = 0x1c, 5282b91e055cSAndrew Lunn .age_time_coeff = 3750, 52831a3b39ecSAndrew Lunn .g1_irqs = 9, 5284d6c5e6afSVivien Didelot .g2_irqs = 14, 5285e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5286f3645652SVivien Didelot .pvt = true, 5287b3e05aa1SVivien Didelot .multi_chip = true, 52881a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 52891a3b39ecSAndrew Lunn }, 52901a3b39ecSAndrew Lunn 52911a3b39ecSAndrew Lunn [MV88E6191] = { 5292107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 52931a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52941a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 52951a3b39ecSAndrew Lunn .num_databases = 4096, 5296d9ea5620SAndrew Lunn .num_macs = 16384, 52971a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 529895150f29SHeiner Kallweit .num_internal_phys = 9, 5299931d1822SVivien Didelot .max_vid = 8191, 53001a3b39ecSAndrew Lunn .port_base_addr = 0x0, 53019255bacdSAndrew Lunn .phy_base_addr = 0x0, 53021a3b39ecSAndrew Lunn .global1_addr = 0x1b, 53039069c13aSVivien Didelot .global2_addr = 0x1c, 5304b91e055cSAndrew Lunn .age_time_coeff = 3750, 5305443d5a1bSAndrew Lunn .g1_irqs = 9, 5306d6c5e6afSVivien Didelot .g2_irqs = 14, 5307e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5308f3645652SVivien Didelot .pvt = true, 5309b3e05aa1SVivien Didelot .multi_chip = true, 53102fa8d3afSBrandon Streiff .ptp_support = true, 53112cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 53121a3b39ecSAndrew Lunn }, 53131a3b39ecSAndrew Lunn 5314de776d0dSPavana Sharma [MV88E6191X] = { 5315de776d0dSPavana Sharma .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X, 5316de776d0dSPavana Sharma .family = MV88E6XXX_FAMILY_6393, 5317de776d0dSPavana Sharma .name = "Marvell 88E6191X", 5318de776d0dSPavana Sharma .num_databases = 4096, 5319de776d0dSPavana Sharma .num_ports = 11, /* 10 + Z80 */ 5320de776d0dSPavana Sharma .num_internal_phys = 9, 5321de776d0dSPavana Sharma .max_vid = 8191, 5322de776d0dSPavana Sharma .port_base_addr = 0x0, 5323de776d0dSPavana Sharma .phy_base_addr = 0x0, 5324de776d0dSPavana Sharma .global1_addr = 0x1b, 5325de776d0dSPavana Sharma .global2_addr = 0x1c, 5326de776d0dSPavana Sharma .age_time_coeff = 3750, 5327de776d0dSPavana Sharma .g1_irqs = 10, 5328de776d0dSPavana Sharma .g2_irqs = 14, 5329de776d0dSPavana Sharma .atu_move_port_mask = 0x1f, 5330de776d0dSPavana Sharma .pvt = true, 5331de776d0dSPavana Sharma .multi_chip = true, 5332de776d0dSPavana Sharma .ptp_support = true, 5333de776d0dSPavana Sharma .ops = &mv88e6393x_ops, 5334de776d0dSPavana Sharma }, 5335de776d0dSPavana Sharma 5336de776d0dSPavana Sharma [MV88E6193X] = { 5337de776d0dSPavana Sharma .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X, 5338de776d0dSPavana Sharma .family = MV88E6XXX_FAMILY_6393, 5339de776d0dSPavana Sharma .name = "Marvell 88E6193X", 5340de776d0dSPavana Sharma .num_databases = 4096, 5341de776d0dSPavana Sharma .num_ports = 11, /* 10 + Z80 */ 5342de776d0dSPavana Sharma .num_internal_phys = 9, 5343de776d0dSPavana Sharma .max_vid = 8191, 5344de776d0dSPavana Sharma .port_base_addr = 0x0, 5345de776d0dSPavana Sharma .phy_base_addr = 0x0, 5346de776d0dSPavana Sharma .global1_addr = 0x1b, 5347de776d0dSPavana Sharma .global2_addr = 0x1c, 5348de776d0dSPavana Sharma .age_time_coeff = 3750, 5349de776d0dSPavana Sharma .g1_irqs = 10, 5350de776d0dSPavana Sharma .g2_irqs = 14, 5351de776d0dSPavana Sharma .atu_move_port_mask = 0x1f, 5352de776d0dSPavana Sharma .pvt = true, 5353de776d0dSPavana Sharma .multi_chip = true, 5354de776d0dSPavana Sharma .ptp_support = true, 5355de776d0dSPavana Sharma .ops = &mv88e6393x_ops, 5356de776d0dSPavana Sharma }, 5357de776d0dSPavana Sharma 535849022647SHubert Feurstein [MV88E6220] = { 535949022647SHubert Feurstein .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220, 536049022647SHubert Feurstein .family = MV88E6XXX_FAMILY_6250, 536149022647SHubert Feurstein .name = "Marvell 88E6220", 536249022647SHubert Feurstein .num_databases = 64, 536349022647SHubert Feurstein 536449022647SHubert Feurstein /* Ports 2-4 are not routed to pins 536549022647SHubert Feurstein * => usable ports 0, 1, 5, 6 536649022647SHubert Feurstein */ 536749022647SHubert Feurstein .num_ports = 7, 536849022647SHubert Feurstein .num_internal_phys = 2, 5369c857486aSHubert Feurstein .invalid_port_mask = BIT(2) | BIT(3) | BIT(4), 537049022647SHubert Feurstein .max_vid = 4095, 537149022647SHubert Feurstein .port_base_addr = 0x08, 537249022647SHubert Feurstein .phy_base_addr = 0x00, 537349022647SHubert Feurstein .global1_addr = 0x0f, 537449022647SHubert Feurstein .global2_addr = 0x07, 537549022647SHubert Feurstein .age_time_coeff = 15000, 537649022647SHubert Feurstein .g1_irqs = 9, 537749022647SHubert Feurstein .g2_irqs = 10, 537849022647SHubert Feurstein .atu_move_port_mask = 0xf, 537949022647SHubert Feurstein .dual_chip = true, 538071509614SHubert Feurstein .ptp_support = true, 538149022647SHubert Feurstein .ops = &mv88e6250_ops, 538249022647SHubert Feurstein }, 538349022647SHubert Feurstein 5384fad09c73SVivien Didelot [MV88E6240] = { 5385107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 5386fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5387fad09c73SVivien Didelot .name = "Marvell 88E6240", 5388fad09c73SVivien Didelot .num_databases = 4096, 5389d9ea5620SAndrew Lunn .num_macs = 8192, 5390fad09c73SVivien Didelot .num_ports = 7, 5391bc393155SAndrew Lunn .num_internal_phys = 5, 5392a73ccd61SBrandon Streiff .num_gpio = 15, 53933cf3c846SVivien Didelot .max_vid = 4095, 5394fad09c73SVivien Didelot .port_base_addr = 0x10, 53959255bacdSAndrew Lunn .phy_base_addr = 0x0, 5396a935c052SVivien Didelot .global1_addr = 0x1b, 53979069c13aSVivien Didelot .global2_addr = 0x1c, 5398acddbd21SVivien Didelot .age_time_coeff = 15000, 5399dc30c35bSAndrew Lunn .g1_irqs = 9, 5400d6c5e6afSVivien Didelot .g2_irqs = 10, 5401e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5402f3645652SVivien Didelot .pvt = true, 5403b3e05aa1SVivien Didelot .multi_chip = true, 5404670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 54052fa8d3afSBrandon Streiff .ptp_support = true, 5406b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 5407fad09c73SVivien Didelot }, 5408fad09c73SVivien Didelot 54091f71836fSRasmus Villemoes [MV88E6250] = { 54101f71836fSRasmus Villemoes .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 54111f71836fSRasmus Villemoes .family = MV88E6XXX_FAMILY_6250, 54121f71836fSRasmus Villemoes .name = "Marvell 88E6250", 54131f71836fSRasmus Villemoes .num_databases = 64, 54141f71836fSRasmus Villemoes .num_ports = 7, 54151f71836fSRasmus Villemoes .num_internal_phys = 5, 54161f71836fSRasmus Villemoes .max_vid = 4095, 54171f71836fSRasmus Villemoes .port_base_addr = 0x08, 54181f71836fSRasmus Villemoes .phy_base_addr = 0x00, 54191f71836fSRasmus Villemoes .global1_addr = 0x0f, 54201f71836fSRasmus Villemoes .global2_addr = 0x07, 54211f71836fSRasmus Villemoes .age_time_coeff = 15000, 54221f71836fSRasmus Villemoes .g1_irqs = 9, 54231f71836fSRasmus Villemoes .g2_irqs = 10, 54241f71836fSRasmus Villemoes .atu_move_port_mask = 0xf, 54251f71836fSRasmus Villemoes .dual_chip = true, 542671509614SHubert Feurstein .ptp_support = true, 54271f71836fSRasmus Villemoes .ops = &mv88e6250_ops, 54281f71836fSRasmus Villemoes }, 54291f71836fSRasmus Villemoes 54301a3b39ecSAndrew Lunn [MV88E6290] = { 5431107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 54321a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 54331a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 54341a3b39ecSAndrew Lunn .num_databases = 4096, 54351a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 543695150f29SHeiner Kallweit .num_internal_phys = 9, 5437a73ccd61SBrandon Streiff .num_gpio = 16, 5438931d1822SVivien Didelot .max_vid = 8191, 54391a3b39ecSAndrew Lunn .port_base_addr = 0x0, 54409255bacdSAndrew Lunn .phy_base_addr = 0x0, 54411a3b39ecSAndrew Lunn .global1_addr = 0x1b, 54429069c13aSVivien Didelot .global2_addr = 0x1c, 5443b91e055cSAndrew Lunn .age_time_coeff = 3750, 54441a3b39ecSAndrew Lunn .g1_irqs = 9, 5445d6c5e6afSVivien Didelot .g2_irqs = 14, 5446e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5447f3645652SVivien Didelot .pvt = true, 5448b3e05aa1SVivien Didelot .multi_chip = true, 54492fa8d3afSBrandon Streiff .ptp_support = true, 54501a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 54511a3b39ecSAndrew Lunn }, 54521a3b39ecSAndrew Lunn 5453fad09c73SVivien Didelot [MV88E6320] = { 5454107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 5455fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 5456fad09c73SVivien Didelot .name = "Marvell 88E6320", 5457fad09c73SVivien Didelot .num_databases = 4096, 5458d9ea5620SAndrew Lunn .num_macs = 8192, 5459fad09c73SVivien Didelot .num_ports = 7, 5460bc393155SAndrew Lunn .num_internal_phys = 5, 5461a73ccd61SBrandon Streiff .num_gpio = 15, 54623cf3c846SVivien Didelot .max_vid = 4095, 5463fad09c73SVivien Didelot .port_base_addr = 0x10, 54649255bacdSAndrew Lunn .phy_base_addr = 0x0, 5465a935c052SVivien Didelot .global1_addr = 0x1b, 54669069c13aSVivien Didelot .global2_addr = 0x1c, 5467acddbd21SVivien Didelot .age_time_coeff = 15000, 5468dc30c35bSAndrew Lunn .g1_irqs = 8, 5469bc393155SAndrew Lunn .g2_irqs = 10, 5470e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5471f3645652SVivien Didelot .pvt = true, 5472b3e05aa1SVivien Didelot .multi_chip = true, 5473670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 54742fa8d3afSBrandon Streiff .ptp_support = true, 5475b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 5476fad09c73SVivien Didelot }, 5477fad09c73SVivien Didelot 5478fad09c73SVivien Didelot [MV88E6321] = { 5479107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 5480fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 5481fad09c73SVivien Didelot .name = "Marvell 88E6321", 5482fad09c73SVivien Didelot .num_databases = 4096, 5483d9ea5620SAndrew Lunn .num_macs = 8192, 5484fad09c73SVivien Didelot .num_ports = 7, 5485bc393155SAndrew Lunn .num_internal_phys = 5, 5486a73ccd61SBrandon Streiff .num_gpio = 15, 54873cf3c846SVivien Didelot .max_vid = 4095, 5488fad09c73SVivien Didelot .port_base_addr = 0x10, 54899255bacdSAndrew Lunn .phy_base_addr = 0x0, 5490a935c052SVivien Didelot .global1_addr = 0x1b, 54919069c13aSVivien Didelot .global2_addr = 0x1c, 5492acddbd21SVivien Didelot .age_time_coeff = 15000, 5493dc30c35bSAndrew Lunn .g1_irqs = 8, 5494bc393155SAndrew Lunn .g2_irqs = 10, 5495e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5496b3e05aa1SVivien Didelot .multi_chip = true, 5497670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 54982fa8d3afSBrandon Streiff .ptp_support = true, 5499b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 5500fad09c73SVivien Didelot }, 5501fad09c73SVivien Didelot 5502a75961d0SGregory CLEMENT [MV88E6341] = { 5503107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 5504a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 5505a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 5506a75961d0SGregory CLEMENT .num_databases = 4096, 5507d9ea5620SAndrew Lunn .num_macs = 2048, 5508bc393155SAndrew Lunn .num_internal_phys = 5, 5509a75961d0SGregory CLEMENT .num_ports = 6, 5510a73ccd61SBrandon Streiff .num_gpio = 11, 55113cf3c846SVivien Didelot .max_vid = 4095, 5512a75961d0SGregory CLEMENT .port_base_addr = 0x10, 55139255bacdSAndrew Lunn .phy_base_addr = 0x10, 5514a75961d0SGregory CLEMENT .global1_addr = 0x1b, 55159069c13aSVivien Didelot .global2_addr = 0x1c, 5516a75961d0SGregory CLEMENT .age_time_coeff = 3750, 5517e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5518adfccf11SAndrew Lunn .g1_irqs = 9, 5519d6c5e6afSVivien Didelot .g2_irqs = 10, 5520f3645652SVivien Didelot .pvt = true, 5521b3e05aa1SVivien Didelot .multi_chip = true, 5522670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 55232fa8d3afSBrandon Streiff .ptp_support = true, 5524a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 5525a75961d0SGregory CLEMENT }, 5526a75961d0SGregory CLEMENT 5527fad09c73SVivien Didelot [MV88E6350] = { 5528107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 5529fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5530fad09c73SVivien Didelot .name = "Marvell 88E6350", 5531fad09c73SVivien Didelot .num_databases = 4096, 5532d9ea5620SAndrew Lunn .num_macs = 8192, 5533fad09c73SVivien Didelot .num_ports = 7, 5534bc393155SAndrew Lunn .num_internal_phys = 5, 55353cf3c846SVivien Didelot .max_vid = 4095, 5536fad09c73SVivien Didelot .port_base_addr = 0x10, 55379255bacdSAndrew Lunn .phy_base_addr = 0x0, 5538a935c052SVivien Didelot .global1_addr = 0x1b, 55399069c13aSVivien Didelot .global2_addr = 0x1c, 5540acddbd21SVivien Didelot .age_time_coeff = 15000, 5541dc30c35bSAndrew Lunn .g1_irqs = 9, 5542d6c5e6afSVivien Didelot .g2_irqs = 10, 5543e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5544f3645652SVivien Didelot .pvt = true, 5545b3e05aa1SVivien Didelot .multi_chip = true, 5546670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5547b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 5548fad09c73SVivien Didelot }, 5549fad09c73SVivien Didelot 5550fad09c73SVivien Didelot [MV88E6351] = { 5551107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 5552fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5553fad09c73SVivien Didelot .name = "Marvell 88E6351", 5554fad09c73SVivien Didelot .num_databases = 4096, 5555d9ea5620SAndrew Lunn .num_macs = 8192, 5556fad09c73SVivien Didelot .num_ports = 7, 5557bc393155SAndrew Lunn .num_internal_phys = 5, 55583cf3c846SVivien Didelot .max_vid = 4095, 5559fad09c73SVivien Didelot .port_base_addr = 0x10, 55609255bacdSAndrew Lunn .phy_base_addr = 0x0, 5561a935c052SVivien Didelot .global1_addr = 0x1b, 55629069c13aSVivien Didelot .global2_addr = 0x1c, 5563acddbd21SVivien Didelot .age_time_coeff = 15000, 5564dc30c35bSAndrew Lunn .g1_irqs = 9, 5565d6c5e6afSVivien Didelot .g2_irqs = 10, 5566e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5567f3645652SVivien Didelot .pvt = true, 5568b3e05aa1SVivien Didelot .multi_chip = true, 5569670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5570b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 5571fad09c73SVivien Didelot }, 5572fad09c73SVivien Didelot 5573fad09c73SVivien Didelot [MV88E6352] = { 5574107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 5575fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5576fad09c73SVivien Didelot .name = "Marvell 88E6352", 5577fad09c73SVivien Didelot .num_databases = 4096, 5578d9ea5620SAndrew Lunn .num_macs = 8192, 5579fad09c73SVivien Didelot .num_ports = 7, 5580bc393155SAndrew Lunn .num_internal_phys = 5, 5581a73ccd61SBrandon Streiff .num_gpio = 15, 55823cf3c846SVivien Didelot .max_vid = 4095, 5583fad09c73SVivien Didelot .port_base_addr = 0x10, 55849255bacdSAndrew Lunn .phy_base_addr = 0x0, 5585a935c052SVivien Didelot .global1_addr = 0x1b, 55869069c13aSVivien Didelot .global2_addr = 0x1c, 5587acddbd21SVivien Didelot .age_time_coeff = 15000, 5588dc30c35bSAndrew Lunn .g1_irqs = 9, 5589d6c5e6afSVivien Didelot .g2_irqs = 10, 5590e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5591f3645652SVivien Didelot .pvt = true, 5592b3e05aa1SVivien Didelot .multi_chip = true, 5593670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 55942fa8d3afSBrandon Streiff .ptp_support = true, 5595b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 5596fad09c73SVivien Didelot }, 55971a3b39ecSAndrew Lunn [MV88E6390] = { 5598107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 55991a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 56001a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 56011a3b39ecSAndrew Lunn .num_databases = 4096, 5602d9ea5620SAndrew Lunn .num_macs = 16384, 56031a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 560495150f29SHeiner Kallweit .num_internal_phys = 9, 5605a73ccd61SBrandon Streiff .num_gpio = 16, 5606931d1822SVivien Didelot .max_vid = 8191, 56071a3b39ecSAndrew Lunn .port_base_addr = 0x0, 56089255bacdSAndrew Lunn .phy_base_addr = 0x0, 56091a3b39ecSAndrew Lunn .global1_addr = 0x1b, 56109069c13aSVivien Didelot .global2_addr = 0x1c, 5611b91e055cSAndrew Lunn .age_time_coeff = 3750, 56121a3b39ecSAndrew Lunn .g1_irqs = 9, 5613d6c5e6afSVivien Didelot .g2_irqs = 14, 5614e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5615f3645652SVivien Didelot .pvt = true, 5616b3e05aa1SVivien Didelot .multi_chip = true, 5617670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED, 56182fa8d3afSBrandon Streiff .ptp_support = true, 56191a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 56201a3b39ecSAndrew Lunn }, 56211a3b39ecSAndrew Lunn [MV88E6390X] = { 5622107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 56231a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 56241a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 56251a3b39ecSAndrew Lunn .num_databases = 4096, 5626d9ea5620SAndrew Lunn .num_macs = 16384, 56271a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 562895150f29SHeiner Kallweit .num_internal_phys = 9, 5629a73ccd61SBrandon Streiff .num_gpio = 16, 5630931d1822SVivien Didelot .max_vid = 8191, 56311a3b39ecSAndrew Lunn .port_base_addr = 0x0, 56329255bacdSAndrew Lunn .phy_base_addr = 0x0, 56331a3b39ecSAndrew Lunn .global1_addr = 0x1b, 56349069c13aSVivien Didelot .global2_addr = 0x1c, 5635b91e055cSAndrew Lunn .age_time_coeff = 3750, 56361a3b39ecSAndrew Lunn .g1_irqs = 9, 5637d6c5e6afSVivien Didelot .g2_irqs = 14, 5638e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5639f3645652SVivien Didelot .pvt = true, 5640b3e05aa1SVivien Didelot .multi_chip = true, 5641670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED, 56422fa8d3afSBrandon Streiff .ptp_support = true, 56431a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 56441a3b39ecSAndrew Lunn }, 5645de776d0dSPavana Sharma 5646de776d0dSPavana Sharma [MV88E6393X] = { 5647de776d0dSPavana Sharma .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, 5648de776d0dSPavana Sharma .family = MV88E6XXX_FAMILY_6393, 5649de776d0dSPavana Sharma .name = "Marvell 88E6393X", 5650de776d0dSPavana Sharma .num_databases = 4096, 5651de776d0dSPavana Sharma .num_ports = 11, /* 10 + Z80 */ 5652de776d0dSPavana Sharma .num_internal_phys = 9, 5653de776d0dSPavana Sharma .max_vid = 8191, 5654de776d0dSPavana Sharma .port_base_addr = 0x0, 5655de776d0dSPavana Sharma .phy_base_addr = 0x0, 5656de776d0dSPavana Sharma .global1_addr = 0x1b, 5657de776d0dSPavana Sharma .global2_addr = 0x1c, 5658de776d0dSPavana Sharma .age_time_coeff = 3750, 5659de776d0dSPavana Sharma .g1_irqs = 10, 5660de776d0dSPavana Sharma .g2_irqs = 14, 5661de776d0dSPavana Sharma .atu_move_port_mask = 0x1f, 5662de776d0dSPavana Sharma .pvt = true, 5663de776d0dSPavana Sharma .multi_chip = true, 5664de776d0dSPavana Sharma .ptp_support = true, 5665de776d0dSPavana Sharma .ops = &mv88e6393x_ops, 5666de776d0dSPavana Sharma }, 5667fad09c73SVivien Didelot }; 5668fad09c73SVivien Didelot 5669fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 5670fad09c73SVivien Didelot { 5671fad09c73SVivien Didelot int i; 5672fad09c73SVivien Didelot 5673fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 5674fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 5675fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 5676fad09c73SVivien Didelot 5677fad09c73SVivien Didelot return NULL; 5678fad09c73SVivien Didelot } 5679fad09c73SVivien Didelot 5680fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 5681fad09c73SVivien Didelot { 5682fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 56838f6345b2SVivien Didelot unsigned int prod_num, rev; 56848f6345b2SVivien Didelot u16 id; 56858f6345b2SVivien Didelot int err; 5686fad09c73SVivien Didelot 5687c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5688107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 5689c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 56908f6345b2SVivien Didelot if (err) 56918f6345b2SVivien Didelot return err; 5692fad09c73SVivien Didelot 5693107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 5694107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 5695fad09c73SVivien Didelot 5696fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 5697fad09c73SVivien Didelot if (!info) 5698fad09c73SVivien Didelot return -ENODEV; 5699fad09c73SVivien Didelot 5700fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 5701fad09c73SVivien Didelot chip->info = info; 5702fad09c73SVivien Didelot 5703fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 5704fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 5705fad09c73SVivien Didelot 5706fad09c73SVivien Didelot return 0; 5707fad09c73SVivien Didelot } 5708fad09c73SVivien Didelot 5709fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 5710fad09c73SVivien Didelot { 5711fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5712fad09c73SVivien Didelot 5713fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 5714fad09c73SVivien Didelot if (!chip) 5715fad09c73SVivien Didelot return NULL; 5716fad09c73SVivien Didelot 5717fad09c73SVivien Didelot chip->dev = dev; 5718fad09c73SVivien Didelot 5719fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 5720a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 5721da7dc875SVivien Didelot idr_init(&chip->policies); 5722fad09c73SVivien Didelot 5723fad09c73SVivien Didelot return chip; 5724fad09c73SVivien Didelot } 5725fad09c73SVivien Didelot 57265ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 57274d776482SFlorian Fainelli int port, 57284d776482SFlorian Fainelli enum dsa_tag_protocol m) 57297b314362SAndrew Lunn { 573004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 57312bbb33beSAndrew Lunn 5732670bb80fSTobias Waldekranz return chip->tag_protocol; 57337b314362SAndrew Lunn } 57347b314362SAndrew Lunn 57359a99bef5STobias Waldekranz static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds, int port, 57369a99bef5STobias Waldekranz enum dsa_tag_protocol proto) 57379a99bef5STobias Waldekranz { 57389a99bef5STobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 57399a99bef5STobias Waldekranz enum dsa_tag_protocol old_protocol; 57409a99bef5STobias Waldekranz int err; 57419a99bef5STobias Waldekranz 57429a99bef5STobias Waldekranz switch (proto) { 57439a99bef5STobias Waldekranz case DSA_TAG_PROTO_EDSA: 57449a99bef5STobias Waldekranz switch (chip->info->edsa_support) { 57459a99bef5STobias Waldekranz case MV88E6XXX_EDSA_UNSUPPORTED: 57469a99bef5STobias Waldekranz return -EPROTONOSUPPORT; 57479a99bef5STobias Waldekranz case MV88E6XXX_EDSA_UNDOCUMENTED: 57489a99bef5STobias Waldekranz dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n"); 57499a99bef5STobias Waldekranz fallthrough; 57509a99bef5STobias Waldekranz case MV88E6XXX_EDSA_SUPPORTED: 57519a99bef5STobias Waldekranz break; 57529a99bef5STobias Waldekranz } 57539a99bef5STobias Waldekranz break; 57549a99bef5STobias Waldekranz case DSA_TAG_PROTO_DSA: 57559a99bef5STobias Waldekranz break; 57569a99bef5STobias Waldekranz default: 57579a99bef5STobias Waldekranz return -EPROTONOSUPPORT; 57589a99bef5STobias Waldekranz } 57599a99bef5STobias Waldekranz 57609a99bef5STobias Waldekranz old_protocol = chip->tag_protocol; 57619a99bef5STobias Waldekranz chip->tag_protocol = proto; 57629a99bef5STobias Waldekranz 57639a99bef5STobias Waldekranz mv88e6xxx_reg_lock(chip); 57649a99bef5STobias Waldekranz err = mv88e6xxx_setup_port_mode(chip, port); 57659a99bef5STobias Waldekranz mv88e6xxx_reg_unlock(chip); 57669a99bef5STobias Waldekranz 57679a99bef5STobias Waldekranz if (err) 57689a99bef5STobias Waldekranz chip->tag_protocol = old_protocol; 57699a99bef5STobias Waldekranz 57709a99bef5STobias Waldekranz return err; 57719a99bef5STobias Waldekranz } 57729a99bef5STobias Waldekranz 5773a52b2da7SVladimir Oltean static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 57743709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 57757df8fbddSVivien Didelot { 577604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 5777a52b2da7SVladimir Oltean int err; 57787df8fbddSVivien Didelot 5779c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5780a52b2da7SVladimir Oltean err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 5781a52b2da7SVladimir Oltean MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC); 5782c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5783a52b2da7SVladimir Oltean 5784a52b2da7SVladimir Oltean return err; 57857df8fbddSVivien Didelot } 57867df8fbddSVivien Didelot 57877df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 57887df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 57897df8fbddSVivien Didelot { 579004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 57917df8fbddSVivien Didelot int err; 57927df8fbddSVivien Didelot 5793c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5794d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0); 5795c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 57967df8fbddSVivien Didelot 57977df8fbddSVivien Didelot return err; 57987df8fbddSVivien Didelot } 57997df8fbddSVivien Didelot 5800f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, 5801f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror, 5802f0942e00SIwan R Timmer bool ingress) 5803f0942e00SIwan R Timmer { 5804f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = ingress ? 5805f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5806f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5807f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5808f0942e00SIwan R Timmer bool other_mirrors = false; 5809f0942e00SIwan R Timmer int i; 5810f0942e00SIwan R Timmer int err; 5811f0942e00SIwan R Timmer 5812f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5813f0942e00SIwan R Timmer if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != 5814f0942e00SIwan R Timmer mirror->to_local_port) { 5815f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5816f0942e00SIwan R Timmer other_mirrors |= ingress ? 5817f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5818f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5819f0942e00SIwan R Timmer 5820f0942e00SIwan R Timmer /* Can't change egress port when other mirror is active */ 5821f0942e00SIwan R Timmer if (other_mirrors) { 5822f0942e00SIwan R Timmer err = -EBUSY; 5823f0942e00SIwan R Timmer goto out; 5824f0942e00SIwan R Timmer } 5825f0942e00SIwan R Timmer 58262fda45f0SMarek Behún err = mv88e6xxx_set_egress_port(chip, direction, 5827f0942e00SIwan R Timmer mirror->to_local_port); 5828f0942e00SIwan R Timmer if (err) 5829f0942e00SIwan R Timmer goto out; 5830f0942e00SIwan R Timmer } 5831f0942e00SIwan R Timmer 5832f0942e00SIwan R Timmer err = mv88e6xxx_port_set_mirror(chip, port, direction, true); 5833f0942e00SIwan R Timmer out: 5834f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5835f0942e00SIwan R Timmer 5836f0942e00SIwan R Timmer return err; 5837f0942e00SIwan R Timmer } 5838f0942e00SIwan R Timmer 5839f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, 5840f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror) 5841f0942e00SIwan R Timmer { 5842f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = mirror->ingress ? 5843f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5844f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5845f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5846f0942e00SIwan R Timmer bool other_mirrors = false; 5847f0942e00SIwan R Timmer int i; 5848f0942e00SIwan R Timmer 5849f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5850f0942e00SIwan R Timmer if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) 5851f0942e00SIwan R Timmer dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); 5852f0942e00SIwan R Timmer 5853f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5854f0942e00SIwan R Timmer other_mirrors |= mirror->ingress ? 5855f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5856f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5857f0942e00SIwan R Timmer 5858f0942e00SIwan R Timmer /* Reset egress port when no other mirror is active */ 5859f0942e00SIwan R Timmer if (!other_mirrors) { 58602fda45f0SMarek Behún if (mv88e6xxx_set_egress_port(chip, direction, 58612fda45f0SMarek Behún dsa_upstream_port(ds, port))) 5862f0942e00SIwan R Timmer dev_err(ds->dev, "failed to set egress port\n"); 5863f0942e00SIwan R Timmer } 5864f0942e00SIwan R Timmer 5865f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5866f0942e00SIwan R Timmer } 5867f0942e00SIwan R Timmer 5868a8b659e7SVladimir Oltean static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port, 5869a8b659e7SVladimir Oltean struct switchdev_brport_flags flags, 5870a8b659e7SVladimir Oltean struct netlink_ext_ack *extack) 5871a8b659e7SVladimir Oltean { 5872a8b659e7SVladimir Oltean struct mv88e6xxx_chip *chip = ds->priv; 5873a8b659e7SVladimir Oltean const struct mv88e6xxx_ops *ops; 5874a8b659e7SVladimir Oltean 58758d1d8298STobias Waldekranz if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | 58768d1d8298STobias Waldekranz BR_BCAST_FLOOD)) 5877a8b659e7SVladimir Oltean return -EINVAL; 5878a8b659e7SVladimir Oltean 5879a8b659e7SVladimir Oltean ops = chip->info->ops; 5880a8b659e7SVladimir Oltean 5881a8b659e7SVladimir Oltean if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood) 5882a8b659e7SVladimir Oltean return -EINVAL; 5883a8b659e7SVladimir Oltean 5884a8b659e7SVladimir Oltean if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood) 5885a8b659e7SVladimir Oltean return -EINVAL; 5886a8b659e7SVladimir Oltean 5887a8b659e7SVladimir Oltean return 0; 5888a8b659e7SVladimir Oltean } 5889a8b659e7SVladimir Oltean 5890a8b659e7SVladimir Oltean static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, 5891a8b659e7SVladimir Oltean struct switchdev_brport_flags flags, 5892a8b659e7SVladimir Oltean struct netlink_ext_ack *extack) 58934f85901fSRussell King { 58944f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 58954f85901fSRussell King int err = -EOPNOTSUPP; 58964f85901fSRussell King 5897c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5898a8b659e7SVladimir Oltean 5899041bd545STobias Waldekranz if (flags.mask & BR_LEARNING) { 5900041bd545STobias Waldekranz bool learning = !!(flags.val & BR_LEARNING); 5901041bd545STobias Waldekranz u16 pav = learning ? (1 << port) : 0; 5902041bd545STobias Waldekranz 5903041bd545STobias Waldekranz err = mv88e6xxx_port_set_assoc_vector(chip, port, pav); 5904041bd545STobias Waldekranz if (err) 5905041bd545STobias Waldekranz goto out; 5906041bd545STobias Waldekranz } 5907041bd545STobias Waldekranz 5908a8b659e7SVladimir Oltean if (flags.mask & BR_FLOOD) { 5909a8b659e7SVladimir Oltean bool unicast = !!(flags.val & BR_FLOOD); 5910a8b659e7SVladimir Oltean 5911a8b659e7SVladimir Oltean err = chip->info->ops->port_set_ucast_flood(chip, port, 5912a8b659e7SVladimir Oltean unicast); 5913a8b659e7SVladimir Oltean if (err) 5914a8b659e7SVladimir Oltean goto out; 5915a8b659e7SVladimir Oltean } 5916a8b659e7SVladimir Oltean 5917a8b659e7SVladimir Oltean if (flags.mask & BR_MCAST_FLOOD) { 5918a8b659e7SVladimir Oltean bool multicast = !!(flags.val & BR_MCAST_FLOOD); 5919a8b659e7SVladimir Oltean 5920a8b659e7SVladimir Oltean err = chip->info->ops->port_set_mcast_flood(chip, port, 59214f85901fSRussell King multicast); 5922a8b659e7SVladimir Oltean if (err) 5923a8b659e7SVladimir Oltean goto out; 5924a8b659e7SVladimir Oltean } 5925a8b659e7SVladimir Oltean 59268d1d8298STobias Waldekranz if (flags.mask & BR_BCAST_FLOOD) { 59278d1d8298STobias Waldekranz bool broadcast = !!(flags.val & BR_BCAST_FLOOD); 59288d1d8298STobias Waldekranz 59298d1d8298STobias Waldekranz err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast); 59308d1d8298STobias Waldekranz if (err) 59318d1d8298STobias Waldekranz goto out; 59328d1d8298STobias Waldekranz } 59338d1d8298STobias Waldekranz 5934a8b659e7SVladimir Oltean out: 5935a8b659e7SVladimir Oltean mv88e6xxx_reg_unlock(chip); 5936a8b659e7SVladimir Oltean 5937a8b659e7SVladimir Oltean return err; 5938a8b659e7SVladimir Oltean } 5939a8b659e7SVladimir Oltean 594057e661aaSTobias Waldekranz static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, 594157e661aaSTobias Waldekranz struct net_device *lag, 594257e661aaSTobias Waldekranz struct netdev_lag_upper_info *info) 594357e661aaSTobias Waldekranz { 5944b80dc51bSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 594557e661aaSTobias Waldekranz struct dsa_port *dp; 594657e661aaSTobias Waldekranz int id, members = 0; 594757e661aaSTobias Waldekranz 5948b80dc51bSTobias Waldekranz if (!mv88e6xxx_has_lag(chip)) 5949b80dc51bSTobias Waldekranz return false; 5950b80dc51bSTobias Waldekranz 595157e661aaSTobias Waldekranz id = dsa_lag_id(ds->dst, lag); 595257e661aaSTobias Waldekranz if (id < 0 || id >= ds->num_lag_ids) 595357e661aaSTobias Waldekranz return false; 595457e661aaSTobias Waldekranz 595557e661aaSTobias Waldekranz dsa_lag_foreach_port(dp, ds->dst, lag) 595657e661aaSTobias Waldekranz /* Includes the port joining the LAG */ 595757e661aaSTobias Waldekranz members++; 595857e661aaSTobias Waldekranz 595957e661aaSTobias Waldekranz if (members > 8) 596057e661aaSTobias Waldekranz return false; 596157e661aaSTobias Waldekranz 596257e661aaSTobias Waldekranz /* We could potentially relax this to include active 596357e661aaSTobias Waldekranz * backup in the future. 596457e661aaSTobias Waldekranz */ 596557e661aaSTobias Waldekranz if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) 596657e661aaSTobias Waldekranz return false; 596757e661aaSTobias Waldekranz 596857e661aaSTobias Waldekranz /* Ideally we would also validate that the hash type matches 596957e661aaSTobias Waldekranz * the hardware. Alas, this is always set to unknown on team 597057e661aaSTobias Waldekranz * interfaces. 597157e661aaSTobias Waldekranz */ 597257e661aaSTobias Waldekranz return true; 597357e661aaSTobias Waldekranz } 597457e661aaSTobias Waldekranz 597557e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct net_device *lag) 597657e661aaSTobias Waldekranz { 597757e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 597857e661aaSTobias Waldekranz struct dsa_port *dp; 597957e661aaSTobias Waldekranz u16 map = 0; 598057e661aaSTobias Waldekranz int id; 598157e661aaSTobias Waldekranz 598257e661aaSTobias Waldekranz id = dsa_lag_id(ds->dst, lag); 598357e661aaSTobias Waldekranz 598457e661aaSTobias Waldekranz /* Build the map of all ports to distribute flows destined for 598557e661aaSTobias Waldekranz * this LAG. This can be either a local user port, or a DSA 598657e661aaSTobias Waldekranz * port if the LAG port is on a remote chip. 598757e661aaSTobias Waldekranz */ 598857e661aaSTobias Waldekranz dsa_lag_foreach_port(dp, ds->dst, lag) 598957e661aaSTobias Waldekranz map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index)); 599057e661aaSTobias Waldekranz 599157e661aaSTobias Waldekranz return mv88e6xxx_g2_trunk_mapping_write(chip, id, map); 599257e661aaSTobias Waldekranz } 599357e661aaSTobias Waldekranz 599457e661aaSTobias Waldekranz static const u8 mv88e6xxx_lag_mask_table[8][8] = { 599557e661aaSTobias Waldekranz /* Row number corresponds to the number of active members in a 599657e661aaSTobias Waldekranz * LAG. Each column states which of the eight hash buckets are 599757e661aaSTobias Waldekranz * mapped to the column:th port in the LAG. 599857e661aaSTobias Waldekranz * 599957e661aaSTobias Waldekranz * Example: In a LAG with three active ports, the second port 600057e661aaSTobias Waldekranz * ([2][1]) would be selected for traffic mapped to buckets 600157e661aaSTobias Waldekranz * 3,4,5 (0x38). 600257e661aaSTobias Waldekranz */ 600357e661aaSTobias Waldekranz { 0xff, 0, 0, 0, 0, 0, 0, 0 }, 600457e661aaSTobias Waldekranz { 0x0f, 0xf0, 0, 0, 0, 0, 0, 0 }, 600557e661aaSTobias Waldekranz { 0x07, 0x38, 0xc0, 0, 0, 0, 0, 0 }, 600657e661aaSTobias Waldekranz { 0x03, 0x0c, 0x30, 0xc0, 0, 0, 0, 0 }, 600757e661aaSTobias Waldekranz { 0x03, 0x0c, 0x30, 0x40, 0x80, 0, 0, 0 }, 600857e661aaSTobias Waldekranz { 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80, 0, 0 }, 600957e661aaSTobias Waldekranz { 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0 }, 601057e661aaSTobias Waldekranz { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, 601157e661aaSTobias Waldekranz }; 601257e661aaSTobias Waldekranz 601357e661aaSTobias Waldekranz static void mv88e6xxx_lag_set_port_mask(u16 *mask, int port, 601457e661aaSTobias Waldekranz int num_tx, int nth) 601557e661aaSTobias Waldekranz { 601657e661aaSTobias Waldekranz u8 active = 0; 601757e661aaSTobias Waldekranz int i; 601857e661aaSTobias Waldekranz 601957e661aaSTobias Waldekranz num_tx = num_tx <= 8 ? num_tx : 8; 602057e661aaSTobias Waldekranz if (nth < num_tx) 602157e661aaSTobias Waldekranz active = mv88e6xxx_lag_mask_table[num_tx - 1][nth]; 602257e661aaSTobias Waldekranz 602357e661aaSTobias Waldekranz for (i = 0; i < 8; i++) { 602457e661aaSTobias Waldekranz if (BIT(i) & active) 602557e661aaSTobias Waldekranz mask[i] |= BIT(port); 602657e661aaSTobias Waldekranz } 602757e661aaSTobias Waldekranz } 602857e661aaSTobias Waldekranz 602957e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds) 603057e661aaSTobias Waldekranz { 603157e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 603257e661aaSTobias Waldekranz unsigned int id, num_tx; 603357e661aaSTobias Waldekranz struct net_device *lag; 603457e661aaSTobias Waldekranz struct dsa_port *dp; 603557e661aaSTobias Waldekranz int i, err, nth; 603657e661aaSTobias Waldekranz u16 mask[8]; 603757e661aaSTobias Waldekranz u16 ivec; 603857e661aaSTobias Waldekranz 603957e661aaSTobias Waldekranz /* Assume no port is a member of any LAG. */ 604057e661aaSTobias Waldekranz ivec = BIT(mv88e6xxx_num_ports(chip)) - 1; 604157e661aaSTobias Waldekranz 604257e661aaSTobias Waldekranz /* Disable all masks for ports that _are_ members of a LAG. */ 604357e661aaSTobias Waldekranz list_for_each_entry(dp, &ds->dst->ports, list) { 604457e661aaSTobias Waldekranz if (!dp->lag_dev || dp->ds != ds) 604557e661aaSTobias Waldekranz continue; 604657e661aaSTobias Waldekranz 604757e661aaSTobias Waldekranz ivec &= ~BIT(dp->index); 604857e661aaSTobias Waldekranz } 604957e661aaSTobias Waldekranz 605057e661aaSTobias Waldekranz for (i = 0; i < 8; i++) 605157e661aaSTobias Waldekranz mask[i] = ivec; 605257e661aaSTobias Waldekranz 605357e661aaSTobias Waldekranz /* Enable the correct subset of masks for all LAG ports that 605457e661aaSTobias Waldekranz * are in the Tx set. 605557e661aaSTobias Waldekranz */ 605657e661aaSTobias Waldekranz dsa_lags_foreach_id(id, ds->dst) { 605757e661aaSTobias Waldekranz lag = dsa_lag_dev(ds->dst, id); 605857e661aaSTobias Waldekranz if (!lag) 605957e661aaSTobias Waldekranz continue; 606057e661aaSTobias Waldekranz 606157e661aaSTobias Waldekranz num_tx = 0; 606257e661aaSTobias Waldekranz dsa_lag_foreach_port(dp, ds->dst, lag) { 606357e661aaSTobias Waldekranz if (dp->lag_tx_enabled) 606457e661aaSTobias Waldekranz num_tx++; 606557e661aaSTobias Waldekranz } 606657e661aaSTobias Waldekranz 606757e661aaSTobias Waldekranz if (!num_tx) 606857e661aaSTobias Waldekranz continue; 606957e661aaSTobias Waldekranz 607057e661aaSTobias Waldekranz nth = 0; 607157e661aaSTobias Waldekranz dsa_lag_foreach_port(dp, ds->dst, lag) { 607257e661aaSTobias Waldekranz if (!dp->lag_tx_enabled) 607357e661aaSTobias Waldekranz continue; 607457e661aaSTobias Waldekranz 607557e661aaSTobias Waldekranz if (dp->ds == ds) 607657e661aaSTobias Waldekranz mv88e6xxx_lag_set_port_mask(mask, dp->index, 607757e661aaSTobias Waldekranz num_tx, nth); 607857e661aaSTobias Waldekranz 607957e661aaSTobias Waldekranz nth++; 608057e661aaSTobias Waldekranz } 608157e661aaSTobias Waldekranz } 608257e661aaSTobias Waldekranz 608357e661aaSTobias Waldekranz for (i = 0; i < 8; i++) { 608457e661aaSTobias Waldekranz err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]); 608557e661aaSTobias Waldekranz if (err) 608657e661aaSTobias Waldekranz return err; 608757e661aaSTobias Waldekranz } 608857e661aaSTobias Waldekranz 608957e661aaSTobias Waldekranz return 0; 609057e661aaSTobias Waldekranz } 609157e661aaSTobias Waldekranz 609257e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds, 609357e661aaSTobias Waldekranz struct net_device *lag) 609457e661aaSTobias Waldekranz { 609557e661aaSTobias Waldekranz int err; 609657e661aaSTobias Waldekranz 609757e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks(ds); 609857e661aaSTobias Waldekranz 609957e661aaSTobias Waldekranz if (!err) 610057e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_map(ds, lag); 610157e661aaSTobias Waldekranz 610257e661aaSTobias Waldekranz return err; 610357e661aaSTobias Waldekranz } 610457e661aaSTobias Waldekranz 610557e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port) 610657e661aaSTobias Waldekranz { 610757e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 610857e661aaSTobias Waldekranz int err; 610957e661aaSTobias Waldekranz 611057e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 611157e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks(ds); 611257e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 611357e661aaSTobias Waldekranz return err; 611457e661aaSTobias Waldekranz } 611557e661aaSTobias Waldekranz 611657e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port, 611757e661aaSTobias Waldekranz struct net_device *lag, 611857e661aaSTobias Waldekranz struct netdev_lag_upper_info *info) 611957e661aaSTobias Waldekranz { 612057e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 612157e661aaSTobias Waldekranz int err, id; 612257e661aaSTobias Waldekranz 612357e661aaSTobias Waldekranz if (!mv88e6xxx_lag_can_offload(ds, lag, info)) 612457e661aaSTobias Waldekranz return -EOPNOTSUPP; 612557e661aaSTobias Waldekranz 612657e661aaSTobias Waldekranz id = dsa_lag_id(ds->dst, lag); 612757e661aaSTobias Waldekranz 612857e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 612957e661aaSTobias Waldekranz 613057e661aaSTobias Waldekranz err = mv88e6xxx_port_set_trunk(chip, port, true, id); 613157e661aaSTobias Waldekranz if (err) 613257e661aaSTobias Waldekranz goto err_unlock; 613357e661aaSTobias Waldekranz 613457e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks_map(ds, lag); 613557e661aaSTobias Waldekranz if (err) 613657e661aaSTobias Waldekranz goto err_clear_trunk; 613757e661aaSTobias Waldekranz 613857e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 613957e661aaSTobias Waldekranz return 0; 614057e661aaSTobias Waldekranz 614157e661aaSTobias Waldekranz err_clear_trunk: 614257e661aaSTobias Waldekranz mv88e6xxx_port_set_trunk(chip, port, false, 0); 614357e661aaSTobias Waldekranz err_unlock: 614457e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 614557e661aaSTobias Waldekranz return err; 614657e661aaSTobias Waldekranz } 614757e661aaSTobias Waldekranz 614857e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port, 614957e661aaSTobias Waldekranz struct net_device *lag) 615057e661aaSTobias Waldekranz { 615157e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 615257e661aaSTobias Waldekranz int err_sync, err_trunk; 615357e661aaSTobias Waldekranz 615457e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 615557e661aaSTobias Waldekranz err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag); 615657e661aaSTobias Waldekranz err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0); 615757e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 615857e661aaSTobias Waldekranz return err_sync ? : err_trunk; 615957e661aaSTobias Waldekranz } 616057e661aaSTobias Waldekranz 616157e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index, 616257e661aaSTobias Waldekranz int port) 616357e661aaSTobias Waldekranz { 616457e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 616557e661aaSTobias Waldekranz int err; 616657e661aaSTobias Waldekranz 616757e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 616857e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks(ds); 616957e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 617057e661aaSTobias Waldekranz return err; 617157e661aaSTobias Waldekranz } 617257e661aaSTobias Waldekranz 617357e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index, 617457e661aaSTobias Waldekranz int port, struct net_device *lag, 617557e661aaSTobias Waldekranz struct netdev_lag_upper_info *info) 617657e661aaSTobias Waldekranz { 617757e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 617857e661aaSTobias Waldekranz int err; 617957e661aaSTobias Waldekranz 618057e661aaSTobias Waldekranz if (!mv88e6xxx_lag_can_offload(ds, lag, info)) 618157e661aaSTobias Waldekranz return -EOPNOTSUPP; 618257e661aaSTobias Waldekranz 618357e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 618457e661aaSTobias Waldekranz 618557e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks_map(ds, lag); 618657e661aaSTobias Waldekranz if (err) 618757e661aaSTobias Waldekranz goto unlock; 618857e661aaSTobias Waldekranz 618957e661aaSTobias Waldekranz err = mv88e6xxx_pvt_map(chip, sw_index, port); 619057e661aaSTobias Waldekranz 619157e661aaSTobias Waldekranz unlock: 619257e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 619357e661aaSTobias Waldekranz return err; 619457e661aaSTobias Waldekranz } 619557e661aaSTobias Waldekranz 619657e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index, 619757e661aaSTobias Waldekranz int port, struct net_device *lag) 619857e661aaSTobias Waldekranz { 619957e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 620057e661aaSTobias Waldekranz int err_sync, err_pvt; 620157e661aaSTobias Waldekranz 620257e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 620357e661aaSTobias Waldekranz err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag); 620457e661aaSTobias Waldekranz err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port); 620557e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 620657e661aaSTobias Waldekranz return err_sync ? : err_pvt; 620757e661aaSTobias Waldekranz } 620857e661aaSTobias Waldekranz 6209a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 62107b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 62119a99bef5STobias Waldekranz .change_tag_protocol = mv88e6xxx_change_tag_protocol, 6212fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 621323e8b470SAndrew Lunn .teardown = mv88e6xxx_teardown, 6214fd292c18SVladimir Oltean .port_setup = mv88e6xxx_port_setup, 6215fd292c18SVladimir Oltean .port_teardown = mv88e6xxx_port_teardown, 6216c9a2356fSRussell King .phylink_validate = mv88e6xxx_validate, 6217a5a6858bSRussell King .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, 6218c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 6219a5a6858bSRussell King .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, 6220c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 6221c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 6222fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 6223fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 6224fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 622504aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 622604aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 62272a550aecSAndrew Lunn .port_max_mtu = mv88e6xxx_get_max_mtu, 62282a550aecSAndrew Lunn .port_change_mtu = mv88e6xxx_change_mtu, 622908f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 623008f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 6231fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 6232fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 6233fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 6234fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 6235fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 6236da7dc875SVivien Didelot .get_rxnfc = mv88e6xxx_get_rxnfc, 6237da7dc875SVivien Didelot .set_rxnfc = mv88e6xxx_set_rxnfc, 62382cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 6239fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 6240fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 6241a8b659e7SVladimir Oltean .port_pre_bridge_flags = mv88e6xxx_port_pre_bridge_flags, 6242a8b659e7SVladimir Oltean .port_bridge_flags = mv88e6xxx_port_bridge_flags, 6243fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 6244749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 6245fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 6246fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 6247fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 6248fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 6249fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 6250fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 62517df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 62527df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 6253f0942e00SIwan R Timmer .port_mirror_add = mv88e6xxx_port_mirror_add, 6254f0942e00SIwan R Timmer .port_mirror_del = mv88e6xxx_port_mirror_del, 6255aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 6256aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 6257c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 6258c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 6259c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 6260c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 6261c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 626223e8b470SAndrew Lunn .devlink_param_get = mv88e6xxx_devlink_param_get, 626323e8b470SAndrew Lunn .devlink_param_set = mv88e6xxx_devlink_param_set, 626493157307SAndrew Lunn .devlink_info_get = mv88e6xxx_devlink_info_get, 626557e661aaSTobias Waldekranz .port_lag_change = mv88e6xxx_port_lag_change, 626657e661aaSTobias Waldekranz .port_lag_join = mv88e6xxx_port_lag_join, 626757e661aaSTobias Waldekranz .port_lag_leave = mv88e6xxx_port_lag_leave, 626857e661aaSTobias Waldekranz .crosschip_lag_change = mv88e6xxx_crosschip_lag_change, 626957e661aaSTobias Waldekranz .crosschip_lag_join = mv88e6xxx_crosschip_lag_join, 627057e661aaSTobias Waldekranz .crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave, 6271ce5df689SVladimir Oltean .port_bridge_tx_fwd_offload = mv88e6xxx_bridge_tx_fwd_offload, 6272ce5df689SVladimir Oltean .port_bridge_tx_fwd_unoffload = mv88e6xxx_bridge_tx_fwd_unoffload, 6273fad09c73SVivien Didelot }; 6274fad09c73SVivien Didelot 627555ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 6276fad09c73SVivien Didelot { 6277fad09c73SVivien Didelot struct device *dev = chip->dev; 6278fad09c73SVivien Didelot struct dsa_switch *ds; 6279fad09c73SVivien Didelot 62807e99e347SVivien Didelot ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); 6281fad09c73SVivien Didelot if (!ds) 6282fad09c73SVivien Didelot return -ENOMEM; 6283fad09c73SVivien Didelot 62847e99e347SVivien Didelot ds->dev = dev; 62857e99e347SVivien Didelot ds->num_ports = mv88e6xxx_num_ports(chip); 6286fad09c73SVivien Didelot ds->priv = chip; 6287877b7cb0SAndrew Lunn ds->dev = dev; 62889d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 62899ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 62909ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 6291fad09c73SVivien Didelot 629257e661aaSTobias Waldekranz /* Some chips support up to 32, but that requires enabling the 629357e661aaSTobias Waldekranz * 5-bit port mode, which we do not support. 640k^W16 ought to 629457e661aaSTobias Waldekranz * be enough for anyone. 629557e661aaSTobias Waldekranz */ 6296b80dc51bSTobias Waldekranz ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0; 629757e661aaSTobias Waldekranz 6298fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 6299fad09c73SVivien Didelot 630023c9ee49SVivien Didelot return dsa_register_switch(ds); 6301fad09c73SVivien Didelot } 6302fad09c73SVivien Didelot 6303fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 6304fad09c73SVivien Didelot { 6305fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 6306fad09c73SVivien Didelot } 6307fad09c73SVivien Didelot 6308877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 6309877b7cb0SAndrew Lunn { 6310877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 6311877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 6312877b7cb0SAndrew Lunn 6313877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 6314877b7cb0SAndrew Lunn matches++) { 6315877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 6316877b7cb0SAndrew Lunn return matches->data; 6317877b7cb0SAndrew Lunn } 6318877b7cb0SAndrew Lunn return NULL; 6319877b7cb0SAndrew Lunn } 6320877b7cb0SAndrew Lunn 6321bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 6322bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 6323bcd3d9d9SMiquel Raynal */ 6324bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 6325bcd3d9d9SMiquel Raynal { 6326bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 6327bcd3d9d9SMiquel Raynal } 6328bcd3d9d9SMiquel Raynal 6329bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 6330bcd3d9d9SMiquel Raynal { 6331bcd3d9d9SMiquel Raynal return 0; 6332bcd3d9d9SMiquel Raynal } 6333bcd3d9d9SMiquel Raynal 6334bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 6335bcd3d9d9SMiquel Raynal 6336fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 6337fad09c73SVivien Didelot { 6338877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 63397ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 6340fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 6341fad09c73SVivien Didelot struct device_node *np = dev->of_node; 6342fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 6343877b7cb0SAndrew Lunn int port; 6344fad09c73SVivien Didelot int err; 6345fad09c73SVivien Didelot 63467bb8c996SAndrew Lunn if (!np && !pdata) 63477bb8c996SAndrew Lunn return -EINVAL; 63487bb8c996SAndrew Lunn 6349877b7cb0SAndrew Lunn if (np) 6350fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 6351877b7cb0SAndrew Lunn 6352877b7cb0SAndrew Lunn if (pdata) { 6353877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 6354877b7cb0SAndrew Lunn 6355877b7cb0SAndrew Lunn if (!pdata->netdev) 6356877b7cb0SAndrew Lunn return -EINVAL; 6357877b7cb0SAndrew Lunn 6358877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 6359877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 6360877b7cb0SAndrew Lunn continue; 6361877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 6362877b7cb0SAndrew Lunn continue; 6363877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 6364877b7cb0SAndrew Lunn break; 6365877b7cb0SAndrew Lunn } 6366877b7cb0SAndrew Lunn } 6367877b7cb0SAndrew Lunn 6368fad09c73SVivien Didelot if (!compat_info) 6369fad09c73SVivien Didelot return -EINVAL; 6370fad09c73SVivien Didelot 6371fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 6372877b7cb0SAndrew Lunn if (!chip) { 6373877b7cb0SAndrew Lunn err = -ENOMEM; 6374877b7cb0SAndrew Lunn goto out; 6375877b7cb0SAndrew Lunn } 6376fad09c73SVivien Didelot 6377fad09c73SVivien Didelot chip->info = compat_info; 6378fad09c73SVivien Didelot 6379fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 6380fad09c73SVivien Didelot if (err) 6381877b7cb0SAndrew Lunn goto out; 6382fad09c73SVivien Didelot 6383b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 6384877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 6385877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 6386877b7cb0SAndrew Lunn goto out; 6387877b7cb0SAndrew Lunn } 63887b75e49dSBaruch Siach if (chip->reset) 63897b75e49dSBaruch Siach usleep_range(1000, 2000); 6390b4308f04SAndrew Lunn 6391fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 6392fad09c73SVivien Didelot if (err) 6393877b7cb0SAndrew Lunn goto out; 6394fad09c73SVivien Didelot 6395670bb80fSTobias Waldekranz if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED) 6396670bb80fSTobias Waldekranz chip->tag_protocol = DSA_TAG_PROTO_EDSA; 6397670bb80fSTobias Waldekranz else 6398670bb80fSTobias Waldekranz chip->tag_protocol = DSA_TAG_PROTO_DSA; 6399670bb80fSTobias Waldekranz 6400e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 6401e57e5e77SVivien Didelot 640200baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 640300baabe5SAndrew Lunn if (np) 640400baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 640500baabe5SAndrew Lunn &chip->eeprom_len); 640600baabe5SAndrew Lunn else 640700baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 640800baabe5SAndrew Lunn } 6409fad09c73SVivien Didelot 6410c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6411dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 6412c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 6413fad09c73SVivien Didelot if (err) 6414dc30c35bSAndrew Lunn goto out; 6415fad09c73SVivien Didelot 6416a27415deSAndrew Lunn if (np) { 6417dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 6418dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 6419dc30c35bSAndrew Lunn err = chip->irq; 6420dc30c35bSAndrew Lunn goto out; 6421fad09c73SVivien Didelot } 6422a27415deSAndrew Lunn } 6423a27415deSAndrew Lunn 6424a27415deSAndrew Lunn if (pdata) 6425a27415deSAndrew Lunn chip->irq = pdata->irq; 6426fad09c73SVivien Didelot 6427294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 6428a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 6429294d711eSAndrew Lunn * controllers 6430dc30c35bSAndrew Lunn */ 6431c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6432294d711eSAndrew Lunn if (chip->irq > 0) 6433dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 6434294d711eSAndrew Lunn else 6435294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 6436c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 6437dc30c35bSAndrew Lunn 6438dc30c35bSAndrew Lunn if (err) 6439dc30c35bSAndrew Lunn goto out; 6440dc30c35bSAndrew Lunn 6441d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 6442dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 6443dc30c35bSAndrew Lunn if (err) 6444dc30c35bSAndrew Lunn goto out_g1_irq; 6445dc30c35bSAndrew Lunn } 64460977644cSAndrew Lunn 64470977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 64480977644cSAndrew Lunn if (err) 64490977644cSAndrew Lunn goto out_g2_irq; 645062eb1162SAndrew Lunn 645162eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 645262eb1162SAndrew Lunn if (err) 645362eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 6454dc30c35bSAndrew Lunn 6455a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 6456dc30c35bSAndrew Lunn if (err) 645762eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 6458dc30c35bSAndrew Lunn 645955ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 6460dc30c35bSAndrew Lunn if (err) 6461dc30c35bSAndrew Lunn goto out_mdio; 6462dc30c35bSAndrew Lunn 6463fad09c73SVivien Didelot return 0; 6464dc30c35bSAndrew Lunn 6465dc30c35bSAndrew Lunn out_mdio: 6466a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 646762eb1162SAndrew Lunn out_g1_vtu_prob_irq: 646862eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 64690977644cSAndrew Lunn out_g1_atu_prob_irq: 64700977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 6471dc30c35bSAndrew Lunn out_g2_irq: 6472294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 6473dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 6474dc30c35bSAndrew Lunn out_g1_irq: 6475294d711eSAndrew Lunn if (chip->irq > 0) 6476dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 6477294d711eSAndrew Lunn else 6478294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 6479dc30c35bSAndrew Lunn out: 6480877b7cb0SAndrew Lunn if (pdata) 6481877b7cb0SAndrew Lunn dev_put(pdata->netdev); 6482877b7cb0SAndrew Lunn 6483dc30c35bSAndrew Lunn return err; 6484fad09c73SVivien Didelot } 6485fad09c73SVivien Didelot 6486fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 6487fad09c73SVivien Didelot { 6488fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 64890650bf52SVladimir Oltean struct mv88e6xxx_chip *chip; 64900650bf52SVladimir Oltean 64910650bf52SVladimir Oltean if (!ds) 64920650bf52SVladimir Oltean return; 64930650bf52SVladimir Oltean 64940650bf52SVladimir Oltean chip = ds->priv; 6495fad09c73SVivien Didelot 6496c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 6497c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 64982fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 6499c6fe0ad2SBrandon Streiff } 65002fa8d3afSBrandon Streiff 6501930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 6502fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 6503a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 6504dc30c35bSAndrew Lunn 650562eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 65060977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 650776f38f1fSAndrew Lunn 6508d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 6509dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 651076f38f1fSAndrew Lunn 651176f38f1fSAndrew Lunn if (chip->irq > 0) 6512dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 651376f38f1fSAndrew Lunn else 651476f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 65150650bf52SVladimir Oltean 65160650bf52SVladimir Oltean dev_set_drvdata(&mdiodev->dev, NULL); 65170650bf52SVladimir Oltean } 65180650bf52SVladimir Oltean 65190650bf52SVladimir Oltean static void mv88e6xxx_shutdown(struct mdio_device *mdiodev) 65200650bf52SVladimir Oltean { 65210650bf52SVladimir Oltean struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 65220650bf52SVladimir Oltean 65230650bf52SVladimir Oltean if (!ds) 65240650bf52SVladimir Oltean return; 65250650bf52SVladimir Oltean 65260650bf52SVladimir Oltean dsa_switch_shutdown(ds); 65270650bf52SVladimir Oltean 65280650bf52SVladimir Oltean dev_set_drvdata(&mdiodev->dev, NULL); 6529fad09c73SVivien Didelot } 6530fad09c73SVivien Didelot 6531fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 6532fad09c73SVivien Didelot { 6533fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 6534fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 6535fad09c73SVivien Didelot }, 65361a3b39ecSAndrew Lunn { 65371a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 65381a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 65391a3b39ecSAndrew Lunn }, 65401f71836fSRasmus Villemoes { 65411f71836fSRasmus Villemoes .compatible = "marvell,mv88e6250", 65421f71836fSRasmus Villemoes .data = &mv88e6xxx_table[MV88E6250], 65431f71836fSRasmus Villemoes }, 6544fad09c73SVivien Didelot { /* sentinel */ }, 6545fad09c73SVivien Didelot }; 6546fad09c73SVivien Didelot 6547fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 6548fad09c73SVivien Didelot 6549fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 6550fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 6551fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 65520650bf52SVladimir Oltean .shutdown = mv88e6xxx_shutdown, 6553fad09c73SVivien Didelot .mdiodrv.driver = { 6554fad09c73SVivien Didelot .name = "mv88e6085", 6555fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 6556bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 6557fad09c73SVivien Didelot }, 6558fad09c73SVivien Didelot }; 6559fad09c73SVivien Didelot 65607324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver); 6561fad09c73SVivien Didelot 6562fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 6563fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 6564fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 6565