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> 15fad09c73SVivien Didelot #include <linux/etherdevice.h> 16fad09c73SVivien Didelot #include <linux/ethtool.h> 17fad09c73SVivien Didelot #include <linux/if_bridge.h> 18dc30c35bSAndrew Lunn #include <linux/interrupt.h> 19dc30c35bSAndrew Lunn #include <linux/irq.h> 20dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 21fad09c73SVivien Didelot #include <linux/jiffies.h> 22fad09c73SVivien Didelot #include <linux/list.h> 23fad09c73SVivien Didelot #include <linux/mdio.h> 24fad09c73SVivien Didelot #include <linux/module.h> 25fad09c73SVivien Didelot #include <linux/of_device.h> 26dc30c35bSAndrew Lunn #include <linux/of_irq.h> 27fad09c73SVivien Didelot #include <linux/of_mdio.h> 28877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h> 29fad09c73SVivien Didelot #include <linux/netdevice.h> 30fad09c73SVivien Didelot #include <linux/gpio/consumer.h> 31c9a2356fSRussell King #include <linux/phylink.h> 32fad09c73SVivien Didelot #include <net/dsa.h> 33ec561276SVivien Didelot 344d5f2ba7SVivien Didelot #include "chip.h" 35a935c052SVivien Didelot #include "global1.h" 36ec561276SVivien Didelot #include "global2.h" 37c6fe0ad2SBrandon Streiff #include "hwtstamp.h" 3810fa5bfcSAndrew Lunn #include "phy.h" 3918abed21SVivien Didelot #include "port.h" 402fa8d3afSBrandon Streiff #include "ptp.h" 416d91782fSAndrew Lunn #include "serdes.h" 42e7ba0fadSVivien Didelot #include "smi.h" 43fad09c73SVivien Didelot 44fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 45fad09c73SVivien Didelot { 46fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 47fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 48fad09c73SVivien Didelot dump_stack(); 49fad09c73SVivien Didelot } 50fad09c73SVivien Didelot } 51fad09c73SVivien Didelot 52ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 53fad09c73SVivien Didelot { 54fad09c73SVivien Didelot int err; 55fad09c73SVivien Didelot 56fad09c73SVivien Didelot assert_reg_lock(chip); 57fad09c73SVivien Didelot 58fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 59fad09c73SVivien Didelot if (err) 60fad09c73SVivien Didelot return err; 61fad09c73SVivien Didelot 62fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 63fad09c73SVivien Didelot addr, reg, *val); 64fad09c73SVivien Didelot 65fad09c73SVivien Didelot return 0; 66fad09c73SVivien Didelot } 67fad09c73SVivien Didelot 68ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 69fad09c73SVivien Didelot { 70fad09c73SVivien Didelot int err; 71fad09c73SVivien Didelot 72fad09c73SVivien Didelot assert_reg_lock(chip); 73fad09c73SVivien Didelot 74fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 75fad09c73SVivien Didelot if (err) 76fad09c73SVivien Didelot return err; 77fad09c73SVivien Didelot 78fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 79fad09c73SVivien Didelot addr, reg, val); 80fad09c73SVivien Didelot 81fad09c73SVivien Didelot return 0; 82fad09c73SVivien Didelot } 83fad09c73SVivien Didelot 84683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, 85683f2244SVivien Didelot u16 mask, u16 val) 86683f2244SVivien Didelot { 87683f2244SVivien Didelot u16 data; 88683f2244SVivien Didelot int err; 89683f2244SVivien Didelot int i; 90683f2244SVivien Didelot 91683f2244SVivien Didelot /* There's no bus specific operation to wait for a mask */ 92683f2244SVivien Didelot for (i = 0; i < 16; i++) { 93683f2244SVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &data); 94683f2244SVivien Didelot if (err) 95683f2244SVivien Didelot return err; 96683f2244SVivien Didelot 97683f2244SVivien Didelot if ((data & mask) == val) 98683f2244SVivien Didelot return 0; 99683f2244SVivien Didelot 100683f2244SVivien Didelot usleep_range(1000, 2000); 101683f2244SVivien Didelot } 102683f2244SVivien Didelot 103683f2244SVivien Didelot dev_err(chip->dev, "Timeout while waiting for switch\n"); 104683f2244SVivien Didelot return -ETIMEDOUT; 105683f2244SVivien Didelot } 106683f2244SVivien Didelot 10719fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, 10819fb7f69SVivien Didelot int bit, int val) 10919fb7f69SVivien Didelot { 11019fb7f69SVivien Didelot return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit), 11119fb7f69SVivien Didelot val ? BIT(bit) : 0x0000); 11219fb7f69SVivien Didelot } 11319fb7f69SVivien Didelot 11410fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 115a3c53be5SAndrew Lunn { 116a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 117a3c53be5SAndrew Lunn 118a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 119a3c53be5SAndrew Lunn list); 120a3c53be5SAndrew Lunn if (!mdio_bus) 121a3c53be5SAndrew Lunn return NULL; 122a3c53be5SAndrew Lunn 123a3c53be5SAndrew Lunn return mdio_bus->bus; 124a3c53be5SAndrew Lunn } 125a3c53be5SAndrew Lunn 126dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d) 127dc30c35bSAndrew Lunn { 128dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 129dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 130dc30c35bSAndrew Lunn 131dc30c35bSAndrew Lunn chip->g1_irq.masked |= (1 << n); 132dc30c35bSAndrew Lunn } 133dc30c35bSAndrew Lunn 134dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 135dc30c35bSAndrew Lunn { 136dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 137dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 138dc30c35bSAndrew Lunn 139dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 140dc30c35bSAndrew Lunn } 141dc30c35bSAndrew Lunn 142294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 143dc30c35bSAndrew Lunn { 144dc30c35bSAndrew Lunn unsigned int nhandled = 0; 145dc30c35bSAndrew Lunn unsigned int sub_irq; 146dc30c35bSAndrew Lunn unsigned int n; 147dc30c35bSAndrew Lunn u16 reg; 1487c0db24cSJohn David Anglin u16 ctl1; 149dc30c35bSAndrew Lunn int err; 150dc30c35bSAndrew Lunn 151c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 15282466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 153c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 154dc30c35bSAndrew Lunn 155dc30c35bSAndrew Lunn if (err) 156dc30c35bSAndrew Lunn goto out; 157dc30c35bSAndrew Lunn 1587c0db24cSJohn David Anglin do { 159dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 160dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1617c0db24cSJohn David Anglin sub_irq = irq_find_mapping(chip->g1_irq.domain, 1627c0db24cSJohn David Anglin n); 163dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 164dc30c35bSAndrew Lunn ++nhandled; 165dc30c35bSAndrew Lunn } 166dc30c35bSAndrew Lunn } 1677c0db24cSJohn David Anglin 168c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1697c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 1707c0db24cSJohn David Anglin if (err) 1717c0db24cSJohn David Anglin goto unlock; 1727c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 1737c0db24cSJohn David Anglin unlock: 174c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1757c0db24cSJohn David Anglin if (err) 1767c0db24cSJohn David Anglin goto out; 1777c0db24cSJohn David Anglin ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 1787c0db24cSJohn David Anglin } while (reg & ctl1); 1797c0db24cSJohn David Anglin 180dc30c35bSAndrew Lunn out: 181dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 182dc30c35bSAndrew Lunn } 183dc30c35bSAndrew Lunn 184294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 185294d711eSAndrew Lunn { 186294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 187294d711eSAndrew Lunn 188294d711eSAndrew Lunn return mv88e6xxx_g1_irq_thread_work(chip); 189294d711eSAndrew Lunn } 190294d711eSAndrew Lunn 191dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 192dc30c35bSAndrew Lunn { 193dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 194dc30c35bSAndrew Lunn 195c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 196dc30c35bSAndrew Lunn } 197dc30c35bSAndrew Lunn 198dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 199dc30c35bSAndrew Lunn { 200dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 201dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 202dc30c35bSAndrew Lunn u16 reg; 203dc30c35bSAndrew Lunn int err; 204dc30c35bSAndrew Lunn 205d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 206dc30c35bSAndrew Lunn if (err) 207dc30c35bSAndrew Lunn goto out; 208dc30c35bSAndrew Lunn 209dc30c35bSAndrew Lunn reg &= ~mask; 210dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 211dc30c35bSAndrew Lunn 212d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 213dc30c35bSAndrew Lunn if (err) 214dc30c35bSAndrew Lunn goto out; 215dc30c35bSAndrew Lunn 216dc30c35bSAndrew Lunn out: 217c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 218dc30c35bSAndrew Lunn } 219dc30c35bSAndrew Lunn 2206eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = { 221dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 222dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 223dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 224dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 225dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 226dc30c35bSAndrew Lunn }; 227dc30c35bSAndrew Lunn 228dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 229dc30c35bSAndrew Lunn unsigned int irq, 230dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 231dc30c35bSAndrew Lunn { 232dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 233dc30c35bSAndrew Lunn 234dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 235dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 236dc30c35bSAndrew Lunn irq_set_noprobe(irq); 237dc30c35bSAndrew Lunn 238dc30c35bSAndrew Lunn return 0; 239dc30c35bSAndrew Lunn } 240dc30c35bSAndrew Lunn 241dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 242dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 243dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 244dc30c35bSAndrew Lunn }; 245dc30c35bSAndrew Lunn 2463d82475aSUwe Kleine-König /* To be called with reg_lock held */ 247294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 248dc30c35bSAndrew Lunn { 249dc30c35bSAndrew Lunn int irq, virq; 2503460a577SAndrew Lunn u16 mask; 2513460a577SAndrew Lunn 252d77f4321SVivien Didelot mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 2533d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 254d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2553460a577SAndrew Lunn 2565edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 257a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 258dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 259dc30c35bSAndrew Lunn } 260dc30c35bSAndrew Lunn 261a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 262dc30c35bSAndrew Lunn } 263dc30c35bSAndrew Lunn 264294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 265294d711eSAndrew Lunn { 2663d82475aSUwe Kleine-König /* 2673d82475aSUwe Kleine-König * free_irq must be called without reg_lock taken because the irq 2683d82475aSUwe Kleine-König * handler takes this lock, too. 2693d82475aSUwe Kleine-König */ 270294d711eSAndrew Lunn free_irq(chip->irq, chip); 2713d82475aSUwe Kleine-König 272c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2733d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 274c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 275294d711eSAndrew Lunn } 276294d711eSAndrew Lunn 277294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 278dc30c35bSAndrew Lunn { 2793dd0ef05SAndrew Lunn int err, irq, virq; 2803dd0ef05SAndrew Lunn u16 reg, mask; 281dc30c35bSAndrew Lunn 282dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 283dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 284dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 285dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 286dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 287dc30c35bSAndrew Lunn return -ENOMEM; 288dc30c35bSAndrew Lunn 289dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 290dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 291dc30c35bSAndrew Lunn 292dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 293dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 294dc30c35bSAndrew Lunn 295d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 296dc30c35bSAndrew Lunn if (err) 2973dd0ef05SAndrew Lunn goto out_mapping; 298dc30c35bSAndrew Lunn 2993dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 300dc30c35bSAndrew Lunn 301d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 302dc30c35bSAndrew Lunn if (err) 3033dd0ef05SAndrew Lunn goto out_disable; 304dc30c35bSAndrew Lunn 305dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 30682466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 307dc30c35bSAndrew Lunn if (err) 3083dd0ef05SAndrew Lunn goto out_disable; 309dc30c35bSAndrew Lunn 310dc30c35bSAndrew Lunn return 0; 311dc30c35bSAndrew Lunn 3123dd0ef05SAndrew Lunn out_disable: 3133d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 314d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 3153dd0ef05SAndrew Lunn 3163dd0ef05SAndrew Lunn out_mapping: 3173dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 3183dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 3193dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 3203dd0ef05SAndrew Lunn } 3213dd0ef05SAndrew Lunn 3223dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 323dc30c35bSAndrew Lunn 324dc30c35bSAndrew Lunn return err; 325dc30c35bSAndrew Lunn } 326dc30c35bSAndrew Lunn 327294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 328294d711eSAndrew Lunn { 329f6d9758bSAndrew Lunn static struct lock_class_key lock_key; 330f6d9758bSAndrew Lunn static struct lock_class_key request_key; 331294d711eSAndrew Lunn int err; 332294d711eSAndrew Lunn 333294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 334294d711eSAndrew Lunn if (err) 335294d711eSAndrew Lunn return err; 336294d711eSAndrew Lunn 337f6d9758bSAndrew Lunn /* These lock classes tells lockdep that global 1 irqs are in 338f6d9758bSAndrew Lunn * a different category than their parent GPIO, so it won't 339f6d9758bSAndrew Lunn * report false recursion. 340f6d9758bSAndrew Lunn */ 341f6d9758bSAndrew Lunn irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 342f6d9758bSAndrew Lunn 3433095383aSAndrew Lunn snprintf(chip->irq_name, sizeof(chip->irq_name), 3443095383aSAndrew Lunn "mv88e6xxx-%s", dev_name(chip->dev)); 3453095383aSAndrew Lunn 346c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 347294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 348294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 3490340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 3503095383aSAndrew Lunn chip->irq_name, chip); 351c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 352294d711eSAndrew Lunn if (err) 353294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 354294d711eSAndrew Lunn 355294d711eSAndrew Lunn return err; 356294d711eSAndrew Lunn } 357294d711eSAndrew Lunn 358294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 359294d711eSAndrew Lunn { 360294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 361294d711eSAndrew Lunn struct mv88e6xxx_chip, 362294d711eSAndrew Lunn irq_poll_work.work); 363294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 364294d711eSAndrew Lunn 365294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 366294d711eSAndrew Lunn msecs_to_jiffies(100)); 367294d711eSAndrew Lunn } 368294d711eSAndrew Lunn 369294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 370294d711eSAndrew Lunn { 371294d711eSAndrew Lunn int err; 372294d711eSAndrew Lunn 373294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 374294d711eSAndrew Lunn if (err) 375294d711eSAndrew Lunn return err; 376294d711eSAndrew Lunn 377294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 378294d711eSAndrew Lunn mv88e6xxx_irq_poll); 379294d711eSAndrew Lunn 3803f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 381294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 382294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 383294d711eSAndrew Lunn 384294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 385294d711eSAndrew Lunn msecs_to_jiffies(100)); 386294d711eSAndrew Lunn 387294d711eSAndrew Lunn return 0; 388294d711eSAndrew Lunn } 389294d711eSAndrew Lunn 390294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 391294d711eSAndrew Lunn { 392294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 393294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 3943d82475aSUwe Kleine-König 395c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3963d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 397c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 398294d711eSAndrew Lunn } 399294d711eSAndrew Lunn 40064d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, 40164d47d50SRussell King int port, phy_interface_t interface) 40264d47d50SRussell King { 40364d47d50SRussell King int err; 40464d47d50SRussell King 40564d47d50SRussell King if (chip->info->ops->port_set_rgmii_delay) { 40664d47d50SRussell King err = chip->info->ops->port_set_rgmii_delay(chip, port, 40764d47d50SRussell King interface); 40864d47d50SRussell King if (err && err != -EOPNOTSUPP) 40964d47d50SRussell King return err; 41064d47d50SRussell King } 41164d47d50SRussell King 41264d47d50SRussell King if (chip->info->ops->port_set_cmode) { 41364d47d50SRussell King err = chip->info->ops->port_set_cmode(chip, port, 41464d47d50SRussell King interface); 41564d47d50SRussell King if (err && err != -EOPNOTSUPP) 41664d47d50SRussell King return err; 41764d47d50SRussell King } 41864d47d50SRussell King 41964d47d50SRussell King return 0; 42064d47d50SRussell King } 42164d47d50SRussell King 422a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, 423a5a6858bSRussell King int link, int speed, int duplex, int pause, 424d78343d2SVivien Didelot phy_interface_t mode) 425d78343d2SVivien Didelot { 426d78343d2SVivien Didelot int err; 427d78343d2SVivien Didelot 428d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 429d78343d2SVivien Didelot return 0; 430d78343d2SVivien Didelot 431d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 43243c8e0aeSHubert Feurstein err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 433d78343d2SVivien Didelot if (err) 434d78343d2SVivien Didelot return err; 435d78343d2SVivien Didelot 436f365c6f7SRussell King if (chip->info->ops->port_set_speed_duplex) { 437f365c6f7SRussell King err = chip->info->ops->port_set_speed_duplex(chip, port, 438f365c6f7SRussell King speed, duplex); 439d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 440d78343d2SVivien Didelot goto restore_link; 441d78343d2SVivien Didelot } 442d78343d2SVivien Didelot 4437cbbee05SAndrew Lunn if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode) 4447cbbee05SAndrew Lunn mode = chip->info->ops->port_max_speed_mode(port); 4457cbbee05SAndrew Lunn 44654186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 44754186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 44854186b91SAndrew Lunn if (err) 44954186b91SAndrew Lunn goto restore_link; 45054186b91SAndrew Lunn } 45154186b91SAndrew Lunn 45264d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, mode); 453d78343d2SVivien Didelot restore_link: 454d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 455774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 456d78343d2SVivien Didelot 457d78343d2SVivien Didelot return err; 458d78343d2SVivien Didelot } 459d78343d2SVivien Didelot 460d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 461d700ec41SMarek Vasut { 462d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 463d700ec41SMarek Vasut 464d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 465d700ec41SMarek Vasut } 466d700ec41SMarek Vasut 4675d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) 4685d5b231dSRussell King { 4695d5b231dSRussell King u16 reg; 4705d5b231dSRussell King int err; 4715d5b231dSRussell King 4725d5b231dSRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4735d5b231dSRussell King if (err) { 4745d5b231dSRussell King dev_err(chip->dev, 4755d5b231dSRussell King "p%d: %s: failed to read port status\n", 4765d5b231dSRussell King port, __func__); 4775d5b231dSRussell King return err; 4785d5b231dSRussell King } 4795d5b231dSRussell King 4805d5b231dSRussell King return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT); 4815d5b231dSRussell King } 4825d5b231dSRussell King 483a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, 484a5a6858bSRussell King struct phylink_link_state *state) 485a5a6858bSRussell King { 486a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 487a5a6858bSRussell King u8 lane; 488a5a6858bSRussell King int err; 489a5a6858bSRussell King 490a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 491a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 492a5a6858bSRussell King if (lane && chip->info->ops->serdes_pcs_get_state) 493a5a6858bSRussell King err = chip->info->ops->serdes_pcs_get_state(chip, port, lane, 494a5a6858bSRussell King state); 495a5a6858bSRussell King else 496a5a6858bSRussell King err = -EOPNOTSUPP; 497a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 498a5a6858bSRussell King 499a5a6858bSRussell King return err; 500a5a6858bSRussell King } 501a5a6858bSRussell King 502a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, 503a5a6858bSRussell King unsigned int mode, 504a5a6858bSRussell King phy_interface_t interface, 505a5a6858bSRussell King const unsigned long *advertise) 506a5a6858bSRussell King { 507a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 508a5a6858bSRussell King u8 lane; 509a5a6858bSRussell King 510a5a6858bSRussell King if (ops->serdes_pcs_config) { 511a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 512a5a6858bSRussell King if (lane) 513a5a6858bSRussell King return ops->serdes_pcs_config(chip, port, lane, mode, 514a5a6858bSRussell King interface, advertise); 515a5a6858bSRussell King } 516a5a6858bSRussell King 517a5a6858bSRussell King return 0; 518a5a6858bSRussell King } 519a5a6858bSRussell King 520a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port) 521a5a6858bSRussell King { 522a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 523a5a6858bSRussell King const struct mv88e6xxx_ops *ops; 524a5a6858bSRussell King int err = 0; 525a5a6858bSRussell King u8 lane; 526a5a6858bSRussell King 527a5a6858bSRussell King ops = chip->info->ops; 528a5a6858bSRussell King 529a5a6858bSRussell King if (ops->serdes_pcs_an_restart) { 530a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 531a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 532a5a6858bSRussell King if (lane) 533a5a6858bSRussell King err = ops->serdes_pcs_an_restart(chip, port, lane); 534a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 535a5a6858bSRussell King 536a5a6858bSRussell King if (err) 537a5a6858bSRussell King dev_err(ds->dev, "p%d: failed to restart AN\n", port); 538a5a6858bSRussell King } 539a5a6858bSRussell King } 540a5a6858bSRussell King 541a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, 542a5a6858bSRussell King unsigned int mode, 543a5a6858bSRussell King int speed, int duplex) 544a5a6858bSRussell King { 545a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 546a5a6858bSRussell King u8 lane; 547a5a6858bSRussell King 548a5a6858bSRussell King if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) { 549a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 550a5a6858bSRussell King if (lane) 551a5a6858bSRussell King return ops->serdes_pcs_link_up(chip, port, lane, 552a5a6858bSRussell King speed, duplex); 553a5a6858bSRussell King } 554a5a6858bSRussell King 555a5a6858bSRussell King return 0; 556a5a6858bSRussell King } 557a5a6858bSRussell King 5586c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5596c422e34SRussell King unsigned long *mask, 5606c422e34SRussell King struct phylink_link_state *state) 5616c422e34SRussell King { 5626c422e34SRussell King if (!phy_interface_mode_is_8023z(state->interface)) { 5636c422e34SRussell King /* 10M and 100M are only supported in non-802.3z mode */ 5646c422e34SRussell King phylink_set(mask, 10baseT_Half); 5656c422e34SRussell King phylink_set(mask, 10baseT_Full); 5666c422e34SRussell King phylink_set(mask, 100baseT_Half); 5676c422e34SRussell King phylink_set(mask, 100baseT_Full); 5686c422e34SRussell King } 5696c422e34SRussell King } 5706c422e34SRussell King 5716c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5726c422e34SRussell King unsigned long *mask, 5736c422e34SRussell King struct phylink_link_state *state) 5746c422e34SRussell King { 5756c422e34SRussell King /* FIXME: if the port is in 1000Base-X mode, then it only supports 5766c422e34SRussell King * 1000M FD speeds. In this case, CMODE will indicate 5. 5776c422e34SRussell King */ 5786c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5796c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5806c422e34SRussell King 5816c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5826c422e34SRussell King } 5836c422e34SRussell King 584e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, 585e3af71a3SMarek Behún unsigned long *mask, 586e3af71a3SMarek Behún struct phylink_link_state *state) 587e3af71a3SMarek Behún { 588e3af71a3SMarek Behún if (port >= 5) 589e3af71a3SMarek Behún phylink_set(mask, 2500baseX_Full); 590e3af71a3SMarek Behún 591e3af71a3SMarek Behún /* No ethtool bits for 200Mbps */ 592e3af71a3SMarek Behún phylink_set(mask, 1000baseT_Full); 593e3af71a3SMarek Behún phylink_set(mask, 1000baseX_Full); 594e3af71a3SMarek Behún 595e3af71a3SMarek Behún mv88e6065_phylink_validate(chip, port, mask, state); 596e3af71a3SMarek Behún } 597e3af71a3SMarek Behún 5986c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5996c422e34SRussell King unsigned long *mask, 6006c422e34SRussell King struct phylink_link_state *state) 6016c422e34SRussell King { 6026c422e34SRussell King /* No ethtool bits for 200Mbps */ 6036c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6046c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6056c422e34SRussell King 6066c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6076c422e34SRussell King } 6086c422e34SRussell King 6096c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6106c422e34SRussell King unsigned long *mask, 6116c422e34SRussell King struct phylink_link_state *state) 6126c422e34SRussell King { 613ec26016bSAndrew Lunn if (port >= 9) { 6146c422e34SRussell King phylink_set(mask, 2500baseX_Full); 615ec26016bSAndrew Lunn phylink_set(mask, 2500baseT_Full); 616ec26016bSAndrew Lunn } 6176c422e34SRussell King 6186c422e34SRussell King /* No ethtool bits for 200Mbps */ 6196c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6206c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6216c422e34SRussell King 6226c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6236c422e34SRussell King } 6246c422e34SRussell King 6256c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6266c422e34SRussell King unsigned long *mask, 6276c422e34SRussell King struct phylink_link_state *state) 6286c422e34SRussell King { 6296c422e34SRussell King if (port >= 9) { 6306c422e34SRussell King phylink_set(mask, 10000baseT_Full); 6316c422e34SRussell King phylink_set(mask, 10000baseKR_Full); 6326c422e34SRussell King } 6336c422e34SRussell King 6346c422e34SRussell King mv88e6390_phylink_validate(chip, port, mask, state); 6356c422e34SRussell King } 6366c422e34SRussell King 637c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port, 638c9a2356fSRussell King unsigned long *supported, 639c9a2356fSRussell King struct phylink_link_state *state) 640c9a2356fSRussell King { 6416c422e34SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 6426c422e34SRussell King struct mv88e6xxx_chip *chip = ds->priv; 6436c422e34SRussell King 6446c422e34SRussell King /* Allow all the expected bits */ 6456c422e34SRussell King phylink_set(mask, Autoneg); 6466c422e34SRussell King phylink_set(mask, Pause); 6476c422e34SRussell King phylink_set_port_modes(mask); 6486c422e34SRussell King 6496c422e34SRussell King if (chip->info->ops->phylink_validate) 6506c422e34SRussell King chip->info->ops->phylink_validate(chip, port, mask, state); 6516c422e34SRussell King 6526c422e34SRussell King bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 6536c422e34SRussell King bitmap_and(state->advertising, state->advertising, mask, 6546c422e34SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS); 6556c422e34SRussell King 6566c422e34SRussell King /* We can only operate at 2500BaseX or 1000BaseX. If requested 6576c422e34SRussell King * to advertise both, only report advertising at 2500BaseX. 6586c422e34SRussell King */ 6596c422e34SRussell King phylink_helper_basex_speed(state); 660c9a2356fSRussell King } 661c9a2356fSRussell King 662c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 663c9a2356fSRussell King unsigned int mode, 664c9a2356fSRussell King const struct phylink_link_state *state) 665c9a2356fSRussell King { 666c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 66764d47d50SRussell King int err; 668c9a2356fSRussell King 66964d47d50SRussell King /* FIXME: is this the correct test? If we're in fixed mode on an 67064d47d50SRussell King * internal port, why should we process this any different from 67164d47d50SRussell King * PHY mode? On the other hand, the port may be automedia between 67264d47d50SRussell King * an internal PHY and the serdes... 67364d47d50SRussell King */ 674d700ec41SMarek Vasut if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) 675c9a2356fSRussell King return; 676c9a2356fSRussell King 677c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 67864d47d50SRussell King /* FIXME: should we force the link down here - but if we do, how 67964d47d50SRussell King * do we restore the link force/unforce state? The driver layering 68064d47d50SRussell King * gets in the way. 68164d47d50SRussell King */ 68264d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, state->interface); 683a5a6858bSRussell King if (err && err != -EOPNOTSUPP) 684a5a6858bSRussell King goto err_unlock; 685a5a6858bSRussell King 686a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface, 687a5a6858bSRussell King state->advertising); 688a5a6858bSRussell King /* FIXME: we should restart negotiation if something changed - which 689a5a6858bSRussell King * is something we get if we convert to using phylinks PCS operations. 690a5a6858bSRussell King */ 691a5a6858bSRussell King if (err > 0) 692a5a6858bSRussell King err = 0; 693a5a6858bSRussell King 694a5a6858bSRussell King err_unlock: 695c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 696c9a2356fSRussell King 697c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 69864d47d50SRussell King dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); 699c9a2356fSRussell King } 700c9a2356fSRussell King 701c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 702c9a2356fSRussell King unsigned int mode, 703c9a2356fSRussell King phy_interface_t interface) 704c9a2356fSRussell King { 70530c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 70630c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 70730c4a5b0SRussell King int err = 0; 70830c4a5b0SRussell King 70930c4a5b0SRussell King ops = chip->info->ops; 71030c4a5b0SRussell King 71130c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 71234b5e6a3SAndrew Lunn if ((!mv88e6xxx_port_ppu_updates(chip, port) || 71334b5e6a3SAndrew Lunn mode == MLO_AN_FIXED) && ops->port_set_link) 71430c4a5b0SRussell King err = ops->port_set_link(chip, port, LINK_FORCED_DOWN); 71530c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 71630c4a5b0SRussell King 71730c4a5b0SRussell King if (err) 71830c4a5b0SRussell King dev_err(chip->dev, 71930c4a5b0SRussell King "p%d: failed to force MAC link down\n", port); 72030c4a5b0SRussell King } 721c9a2356fSRussell King 722c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 723c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 7245b502a7bSRussell King struct phy_device *phydev, 7255b502a7bSRussell King int speed, int duplex, 7265b502a7bSRussell King bool tx_pause, bool rx_pause) 727c9a2356fSRussell King { 72830c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 72930c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 73030c4a5b0SRussell King int err = 0; 73130c4a5b0SRussell King 73230c4a5b0SRussell King ops = chip->info->ops; 73330c4a5b0SRussell King 73430c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 73534b5e6a3SAndrew Lunn if (!mv88e6xxx_port_ppu_updates(chip, port) || mode == MLO_AN_FIXED) { 73630c4a5b0SRussell King /* FIXME: for an automedia port, should we force the link 73730c4a5b0SRussell King * down here - what if the link comes up due to "other" media 73830c4a5b0SRussell King * while we're bringing the port up, how is the exclusivity 739a5a6858bSRussell King * handled in the Marvell hardware? E.g. port 2 on 88E6390 74030c4a5b0SRussell King * shared between internal PHY and Serdes. 74130c4a5b0SRussell King */ 742a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed, 743a5a6858bSRussell King duplex); 744a5a6858bSRussell King if (err) 745a5a6858bSRussell King goto error; 746a5a6858bSRussell King 747f365c6f7SRussell King if (ops->port_set_speed_duplex) { 748f365c6f7SRussell King err = ops->port_set_speed_duplex(chip, port, 749f365c6f7SRussell King speed, duplex); 75030c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 75130c4a5b0SRussell King goto error; 75230c4a5b0SRussell King } 75330c4a5b0SRussell King 75430c4a5b0SRussell King if (ops->port_set_link) 75530c4a5b0SRussell King err = ops->port_set_link(chip, port, LINK_FORCED_UP); 7565d5b231dSRussell King } 75730c4a5b0SRussell King error: 75830c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 75930c4a5b0SRussell King 76030c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 76130c4a5b0SRussell King dev_err(ds->dev, 76230c4a5b0SRussell King "p%d: failed to configure MAC link up\n", port); 76330c4a5b0SRussell King } 764c9a2356fSRussell King 765a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 766fad09c73SVivien Didelot { 767a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 768a605a0feSAndrew Lunn return -EOPNOTSUPP; 769fad09c73SVivien Didelot 770a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 771fad09c73SVivien Didelot } 772fad09c73SVivien Didelot 773fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 774dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 775dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 776dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 777dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 778dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 779dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 780dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 781dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 782dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 783dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 784dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 785dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 786dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 787dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 788dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 789dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 790dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 791dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 792dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 793dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 794dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 795dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 796dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 797dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 798dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 799dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 800dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 801dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 802dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 803dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 804dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 805dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 806dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 807dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 808dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 809dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 810dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 811dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 812dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 813dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 814dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 815dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 816dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 817dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 818dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 819dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 820dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 821dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 822dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 823dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 824dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 825dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 826dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 827dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 828dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 829dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 830dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 831dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 832dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 833fad09c73SVivien Didelot }; 834fad09c73SVivien Didelot 835fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 836fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 837e0d8b615SAndrew Lunn int port, u16 bank1_select, 838e0d8b615SAndrew Lunn u16 histogram) 839fad09c73SVivien Didelot { 840fad09c73SVivien Didelot u32 low; 841fad09c73SVivien Didelot u32 high = 0; 842dfafe449SAndrew Lunn u16 reg = 0; 8430e7b9925SAndrew Lunn int err; 844fad09c73SVivien Didelot u64 value; 845fad09c73SVivien Didelot 846fad09c73SVivien Didelot switch (s->type) { 847dfafe449SAndrew Lunn case STATS_TYPE_PORT: 8480e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 8490e7b9925SAndrew Lunn if (err) 8506c3442f5SJisheng Zhang return U64_MAX; 851fad09c73SVivien Didelot 8520e7b9925SAndrew Lunn low = reg; 853cda9f4aaSAndrew Lunn if (s->size == 4) { 8540e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 8550e7b9925SAndrew Lunn if (err) 8566c3442f5SJisheng Zhang return U64_MAX; 85784b3fd1fSRasmus Villemoes low |= ((u32)reg) << 16; 858fad09c73SVivien Didelot } 859fad09c73SVivien Didelot break; 860dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 861e0d8b615SAndrew Lunn reg = bank1_select; 862dfafe449SAndrew Lunn /* fall through */ 863dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 864e0d8b615SAndrew Lunn reg |= s->reg | histogram; 8657f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 866cda9f4aaSAndrew Lunn if (s->size == 8) 8677f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 8689fc3e4dcSGustavo A. R. Silva break; 8699fc3e4dcSGustavo A. R. Silva default: 8706c3442f5SJisheng Zhang return U64_MAX; 871fad09c73SVivien Didelot } 8726e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 873fad09c73SVivien Didelot return value; 874fad09c73SVivien Didelot } 875fad09c73SVivien Didelot 876436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 877dfafe449SAndrew Lunn uint8_t *data, int types) 878fad09c73SVivien Didelot { 879fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 880fad09c73SVivien Didelot int i, j; 881fad09c73SVivien Didelot 882fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 883fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 884dfafe449SAndrew Lunn if (stat->type & types) { 885fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 886fad09c73SVivien Didelot ETH_GSTRING_LEN); 887fad09c73SVivien Didelot j++; 888fad09c73SVivien Didelot } 889fad09c73SVivien Didelot } 890436fe17dSAndrew Lunn 891436fe17dSAndrew Lunn return j; 892fad09c73SVivien Didelot } 893fad09c73SVivien Didelot 894436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 895dfafe449SAndrew Lunn uint8_t *data) 896dfafe449SAndrew Lunn { 897436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 898dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 899dfafe449SAndrew Lunn } 900dfafe449SAndrew Lunn 9011f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 9021f71836fSRasmus Villemoes uint8_t *data) 9031f71836fSRasmus Villemoes { 9041f71836fSRasmus Villemoes return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 9051f71836fSRasmus Villemoes } 9061f71836fSRasmus Villemoes 907436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 908dfafe449SAndrew Lunn uint8_t *data) 909dfafe449SAndrew Lunn { 910436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 911dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 912dfafe449SAndrew Lunn } 913dfafe449SAndrew Lunn 91465f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 91565f60e45SAndrew Lunn "atu_member_violation", 91665f60e45SAndrew Lunn "atu_miss_violation", 91765f60e45SAndrew Lunn "atu_full_violation", 91865f60e45SAndrew Lunn "vtu_member_violation", 91965f60e45SAndrew Lunn "vtu_miss_violation", 92065f60e45SAndrew Lunn }; 92165f60e45SAndrew Lunn 92265f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 92365f60e45SAndrew Lunn { 92465f60e45SAndrew Lunn unsigned int i; 92565f60e45SAndrew Lunn 92665f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 92765f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 92865f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 92965f60e45SAndrew Lunn ETH_GSTRING_LEN); 93065f60e45SAndrew Lunn } 93165f60e45SAndrew Lunn 932dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 93389f09048SFlorian Fainelli u32 stringset, uint8_t *data) 934fad09c73SVivien Didelot { 93504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 936436fe17dSAndrew Lunn int count = 0; 937dfafe449SAndrew Lunn 93889f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 93989f09048SFlorian Fainelli return; 94089f09048SFlorian Fainelli 941c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 942c6c8cd5eSAndrew Lunn 943dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 944436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 945436fe17dSAndrew Lunn 946436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 947436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 94865f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 949436fe17dSAndrew Lunn } 950c6c8cd5eSAndrew Lunn 95165f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 95265f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 95365f60e45SAndrew Lunn 954c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 955dfafe449SAndrew Lunn } 956dfafe449SAndrew Lunn 957dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 958dfafe449SAndrew Lunn int types) 959dfafe449SAndrew Lunn { 960fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 961fad09c73SVivien Didelot int i, j; 962fad09c73SVivien Didelot 963fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 964fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 965dfafe449SAndrew Lunn if (stat->type & types) 966fad09c73SVivien Didelot j++; 967fad09c73SVivien Didelot } 968fad09c73SVivien Didelot return j; 969fad09c73SVivien Didelot } 970fad09c73SVivien Didelot 971dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 972dfafe449SAndrew Lunn { 973dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 974dfafe449SAndrew Lunn STATS_TYPE_PORT); 975dfafe449SAndrew Lunn } 976dfafe449SAndrew Lunn 9771f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 9781f71836fSRasmus Villemoes { 9791f71836fSRasmus Villemoes return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 9801f71836fSRasmus Villemoes } 9811f71836fSRasmus Villemoes 982dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 983dfafe449SAndrew Lunn { 984dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 985dfafe449SAndrew Lunn STATS_TYPE_BANK1); 986dfafe449SAndrew Lunn } 987dfafe449SAndrew Lunn 98889f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 989dfafe449SAndrew Lunn { 990dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 991436fe17dSAndrew Lunn int serdes_count = 0; 992436fe17dSAndrew Lunn int count = 0; 993dfafe449SAndrew Lunn 99489f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 99589f09048SFlorian Fainelli return 0; 99689f09048SFlorian Fainelli 997c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 998dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 999436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 1000436fe17dSAndrew Lunn if (count < 0) 1001436fe17dSAndrew Lunn goto out; 1002436fe17dSAndrew Lunn 1003436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 1004436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 1005436fe17dSAndrew Lunn port); 100665f60e45SAndrew Lunn if (serdes_count < 0) { 1007436fe17dSAndrew Lunn count = serdes_count; 100865f60e45SAndrew Lunn goto out; 100965f60e45SAndrew Lunn } 1010436fe17dSAndrew Lunn count += serdes_count; 101165f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 101265f60e45SAndrew Lunn 1013436fe17dSAndrew Lunn out: 1014c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1015dfafe449SAndrew Lunn 1016436fe17dSAndrew Lunn return count; 1017dfafe449SAndrew Lunn } 1018dfafe449SAndrew Lunn 1019436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1020e0d8b615SAndrew Lunn uint64_t *data, int types, 1021e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 1022052f947fSAndrew Lunn { 1023052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 1024052f947fSAndrew Lunn int i, j; 1025052f947fSAndrew Lunn 1026052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1027052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 1028052f947fSAndrew Lunn if (stat->type & types) { 1029c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1030e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 1031e0d8b615SAndrew Lunn bank1_select, 1032e0d8b615SAndrew Lunn histogram); 1033c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1034377cda13SAndrew Lunn 1035052f947fSAndrew Lunn j++; 1036052f947fSAndrew Lunn } 1037052f947fSAndrew Lunn } 1038436fe17dSAndrew Lunn return j; 1039052f947fSAndrew Lunn } 1040052f947fSAndrew Lunn 1041436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1042052f947fSAndrew Lunn uint64_t *data) 1043052f947fSAndrew Lunn { 1044052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1045e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 104657d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1047052f947fSAndrew Lunn } 1048052f947fSAndrew Lunn 10491f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 10501f71836fSRasmus Villemoes uint64_t *data) 10511f71836fSRasmus Villemoes { 10521f71836fSRasmus Villemoes return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 10531f71836fSRasmus Villemoes 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 10541f71836fSRasmus Villemoes } 10551f71836fSRasmus Villemoes 1056436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1057052f947fSAndrew Lunn uint64_t *data) 1058052f947fSAndrew Lunn { 1059052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1060e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 106157d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 106257d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1063e0d8b615SAndrew Lunn } 1064e0d8b615SAndrew Lunn 1065436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1066e0d8b615SAndrew Lunn uint64_t *data) 1067e0d8b615SAndrew Lunn { 1068e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1069e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 107057d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 107157d1ef38SVivien Didelot 0); 1072052f947fSAndrew Lunn } 1073052f947fSAndrew Lunn 107465f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 107565f60e45SAndrew Lunn uint64_t *data) 107665f60e45SAndrew Lunn { 107765f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 107865f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 107965f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 108065f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 108165f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 108265f60e45SAndrew Lunn } 108365f60e45SAndrew Lunn 1084052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1085052f947fSAndrew Lunn uint64_t *data) 1086052f947fSAndrew Lunn { 1087436fe17dSAndrew Lunn int count = 0; 1088436fe17dSAndrew Lunn 1089052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1090436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1091436fe17dSAndrew Lunn 1092c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1093436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1094436fe17dSAndrew Lunn data += count; 109565f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1096436fe17dSAndrew Lunn } 109765f60e45SAndrew Lunn data += count; 109865f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 1099c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1100052f947fSAndrew Lunn } 1101052f947fSAndrew Lunn 1102fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1103fad09c73SVivien Didelot uint64_t *data) 1104fad09c73SVivien Didelot { 110504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1106fad09c73SVivien Didelot int ret; 1107fad09c73SVivien Didelot 1108c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1109fad09c73SVivien Didelot 1110a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1111c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1112377cda13SAndrew Lunn 1113377cda13SAndrew Lunn if (ret < 0) 1114fad09c73SVivien Didelot return; 1115052f947fSAndrew Lunn 1116052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1117fad09c73SVivien Didelot 1118fad09c73SVivien Didelot } 1119fad09c73SVivien Didelot 1120fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1121fad09c73SVivien Didelot { 11220d30bbd0SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 11230d30bbd0SAndrew Lunn int len; 11240d30bbd0SAndrew Lunn 11250d30bbd0SAndrew Lunn len = 32 * sizeof(u16); 11260d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs_len) 11270d30bbd0SAndrew Lunn len += chip->info->ops->serdes_get_regs_len(chip, port); 11280d30bbd0SAndrew Lunn 11290d30bbd0SAndrew Lunn return len; 1130fad09c73SVivien Didelot } 1131fad09c73SVivien Didelot 1132fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1133fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1134fad09c73SVivien Didelot { 113504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 11360e7b9925SAndrew Lunn int err; 11370e7b9925SAndrew Lunn u16 reg; 1138fad09c73SVivien Didelot u16 *p = _p; 1139fad09c73SVivien Didelot int i; 1140fad09c73SVivien Didelot 1141a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1142fad09c73SVivien Didelot 1143fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1144fad09c73SVivien Didelot 1145c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1146fad09c73SVivien Didelot 1147fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1148fad09c73SVivien Didelot 11490e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 11500e7b9925SAndrew Lunn if (!err) 11510e7b9925SAndrew Lunn p[i] = reg; 1152fad09c73SVivien Didelot } 1153fad09c73SVivien Didelot 11540d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs) 11550d30bbd0SAndrew Lunn chip->info->ops->serdes_get_regs(chip, port, &p[i]); 11560d30bbd0SAndrew Lunn 1157c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1158fad09c73SVivien Didelot } 1159fad09c73SVivien Didelot 116008f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1161fad09c73SVivien Didelot struct ethtool_eee *e) 1162fad09c73SVivien Didelot { 11635480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11645480db69SVivien Didelot return 0; 1165fad09c73SVivien Didelot } 1166fad09c73SVivien Didelot 116708f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 116846587e4aSVivien Didelot struct ethtool_eee *e) 1169fad09c73SVivien Didelot { 11705480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11715480db69SVivien Didelot return 0; 1172fad09c73SVivien Didelot } 1173fad09c73SVivien Didelot 11749dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */ 1175e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1176fad09c73SVivien Didelot { 11779dc8b13eSVivien Didelot struct dsa_switch *ds = chip->ds; 11789dc8b13eSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 1179e5887a2aSVivien Didelot struct net_device *br; 11809dc8b13eSVivien Didelot struct dsa_port *dp; 11819dc8b13eSVivien Didelot bool found = false; 1182e5887a2aSVivien Didelot u16 pvlan; 1183fad09c73SVivien Didelot 11849dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 11859dc8b13eSVivien Didelot if (dp->ds->index == dev && dp->index == port) { 11869dc8b13eSVivien Didelot found = true; 11879dc8b13eSVivien Didelot break; 11889dc8b13eSVivien Didelot } 11899dc8b13eSVivien Didelot } 1190fad09c73SVivien Didelot 1191e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 11929dc8b13eSVivien Didelot if (!found) 1193e5887a2aSVivien Didelot return 0; 1194e5887a2aSVivien Didelot 1195e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 11969dc8b13eSVivien Didelot if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) 1197e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1198e5887a2aSVivien Didelot 11999dc8b13eSVivien Didelot br = dp->bridge_dev; 1200e5887a2aSVivien Didelot pvlan = 0; 1201e5887a2aSVivien Didelot 1202e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 1203e5887a2aSVivien Didelot * as well as any local member of their bridge group. 1204e5887a2aSVivien Didelot */ 12059dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) 12069dc8b13eSVivien Didelot if (dp->ds == ds && 12079dc8b13eSVivien Didelot (dp->type == DSA_PORT_TYPE_CPU || 12089dc8b13eSVivien Didelot dp->type == DSA_PORT_TYPE_DSA || 12099dc8b13eSVivien Didelot (br && dp->bridge_dev == br))) 12109dc8b13eSVivien Didelot pvlan |= BIT(dp->index); 1211e5887a2aSVivien Didelot 1212e5887a2aSVivien Didelot return pvlan; 1213fad09c73SVivien Didelot } 1214e5887a2aSVivien Didelot 1215240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1216e5887a2aSVivien Didelot { 1217e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1218fad09c73SVivien Didelot 1219fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1220fad09c73SVivien Didelot output_ports &= ~BIT(port); 1221fad09c73SVivien Didelot 12225a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1223fad09c73SVivien Didelot } 1224fad09c73SVivien Didelot 1225fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1226fad09c73SVivien Didelot u8 state) 1227fad09c73SVivien Didelot { 122804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1229fad09c73SVivien Didelot int err; 1230fad09c73SVivien Didelot 1231c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1232f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1233c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1234fad09c73SVivien Didelot 1235fad09c73SVivien Didelot if (err) 1236774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1237fad09c73SVivien Didelot } 1238fad09c73SVivien Didelot 123993e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 124093e18d61SVivien Didelot { 124193e18d61SVivien Didelot int err; 124293e18d61SVivien Didelot 124393e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 124493e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 124593e18d61SVivien Didelot if (err) 124693e18d61SVivien Didelot return err; 124793e18d61SVivien Didelot } 124893e18d61SVivien Didelot 124993e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 125093e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 125193e18d61SVivien Didelot if (err) 125293e18d61SVivien Didelot return err; 125393e18d61SVivien Didelot } 125493e18d61SVivien Didelot 125593e18d61SVivien Didelot return 0; 125693e18d61SVivien Didelot } 125793e18d61SVivien Didelot 1258c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1259c7f047b6SVivien Didelot { 1260c5f51765SVivien Didelot struct dsa_switch *ds = chip->ds; 1261c7f047b6SVivien Didelot int target, port; 1262c7f047b6SVivien Didelot int err; 1263c7f047b6SVivien Didelot 1264c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1265c7f047b6SVivien Didelot return 0; 1266c7f047b6SVivien Didelot 1267c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1268c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1269c5f51765SVivien Didelot port = dsa_routing_port(ds, target); 1270c5f51765SVivien Didelot if (port == ds->num_ports) 1271c7f047b6SVivien Didelot port = 0x1f; 1272c7f047b6SVivien Didelot 1273c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1274c7f047b6SVivien Didelot if (err) 1275c7f047b6SVivien Didelot return err; 1276c7f047b6SVivien Didelot } 1277c7f047b6SVivien Didelot 127802317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 127902317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 128002317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 128102317e68SVivien Didelot if (err) 128202317e68SVivien Didelot return err; 128302317e68SVivien Didelot } 128402317e68SVivien Didelot 128523c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 128623c98919SVivien Didelot if (err) 128723c98919SVivien Didelot return err; 128823c98919SVivien Didelot 1289c7f047b6SVivien Didelot return 0; 1290c7f047b6SVivien Didelot } 1291c7f047b6SVivien Didelot 1292b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1293b28f872dSVivien Didelot { 1294b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1295b28f872dSVivien Didelot if (chip->info->global2_addr) 1296b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1297b28f872dSVivien Didelot 1298b28f872dSVivien Didelot return 0; 1299b28f872dSVivien Didelot } 1300b28f872dSVivien Didelot 13019e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 13029e5baf9bSVivien Didelot { 13039e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 13049e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 13059e5baf9bSVivien Didelot 13069e5baf9bSVivien Didelot return 0; 13079e5baf9bSVivien Didelot } 13089e5baf9bSVivien Didelot 13099e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 13109e907d73SVivien Didelot { 13119e907d73SVivien Didelot if (chip->info->ops->pot_clear) 13129e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 13139e907d73SVivien Didelot 13149e907d73SVivien Didelot return 0; 13159e907d73SVivien Didelot } 13169e907d73SVivien Didelot 131751c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 131851c901a7SVivien Didelot { 131951c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 132051c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 132151c901a7SVivien Didelot 132251c901a7SVivien Didelot return 0; 132351c901a7SVivien Didelot } 132451c901a7SVivien Didelot 1325a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1326a2ac29d2SVivien Didelot { 1327c3a7d4adSVivien Didelot int err; 1328c3a7d4adSVivien Didelot 1329daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1330daefc943SVivien Didelot if (err) 1331daefc943SVivien Didelot return err; 1332daefc943SVivien Didelot 1333c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1334c3a7d4adSVivien Didelot if (err) 1335c3a7d4adSVivien Didelot return err; 1336c3a7d4adSVivien Didelot 1337a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1338a2ac29d2SVivien Didelot } 1339a2ac29d2SVivien Didelot 1340cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1341cd8da8bbSVivien Didelot { 1342cd8da8bbSVivien Didelot int port; 1343cd8da8bbSVivien Didelot int err; 1344cd8da8bbSVivien Didelot 1345cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1346cd8da8bbSVivien Didelot return 0; 1347cd8da8bbSVivien Didelot 1348cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1349cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1350cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1351cd8da8bbSVivien Didelot */ 1352cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1353cd8da8bbSVivien Didelot if (err) 1354cd8da8bbSVivien Didelot return err; 1355cd8da8bbSVivien Didelot } 1356cd8da8bbSVivien Didelot 1357cd8da8bbSVivien Didelot return 0; 1358cd8da8bbSVivien Didelot } 1359cd8da8bbSVivien Didelot 136004a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 136104a69a17SVivien Didelot { 136204a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 136304a69a17SVivien Didelot u8 addr[ETH_ALEN]; 136404a69a17SVivien Didelot 136504a69a17SVivien Didelot eth_random_addr(addr); 136604a69a17SVivien Didelot 136704a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 136804a69a17SVivien Didelot } 136904a69a17SVivien Didelot 137004a69a17SVivien Didelot return 0; 137104a69a17SVivien Didelot } 137204a69a17SVivien Didelot 137317a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 137417a1594eSVivien Didelot { 137517a1594eSVivien Didelot u16 pvlan = 0; 137617a1594eSVivien Didelot 137717a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1378d14939beSVivien Didelot return 0; 137917a1594eSVivien Didelot 138017a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 138117a1594eSVivien Didelot if (dev != chip->ds->index) 1382aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 138317a1594eSVivien Didelot 138417a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 138517a1594eSVivien Didelot } 138617a1594eSVivien Didelot 138781228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 138881228996SVivien Didelot { 138917a1594eSVivien Didelot int dev, port; 139017a1594eSVivien Didelot int err; 139117a1594eSVivien Didelot 139281228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 139381228996SVivien Didelot return 0; 139481228996SVivien Didelot 139581228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 139681228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 139781228996SVivien Didelot */ 139817a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 139917a1594eSVivien Didelot if (err) 140017a1594eSVivien Didelot return err; 140117a1594eSVivien Didelot 140217a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 140317a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 140417a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 140517a1594eSVivien Didelot if (err) 140617a1594eSVivien Didelot return err; 140717a1594eSVivien Didelot } 140817a1594eSVivien Didelot } 140917a1594eSVivien Didelot 141017a1594eSVivien Didelot return 0; 141181228996SVivien Didelot } 141281228996SVivien Didelot 1413749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1414749efcb8SVivien Didelot { 1415749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1416749efcb8SVivien Didelot int err; 1417749efcb8SVivien Didelot 1418c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1419e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1420c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1421749efcb8SVivien Didelot 1422749efcb8SVivien Didelot if (err) 1423774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 1424749efcb8SVivien Didelot } 1425749efcb8SVivien Didelot 1426b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1427b486d7c9SVivien Didelot { 1428b486d7c9SVivien Didelot if (!chip->info->max_vid) 1429b486d7c9SVivien Didelot return 0; 1430b486d7c9SVivien Didelot 1431b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1432b486d7c9SVivien Didelot } 1433b486d7c9SVivien Didelot 1434f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1435f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1436f1394b78SVivien Didelot { 1437f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1438f1394b78SVivien Didelot return -EOPNOTSUPP; 1439f1394b78SVivien Didelot 1440f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1441f1394b78SVivien Didelot } 1442f1394b78SVivien Didelot 14430ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 14440ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 14450ad5daf6SVivien Didelot { 14460ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 14470ad5daf6SVivien Didelot return -EOPNOTSUPP; 14480ad5daf6SVivien Didelot 14490ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 14500ad5daf6SVivien Didelot } 14510ad5daf6SVivien Didelot 1452d7f435f9SVivien Didelot static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 1453fad09c73SVivien Didelot { 1454fad09c73SVivien Didelot DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 1455425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1456fad09c73SVivien Didelot int i, err; 1457fad09c73SVivien Didelot 1458fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1459fad09c73SVivien Didelot 1460fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1461370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1462b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, i, fid); 1463fad09c73SVivien Didelot if (err) 1464fad09c73SVivien Didelot return err; 1465fad09c73SVivien Didelot 1466fad09c73SVivien Didelot set_bit(*fid, fid_bitmap); 1467fad09c73SVivien Didelot } 1468fad09c73SVivien Didelot 1469fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1470425d2d37SVivien Didelot vlan.vid = chip->info->max_vid; 1471425d2d37SVivien Didelot vlan.valid = false; 1472425d2d37SVivien Didelot 1473fad09c73SVivien Didelot do { 1474f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1475fad09c73SVivien Didelot if (err) 1476fad09c73SVivien Didelot return err; 1477fad09c73SVivien Didelot 1478fad09c73SVivien Didelot if (!vlan.valid) 1479fad09c73SVivien Didelot break; 1480fad09c73SVivien Didelot 1481fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 14823cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1483fad09c73SVivien Didelot 1484fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1485fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1486fad09c73SVivien Didelot */ 1487fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1488fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1489fad09c73SVivien Didelot return -ENOSPC; 1490fad09c73SVivien Didelot 1491fad09c73SVivien Didelot /* Clear the database */ 1492daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1493fad09c73SVivien Didelot } 1494fad09c73SVivien Didelot 149523e8b470SAndrew Lunn static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) 149623e8b470SAndrew Lunn { 149723e8b470SAndrew Lunn if (chip->info->ops->atu_get_hash) 149823e8b470SAndrew Lunn return chip->info->ops->atu_get_hash(chip, hash); 149923e8b470SAndrew Lunn 150023e8b470SAndrew Lunn return -EOPNOTSUPP; 150123e8b470SAndrew Lunn } 150223e8b470SAndrew Lunn 150323e8b470SAndrew Lunn static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) 150423e8b470SAndrew Lunn { 150523e8b470SAndrew Lunn if (chip->info->ops->atu_set_hash) 150623e8b470SAndrew Lunn return chip->info->ops->atu_set_hash(chip, hash); 150723e8b470SAndrew Lunn 150823e8b470SAndrew Lunn return -EOPNOTSUPP; 150923e8b470SAndrew Lunn } 151023e8b470SAndrew Lunn 1511fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1512fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1513fad09c73SVivien Didelot { 151404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1515425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1516fad09c73SVivien Didelot int i, err; 1517fad09c73SVivien Didelot 1518db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 1519db06ae41SAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 1520db06ae41SAndrew Lunn return 0; 1521db06ae41SAndrew Lunn 1522fad09c73SVivien Didelot if (!vid_begin) 1523fad09c73SVivien Didelot return -EOPNOTSUPP; 1524fad09c73SVivien Didelot 1525425d2d37SVivien Didelot vlan.vid = vid_begin - 1; 1526425d2d37SVivien Didelot vlan.valid = false; 1527425d2d37SVivien Didelot 1528fad09c73SVivien Didelot do { 1529f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1530fad09c73SVivien Didelot if (err) 15317095a4c4SVivien Didelot return err; 1532fad09c73SVivien Didelot 1533fad09c73SVivien Didelot if (!vlan.valid) 1534fad09c73SVivien Didelot break; 1535fad09c73SVivien Didelot 1536fad09c73SVivien Didelot if (vlan.vid > vid_end) 1537fad09c73SVivien Didelot break; 1538fad09c73SVivien Didelot 1539370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1540fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1541fad09c73SVivien Didelot continue; 1542fad09c73SVivien Didelot 154368bb8ea8SVivien Didelot if (!dsa_to_port(ds, i)->slave) 154466e2809dSAndrew Lunn continue; 154566e2809dSAndrew Lunn 1546bd00e053SVivien Didelot if (vlan.member[i] == 15477ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1548fad09c73SVivien Didelot continue; 1549fad09c73SVivien Didelot 1550c8652c83SVivien Didelot if (dsa_to_port(ds, i)->bridge_dev == 155168bb8ea8SVivien Didelot dsa_to_port(ds, port)->bridge_dev) 1552fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1553fad09c73SVivien Didelot 1554c8652c83SVivien Didelot if (!dsa_to_port(ds, i)->bridge_dev) 155566e2809dSAndrew Lunn continue; 155666e2809dSAndrew Lunn 1557743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 1558743fcc28SAndrew Lunn port, vlan.vid, i, 1559c8652c83SVivien Didelot netdev_name(dsa_to_port(ds, i)->bridge_dev)); 15607095a4c4SVivien Didelot return -EOPNOTSUPP; 1561fad09c73SVivien Didelot } 1562fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1563fad09c73SVivien Didelot 15647095a4c4SVivien Didelot return 0; 1565fad09c73SVivien Didelot } 1566fad09c73SVivien Didelot 1567fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1568fad09c73SVivien Didelot bool vlan_filtering) 1569fad09c73SVivien Didelot { 157004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 157181c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 157281c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 15730e7b9925SAndrew Lunn int err; 1574fad09c73SVivien Didelot 15753cf3c846SVivien Didelot if (!chip->info->max_vid) 1576fad09c73SVivien Didelot return -EOPNOTSUPP; 1577fad09c73SVivien Didelot 1578c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1579385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1580c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1581fad09c73SVivien Didelot 15820e7b9925SAndrew Lunn return err; 1583fad09c73SVivien Didelot } 1584fad09c73SVivien Didelot 1585fad09c73SVivien Didelot static int 1586fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 158780e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1588fad09c73SVivien Didelot { 158904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1590fad09c73SVivien Didelot int err; 1591fad09c73SVivien Didelot 15923cf3c846SVivien Didelot if (!chip->info->max_vid) 1593fad09c73SVivien Didelot return -EOPNOTSUPP; 1594fad09c73SVivien Didelot 1595fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1596fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1597fad09c73SVivien Didelot */ 15987095a4c4SVivien Didelot mv88e6xxx_reg_lock(chip); 1599fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1600fad09c73SVivien Didelot vlan->vid_end); 16017095a4c4SVivien Didelot mv88e6xxx_reg_unlock(chip); 1602fad09c73SVivien Didelot 1603fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1604fad09c73SVivien Didelot * so skip the prepare phase. 1605fad09c73SVivien Didelot */ 16067095a4c4SVivien Didelot return err; 1607fad09c73SVivien Didelot } 1608fad09c73SVivien Didelot 1609a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1610a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 1611a4c93ae1SAndrew Lunn u8 state) 1612a4c93ae1SAndrew Lunn { 1613a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 16145ef8d249SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 16155ef8d249SVivien Didelot u16 fid; 1616a4c93ae1SAndrew Lunn int err; 1617a4c93ae1SAndrew Lunn 1618a4c93ae1SAndrew Lunn /* Null VLAN ID corresponds to the port private database */ 16195ef8d249SVivien Didelot if (vid == 0) { 16205ef8d249SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 1621a4c93ae1SAndrew Lunn if (err) 1622a4c93ae1SAndrew Lunn return err; 16235ef8d249SVivien Didelot } else { 16245ef8d249SVivien Didelot vlan.vid = vid - 1; 16255ef8d249SVivien Didelot vlan.valid = false; 16265ef8d249SVivien Didelot 16275ef8d249SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 16285ef8d249SVivien Didelot if (err) 16295ef8d249SVivien Didelot return err; 16305ef8d249SVivien Didelot 16315ef8d249SVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 16325ef8d249SVivien Didelot if (vlan.vid != vid || !vlan.valid) 16335ef8d249SVivien Didelot return -EOPNOTSUPP; 16345ef8d249SVivien Didelot 16355ef8d249SVivien Didelot fid = vlan.fid; 16365ef8d249SVivien Didelot } 1637a4c93ae1SAndrew Lunn 1638d8291a95SVivien Didelot entry.state = 0; 1639a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1640a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 1641a4c93ae1SAndrew Lunn 16425ef8d249SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry); 1643a4c93ae1SAndrew Lunn if (err) 1644a4c93ae1SAndrew Lunn return err; 1645a4c93ae1SAndrew Lunn 1646a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 1647d8291a95SVivien Didelot if (!entry.state || !ether_addr_equal(entry.mac, addr)) { 1648a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 1649a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1650a4c93ae1SAndrew Lunn } 1651a4c93ae1SAndrew Lunn 1652a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 1653d8291a95SVivien Didelot if (!state) { 1654a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 1655a4c93ae1SAndrew Lunn if (!entry.portvec) 1656d8291a95SVivien Didelot entry.state = 0; 1657a4c93ae1SAndrew Lunn } else { 1658a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 1659a4c93ae1SAndrew Lunn entry.state = state; 1660a4c93ae1SAndrew Lunn } 1661a4c93ae1SAndrew Lunn 16625ef8d249SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry); 1663a4c93ae1SAndrew Lunn } 1664a4c93ae1SAndrew Lunn 1665da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port, 1666da7dc875SVivien Didelot const struct mv88e6xxx_policy *policy) 1667da7dc875SVivien Didelot { 1668da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping = policy->mapping; 1669da7dc875SVivien Didelot enum mv88e6xxx_policy_action action = policy->action; 1670da7dc875SVivien Didelot const u8 *addr = policy->addr; 1671da7dc875SVivien Didelot u16 vid = policy->vid; 1672da7dc875SVivien Didelot u8 state; 1673da7dc875SVivien Didelot int err; 1674da7dc875SVivien Didelot int id; 1675da7dc875SVivien Didelot 1676da7dc875SVivien Didelot if (!chip->info->ops->port_set_policy) 1677da7dc875SVivien Didelot return -EOPNOTSUPP; 1678da7dc875SVivien Didelot 1679da7dc875SVivien Didelot switch (mapping) { 1680da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_DA: 1681da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_SA: 1682da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1683da7dc875SVivien Didelot state = 0; /* Dissociate the port and address */ 1684da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1685da7dc875SVivien Didelot is_multicast_ether_addr(addr)) 1686da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY; 1687da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1688da7dc875SVivien Didelot is_unicast_ether_addr(addr)) 1689da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY; 1690da7dc875SVivien Didelot else 1691da7dc875SVivien Didelot return -EOPNOTSUPP; 1692da7dc875SVivien Didelot 1693da7dc875SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 1694da7dc875SVivien Didelot state); 1695da7dc875SVivien Didelot if (err) 1696da7dc875SVivien Didelot return err; 1697da7dc875SVivien Didelot break; 1698da7dc875SVivien Didelot default: 1699da7dc875SVivien Didelot return -EOPNOTSUPP; 1700da7dc875SVivien Didelot } 1701da7dc875SVivien Didelot 1702da7dc875SVivien Didelot /* Skip the port's policy clearing if the mapping is still in use */ 1703da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1704da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1705da7dc875SVivien Didelot if (policy->port == port && 1706da7dc875SVivien Didelot policy->mapping == mapping && 1707da7dc875SVivien Didelot policy->action != action) 1708da7dc875SVivien Didelot return 0; 1709da7dc875SVivien Didelot 1710da7dc875SVivien Didelot return chip->info->ops->port_set_policy(chip, port, mapping, action); 1711da7dc875SVivien Didelot } 1712da7dc875SVivien Didelot 1713da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port, 1714da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs) 1715da7dc875SVivien Didelot { 1716da7dc875SVivien Didelot struct ethhdr *mac_entry = &fs->h_u.ether_spec; 1717da7dc875SVivien Didelot struct ethhdr *mac_mask = &fs->m_u.ether_spec; 1718da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping; 1719da7dc875SVivien Didelot enum mv88e6xxx_policy_action action; 1720da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1721da7dc875SVivien Didelot u16 vid = 0; 1722da7dc875SVivien Didelot u8 *addr; 1723da7dc875SVivien Didelot int err; 1724da7dc875SVivien Didelot int id; 1725da7dc875SVivien Didelot 1726da7dc875SVivien Didelot if (fs->location != RX_CLS_LOC_ANY) 1727da7dc875SVivien Didelot return -EINVAL; 1728da7dc875SVivien Didelot 1729da7dc875SVivien Didelot if (fs->ring_cookie == RX_CLS_FLOW_DISC) 1730da7dc875SVivien Didelot action = MV88E6XXX_POLICY_ACTION_DISCARD; 1731da7dc875SVivien Didelot else 1732da7dc875SVivien Didelot return -EOPNOTSUPP; 1733da7dc875SVivien Didelot 1734da7dc875SVivien Didelot switch (fs->flow_type & ~FLOW_EXT) { 1735da7dc875SVivien Didelot case ETHER_FLOW: 1736da7dc875SVivien Didelot if (!is_zero_ether_addr(mac_mask->h_dest) && 1737da7dc875SVivien Didelot is_zero_ether_addr(mac_mask->h_source)) { 1738da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_DA; 1739da7dc875SVivien Didelot addr = mac_entry->h_dest; 1740da7dc875SVivien Didelot } else if (is_zero_ether_addr(mac_mask->h_dest) && 1741da7dc875SVivien Didelot !is_zero_ether_addr(mac_mask->h_source)) { 1742da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_SA; 1743da7dc875SVivien Didelot addr = mac_entry->h_source; 1744da7dc875SVivien Didelot } else { 1745da7dc875SVivien Didelot /* Cannot support DA and SA mapping in the same rule */ 1746da7dc875SVivien Didelot return -EOPNOTSUPP; 1747da7dc875SVivien Didelot } 1748da7dc875SVivien Didelot break; 1749da7dc875SVivien Didelot default: 1750da7dc875SVivien Didelot return -EOPNOTSUPP; 1751da7dc875SVivien Didelot } 1752da7dc875SVivien Didelot 1753da7dc875SVivien Didelot if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) { 1754da7dc875SVivien Didelot if (fs->m_ext.vlan_tci != 0xffff) 1755da7dc875SVivien Didelot return -EOPNOTSUPP; 1756da7dc875SVivien Didelot vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; 1757da7dc875SVivien Didelot } 1758da7dc875SVivien Didelot 1759da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) { 1760da7dc875SVivien Didelot if (policy->port == port && policy->mapping == mapping && 1761da7dc875SVivien Didelot policy->action == action && policy->vid == vid && 1762da7dc875SVivien Didelot ether_addr_equal(policy->addr, addr)) 1763da7dc875SVivien Didelot return -EEXIST; 1764da7dc875SVivien Didelot } 1765da7dc875SVivien Didelot 1766da7dc875SVivien Didelot policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL); 1767da7dc875SVivien Didelot if (!policy) 1768da7dc875SVivien Didelot return -ENOMEM; 1769da7dc875SVivien Didelot 1770da7dc875SVivien Didelot fs->location = 0; 1771da7dc875SVivien Didelot err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff, 1772da7dc875SVivien Didelot GFP_KERNEL); 1773da7dc875SVivien Didelot if (err) { 1774da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1775da7dc875SVivien Didelot return err; 1776da7dc875SVivien Didelot } 1777da7dc875SVivien Didelot 1778da7dc875SVivien Didelot memcpy(&policy->fs, fs, sizeof(*fs)); 1779da7dc875SVivien Didelot ether_addr_copy(policy->addr, addr); 1780da7dc875SVivien Didelot policy->mapping = mapping; 1781da7dc875SVivien Didelot policy->action = action; 1782da7dc875SVivien Didelot policy->port = port; 1783da7dc875SVivien Didelot policy->vid = vid; 1784da7dc875SVivien Didelot 1785da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1786da7dc875SVivien Didelot if (err) { 1787da7dc875SVivien Didelot idr_remove(&chip->policies, fs->location); 1788da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1789da7dc875SVivien Didelot return err; 1790da7dc875SVivien Didelot } 1791da7dc875SVivien Didelot 1792da7dc875SVivien Didelot return 0; 1793da7dc875SVivien Didelot } 1794da7dc875SVivien Didelot 1795da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, 1796da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 1797da7dc875SVivien Didelot { 1798da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1799da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1800da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1801da7dc875SVivien Didelot int err; 1802da7dc875SVivien Didelot int id; 1803da7dc875SVivien Didelot 1804da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1805da7dc875SVivien Didelot 1806da7dc875SVivien Didelot switch (rxnfc->cmd) { 1807da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLCNT: 1808da7dc875SVivien Didelot rxnfc->data = 0; 1809da7dc875SVivien Didelot rxnfc->data |= RX_CLS_LOC_SPECIAL; 1810da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1811da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1812da7dc875SVivien Didelot if (policy->port == port) 1813da7dc875SVivien Didelot rxnfc->rule_cnt++; 1814da7dc875SVivien Didelot err = 0; 1815da7dc875SVivien Didelot break; 1816da7dc875SVivien Didelot case ETHTOOL_GRXCLSRULE: 1817da7dc875SVivien Didelot err = -ENOENT; 1818da7dc875SVivien Didelot policy = idr_find(&chip->policies, fs->location); 1819da7dc875SVivien Didelot if (policy) { 1820da7dc875SVivien Didelot memcpy(fs, &policy->fs, sizeof(*fs)); 1821da7dc875SVivien Didelot err = 0; 1822da7dc875SVivien Didelot } 1823da7dc875SVivien Didelot break; 1824da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLALL: 1825da7dc875SVivien Didelot rxnfc->data = 0; 1826da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1827da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1828da7dc875SVivien Didelot if (policy->port == port) 1829da7dc875SVivien Didelot rule_locs[rxnfc->rule_cnt++] = id; 1830da7dc875SVivien Didelot err = 0; 1831da7dc875SVivien Didelot break; 1832da7dc875SVivien Didelot default: 1833da7dc875SVivien Didelot err = -EOPNOTSUPP; 1834da7dc875SVivien Didelot break; 1835da7dc875SVivien Didelot } 1836da7dc875SVivien Didelot 1837da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1838da7dc875SVivien Didelot 1839da7dc875SVivien Didelot return err; 1840da7dc875SVivien Didelot } 1841da7dc875SVivien Didelot 1842da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, 1843da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc) 1844da7dc875SVivien Didelot { 1845da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1846da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1847da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1848da7dc875SVivien Didelot int err; 1849da7dc875SVivien Didelot 1850da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1851da7dc875SVivien Didelot 1852da7dc875SVivien Didelot switch (rxnfc->cmd) { 1853da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLINS: 1854da7dc875SVivien Didelot err = mv88e6xxx_policy_insert(chip, port, fs); 1855da7dc875SVivien Didelot break; 1856da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLDEL: 1857da7dc875SVivien Didelot err = -ENOENT; 1858da7dc875SVivien Didelot policy = idr_remove(&chip->policies, fs->location); 1859da7dc875SVivien Didelot if (policy) { 1860da7dc875SVivien Didelot policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; 1861da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1862da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1863da7dc875SVivien Didelot } 1864da7dc875SVivien Didelot break; 1865da7dc875SVivien Didelot default: 1866da7dc875SVivien Didelot err = -EOPNOTSUPP; 1867da7dc875SVivien Didelot break; 1868da7dc875SVivien Didelot } 1869da7dc875SVivien Didelot 1870da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1871da7dc875SVivien Didelot 1872da7dc875SVivien Didelot return err; 1873da7dc875SVivien Didelot } 1874da7dc875SVivien Didelot 187587fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 187687fa886eSAndrew Lunn u16 vid) 187787fa886eSAndrew Lunn { 187887fa886eSAndrew Lunn const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 187987fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 188087fa886eSAndrew Lunn 188187fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 188287fa886eSAndrew Lunn } 188387fa886eSAndrew Lunn 188487fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 188587fa886eSAndrew Lunn { 188687fa886eSAndrew Lunn int port; 188787fa886eSAndrew Lunn int err; 188887fa886eSAndrew Lunn 188987fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 189087fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 189187fa886eSAndrew Lunn if (err) 189287fa886eSAndrew Lunn return err; 189387fa886eSAndrew Lunn } 189487fa886eSAndrew Lunn 189587fa886eSAndrew Lunn return 0; 189687fa886eSAndrew Lunn } 189787fa886eSAndrew Lunn 1898b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, 1899933b4425SRussell King u16 vid, u8 member, bool warn) 1900fad09c73SVivien Didelot { 1901b1ac6fb4SVivien Didelot const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1902b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1903b1ac6fb4SVivien Didelot int i, err; 1904fad09c73SVivien Didelot 1905b1ac6fb4SVivien Didelot if (!vid) 1906b1ac6fb4SVivien Didelot return -EOPNOTSUPP; 1907b1ac6fb4SVivien Didelot 1908b1ac6fb4SVivien Didelot vlan.vid = vid - 1; 1909b1ac6fb4SVivien Didelot vlan.valid = false; 1910b1ac6fb4SVivien Didelot 1911b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1912fad09c73SVivien Didelot if (err) 1913fad09c73SVivien Didelot return err; 1914fad09c73SVivien Didelot 1915b1ac6fb4SVivien Didelot if (vlan.vid != vid || !vlan.valid) { 1916b1ac6fb4SVivien Didelot memset(&vlan, 0, sizeof(vlan)); 1917b1ac6fb4SVivien Didelot 1918b1ac6fb4SVivien Didelot err = mv88e6xxx_atu_new(chip, &vlan.fid); 1919b1ac6fb4SVivien Didelot if (err) 1920b1ac6fb4SVivien Didelot return err; 1921b1ac6fb4SVivien Didelot 1922b1ac6fb4SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1923b1ac6fb4SVivien Didelot if (i == port) 1924b1ac6fb4SVivien Didelot vlan.member[i] = member; 1925b1ac6fb4SVivien Didelot else 1926b1ac6fb4SVivien Didelot vlan.member[i] = non_member; 1927b1ac6fb4SVivien Didelot 1928b1ac6fb4SVivien Didelot vlan.vid = vid; 19291cb9dfcaSRasmus Villemoes vlan.valid = true; 1930fad09c73SVivien Didelot 193187fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 193287fa886eSAndrew Lunn if (err) 193387fa886eSAndrew Lunn return err; 193487fa886eSAndrew Lunn 1935b1ac6fb4SVivien Didelot err = mv88e6xxx_broadcast_setup(chip, vlan.vid); 1936b1ac6fb4SVivien Didelot if (err) 1937b1ac6fb4SVivien Didelot return err; 1938b1ac6fb4SVivien Didelot } else if (vlan.member[port] != member) { 1939b1ac6fb4SVivien Didelot vlan.member[port] = member; 1940b1ac6fb4SVivien Didelot 1941b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1942b1ac6fb4SVivien Didelot if (err) 1943b1ac6fb4SVivien Didelot return err; 1944933b4425SRussell King } else if (warn) { 1945b1ac6fb4SVivien Didelot dev_info(chip->dev, "p%d: already a member of VLAN %d\n", 1946b1ac6fb4SVivien Didelot port, vid); 1947b1ac6fb4SVivien Didelot } 1948b1ac6fb4SVivien Didelot 1949b1ac6fb4SVivien Didelot return 0; 1950fad09c73SVivien Didelot } 1951fad09c73SVivien Didelot 1952fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 195380e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1954fad09c73SVivien Didelot { 195504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1956fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1957fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1958933b4425SRussell King bool warn; 1959c91498e1SVivien Didelot u8 member; 1960fad09c73SVivien Didelot u16 vid; 1961fad09c73SVivien Didelot 19623cf3c846SVivien Didelot if (!chip->info->max_vid) 1963fad09c73SVivien Didelot return; 1964fad09c73SVivien Didelot 1965c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 19667ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1967c91498e1SVivien Didelot else if (untagged) 19687ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 1969c91498e1SVivien Didelot else 19707ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 1971c91498e1SVivien Didelot 1972933b4425SRussell King /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port 1973933b4425SRussell King * and then the CPU port. Do not warn for duplicates for the CPU port. 1974933b4425SRussell King */ 1975933b4425SRussell King warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); 1976933b4425SRussell King 1977c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1978fad09c73SVivien Didelot 1979fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1980933b4425SRussell King if (mv88e6xxx_port_vlan_join(chip, port, vid, member, warn)) 1981774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 1982fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1983fad09c73SVivien Didelot 198477064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1985774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, 1986fad09c73SVivien Didelot vlan->vid_end); 1987fad09c73SVivien Didelot 1988c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1989fad09c73SVivien Didelot } 1990fad09c73SVivien Didelot 199152109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, 1992fad09c73SVivien Didelot int port, u16 vid) 1993fad09c73SVivien Didelot { 1994b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1995fad09c73SVivien Didelot int i, err; 1996fad09c73SVivien Didelot 199752109892SVivien Didelot if (!vid) 199852109892SVivien Didelot return -EOPNOTSUPP; 199952109892SVivien Didelot 200052109892SVivien Didelot vlan.vid = vid - 1; 200152109892SVivien Didelot vlan.valid = false; 200252109892SVivien Didelot 200352109892SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 2004fad09c73SVivien Didelot if (err) 2005fad09c73SVivien Didelot return err; 2006fad09c73SVivien Didelot 200752109892SVivien Didelot /* If the VLAN doesn't exist in hardware or the port isn't a member, 200852109892SVivien Didelot * tell switchdev that this VLAN is likely handled in software. 200952109892SVivien Didelot */ 201052109892SVivien Didelot if (vlan.vid != vid || !vlan.valid || 201152109892SVivien Didelot vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 2012fad09c73SVivien Didelot return -EOPNOTSUPP; 2013fad09c73SVivien Didelot 20147ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 2015fad09c73SVivien Didelot 2016fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 2017fad09c73SVivien Didelot vlan.valid = false; 2018370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 20197ec60d6eSVivien Didelot if (vlan.member[i] != 20207ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 2021fad09c73SVivien Didelot vlan.valid = true; 2022fad09c73SVivien Didelot break; 2023fad09c73SVivien Didelot } 2024fad09c73SVivien Didelot } 2025fad09c73SVivien Didelot 20260ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2027fad09c73SVivien Didelot if (err) 2028fad09c73SVivien Didelot return err; 2029fad09c73SVivien Didelot 2030e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 2031fad09c73SVivien Didelot } 2032fad09c73SVivien Didelot 2033fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 2034fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 2035fad09c73SVivien Didelot { 203604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2037fad09c73SVivien Didelot u16 pvid, vid; 2038fad09c73SVivien Didelot int err = 0; 2039fad09c73SVivien Didelot 20403cf3c846SVivien Didelot if (!chip->info->max_vid) 2041fad09c73SVivien Didelot return -EOPNOTSUPP; 2042fad09c73SVivien Didelot 2043c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2044fad09c73SVivien Didelot 204577064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 2046fad09c73SVivien Didelot if (err) 2047fad09c73SVivien Didelot goto unlock; 2048fad09c73SVivien Didelot 2049fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 205052109892SVivien Didelot err = mv88e6xxx_port_vlan_leave(chip, port, vid); 2051fad09c73SVivien Didelot if (err) 2052fad09c73SVivien Didelot goto unlock; 2053fad09c73SVivien Didelot 2054fad09c73SVivien Didelot if (vid == pvid) { 205577064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 2056fad09c73SVivien Didelot if (err) 2057fad09c73SVivien Didelot goto unlock; 2058fad09c73SVivien Didelot } 2059fad09c73SVivien Didelot } 2060fad09c73SVivien Didelot 2061fad09c73SVivien Didelot unlock: 2062c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2063fad09c73SVivien Didelot 2064fad09c73SVivien Didelot return err; 2065fad09c73SVivien Didelot } 2066fad09c73SVivien Didelot 20671b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 20686c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2069fad09c73SVivien Didelot { 207004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 20711b6dd556SArkadi Sharshevsky int err; 2072fad09c73SVivien Didelot 2073c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 20741b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 20751b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 2076c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 20771b6dd556SArkadi Sharshevsky 20781b6dd556SArkadi Sharshevsky return err; 2079fad09c73SVivien Didelot } 2080fad09c73SVivien Didelot 2081fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 20826c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2083fad09c73SVivien Didelot { 208404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 208583dabd1fSVivien Didelot int err; 2086fad09c73SVivien Didelot 2087c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2088d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); 2089c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2090fad09c73SVivien Didelot 209183dabd1fSVivien Didelot return err; 2092fad09c73SVivien Didelot } 2093fad09c73SVivien Didelot 209483dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 2095fad09c73SVivien Didelot u16 fid, u16 vid, int port, 20962bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2097fad09c73SVivien Didelot { 2098dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 20992bedde1aSArkadi Sharshevsky bool is_static; 2100fad09c73SVivien Didelot int err; 2101fad09c73SVivien Didelot 2102d8291a95SVivien Didelot addr.state = 0; 2103dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 2104fad09c73SVivien Didelot 2105fad09c73SVivien Didelot do { 2106dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 2107fad09c73SVivien Didelot if (err) 210883dabd1fSVivien Didelot return err; 2109fad09c73SVivien Didelot 2110d8291a95SVivien Didelot if (!addr.state) 2111fad09c73SVivien Didelot break; 2112fad09c73SVivien Didelot 211301bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 211483dabd1fSVivien Didelot continue; 2115fad09c73SVivien Didelot 211683dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 211783dabd1fSVivien Didelot continue; 211883dabd1fSVivien Didelot 21192bedde1aSArkadi Sharshevsky is_static = (addr.state == 21202bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 21212bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 212283dabd1fSVivien Didelot if (err) 212383dabd1fSVivien Didelot return err; 2124fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 2125fad09c73SVivien Didelot 2126fad09c73SVivien Didelot return err; 2127fad09c73SVivien Didelot } 2128fad09c73SVivien Didelot 212983dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 21302bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 213183dabd1fSVivien Didelot { 2132425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 213383dabd1fSVivien Didelot u16 fid; 213483dabd1fSVivien Didelot int err; 213583dabd1fSVivien Didelot 213683dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 2137b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 213883dabd1fSVivien Didelot if (err) 213983dabd1fSVivien Didelot return err; 214083dabd1fSVivien Didelot 21412bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 214283dabd1fSVivien Didelot if (err) 214383dabd1fSVivien Didelot return err; 214483dabd1fSVivien Didelot 214583dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 2146425d2d37SVivien Didelot vlan.vid = chip->info->max_vid; 2147425d2d37SVivien Didelot vlan.valid = false; 2148425d2d37SVivien Didelot 214983dabd1fSVivien Didelot do { 2150f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 215183dabd1fSVivien Didelot if (err) 215283dabd1fSVivien Didelot return err; 215383dabd1fSVivien Didelot 215483dabd1fSVivien Didelot if (!vlan.valid) 215583dabd1fSVivien Didelot break; 215683dabd1fSVivien Didelot 215783dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 21582bedde1aSArkadi Sharshevsky cb, data); 215983dabd1fSVivien Didelot if (err) 216083dabd1fSVivien Didelot return err; 21613cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 216283dabd1fSVivien Didelot 216383dabd1fSVivien Didelot return err; 216483dabd1fSVivien Didelot } 216583dabd1fSVivien Didelot 2166fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 21672bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2168fad09c73SVivien Didelot { 216904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2170fcf15367SVivien Didelot int err; 2171fad09c73SVivien Didelot 2172c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2173fcf15367SVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, cb, data); 2174c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2175fcf15367SVivien Didelot 2176fcf15367SVivien Didelot return err; 2177fad09c73SVivien Didelot } 2178fad09c73SVivien Didelot 2179240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 2180240ea3efSVivien Didelot struct net_device *br) 2181240ea3efSVivien Didelot { 2182ef2025ecSVivien Didelot struct dsa_switch *ds = chip->ds; 2183ef2025ecSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 2184ef2025ecSVivien Didelot struct dsa_port *dp; 2185240ea3efSVivien Didelot int err; 2186240ea3efSVivien Didelot 2187ef2025ecSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 2188ef2025ecSVivien Didelot if (dp->bridge_dev == br) { 2189ef2025ecSVivien Didelot if (dp->ds == ds) { 2190ef2025ecSVivien Didelot /* This is a local bridge group member, 2191ef2025ecSVivien Didelot * remap its Port VLAN Map. 2192ef2025ecSVivien Didelot */ 2193ef2025ecSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, dp->index); 2194240ea3efSVivien Didelot if (err) 2195240ea3efSVivien Didelot return err; 2196ef2025ecSVivien Didelot } else { 2197ef2025ecSVivien Didelot /* This is an external bridge group member, 2198ef2025ecSVivien Didelot * remap its cross-chip Port VLAN Table entry. 2199ef2025ecSVivien Didelot */ 2200ef2025ecSVivien Didelot err = mv88e6xxx_pvt_map(chip, dp->ds->index, 2201ef2025ecSVivien Didelot dp->index); 2202e96a6e02SVivien Didelot if (err) 2203e96a6e02SVivien Didelot return err; 2204e96a6e02SVivien Didelot } 2205e96a6e02SVivien Didelot } 2206e96a6e02SVivien Didelot } 2207e96a6e02SVivien Didelot 2208240ea3efSVivien Didelot return 0; 2209240ea3efSVivien Didelot } 2210240ea3efSVivien Didelot 2211fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 2212fae8a25eSVivien Didelot struct net_device *br) 2213fad09c73SVivien Didelot { 221404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2215240ea3efSVivien Didelot int err; 2216fad09c73SVivien Didelot 2217c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2218240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 2219c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2220fad09c73SVivien Didelot 2221fad09c73SVivien Didelot return err; 2222fad09c73SVivien Didelot } 2223fad09c73SVivien Didelot 2224f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 2225f123f2fbSVivien Didelot struct net_device *br) 2226fad09c73SVivien Didelot { 222704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2228fad09c73SVivien Didelot 2229c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2230240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 2231240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 2232240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 2233c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2234fad09c73SVivien Didelot } 2235fad09c73SVivien Didelot 2236aec5ac88SVivien Didelot static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, 2237aec5ac88SVivien Didelot int port, struct net_device *br) 2238aec5ac88SVivien Didelot { 2239aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2240aec5ac88SVivien Didelot int err; 2241aec5ac88SVivien Didelot 2242c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2243aec5ac88SVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 2244c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2245aec5ac88SVivien Didelot 2246aec5ac88SVivien Didelot return err; 2247aec5ac88SVivien Didelot } 2248aec5ac88SVivien Didelot 2249aec5ac88SVivien Didelot static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, 2250aec5ac88SVivien Didelot int port, struct net_device *br) 2251aec5ac88SVivien Didelot { 2252aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2253aec5ac88SVivien Didelot 2254c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2255aec5ac88SVivien Didelot if (mv88e6xxx_pvt_map(chip, dev, port)) 2256aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2257c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2258aec5ac88SVivien Didelot } 2259aec5ac88SVivien Didelot 226017e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 226117e708baSVivien Didelot { 226217e708baSVivien Didelot if (chip->info->ops->reset) 226317e708baSVivien Didelot return chip->info->ops->reset(chip); 226417e708baSVivien Didelot 226517e708baSVivien Didelot return 0; 226617e708baSVivien Didelot } 226717e708baSVivien Didelot 2268309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 2269309eca6dSVivien Didelot { 2270309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 2271309eca6dSVivien Didelot 2272309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 2273309eca6dSVivien Didelot if (gpiod) { 2274309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 2275309eca6dSVivien Didelot usleep_range(10000, 20000); 2276309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 2277309eca6dSVivien Didelot usleep_range(10000, 20000); 2278309eca6dSVivien Didelot } 2279309eca6dSVivien Didelot } 2280309eca6dSVivien Didelot 22814ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 22824ac4b5a6SVivien Didelot { 22834ac4b5a6SVivien Didelot int i, err; 22844ac4b5a6SVivien Didelot 22854ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 22864ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2287f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 22884ac4b5a6SVivien Didelot if (err) 22894ac4b5a6SVivien Didelot return err; 22904ac4b5a6SVivien Didelot } 22914ac4b5a6SVivien Didelot 22924ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 22934ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 22944ac4b5a6SVivien Didelot */ 22954ac4b5a6SVivien Didelot usleep_range(2000, 4000); 22964ac4b5a6SVivien Didelot 22974ac4b5a6SVivien Didelot return 0; 22984ac4b5a6SVivien Didelot } 22994ac4b5a6SVivien Didelot 2300fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 2301fad09c73SVivien Didelot { 2302a935c052SVivien Didelot int err; 2303fad09c73SVivien Didelot 23044ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 23050e7b9925SAndrew Lunn if (err) 23060e7b9925SAndrew Lunn return err; 2307fad09c73SVivien Didelot 2308309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 2309fad09c73SVivien Didelot 231017e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 2311fad09c73SVivien Didelot } 2312fad09c73SVivien Didelot 23134314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 231431bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 231531bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 231656995cbcSAndrew Lunn { 231756995cbcSAndrew Lunn int err; 231856995cbcSAndrew Lunn 23194314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 23204314557cSVivien Didelot return -EOPNOTSUPP; 23214314557cSVivien Didelot 23224314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 232356995cbcSAndrew Lunn if (err) 232456995cbcSAndrew Lunn return err; 232556995cbcSAndrew Lunn 23264314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 23274314557cSVivien Didelot if (err) 23284314557cSVivien Didelot return err; 23294314557cSVivien Didelot 23304314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 23314314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 23324314557cSVivien Didelot 23334314557cSVivien Didelot return 0; 23344314557cSVivien Didelot } 23354314557cSVivien Didelot 23364314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 23374314557cSVivien Didelot { 23384314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 233931bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2340b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 23414314557cSVivien Didelot } 23424314557cSVivien Didelot 23434314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 23444314557cSVivien Didelot { 23454314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 234631bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2347b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 23484314557cSVivien Didelot } 23494314557cSVivien Didelot 23504314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 23514314557cSVivien Didelot { 23524314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 23534314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 235431bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 235531bef4e9SVivien Didelot ETH_P_EDSA); 23564314557cSVivien Didelot } 23574314557cSVivien Didelot 23584314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 23594314557cSVivien Didelot { 23604314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 23614314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 23624314557cSVivien Didelot 23632b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 23644314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 23654314557cSVivien Didelot 23664314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 23674314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 23684314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 23694314557cSVivien Didelot 23704314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 23714314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 23724314557cSVivien Didelot 23734314557cSVivien Didelot return -EINVAL; 23744314557cSVivien Didelot } 23754314557cSVivien Didelot 2376ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 2377ea698f4fSVivien Didelot { 2378ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 2379ea698f4fSVivien Didelot 2380ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 2381ea698f4fSVivien Didelot } 2382ea698f4fSVivien Didelot 2383601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 2384601aeed3SVivien Didelot { 23853ee50cbfSVivien Didelot struct dsa_switch *ds = chip->ds; 2386407308f6SDavid S. Miller bool flood; 2387601aeed3SVivien Didelot 2388407308f6SDavid S. Miller /* Upstream ports flood frames with unknown unicast or multicast DA */ 2389407308f6SDavid S. Miller flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port); 2390407308f6SDavid S. Miller if (chip->info->ops->port_set_egress_floods) 2391407308f6SDavid S. Miller return chip->info->ops->port_set_egress_floods(chip, port, 2392407308f6SDavid S. Miller flood, flood); 2393407308f6SDavid S. Miller 2394601aeed3SVivien Didelot return 0; 2395601aeed3SVivien Didelot } 2396601aeed3SVivien Didelot 239745de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id) 239845de77ffSVivien Didelot { 239945de77ffSVivien Didelot struct mv88e6xxx_port *mvp = dev_id; 240045de77ffSVivien Didelot struct mv88e6xxx_chip *chip = mvp->chip; 240145de77ffSVivien Didelot irqreturn_t ret = IRQ_NONE; 240245de77ffSVivien Didelot int port = mvp->port; 240345de77ffSVivien Didelot u8 lane; 240445de77ffSVivien Didelot 240545de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 240645de77ffSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 240745de77ffSVivien Didelot if (lane) 240845de77ffSVivien Didelot ret = mv88e6xxx_serdes_irq_status(chip, port, lane); 240945de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 241045de77ffSVivien Didelot 241145de77ffSVivien Didelot return ret; 241245de77ffSVivien Didelot } 241345de77ffSVivien Didelot 241445de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port, 241545de77ffSVivien Didelot u8 lane) 241645de77ffSVivien Didelot { 241745de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 241845de77ffSVivien Didelot unsigned int irq; 241945de77ffSVivien Didelot int err; 242045de77ffSVivien Didelot 242145de77ffSVivien Didelot /* Nothing to request if this SERDES port has no IRQ */ 242245de77ffSVivien Didelot irq = mv88e6xxx_serdes_irq_mapping(chip, port); 242345de77ffSVivien Didelot if (!irq) 242445de77ffSVivien Didelot return 0; 242545de77ffSVivien Didelot 2426e6f2f6b8SAndrew Lunn snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name), 2427e6f2f6b8SAndrew Lunn "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port); 2428e6f2f6b8SAndrew Lunn 242945de77ffSVivien Didelot /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */ 243045de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 243145de77ffSVivien Didelot err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn, 2432e6f2f6b8SAndrew Lunn IRQF_ONESHOT, dev_id->serdes_irq_name, 2433e6f2f6b8SAndrew Lunn dev_id); 243445de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 243545de77ffSVivien Didelot if (err) 243645de77ffSVivien Didelot return err; 243745de77ffSVivien Didelot 243845de77ffSVivien Didelot dev_id->serdes_irq = irq; 243945de77ffSVivien Didelot 244045de77ffSVivien Didelot return mv88e6xxx_serdes_irq_enable(chip, port, lane); 244145de77ffSVivien Didelot } 244245de77ffSVivien Didelot 244345de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port, 244445de77ffSVivien Didelot u8 lane) 244545de77ffSVivien Didelot { 244645de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 244745de77ffSVivien Didelot unsigned int irq = dev_id->serdes_irq; 244845de77ffSVivien Didelot int err; 244945de77ffSVivien Didelot 245045de77ffSVivien Didelot /* Nothing to free if no IRQ has been requested */ 245145de77ffSVivien Didelot if (!irq) 245245de77ffSVivien Didelot return 0; 245345de77ffSVivien Didelot 245445de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 245545de77ffSVivien Didelot 245645de77ffSVivien Didelot /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */ 245745de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 245845de77ffSVivien Didelot free_irq(irq, dev_id); 245945de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 246045de77ffSVivien Didelot 246145de77ffSVivien Didelot dev_id->serdes_irq = 0; 246245de77ffSVivien Didelot 246345de77ffSVivien Didelot return err; 246445de77ffSVivien Didelot } 246545de77ffSVivien Didelot 24666d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 24676d91782fSAndrew Lunn bool on) 24686d91782fSAndrew Lunn { 2469dc272f60SVivien Didelot u8 lane; 2470fc0bc019SVivien Didelot int err; 24716d91782fSAndrew Lunn 2472dc272f60SVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 2473dc272f60SVivien Didelot if (!lane) 2474523a8904SVivien Didelot return 0; 2475fc0bc019SVivien Didelot 2476fc0bc019SVivien Didelot if (on) { 2477dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_up(chip, port, lane); 2478fc0bc019SVivien Didelot if (err) 2479fc0bc019SVivien Didelot return err; 2480fc0bc019SVivien Didelot 248145de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_request(chip, port, lane); 2482fc0bc019SVivien Didelot } else { 248345de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_free(chip, port, lane); 248445de77ffSVivien Didelot if (err) 248545de77ffSVivien Didelot return err; 2486fc0bc019SVivien Didelot 2487dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_down(chip, port, lane); 2488fc0bc019SVivien Didelot } 2489fc0bc019SVivien Didelot 2490fc0bc019SVivien Didelot return err; 24916d91782fSAndrew Lunn } 24926d91782fSAndrew Lunn 2493fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 2494fa371c80SVivien Didelot { 2495fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 2496fa371c80SVivien Didelot int upstream_port; 2497fa371c80SVivien Didelot int err; 2498fa371c80SVivien Didelot 249907073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 2500fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 2501fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 2502fa371c80SVivien Didelot upstream_port); 2503fa371c80SVivien Didelot if (err) 2504fa371c80SVivien Didelot return err; 2505fa371c80SVivien Didelot } 2506fa371c80SVivien Didelot 25070ea54ddaSVivien Didelot if (port == upstream_port) { 25080ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 25090ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 25100ea54ddaSVivien Didelot upstream_port); 25110ea54ddaSVivien Didelot if (err) 25120ea54ddaSVivien Didelot return err; 25130ea54ddaSVivien Didelot } 25140ea54ddaSVivien Didelot 25150ea54ddaSVivien Didelot if (chip->info->ops->set_egress_port) { 25160ea54ddaSVivien Didelot err = chip->info->ops->set_egress_port(chip, 25175c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS, 25185c74c54cSIwan R Timmer upstream_port); 25195c74c54cSIwan R Timmer if (err) 25205c74c54cSIwan R Timmer return err; 25215c74c54cSIwan R Timmer 25225c74c54cSIwan R Timmer err = chip->info->ops->set_egress_port(chip, 25235c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS, 25240ea54ddaSVivien Didelot upstream_port); 25250ea54ddaSVivien Didelot if (err) 25260ea54ddaSVivien Didelot return err; 25270ea54ddaSVivien Didelot } 25280ea54ddaSVivien Didelot } 25290ea54ddaSVivien Didelot 2530fa371c80SVivien Didelot return 0; 2531fa371c80SVivien Didelot } 2532fa371c80SVivien Didelot 2533fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 2534fad09c73SVivien Didelot { 2535fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 25360e7b9925SAndrew Lunn int err; 2537fad09c73SVivien Didelot u16 reg; 2538fad09c73SVivien Didelot 25397b898469SAndrew Lunn chip->ports[port].chip = chip; 25407b898469SAndrew Lunn chip->ports[port].port = port; 25417b898469SAndrew Lunn 2542d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 2543d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 2544d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 2545fad09c73SVivien Didelot */ 2546d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 2547d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 2548d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 254954186b91SAndrew Lunn PAUSE_OFF, 2550d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 2551fad09c73SVivien Didelot else 2552d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 2553d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 255454186b91SAndrew Lunn PAUSE_ON, 2555d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 25560e7b9925SAndrew Lunn if (err) 25570e7b9925SAndrew Lunn return err; 2558fad09c73SVivien Didelot 2559fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 2560fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 2561fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 2562fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 2563fad09c73SVivien Didelot * to Forwarding. 2564fad09c73SVivien Didelot * 2565fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 2566fad09c73SVivien Didelot * on which tagging mode was configured. 2567fad09c73SVivien Didelot * 2568fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 2569fad09c73SVivien Didelot * 2570fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 2571fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 2572fad09c73SVivien Didelot */ 2573a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 2574a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 2575a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 2576a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 25770e7b9925SAndrew Lunn if (err) 25780e7b9925SAndrew Lunn return err; 257956995cbcSAndrew Lunn 2580601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 258156995cbcSAndrew Lunn if (err) 258256995cbcSAndrew Lunn return err; 2583fad09c73SVivien Didelot 2584601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 25854314557cSVivien Didelot if (err) 25864314557cSVivien Didelot return err; 25874314557cSVivien Didelot 2588fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 2589fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 2590fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 2591fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 2592fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 2593fad09c73SVivien Didelot */ 2594a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 2595a23b2961SAndrew Lunn if (err) 2596a23b2961SAndrew Lunn return err; 2597a23b2961SAndrew Lunn 2598fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 25990e7b9925SAndrew Lunn if (err) 26000e7b9925SAndrew Lunn return err; 2601fad09c73SVivien Didelot 2602a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 260381c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); 2604a23b2961SAndrew Lunn if (err) 2605a23b2961SAndrew Lunn return err; 2606a23b2961SAndrew Lunn 2607cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 2608cd782656SVivien Didelot err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); 26095f436666SAndrew Lunn if (err) 26105f436666SAndrew Lunn return err; 26115f436666SAndrew Lunn } 26125f436666SAndrew Lunn 2613fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 2614fad09c73SVivien Didelot * of packets, add the address to the address database using 2615fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 2616fad09c73SVivien Didelot * the other bits clear. 2617fad09c73SVivien Didelot */ 2618fad09c73SVivien Didelot reg = 1 << port; 2619fad09c73SVivien Didelot /* Disable learning for CPU port */ 2620fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 2621fad09c73SVivien Didelot reg = 0; 2622fad09c73SVivien Didelot 26232a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 26242a4614e4SVivien Didelot reg); 26250e7b9925SAndrew Lunn if (err) 26260e7b9925SAndrew Lunn return err; 2627fad09c73SVivien Didelot 2628fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 26292cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 26302cb8cb14SVivien Didelot 0x0000); 26310e7b9925SAndrew Lunn if (err) 26320e7b9925SAndrew Lunn return err; 2633fad09c73SVivien Didelot 26340898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 26350898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 2636b35d322aSAndrew Lunn if (err) 2637b35d322aSAndrew Lunn return err; 2638b35d322aSAndrew Lunn } 2639b35d322aSAndrew Lunn 2640c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 2641c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 2642c8c94891SVivien Didelot if (err) 2643c8c94891SVivien Didelot return err; 2644c8c94891SVivien Didelot } 2645c8c94891SVivien Didelot 26469dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 26479dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 26480e7b9925SAndrew Lunn if (err) 26490e7b9925SAndrew Lunn return err; 2650ef0a7318SAndrew Lunn } 26512bbb33beSAndrew Lunn 2652ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 2653ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 26540e7b9925SAndrew Lunn if (err) 26550e7b9925SAndrew Lunn return err; 2656fad09c73SVivien Didelot } 2657fad09c73SVivien Didelot 2658ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 2659ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 26600e7b9925SAndrew Lunn if (err) 26610e7b9925SAndrew Lunn return err; 2662fad09c73SVivien Didelot } 2663fad09c73SVivien Didelot 2664121b8fe2SHubert Feurstein if (chip->info->ops->port_setup_message_port) { 2665121b8fe2SHubert Feurstein err = chip->info->ops->port_setup_message_port(chip, port); 26660e7b9925SAndrew Lunn if (err) 26670e7b9925SAndrew Lunn return err; 2668121b8fe2SHubert Feurstein } 2669fad09c73SVivien Didelot 2670fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 2671fad09c73SVivien Didelot * database, and allow bidirectional communication between the 2672fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 2673fad09c73SVivien Didelot */ 2674b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 26750e7b9925SAndrew Lunn if (err) 26760e7b9925SAndrew Lunn return err; 2677fad09c73SVivien Didelot 2678240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 26790e7b9925SAndrew Lunn if (err) 26800e7b9925SAndrew Lunn return err; 2681fad09c73SVivien Didelot 2682fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 2683fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 2684fad09c73SVivien Didelot */ 2685b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 2686fad09c73SVivien Didelot } 2687fad09c73SVivien Didelot 268804aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 268904aca993SAndrew Lunn struct phy_device *phydev) 269004aca993SAndrew Lunn { 269104aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2692523a8904SVivien Didelot int err; 269304aca993SAndrew Lunn 2694c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2695523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 2696c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 269704aca993SAndrew Lunn 269804aca993SAndrew Lunn return err; 269904aca993SAndrew Lunn } 270004aca993SAndrew Lunn 270175104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 270204aca993SAndrew Lunn { 270304aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 270404aca993SAndrew Lunn 2705c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2706523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 2707523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 2708c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 270904aca993SAndrew Lunn } 271004aca993SAndrew Lunn 27112cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 27122cfcd964SVivien Didelot unsigned int ageing_time) 27132cfcd964SVivien Didelot { 271404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 27152cfcd964SVivien Didelot int err; 27162cfcd964SVivien Didelot 2717c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2718720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 2719c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 27202cfcd964SVivien Didelot 27212cfcd964SVivien Didelot return err; 27222cfcd964SVivien Didelot } 27232cfcd964SVivien Didelot 2724447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 2725fad09c73SVivien Didelot { 2726fad09c73SVivien Didelot int err; 2727fad09c73SVivien Didelot 2728de227387SAndrew Lunn /* Initialize the statistics unit */ 2729447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 2730447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 2731de227387SAndrew Lunn if (err) 2732de227387SAndrew Lunn return err; 2733447b1bb8SVivien Didelot } 2734de227387SAndrew Lunn 273540cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 27369729934cSVivien Didelot } 27379729934cSVivien Didelot 2738ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 2739ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 2740ea89098eSAndrew Lunn { 2741ea89098eSAndrew Lunn int port; 2742ea89098eSAndrew Lunn int err; 2743ea89098eSAndrew Lunn u16 val; 2744ea89098eSAndrew Lunn 2745ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 274660907013SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val); 2747ea89098eSAndrew Lunn if (err) { 2748ea89098eSAndrew Lunn dev_err(chip->dev, 2749ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 2750ea89098eSAndrew Lunn return false; 2751ea89098eSAndrew Lunn } 2752ea89098eSAndrew Lunn if (val != 0x01c0) 2753ea89098eSAndrew Lunn return false; 2754ea89098eSAndrew Lunn } 2755ea89098eSAndrew Lunn 2756ea89098eSAndrew Lunn return true; 2757ea89098eSAndrew Lunn } 2758ea89098eSAndrew Lunn 2759ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 2760ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 2761ea89098eSAndrew Lunn * software reset. 2762ea89098eSAndrew Lunn */ 2763ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 2764ea89098eSAndrew Lunn { 2765ea89098eSAndrew Lunn int port; 2766ea89098eSAndrew Lunn int err; 2767ea89098eSAndrew Lunn 2768ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 2769ea89098eSAndrew Lunn return 0; 2770ea89098eSAndrew Lunn 2771ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 2772ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2773ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 2774ea89098eSAndrew Lunn if (err) 2775ea89098eSAndrew Lunn return err; 2776ea89098eSAndrew Lunn } 2777ea89098eSAndrew Lunn 2778ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 277960907013SMarek Behún err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0); 2780ea89098eSAndrew Lunn if (err) 2781ea89098eSAndrew Lunn return err; 2782ea89098eSAndrew Lunn } 2783ea89098eSAndrew Lunn 2784ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 2785ea89098eSAndrew Lunn } 2786ea89098eSAndrew Lunn 278723e8b470SAndrew Lunn enum mv88e6xxx_devlink_param_id { 278823e8b470SAndrew Lunn MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 278923e8b470SAndrew Lunn MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, 279023e8b470SAndrew Lunn }; 279123e8b470SAndrew Lunn 279223e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, 279323e8b470SAndrew Lunn struct devlink_param_gset_ctx *ctx) 279423e8b470SAndrew Lunn { 279523e8b470SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 279623e8b470SAndrew Lunn int err; 279723e8b470SAndrew Lunn 279823e8b470SAndrew Lunn mv88e6xxx_reg_lock(chip); 279923e8b470SAndrew Lunn 280023e8b470SAndrew Lunn switch (id) { 280123e8b470SAndrew Lunn case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: 280223e8b470SAndrew Lunn err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8); 280323e8b470SAndrew Lunn break; 280423e8b470SAndrew Lunn default: 280523e8b470SAndrew Lunn err = -EOPNOTSUPP; 280623e8b470SAndrew Lunn break; 280723e8b470SAndrew Lunn } 280823e8b470SAndrew Lunn 280923e8b470SAndrew Lunn mv88e6xxx_reg_unlock(chip); 281023e8b470SAndrew Lunn 281123e8b470SAndrew Lunn return err; 281223e8b470SAndrew Lunn } 281323e8b470SAndrew Lunn 281423e8b470SAndrew Lunn static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, 281523e8b470SAndrew Lunn struct devlink_param_gset_ctx *ctx) 281623e8b470SAndrew Lunn { 281723e8b470SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 281823e8b470SAndrew Lunn int err; 281923e8b470SAndrew Lunn 282023e8b470SAndrew Lunn mv88e6xxx_reg_lock(chip); 282123e8b470SAndrew Lunn 282223e8b470SAndrew Lunn switch (id) { 282323e8b470SAndrew Lunn case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: 282423e8b470SAndrew Lunn err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8); 282523e8b470SAndrew Lunn break; 282623e8b470SAndrew Lunn default: 282723e8b470SAndrew Lunn err = -EOPNOTSUPP; 282823e8b470SAndrew Lunn break; 282923e8b470SAndrew Lunn } 283023e8b470SAndrew Lunn 283123e8b470SAndrew Lunn mv88e6xxx_reg_unlock(chip); 283223e8b470SAndrew Lunn 283323e8b470SAndrew Lunn return err; 283423e8b470SAndrew Lunn } 283523e8b470SAndrew Lunn 283623e8b470SAndrew Lunn static const struct devlink_param mv88e6xxx_devlink_params[] = { 283723e8b470SAndrew Lunn DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, 283823e8b470SAndrew Lunn "ATU_hash", DEVLINK_PARAM_TYPE_U8, 283923e8b470SAndrew Lunn BIT(DEVLINK_PARAM_CMODE_RUNTIME)), 284023e8b470SAndrew Lunn }; 284123e8b470SAndrew Lunn 284223e8b470SAndrew Lunn static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds) 284323e8b470SAndrew Lunn { 284423e8b470SAndrew Lunn return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params, 284523e8b470SAndrew Lunn ARRAY_SIZE(mv88e6xxx_devlink_params)); 284623e8b470SAndrew Lunn } 284723e8b470SAndrew Lunn 284823e8b470SAndrew Lunn static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) 284923e8b470SAndrew Lunn { 285023e8b470SAndrew Lunn dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params, 285123e8b470SAndrew Lunn ARRAY_SIZE(mv88e6xxx_devlink_params)); 285223e8b470SAndrew Lunn } 285323e8b470SAndrew Lunn 2854e0c69ca7SAndrew Lunn enum mv88e6xxx_devlink_resource_id { 2855e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2856e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 2857e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 2858e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 2859e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 2860e0c69ca7SAndrew Lunn }; 2861e0c69ca7SAndrew Lunn 2862e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip, 2863e0c69ca7SAndrew Lunn u16 bin) 2864e0c69ca7SAndrew Lunn { 2865e0c69ca7SAndrew Lunn u16 occupancy = 0; 2866e0c69ca7SAndrew Lunn int err; 2867e0c69ca7SAndrew Lunn 2868e0c69ca7SAndrew Lunn mv88e6xxx_reg_lock(chip); 2869e0c69ca7SAndrew Lunn 2870e0c69ca7SAndrew Lunn err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL, 2871e0c69ca7SAndrew Lunn bin); 2872e0c69ca7SAndrew Lunn if (err) { 2873e0c69ca7SAndrew Lunn dev_err(chip->dev, "failed to set ATU stats kind/bin\n"); 2874e0c69ca7SAndrew Lunn goto unlock; 2875e0c69ca7SAndrew Lunn } 2876e0c69ca7SAndrew Lunn 2877e0c69ca7SAndrew Lunn err = mv88e6xxx_g1_atu_get_next(chip, 0); 2878e0c69ca7SAndrew Lunn if (err) { 2879e0c69ca7SAndrew Lunn dev_err(chip->dev, "failed to perform ATU get next\n"); 2880e0c69ca7SAndrew Lunn goto unlock; 2881e0c69ca7SAndrew Lunn } 2882e0c69ca7SAndrew Lunn 2883e0c69ca7SAndrew Lunn err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy); 2884e0c69ca7SAndrew Lunn if (err) { 2885e0c69ca7SAndrew Lunn dev_err(chip->dev, "failed to get ATU stats\n"); 2886e0c69ca7SAndrew Lunn goto unlock; 2887e0c69ca7SAndrew Lunn } 2888e0c69ca7SAndrew Lunn 2889012fc745SAndrew Lunn occupancy &= MV88E6XXX_G2_ATU_STATS_MASK; 2890012fc745SAndrew Lunn 2891e0c69ca7SAndrew Lunn unlock: 2892e0c69ca7SAndrew Lunn mv88e6xxx_reg_unlock(chip); 2893e0c69ca7SAndrew Lunn 2894e0c69ca7SAndrew Lunn return occupancy; 2895e0c69ca7SAndrew Lunn } 2896e0c69ca7SAndrew Lunn 2897e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv) 2898e0c69ca7SAndrew Lunn { 2899e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2900e0c69ca7SAndrew Lunn 2901e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2902e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_0); 2903e0c69ca7SAndrew Lunn } 2904e0c69ca7SAndrew Lunn 2905e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv) 2906e0c69ca7SAndrew Lunn { 2907e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2908e0c69ca7SAndrew Lunn 2909e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2910e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_1); 2911e0c69ca7SAndrew Lunn } 2912e0c69ca7SAndrew Lunn 2913e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv) 2914e0c69ca7SAndrew Lunn { 2915e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2916e0c69ca7SAndrew Lunn 2917e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2918e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_2); 2919e0c69ca7SAndrew Lunn } 2920e0c69ca7SAndrew Lunn 2921e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv) 2922e0c69ca7SAndrew Lunn { 2923e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = priv; 2924e0c69ca7SAndrew Lunn 2925e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_get(chip, 2926e0c69ca7SAndrew Lunn MV88E6XXX_G2_ATU_STATS_BIN_3); 2927e0c69ca7SAndrew Lunn } 2928e0c69ca7SAndrew Lunn 2929e0c69ca7SAndrew Lunn static u64 mv88e6xxx_devlink_atu_get(void *priv) 2930e0c69ca7SAndrew Lunn { 2931e0c69ca7SAndrew Lunn return mv88e6xxx_devlink_atu_bin_0_get(priv) + 2932e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_1_get(priv) + 2933e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_2_get(priv) + 2934e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_3_get(priv); 2935e0c69ca7SAndrew Lunn } 2936e0c69ca7SAndrew Lunn 2937e0c69ca7SAndrew Lunn static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds) 2938e0c69ca7SAndrew Lunn { 2939e0c69ca7SAndrew Lunn struct devlink_resource_size_params size_params; 2940e0c69ca7SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2941e0c69ca7SAndrew Lunn int err; 2942e0c69ca7SAndrew Lunn 2943e0c69ca7SAndrew Lunn devlink_resource_size_params_init(&size_params, 2944e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip), 2945e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip), 2946e0c69ca7SAndrew Lunn 1, DEVLINK_RESOURCE_UNIT_ENTRY); 2947e0c69ca7SAndrew Lunn 2948e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU", 2949e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip), 2950e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2951e0c69ca7SAndrew Lunn DEVLINK_RESOURCE_ID_PARENT_TOP, 2952e0c69ca7SAndrew Lunn &size_params); 2953e0c69ca7SAndrew Lunn if (err) 2954e0c69ca7SAndrew Lunn goto out; 2955e0c69ca7SAndrew Lunn 2956e0c69ca7SAndrew Lunn devlink_resource_size_params_init(&size_params, 2957e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2958e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2959e0c69ca7SAndrew Lunn 1, DEVLINK_RESOURCE_UNIT_ENTRY); 2960e0c69ca7SAndrew Lunn 2961e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_0", 2962e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2963e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 2964e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2965e0c69ca7SAndrew Lunn &size_params); 2966e0c69ca7SAndrew Lunn if (err) 2967e0c69ca7SAndrew Lunn goto out; 2968e0c69ca7SAndrew Lunn 2969e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_1", 2970e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2971e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 2972e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2973e0c69ca7SAndrew Lunn &size_params); 2974e0c69ca7SAndrew Lunn if (err) 2975e0c69ca7SAndrew Lunn goto out; 2976e0c69ca7SAndrew Lunn 2977e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_2", 2978e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2979e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 2980e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2981e0c69ca7SAndrew Lunn &size_params); 2982e0c69ca7SAndrew Lunn if (err) 2983e0c69ca7SAndrew Lunn goto out; 2984e0c69ca7SAndrew Lunn 2985e0c69ca7SAndrew Lunn err = dsa_devlink_resource_register(ds, "ATU_bin_3", 2986e0c69ca7SAndrew Lunn mv88e6xxx_num_macs(chip) / 4, 2987e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 2988e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2989e0c69ca7SAndrew Lunn &size_params); 2990e0c69ca7SAndrew Lunn if (err) 2991e0c69ca7SAndrew Lunn goto out; 2992e0c69ca7SAndrew Lunn 2993e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2994e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU, 2995e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_get, 2996e0c69ca7SAndrew Lunn chip); 2997e0c69ca7SAndrew Lunn 2998e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 2999e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 3000e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_0_get, 3001e0c69ca7SAndrew Lunn chip); 3002e0c69ca7SAndrew Lunn 3003e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 3004e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 3005e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_1_get, 3006e0c69ca7SAndrew Lunn chip); 3007e0c69ca7SAndrew Lunn 3008e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 3009e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 3010e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_2_get, 3011e0c69ca7SAndrew Lunn chip); 3012e0c69ca7SAndrew Lunn 3013e0c69ca7SAndrew Lunn dsa_devlink_resource_occ_get_register(ds, 3014e0c69ca7SAndrew Lunn MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 3015e0c69ca7SAndrew Lunn mv88e6xxx_devlink_atu_bin_3_get, 3016e0c69ca7SAndrew Lunn chip); 3017e0c69ca7SAndrew Lunn 3018e0c69ca7SAndrew Lunn return 0; 3019e0c69ca7SAndrew Lunn 3020e0c69ca7SAndrew Lunn out: 3021e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3022e0c69ca7SAndrew Lunn return err; 3023e0c69ca7SAndrew Lunn } 3024e0c69ca7SAndrew Lunn 302523e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds) 302623e8b470SAndrew Lunn { 302723e8b470SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 3028e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 302923e8b470SAndrew Lunn } 303023e8b470SAndrew Lunn 3031fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 3032fad09c73SVivien Didelot { 303304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 30342d2e1dd2SAndrew Lunn u8 cmode; 3035fad09c73SVivien Didelot int err; 3036fad09c73SVivien Didelot int i; 3037fad09c73SVivien Didelot 3038fad09c73SVivien Didelot chip->ds = ds; 3039a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 3040fad09c73SVivien Didelot 3041c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3042fad09c73SVivien Didelot 3043ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 3044ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 3045ea89098eSAndrew Lunn if (err) 3046ea89098eSAndrew Lunn goto unlock; 3047ea89098eSAndrew Lunn } 3048ea89098eSAndrew Lunn 30492d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 30502d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 30512d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 30522d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 30532d2e1dd2SAndrew Lunn if (err) 3054e29129fcSDan Carpenter goto unlock; 30552d2e1dd2SAndrew Lunn 30562d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 30572d2e1dd2SAndrew Lunn } 30582d2e1dd2SAndrew Lunn } 30592d2e1dd2SAndrew Lunn 30609729934cSVivien Didelot /* Setup Switch Port Registers */ 3061370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 3062b759f528SVivien Didelot if (dsa_is_unused_port(ds, i)) 3063b759f528SVivien Didelot continue; 3064b759f528SVivien Didelot 3065c857486aSHubert Feurstein /* Prevent the use of an invalid port. */ 3066b759f528SVivien Didelot if (mv88e6xxx_is_invalid_port(chip, i)) { 3067c857486aSHubert Feurstein dev_err(chip->dev, "port %d is invalid\n", i); 3068c857486aSHubert Feurstein err = -EINVAL; 3069c857486aSHubert Feurstein goto unlock; 3070c857486aSHubert Feurstein } 3071c857486aSHubert Feurstein 30729729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 30739729934cSVivien Didelot if (err) 30749729934cSVivien Didelot goto unlock; 30759729934cSVivien Didelot } 30769729934cSVivien Didelot 3077cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 3078cd8da8bbSVivien Didelot if (err) 3079cd8da8bbSVivien Didelot goto unlock; 3080cd8da8bbSVivien Didelot 308104a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 308204a69a17SVivien Didelot if (err) 308304a69a17SVivien Didelot goto unlock; 308404a69a17SVivien Didelot 30851b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 30861b17aedfSVivien Didelot if (err) 30871b17aedfSVivien Didelot goto unlock; 30881b17aedfSVivien Didelot 3089b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 3090b486d7c9SVivien Didelot if (err) 3091b486d7c9SVivien Didelot goto unlock; 3092b486d7c9SVivien Didelot 309381228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 309481228996SVivien Didelot if (err) 309581228996SVivien Didelot goto unlock; 309681228996SVivien Didelot 3097a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 3098a2ac29d2SVivien Didelot if (err) 3099a2ac29d2SVivien Didelot goto unlock; 3100a2ac29d2SVivien Didelot 310187fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 310287fa886eSAndrew Lunn if (err) 310387fa886eSAndrew Lunn goto unlock; 310487fa886eSAndrew Lunn 31059e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 31069e907d73SVivien Didelot if (err) 31079e907d73SVivien Didelot goto unlock; 31089e907d73SVivien Didelot 31099e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 31109e5baf9bSVivien Didelot if (err) 31119e5baf9bSVivien Didelot goto unlock; 31129e5baf9bSVivien Didelot 311351c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 31146e55f698SAndrew Lunn if (err) 31156e55f698SAndrew Lunn goto unlock; 31166e55f698SAndrew Lunn 3117b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 3118b28f872dSVivien Didelot if (err) 3119b28f872dSVivien Didelot goto unlock; 3120b28f872dSVivien Didelot 3121c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 3122c7f047b6SVivien Didelot if (err) 3123c7f047b6SVivien Didelot goto unlock; 3124c7f047b6SVivien Didelot 312593e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 312693e18d61SVivien Didelot if (err) 312793e18d61SVivien Didelot goto unlock; 312893e18d61SVivien Didelot 3129c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 31302fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 31312fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 31322fa8d3afSBrandon Streiff if (err) 31332fa8d3afSBrandon Streiff goto unlock; 3134c6fe0ad2SBrandon Streiff 3135c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 3136c6fe0ad2SBrandon Streiff if (err) 3137c6fe0ad2SBrandon Streiff goto unlock; 31382fa8d3afSBrandon Streiff } 31392fa8d3afSBrandon Streiff 3140447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 3141447b1bb8SVivien Didelot if (err) 3142447b1bb8SVivien Didelot goto unlock; 3143447b1bb8SVivien Didelot 3144fad09c73SVivien Didelot unlock: 3145c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3146fad09c73SVivien Didelot 3147e0c69ca7SAndrew Lunn if (err) 3148e0c69ca7SAndrew Lunn return err; 3149e0c69ca7SAndrew Lunn 3150e0c69ca7SAndrew Lunn /* Have to be called without holding the register lock, since 3151e0c69ca7SAndrew Lunn * they take the devlink lock, and we later take the locks in 3152e0c69ca7SAndrew Lunn * the reverse order when getting/setting parameters or 3153e0c69ca7SAndrew Lunn * resource occupancy. 315423e8b470SAndrew Lunn */ 3155e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_resources(ds); 3156e0c69ca7SAndrew Lunn if (err) 3157e0c69ca7SAndrew Lunn return err; 3158e0c69ca7SAndrew Lunn 3159e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_params(ds); 3160e0c69ca7SAndrew Lunn if (err) 3161e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3162e0c69ca7SAndrew Lunn 3163e0c69ca7SAndrew Lunn return err; 3164fad09c73SVivien Didelot } 3165fad09c73SVivien Didelot 3166e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 3167fad09c73SVivien Didelot { 31680dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 31690dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3170e57e5e77SVivien Didelot u16 val; 3171e57e5e77SVivien Didelot int err; 3172fad09c73SVivien Didelot 3173ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 3174ee26a228SAndrew Lunn return -EOPNOTSUPP; 3175ee26a228SAndrew Lunn 3176c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3177ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 3178c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3179e57e5e77SVivien Didelot 3180da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 3181ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 3182ddc49acbSAndrew Lunn if (chip->info->family != MV88E6XXX_FAMILY_6165) 3183ddc49acbSAndrew Lunn /* Then there is the 6165 family. It gets is 3184ddc49acbSAndrew Lunn * PHYs correct. But it can also have two 3185ddc49acbSAndrew Lunn * SERDES interfaces in the PHY address 3186ddc49acbSAndrew Lunn * space. And these don't have a model 3187ddc49acbSAndrew Lunn * number. But they are not PHYs, so we don't 3188ddc49acbSAndrew Lunn * want to give them something a PHY driver 3189ddc49acbSAndrew Lunn * will recognise. 3190ddc49acbSAndrew Lunn * 3191ddc49acbSAndrew Lunn * Use the mv88e6390 family model number 3192ddc49acbSAndrew Lunn * instead, for anything which really could be 3193ddc49acbSAndrew Lunn * a PHY, 3194da9f3301SAndrew Lunn */ 3195da9f3301SAndrew Lunn if (!(val & 0x3f0)) 3196107fcc10SVivien Didelot val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 3197da9f3301SAndrew Lunn } 3198da9f3301SAndrew Lunn 3199e57e5e77SVivien Didelot return err ? err : val; 3200fad09c73SVivien Didelot } 3201fad09c73SVivien Didelot 3202e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 3203fad09c73SVivien Didelot { 32040dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 32050dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3206e57e5e77SVivien Didelot int err; 3207fad09c73SVivien Didelot 3208ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 3209ee26a228SAndrew Lunn return -EOPNOTSUPP; 3210ee26a228SAndrew Lunn 3211c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3212ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 3213c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3214e57e5e77SVivien Didelot 3215e57e5e77SVivien Didelot return err; 3216fad09c73SVivien Didelot } 3217fad09c73SVivien Didelot 3218fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 3219a3c53be5SAndrew Lunn struct device_node *np, 3220a3c53be5SAndrew Lunn bool external) 3221fad09c73SVivien Didelot { 3222fad09c73SVivien Didelot static int index; 32230dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 3224fad09c73SVivien Didelot struct mii_bus *bus; 3225fad09c73SVivien Didelot int err; 3226fad09c73SVivien Didelot 32272510babcSAndrew Lunn if (external) { 3228c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 32292510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 3230c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 32312510babcSAndrew Lunn 32322510babcSAndrew Lunn if (err) 32332510babcSAndrew Lunn return err; 32342510babcSAndrew Lunn } 32352510babcSAndrew Lunn 32360dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 3237fad09c73SVivien Didelot if (!bus) 3238fad09c73SVivien Didelot return -ENOMEM; 3239fad09c73SVivien Didelot 32400dd12d54SAndrew Lunn mdio_bus = bus->priv; 3241a3c53be5SAndrew Lunn mdio_bus->bus = bus; 32420dd12d54SAndrew Lunn mdio_bus->chip = chip; 3243a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 3244a3c53be5SAndrew Lunn mdio_bus->external = external; 32450dd12d54SAndrew Lunn 3246fad09c73SVivien Didelot if (np) { 3247fad09c73SVivien Didelot bus->name = np->full_name; 3248f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 3249fad09c73SVivien Didelot } else { 3250fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 3251fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 3252fad09c73SVivien Didelot } 3253fad09c73SVivien Didelot 3254fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 3255fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 3256fad09c73SVivien Didelot bus->parent = chip->dev; 3257fad09c73SVivien Didelot 32586f88284fSAndrew Lunn if (!external) { 32596f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 32606f88284fSAndrew Lunn if (err) 32616f88284fSAndrew Lunn return err; 32626f88284fSAndrew Lunn } 32636f88284fSAndrew Lunn 3264a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 3265fad09c73SVivien Didelot if (err) { 3266fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 32676f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 3268fad09c73SVivien Didelot return err; 3269fad09c73SVivien Didelot } 3270fad09c73SVivien Didelot 3271a3c53be5SAndrew Lunn if (external) 3272a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 3273a3c53be5SAndrew Lunn else 3274a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 3275a3c53be5SAndrew Lunn 3276a3c53be5SAndrew Lunn return 0; 3277a3c53be5SAndrew Lunn } 3278a3c53be5SAndrew Lunn 3279a3c53be5SAndrew Lunn static const struct of_device_id mv88e6xxx_mdio_external_match[] = { 3280a3c53be5SAndrew Lunn { .compatible = "marvell,mv88e6xxx-mdio-external", 3281a3c53be5SAndrew Lunn .data = (void *)true }, 3282a3c53be5SAndrew Lunn { }, 3283a3c53be5SAndrew Lunn }; 3284a3c53be5SAndrew Lunn 32853126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 32863126aeecSAndrew Lunn 32873126aeecSAndrew Lunn { 32883126aeecSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 32893126aeecSAndrew Lunn struct mii_bus *bus; 32903126aeecSAndrew Lunn 32913126aeecSAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 32923126aeecSAndrew Lunn bus = mdio_bus->bus; 32933126aeecSAndrew Lunn 32946f88284fSAndrew Lunn if (!mdio_bus->external) 32956f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 32966f88284fSAndrew Lunn 32973126aeecSAndrew Lunn mdiobus_unregister(bus); 32983126aeecSAndrew Lunn } 32993126aeecSAndrew Lunn } 33003126aeecSAndrew Lunn 3301a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 3302a3c53be5SAndrew Lunn struct device_node *np) 3303a3c53be5SAndrew Lunn { 3304a3c53be5SAndrew Lunn const struct of_device_id *match; 3305a3c53be5SAndrew Lunn struct device_node *child; 3306a3c53be5SAndrew Lunn int err; 3307a3c53be5SAndrew Lunn 3308a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 3309a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 3310a3c53be5SAndrew Lunn * optional. 3311a3c53be5SAndrew Lunn */ 3312a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 3313a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 3314a3c53be5SAndrew Lunn if (err) 3315a3c53be5SAndrew Lunn return err; 3316a3c53be5SAndrew Lunn 3317a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 3318a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 3319a3c53be5SAndrew Lunn * bus. 3320a3c53be5SAndrew Lunn */ 3321a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 3322a3c53be5SAndrew Lunn match = of_match_node(mv88e6xxx_mdio_external_match, child); 3323a3c53be5SAndrew Lunn if (match) { 3324a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 33253126aeecSAndrew Lunn if (err) { 33263126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 332778e42040SNishka Dasgupta of_node_put(child); 3328a3c53be5SAndrew Lunn return err; 3329a3c53be5SAndrew Lunn } 3330a3c53be5SAndrew Lunn } 33313126aeecSAndrew Lunn } 3332a3c53be5SAndrew Lunn 3333a3c53be5SAndrew Lunn return 0; 3334a3c53be5SAndrew Lunn } 3335a3c53be5SAndrew Lunn 3336855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 3337855b1932SVivien Didelot { 333804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3339855b1932SVivien Didelot 3340855b1932SVivien Didelot return chip->eeprom_len; 3341855b1932SVivien Didelot } 3342855b1932SVivien Didelot 3343855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 3344855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3345855b1932SVivien Didelot { 334604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3347855b1932SVivien Didelot int err; 3348855b1932SVivien Didelot 3349ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 3350ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3351ee4dc2e7SVivien Didelot 3352c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3353ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 3354c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3355855b1932SVivien Didelot 3356855b1932SVivien Didelot if (err) 3357855b1932SVivien Didelot return err; 3358855b1932SVivien Didelot 3359855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 3360855b1932SVivien Didelot 3361855b1932SVivien Didelot return 0; 3362855b1932SVivien Didelot } 3363855b1932SVivien Didelot 3364855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 3365855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3366855b1932SVivien Didelot { 336704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3368855b1932SVivien Didelot int err; 3369855b1932SVivien Didelot 3370ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 3371ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3372ee4dc2e7SVivien Didelot 3373855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 3374855b1932SVivien Didelot return -EINVAL; 3375855b1932SVivien Didelot 3376c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3377ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 3378c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3379855b1932SVivien Didelot 3380855b1932SVivien Didelot return err; 3381855b1932SVivien Didelot } 3382855b1932SVivien Didelot 3383b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 33844b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 338593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 338693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3387cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3388b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 33897e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 33907e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 339108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3392f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3393ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 339456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3395601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 339656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3397ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 33980898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3399c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34009dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34012d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3402121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3403a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 340440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3405dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3406dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3407052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3408fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3409fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3410fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 341151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34129e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3413a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3414a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 341517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 34169e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3417f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34180ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 34196c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3420b3469dd8SVivien Didelot }; 3421b3469dd8SVivien Didelot 3422b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 34234b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 342493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 342593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3426b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 34277e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 34287e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 342908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3430f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 343156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3432601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3433a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 34342d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3435121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3436a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 343740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3438dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3439dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3440052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 344151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3442a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3443a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 344417e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3445f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 34460ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 34476c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3448b3469dd8SVivien Didelot }; 3449b3469dd8SVivien Didelot 34507d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 345115da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 345293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 345393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3454cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 34557d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 34567d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 34577d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 34587d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 3459f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3460ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 346156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3462601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 346356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3464cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3465ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 34660898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3467c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34689dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34692d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3470121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 34717d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 347240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 34737d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 34747d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 34757d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 3476fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3477fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 347891eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 347951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34809e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 348117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 34829e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3483f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34840ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 34856c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 34867d381a02SStefan Eichenberger }; 34877d381a02SStefan Eichenberger 3488b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 34894b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 349093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 349193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3492cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3493b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3494ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3495ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 349608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3497f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 349856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3499601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3500c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35019dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35022d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3503121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 35040ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 350540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3506dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3507dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3508052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3509fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3510fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3511fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 351251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35139e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 351417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 351523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 351623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3517f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35180ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 35196c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3520b3469dd8SVivien Didelot }; 3521b3469dd8SVivien Didelot 3522b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 35234b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 352493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 352593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3526b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 35277e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 35287e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 352908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3530f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3531ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 353256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3533601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 353456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3535a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 3536cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3537ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35380898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 353954186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 35402d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3541121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3542a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 354340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3544dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3545dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3546052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3547fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3548fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3549fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 355051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3551a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 355202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3553a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 355417e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3555f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 35560ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 35576c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3558b3469dd8SVivien Didelot }; 3559b3469dd8SVivien Didelot 3560990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 3561990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 356293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 356393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3564cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3565990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 3566990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 3567990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3568990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3569990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 3570990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3571990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3572f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 35737cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 3574990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 3575990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3576990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3577990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3578cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3579990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35800898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3581990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 3582990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35832d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 35847a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 3585121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3586990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 358740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3588990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3589990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 3590990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3591fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3592fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 3593990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 3594990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 35959e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3596990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 3597f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35980ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3599d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 3600d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 3601a5a6858bSRussell King /* Check status register pause & lpa register */ 3602a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3603a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3604a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3605a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 36064241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 360761a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3608907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 3609a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 3610e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 3611990e27b0SVivien Didelot }; 3612990e27b0SVivien Didelot 3613b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 36144b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 361593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 361693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3617cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3618b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3619ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3620ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 362108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3622f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3623ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 362456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3625601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 362656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3627cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3628ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36290898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3630c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36319dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36322d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3633121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3634a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 363540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3636dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3637dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3638052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3639fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3640fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3641fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 364251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36439e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 364417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 364523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 364623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3647f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36480ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3649a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3650dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 36516c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3652b3469dd8SVivien Didelot }; 3653b3469dd8SVivien Didelot 3654b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 36554b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 365693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 365793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3658cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3659b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3660efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 3661efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 366208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3663f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3664c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36659dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36662d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3667121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3668a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 366940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3670dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3671dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3672052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3673fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3674fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3675fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 367651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36779e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 367817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 367923e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 368023e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3681f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36820ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3683a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3684dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 36856c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3686b3469dd8SVivien Didelot }; 3687b3469dd8SVivien Didelot 3688b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 36894b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 369093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 369193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3692cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3693b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3694b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3695b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 369608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 369794d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3698f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3699ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 370056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3701601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 370256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3703cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3704ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37050898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3706c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37079dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37082d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3709121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3710a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 371140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3712dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3713dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3714052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3715fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3716fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3717fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 371851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37199e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 372017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 372123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 372223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3723f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37240ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37256c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3726b3469dd8SVivien Didelot }; 3727b3469dd8SVivien Didelot 3728b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 37294b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 373093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 373193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3732cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3733ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3734ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3735b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3736b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3737b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 373808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3739a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3740f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 3741ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3742f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 374356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3744601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 374556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3746cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3747ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37480898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3749c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37509dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37512d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3752121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3753a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 375440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3755dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3756dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3757052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3758fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3759fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3760fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 376151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 37629e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 376317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 37649e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 376523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 376623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3767f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 37680ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 37699db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 3770a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 3771a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 3772a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 3773a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 37746d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3775d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3776d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3777a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 37786c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3779b3469dd8SVivien Didelot }; 3780b3469dd8SVivien Didelot 3781b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 37824b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 378393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 378493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3785cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3786b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3787b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3788b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 378908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 379094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3791f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3792ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 379356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3794601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 379556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3796cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3797ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 37980898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3799c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38009dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38012d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3802121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3803a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 380440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3805dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3806dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3807052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3808fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3809fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3810fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 381151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38129e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 381317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 381423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 381523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3816f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38170ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 38186c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3819b3469dd8SVivien Didelot }; 3820b3469dd8SVivien Didelot 3821b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 38224b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 382393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 382493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3825cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3826ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3827ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3828b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3829b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3830b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 383108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3832a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3833f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 3834ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3835f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 383656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3837601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 383856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3839cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3840ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 38410898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3842c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38439dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38442d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3845121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3846a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 384740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3848dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3849dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3850052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3851fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3852fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3853fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 385451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 38559e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 385617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38579e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 385823e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 385923e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3860f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 38610ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 38629db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 3863a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 3864a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 3865a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 3866a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 38676d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 38684241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 386961a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 3870907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 3871d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3872d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3873a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 38746c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3875b3469dd8SVivien Didelot }; 3876b3469dd8SVivien Didelot 3877b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 38784b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 387993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 388093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3881b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 38827e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 38837e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 388408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3885f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 388656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3887601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3888ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 3889a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 389054186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 38912d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3892121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3893a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 389440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3895dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3896dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3897052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3898fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3899fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3900fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 390151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 390202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3903a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3904a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 390517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3906f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 39070ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 39086c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3909b3469dd8SVivien Didelot }; 3910b3469dd8SVivien Didelot 39111a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 39124b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3913ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3914cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 391598fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 391698fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 39171a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 39181a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 39191a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 39201a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 39211a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3922f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 39237cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3924ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 3925f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 392656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3927601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 392856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 39290898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3930c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39319dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39322d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3933fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 3934121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 393579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3936de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3937dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3938dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3939e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3940fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3941fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 394261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 39436e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 39449e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 394517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 39469e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 394723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 394823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3949931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3950931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 39516335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 395217deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 3953a5a6858bSRussell King /* Check status register pause & lpa register */ 3954a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3955a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3956a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3957a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 39584241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 395961a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3960907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 39614262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 39624262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 3963bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3964bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 39654262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 3966a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39676c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 39681a3b39ecSAndrew Lunn }; 39691a3b39ecSAndrew Lunn 39701a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 39714b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3972ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3973cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 397498fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 397598fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 39761a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 39771a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 39781a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 39791a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 39801a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3981f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 39827cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 3983ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 3984f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 398556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3986601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 398756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 39880898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3989c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39909dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39912d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3992fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 3993121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 399479523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3995de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3996dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3997dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3998e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3999fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4000fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 400161303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 40026e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 40039e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 400417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 40059e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 400623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 400723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4008931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4009931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4010d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 401117deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 4012a5a6858bSRussell King /* Check status register pause & lpa register */ 4013a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4014a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4015a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4016a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 40174241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 401861a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4019907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 40204262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 40214262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4022bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4023bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 40244262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 4025a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 40266c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 40271a3b39ecSAndrew Lunn }; 40281a3b39ecSAndrew Lunn 40291a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 40304b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4031ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4032cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 403398fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 403498fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 40351a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 40361a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 40371a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 40381a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 40391a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4040f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 40417cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4042ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 404356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4044601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 404556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 40460898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4047c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40489dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40492d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4050fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4051121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 405279523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4053de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4054dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4055dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4056e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4057fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4058fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 405961303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 40606e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 40619e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 406217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 40639e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 406423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 406523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4066931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4067931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 40686335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 406917deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4070a5a6858bSRussell King /* Check status register pause & lpa register */ 4071a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4072a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4073a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4074a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 40754241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 407661a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4077907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 40784262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 40794262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4080bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4081bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 40824262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 40836d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 40846d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 40856c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 40861a3b39ecSAndrew Lunn }; 40871a3b39ecSAndrew Lunn 4088b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 40894b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 409093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 409193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4092cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4093ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4094ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4095b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4096b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4097b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 409808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4099a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4100f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4101ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4102f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 410356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4104601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 410556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4106cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4107ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 41080898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4109c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41109dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41112d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4112121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4113a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 411440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4115dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4116dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4117052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4118fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4119fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4120fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 412151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 41229e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 412317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 41249e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 412523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 412623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4127f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 41280ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 41299db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4130a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4131a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4132a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4133a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 41346d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 41354241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 413661a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4137907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4138d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4139d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4140a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 41410d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 41426d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 41436c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4144b3469dd8SVivien Didelot }; 4145b3469dd8SVivien Didelot 41461f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = { 41471f71836fSRasmus Villemoes /* MV88E6XXX_FAMILY_6250 */ 41481f71836fSRasmus Villemoes .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 41491f71836fSRasmus Villemoes .ip_pri_map = mv88e6085_g1_ip_pri_map, 41501f71836fSRasmus Villemoes .irl_init_all = mv88e6352_g2_irl_init_all, 41511f71836fSRasmus Villemoes .get_eeprom = mv88e6xxx_g2_get_eeprom16, 41521f71836fSRasmus Villemoes .set_eeprom = mv88e6xxx_g2_set_eeprom16, 41531f71836fSRasmus Villemoes .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41541f71836fSRasmus Villemoes .phy_read = mv88e6xxx_g2_smi_phy_read, 41551f71836fSRasmus Villemoes .phy_write = mv88e6xxx_g2_smi_phy_write, 41561f71836fSRasmus Villemoes .port_set_link = mv88e6xxx_port_set_link, 41571f71836fSRasmus Villemoes .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4158f365c6f7SRussell King .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, 41591f71836fSRasmus Villemoes .port_tag_remap = mv88e6095_port_tag_remap, 41601f71836fSRasmus Villemoes .port_set_frame_mode = mv88e6351_port_set_frame_mode, 41611f71836fSRasmus Villemoes .port_set_egress_floods = mv88e6352_port_set_egress_floods, 41621f71836fSRasmus Villemoes .port_set_ether_type = mv88e6351_port_set_ether_type, 41631f71836fSRasmus Villemoes .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 41641f71836fSRasmus Villemoes .port_pause_limit = mv88e6097_port_pause_limit, 41651f71836fSRasmus Villemoes .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41661f71836fSRasmus Villemoes .stats_snapshot = mv88e6320_g1_stats_snapshot, 41671f71836fSRasmus Villemoes .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 41681f71836fSRasmus Villemoes .stats_get_sset_count = mv88e6250_stats_get_sset_count, 41691f71836fSRasmus Villemoes .stats_get_strings = mv88e6250_stats_get_strings, 41701f71836fSRasmus Villemoes .stats_get_stats = mv88e6250_stats_get_stats, 41711f71836fSRasmus Villemoes .set_cpu_port = mv88e6095_g1_set_cpu_port, 41721f71836fSRasmus Villemoes .set_egress_port = mv88e6095_g1_set_egress_port, 41731f71836fSRasmus Villemoes .watchdog_ops = &mv88e6250_watchdog_ops, 41741f71836fSRasmus Villemoes .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 41751f71836fSRasmus Villemoes .pot_clear = mv88e6xxx_g2_pot_clear, 41761f71836fSRasmus Villemoes .reset = mv88e6250_g1_reset, 41771f71836fSRasmus Villemoes .vtu_getnext = mv88e6250_g1_vtu_getnext, 41781f71836fSRasmus Villemoes .vtu_loadpurge = mv88e6250_g1_vtu_loadpurge, 417971509614SHubert Feurstein .avb_ops = &mv88e6352_avb_ops, 418071509614SHubert Feurstein .ptp_ops = &mv88e6250_ptp_ops, 41811f71836fSRasmus Villemoes .phylink_validate = mv88e6065_phylink_validate, 41821f71836fSRasmus Villemoes }; 41831f71836fSRasmus Villemoes 41841a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 41854b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4186ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4187cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 418898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 418998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 41901a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41911a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 41921a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 41931a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 41941a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4195f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 41967cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4197ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4198f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 419956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4200601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 420156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 42020898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4203c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42049dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42052d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4206fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4207121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 420879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4209de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4210dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4211dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4212e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4213fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4214fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 421561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 42166e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 42179e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 421817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 42199e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 422023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 422123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4222931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4223931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 42246335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 422517deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4226a5a6858bSRussell King /* Check status register pause & lpa register */ 4227a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4228a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4229a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4230a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 42314241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 423261a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4233907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 42344262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 42354262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4236bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4237bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 42384262c38dSAndrew Lunn .phylink_validate = mv88e6390_phylink_validate, 4239a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 42400d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 42416d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 42426c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 42431a3b39ecSAndrew Lunn }; 42441a3b39ecSAndrew Lunn 4245b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 42464b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 424793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 424893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4249cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4250ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4251ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4252b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4253b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4254b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 425508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4256f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4257ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 425856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4259601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 426056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4261cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4262ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42630898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4264c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42659dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42662d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4267121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4268a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 426940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4270dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4271dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4272052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4273fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4274fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 42759c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 427651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 42779e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 427817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4279f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 42800ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4281a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 42820d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 42836d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 42846c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4285b3469dd8SVivien Didelot }; 4286b3469dd8SVivien Didelot 4287b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 4288bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 428993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 429093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4291cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4292ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4293ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4294b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4295b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4296b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 429708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4298f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4299ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 430056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4301601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 430256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4303cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4304ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43050898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4306c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43079dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43082d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4309121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4310a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 431140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4312dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4313dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4314052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4315fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4316fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 43179c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 431817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4319f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 43200ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4321a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 43220d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 43236d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 43246c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4325b3469dd8SVivien Didelot }; 4326b3469dd8SVivien Didelot 432716e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 432816e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 432993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 433093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4331cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 433216e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 433316e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 433416e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 433516e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 433616e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 433716e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 433816e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4339f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 43407cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 434116e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 434216e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 434316e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 434416e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 4345cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 434616e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43470898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 434816e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 434916e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43502d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 43517a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 4352121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 435316e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 435440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 435516e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 435616e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 435716e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 4358fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4359fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 436016e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 436116e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 43629e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 436316e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 4364f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43650ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4366d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 4367d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 4368a5a6858bSRussell King /* Check status register pause & lpa register */ 4369a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4370a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4371a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4372a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 43734241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 437461a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4375907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4376a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 43770d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 43786d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4379e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 438016e329aeSVivien Didelot }; 438116e329aeSVivien Didelot 4382b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 43834b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 438493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 438593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4386cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4387b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4388b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4389b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 439008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 439194d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4392f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4393ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 439456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4395601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 439656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4397cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4398ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43990898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4400c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44019dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44022d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4403121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4404a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 440540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4406dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4407dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4408052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4409fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4410fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4411fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 441251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44139e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 441417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 441523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 441623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4417f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 44180ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 44196c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4420b3469dd8SVivien Didelot }; 4421b3469dd8SVivien Didelot 4422b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 44234b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 442493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 442593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4426cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4427b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4428b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4429b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 443008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 443194d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4432f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4433ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 443456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4435601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 443656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4437cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4438ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44390898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4440c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44419dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44422d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4443121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4444a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 444540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4446dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4447dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4448052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4449fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4450fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4451fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 445251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44539e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 445417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 445523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 445623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4457f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 44580ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 44590d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 44606d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 44616c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4462b3469dd8SVivien Didelot }; 4463b3469dd8SVivien Didelot 4464b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 44654b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 446693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 446793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4468cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4469ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4470ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4471b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4472b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4473b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 447408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4475a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4476f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4477ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4478f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 447956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4480601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 448156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4482cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4483ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44840898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4485c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44869dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44872d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4488121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4489a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 449040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4491dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4492dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4493052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4494fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4495fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4496fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 449751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44989e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 449917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 45009e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 450123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 450223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4503f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 45040ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 45059db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4506a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4507a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4508a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4509a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 45106d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 45114241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 451261a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4513907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4514a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 45150d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 45166d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4517cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 4518cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 4519cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 4520d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4521d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 45226c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4523b3469dd8SVivien Didelot }; 4524b3469dd8SVivien Didelot 45251a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 45264b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4527ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4528cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 452998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 453098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 45311a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 45321a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 45331a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 45341a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 45351a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4536f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 45377cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4538ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4539f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 454056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4541601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 454256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4543cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4544ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 45450898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4546c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 45479dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45482d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4549fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4550121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 455179523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4552de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4553dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4554dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4555e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4556fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4557fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 455861303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 45596e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 45609e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 456117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 45629e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 456323e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 456423e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4565931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4566931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 45676335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 456817deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4569a5a6858bSRussell King /* Check status register pause & lpa register */ 4570a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4571a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4572a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4573a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 45744241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 457561a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4576907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4577a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 45780d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 45796d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 45800df95287SNikita Yushchenko .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 45810df95287SNikita Yushchenko .serdes_get_strings = mv88e6390_serdes_get_strings, 45820df95287SNikita Yushchenko .serdes_get_stats = mv88e6390_serdes_get_stats, 4583bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4584bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 45856c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 45861a3b39ecSAndrew Lunn }; 45871a3b39ecSAndrew Lunn 45881a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 45894b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4590ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4591cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 459298fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 459398fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 45941a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 45951a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 45961a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 45971a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 45981a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4599f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 46007cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 4601ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4602f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 460356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4604601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 460556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4606cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4607ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 46080898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4609c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 46109dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 46112d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4612b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 4613121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 461479523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4615de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4616dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4617dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4618e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4619fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4620fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 462161303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 46226e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 46239e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 462417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 46259e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 462623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 462723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4628931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4629931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4630d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 463117deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 4632a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4633a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4634a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4635a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 46364241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 463761a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4638907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 46394262c38dSAndrew Lunn .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 46404262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 46414262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4642bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4643bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4644a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 46450d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 46466d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 46476c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 46481a3b39ecSAndrew Lunn }; 46491a3b39ecSAndrew Lunn 4650fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 4651fad09c73SVivien Didelot [MV88E6085] = { 4652107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 4653fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 4654fad09c73SVivien Didelot .name = "Marvell 88E6085", 4655fad09c73SVivien Didelot .num_databases = 4096, 4656d9ea5620SAndrew Lunn .num_macs = 8192, 4657fad09c73SVivien Didelot .num_ports = 10, 4658bc393155SAndrew Lunn .num_internal_phys = 5, 46593cf3c846SVivien Didelot .max_vid = 4095, 4660fad09c73SVivien Didelot .port_base_addr = 0x10, 46619255bacdSAndrew Lunn .phy_base_addr = 0x0, 4662a935c052SVivien Didelot .global1_addr = 0x1b, 46639069c13aSVivien Didelot .global2_addr = 0x1c, 4664acddbd21SVivien Didelot .age_time_coeff = 15000, 4665dc30c35bSAndrew Lunn .g1_irqs = 8, 4666d6c5e6afSVivien Didelot .g2_irqs = 10, 4667e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4668f3645652SVivien Didelot .pvt = true, 4669b3e05aa1SVivien Didelot .multi_chip = true, 4670443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4671b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 4672fad09c73SVivien Didelot }, 4673fad09c73SVivien Didelot 4674fad09c73SVivien Didelot [MV88E6095] = { 4675107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 4676fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 4677fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 4678fad09c73SVivien Didelot .num_databases = 256, 4679d9ea5620SAndrew Lunn .num_macs = 8192, 4680fad09c73SVivien Didelot .num_ports = 11, 4681bc393155SAndrew Lunn .num_internal_phys = 0, 46823cf3c846SVivien Didelot .max_vid = 4095, 4683fad09c73SVivien Didelot .port_base_addr = 0x10, 46849255bacdSAndrew Lunn .phy_base_addr = 0x0, 4685a935c052SVivien Didelot .global1_addr = 0x1b, 46869069c13aSVivien Didelot .global2_addr = 0x1c, 4687acddbd21SVivien Didelot .age_time_coeff = 15000, 4688dc30c35bSAndrew Lunn .g1_irqs = 8, 4689e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4690b3e05aa1SVivien Didelot .multi_chip = true, 4691443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4692b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 4693fad09c73SVivien Didelot }, 4694fad09c73SVivien Didelot 46957d381a02SStefan Eichenberger [MV88E6097] = { 4696107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 46977d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 46987d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 46997d381a02SStefan Eichenberger .num_databases = 4096, 4700d9ea5620SAndrew Lunn .num_macs = 8192, 47017d381a02SStefan Eichenberger .num_ports = 11, 4702bc393155SAndrew Lunn .num_internal_phys = 8, 47033cf3c846SVivien Didelot .max_vid = 4095, 47047d381a02SStefan Eichenberger .port_base_addr = 0x10, 47059255bacdSAndrew Lunn .phy_base_addr = 0x0, 47067d381a02SStefan Eichenberger .global1_addr = 0x1b, 47079069c13aSVivien Didelot .global2_addr = 0x1c, 47087d381a02SStefan Eichenberger .age_time_coeff = 15000, 4709c534178bSStefan Eichenberger .g1_irqs = 8, 4710d6c5e6afSVivien Didelot .g2_irqs = 10, 4711e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4712f3645652SVivien Didelot .pvt = true, 4713b3e05aa1SVivien Didelot .multi_chip = true, 47142bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 47157d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 47167d381a02SStefan Eichenberger }, 47177d381a02SStefan Eichenberger 4718fad09c73SVivien Didelot [MV88E6123] = { 4719107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 4720fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4721fad09c73SVivien Didelot .name = "Marvell 88E6123", 4722fad09c73SVivien Didelot .num_databases = 4096, 4723d9ea5620SAndrew Lunn .num_macs = 1024, 4724fad09c73SVivien Didelot .num_ports = 3, 4725bc393155SAndrew Lunn .num_internal_phys = 5, 47263cf3c846SVivien Didelot .max_vid = 4095, 4727fad09c73SVivien Didelot .port_base_addr = 0x10, 47289255bacdSAndrew Lunn .phy_base_addr = 0x0, 4729a935c052SVivien Didelot .global1_addr = 0x1b, 47309069c13aSVivien Didelot .global2_addr = 0x1c, 4731acddbd21SVivien Didelot .age_time_coeff = 15000, 4732dc30c35bSAndrew Lunn .g1_irqs = 9, 4733d6c5e6afSVivien Didelot .g2_irqs = 10, 4734e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4735f3645652SVivien Didelot .pvt = true, 4736b3e05aa1SVivien Didelot .multi_chip = true, 47375ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4738b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 4739fad09c73SVivien Didelot }, 4740fad09c73SVivien Didelot 4741fad09c73SVivien Didelot [MV88E6131] = { 4742107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 4743fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4744fad09c73SVivien Didelot .name = "Marvell 88E6131", 4745fad09c73SVivien Didelot .num_databases = 256, 4746d9ea5620SAndrew Lunn .num_macs = 8192, 4747fad09c73SVivien Didelot .num_ports = 8, 4748bc393155SAndrew Lunn .num_internal_phys = 0, 47493cf3c846SVivien Didelot .max_vid = 4095, 4750fad09c73SVivien Didelot .port_base_addr = 0x10, 47519255bacdSAndrew Lunn .phy_base_addr = 0x0, 4752a935c052SVivien Didelot .global1_addr = 0x1b, 47539069c13aSVivien Didelot .global2_addr = 0x1c, 4754acddbd21SVivien Didelot .age_time_coeff = 15000, 4755dc30c35bSAndrew Lunn .g1_irqs = 9, 4756e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4757b3e05aa1SVivien Didelot .multi_chip = true, 4758443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4759b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 4760fad09c73SVivien Didelot }, 4761fad09c73SVivien Didelot 4762990e27b0SVivien Didelot [MV88E6141] = { 4763107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 4764990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 476579a68b26SUwe Kleine-König .name = "Marvell 88E6141", 4766990e27b0SVivien Didelot .num_databases = 4096, 4767d9ea5620SAndrew Lunn .num_macs = 2048, 4768990e27b0SVivien Didelot .num_ports = 6, 4769bc393155SAndrew Lunn .num_internal_phys = 5, 4770a73ccd61SBrandon Streiff .num_gpio = 11, 47713cf3c846SVivien Didelot .max_vid = 4095, 4772990e27b0SVivien Didelot .port_base_addr = 0x10, 47739255bacdSAndrew Lunn .phy_base_addr = 0x10, 4774990e27b0SVivien Didelot .global1_addr = 0x1b, 47759069c13aSVivien Didelot .global2_addr = 0x1c, 4776990e27b0SVivien Didelot .age_time_coeff = 3750, 4777990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 4778adfccf11SAndrew Lunn .g1_irqs = 9, 4779d6c5e6afSVivien Didelot .g2_irqs = 10, 4780f3645652SVivien Didelot .pvt = true, 4781b3e05aa1SVivien Didelot .multi_chip = true, 4782990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 4783990e27b0SVivien Didelot .ops = &mv88e6141_ops, 4784990e27b0SVivien Didelot }, 4785990e27b0SVivien Didelot 4786fad09c73SVivien Didelot [MV88E6161] = { 4787107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 4788fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4789fad09c73SVivien Didelot .name = "Marvell 88E6161", 4790fad09c73SVivien Didelot .num_databases = 4096, 4791d9ea5620SAndrew Lunn .num_macs = 1024, 4792fad09c73SVivien Didelot .num_ports = 6, 4793bc393155SAndrew Lunn .num_internal_phys = 5, 47943cf3c846SVivien Didelot .max_vid = 4095, 4795fad09c73SVivien Didelot .port_base_addr = 0x10, 47969255bacdSAndrew Lunn .phy_base_addr = 0x0, 4797a935c052SVivien Didelot .global1_addr = 0x1b, 47989069c13aSVivien Didelot .global2_addr = 0x1c, 4799acddbd21SVivien Didelot .age_time_coeff = 15000, 4800dc30c35bSAndrew Lunn .g1_irqs = 9, 4801d6c5e6afSVivien Didelot .g2_irqs = 10, 4802e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4803f3645652SVivien Didelot .pvt = true, 4804b3e05aa1SVivien Didelot .multi_chip = true, 48055ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4806dfa54348SAndrew Lunn .ptp_support = true, 4807b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 4808fad09c73SVivien Didelot }, 4809fad09c73SVivien Didelot 4810fad09c73SVivien Didelot [MV88E6165] = { 4811107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 4812fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4813fad09c73SVivien Didelot .name = "Marvell 88E6165", 4814fad09c73SVivien Didelot .num_databases = 4096, 4815d9ea5620SAndrew Lunn .num_macs = 8192, 4816fad09c73SVivien Didelot .num_ports = 6, 4817bc393155SAndrew Lunn .num_internal_phys = 0, 48183cf3c846SVivien Didelot .max_vid = 4095, 4819fad09c73SVivien Didelot .port_base_addr = 0x10, 48209255bacdSAndrew Lunn .phy_base_addr = 0x0, 4821a935c052SVivien Didelot .global1_addr = 0x1b, 48229069c13aSVivien Didelot .global2_addr = 0x1c, 4823acddbd21SVivien Didelot .age_time_coeff = 15000, 4824dc30c35bSAndrew Lunn .g1_irqs = 9, 4825d6c5e6afSVivien Didelot .g2_irqs = 10, 4826e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4827f3645652SVivien Didelot .pvt = true, 4828b3e05aa1SVivien Didelot .multi_chip = true, 4829443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4830dfa54348SAndrew Lunn .ptp_support = true, 4831b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 4832fad09c73SVivien Didelot }, 4833fad09c73SVivien Didelot 4834fad09c73SVivien Didelot [MV88E6171] = { 4835107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 4836fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4837fad09c73SVivien Didelot .name = "Marvell 88E6171", 4838fad09c73SVivien Didelot .num_databases = 4096, 4839d9ea5620SAndrew Lunn .num_macs = 8192, 4840fad09c73SVivien Didelot .num_ports = 7, 4841bc393155SAndrew Lunn .num_internal_phys = 5, 48423cf3c846SVivien Didelot .max_vid = 4095, 4843fad09c73SVivien Didelot .port_base_addr = 0x10, 48449255bacdSAndrew Lunn .phy_base_addr = 0x0, 4845a935c052SVivien Didelot .global1_addr = 0x1b, 48469069c13aSVivien Didelot .global2_addr = 0x1c, 4847acddbd21SVivien Didelot .age_time_coeff = 15000, 4848dc30c35bSAndrew Lunn .g1_irqs = 9, 4849d6c5e6afSVivien Didelot .g2_irqs = 10, 4850e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4851f3645652SVivien Didelot .pvt = true, 4852b3e05aa1SVivien Didelot .multi_chip = true, 4853443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4854b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 4855fad09c73SVivien Didelot }, 4856fad09c73SVivien Didelot 4857fad09c73SVivien Didelot [MV88E6172] = { 4858107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 4859fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4860fad09c73SVivien Didelot .name = "Marvell 88E6172", 4861fad09c73SVivien Didelot .num_databases = 4096, 4862d9ea5620SAndrew Lunn .num_macs = 8192, 4863fad09c73SVivien Didelot .num_ports = 7, 4864bc393155SAndrew Lunn .num_internal_phys = 5, 4865a73ccd61SBrandon Streiff .num_gpio = 15, 48663cf3c846SVivien Didelot .max_vid = 4095, 4867fad09c73SVivien Didelot .port_base_addr = 0x10, 48689255bacdSAndrew Lunn .phy_base_addr = 0x0, 4869a935c052SVivien Didelot .global1_addr = 0x1b, 48709069c13aSVivien Didelot .global2_addr = 0x1c, 4871acddbd21SVivien Didelot .age_time_coeff = 15000, 4872dc30c35bSAndrew Lunn .g1_irqs = 9, 4873d6c5e6afSVivien Didelot .g2_irqs = 10, 4874e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4875f3645652SVivien Didelot .pvt = true, 4876b3e05aa1SVivien Didelot .multi_chip = true, 4877443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4878b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 4879fad09c73SVivien Didelot }, 4880fad09c73SVivien Didelot 4881fad09c73SVivien Didelot [MV88E6175] = { 4882107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 4883fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4884fad09c73SVivien Didelot .name = "Marvell 88E6175", 4885fad09c73SVivien Didelot .num_databases = 4096, 4886d9ea5620SAndrew Lunn .num_macs = 8192, 4887fad09c73SVivien Didelot .num_ports = 7, 4888bc393155SAndrew Lunn .num_internal_phys = 5, 48893cf3c846SVivien Didelot .max_vid = 4095, 4890fad09c73SVivien Didelot .port_base_addr = 0x10, 48919255bacdSAndrew Lunn .phy_base_addr = 0x0, 4892a935c052SVivien Didelot .global1_addr = 0x1b, 48939069c13aSVivien Didelot .global2_addr = 0x1c, 4894acddbd21SVivien Didelot .age_time_coeff = 15000, 4895dc30c35bSAndrew Lunn .g1_irqs = 9, 4896d6c5e6afSVivien Didelot .g2_irqs = 10, 4897e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4898f3645652SVivien Didelot .pvt = true, 4899b3e05aa1SVivien Didelot .multi_chip = true, 4900443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4901b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 4902fad09c73SVivien Didelot }, 4903fad09c73SVivien Didelot 4904fad09c73SVivien Didelot [MV88E6176] = { 4905107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 4906fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4907fad09c73SVivien Didelot .name = "Marvell 88E6176", 4908fad09c73SVivien Didelot .num_databases = 4096, 4909d9ea5620SAndrew Lunn .num_macs = 8192, 4910fad09c73SVivien Didelot .num_ports = 7, 4911bc393155SAndrew Lunn .num_internal_phys = 5, 4912a73ccd61SBrandon Streiff .num_gpio = 15, 49133cf3c846SVivien Didelot .max_vid = 4095, 4914fad09c73SVivien Didelot .port_base_addr = 0x10, 49159255bacdSAndrew Lunn .phy_base_addr = 0x0, 4916a935c052SVivien Didelot .global1_addr = 0x1b, 49179069c13aSVivien Didelot .global2_addr = 0x1c, 4918acddbd21SVivien Didelot .age_time_coeff = 15000, 4919dc30c35bSAndrew Lunn .g1_irqs = 9, 4920d6c5e6afSVivien Didelot .g2_irqs = 10, 4921e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4922f3645652SVivien Didelot .pvt = true, 4923b3e05aa1SVivien Didelot .multi_chip = true, 4924443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4925b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 4926fad09c73SVivien Didelot }, 4927fad09c73SVivien Didelot 4928fad09c73SVivien Didelot [MV88E6185] = { 4929107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 4930fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4931fad09c73SVivien Didelot .name = "Marvell 88E6185", 4932fad09c73SVivien Didelot .num_databases = 256, 4933d9ea5620SAndrew Lunn .num_macs = 8192, 4934fad09c73SVivien Didelot .num_ports = 10, 4935bc393155SAndrew Lunn .num_internal_phys = 0, 49363cf3c846SVivien Didelot .max_vid = 4095, 4937fad09c73SVivien Didelot .port_base_addr = 0x10, 49389255bacdSAndrew Lunn .phy_base_addr = 0x0, 4939a935c052SVivien Didelot .global1_addr = 0x1b, 49409069c13aSVivien Didelot .global2_addr = 0x1c, 4941acddbd21SVivien Didelot .age_time_coeff = 15000, 4942dc30c35bSAndrew Lunn .g1_irqs = 8, 4943e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4944b3e05aa1SVivien Didelot .multi_chip = true, 4945443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4946b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 4947fad09c73SVivien Didelot }, 4948fad09c73SVivien Didelot 49491a3b39ecSAndrew Lunn [MV88E6190] = { 4950107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 49511a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 49521a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 49531a3b39ecSAndrew Lunn .num_databases = 4096, 4954d9ea5620SAndrew Lunn .num_macs = 16384, 49551a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 495695150f29SHeiner Kallweit .num_internal_phys = 9, 4957a73ccd61SBrandon Streiff .num_gpio = 16, 4958931d1822SVivien Didelot .max_vid = 8191, 49591a3b39ecSAndrew Lunn .port_base_addr = 0x0, 49609255bacdSAndrew Lunn .phy_base_addr = 0x0, 49611a3b39ecSAndrew Lunn .global1_addr = 0x1b, 49629069c13aSVivien Didelot .global2_addr = 0x1c, 4963443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4964b91e055cSAndrew Lunn .age_time_coeff = 3750, 49651a3b39ecSAndrew Lunn .g1_irqs = 9, 4966d6c5e6afSVivien Didelot .g2_irqs = 14, 4967f3645652SVivien Didelot .pvt = true, 4968b3e05aa1SVivien Didelot .multi_chip = true, 4969e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 49701a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 49711a3b39ecSAndrew Lunn }, 49721a3b39ecSAndrew Lunn 49731a3b39ecSAndrew Lunn [MV88E6190X] = { 4974107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 49751a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 49761a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 49771a3b39ecSAndrew Lunn .num_databases = 4096, 4978d9ea5620SAndrew Lunn .num_macs = 16384, 49791a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 498095150f29SHeiner Kallweit .num_internal_phys = 9, 4981a73ccd61SBrandon Streiff .num_gpio = 16, 4982931d1822SVivien Didelot .max_vid = 8191, 49831a3b39ecSAndrew Lunn .port_base_addr = 0x0, 49849255bacdSAndrew Lunn .phy_base_addr = 0x0, 49851a3b39ecSAndrew Lunn .global1_addr = 0x1b, 49869069c13aSVivien Didelot .global2_addr = 0x1c, 4987b91e055cSAndrew Lunn .age_time_coeff = 3750, 49881a3b39ecSAndrew Lunn .g1_irqs = 9, 4989d6c5e6afSVivien Didelot .g2_irqs = 14, 4990e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4991f3645652SVivien Didelot .pvt = true, 4992b3e05aa1SVivien Didelot .multi_chip = true, 4993443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 49941a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 49951a3b39ecSAndrew Lunn }, 49961a3b39ecSAndrew Lunn 49971a3b39ecSAndrew Lunn [MV88E6191] = { 4998107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 49991a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 50001a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 50011a3b39ecSAndrew Lunn .num_databases = 4096, 5002d9ea5620SAndrew Lunn .num_macs = 16384, 50031a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 500495150f29SHeiner Kallweit .num_internal_phys = 9, 5005931d1822SVivien Didelot .max_vid = 8191, 50061a3b39ecSAndrew Lunn .port_base_addr = 0x0, 50079255bacdSAndrew Lunn .phy_base_addr = 0x0, 50081a3b39ecSAndrew Lunn .global1_addr = 0x1b, 50099069c13aSVivien Didelot .global2_addr = 0x1c, 5010b91e055cSAndrew Lunn .age_time_coeff = 3750, 5011443d5a1bSAndrew Lunn .g1_irqs = 9, 5012d6c5e6afSVivien Didelot .g2_irqs = 14, 5013e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5014f3645652SVivien Didelot .pvt = true, 5015b3e05aa1SVivien Didelot .multi_chip = true, 5016443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 50172fa8d3afSBrandon Streiff .ptp_support = true, 50182cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 50191a3b39ecSAndrew Lunn }, 50201a3b39ecSAndrew Lunn 502149022647SHubert Feurstein [MV88E6220] = { 502249022647SHubert Feurstein .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220, 502349022647SHubert Feurstein .family = MV88E6XXX_FAMILY_6250, 502449022647SHubert Feurstein .name = "Marvell 88E6220", 502549022647SHubert Feurstein .num_databases = 64, 502649022647SHubert Feurstein 502749022647SHubert Feurstein /* Ports 2-4 are not routed to pins 502849022647SHubert Feurstein * => usable ports 0, 1, 5, 6 502949022647SHubert Feurstein */ 503049022647SHubert Feurstein .num_ports = 7, 503149022647SHubert Feurstein .num_internal_phys = 2, 5032c857486aSHubert Feurstein .invalid_port_mask = BIT(2) | BIT(3) | BIT(4), 503349022647SHubert Feurstein .max_vid = 4095, 503449022647SHubert Feurstein .port_base_addr = 0x08, 503549022647SHubert Feurstein .phy_base_addr = 0x00, 503649022647SHubert Feurstein .global1_addr = 0x0f, 503749022647SHubert Feurstein .global2_addr = 0x07, 503849022647SHubert Feurstein .age_time_coeff = 15000, 503949022647SHubert Feurstein .g1_irqs = 9, 504049022647SHubert Feurstein .g2_irqs = 10, 504149022647SHubert Feurstein .atu_move_port_mask = 0xf, 504249022647SHubert Feurstein .dual_chip = true, 504349022647SHubert Feurstein .tag_protocol = DSA_TAG_PROTO_DSA, 504471509614SHubert Feurstein .ptp_support = true, 504549022647SHubert Feurstein .ops = &mv88e6250_ops, 504649022647SHubert Feurstein }, 504749022647SHubert Feurstein 5048fad09c73SVivien Didelot [MV88E6240] = { 5049107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 5050fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5051fad09c73SVivien Didelot .name = "Marvell 88E6240", 5052fad09c73SVivien Didelot .num_databases = 4096, 5053d9ea5620SAndrew Lunn .num_macs = 8192, 5054fad09c73SVivien Didelot .num_ports = 7, 5055bc393155SAndrew Lunn .num_internal_phys = 5, 5056a73ccd61SBrandon Streiff .num_gpio = 15, 50573cf3c846SVivien Didelot .max_vid = 4095, 5058fad09c73SVivien Didelot .port_base_addr = 0x10, 50599255bacdSAndrew Lunn .phy_base_addr = 0x0, 5060a935c052SVivien Didelot .global1_addr = 0x1b, 50619069c13aSVivien Didelot .global2_addr = 0x1c, 5062acddbd21SVivien Didelot .age_time_coeff = 15000, 5063dc30c35bSAndrew Lunn .g1_irqs = 9, 5064d6c5e6afSVivien Didelot .g2_irqs = 10, 5065e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5066f3645652SVivien Didelot .pvt = true, 5067b3e05aa1SVivien Didelot .multi_chip = true, 5068443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 50692fa8d3afSBrandon Streiff .ptp_support = true, 5070b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 5071fad09c73SVivien Didelot }, 5072fad09c73SVivien Didelot 50731f71836fSRasmus Villemoes [MV88E6250] = { 50741f71836fSRasmus Villemoes .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 50751f71836fSRasmus Villemoes .family = MV88E6XXX_FAMILY_6250, 50761f71836fSRasmus Villemoes .name = "Marvell 88E6250", 50771f71836fSRasmus Villemoes .num_databases = 64, 50781f71836fSRasmus Villemoes .num_ports = 7, 50791f71836fSRasmus Villemoes .num_internal_phys = 5, 50801f71836fSRasmus Villemoes .max_vid = 4095, 50811f71836fSRasmus Villemoes .port_base_addr = 0x08, 50821f71836fSRasmus Villemoes .phy_base_addr = 0x00, 50831f71836fSRasmus Villemoes .global1_addr = 0x0f, 50841f71836fSRasmus Villemoes .global2_addr = 0x07, 50851f71836fSRasmus Villemoes .age_time_coeff = 15000, 50861f71836fSRasmus Villemoes .g1_irqs = 9, 50871f71836fSRasmus Villemoes .g2_irqs = 10, 50881f71836fSRasmus Villemoes .atu_move_port_mask = 0xf, 50891f71836fSRasmus Villemoes .dual_chip = true, 50901f71836fSRasmus Villemoes .tag_protocol = DSA_TAG_PROTO_DSA, 509171509614SHubert Feurstein .ptp_support = true, 50921f71836fSRasmus Villemoes .ops = &mv88e6250_ops, 50931f71836fSRasmus Villemoes }, 50941f71836fSRasmus Villemoes 50951a3b39ecSAndrew Lunn [MV88E6290] = { 5096107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 50971a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 50981a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 50991a3b39ecSAndrew Lunn .num_databases = 4096, 51001a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 510195150f29SHeiner Kallweit .num_internal_phys = 9, 5102a73ccd61SBrandon Streiff .num_gpio = 16, 5103931d1822SVivien Didelot .max_vid = 8191, 51041a3b39ecSAndrew Lunn .port_base_addr = 0x0, 51059255bacdSAndrew Lunn .phy_base_addr = 0x0, 51061a3b39ecSAndrew Lunn .global1_addr = 0x1b, 51079069c13aSVivien Didelot .global2_addr = 0x1c, 5108b91e055cSAndrew Lunn .age_time_coeff = 3750, 51091a3b39ecSAndrew Lunn .g1_irqs = 9, 5110d6c5e6afSVivien Didelot .g2_irqs = 14, 5111e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5112f3645652SVivien Didelot .pvt = true, 5113b3e05aa1SVivien Didelot .multi_chip = true, 5114443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 51152fa8d3afSBrandon Streiff .ptp_support = true, 51161a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 51171a3b39ecSAndrew Lunn }, 51181a3b39ecSAndrew Lunn 5119fad09c73SVivien Didelot [MV88E6320] = { 5120107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 5121fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 5122fad09c73SVivien Didelot .name = "Marvell 88E6320", 5123fad09c73SVivien Didelot .num_databases = 4096, 5124d9ea5620SAndrew Lunn .num_macs = 8192, 5125fad09c73SVivien Didelot .num_ports = 7, 5126bc393155SAndrew Lunn .num_internal_phys = 5, 5127a73ccd61SBrandon Streiff .num_gpio = 15, 51283cf3c846SVivien Didelot .max_vid = 4095, 5129fad09c73SVivien Didelot .port_base_addr = 0x10, 51309255bacdSAndrew Lunn .phy_base_addr = 0x0, 5131a935c052SVivien Didelot .global1_addr = 0x1b, 51329069c13aSVivien Didelot .global2_addr = 0x1c, 5133acddbd21SVivien Didelot .age_time_coeff = 15000, 5134dc30c35bSAndrew Lunn .g1_irqs = 8, 5135bc393155SAndrew Lunn .g2_irqs = 10, 5136e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5137f3645652SVivien Didelot .pvt = true, 5138b3e05aa1SVivien Didelot .multi_chip = true, 5139443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 51402fa8d3afSBrandon Streiff .ptp_support = true, 5141b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 5142fad09c73SVivien Didelot }, 5143fad09c73SVivien Didelot 5144fad09c73SVivien Didelot [MV88E6321] = { 5145107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 5146fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 5147fad09c73SVivien Didelot .name = "Marvell 88E6321", 5148fad09c73SVivien Didelot .num_databases = 4096, 5149d9ea5620SAndrew Lunn .num_macs = 8192, 5150fad09c73SVivien Didelot .num_ports = 7, 5151bc393155SAndrew Lunn .num_internal_phys = 5, 5152a73ccd61SBrandon Streiff .num_gpio = 15, 51533cf3c846SVivien Didelot .max_vid = 4095, 5154fad09c73SVivien Didelot .port_base_addr = 0x10, 51559255bacdSAndrew Lunn .phy_base_addr = 0x0, 5156a935c052SVivien Didelot .global1_addr = 0x1b, 51579069c13aSVivien Didelot .global2_addr = 0x1c, 5158acddbd21SVivien Didelot .age_time_coeff = 15000, 5159dc30c35bSAndrew Lunn .g1_irqs = 8, 5160bc393155SAndrew Lunn .g2_irqs = 10, 5161e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5162b3e05aa1SVivien Didelot .multi_chip = true, 5163443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 51642fa8d3afSBrandon Streiff .ptp_support = true, 5165b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 5166fad09c73SVivien Didelot }, 5167fad09c73SVivien Didelot 5168a75961d0SGregory CLEMENT [MV88E6341] = { 5169107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 5170a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 5171a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 5172a75961d0SGregory CLEMENT .num_databases = 4096, 5173d9ea5620SAndrew Lunn .num_macs = 2048, 5174bc393155SAndrew Lunn .num_internal_phys = 5, 5175a75961d0SGregory CLEMENT .num_ports = 6, 5176a73ccd61SBrandon Streiff .num_gpio = 11, 51773cf3c846SVivien Didelot .max_vid = 4095, 5178a75961d0SGregory CLEMENT .port_base_addr = 0x10, 51799255bacdSAndrew Lunn .phy_base_addr = 0x10, 5180a75961d0SGregory CLEMENT .global1_addr = 0x1b, 51819069c13aSVivien Didelot .global2_addr = 0x1c, 5182a75961d0SGregory CLEMENT .age_time_coeff = 3750, 5183e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5184adfccf11SAndrew Lunn .g1_irqs = 9, 5185d6c5e6afSVivien Didelot .g2_irqs = 10, 5186f3645652SVivien Didelot .pvt = true, 5187b3e05aa1SVivien Didelot .multi_chip = true, 5188a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 51892fa8d3afSBrandon Streiff .ptp_support = true, 5190a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 5191a75961d0SGregory CLEMENT }, 5192a75961d0SGregory CLEMENT 5193fad09c73SVivien Didelot [MV88E6350] = { 5194107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 5195fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5196fad09c73SVivien Didelot .name = "Marvell 88E6350", 5197fad09c73SVivien Didelot .num_databases = 4096, 5198d9ea5620SAndrew Lunn .num_macs = 8192, 5199fad09c73SVivien Didelot .num_ports = 7, 5200bc393155SAndrew Lunn .num_internal_phys = 5, 52013cf3c846SVivien Didelot .max_vid = 4095, 5202fad09c73SVivien Didelot .port_base_addr = 0x10, 52039255bacdSAndrew Lunn .phy_base_addr = 0x0, 5204a935c052SVivien Didelot .global1_addr = 0x1b, 52059069c13aSVivien Didelot .global2_addr = 0x1c, 5206acddbd21SVivien Didelot .age_time_coeff = 15000, 5207dc30c35bSAndrew Lunn .g1_irqs = 9, 5208d6c5e6afSVivien Didelot .g2_irqs = 10, 5209e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5210f3645652SVivien Didelot .pvt = true, 5211b3e05aa1SVivien Didelot .multi_chip = true, 5212443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 5213b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 5214fad09c73SVivien Didelot }, 5215fad09c73SVivien Didelot 5216fad09c73SVivien Didelot [MV88E6351] = { 5217107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 5218fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5219fad09c73SVivien Didelot .name = "Marvell 88E6351", 5220fad09c73SVivien Didelot .num_databases = 4096, 5221d9ea5620SAndrew Lunn .num_macs = 8192, 5222fad09c73SVivien Didelot .num_ports = 7, 5223bc393155SAndrew Lunn .num_internal_phys = 5, 52243cf3c846SVivien Didelot .max_vid = 4095, 5225fad09c73SVivien Didelot .port_base_addr = 0x10, 52269255bacdSAndrew Lunn .phy_base_addr = 0x0, 5227a935c052SVivien Didelot .global1_addr = 0x1b, 52289069c13aSVivien Didelot .global2_addr = 0x1c, 5229acddbd21SVivien Didelot .age_time_coeff = 15000, 5230dc30c35bSAndrew Lunn .g1_irqs = 9, 5231d6c5e6afSVivien Didelot .g2_irqs = 10, 5232e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5233f3645652SVivien Didelot .pvt = true, 5234b3e05aa1SVivien Didelot .multi_chip = true, 5235443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 5236b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 5237fad09c73SVivien Didelot }, 5238fad09c73SVivien Didelot 5239fad09c73SVivien Didelot [MV88E6352] = { 5240107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 5241fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5242fad09c73SVivien Didelot .name = "Marvell 88E6352", 5243fad09c73SVivien Didelot .num_databases = 4096, 5244d9ea5620SAndrew Lunn .num_macs = 8192, 5245fad09c73SVivien Didelot .num_ports = 7, 5246bc393155SAndrew Lunn .num_internal_phys = 5, 5247a73ccd61SBrandon Streiff .num_gpio = 15, 52483cf3c846SVivien Didelot .max_vid = 4095, 5249fad09c73SVivien Didelot .port_base_addr = 0x10, 52509255bacdSAndrew Lunn .phy_base_addr = 0x0, 5251a935c052SVivien Didelot .global1_addr = 0x1b, 52529069c13aSVivien Didelot .global2_addr = 0x1c, 5253acddbd21SVivien Didelot .age_time_coeff = 15000, 5254dc30c35bSAndrew Lunn .g1_irqs = 9, 5255d6c5e6afSVivien Didelot .g2_irqs = 10, 5256e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5257f3645652SVivien Didelot .pvt = true, 5258b3e05aa1SVivien Didelot .multi_chip = true, 5259443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 52602fa8d3afSBrandon Streiff .ptp_support = true, 5261b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 5262fad09c73SVivien Didelot }, 52631a3b39ecSAndrew Lunn [MV88E6390] = { 5264107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 52651a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52661a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 52671a3b39ecSAndrew Lunn .num_databases = 4096, 5268d9ea5620SAndrew Lunn .num_macs = 16384, 52691a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 527095150f29SHeiner Kallweit .num_internal_phys = 9, 5271a73ccd61SBrandon Streiff .num_gpio = 16, 5272931d1822SVivien Didelot .max_vid = 8191, 52731a3b39ecSAndrew Lunn .port_base_addr = 0x0, 52749255bacdSAndrew Lunn .phy_base_addr = 0x0, 52751a3b39ecSAndrew Lunn .global1_addr = 0x1b, 52769069c13aSVivien Didelot .global2_addr = 0x1c, 5277b91e055cSAndrew Lunn .age_time_coeff = 3750, 52781a3b39ecSAndrew Lunn .g1_irqs = 9, 5279d6c5e6afSVivien Didelot .g2_irqs = 14, 5280e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5281f3645652SVivien Didelot .pvt = true, 5282b3e05aa1SVivien Didelot .multi_chip = true, 5283443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 52842fa8d3afSBrandon Streiff .ptp_support = true, 52851a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 52861a3b39ecSAndrew Lunn }, 52871a3b39ecSAndrew Lunn [MV88E6390X] = { 5288107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 52891a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 52901a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 52911a3b39ecSAndrew Lunn .num_databases = 4096, 5292d9ea5620SAndrew Lunn .num_macs = 16384, 52931a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 529495150f29SHeiner Kallweit .num_internal_phys = 9, 5295a73ccd61SBrandon Streiff .num_gpio = 16, 5296931d1822SVivien Didelot .max_vid = 8191, 52971a3b39ecSAndrew Lunn .port_base_addr = 0x0, 52989255bacdSAndrew Lunn .phy_base_addr = 0x0, 52991a3b39ecSAndrew Lunn .global1_addr = 0x1b, 53009069c13aSVivien Didelot .global2_addr = 0x1c, 5301b91e055cSAndrew Lunn .age_time_coeff = 3750, 53021a3b39ecSAndrew Lunn .g1_irqs = 9, 5303d6c5e6afSVivien Didelot .g2_irqs = 14, 5304e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5305f3645652SVivien Didelot .pvt = true, 5306b3e05aa1SVivien Didelot .multi_chip = true, 5307443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 53082fa8d3afSBrandon Streiff .ptp_support = true, 53091a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 53101a3b39ecSAndrew Lunn }, 5311fad09c73SVivien Didelot }; 5312fad09c73SVivien Didelot 5313fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 5314fad09c73SVivien Didelot { 5315fad09c73SVivien Didelot int i; 5316fad09c73SVivien Didelot 5317fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 5318fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 5319fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 5320fad09c73SVivien Didelot 5321fad09c73SVivien Didelot return NULL; 5322fad09c73SVivien Didelot } 5323fad09c73SVivien Didelot 5324fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 5325fad09c73SVivien Didelot { 5326fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 53278f6345b2SVivien Didelot unsigned int prod_num, rev; 53288f6345b2SVivien Didelot u16 id; 53298f6345b2SVivien Didelot int err; 5330fad09c73SVivien Didelot 5331c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5332107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 5333c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 53348f6345b2SVivien Didelot if (err) 53358f6345b2SVivien Didelot return err; 5336fad09c73SVivien Didelot 5337107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 5338107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 5339fad09c73SVivien Didelot 5340fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 5341fad09c73SVivien Didelot if (!info) 5342fad09c73SVivien Didelot return -ENODEV; 5343fad09c73SVivien Didelot 5344fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 5345fad09c73SVivien Didelot chip->info = info; 5346fad09c73SVivien Didelot 5347ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 5348ca070c10SVivien Didelot if (err) 5349ca070c10SVivien Didelot return err; 5350ca070c10SVivien Didelot 5351fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 5352fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 5353fad09c73SVivien Didelot 5354fad09c73SVivien Didelot return 0; 5355fad09c73SVivien Didelot } 5356fad09c73SVivien Didelot 5357fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 5358fad09c73SVivien Didelot { 5359fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5360fad09c73SVivien Didelot 5361fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 5362fad09c73SVivien Didelot if (!chip) 5363fad09c73SVivien Didelot return NULL; 5364fad09c73SVivien Didelot 5365fad09c73SVivien Didelot chip->dev = dev; 5366fad09c73SVivien Didelot 5367fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 5368a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 5369da7dc875SVivien Didelot idr_init(&chip->policies); 5370fad09c73SVivien Didelot 5371fad09c73SVivien Didelot return chip; 5372fad09c73SVivien Didelot } 5373fad09c73SVivien Didelot 53745ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 53754d776482SFlorian Fainelli int port, 53764d776482SFlorian Fainelli enum dsa_tag_protocol m) 53777b314362SAndrew Lunn { 537804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 53792bbb33beSAndrew Lunn 5380443d5a1bSAndrew Lunn return chip->info->tag_protocol; 53817b314362SAndrew Lunn } 53827b314362SAndrew Lunn 53837df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 53843709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 53857df8fbddSVivien Didelot { 53867df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 53877df8fbddSVivien Didelot * so skip the prepare phase. 53887df8fbddSVivien Didelot */ 53897df8fbddSVivien Didelot 53907df8fbddSVivien Didelot return 0; 53917df8fbddSVivien Didelot } 53927df8fbddSVivien Didelot 53937df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 53943709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 53957df8fbddSVivien Didelot { 539604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 53977df8fbddSVivien Didelot 5398c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 53997df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 540027c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC)) 5401774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", 5402774439e5SVivien Didelot port); 5403c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 54047df8fbddSVivien Didelot } 54057df8fbddSVivien Didelot 54067df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 54077df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 54087df8fbddSVivien Didelot { 540904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 54107df8fbddSVivien Didelot int err; 54117df8fbddSVivien Didelot 5412c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5413d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0); 5414c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 54157df8fbddSVivien Didelot 54167df8fbddSVivien Didelot return err; 54177df8fbddSVivien Didelot } 54187df8fbddSVivien Didelot 5419f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, 5420f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror, 5421f0942e00SIwan R Timmer bool ingress) 5422f0942e00SIwan R Timmer { 5423f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = ingress ? 5424f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5425f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5426f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5427f0942e00SIwan R Timmer bool other_mirrors = false; 5428f0942e00SIwan R Timmer int i; 5429f0942e00SIwan R Timmer int err; 5430f0942e00SIwan R Timmer 5431f0942e00SIwan R Timmer if (!chip->info->ops->set_egress_port) 5432f0942e00SIwan R Timmer return -EOPNOTSUPP; 5433f0942e00SIwan R Timmer 5434f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5435f0942e00SIwan R Timmer if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != 5436f0942e00SIwan R Timmer mirror->to_local_port) { 5437f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5438f0942e00SIwan R Timmer other_mirrors |= ingress ? 5439f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5440f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5441f0942e00SIwan R Timmer 5442f0942e00SIwan R Timmer /* Can't change egress port when other mirror is active */ 5443f0942e00SIwan R Timmer if (other_mirrors) { 5444f0942e00SIwan R Timmer err = -EBUSY; 5445f0942e00SIwan R Timmer goto out; 5446f0942e00SIwan R Timmer } 5447f0942e00SIwan R Timmer 5448f0942e00SIwan R Timmer err = chip->info->ops->set_egress_port(chip, 5449f0942e00SIwan R Timmer direction, 5450f0942e00SIwan R Timmer mirror->to_local_port); 5451f0942e00SIwan R Timmer if (err) 5452f0942e00SIwan R Timmer goto out; 5453f0942e00SIwan R Timmer } 5454f0942e00SIwan R Timmer 5455f0942e00SIwan R Timmer err = mv88e6xxx_port_set_mirror(chip, port, direction, true); 5456f0942e00SIwan R Timmer out: 5457f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5458f0942e00SIwan R Timmer 5459f0942e00SIwan R Timmer return err; 5460f0942e00SIwan R Timmer } 5461f0942e00SIwan R Timmer 5462f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, 5463f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror) 5464f0942e00SIwan R Timmer { 5465f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = mirror->ingress ? 5466f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5467f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5468f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5469f0942e00SIwan R Timmer bool other_mirrors = false; 5470f0942e00SIwan R Timmer int i; 5471f0942e00SIwan R Timmer 5472f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5473f0942e00SIwan R Timmer if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) 5474f0942e00SIwan R Timmer dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); 5475f0942e00SIwan R Timmer 5476f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5477f0942e00SIwan R Timmer other_mirrors |= mirror->ingress ? 5478f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5479f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5480f0942e00SIwan R Timmer 5481f0942e00SIwan R Timmer /* Reset egress port when no other mirror is active */ 5482f0942e00SIwan R Timmer if (!other_mirrors) { 5483f0942e00SIwan R Timmer if (chip->info->ops->set_egress_port(chip, 5484f0942e00SIwan R Timmer direction, 5485f0942e00SIwan R Timmer dsa_upstream_port(ds, 54864e4637b1SColin Ian King port))) 5487f0942e00SIwan R Timmer dev_err(ds->dev, "failed to set egress port\n"); 5488f0942e00SIwan R Timmer } 5489f0942e00SIwan R Timmer 5490f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5491f0942e00SIwan R Timmer } 5492f0942e00SIwan R Timmer 54934f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, 54944f85901fSRussell King bool unicast, bool multicast) 54954f85901fSRussell King { 54964f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 54974f85901fSRussell King int err = -EOPNOTSUPP; 54984f85901fSRussell King 5499c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 55004f85901fSRussell King if (chip->info->ops->port_set_egress_floods) 55014f85901fSRussell King err = chip->info->ops->port_set_egress_floods(chip, port, 55024f85901fSRussell King unicast, 55034f85901fSRussell King multicast); 5504c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 55054f85901fSRussell King 55064f85901fSRussell King return err; 55074f85901fSRussell King } 55084f85901fSRussell King 5509a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 55107b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 5511fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 551223e8b470SAndrew Lunn .teardown = mv88e6xxx_teardown, 5513c9a2356fSRussell King .phylink_validate = mv88e6xxx_validate, 5514a5a6858bSRussell King .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, 5515c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 5516a5a6858bSRussell King .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, 5517c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 5518c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 5519fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 5520fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 5521fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 552204aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 552304aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 552408f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 552508f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 5526fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 5527fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 5528fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 5529fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 5530fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 5531da7dc875SVivien Didelot .get_rxnfc = mv88e6xxx_get_rxnfc, 5532da7dc875SVivien Didelot .set_rxnfc = mv88e6xxx_set_rxnfc, 55332cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 5534fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 5535fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 55364f85901fSRussell King .port_egress_floods = mv88e6xxx_port_egress_floods, 5537fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 5538749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 5539fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 5540fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 5541fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 5542fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 5543fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 5544fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 5545fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 55467df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 55477df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 55487df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 5549f0942e00SIwan R Timmer .port_mirror_add = mv88e6xxx_port_mirror_add, 5550f0942e00SIwan R Timmer .port_mirror_del = mv88e6xxx_port_mirror_del, 5551aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 5552aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 5553c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 5554c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 5555c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 5556c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 5557c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 555823e8b470SAndrew Lunn .devlink_param_get = mv88e6xxx_devlink_param_get, 555923e8b470SAndrew Lunn .devlink_param_set = mv88e6xxx_devlink_param_set, 5560fad09c73SVivien Didelot }; 5561fad09c73SVivien Didelot 556255ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 5563fad09c73SVivien Didelot { 5564fad09c73SVivien Didelot struct device *dev = chip->dev; 5565fad09c73SVivien Didelot struct dsa_switch *ds; 5566fad09c73SVivien Didelot 55677e99e347SVivien Didelot ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); 5568fad09c73SVivien Didelot if (!ds) 5569fad09c73SVivien Didelot return -ENOMEM; 5570fad09c73SVivien Didelot 55717e99e347SVivien Didelot ds->dev = dev; 55727e99e347SVivien Didelot ds->num_ports = mv88e6xxx_num_ports(chip); 5573fad09c73SVivien Didelot ds->priv = chip; 5574877b7cb0SAndrew Lunn ds->dev = dev; 55759d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 55769ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 55779ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 5578fad09c73SVivien Didelot 5579fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 5580fad09c73SVivien Didelot 558123c9ee49SVivien Didelot return dsa_register_switch(ds); 5582fad09c73SVivien Didelot } 5583fad09c73SVivien Didelot 5584fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 5585fad09c73SVivien Didelot { 5586fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 5587fad09c73SVivien Didelot } 5588fad09c73SVivien Didelot 5589877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 5590877b7cb0SAndrew Lunn { 5591877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 5592877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 5593877b7cb0SAndrew Lunn 5594877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 5595877b7cb0SAndrew Lunn matches++) { 5596877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 5597877b7cb0SAndrew Lunn return matches->data; 5598877b7cb0SAndrew Lunn } 5599877b7cb0SAndrew Lunn return NULL; 5600877b7cb0SAndrew Lunn } 5601877b7cb0SAndrew Lunn 5602bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 5603bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 5604bcd3d9d9SMiquel Raynal */ 5605bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 5606bcd3d9d9SMiquel Raynal { 5607bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 5608bcd3d9d9SMiquel Raynal } 5609bcd3d9d9SMiquel Raynal 5610bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 5611bcd3d9d9SMiquel Raynal { 5612bcd3d9d9SMiquel Raynal return 0; 5613bcd3d9d9SMiquel Raynal } 5614bcd3d9d9SMiquel Raynal 5615bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 5616bcd3d9d9SMiquel Raynal 5617fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 5618fad09c73SVivien Didelot { 5619877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 56207ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 5621fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 5622fad09c73SVivien Didelot struct device_node *np = dev->of_node; 5623fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5624877b7cb0SAndrew Lunn int port; 5625fad09c73SVivien Didelot int err; 5626fad09c73SVivien Didelot 56277bb8c996SAndrew Lunn if (!np && !pdata) 56287bb8c996SAndrew Lunn return -EINVAL; 56297bb8c996SAndrew Lunn 5630877b7cb0SAndrew Lunn if (np) 5631fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 5632877b7cb0SAndrew Lunn 5633877b7cb0SAndrew Lunn if (pdata) { 5634877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 5635877b7cb0SAndrew Lunn 5636877b7cb0SAndrew Lunn if (!pdata->netdev) 5637877b7cb0SAndrew Lunn return -EINVAL; 5638877b7cb0SAndrew Lunn 5639877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 5640877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 5641877b7cb0SAndrew Lunn continue; 5642877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 5643877b7cb0SAndrew Lunn continue; 5644877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 5645877b7cb0SAndrew Lunn break; 5646877b7cb0SAndrew Lunn } 5647877b7cb0SAndrew Lunn } 5648877b7cb0SAndrew Lunn 5649fad09c73SVivien Didelot if (!compat_info) 5650fad09c73SVivien Didelot return -EINVAL; 5651fad09c73SVivien Didelot 5652fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 5653877b7cb0SAndrew Lunn if (!chip) { 5654877b7cb0SAndrew Lunn err = -ENOMEM; 5655877b7cb0SAndrew Lunn goto out; 5656877b7cb0SAndrew Lunn } 5657fad09c73SVivien Didelot 5658fad09c73SVivien Didelot chip->info = compat_info; 5659fad09c73SVivien Didelot 5660fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 5661fad09c73SVivien Didelot if (err) 5662877b7cb0SAndrew Lunn goto out; 5663fad09c73SVivien Didelot 5664b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 5665877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 5666877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 5667877b7cb0SAndrew Lunn goto out; 5668877b7cb0SAndrew Lunn } 56697b75e49dSBaruch Siach if (chip->reset) 56707b75e49dSBaruch Siach usleep_range(1000, 2000); 5671b4308f04SAndrew Lunn 5672fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 5673fad09c73SVivien Didelot if (err) 5674877b7cb0SAndrew Lunn goto out; 5675fad09c73SVivien Didelot 5676e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 5677e57e5e77SVivien Didelot 567800baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 567900baabe5SAndrew Lunn if (np) 568000baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 568100baabe5SAndrew Lunn &chip->eeprom_len); 568200baabe5SAndrew Lunn else 568300baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 568400baabe5SAndrew Lunn } 5685fad09c73SVivien Didelot 5686c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5687dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 5688c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5689fad09c73SVivien Didelot if (err) 5690dc30c35bSAndrew Lunn goto out; 5691fad09c73SVivien Didelot 5692a27415deSAndrew Lunn if (np) { 5693dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 5694dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 5695dc30c35bSAndrew Lunn err = chip->irq; 5696dc30c35bSAndrew Lunn goto out; 5697fad09c73SVivien Didelot } 5698a27415deSAndrew Lunn } 5699a27415deSAndrew Lunn 5700a27415deSAndrew Lunn if (pdata) 5701a27415deSAndrew Lunn chip->irq = pdata->irq; 5702fad09c73SVivien Didelot 5703294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 5704a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 5705294d711eSAndrew Lunn * controllers 5706dc30c35bSAndrew Lunn */ 5707c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5708294d711eSAndrew Lunn if (chip->irq > 0) 5709dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 5710294d711eSAndrew Lunn else 5711294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 5712c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5713dc30c35bSAndrew Lunn 5714dc30c35bSAndrew Lunn if (err) 5715dc30c35bSAndrew Lunn goto out; 5716dc30c35bSAndrew Lunn 5717d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 5718dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 5719dc30c35bSAndrew Lunn if (err) 5720dc30c35bSAndrew Lunn goto out_g1_irq; 5721dc30c35bSAndrew Lunn } 57220977644cSAndrew Lunn 57230977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 57240977644cSAndrew Lunn if (err) 57250977644cSAndrew Lunn goto out_g2_irq; 572662eb1162SAndrew Lunn 572762eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 572862eb1162SAndrew Lunn if (err) 572962eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 5730dc30c35bSAndrew Lunn 5731a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 5732dc30c35bSAndrew Lunn if (err) 573362eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 5734dc30c35bSAndrew Lunn 573555ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 5736dc30c35bSAndrew Lunn if (err) 5737dc30c35bSAndrew Lunn goto out_mdio; 5738dc30c35bSAndrew Lunn 5739fad09c73SVivien Didelot return 0; 5740dc30c35bSAndrew Lunn 5741dc30c35bSAndrew Lunn out_mdio: 5742a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 574362eb1162SAndrew Lunn out_g1_vtu_prob_irq: 574462eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 57450977644cSAndrew Lunn out_g1_atu_prob_irq: 57460977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 5747dc30c35bSAndrew Lunn out_g2_irq: 5748294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 5749dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 5750dc30c35bSAndrew Lunn out_g1_irq: 5751294d711eSAndrew Lunn if (chip->irq > 0) 5752dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 5753294d711eSAndrew Lunn else 5754294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5755dc30c35bSAndrew Lunn out: 5756877b7cb0SAndrew Lunn if (pdata) 5757877b7cb0SAndrew Lunn dev_put(pdata->netdev); 5758877b7cb0SAndrew Lunn 5759dc30c35bSAndrew Lunn return err; 5760fad09c73SVivien Didelot } 5761fad09c73SVivien Didelot 5762fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 5763fad09c73SVivien Didelot { 5764fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 576504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 5766fad09c73SVivien Didelot 5767c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 5768c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 57692fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 5770c6fe0ad2SBrandon Streiff } 57712fa8d3afSBrandon Streiff 5772930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 5773fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 5774a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 5775dc30c35bSAndrew Lunn 577662eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 57770977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 577876f38f1fSAndrew Lunn 5779d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 5780dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 578176f38f1fSAndrew Lunn 578276f38f1fSAndrew Lunn if (chip->irq > 0) 5783dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 578476f38f1fSAndrew Lunn else 578576f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5786fad09c73SVivien Didelot } 5787fad09c73SVivien Didelot 5788fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 5789fad09c73SVivien Didelot { 5790fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 5791fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 5792fad09c73SVivien Didelot }, 57931a3b39ecSAndrew Lunn { 57941a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 57951a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 57961a3b39ecSAndrew Lunn }, 57971f71836fSRasmus Villemoes { 57981f71836fSRasmus Villemoes .compatible = "marvell,mv88e6250", 57991f71836fSRasmus Villemoes .data = &mv88e6xxx_table[MV88E6250], 58001f71836fSRasmus Villemoes }, 5801fad09c73SVivien Didelot { /* sentinel */ }, 5802fad09c73SVivien Didelot }; 5803fad09c73SVivien Didelot 5804fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 5805fad09c73SVivien Didelot 5806fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 5807fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 5808fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 5809fad09c73SVivien Didelot .mdiodrv.driver = { 5810fad09c73SVivien Didelot .name = "mv88e6085", 5811fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 5812bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 5813fad09c73SVivien Didelot }, 5814fad09c73SVivien Didelot }; 5815fad09c73SVivien Didelot 58167324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver); 5817fad09c73SVivien Didelot 5818fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 5819fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 5820fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 5821