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" 359dd43aa2SAndrew Lunn #include "devlink.h" 36a935c052SVivien Didelot #include "global1.h" 37ec561276SVivien Didelot #include "global2.h" 38c6fe0ad2SBrandon Streiff #include "hwtstamp.h" 3910fa5bfcSAndrew Lunn #include "phy.h" 4018abed21SVivien Didelot #include "port.h" 412fa8d3afSBrandon Streiff #include "ptp.h" 426d91782fSAndrew Lunn #include "serdes.h" 43e7ba0fadSVivien Didelot #include "smi.h" 44fad09c73SVivien Didelot 45fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 46fad09c73SVivien Didelot { 47fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 48fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 49fad09c73SVivien Didelot dump_stack(); 50fad09c73SVivien Didelot } 51fad09c73SVivien Didelot } 52fad09c73SVivien Didelot 53ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 54fad09c73SVivien Didelot { 55fad09c73SVivien Didelot int err; 56fad09c73SVivien Didelot 57fad09c73SVivien Didelot assert_reg_lock(chip); 58fad09c73SVivien Didelot 59fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 60fad09c73SVivien Didelot if (err) 61fad09c73SVivien Didelot return err; 62fad09c73SVivien Didelot 63fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 64fad09c73SVivien Didelot addr, reg, *val); 65fad09c73SVivien Didelot 66fad09c73SVivien Didelot return 0; 67fad09c73SVivien Didelot } 68fad09c73SVivien Didelot 69ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 70fad09c73SVivien Didelot { 71fad09c73SVivien Didelot int err; 72fad09c73SVivien Didelot 73fad09c73SVivien Didelot assert_reg_lock(chip); 74fad09c73SVivien Didelot 75fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 76fad09c73SVivien Didelot if (err) 77fad09c73SVivien Didelot return err; 78fad09c73SVivien Didelot 79fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 80fad09c73SVivien Didelot addr, reg, val); 81fad09c73SVivien Didelot 82fad09c73SVivien Didelot return 0; 83fad09c73SVivien Didelot } 84fad09c73SVivien Didelot 85683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, 86683f2244SVivien Didelot u16 mask, u16 val) 87683f2244SVivien Didelot { 88683f2244SVivien Didelot u16 data; 89683f2244SVivien Didelot int err; 90683f2244SVivien Didelot int i; 91683f2244SVivien Didelot 92683f2244SVivien Didelot /* There's no bus specific operation to wait for a mask */ 93683f2244SVivien Didelot for (i = 0; i < 16; i++) { 94683f2244SVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &data); 95683f2244SVivien Didelot if (err) 96683f2244SVivien Didelot return err; 97683f2244SVivien Didelot 98683f2244SVivien Didelot if ((data & mask) == val) 99683f2244SVivien Didelot return 0; 100683f2244SVivien Didelot 101683f2244SVivien Didelot usleep_range(1000, 2000); 102683f2244SVivien Didelot } 103683f2244SVivien Didelot 104683f2244SVivien Didelot dev_err(chip->dev, "Timeout while waiting for switch\n"); 105683f2244SVivien Didelot return -ETIMEDOUT; 106683f2244SVivien Didelot } 107683f2244SVivien Didelot 10819fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, 10919fb7f69SVivien Didelot int bit, int val) 11019fb7f69SVivien Didelot { 11119fb7f69SVivien Didelot return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit), 11219fb7f69SVivien Didelot val ? BIT(bit) : 0x0000); 11319fb7f69SVivien Didelot } 11419fb7f69SVivien Didelot 11510fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 116a3c53be5SAndrew Lunn { 117a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 118a3c53be5SAndrew Lunn 119a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 120a3c53be5SAndrew Lunn list); 121a3c53be5SAndrew Lunn if (!mdio_bus) 122a3c53be5SAndrew Lunn return NULL; 123a3c53be5SAndrew Lunn 124a3c53be5SAndrew Lunn return mdio_bus->bus; 125a3c53be5SAndrew Lunn } 126a3c53be5SAndrew Lunn 127dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(struct irq_data *d) 128dc30c35bSAndrew Lunn { 129dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 130dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 131dc30c35bSAndrew Lunn 132dc30c35bSAndrew Lunn chip->g1_irq.masked |= (1 << n); 133dc30c35bSAndrew Lunn } 134dc30c35bSAndrew Lunn 135dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 136dc30c35bSAndrew Lunn { 137dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 138dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 139dc30c35bSAndrew Lunn 140dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 141dc30c35bSAndrew Lunn } 142dc30c35bSAndrew Lunn 143294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 144dc30c35bSAndrew Lunn { 145dc30c35bSAndrew Lunn unsigned int nhandled = 0; 146dc30c35bSAndrew Lunn unsigned int sub_irq; 147dc30c35bSAndrew Lunn unsigned int n; 148dc30c35bSAndrew Lunn u16 reg; 1497c0db24cSJohn David Anglin u16 ctl1; 150dc30c35bSAndrew Lunn int err; 151dc30c35bSAndrew Lunn 152c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 15382466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 154c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 155dc30c35bSAndrew Lunn 156dc30c35bSAndrew Lunn if (err) 157dc30c35bSAndrew Lunn goto out; 158dc30c35bSAndrew Lunn 1597c0db24cSJohn David Anglin do { 160dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 161dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1627c0db24cSJohn David Anglin sub_irq = irq_find_mapping(chip->g1_irq.domain, 1637c0db24cSJohn David Anglin n); 164dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 165dc30c35bSAndrew Lunn ++nhandled; 166dc30c35bSAndrew Lunn } 167dc30c35bSAndrew Lunn } 1687c0db24cSJohn David Anglin 169c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1707c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 1717c0db24cSJohn David Anglin if (err) 1727c0db24cSJohn David Anglin goto unlock; 1737c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 1747c0db24cSJohn David Anglin unlock: 175c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1767c0db24cSJohn David Anglin if (err) 1777c0db24cSJohn David Anglin goto out; 1787c0db24cSJohn David Anglin ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 1797c0db24cSJohn David Anglin } while (reg & ctl1); 1807c0db24cSJohn David Anglin 181dc30c35bSAndrew Lunn out: 182dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 183dc30c35bSAndrew Lunn } 184dc30c35bSAndrew Lunn 185294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 186294d711eSAndrew Lunn { 187294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 188294d711eSAndrew Lunn 189294d711eSAndrew Lunn return mv88e6xxx_g1_irq_thread_work(chip); 190294d711eSAndrew Lunn } 191294d711eSAndrew Lunn 192dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 193dc30c35bSAndrew Lunn { 194dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 195dc30c35bSAndrew Lunn 196c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 197dc30c35bSAndrew Lunn } 198dc30c35bSAndrew Lunn 199dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 200dc30c35bSAndrew Lunn { 201dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 202dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 203dc30c35bSAndrew Lunn u16 reg; 204dc30c35bSAndrew Lunn int err; 205dc30c35bSAndrew Lunn 206d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 207dc30c35bSAndrew Lunn if (err) 208dc30c35bSAndrew Lunn goto out; 209dc30c35bSAndrew Lunn 210dc30c35bSAndrew Lunn reg &= ~mask; 211dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 212dc30c35bSAndrew Lunn 213d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 214dc30c35bSAndrew Lunn if (err) 215dc30c35bSAndrew Lunn goto out; 216dc30c35bSAndrew Lunn 217dc30c35bSAndrew Lunn out: 218c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 219dc30c35bSAndrew Lunn } 220dc30c35bSAndrew Lunn 2216eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = { 222dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 223dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 224dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 225dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 226dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 227dc30c35bSAndrew Lunn }; 228dc30c35bSAndrew Lunn 229dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 230dc30c35bSAndrew Lunn unsigned int irq, 231dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 232dc30c35bSAndrew Lunn { 233dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 234dc30c35bSAndrew Lunn 235dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 236dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 237dc30c35bSAndrew Lunn irq_set_noprobe(irq); 238dc30c35bSAndrew Lunn 239dc30c35bSAndrew Lunn return 0; 240dc30c35bSAndrew Lunn } 241dc30c35bSAndrew Lunn 242dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 243dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 244dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 245dc30c35bSAndrew Lunn }; 246dc30c35bSAndrew Lunn 2473d82475aSUwe Kleine-König /* To be called with reg_lock held */ 248294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 249dc30c35bSAndrew Lunn { 250dc30c35bSAndrew Lunn int irq, virq; 2513460a577SAndrew Lunn u16 mask; 2523460a577SAndrew Lunn 253d77f4321SVivien Didelot mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 2543d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 255d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2563460a577SAndrew Lunn 2575edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 258a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 259dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 260dc30c35bSAndrew Lunn } 261dc30c35bSAndrew Lunn 262a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 263dc30c35bSAndrew Lunn } 264dc30c35bSAndrew Lunn 265294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 266294d711eSAndrew Lunn { 2673d82475aSUwe Kleine-König /* 2683d82475aSUwe Kleine-König * free_irq must be called without reg_lock taken because the irq 2693d82475aSUwe Kleine-König * handler takes this lock, too. 2703d82475aSUwe Kleine-König */ 271294d711eSAndrew Lunn free_irq(chip->irq, chip); 2723d82475aSUwe Kleine-König 273c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2743d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 275c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 276294d711eSAndrew Lunn } 277294d711eSAndrew Lunn 278294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 279dc30c35bSAndrew Lunn { 2803dd0ef05SAndrew Lunn int err, irq, virq; 2813dd0ef05SAndrew Lunn u16 reg, mask; 282dc30c35bSAndrew Lunn 283dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 284dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 285dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 286dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 287dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 288dc30c35bSAndrew Lunn return -ENOMEM; 289dc30c35bSAndrew Lunn 290dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 291dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 292dc30c35bSAndrew Lunn 293dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 294dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 295dc30c35bSAndrew Lunn 296d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 297dc30c35bSAndrew Lunn if (err) 2983dd0ef05SAndrew Lunn goto out_mapping; 299dc30c35bSAndrew Lunn 3003dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 301dc30c35bSAndrew Lunn 302d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 303dc30c35bSAndrew Lunn if (err) 3043dd0ef05SAndrew Lunn goto out_disable; 305dc30c35bSAndrew Lunn 306dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 30782466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 308dc30c35bSAndrew Lunn if (err) 3093dd0ef05SAndrew Lunn goto out_disable; 310dc30c35bSAndrew Lunn 311dc30c35bSAndrew Lunn return 0; 312dc30c35bSAndrew Lunn 3133dd0ef05SAndrew Lunn out_disable: 3143d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 315d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 3163dd0ef05SAndrew Lunn 3173dd0ef05SAndrew Lunn out_mapping: 3183dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 3193dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 3203dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 3213dd0ef05SAndrew Lunn } 3223dd0ef05SAndrew Lunn 3233dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 324dc30c35bSAndrew Lunn 325dc30c35bSAndrew Lunn return err; 326dc30c35bSAndrew Lunn } 327dc30c35bSAndrew Lunn 328294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 329294d711eSAndrew Lunn { 330f6d9758bSAndrew Lunn static struct lock_class_key lock_key; 331f6d9758bSAndrew Lunn static struct lock_class_key request_key; 332294d711eSAndrew Lunn int err; 333294d711eSAndrew Lunn 334294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 335294d711eSAndrew Lunn if (err) 336294d711eSAndrew Lunn return err; 337294d711eSAndrew Lunn 338f6d9758bSAndrew Lunn /* These lock classes tells lockdep that global 1 irqs are in 339f6d9758bSAndrew Lunn * a different category than their parent GPIO, so it won't 340f6d9758bSAndrew Lunn * report false recursion. 341f6d9758bSAndrew Lunn */ 342f6d9758bSAndrew Lunn irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 343f6d9758bSAndrew Lunn 3443095383aSAndrew Lunn snprintf(chip->irq_name, sizeof(chip->irq_name), 3453095383aSAndrew Lunn "mv88e6xxx-%s", dev_name(chip->dev)); 3463095383aSAndrew Lunn 347c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 348294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 349294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 3500340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 3513095383aSAndrew Lunn chip->irq_name, chip); 352c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 353294d711eSAndrew Lunn if (err) 354294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 355294d711eSAndrew Lunn 356294d711eSAndrew Lunn return err; 357294d711eSAndrew Lunn } 358294d711eSAndrew Lunn 359294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 360294d711eSAndrew Lunn { 361294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 362294d711eSAndrew Lunn struct mv88e6xxx_chip, 363294d711eSAndrew Lunn irq_poll_work.work); 364294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 365294d711eSAndrew Lunn 366294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 367294d711eSAndrew Lunn msecs_to_jiffies(100)); 368294d711eSAndrew Lunn } 369294d711eSAndrew Lunn 370294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 371294d711eSAndrew Lunn { 372294d711eSAndrew Lunn int err; 373294d711eSAndrew Lunn 374294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 375294d711eSAndrew Lunn if (err) 376294d711eSAndrew Lunn return err; 377294d711eSAndrew Lunn 378294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 379294d711eSAndrew Lunn mv88e6xxx_irq_poll); 380294d711eSAndrew Lunn 3813f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 382294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 383294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 384294d711eSAndrew Lunn 385294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 386294d711eSAndrew Lunn msecs_to_jiffies(100)); 387294d711eSAndrew Lunn 388294d711eSAndrew Lunn return 0; 389294d711eSAndrew Lunn } 390294d711eSAndrew Lunn 391294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 392294d711eSAndrew Lunn { 393294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 394294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 3953d82475aSUwe Kleine-König 396c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3973d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 398c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 399294d711eSAndrew Lunn } 400294d711eSAndrew Lunn 40164d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, 40264d47d50SRussell King int port, phy_interface_t interface) 40364d47d50SRussell King { 40464d47d50SRussell King int err; 40564d47d50SRussell King 40664d47d50SRussell King if (chip->info->ops->port_set_rgmii_delay) { 40764d47d50SRussell King err = chip->info->ops->port_set_rgmii_delay(chip, port, 40864d47d50SRussell King interface); 40964d47d50SRussell King if (err && err != -EOPNOTSUPP) 41064d47d50SRussell King return err; 41164d47d50SRussell King } 41264d47d50SRussell King 41364d47d50SRussell King if (chip->info->ops->port_set_cmode) { 41464d47d50SRussell King err = chip->info->ops->port_set_cmode(chip, port, 41564d47d50SRussell King interface); 41664d47d50SRussell King if (err && err != -EOPNOTSUPP) 41764d47d50SRussell King return err; 41864d47d50SRussell King } 41964d47d50SRussell King 42064d47d50SRussell King return 0; 42164d47d50SRussell King } 42264d47d50SRussell King 423a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, 424a5a6858bSRussell King int link, int speed, int duplex, int pause, 425d78343d2SVivien Didelot phy_interface_t mode) 426d78343d2SVivien Didelot { 427d78343d2SVivien Didelot int err; 428d78343d2SVivien Didelot 429d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 430d78343d2SVivien Didelot return 0; 431d78343d2SVivien Didelot 432d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 43343c8e0aeSHubert Feurstein err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 434d78343d2SVivien Didelot if (err) 435d78343d2SVivien Didelot return err; 436d78343d2SVivien Didelot 437f365c6f7SRussell King if (chip->info->ops->port_set_speed_duplex) { 438f365c6f7SRussell King err = chip->info->ops->port_set_speed_duplex(chip, port, 439f365c6f7SRussell King speed, duplex); 440d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 441d78343d2SVivien Didelot goto restore_link; 442d78343d2SVivien Didelot } 443d78343d2SVivien Didelot 4447cbbee05SAndrew Lunn if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode) 4457cbbee05SAndrew Lunn mode = chip->info->ops->port_max_speed_mode(port); 4467cbbee05SAndrew Lunn 44754186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 44854186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 44954186b91SAndrew Lunn if (err) 45054186b91SAndrew Lunn goto restore_link; 45154186b91SAndrew Lunn } 45254186b91SAndrew Lunn 45364d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, mode); 454d78343d2SVivien Didelot restore_link: 455d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 456774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 457d78343d2SVivien Didelot 458d78343d2SVivien Didelot return err; 459d78343d2SVivien Didelot } 460d78343d2SVivien Didelot 461d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 462d700ec41SMarek Vasut { 463d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 464d700ec41SMarek Vasut 465d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 466d700ec41SMarek Vasut } 467d700ec41SMarek Vasut 4685d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) 4695d5b231dSRussell King { 4705d5b231dSRussell King u16 reg; 4715d5b231dSRussell King int err; 4725d5b231dSRussell King 4735d5b231dSRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4745d5b231dSRussell King if (err) { 4755d5b231dSRussell King dev_err(chip->dev, 4765d5b231dSRussell King "p%d: %s: failed to read port status\n", 4775d5b231dSRussell King port, __func__); 4785d5b231dSRussell King return err; 4795d5b231dSRussell King } 4805d5b231dSRussell King 4815d5b231dSRussell King return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT); 4825d5b231dSRussell King } 4835d5b231dSRussell King 484a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, 485a5a6858bSRussell King struct phylink_link_state *state) 486a5a6858bSRussell King { 487a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 488a5a6858bSRussell King u8 lane; 489a5a6858bSRussell King int err; 490a5a6858bSRussell King 491a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 492a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 493a5a6858bSRussell King if (lane && chip->info->ops->serdes_pcs_get_state) 494a5a6858bSRussell King err = chip->info->ops->serdes_pcs_get_state(chip, port, lane, 495a5a6858bSRussell King state); 496a5a6858bSRussell King else 497a5a6858bSRussell King err = -EOPNOTSUPP; 498a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 499a5a6858bSRussell King 500a5a6858bSRussell King return err; 501a5a6858bSRussell King } 502a5a6858bSRussell King 503a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, 504a5a6858bSRussell King unsigned int mode, 505a5a6858bSRussell King phy_interface_t interface, 506a5a6858bSRussell King const unsigned long *advertise) 507a5a6858bSRussell King { 508a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 509a5a6858bSRussell King u8 lane; 510a5a6858bSRussell King 511a5a6858bSRussell King if (ops->serdes_pcs_config) { 512a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 513a5a6858bSRussell King if (lane) 514a5a6858bSRussell King return ops->serdes_pcs_config(chip, port, lane, mode, 515a5a6858bSRussell King interface, advertise); 516a5a6858bSRussell King } 517a5a6858bSRussell King 518a5a6858bSRussell King return 0; 519a5a6858bSRussell King } 520a5a6858bSRussell King 521a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port) 522a5a6858bSRussell King { 523a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 524a5a6858bSRussell King const struct mv88e6xxx_ops *ops; 525a5a6858bSRussell King int err = 0; 526a5a6858bSRussell King u8 lane; 527a5a6858bSRussell King 528a5a6858bSRussell King ops = chip->info->ops; 529a5a6858bSRussell King 530a5a6858bSRussell King if (ops->serdes_pcs_an_restart) { 531a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 532a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 533a5a6858bSRussell King if (lane) 534a5a6858bSRussell King err = ops->serdes_pcs_an_restart(chip, port, lane); 535a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 536a5a6858bSRussell King 537a5a6858bSRussell King if (err) 538a5a6858bSRussell King dev_err(ds->dev, "p%d: failed to restart AN\n", port); 539a5a6858bSRussell King } 540a5a6858bSRussell King } 541a5a6858bSRussell King 542a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, 543a5a6858bSRussell King unsigned int mode, 544a5a6858bSRussell King int speed, int duplex) 545a5a6858bSRussell King { 546a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 547a5a6858bSRussell King u8 lane; 548a5a6858bSRussell King 549a5a6858bSRussell King if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) { 550a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 551a5a6858bSRussell King if (lane) 552a5a6858bSRussell King return ops->serdes_pcs_link_up(chip, port, lane, 553a5a6858bSRussell King speed, duplex); 554a5a6858bSRussell King } 555a5a6858bSRussell King 556a5a6858bSRussell King return 0; 557a5a6858bSRussell King } 558a5a6858bSRussell King 5596c422e34SRussell King static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5606c422e34SRussell King unsigned long *mask, 5616c422e34SRussell King struct phylink_link_state *state) 5626c422e34SRussell King { 5636c422e34SRussell King if (!phy_interface_mode_is_8023z(state->interface)) { 5646c422e34SRussell King /* 10M and 100M are only supported in non-802.3z mode */ 5656c422e34SRussell King phylink_set(mask, 10baseT_Half); 5666c422e34SRussell King phylink_set(mask, 10baseT_Full); 5676c422e34SRussell King phylink_set(mask, 100baseT_Half); 5686c422e34SRussell King phylink_set(mask, 100baseT_Full); 5696c422e34SRussell King } 5706c422e34SRussell King } 5716c422e34SRussell King 5726c422e34SRussell King static void mv88e6185_phylink_validate(struct mv88e6xxx_chip *chip, int port, 5736c422e34SRussell King unsigned long *mask, 5746c422e34SRussell King struct phylink_link_state *state) 5756c422e34SRussell King { 5766c422e34SRussell King /* FIXME: if the port is in 1000Base-X mode, then it only supports 5776c422e34SRussell King * 1000M FD speeds. In this case, CMODE will indicate 5. 5786c422e34SRussell King */ 5796c422e34SRussell King phylink_set(mask, 1000baseT_Full); 5806c422e34SRussell King phylink_set(mask, 1000baseX_Full); 5816c422e34SRussell King 5826c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 5836c422e34SRussell King } 5846c422e34SRussell King 585e3af71a3SMarek Behún static void mv88e6341_phylink_validate(struct mv88e6xxx_chip *chip, int port, 586e3af71a3SMarek Behún unsigned long *mask, 587e3af71a3SMarek Behún struct phylink_link_state *state) 588e3af71a3SMarek Behún { 589e3af71a3SMarek Behún if (port >= 5) 590e3af71a3SMarek Behún phylink_set(mask, 2500baseX_Full); 591e3af71a3SMarek Behún 592e3af71a3SMarek Behún /* No ethtool bits for 200Mbps */ 593e3af71a3SMarek Behún phylink_set(mask, 1000baseT_Full); 594e3af71a3SMarek Behún phylink_set(mask, 1000baseX_Full); 595e3af71a3SMarek Behún 596e3af71a3SMarek Behún mv88e6065_phylink_validate(chip, port, mask, state); 597e3af71a3SMarek Behún } 598e3af71a3SMarek Behún 5996c422e34SRussell King static void mv88e6352_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6006c422e34SRussell King unsigned long *mask, 6016c422e34SRussell King struct phylink_link_state *state) 6026c422e34SRussell King { 6036c422e34SRussell King /* No ethtool bits for 200Mbps */ 6046c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6056c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6066c422e34SRussell King 6076c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6086c422e34SRussell King } 6096c422e34SRussell King 6106c422e34SRussell King static void mv88e6390_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6116c422e34SRussell King unsigned long *mask, 6126c422e34SRussell King struct phylink_link_state *state) 6136c422e34SRussell King { 614ec26016bSAndrew Lunn if (port >= 9) { 6156c422e34SRussell King phylink_set(mask, 2500baseX_Full); 616ec26016bSAndrew Lunn phylink_set(mask, 2500baseT_Full); 617ec26016bSAndrew Lunn } 6186c422e34SRussell King 6196c422e34SRussell King /* No ethtool bits for 200Mbps */ 6206c422e34SRussell King phylink_set(mask, 1000baseT_Full); 6216c422e34SRussell King phylink_set(mask, 1000baseX_Full); 6226c422e34SRussell King 6236c422e34SRussell King mv88e6065_phylink_validate(chip, port, mask, state); 6246c422e34SRussell King } 6256c422e34SRussell King 6266c422e34SRussell King static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, 6276c422e34SRussell King unsigned long *mask, 6286c422e34SRussell King struct phylink_link_state *state) 6296c422e34SRussell King { 6306c422e34SRussell King if (port >= 9) { 6316c422e34SRussell King phylink_set(mask, 10000baseT_Full); 6326c422e34SRussell King phylink_set(mask, 10000baseKR_Full); 6336c422e34SRussell King } 6346c422e34SRussell King 6356c422e34SRussell King mv88e6390_phylink_validate(chip, port, mask, state); 6366c422e34SRussell King } 6376c422e34SRussell King 638c9a2356fSRussell King static void mv88e6xxx_validate(struct dsa_switch *ds, int port, 639c9a2356fSRussell King unsigned long *supported, 640c9a2356fSRussell King struct phylink_link_state *state) 641c9a2356fSRussell King { 6426c422e34SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 6436c422e34SRussell King struct mv88e6xxx_chip *chip = ds->priv; 6446c422e34SRussell King 6456c422e34SRussell King /* Allow all the expected bits */ 6466c422e34SRussell King phylink_set(mask, Autoneg); 6476c422e34SRussell King phylink_set(mask, Pause); 6486c422e34SRussell King phylink_set_port_modes(mask); 6496c422e34SRussell King 6506c422e34SRussell King if (chip->info->ops->phylink_validate) 6516c422e34SRussell King chip->info->ops->phylink_validate(chip, port, mask, state); 6526c422e34SRussell King 6536c422e34SRussell King bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 6546c422e34SRussell King bitmap_and(state->advertising, state->advertising, mask, 6556c422e34SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS); 6566c422e34SRussell King 6576c422e34SRussell King /* We can only operate at 2500BaseX or 1000BaseX. If requested 6586c422e34SRussell King * to advertise both, only report advertising at 2500BaseX. 6596c422e34SRussell King */ 6606c422e34SRussell King phylink_helper_basex_speed(state); 661c9a2356fSRussell King } 662c9a2356fSRussell King 663c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 664c9a2356fSRussell King unsigned int mode, 665c9a2356fSRussell King const struct phylink_link_state *state) 666c9a2356fSRussell King { 667c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 668fad58190SRussell King struct mv88e6xxx_port *p; 66964d47d50SRussell King int err; 670c9a2356fSRussell King 671fad58190SRussell King p = &chip->ports[port]; 672fad58190SRussell King 67364d47d50SRussell King /* FIXME: is this the correct test? If we're in fixed mode on an 67464d47d50SRussell King * internal port, why should we process this any different from 67564d47d50SRussell King * PHY mode? On the other hand, the port may be automedia between 67664d47d50SRussell King * an internal PHY and the serdes... 67764d47d50SRussell King */ 678d700ec41SMarek Vasut if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) 679c9a2356fSRussell King return; 680c9a2356fSRussell King 681c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 682fad58190SRussell King /* In inband mode, the link may come up at any time while the link 683fad58190SRussell King * is not forced down. Force the link down while we reconfigure the 684fad58190SRussell King * interface mode. 68564d47d50SRussell King */ 686fad58190SRussell King if (mode == MLO_AN_INBAND && p->interface != state->interface && 687fad58190SRussell King chip->info->ops->port_set_link) 688fad58190SRussell King chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 689fad58190SRussell King 69064d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, state->interface); 691a5a6858bSRussell King if (err && err != -EOPNOTSUPP) 692a5a6858bSRussell King goto err_unlock; 693a5a6858bSRussell King 694a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface, 695a5a6858bSRussell King state->advertising); 696a5a6858bSRussell King /* FIXME: we should restart negotiation if something changed - which 697a5a6858bSRussell King * is something we get if we convert to using phylinks PCS operations. 698a5a6858bSRussell King */ 699a5a6858bSRussell King if (err > 0) 700a5a6858bSRussell King err = 0; 701a5a6858bSRussell King 702fad58190SRussell King /* Undo the forced down state above after completing configuration 703fad58190SRussell King * irrespective of its state on entry, which allows the link to come up. 704fad58190SRussell King */ 705fad58190SRussell King if (mode == MLO_AN_INBAND && p->interface != state->interface && 706fad58190SRussell King chip->info->ops->port_set_link) 707fad58190SRussell King chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); 708fad58190SRussell King 709fad58190SRussell King p->interface = state->interface; 710fad58190SRussell King 711a5a6858bSRussell King err_unlock: 712c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 713c9a2356fSRussell King 714c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 71564d47d50SRussell King dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); 716c9a2356fSRussell King } 717c9a2356fSRussell King 718c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 719c9a2356fSRussell King unsigned int mode, 720c9a2356fSRussell King phy_interface_t interface) 721c9a2356fSRussell King { 72230c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 72330c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 72430c4a5b0SRussell King int err = 0; 72530c4a5b0SRussell King 72630c4a5b0SRussell King ops = chip->info->ops; 72730c4a5b0SRussell King 72830c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 72934b5e6a3SAndrew Lunn if ((!mv88e6xxx_port_ppu_updates(chip, port) || 73034b5e6a3SAndrew Lunn mode == MLO_AN_FIXED) && ops->port_set_link) 73130c4a5b0SRussell King err = ops->port_set_link(chip, port, LINK_FORCED_DOWN); 73230c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 73330c4a5b0SRussell King 73430c4a5b0SRussell King if (err) 73530c4a5b0SRussell King dev_err(chip->dev, 73630c4a5b0SRussell King "p%d: failed to force MAC link down\n", port); 73730c4a5b0SRussell King } 738c9a2356fSRussell King 739c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 740c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 7415b502a7bSRussell King struct phy_device *phydev, 7425b502a7bSRussell King int speed, int duplex, 7435b502a7bSRussell King bool tx_pause, bool rx_pause) 744c9a2356fSRussell King { 74530c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 74630c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 74730c4a5b0SRussell King int err = 0; 74830c4a5b0SRussell King 74930c4a5b0SRussell King ops = chip->info->ops; 75030c4a5b0SRussell King 75130c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 75234b5e6a3SAndrew Lunn if (!mv88e6xxx_port_ppu_updates(chip, port) || mode == MLO_AN_FIXED) { 75330c4a5b0SRussell King /* FIXME: for an automedia port, should we force the link 75430c4a5b0SRussell King * down here - what if the link comes up due to "other" media 75530c4a5b0SRussell King * while we're bringing the port up, how is the exclusivity 756a5a6858bSRussell King * handled in the Marvell hardware? E.g. port 2 on 88E6390 75730c4a5b0SRussell King * shared between internal PHY and Serdes. 75830c4a5b0SRussell King */ 759a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed, 760a5a6858bSRussell King duplex); 761a5a6858bSRussell King if (err) 762a5a6858bSRussell King goto error; 763a5a6858bSRussell King 764f365c6f7SRussell King if (ops->port_set_speed_duplex) { 765f365c6f7SRussell King err = ops->port_set_speed_duplex(chip, port, 766f365c6f7SRussell King speed, duplex); 76730c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 76830c4a5b0SRussell King goto error; 76930c4a5b0SRussell King } 77030c4a5b0SRussell King 77130c4a5b0SRussell King if (ops->port_set_link) 77230c4a5b0SRussell King err = ops->port_set_link(chip, port, LINK_FORCED_UP); 7735d5b231dSRussell King } 77430c4a5b0SRussell King error: 77530c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 77630c4a5b0SRussell King 77730c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 77830c4a5b0SRussell King dev_err(ds->dev, 77930c4a5b0SRussell King "p%d: failed to configure MAC link up\n", port); 78030c4a5b0SRussell King } 781c9a2356fSRussell King 782a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 783fad09c73SVivien Didelot { 784a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 785a605a0feSAndrew Lunn return -EOPNOTSUPP; 786fad09c73SVivien Didelot 787a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 788fad09c73SVivien Didelot } 789fad09c73SVivien Didelot 790fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 791dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 792dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 793dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 794dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 795dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 796dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 797dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 798dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 799dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 800dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 801dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 802dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 803dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 804dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 805dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 806dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 807dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 808dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 809dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 810dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 811dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 812dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 813dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 814dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 815dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 816dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 817dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 818dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 819dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 820dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 821dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 822dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 823dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 824dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 825dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 826dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 827dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 828dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 829dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 830dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 831dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 832dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 833dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 834dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 835dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 836dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 837dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 838dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 839dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 840dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 841dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 842dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 843dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 844dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 845dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 846dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 847dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 848dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 849dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 850fad09c73SVivien Didelot }; 851fad09c73SVivien Didelot 852fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 853fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 854e0d8b615SAndrew Lunn int port, u16 bank1_select, 855e0d8b615SAndrew Lunn u16 histogram) 856fad09c73SVivien Didelot { 857fad09c73SVivien Didelot u32 low; 858fad09c73SVivien Didelot u32 high = 0; 859dfafe449SAndrew Lunn u16 reg = 0; 8600e7b9925SAndrew Lunn int err; 861fad09c73SVivien Didelot u64 value; 862fad09c73SVivien Didelot 863fad09c73SVivien Didelot switch (s->type) { 864dfafe449SAndrew Lunn case STATS_TYPE_PORT: 8650e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 8660e7b9925SAndrew Lunn if (err) 8676c3442f5SJisheng Zhang return U64_MAX; 868fad09c73SVivien Didelot 8690e7b9925SAndrew Lunn low = reg; 870cda9f4aaSAndrew Lunn if (s->size == 4) { 8710e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 8720e7b9925SAndrew Lunn if (err) 8736c3442f5SJisheng Zhang return U64_MAX; 87484b3fd1fSRasmus Villemoes low |= ((u32)reg) << 16; 875fad09c73SVivien Didelot } 876fad09c73SVivien Didelot break; 877dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 878e0d8b615SAndrew Lunn reg = bank1_select; 879df561f66SGustavo A. R. Silva fallthrough; 880dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 881e0d8b615SAndrew Lunn reg |= s->reg | histogram; 8827f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 883cda9f4aaSAndrew Lunn if (s->size == 8) 8847f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 8859fc3e4dcSGustavo A. R. Silva break; 8869fc3e4dcSGustavo A. R. Silva default: 8876c3442f5SJisheng Zhang return U64_MAX; 888fad09c73SVivien Didelot } 8896e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 890fad09c73SVivien Didelot return value; 891fad09c73SVivien Didelot } 892fad09c73SVivien Didelot 893436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 894dfafe449SAndrew Lunn uint8_t *data, int types) 895fad09c73SVivien Didelot { 896fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 897fad09c73SVivien Didelot int i, j; 898fad09c73SVivien Didelot 899fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 900fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 901dfafe449SAndrew Lunn if (stat->type & types) { 902fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 903fad09c73SVivien Didelot ETH_GSTRING_LEN); 904fad09c73SVivien Didelot j++; 905fad09c73SVivien Didelot } 906fad09c73SVivien Didelot } 907436fe17dSAndrew Lunn 908436fe17dSAndrew Lunn return j; 909fad09c73SVivien Didelot } 910fad09c73SVivien Didelot 911436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 912dfafe449SAndrew Lunn uint8_t *data) 913dfafe449SAndrew Lunn { 914436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 915dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 916dfafe449SAndrew Lunn } 917dfafe449SAndrew Lunn 9181f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 9191f71836fSRasmus Villemoes uint8_t *data) 9201f71836fSRasmus Villemoes { 9211f71836fSRasmus Villemoes return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 9221f71836fSRasmus Villemoes } 9231f71836fSRasmus Villemoes 924436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 925dfafe449SAndrew Lunn uint8_t *data) 926dfafe449SAndrew Lunn { 927436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 928dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 929dfafe449SAndrew Lunn } 930dfafe449SAndrew Lunn 93165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 93265f60e45SAndrew Lunn "atu_member_violation", 93365f60e45SAndrew Lunn "atu_miss_violation", 93465f60e45SAndrew Lunn "atu_full_violation", 93565f60e45SAndrew Lunn "vtu_member_violation", 93665f60e45SAndrew Lunn "vtu_miss_violation", 93765f60e45SAndrew Lunn }; 93865f60e45SAndrew Lunn 93965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 94065f60e45SAndrew Lunn { 94165f60e45SAndrew Lunn unsigned int i; 94265f60e45SAndrew Lunn 94365f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 94465f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 94565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 94665f60e45SAndrew Lunn ETH_GSTRING_LEN); 94765f60e45SAndrew Lunn } 94865f60e45SAndrew Lunn 949dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 95089f09048SFlorian Fainelli u32 stringset, uint8_t *data) 951fad09c73SVivien Didelot { 95204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 953436fe17dSAndrew Lunn int count = 0; 954dfafe449SAndrew Lunn 95589f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 95689f09048SFlorian Fainelli return; 95789f09048SFlorian Fainelli 958c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 959c6c8cd5eSAndrew Lunn 960dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 961436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 962436fe17dSAndrew Lunn 963436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 964436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 96565f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 966436fe17dSAndrew Lunn } 967c6c8cd5eSAndrew Lunn 96865f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 96965f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 97065f60e45SAndrew Lunn 971c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 972dfafe449SAndrew Lunn } 973dfafe449SAndrew Lunn 974dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 975dfafe449SAndrew Lunn int types) 976dfafe449SAndrew Lunn { 977fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 978fad09c73SVivien Didelot int i, j; 979fad09c73SVivien Didelot 980fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 981fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 982dfafe449SAndrew Lunn if (stat->type & types) 983fad09c73SVivien Didelot j++; 984fad09c73SVivien Didelot } 985fad09c73SVivien Didelot return j; 986fad09c73SVivien Didelot } 987fad09c73SVivien Didelot 988dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 989dfafe449SAndrew Lunn { 990dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 991dfafe449SAndrew Lunn STATS_TYPE_PORT); 992dfafe449SAndrew Lunn } 993dfafe449SAndrew Lunn 9941f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 9951f71836fSRasmus Villemoes { 9961f71836fSRasmus Villemoes return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 9971f71836fSRasmus Villemoes } 9981f71836fSRasmus Villemoes 999dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1000dfafe449SAndrew Lunn { 1001dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1002dfafe449SAndrew Lunn STATS_TYPE_BANK1); 1003dfafe449SAndrew Lunn } 1004dfafe449SAndrew Lunn 100589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 1006dfafe449SAndrew Lunn { 1007dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 1008436fe17dSAndrew Lunn int serdes_count = 0; 1009436fe17dSAndrew Lunn int count = 0; 1010dfafe449SAndrew Lunn 101189f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 101289f09048SFlorian Fainelli return 0; 101389f09048SFlorian Fainelli 1014c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1015dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 1016436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 1017436fe17dSAndrew Lunn if (count < 0) 1018436fe17dSAndrew Lunn goto out; 1019436fe17dSAndrew Lunn 1020436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 1021436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 1022436fe17dSAndrew Lunn port); 102365f60e45SAndrew Lunn if (serdes_count < 0) { 1024436fe17dSAndrew Lunn count = serdes_count; 102565f60e45SAndrew Lunn goto out; 102665f60e45SAndrew Lunn } 1027436fe17dSAndrew Lunn count += serdes_count; 102865f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 102965f60e45SAndrew Lunn 1030436fe17dSAndrew Lunn out: 1031c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1032dfafe449SAndrew Lunn 1033436fe17dSAndrew Lunn return count; 1034dfafe449SAndrew Lunn } 1035dfafe449SAndrew Lunn 1036436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1037e0d8b615SAndrew Lunn uint64_t *data, int types, 1038e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 1039052f947fSAndrew Lunn { 1040052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 1041052f947fSAndrew Lunn int i, j; 1042052f947fSAndrew Lunn 1043052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1044052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 1045052f947fSAndrew Lunn if (stat->type & types) { 1046c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1047e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 1048e0d8b615SAndrew Lunn bank1_select, 1049e0d8b615SAndrew Lunn histogram); 1050c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1051377cda13SAndrew Lunn 1052052f947fSAndrew Lunn j++; 1053052f947fSAndrew Lunn } 1054052f947fSAndrew Lunn } 1055436fe17dSAndrew Lunn return j; 1056052f947fSAndrew Lunn } 1057052f947fSAndrew Lunn 1058436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1059052f947fSAndrew Lunn uint64_t *data) 1060052f947fSAndrew Lunn { 1061052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1062e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 106357d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1064052f947fSAndrew Lunn } 1065052f947fSAndrew Lunn 10661f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 10671f71836fSRasmus Villemoes uint64_t *data) 10681f71836fSRasmus Villemoes { 10691f71836fSRasmus Villemoes return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 10701f71836fSRasmus Villemoes 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 10711f71836fSRasmus Villemoes } 10721f71836fSRasmus Villemoes 1073436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1074052f947fSAndrew Lunn uint64_t *data) 1075052f947fSAndrew Lunn { 1076052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1077e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 107857d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 107957d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1080e0d8b615SAndrew Lunn } 1081e0d8b615SAndrew Lunn 1082436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1083e0d8b615SAndrew Lunn uint64_t *data) 1084e0d8b615SAndrew Lunn { 1085e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1086e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 108757d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 108857d1ef38SVivien Didelot 0); 1089052f947fSAndrew Lunn } 1090052f947fSAndrew Lunn 109165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 109265f60e45SAndrew Lunn uint64_t *data) 109365f60e45SAndrew Lunn { 109465f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 109565f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 109665f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 109765f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 109865f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 109965f60e45SAndrew Lunn } 110065f60e45SAndrew Lunn 1101052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1102052f947fSAndrew Lunn uint64_t *data) 1103052f947fSAndrew Lunn { 1104436fe17dSAndrew Lunn int count = 0; 1105436fe17dSAndrew Lunn 1106052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1107436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1108436fe17dSAndrew Lunn 1109c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1110436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1111436fe17dSAndrew Lunn data += count; 111265f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1113436fe17dSAndrew Lunn } 111465f60e45SAndrew Lunn data += count; 111565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 1116c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1117052f947fSAndrew Lunn } 1118052f947fSAndrew Lunn 1119fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1120fad09c73SVivien Didelot uint64_t *data) 1121fad09c73SVivien Didelot { 112204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1123fad09c73SVivien Didelot int ret; 1124fad09c73SVivien Didelot 1125c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1126fad09c73SVivien Didelot 1127a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1128c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1129377cda13SAndrew Lunn 1130377cda13SAndrew Lunn if (ret < 0) 1131fad09c73SVivien Didelot return; 1132052f947fSAndrew Lunn 1133052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1134fad09c73SVivien Didelot 1135fad09c73SVivien Didelot } 1136fad09c73SVivien Didelot 1137fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1138fad09c73SVivien Didelot { 11390d30bbd0SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 11400d30bbd0SAndrew Lunn int len; 11410d30bbd0SAndrew Lunn 11420d30bbd0SAndrew Lunn len = 32 * sizeof(u16); 11430d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs_len) 11440d30bbd0SAndrew Lunn len += chip->info->ops->serdes_get_regs_len(chip, port); 11450d30bbd0SAndrew Lunn 11460d30bbd0SAndrew Lunn return len; 1147fad09c73SVivien Didelot } 1148fad09c73SVivien Didelot 1149fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1150fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1151fad09c73SVivien Didelot { 115204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 11530e7b9925SAndrew Lunn int err; 11540e7b9925SAndrew Lunn u16 reg; 1155fad09c73SVivien Didelot u16 *p = _p; 1156fad09c73SVivien Didelot int i; 1157fad09c73SVivien Didelot 1158a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1159fad09c73SVivien Didelot 1160fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1161fad09c73SVivien Didelot 1162c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1163fad09c73SVivien Didelot 1164fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1165fad09c73SVivien Didelot 11660e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 11670e7b9925SAndrew Lunn if (!err) 11680e7b9925SAndrew Lunn p[i] = reg; 1169fad09c73SVivien Didelot } 1170fad09c73SVivien Didelot 11710d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs) 11720d30bbd0SAndrew Lunn chip->info->ops->serdes_get_regs(chip, port, &p[i]); 11730d30bbd0SAndrew Lunn 1174c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1175fad09c73SVivien Didelot } 1176fad09c73SVivien Didelot 117708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1178fad09c73SVivien Didelot struct ethtool_eee *e) 1179fad09c73SVivien Didelot { 11805480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11815480db69SVivien Didelot return 0; 1182fad09c73SVivien Didelot } 1183fad09c73SVivien Didelot 118408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 118546587e4aSVivien Didelot struct ethtool_eee *e) 1186fad09c73SVivien Didelot { 11875480db69SVivien Didelot /* Nothing to do on the port's MAC */ 11885480db69SVivien Didelot return 0; 1189fad09c73SVivien Didelot } 1190fad09c73SVivien Didelot 11919dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */ 1192e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1193fad09c73SVivien Didelot { 11949dc8b13eSVivien Didelot struct dsa_switch *ds = chip->ds; 11959dc8b13eSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 1196e5887a2aSVivien Didelot struct net_device *br; 11979dc8b13eSVivien Didelot struct dsa_port *dp; 11989dc8b13eSVivien Didelot bool found = false; 1199e5887a2aSVivien Didelot u16 pvlan; 1200fad09c73SVivien Didelot 12019dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 12029dc8b13eSVivien Didelot if (dp->ds->index == dev && dp->index == port) { 12039dc8b13eSVivien Didelot found = true; 12049dc8b13eSVivien Didelot break; 12059dc8b13eSVivien Didelot } 12069dc8b13eSVivien Didelot } 1207fad09c73SVivien Didelot 1208e5887a2aSVivien Didelot /* Prevent frames from unknown switch or port */ 12099dc8b13eSVivien Didelot if (!found) 1210e5887a2aSVivien Didelot return 0; 1211e5887a2aSVivien Didelot 1212e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 12139dc8b13eSVivien Didelot if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) 1214e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1215e5887a2aSVivien Didelot 12169dc8b13eSVivien Didelot br = dp->bridge_dev; 1217e5887a2aSVivien Didelot pvlan = 0; 1218e5887a2aSVivien Didelot 1219e5887a2aSVivien Didelot /* Frames from user ports can egress any local DSA links and CPU ports, 1220e5887a2aSVivien Didelot * as well as any local member of their bridge group. 1221e5887a2aSVivien Didelot */ 12229dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) 12239dc8b13eSVivien Didelot if (dp->ds == ds && 12249dc8b13eSVivien Didelot (dp->type == DSA_PORT_TYPE_CPU || 12259dc8b13eSVivien Didelot dp->type == DSA_PORT_TYPE_DSA || 12269dc8b13eSVivien Didelot (br && dp->bridge_dev == br))) 12279dc8b13eSVivien Didelot pvlan |= BIT(dp->index); 1228e5887a2aSVivien Didelot 1229e5887a2aSVivien Didelot return pvlan; 1230fad09c73SVivien Didelot } 1231e5887a2aSVivien Didelot 1232240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1233e5887a2aSVivien Didelot { 1234e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1235fad09c73SVivien Didelot 1236fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1237fad09c73SVivien Didelot output_ports &= ~BIT(port); 1238fad09c73SVivien Didelot 12395a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1240fad09c73SVivien Didelot } 1241fad09c73SVivien Didelot 1242fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1243fad09c73SVivien Didelot u8 state) 1244fad09c73SVivien Didelot { 124504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1246fad09c73SVivien Didelot int err; 1247fad09c73SVivien Didelot 1248c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1249f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1250c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1251fad09c73SVivien Didelot 1252fad09c73SVivien Didelot if (err) 1253774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1254fad09c73SVivien Didelot } 1255fad09c73SVivien Didelot 125693e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 125793e18d61SVivien Didelot { 125893e18d61SVivien Didelot int err; 125993e18d61SVivien Didelot 126093e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 126193e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 126293e18d61SVivien Didelot if (err) 126393e18d61SVivien Didelot return err; 126493e18d61SVivien Didelot } 126593e18d61SVivien Didelot 126693e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 126793e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 126893e18d61SVivien Didelot if (err) 126993e18d61SVivien Didelot return err; 127093e18d61SVivien Didelot } 127193e18d61SVivien Didelot 127293e18d61SVivien Didelot return 0; 127393e18d61SVivien Didelot } 127493e18d61SVivien Didelot 1275c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1276c7f047b6SVivien Didelot { 1277c5f51765SVivien Didelot struct dsa_switch *ds = chip->ds; 1278c7f047b6SVivien Didelot int target, port; 1279c7f047b6SVivien Didelot int err; 1280c7f047b6SVivien Didelot 1281c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1282c7f047b6SVivien Didelot return 0; 1283c7f047b6SVivien Didelot 1284c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1285c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1286c5f51765SVivien Didelot port = dsa_routing_port(ds, target); 1287c5f51765SVivien Didelot if (port == ds->num_ports) 1288c7f047b6SVivien Didelot port = 0x1f; 1289c7f047b6SVivien Didelot 1290c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1291c7f047b6SVivien Didelot if (err) 1292c7f047b6SVivien Didelot return err; 1293c7f047b6SVivien Didelot } 1294c7f047b6SVivien Didelot 129502317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 129602317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 129702317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 129802317e68SVivien Didelot if (err) 129902317e68SVivien Didelot return err; 130002317e68SVivien Didelot } 130102317e68SVivien Didelot 130223c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 130323c98919SVivien Didelot if (err) 130423c98919SVivien Didelot return err; 130523c98919SVivien Didelot 1306c7f047b6SVivien Didelot return 0; 1307c7f047b6SVivien Didelot } 1308c7f047b6SVivien Didelot 1309b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1310b28f872dSVivien Didelot { 1311b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1312b28f872dSVivien Didelot if (chip->info->global2_addr) 1313b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1314b28f872dSVivien Didelot 1315b28f872dSVivien Didelot return 0; 1316b28f872dSVivien Didelot } 1317b28f872dSVivien Didelot 13189e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 13199e5baf9bSVivien Didelot { 13209e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 13219e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 13229e5baf9bSVivien Didelot 13239e5baf9bSVivien Didelot return 0; 13249e5baf9bSVivien Didelot } 13259e5baf9bSVivien Didelot 13269e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 13279e907d73SVivien Didelot { 13289e907d73SVivien Didelot if (chip->info->ops->pot_clear) 13299e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 13309e907d73SVivien Didelot 13319e907d73SVivien Didelot return 0; 13329e907d73SVivien Didelot } 13339e907d73SVivien Didelot 133451c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 133551c901a7SVivien Didelot { 133651c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 133751c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 133851c901a7SVivien Didelot 133951c901a7SVivien Didelot return 0; 134051c901a7SVivien Didelot } 134151c901a7SVivien Didelot 1342a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1343a2ac29d2SVivien Didelot { 1344c3a7d4adSVivien Didelot int err; 1345c3a7d4adSVivien Didelot 1346daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1347daefc943SVivien Didelot if (err) 1348daefc943SVivien Didelot return err; 1349daefc943SVivien Didelot 1350c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1351c3a7d4adSVivien Didelot if (err) 1352c3a7d4adSVivien Didelot return err; 1353c3a7d4adSVivien Didelot 1354a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1355a2ac29d2SVivien Didelot } 1356a2ac29d2SVivien Didelot 1357cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1358cd8da8bbSVivien Didelot { 1359cd8da8bbSVivien Didelot int port; 1360cd8da8bbSVivien Didelot int err; 1361cd8da8bbSVivien Didelot 1362cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1363cd8da8bbSVivien Didelot return 0; 1364cd8da8bbSVivien Didelot 1365cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1366cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1367cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1368cd8da8bbSVivien Didelot */ 1369cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1370cd8da8bbSVivien Didelot if (err) 1371cd8da8bbSVivien Didelot return err; 1372cd8da8bbSVivien Didelot } 1373cd8da8bbSVivien Didelot 1374cd8da8bbSVivien Didelot return 0; 1375cd8da8bbSVivien Didelot } 1376cd8da8bbSVivien Didelot 137704a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 137804a69a17SVivien Didelot { 137904a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 138004a69a17SVivien Didelot u8 addr[ETH_ALEN]; 138104a69a17SVivien Didelot 138204a69a17SVivien Didelot eth_random_addr(addr); 138304a69a17SVivien Didelot 138404a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 138504a69a17SVivien Didelot } 138604a69a17SVivien Didelot 138704a69a17SVivien Didelot return 0; 138804a69a17SVivien Didelot } 138904a69a17SVivien Didelot 139017a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 139117a1594eSVivien Didelot { 139217a1594eSVivien Didelot u16 pvlan = 0; 139317a1594eSVivien Didelot 139417a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1395d14939beSVivien Didelot return 0; 139617a1594eSVivien Didelot 139717a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 139817a1594eSVivien Didelot if (dev != chip->ds->index) 1399aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 140017a1594eSVivien Didelot 140117a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 140217a1594eSVivien Didelot } 140317a1594eSVivien Didelot 140481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 140581228996SVivien Didelot { 140617a1594eSVivien Didelot int dev, port; 140717a1594eSVivien Didelot int err; 140817a1594eSVivien Didelot 140981228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 141081228996SVivien Didelot return 0; 141181228996SVivien Didelot 141281228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 141381228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 141481228996SVivien Didelot */ 141517a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 141617a1594eSVivien Didelot if (err) 141717a1594eSVivien Didelot return err; 141817a1594eSVivien Didelot 141917a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 142017a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 142117a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 142217a1594eSVivien Didelot if (err) 142317a1594eSVivien Didelot return err; 142417a1594eSVivien Didelot } 142517a1594eSVivien Didelot } 142617a1594eSVivien Didelot 142717a1594eSVivien Didelot return 0; 142881228996SVivien Didelot } 142981228996SVivien Didelot 1430749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1431749efcb8SVivien Didelot { 1432749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1433749efcb8SVivien Didelot int err; 1434749efcb8SVivien Didelot 1435c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1436e606ca36SVivien Didelot err = mv88e6xxx_g1_atu_remove(chip, 0, port, false); 1437c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1438749efcb8SVivien Didelot 1439749efcb8SVivien Didelot if (err) 1440774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to flush ATU\n", port); 1441749efcb8SVivien Didelot } 1442749efcb8SVivien Didelot 1443b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1444b486d7c9SVivien Didelot { 1445b486d7c9SVivien Didelot if (!chip->info->max_vid) 1446b486d7c9SVivien Didelot return 0; 1447b486d7c9SVivien Didelot 1448b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1449b486d7c9SVivien Didelot } 1450b486d7c9SVivien Didelot 1451f1394b78SVivien Didelot static int mv88e6xxx_vtu_getnext(struct mv88e6xxx_chip *chip, 1452f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1453f1394b78SVivien Didelot { 1454f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1455f1394b78SVivien Didelot return -EOPNOTSUPP; 1456f1394b78SVivien Didelot 1457f1394b78SVivien Didelot return chip->info->ops->vtu_getnext(chip, entry); 1458f1394b78SVivien Didelot } 1459f1394b78SVivien Didelot 14600ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 14610ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 14620ad5daf6SVivien Didelot { 14630ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 14640ad5daf6SVivien Didelot return -EOPNOTSUPP; 14650ad5daf6SVivien Didelot 14660ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 14670ad5daf6SVivien Didelot } 14680ad5daf6SVivien Didelot 146990b6dbdfSAndrew Lunn int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap) 1470fad09c73SVivien Didelot { 1471425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1472fad09c73SVivien Didelot int i, err; 147390b6dbdfSAndrew Lunn u16 fid; 1474fad09c73SVivien Didelot 1475fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1476fad09c73SVivien Didelot 1477fad09c73SVivien Didelot /* Set every FID bit used by the (un)bridged ports */ 1478370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 147990b6dbdfSAndrew Lunn err = mv88e6xxx_port_get_fid(chip, i, &fid); 1480fad09c73SVivien Didelot if (err) 1481fad09c73SVivien Didelot return err; 1482fad09c73SVivien Didelot 148390b6dbdfSAndrew Lunn set_bit(fid, fid_bitmap); 1484fad09c73SVivien Didelot } 1485fad09c73SVivien Didelot 1486fad09c73SVivien Didelot /* Set every FID bit used by the VLAN entries */ 1487425d2d37SVivien Didelot vlan.vid = chip->info->max_vid; 1488425d2d37SVivien Didelot vlan.valid = false; 1489425d2d37SVivien Didelot 1490fad09c73SVivien Didelot do { 1491f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1492fad09c73SVivien Didelot if (err) 1493fad09c73SVivien Didelot return err; 1494fad09c73SVivien Didelot 1495fad09c73SVivien Didelot if (!vlan.valid) 1496fad09c73SVivien Didelot break; 1497fad09c73SVivien Didelot 1498fad09c73SVivien Didelot set_bit(vlan.fid, fid_bitmap); 14993cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 1500fad09c73SVivien Didelot 150190b6dbdfSAndrew Lunn return 0; 150290b6dbdfSAndrew Lunn } 150390b6dbdfSAndrew Lunn 150490b6dbdfSAndrew Lunn static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 150590b6dbdfSAndrew Lunn { 150690b6dbdfSAndrew Lunn DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 150790b6dbdfSAndrew Lunn int err; 150890b6dbdfSAndrew Lunn 150990b6dbdfSAndrew Lunn err = mv88e6xxx_fid_map(chip, fid_bitmap); 151090b6dbdfSAndrew Lunn if (err) 151190b6dbdfSAndrew Lunn return err; 151290b6dbdfSAndrew Lunn 1513fad09c73SVivien Didelot /* The reset value 0x000 is used to indicate that multiple address 1514fad09c73SVivien Didelot * databases are not needed. Return the next positive available. 1515fad09c73SVivien Didelot */ 1516fad09c73SVivien Didelot *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1); 1517fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1518fad09c73SVivien Didelot return -ENOSPC; 1519fad09c73SVivien Didelot 1520fad09c73SVivien Didelot /* Clear the database */ 1521daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1522fad09c73SVivien Didelot } 1523fad09c73SVivien Didelot 1524fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1525fad09c73SVivien Didelot u16 vid_begin, u16 vid_end) 1526fad09c73SVivien Didelot { 152704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1528425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1529fad09c73SVivien Didelot int i, err; 1530fad09c73SVivien Didelot 1531db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 1532db06ae41SAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 1533db06ae41SAndrew Lunn return 0; 1534db06ae41SAndrew Lunn 1535fad09c73SVivien Didelot if (!vid_begin) 1536fad09c73SVivien Didelot return -EOPNOTSUPP; 1537fad09c73SVivien Didelot 1538425d2d37SVivien Didelot vlan.vid = vid_begin - 1; 1539425d2d37SVivien Didelot vlan.valid = false; 1540425d2d37SVivien Didelot 1541fad09c73SVivien Didelot do { 1542f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1543fad09c73SVivien Didelot if (err) 15447095a4c4SVivien Didelot return err; 1545fad09c73SVivien Didelot 1546fad09c73SVivien Didelot if (!vlan.valid) 1547fad09c73SVivien Didelot break; 1548fad09c73SVivien Didelot 1549fad09c73SVivien Didelot if (vlan.vid > vid_end) 1550fad09c73SVivien Didelot break; 1551fad09c73SVivien Didelot 1552370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 1553fad09c73SVivien Didelot if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) 1554fad09c73SVivien Didelot continue; 1555fad09c73SVivien Didelot 155668bb8ea8SVivien Didelot if (!dsa_to_port(ds, i)->slave) 155766e2809dSAndrew Lunn continue; 155866e2809dSAndrew Lunn 1559bd00e053SVivien Didelot if (vlan.member[i] == 15607ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 1561fad09c73SVivien Didelot continue; 1562fad09c73SVivien Didelot 1563c8652c83SVivien Didelot if (dsa_to_port(ds, i)->bridge_dev == 156468bb8ea8SVivien Didelot dsa_to_port(ds, port)->bridge_dev) 1565fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 1566fad09c73SVivien Didelot 1567c8652c83SVivien Didelot if (!dsa_to_port(ds, i)->bridge_dev) 156866e2809dSAndrew Lunn continue; 156966e2809dSAndrew Lunn 1570743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 1571743fcc28SAndrew Lunn port, vlan.vid, i, 1572c8652c83SVivien Didelot netdev_name(dsa_to_port(ds, i)->bridge_dev)); 15737095a4c4SVivien Didelot return -EOPNOTSUPP; 1574fad09c73SVivien Didelot } 1575fad09c73SVivien Didelot } while (vlan.vid < vid_end); 1576fad09c73SVivien Didelot 15777095a4c4SVivien Didelot return 0; 1578fad09c73SVivien Didelot } 1579fad09c73SVivien Didelot 1580fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 1581fad09c73SVivien Didelot bool vlan_filtering) 1582fad09c73SVivien Didelot { 158304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 158481c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 158581c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 15860e7b9925SAndrew Lunn int err; 1587fad09c73SVivien Didelot 15883cf3c846SVivien Didelot if (!chip->info->max_vid) 1589fad09c73SVivien Didelot return -EOPNOTSUPP; 1590fad09c73SVivien Didelot 1591c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1592385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 1593c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1594fad09c73SVivien Didelot 15950e7b9925SAndrew Lunn return err; 1596fad09c73SVivien Didelot } 1597fad09c73SVivien Didelot 1598fad09c73SVivien Didelot static int 1599fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 160080e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1601fad09c73SVivien Didelot { 160204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1603fad09c73SVivien Didelot int err; 1604fad09c73SVivien Didelot 16053cf3c846SVivien Didelot if (!chip->info->max_vid) 1606fad09c73SVivien Didelot return -EOPNOTSUPP; 1607fad09c73SVivien Didelot 1608fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 1609fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 1610fad09c73SVivien Didelot */ 16117095a4c4SVivien Didelot mv88e6xxx_reg_lock(chip); 1612fad09c73SVivien Didelot err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin, 1613fad09c73SVivien Didelot vlan->vid_end); 16147095a4c4SVivien Didelot mv88e6xxx_reg_unlock(chip); 1615fad09c73SVivien Didelot 1616fad09c73SVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 1617fad09c73SVivien Didelot * so skip the prepare phase. 1618fad09c73SVivien Didelot */ 16197095a4c4SVivien Didelot return err; 1620fad09c73SVivien Didelot } 1621fad09c73SVivien Didelot 1622a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 1623a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 1624a4c93ae1SAndrew Lunn u8 state) 1625a4c93ae1SAndrew Lunn { 1626a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 16275ef8d249SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 16285ef8d249SVivien Didelot u16 fid; 1629a4c93ae1SAndrew Lunn int err; 1630a4c93ae1SAndrew Lunn 1631a4c93ae1SAndrew Lunn /* Null VLAN ID corresponds to the port private database */ 16325ef8d249SVivien Didelot if (vid == 0) { 16335ef8d249SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 1634a4c93ae1SAndrew Lunn if (err) 1635a4c93ae1SAndrew Lunn return err; 16365ef8d249SVivien Didelot } else { 16375ef8d249SVivien Didelot vlan.vid = vid - 1; 16385ef8d249SVivien Didelot vlan.valid = false; 16395ef8d249SVivien Didelot 16405ef8d249SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 16415ef8d249SVivien Didelot if (err) 16425ef8d249SVivien Didelot return err; 16435ef8d249SVivien Didelot 16445ef8d249SVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 16455ef8d249SVivien Didelot if (vlan.vid != vid || !vlan.valid) 16465ef8d249SVivien Didelot return -EOPNOTSUPP; 16475ef8d249SVivien Didelot 16485ef8d249SVivien Didelot fid = vlan.fid; 16495ef8d249SVivien Didelot } 1650a4c93ae1SAndrew Lunn 1651d8291a95SVivien Didelot entry.state = 0; 1652a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1653a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 1654a4c93ae1SAndrew Lunn 16555ef8d249SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry); 1656a4c93ae1SAndrew Lunn if (err) 1657a4c93ae1SAndrew Lunn return err; 1658a4c93ae1SAndrew Lunn 1659a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 1660d8291a95SVivien Didelot if (!entry.state || !ether_addr_equal(entry.mac, addr)) { 1661a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 1662a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 1663a4c93ae1SAndrew Lunn } 1664a4c93ae1SAndrew Lunn 1665a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 1666d8291a95SVivien Didelot if (!state) { 1667a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 1668a4c93ae1SAndrew Lunn if (!entry.portvec) 1669d8291a95SVivien Didelot entry.state = 0; 1670a4c93ae1SAndrew Lunn } else { 1671a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 1672a4c93ae1SAndrew Lunn entry.state = state; 1673a4c93ae1SAndrew Lunn } 1674a4c93ae1SAndrew Lunn 16755ef8d249SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry); 1676a4c93ae1SAndrew Lunn } 1677a4c93ae1SAndrew Lunn 1678da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port, 1679da7dc875SVivien Didelot const struct mv88e6xxx_policy *policy) 1680da7dc875SVivien Didelot { 1681da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping = policy->mapping; 1682da7dc875SVivien Didelot enum mv88e6xxx_policy_action action = policy->action; 1683da7dc875SVivien Didelot const u8 *addr = policy->addr; 1684da7dc875SVivien Didelot u16 vid = policy->vid; 1685da7dc875SVivien Didelot u8 state; 1686da7dc875SVivien Didelot int err; 1687da7dc875SVivien Didelot int id; 1688da7dc875SVivien Didelot 1689da7dc875SVivien Didelot if (!chip->info->ops->port_set_policy) 1690da7dc875SVivien Didelot return -EOPNOTSUPP; 1691da7dc875SVivien Didelot 1692da7dc875SVivien Didelot switch (mapping) { 1693da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_DA: 1694da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_SA: 1695da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1696da7dc875SVivien Didelot state = 0; /* Dissociate the port and address */ 1697da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1698da7dc875SVivien Didelot is_multicast_ether_addr(addr)) 1699da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY; 1700da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 1701da7dc875SVivien Didelot is_unicast_ether_addr(addr)) 1702da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY; 1703da7dc875SVivien Didelot else 1704da7dc875SVivien Didelot return -EOPNOTSUPP; 1705da7dc875SVivien Didelot 1706da7dc875SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 1707da7dc875SVivien Didelot state); 1708da7dc875SVivien Didelot if (err) 1709da7dc875SVivien Didelot return err; 1710da7dc875SVivien Didelot break; 1711da7dc875SVivien Didelot default: 1712da7dc875SVivien Didelot return -EOPNOTSUPP; 1713da7dc875SVivien Didelot } 1714da7dc875SVivien Didelot 1715da7dc875SVivien Didelot /* Skip the port's policy clearing if the mapping is still in use */ 1716da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 1717da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1718da7dc875SVivien Didelot if (policy->port == port && 1719da7dc875SVivien Didelot policy->mapping == mapping && 1720da7dc875SVivien Didelot policy->action != action) 1721da7dc875SVivien Didelot return 0; 1722da7dc875SVivien Didelot 1723da7dc875SVivien Didelot return chip->info->ops->port_set_policy(chip, port, mapping, action); 1724da7dc875SVivien Didelot } 1725da7dc875SVivien Didelot 1726da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port, 1727da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs) 1728da7dc875SVivien Didelot { 1729da7dc875SVivien Didelot struct ethhdr *mac_entry = &fs->h_u.ether_spec; 1730da7dc875SVivien Didelot struct ethhdr *mac_mask = &fs->m_u.ether_spec; 1731da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping; 1732da7dc875SVivien Didelot enum mv88e6xxx_policy_action action; 1733da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1734da7dc875SVivien Didelot u16 vid = 0; 1735da7dc875SVivien Didelot u8 *addr; 1736da7dc875SVivien Didelot int err; 1737da7dc875SVivien Didelot int id; 1738da7dc875SVivien Didelot 1739da7dc875SVivien Didelot if (fs->location != RX_CLS_LOC_ANY) 1740da7dc875SVivien Didelot return -EINVAL; 1741da7dc875SVivien Didelot 1742da7dc875SVivien Didelot if (fs->ring_cookie == RX_CLS_FLOW_DISC) 1743da7dc875SVivien Didelot action = MV88E6XXX_POLICY_ACTION_DISCARD; 1744da7dc875SVivien Didelot else 1745da7dc875SVivien Didelot return -EOPNOTSUPP; 1746da7dc875SVivien Didelot 1747da7dc875SVivien Didelot switch (fs->flow_type & ~FLOW_EXT) { 1748da7dc875SVivien Didelot case ETHER_FLOW: 1749da7dc875SVivien Didelot if (!is_zero_ether_addr(mac_mask->h_dest) && 1750da7dc875SVivien Didelot is_zero_ether_addr(mac_mask->h_source)) { 1751da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_DA; 1752da7dc875SVivien Didelot addr = mac_entry->h_dest; 1753da7dc875SVivien Didelot } else if (is_zero_ether_addr(mac_mask->h_dest) && 1754da7dc875SVivien Didelot !is_zero_ether_addr(mac_mask->h_source)) { 1755da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_SA; 1756da7dc875SVivien Didelot addr = mac_entry->h_source; 1757da7dc875SVivien Didelot } else { 1758da7dc875SVivien Didelot /* Cannot support DA and SA mapping in the same rule */ 1759da7dc875SVivien Didelot return -EOPNOTSUPP; 1760da7dc875SVivien Didelot } 1761da7dc875SVivien Didelot break; 1762da7dc875SVivien Didelot default: 1763da7dc875SVivien Didelot return -EOPNOTSUPP; 1764da7dc875SVivien Didelot } 1765da7dc875SVivien Didelot 1766da7dc875SVivien Didelot if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) { 176704844280SAndrew Lunn if (fs->m_ext.vlan_tci != htons(0xffff)) 1768da7dc875SVivien Didelot return -EOPNOTSUPP; 1769da7dc875SVivien Didelot vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; 1770da7dc875SVivien Didelot } 1771da7dc875SVivien Didelot 1772da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) { 1773da7dc875SVivien Didelot if (policy->port == port && policy->mapping == mapping && 1774da7dc875SVivien Didelot policy->action == action && policy->vid == vid && 1775da7dc875SVivien Didelot ether_addr_equal(policy->addr, addr)) 1776da7dc875SVivien Didelot return -EEXIST; 1777da7dc875SVivien Didelot } 1778da7dc875SVivien Didelot 1779da7dc875SVivien Didelot policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL); 1780da7dc875SVivien Didelot if (!policy) 1781da7dc875SVivien Didelot return -ENOMEM; 1782da7dc875SVivien Didelot 1783da7dc875SVivien Didelot fs->location = 0; 1784da7dc875SVivien Didelot err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff, 1785da7dc875SVivien Didelot GFP_KERNEL); 1786da7dc875SVivien Didelot if (err) { 1787da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1788da7dc875SVivien Didelot return err; 1789da7dc875SVivien Didelot } 1790da7dc875SVivien Didelot 1791da7dc875SVivien Didelot memcpy(&policy->fs, fs, sizeof(*fs)); 1792da7dc875SVivien Didelot ether_addr_copy(policy->addr, addr); 1793da7dc875SVivien Didelot policy->mapping = mapping; 1794da7dc875SVivien Didelot policy->action = action; 1795da7dc875SVivien Didelot policy->port = port; 1796da7dc875SVivien Didelot policy->vid = vid; 1797da7dc875SVivien Didelot 1798da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1799da7dc875SVivien Didelot if (err) { 1800da7dc875SVivien Didelot idr_remove(&chip->policies, fs->location); 1801da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1802da7dc875SVivien Didelot return err; 1803da7dc875SVivien Didelot } 1804da7dc875SVivien Didelot 1805da7dc875SVivien Didelot return 0; 1806da7dc875SVivien Didelot } 1807da7dc875SVivien Didelot 1808da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, 1809da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 1810da7dc875SVivien Didelot { 1811da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1812da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1813da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1814da7dc875SVivien Didelot int err; 1815da7dc875SVivien Didelot int id; 1816da7dc875SVivien Didelot 1817da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1818da7dc875SVivien Didelot 1819da7dc875SVivien Didelot switch (rxnfc->cmd) { 1820da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLCNT: 1821da7dc875SVivien Didelot rxnfc->data = 0; 1822da7dc875SVivien Didelot rxnfc->data |= RX_CLS_LOC_SPECIAL; 1823da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1824da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1825da7dc875SVivien Didelot if (policy->port == port) 1826da7dc875SVivien Didelot rxnfc->rule_cnt++; 1827da7dc875SVivien Didelot err = 0; 1828da7dc875SVivien Didelot break; 1829da7dc875SVivien Didelot case ETHTOOL_GRXCLSRULE: 1830da7dc875SVivien Didelot err = -ENOENT; 1831da7dc875SVivien Didelot policy = idr_find(&chip->policies, fs->location); 1832da7dc875SVivien Didelot if (policy) { 1833da7dc875SVivien Didelot memcpy(fs, &policy->fs, sizeof(*fs)); 1834da7dc875SVivien Didelot err = 0; 1835da7dc875SVivien Didelot } 1836da7dc875SVivien Didelot break; 1837da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLALL: 1838da7dc875SVivien Didelot rxnfc->data = 0; 1839da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 1840da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 1841da7dc875SVivien Didelot if (policy->port == port) 1842da7dc875SVivien Didelot rule_locs[rxnfc->rule_cnt++] = id; 1843da7dc875SVivien Didelot err = 0; 1844da7dc875SVivien Didelot break; 1845da7dc875SVivien Didelot default: 1846da7dc875SVivien Didelot err = -EOPNOTSUPP; 1847da7dc875SVivien Didelot break; 1848da7dc875SVivien Didelot } 1849da7dc875SVivien Didelot 1850da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1851da7dc875SVivien Didelot 1852da7dc875SVivien Didelot return err; 1853da7dc875SVivien Didelot } 1854da7dc875SVivien Didelot 1855da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, 1856da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc) 1857da7dc875SVivien Didelot { 1858da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 1859da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1860da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 1861da7dc875SVivien Didelot int err; 1862da7dc875SVivien Didelot 1863da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 1864da7dc875SVivien Didelot 1865da7dc875SVivien Didelot switch (rxnfc->cmd) { 1866da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLINS: 1867da7dc875SVivien Didelot err = mv88e6xxx_policy_insert(chip, port, fs); 1868da7dc875SVivien Didelot break; 1869da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLDEL: 1870da7dc875SVivien Didelot err = -ENOENT; 1871da7dc875SVivien Didelot policy = idr_remove(&chip->policies, fs->location); 1872da7dc875SVivien Didelot if (policy) { 1873da7dc875SVivien Didelot policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; 1874da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 1875da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 1876da7dc875SVivien Didelot } 1877da7dc875SVivien Didelot break; 1878da7dc875SVivien Didelot default: 1879da7dc875SVivien Didelot err = -EOPNOTSUPP; 1880da7dc875SVivien Didelot break; 1881da7dc875SVivien Didelot } 1882da7dc875SVivien Didelot 1883da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 1884da7dc875SVivien Didelot 1885da7dc875SVivien Didelot return err; 1886da7dc875SVivien Didelot } 1887da7dc875SVivien Didelot 188887fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 188987fa886eSAndrew Lunn u16 vid) 189087fa886eSAndrew Lunn { 189187fa886eSAndrew Lunn const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 189287fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 189387fa886eSAndrew Lunn 189487fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 189587fa886eSAndrew Lunn } 189687fa886eSAndrew Lunn 189787fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 189887fa886eSAndrew Lunn { 189987fa886eSAndrew Lunn int port; 190087fa886eSAndrew Lunn int err; 190187fa886eSAndrew Lunn 190287fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 190387fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 190487fa886eSAndrew Lunn if (err) 190587fa886eSAndrew Lunn return err; 190687fa886eSAndrew Lunn } 190787fa886eSAndrew Lunn 190887fa886eSAndrew Lunn return 0; 190987fa886eSAndrew Lunn } 191087fa886eSAndrew Lunn 1911b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, 1912933b4425SRussell King u16 vid, u8 member, bool warn) 1913fad09c73SVivien Didelot { 1914b1ac6fb4SVivien Didelot const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 1915b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 1916b1ac6fb4SVivien Didelot int i, err; 1917fad09c73SVivien Didelot 1918b1ac6fb4SVivien Didelot if (!vid) 1919b1ac6fb4SVivien Didelot return -EOPNOTSUPP; 1920b1ac6fb4SVivien Didelot 1921b1ac6fb4SVivien Didelot vlan.vid = vid - 1; 1922b1ac6fb4SVivien Didelot vlan.valid = false; 1923b1ac6fb4SVivien Didelot 1924b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 1925fad09c73SVivien Didelot if (err) 1926fad09c73SVivien Didelot return err; 1927fad09c73SVivien Didelot 1928b1ac6fb4SVivien Didelot if (vlan.vid != vid || !vlan.valid) { 1929b1ac6fb4SVivien Didelot memset(&vlan, 0, sizeof(vlan)); 1930b1ac6fb4SVivien Didelot 1931b1ac6fb4SVivien Didelot err = mv88e6xxx_atu_new(chip, &vlan.fid); 1932b1ac6fb4SVivien Didelot if (err) 1933b1ac6fb4SVivien Didelot return err; 1934b1ac6fb4SVivien Didelot 1935b1ac6fb4SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 1936b1ac6fb4SVivien Didelot if (i == port) 1937b1ac6fb4SVivien Didelot vlan.member[i] = member; 1938b1ac6fb4SVivien Didelot else 1939b1ac6fb4SVivien Didelot vlan.member[i] = non_member; 1940b1ac6fb4SVivien Didelot 1941b1ac6fb4SVivien Didelot vlan.vid = vid; 19421cb9dfcaSRasmus Villemoes vlan.valid = true; 1943fad09c73SVivien Didelot 194487fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 194587fa886eSAndrew Lunn if (err) 194687fa886eSAndrew Lunn return err; 194787fa886eSAndrew Lunn 1948b1ac6fb4SVivien Didelot err = mv88e6xxx_broadcast_setup(chip, vlan.vid); 1949b1ac6fb4SVivien Didelot if (err) 1950b1ac6fb4SVivien Didelot return err; 1951b1ac6fb4SVivien Didelot } else if (vlan.member[port] != member) { 1952b1ac6fb4SVivien Didelot vlan.member[port] = member; 1953b1ac6fb4SVivien Didelot 1954b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 1955b1ac6fb4SVivien Didelot if (err) 1956b1ac6fb4SVivien Didelot return err; 1957933b4425SRussell King } else if (warn) { 1958b1ac6fb4SVivien Didelot dev_info(chip->dev, "p%d: already a member of VLAN %d\n", 1959b1ac6fb4SVivien Didelot port, vid); 1960b1ac6fb4SVivien Didelot } 1961b1ac6fb4SVivien Didelot 1962b1ac6fb4SVivien Didelot return 0; 1963fad09c73SVivien Didelot } 1964fad09c73SVivien Didelot 1965fad09c73SVivien Didelot static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 196680e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1967fad09c73SVivien Didelot { 196804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1969fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 1970fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 1971933b4425SRussell King bool warn; 1972c91498e1SVivien Didelot u8 member; 1973fad09c73SVivien Didelot u16 vid; 1974fad09c73SVivien Didelot 19753cf3c846SVivien Didelot if (!chip->info->max_vid) 1976fad09c73SVivien Didelot return; 1977fad09c73SVivien Didelot 1978c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 19797ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 1980c91498e1SVivien Didelot else if (untagged) 19817ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 1982c91498e1SVivien Didelot else 19837ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 1984c91498e1SVivien Didelot 1985933b4425SRussell King /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port 1986933b4425SRussell King * and then the CPU port. Do not warn for duplicates for the CPU port. 1987933b4425SRussell King */ 1988933b4425SRussell King warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); 1989933b4425SRussell King 1990c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1991fad09c73SVivien Didelot 1992fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) 1993933b4425SRussell King if (mv88e6xxx_port_vlan_join(chip, port, vid, member, warn)) 1994774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 1995fad09c73SVivien Didelot vid, untagged ? 'u' : 't'); 1996fad09c73SVivien Didelot 199777064f37SVivien Didelot if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) 1998774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, 1999fad09c73SVivien Didelot vlan->vid_end); 2000fad09c73SVivien Didelot 2001c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2002fad09c73SVivien Didelot } 2003fad09c73SVivien Didelot 200452109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, 2005fad09c73SVivien Didelot int port, u16 vid) 2006fad09c73SVivien Didelot { 2007b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 2008fad09c73SVivien Didelot int i, err; 2009fad09c73SVivien Didelot 201052109892SVivien Didelot if (!vid) 201152109892SVivien Didelot return -EOPNOTSUPP; 201252109892SVivien Didelot 201352109892SVivien Didelot vlan.vid = vid - 1; 201452109892SVivien Didelot vlan.valid = false; 201552109892SVivien Didelot 201652109892SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 2017fad09c73SVivien Didelot if (err) 2018fad09c73SVivien Didelot return err; 2019fad09c73SVivien Didelot 202052109892SVivien Didelot /* If the VLAN doesn't exist in hardware or the port isn't a member, 202152109892SVivien Didelot * tell switchdev that this VLAN is likely handled in software. 202252109892SVivien Didelot */ 202352109892SVivien Didelot if (vlan.vid != vid || !vlan.valid || 202452109892SVivien Didelot vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 2025fad09c73SVivien Didelot return -EOPNOTSUPP; 2026fad09c73SVivien Didelot 20277ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 2028fad09c73SVivien Didelot 2029fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 2030fad09c73SVivien Didelot vlan.valid = false; 2031370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 20327ec60d6eSVivien Didelot if (vlan.member[i] != 20337ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 2034fad09c73SVivien Didelot vlan.valid = true; 2035fad09c73SVivien Didelot break; 2036fad09c73SVivien Didelot } 2037fad09c73SVivien Didelot } 2038fad09c73SVivien Didelot 20390ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2040fad09c73SVivien Didelot if (err) 2041fad09c73SVivien Didelot return err; 2042fad09c73SVivien Didelot 2043e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 2044fad09c73SVivien Didelot } 2045fad09c73SVivien Didelot 2046fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 2047fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 2048fad09c73SVivien Didelot { 204904bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2050fad09c73SVivien Didelot u16 pvid, vid; 2051fad09c73SVivien Didelot int err = 0; 2052fad09c73SVivien Didelot 20533cf3c846SVivien Didelot if (!chip->info->max_vid) 2054fad09c73SVivien Didelot return -EOPNOTSUPP; 2055fad09c73SVivien Didelot 2056c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2057fad09c73SVivien Didelot 205877064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 2059fad09c73SVivien Didelot if (err) 2060fad09c73SVivien Didelot goto unlock; 2061fad09c73SVivien Didelot 2062fad09c73SVivien Didelot for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { 206352109892SVivien Didelot err = mv88e6xxx_port_vlan_leave(chip, port, vid); 2064fad09c73SVivien Didelot if (err) 2065fad09c73SVivien Didelot goto unlock; 2066fad09c73SVivien Didelot 2067fad09c73SVivien Didelot if (vid == pvid) { 206877064f37SVivien Didelot err = mv88e6xxx_port_set_pvid(chip, port, 0); 2069fad09c73SVivien Didelot if (err) 2070fad09c73SVivien Didelot goto unlock; 2071fad09c73SVivien Didelot } 2072fad09c73SVivien Didelot } 2073fad09c73SVivien Didelot 2074fad09c73SVivien Didelot unlock: 2075c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2076fad09c73SVivien Didelot 2077fad09c73SVivien Didelot return err; 2078fad09c73SVivien Didelot } 2079fad09c73SVivien Didelot 20801b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 20816c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2082fad09c73SVivien Didelot { 208304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 20841b6dd556SArkadi Sharshevsky int err; 2085fad09c73SVivien Didelot 2086c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 20871b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 20881b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 2089c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 20901b6dd556SArkadi Sharshevsky 20911b6dd556SArkadi Sharshevsky return err; 2092fad09c73SVivien Didelot } 2093fad09c73SVivien Didelot 2094fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 20956c2c1dcbSArkadi Sharshevsky const unsigned char *addr, u16 vid) 2096fad09c73SVivien Didelot { 209704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 209883dabd1fSVivien Didelot int err; 2099fad09c73SVivien Didelot 2100c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2101d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); 2102c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2103fad09c73SVivien Didelot 210483dabd1fSVivien Didelot return err; 2105fad09c73SVivien Didelot } 2106fad09c73SVivien Didelot 210783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 2108fad09c73SVivien Didelot u16 fid, u16 vid, int port, 21092bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2110fad09c73SVivien Didelot { 2111dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 21122bedde1aSArkadi Sharshevsky bool is_static; 2113fad09c73SVivien Didelot int err; 2114fad09c73SVivien Didelot 2115d8291a95SVivien Didelot addr.state = 0; 2116dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 2117fad09c73SVivien Didelot 2118fad09c73SVivien Didelot do { 2119dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 2120fad09c73SVivien Didelot if (err) 212183dabd1fSVivien Didelot return err; 2122fad09c73SVivien Didelot 2123d8291a95SVivien Didelot if (!addr.state) 2124fad09c73SVivien Didelot break; 2125fad09c73SVivien Didelot 212601bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 212783dabd1fSVivien Didelot continue; 2128fad09c73SVivien Didelot 212983dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 213083dabd1fSVivien Didelot continue; 213183dabd1fSVivien Didelot 21322bedde1aSArkadi Sharshevsky is_static = (addr.state == 21332bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 21342bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 213583dabd1fSVivien Didelot if (err) 213683dabd1fSVivien Didelot return err; 2137fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 2138fad09c73SVivien Didelot 2139fad09c73SVivien Didelot return err; 2140fad09c73SVivien Didelot } 2141fad09c73SVivien Didelot 214283dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 21432bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 214483dabd1fSVivien Didelot { 2145425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 214683dabd1fSVivien Didelot u16 fid; 214783dabd1fSVivien Didelot int err; 214883dabd1fSVivien Didelot 214983dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 2150b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 215183dabd1fSVivien Didelot if (err) 215283dabd1fSVivien Didelot return err; 215383dabd1fSVivien Didelot 21542bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 215583dabd1fSVivien Didelot if (err) 215683dabd1fSVivien Didelot return err; 215783dabd1fSVivien Didelot 215883dabd1fSVivien Didelot /* Dump VLANs' Filtering Information Databases */ 2159425d2d37SVivien Didelot vlan.vid = chip->info->max_vid; 2160425d2d37SVivien Didelot vlan.valid = false; 2161425d2d37SVivien Didelot 216283dabd1fSVivien Didelot do { 2163f1394b78SVivien Didelot err = mv88e6xxx_vtu_getnext(chip, &vlan); 216483dabd1fSVivien Didelot if (err) 216583dabd1fSVivien Didelot return err; 216683dabd1fSVivien Didelot 216783dabd1fSVivien Didelot if (!vlan.valid) 216883dabd1fSVivien Didelot break; 216983dabd1fSVivien Didelot 217083dabd1fSVivien Didelot err = mv88e6xxx_port_db_dump_fid(chip, vlan.fid, vlan.vid, port, 21712bedde1aSArkadi Sharshevsky cb, data); 217283dabd1fSVivien Didelot if (err) 217383dabd1fSVivien Didelot return err; 21743cf3c846SVivien Didelot } while (vlan.vid < chip->info->max_vid); 217583dabd1fSVivien Didelot 217683dabd1fSVivien Didelot return err; 217783dabd1fSVivien Didelot } 217883dabd1fSVivien Didelot 2179fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 21802bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2181fad09c73SVivien Didelot { 218204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2183fcf15367SVivien Didelot int err; 2184fad09c73SVivien Didelot 2185c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2186fcf15367SVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, cb, data); 2187c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2188fcf15367SVivien Didelot 2189fcf15367SVivien Didelot return err; 2190fad09c73SVivien Didelot } 2191fad09c73SVivien Didelot 2192240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 2193240ea3efSVivien Didelot struct net_device *br) 2194240ea3efSVivien Didelot { 2195ef2025ecSVivien Didelot struct dsa_switch *ds = chip->ds; 2196ef2025ecSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 2197ef2025ecSVivien Didelot struct dsa_port *dp; 2198240ea3efSVivien Didelot int err; 2199240ea3efSVivien Didelot 2200ef2025ecSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 2201ef2025ecSVivien Didelot if (dp->bridge_dev == br) { 2202ef2025ecSVivien Didelot if (dp->ds == ds) { 2203ef2025ecSVivien Didelot /* This is a local bridge group member, 2204ef2025ecSVivien Didelot * remap its Port VLAN Map. 2205ef2025ecSVivien Didelot */ 2206ef2025ecSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, dp->index); 2207240ea3efSVivien Didelot if (err) 2208240ea3efSVivien Didelot return err; 2209ef2025ecSVivien Didelot } else { 2210ef2025ecSVivien Didelot /* This is an external bridge group member, 2211ef2025ecSVivien Didelot * remap its cross-chip Port VLAN Table entry. 2212ef2025ecSVivien Didelot */ 2213ef2025ecSVivien Didelot err = mv88e6xxx_pvt_map(chip, dp->ds->index, 2214ef2025ecSVivien Didelot dp->index); 2215e96a6e02SVivien Didelot if (err) 2216e96a6e02SVivien Didelot return err; 2217e96a6e02SVivien Didelot } 2218e96a6e02SVivien Didelot } 2219e96a6e02SVivien Didelot } 2220e96a6e02SVivien Didelot 2221240ea3efSVivien Didelot return 0; 2222240ea3efSVivien Didelot } 2223240ea3efSVivien Didelot 2224fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 2225fae8a25eSVivien Didelot struct net_device *br) 2226fad09c73SVivien Didelot { 222704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2228240ea3efSVivien Didelot int err; 2229fad09c73SVivien Didelot 2230c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2231240ea3efSVivien Didelot err = mv88e6xxx_bridge_map(chip, br); 2232c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2233fad09c73SVivien Didelot 2234fad09c73SVivien Didelot return err; 2235fad09c73SVivien Didelot } 2236fad09c73SVivien Didelot 2237f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 2238f123f2fbSVivien Didelot struct net_device *br) 2239fad09c73SVivien Didelot { 224004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2241fad09c73SVivien Didelot 2242c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2243240ea3efSVivien Didelot if (mv88e6xxx_bridge_map(chip, br) || 2244240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 2245240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 2246c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2247fad09c73SVivien Didelot } 2248fad09c73SVivien Didelot 2249f66a6a69SVladimir Oltean static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, 2250f66a6a69SVladimir Oltean int tree_index, int sw_index, 2251aec5ac88SVivien Didelot int port, struct net_device *br) 2252aec5ac88SVivien Didelot { 2253aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2254aec5ac88SVivien Didelot int err; 2255aec5ac88SVivien Didelot 2256f66a6a69SVladimir Oltean if (tree_index != ds->dst->index) 2257f66a6a69SVladimir Oltean return 0; 2258f66a6a69SVladimir Oltean 2259c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2260f66a6a69SVladimir Oltean err = mv88e6xxx_pvt_map(chip, sw_index, port); 2261c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2262aec5ac88SVivien Didelot 2263aec5ac88SVivien Didelot return err; 2264aec5ac88SVivien Didelot } 2265aec5ac88SVivien Didelot 2266f66a6a69SVladimir Oltean static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, 2267f66a6a69SVladimir Oltean int tree_index, int sw_index, 2268aec5ac88SVivien Didelot int port, struct net_device *br) 2269aec5ac88SVivien Didelot { 2270aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2271aec5ac88SVivien Didelot 2272f66a6a69SVladimir Oltean if (tree_index != ds->dst->index) 2273f66a6a69SVladimir Oltean return; 2274f66a6a69SVladimir Oltean 2275c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2276f66a6a69SVladimir Oltean if (mv88e6xxx_pvt_map(chip, sw_index, port)) 2277aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2278c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2279aec5ac88SVivien Didelot } 2280aec5ac88SVivien Didelot 228117e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 228217e708baSVivien Didelot { 228317e708baSVivien Didelot if (chip->info->ops->reset) 228417e708baSVivien Didelot return chip->info->ops->reset(chip); 228517e708baSVivien Didelot 228617e708baSVivien Didelot return 0; 228717e708baSVivien Didelot } 228817e708baSVivien Didelot 2289309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 2290309eca6dSVivien Didelot { 2291309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 2292309eca6dSVivien Didelot 2293309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 2294309eca6dSVivien Didelot if (gpiod) { 2295309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 2296309eca6dSVivien Didelot usleep_range(10000, 20000); 2297309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 2298309eca6dSVivien Didelot usleep_range(10000, 20000); 2299309eca6dSVivien Didelot } 2300309eca6dSVivien Didelot } 2301309eca6dSVivien Didelot 23024ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 23034ac4b5a6SVivien Didelot { 23044ac4b5a6SVivien Didelot int i, err; 23054ac4b5a6SVivien Didelot 23064ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 23074ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2308f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 23094ac4b5a6SVivien Didelot if (err) 23104ac4b5a6SVivien Didelot return err; 23114ac4b5a6SVivien Didelot } 23124ac4b5a6SVivien Didelot 23134ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 23144ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 23154ac4b5a6SVivien Didelot */ 23164ac4b5a6SVivien Didelot usleep_range(2000, 4000); 23174ac4b5a6SVivien Didelot 23184ac4b5a6SVivien Didelot return 0; 23194ac4b5a6SVivien Didelot } 23204ac4b5a6SVivien Didelot 2321fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 2322fad09c73SVivien Didelot { 2323a935c052SVivien Didelot int err; 2324fad09c73SVivien Didelot 23254ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 23260e7b9925SAndrew Lunn if (err) 23270e7b9925SAndrew Lunn return err; 2328fad09c73SVivien Didelot 2329309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 2330fad09c73SVivien Didelot 233117e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 2332fad09c73SVivien Didelot } 2333fad09c73SVivien Didelot 23344314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 233531bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 233631bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 233756995cbcSAndrew Lunn { 233856995cbcSAndrew Lunn int err; 233956995cbcSAndrew Lunn 23404314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 23414314557cSVivien Didelot return -EOPNOTSUPP; 23424314557cSVivien Didelot 23434314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 234456995cbcSAndrew Lunn if (err) 234556995cbcSAndrew Lunn return err; 234656995cbcSAndrew Lunn 23474314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 23484314557cSVivien Didelot if (err) 23494314557cSVivien Didelot return err; 23504314557cSVivien Didelot 23514314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 23524314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 23534314557cSVivien Didelot 23544314557cSVivien Didelot return 0; 23554314557cSVivien Didelot } 23564314557cSVivien Didelot 23574314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 23584314557cSVivien Didelot { 23594314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 236031bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2361b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 23624314557cSVivien Didelot } 23634314557cSVivien Didelot 23644314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 23654314557cSVivien Didelot { 23664314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 236731bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 2368b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 23694314557cSVivien Didelot } 23704314557cSVivien Didelot 23714314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 23724314557cSVivien Didelot { 23734314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 23744314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 237531bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 237631bef4e9SVivien Didelot ETH_P_EDSA); 23774314557cSVivien Didelot } 23784314557cSVivien Didelot 23794314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 23804314557cSVivien Didelot { 23814314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 23824314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 23834314557cSVivien Didelot 23842b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 23854314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 23864314557cSVivien Didelot 23874314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 23884314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_DSA) 23894314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 23904314557cSVivien Didelot 23914314557cSVivien Didelot if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) 23924314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 23934314557cSVivien Didelot 23944314557cSVivien Didelot return -EINVAL; 23954314557cSVivien Didelot } 23964314557cSVivien Didelot 2397ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 2398ea698f4fSVivien Didelot { 2399ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 2400ea698f4fSVivien Didelot 2401ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 2402ea698f4fSVivien Didelot } 2403ea698f4fSVivien Didelot 2404601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 2405601aeed3SVivien Didelot { 24063ee50cbfSVivien Didelot struct dsa_switch *ds = chip->ds; 2407407308f6SDavid S. Miller bool flood; 2408601aeed3SVivien Didelot 2409407308f6SDavid S. Miller /* Upstream ports flood frames with unknown unicast or multicast DA */ 2410407308f6SDavid S. Miller flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port); 2411407308f6SDavid S. Miller if (chip->info->ops->port_set_egress_floods) 2412407308f6SDavid S. Miller return chip->info->ops->port_set_egress_floods(chip, port, 2413407308f6SDavid S. Miller flood, flood); 2414407308f6SDavid S. Miller 2415601aeed3SVivien Didelot return 0; 2416601aeed3SVivien Didelot } 2417601aeed3SVivien Didelot 241845de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id) 241945de77ffSVivien Didelot { 242045de77ffSVivien Didelot struct mv88e6xxx_port *mvp = dev_id; 242145de77ffSVivien Didelot struct mv88e6xxx_chip *chip = mvp->chip; 242245de77ffSVivien Didelot irqreturn_t ret = IRQ_NONE; 242345de77ffSVivien Didelot int port = mvp->port; 242445de77ffSVivien Didelot u8 lane; 242545de77ffSVivien Didelot 242645de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 242745de77ffSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 242845de77ffSVivien Didelot if (lane) 242945de77ffSVivien Didelot ret = mv88e6xxx_serdes_irq_status(chip, port, lane); 243045de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 243145de77ffSVivien Didelot 243245de77ffSVivien Didelot return ret; 243345de77ffSVivien Didelot } 243445de77ffSVivien Didelot 243545de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port, 243645de77ffSVivien Didelot u8 lane) 243745de77ffSVivien Didelot { 243845de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 243945de77ffSVivien Didelot unsigned int irq; 244045de77ffSVivien Didelot int err; 244145de77ffSVivien Didelot 244245de77ffSVivien Didelot /* Nothing to request if this SERDES port has no IRQ */ 244345de77ffSVivien Didelot irq = mv88e6xxx_serdes_irq_mapping(chip, port); 244445de77ffSVivien Didelot if (!irq) 244545de77ffSVivien Didelot return 0; 244645de77ffSVivien Didelot 2447e6f2f6b8SAndrew Lunn snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name), 2448e6f2f6b8SAndrew Lunn "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port); 2449e6f2f6b8SAndrew Lunn 245045de77ffSVivien Didelot /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */ 245145de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 245245de77ffSVivien Didelot err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn, 2453e6f2f6b8SAndrew Lunn IRQF_ONESHOT, dev_id->serdes_irq_name, 2454e6f2f6b8SAndrew Lunn dev_id); 245545de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 245645de77ffSVivien Didelot if (err) 245745de77ffSVivien Didelot return err; 245845de77ffSVivien Didelot 245945de77ffSVivien Didelot dev_id->serdes_irq = irq; 246045de77ffSVivien Didelot 246145de77ffSVivien Didelot return mv88e6xxx_serdes_irq_enable(chip, port, lane); 246245de77ffSVivien Didelot } 246345de77ffSVivien Didelot 246445de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port, 246545de77ffSVivien Didelot u8 lane) 246645de77ffSVivien Didelot { 246745de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 246845de77ffSVivien Didelot unsigned int irq = dev_id->serdes_irq; 246945de77ffSVivien Didelot int err; 247045de77ffSVivien Didelot 247145de77ffSVivien Didelot /* Nothing to free if no IRQ has been requested */ 247245de77ffSVivien Didelot if (!irq) 247345de77ffSVivien Didelot return 0; 247445de77ffSVivien Didelot 247545de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 247645de77ffSVivien Didelot 247745de77ffSVivien Didelot /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */ 247845de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 247945de77ffSVivien Didelot free_irq(irq, dev_id); 248045de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 248145de77ffSVivien Didelot 248245de77ffSVivien Didelot dev_id->serdes_irq = 0; 248345de77ffSVivien Didelot 248445de77ffSVivien Didelot return err; 248545de77ffSVivien Didelot } 248645de77ffSVivien Didelot 24876d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 24886d91782fSAndrew Lunn bool on) 24896d91782fSAndrew Lunn { 2490dc272f60SVivien Didelot u8 lane; 2491fc0bc019SVivien Didelot int err; 24926d91782fSAndrew Lunn 2493dc272f60SVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 2494dc272f60SVivien Didelot if (!lane) 2495523a8904SVivien Didelot return 0; 2496fc0bc019SVivien Didelot 2497fc0bc019SVivien Didelot if (on) { 2498dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_up(chip, port, lane); 2499fc0bc019SVivien Didelot if (err) 2500fc0bc019SVivien Didelot return err; 2501fc0bc019SVivien Didelot 250245de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_request(chip, port, lane); 2503fc0bc019SVivien Didelot } else { 250445de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_free(chip, port, lane); 250545de77ffSVivien Didelot if (err) 250645de77ffSVivien Didelot return err; 2507fc0bc019SVivien Didelot 2508dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_down(chip, port, lane); 2509fc0bc019SVivien Didelot } 2510fc0bc019SVivien Didelot 2511fc0bc019SVivien Didelot return err; 25126d91782fSAndrew Lunn } 25136d91782fSAndrew Lunn 2514fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 2515fa371c80SVivien Didelot { 2516fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 2517fa371c80SVivien Didelot int upstream_port; 2518fa371c80SVivien Didelot int err; 2519fa371c80SVivien Didelot 252007073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 2521fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 2522fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 2523fa371c80SVivien Didelot upstream_port); 2524fa371c80SVivien Didelot if (err) 2525fa371c80SVivien Didelot return err; 2526fa371c80SVivien Didelot } 2527fa371c80SVivien Didelot 25280ea54ddaSVivien Didelot if (port == upstream_port) { 25290ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 25300ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 25310ea54ddaSVivien Didelot upstream_port); 25320ea54ddaSVivien Didelot if (err) 25330ea54ddaSVivien Didelot return err; 25340ea54ddaSVivien Didelot } 25350ea54ddaSVivien Didelot 25360ea54ddaSVivien Didelot if (chip->info->ops->set_egress_port) { 25370ea54ddaSVivien Didelot err = chip->info->ops->set_egress_port(chip, 25385c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS, 25395c74c54cSIwan R Timmer upstream_port); 25405c74c54cSIwan R Timmer if (err) 25415c74c54cSIwan R Timmer return err; 25425c74c54cSIwan R Timmer 25435c74c54cSIwan R Timmer err = chip->info->ops->set_egress_port(chip, 25445c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS, 25450ea54ddaSVivien Didelot upstream_port); 25460ea54ddaSVivien Didelot if (err) 25470ea54ddaSVivien Didelot return err; 25480ea54ddaSVivien Didelot } 25490ea54ddaSVivien Didelot } 25500ea54ddaSVivien Didelot 2551fa371c80SVivien Didelot return 0; 2552fa371c80SVivien Didelot } 2553fa371c80SVivien Didelot 2554fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 2555fad09c73SVivien Didelot { 2556fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 25570e7b9925SAndrew Lunn int err; 2558fad09c73SVivien Didelot u16 reg; 2559fad09c73SVivien Didelot 25607b898469SAndrew Lunn chip->ports[port].chip = chip; 25617b898469SAndrew Lunn chip->ports[port].port = port; 25627b898469SAndrew Lunn 2563d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 2564d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 2565d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 2566fad09c73SVivien Didelot */ 2567d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 2568d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 2569d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 257054186b91SAndrew Lunn PAUSE_OFF, 2571d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 2572fad09c73SVivien Didelot else 2573d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 2574d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 257554186b91SAndrew Lunn PAUSE_ON, 2576d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 25770e7b9925SAndrew Lunn if (err) 25780e7b9925SAndrew Lunn return err; 2579fad09c73SVivien Didelot 2580fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 2581fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 2582fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 2583fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 2584fad09c73SVivien Didelot * to Forwarding. 2585fad09c73SVivien Didelot * 2586fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 2587fad09c73SVivien Didelot * on which tagging mode was configured. 2588fad09c73SVivien Didelot * 2589fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 2590fad09c73SVivien Didelot * 2591fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 2592fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 2593fad09c73SVivien Didelot */ 2594a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 2595a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 2596a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 2597a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 25980e7b9925SAndrew Lunn if (err) 25990e7b9925SAndrew Lunn return err; 260056995cbcSAndrew Lunn 2601601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 260256995cbcSAndrew Lunn if (err) 260356995cbcSAndrew Lunn return err; 2604fad09c73SVivien Didelot 2605601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 26064314557cSVivien Didelot if (err) 26074314557cSVivien Didelot return err; 26084314557cSVivien Didelot 2609fad09c73SVivien Didelot /* Port Control 2: don't force a good FCS, set the maximum frame size to 2610fad09c73SVivien Didelot * 10240 bytes, disable 802.1q tags checking, don't discard tagged or 2611fad09c73SVivien Didelot * untagged frames on this port, do a destination address lookup on all 2612fad09c73SVivien Didelot * received packets as usual, disable ARP mirroring and don't send a 2613fad09c73SVivien Didelot * copy of all transmitted/received frames on this port to the CPU. 2614fad09c73SVivien Didelot */ 2615a23b2961SAndrew Lunn err = mv88e6xxx_port_set_map_da(chip, port); 2616a23b2961SAndrew Lunn if (err) 2617a23b2961SAndrew Lunn return err; 2618a23b2961SAndrew Lunn 2619fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 26200e7b9925SAndrew Lunn if (err) 26210e7b9925SAndrew Lunn return err; 2622fad09c73SVivien Didelot 2623a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 262481c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); 2625a23b2961SAndrew Lunn if (err) 2626a23b2961SAndrew Lunn return err; 2627a23b2961SAndrew Lunn 2628cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 2629cd782656SVivien Didelot err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); 26305f436666SAndrew Lunn if (err) 26315f436666SAndrew Lunn return err; 26325f436666SAndrew Lunn } 26335f436666SAndrew Lunn 2634fad09c73SVivien Didelot /* Port Association Vector: when learning source addresses 2635fad09c73SVivien Didelot * of packets, add the address to the address database using 2636fad09c73SVivien Didelot * a port bitmap that has only the bit for this port set and 2637fad09c73SVivien Didelot * the other bits clear. 2638fad09c73SVivien Didelot */ 2639fad09c73SVivien Didelot reg = 1 << port; 2640fad09c73SVivien Didelot /* Disable learning for CPU port */ 2641fad09c73SVivien Didelot if (dsa_is_cpu_port(ds, port)) 2642fad09c73SVivien Didelot reg = 0; 2643fad09c73SVivien Didelot 26442a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 26452a4614e4SVivien Didelot reg); 26460e7b9925SAndrew Lunn if (err) 26470e7b9925SAndrew Lunn return err; 2648fad09c73SVivien Didelot 2649fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 26502cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 26512cb8cb14SVivien Didelot 0x0000); 26520e7b9925SAndrew Lunn if (err) 26530e7b9925SAndrew Lunn return err; 2654fad09c73SVivien Didelot 26550898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 26560898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 2657b35d322aSAndrew Lunn if (err) 2658b35d322aSAndrew Lunn return err; 2659b35d322aSAndrew Lunn } 2660b35d322aSAndrew Lunn 2661c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 2662c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 2663c8c94891SVivien Didelot if (err) 2664c8c94891SVivien Didelot return err; 2665c8c94891SVivien Didelot } 2666c8c94891SVivien Didelot 26679dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 26689dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 26690e7b9925SAndrew Lunn if (err) 26700e7b9925SAndrew Lunn return err; 2671ef0a7318SAndrew Lunn } 26722bbb33beSAndrew Lunn 2673ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 2674ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 26750e7b9925SAndrew Lunn if (err) 26760e7b9925SAndrew Lunn return err; 2677fad09c73SVivien Didelot } 2678fad09c73SVivien Didelot 2679ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 2680ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 26810e7b9925SAndrew Lunn if (err) 26820e7b9925SAndrew Lunn return err; 2683fad09c73SVivien Didelot } 2684fad09c73SVivien Didelot 2685121b8fe2SHubert Feurstein if (chip->info->ops->port_setup_message_port) { 2686121b8fe2SHubert Feurstein err = chip->info->ops->port_setup_message_port(chip, port); 26870e7b9925SAndrew Lunn if (err) 26880e7b9925SAndrew Lunn return err; 2689121b8fe2SHubert Feurstein } 2690fad09c73SVivien Didelot 2691fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 2692fad09c73SVivien Didelot * database, and allow bidirectional communication between the 2693fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 2694fad09c73SVivien Didelot */ 2695b4e48c50SVivien Didelot err = mv88e6xxx_port_set_fid(chip, port, 0); 26960e7b9925SAndrew Lunn if (err) 26970e7b9925SAndrew Lunn return err; 2698fad09c73SVivien Didelot 2699240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 27000e7b9925SAndrew Lunn if (err) 27010e7b9925SAndrew Lunn return err; 2702fad09c73SVivien Didelot 2703fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 2704fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 2705fad09c73SVivien Didelot */ 2706b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 2707fad09c73SVivien Didelot } 2708fad09c73SVivien Didelot 27092a550aecSAndrew Lunn static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port) 27102a550aecSAndrew Lunn { 27112a550aecSAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 27122a550aecSAndrew Lunn 27132a550aecSAndrew Lunn if (chip->info->ops->port_set_jumbo_size) 27142a550aecSAndrew Lunn return 10240; 27151baf0facSChris Packham else if (chip->info->ops->set_max_frame_size) 27161baf0facSChris Packham return 1632; 27172a550aecSAndrew Lunn return 1522; 27182a550aecSAndrew Lunn } 27192a550aecSAndrew Lunn 27202a550aecSAndrew Lunn static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 27212a550aecSAndrew Lunn { 27222a550aecSAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 27232a550aecSAndrew Lunn int ret = 0; 27242a550aecSAndrew Lunn 27252a550aecSAndrew Lunn mv88e6xxx_reg_lock(chip); 27262a550aecSAndrew Lunn if (chip->info->ops->port_set_jumbo_size) 27272a550aecSAndrew Lunn ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu); 27281baf0facSChris Packham else if (chip->info->ops->set_max_frame_size) 27291baf0facSChris Packham ret = chip->info->ops->set_max_frame_size(chip, new_mtu); 27302a550aecSAndrew Lunn else 27312a550aecSAndrew Lunn if (new_mtu > 1522) 27322a550aecSAndrew Lunn ret = -EINVAL; 27332a550aecSAndrew Lunn mv88e6xxx_reg_unlock(chip); 27342a550aecSAndrew Lunn 27352a550aecSAndrew Lunn return ret; 27362a550aecSAndrew Lunn } 27372a550aecSAndrew Lunn 273804aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 273904aca993SAndrew Lunn struct phy_device *phydev) 274004aca993SAndrew Lunn { 274104aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 2742523a8904SVivien Didelot int err; 274304aca993SAndrew Lunn 2744c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2745523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 2746c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 274704aca993SAndrew Lunn 274804aca993SAndrew Lunn return err; 274904aca993SAndrew Lunn } 275004aca993SAndrew Lunn 275175104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 275204aca993SAndrew Lunn { 275304aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 275404aca993SAndrew Lunn 2755c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2756523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 2757523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 2758c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 275904aca993SAndrew Lunn } 276004aca993SAndrew Lunn 27612cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 27622cfcd964SVivien Didelot unsigned int ageing_time) 27632cfcd964SVivien Didelot { 276404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 27652cfcd964SVivien Didelot int err; 27662cfcd964SVivien Didelot 2767c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2768720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 2769c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 27702cfcd964SVivien Didelot 27712cfcd964SVivien Didelot return err; 27722cfcd964SVivien Didelot } 27732cfcd964SVivien Didelot 2774447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 2775fad09c73SVivien Didelot { 2776fad09c73SVivien Didelot int err; 2777fad09c73SVivien Didelot 2778de227387SAndrew Lunn /* Initialize the statistics unit */ 2779447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 2780447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 2781de227387SAndrew Lunn if (err) 2782de227387SAndrew Lunn return err; 2783447b1bb8SVivien Didelot } 2784de227387SAndrew Lunn 278540cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 27869729934cSVivien Didelot } 27879729934cSVivien Didelot 2788ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 2789ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 2790ea89098eSAndrew Lunn { 2791ea89098eSAndrew Lunn int port; 2792ea89098eSAndrew Lunn int err; 2793ea89098eSAndrew Lunn u16 val; 2794ea89098eSAndrew Lunn 2795ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 279660907013SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val); 2797ea89098eSAndrew Lunn if (err) { 2798ea89098eSAndrew Lunn dev_err(chip->dev, 2799ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 2800ea89098eSAndrew Lunn return false; 2801ea89098eSAndrew Lunn } 2802ea89098eSAndrew Lunn if (val != 0x01c0) 2803ea89098eSAndrew Lunn return false; 2804ea89098eSAndrew Lunn } 2805ea89098eSAndrew Lunn 2806ea89098eSAndrew Lunn return true; 2807ea89098eSAndrew Lunn } 2808ea89098eSAndrew Lunn 2809ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 2810ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 2811ea89098eSAndrew Lunn * software reset. 2812ea89098eSAndrew Lunn */ 2813ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 2814ea89098eSAndrew Lunn { 2815ea89098eSAndrew Lunn int port; 2816ea89098eSAndrew Lunn int err; 2817ea89098eSAndrew Lunn 2818ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 2819ea89098eSAndrew Lunn return 0; 2820ea89098eSAndrew Lunn 2821ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 2822ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 2823ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 2824ea89098eSAndrew Lunn if (err) 2825ea89098eSAndrew Lunn return err; 2826ea89098eSAndrew Lunn } 2827ea89098eSAndrew Lunn 2828ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 282960907013SMarek Behún err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0); 2830ea89098eSAndrew Lunn if (err) 2831ea89098eSAndrew Lunn return err; 2832ea89098eSAndrew Lunn } 2833ea89098eSAndrew Lunn 2834ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 2835ea89098eSAndrew Lunn } 2836ea89098eSAndrew Lunn 283723e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds) 283823e8b470SAndrew Lunn { 283923e8b470SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 2840e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 2841bfb25542SAndrew Lunn mv88e6xxx_teardown_devlink_regions(ds); 284223e8b470SAndrew Lunn } 284323e8b470SAndrew Lunn 2844fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 2845fad09c73SVivien Didelot { 284604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 28472d2e1dd2SAndrew Lunn u8 cmode; 2848fad09c73SVivien Didelot int err; 2849fad09c73SVivien Didelot int i; 2850fad09c73SVivien Didelot 2851fad09c73SVivien Didelot chip->ds = ds; 2852a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 2853fad09c73SVivien Didelot 2854c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2855fad09c73SVivien Didelot 2856ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 2857ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 2858ea89098eSAndrew Lunn if (err) 2859ea89098eSAndrew Lunn goto unlock; 2860ea89098eSAndrew Lunn } 2861ea89098eSAndrew Lunn 28622d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 28632d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 28642d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 28652d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 28662d2e1dd2SAndrew Lunn if (err) 2867e29129fcSDan Carpenter goto unlock; 28682d2e1dd2SAndrew Lunn 28692d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 28702d2e1dd2SAndrew Lunn } 28712d2e1dd2SAndrew Lunn } 28722d2e1dd2SAndrew Lunn 28739729934cSVivien Didelot /* Setup Switch Port Registers */ 2874370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 2875b759f528SVivien Didelot if (dsa_is_unused_port(ds, i)) 2876b759f528SVivien Didelot continue; 2877b759f528SVivien Didelot 2878c857486aSHubert Feurstein /* Prevent the use of an invalid port. */ 2879b759f528SVivien Didelot if (mv88e6xxx_is_invalid_port(chip, i)) { 2880c857486aSHubert Feurstein dev_err(chip->dev, "port %d is invalid\n", i); 2881c857486aSHubert Feurstein err = -EINVAL; 2882c857486aSHubert Feurstein goto unlock; 2883c857486aSHubert Feurstein } 2884c857486aSHubert Feurstein 28859729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 28869729934cSVivien Didelot if (err) 28879729934cSVivien Didelot goto unlock; 28889729934cSVivien Didelot } 28899729934cSVivien Didelot 2890cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 2891cd8da8bbSVivien Didelot if (err) 2892cd8da8bbSVivien Didelot goto unlock; 2893cd8da8bbSVivien Didelot 289404a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 289504a69a17SVivien Didelot if (err) 289604a69a17SVivien Didelot goto unlock; 289704a69a17SVivien Didelot 28981b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 28991b17aedfSVivien Didelot if (err) 29001b17aedfSVivien Didelot goto unlock; 29011b17aedfSVivien Didelot 2902b486d7c9SVivien Didelot err = mv88e6xxx_vtu_setup(chip); 2903b486d7c9SVivien Didelot if (err) 2904b486d7c9SVivien Didelot goto unlock; 2905b486d7c9SVivien Didelot 290681228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 290781228996SVivien Didelot if (err) 290881228996SVivien Didelot goto unlock; 290981228996SVivien Didelot 2910a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 2911a2ac29d2SVivien Didelot if (err) 2912a2ac29d2SVivien Didelot goto unlock; 2913a2ac29d2SVivien Didelot 291487fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 291587fa886eSAndrew Lunn if (err) 291687fa886eSAndrew Lunn goto unlock; 291787fa886eSAndrew Lunn 29189e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 29199e907d73SVivien Didelot if (err) 29209e907d73SVivien Didelot goto unlock; 29219e907d73SVivien Didelot 29229e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 29239e5baf9bSVivien Didelot if (err) 29249e5baf9bSVivien Didelot goto unlock; 29259e5baf9bSVivien Didelot 292651c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 29276e55f698SAndrew Lunn if (err) 29286e55f698SAndrew Lunn goto unlock; 29296e55f698SAndrew Lunn 2930b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 2931b28f872dSVivien Didelot if (err) 2932b28f872dSVivien Didelot goto unlock; 2933b28f872dSVivien Didelot 2934c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 2935c7f047b6SVivien Didelot if (err) 2936c7f047b6SVivien Didelot goto unlock; 2937c7f047b6SVivien Didelot 293893e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 293993e18d61SVivien Didelot if (err) 294093e18d61SVivien Didelot goto unlock; 294193e18d61SVivien Didelot 2942c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 29432fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 29442fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 29452fa8d3afSBrandon Streiff if (err) 29462fa8d3afSBrandon Streiff goto unlock; 2947c6fe0ad2SBrandon Streiff 2948c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 2949c6fe0ad2SBrandon Streiff if (err) 2950c6fe0ad2SBrandon Streiff goto unlock; 29512fa8d3afSBrandon Streiff } 29522fa8d3afSBrandon Streiff 2953447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 2954447b1bb8SVivien Didelot if (err) 2955447b1bb8SVivien Didelot goto unlock; 2956447b1bb8SVivien Didelot 2957fad09c73SVivien Didelot unlock: 2958c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2959fad09c73SVivien Didelot 2960e0c69ca7SAndrew Lunn if (err) 2961e0c69ca7SAndrew Lunn return err; 2962e0c69ca7SAndrew Lunn 2963e0c69ca7SAndrew Lunn /* Have to be called without holding the register lock, since 2964e0c69ca7SAndrew Lunn * they take the devlink lock, and we later take the locks in 2965e0c69ca7SAndrew Lunn * the reverse order when getting/setting parameters or 2966e0c69ca7SAndrew Lunn * resource occupancy. 296723e8b470SAndrew Lunn */ 2968e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_resources(ds); 2969e0c69ca7SAndrew Lunn if (err) 2970e0c69ca7SAndrew Lunn return err; 2971e0c69ca7SAndrew Lunn 2972e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_params(ds); 2973e0c69ca7SAndrew Lunn if (err) 2974bfb25542SAndrew Lunn goto out_resources; 2975bfb25542SAndrew Lunn 2976bfb25542SAndrew Lunn err = mv88e6xxx_setup_devlink_regions(ds); 2977bfb25542SAndrew Lunn if (err) 2978bfb25542SAndrew Lunn goto out_params; 2979bfb25542SAndrew Lunn 2980bfb25542SAndrew Lunn return 0; 2981bfb25542SAndrew Lunn 2982bfb25542SAndrew Lunn out_params: 2983bfb25542SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 2984bfb25542SAndrew Lunn out_resources: 2985e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 2986e0c69ca7SAndrew Lunn 2987e0c69ca7SAndrew Lunn return err; 2988fad09c73SVivien Didelot } 2989fad09c73SVivien Didelot 2990e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 2991fad09c73SVivien Didelot { 29920dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 29930dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 2994e57e5e77SVivien Didelot u16 val; 2995e57e5e77SVivien Didelot int err; 2996fad09c73SVivien Didelot 2997ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 2998ee26a228SAndrew Lunn return -EOPNOTSUPP; 2999ee26a228SAndrew Lunn 3000c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3001ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 3002c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3003e57e5e77SVivien Didelot 3004da9f3301SAndrew Lunn if (reg == MII_PHYSID2) { 3005ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 3006ddc49acbSAndrew Lunn if (chip->info->family != MV88E6XXX_FAMILY_6165) 3007ddc49acbSAndrew Lunn /* Then there is the 6165 family. It gets is 3008ddc49acbSAndrew Lunn * PHYs correct. But it can also have two 3009ddc49acbSAndrew Lunn * SERDES interfaces in the PHY address 3010ddc49acbSAndrew Lunn * space. And these don't have a model 3011ddc49acbSAndrew Lunn * number. But they are not PHYs, so we don't 3012ddc49acbSAndrew Lunn * want to give them something a PHY driver 3013ddc49acbSAndrew Lunn * will recognise. 3014ddc49acbSAndrew Lunn * 3015ddc49acbSAndrew Lunn * Use the mv88e6390 family model number 3016ddc49acbSAndrew Lunn * instead, for anything which really could be 3017ddc49acbSAndrew Lunn * a PHY, 3018da9f3301SAndrew Lunn */ 3019da9f3301SAndrew Lunn if (!(val & 0x3f0)) 3020107fcc10SVivien Didelot val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 3021da9f3301SAndrew Lunn } 3022da9f3301SAndrew Lunn 3023e57e5e77SVivien Didelot return err ? err : val; 3024fad09c73SVivien Didelot } 3025fad09c73SVivien Didelot 3026e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 3027fad09c73SVivien Didelot { 30280dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 30290dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3030e57e5e77SVivien Didelot int err; 3031fad09c73SVivien Didelot 3032ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 3033ee26a228SAndrew Lunn return -EOPNOTSUPP; 3034ee26a228SAndrew Lunn 3035c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3036ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 3037c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3038e57e5e77SVivien Didelot 3039e57e5e77SVivien Didelot return err; 3040fad09c73SVivien Didelot } 3041fad09c73SVivien Didelot 3042fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 3043a3c53be5SAndrew Lunn struct device_node *np, 3044a3c53be5SAndrew Lunn bool external) 3045fad09c73SVivien Didelot { 3046fad09c73SVivien Didelot static int index; 30470dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 3048fad09c73SVivien Didelot struct mii_bus *bus; 3049fad09c73SVivien Didelot int err; 3050fad09c73SVivien Didelot 30512510babcSAndrew Lunn if (external) { 3052c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 30532510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 3054c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 30552510babcSAndrew Lunn 30562510babcSAndrew Lunn if (err) 30572510babcSAndrew Lunn return err; 30582510babcSAndrew Lunn } 30592510babcSAndrew Lunn 30600dd12d54SAndrew Lunn bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); 3061fad09c73SVivien Didelot if (!bus) 3062fad09c73SVivien Didelot return -ENOMEM; 3063fad09c73SVivien Didelot 30640dd12d54SAndrew Lunn mdio_bus = bus->priv; 3065a3c53be5SAndrew Lunn mdio_bus->bus = bus; 30660dd12d54SAndrew Lunn mdio_bus->chip = chip; 3067a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 3068a3c53be5SAndrew Lunn mdio_bus->external = external; 30690dd12d54SAndrew Lunn 3070fad09c73SVivien Didelot if (np) { 3071fad09c73SVivien Didelot bus->name = np->full_name; 3072f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 3073fad09c73SVivien Didelot } else { 3074fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 3075fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 3076fad09c73SVivien Didelot } 3077fad09c73SVivien Didelot 3078fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 3079fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 3080fad09c73SVivien Didelot bus->parent = chip->dev; 3081fad09c73SVivien Didelot 30826f88284fSAndrew Lunn if (!external) { 30836f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 30846f88284fSAndrew Lunn if (err) 30856f88284fSAndrew Lunn return err; 30866f88284fSAndrew Lunn } 30876f88284fSAndrew Lunn 3088a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 3089fad09c73SVivien Didelot if (err) { 3090fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 30916f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 3092fad09c73SVivien Didelot return err; 3093fad09c73SVivien Didelot } 3094fad09c73SVivien Didelot 3095a3c53be5SAndrew Lunn if (external) 3096a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 3097a3c53be5SAndrew Lunn else 3098a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 3099a3c53be5SAndrew Lunn 3100a3c53be5SAndrew Lunn return 0; 3101a3c53be5SAndrew Lunn } 3102a3c53be5SAndrew Lunn 31033126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 31043126aeecSAndrew Lunn 31053126aeecSAndrew Lunn { 31063126aeecSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 31073126aeecSAndrew Lunn struct mii_bus *bus; 31083126aeecSAndrew Lunn 31093126aeecSAndrew Lunn list_for_each_entry(mdio_bus, &chip->mdios, list) { 31103126aeecSAndrew Lunn bus = mdio_bus->bus; 31113126aeecSAndrew Lunn 31126f88284fSAndrew Lunn if (!mdio_bus->external) 31136f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 31146f88284fSAndrew Lunn 31153126aeecSAndrew Lunn mdiobus_unregister(bus); 31163126aeecSAndrew Lunn } 31173126aeecSAndrew Lunn } 31183126aeecSAndrew Lunn 3119a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 3120a3c53be5SAndrew Lunn struct device_node *np) 3121a3c53be5SAndrew Lunn { 3122a3c53be5SAndrew Lunn struct device_node *child; 3123a3c53be5SAndrew Lunn int err; 3124a3c53be5SAndrew Lunn 3125a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 3126a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 3127a3c53be5SAndrew Lunn * optional. 3128a3c53be5SAndrew Lunn */ 3129a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 3130a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 3131a3c53be5SAndrew Lunn if (err) 3132a3c53be5SAndrew Lunn return err; 3133a3c53be5SAndrew Lunn 3134a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 3135a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 3136a3c53be5SAndrew Lunn * bus. 3137a3c53be5SAndrew Lunn */ 3138a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 3139ceb96faeSAndrew Lunn if (of_device_is_compatible( 3140ceb96faeSAndrew Lunn child, "marvell,mv88e6xxx-mdio-external")) { 3141a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 31423126aeecSAndrew Lunn if (err) { 31433126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 314478e42040SNishka Dasgupta of_node_put(child); 3145a3c53be5SAndrew Lunn return err; 3146a3c53be5SAndrew Lunn } 3147a3c53be5SAndrew Lunn } 31483126aeecSAndrew Lunn } 3149a3c53be5SAndrew Lunn 3150a3c53be5SAndrew Lunn return 0; 3151a3c53be5SAndrew Lunn } 3152a3c53be5SAndrew Lunn 3153855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 3154855b1932SVivien Didelot { 315504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3156855b1932SVivien Didelot 3157855b1932SVivien Didelot return chip->eeprom_len; 3158855b1932SVivien Didelot } 3159855b1932SVivien Didelot 3160855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 3161855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3162855b1932SVivien Didelot { 316304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3164855b1932SVivien Didelot int err; 3165855b1932SVivien Didelot 3166ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 3167ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3168ee4dc2e7SVivien Didelot 3169c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3170ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 3171c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3172855b1932SVivien Didelot 3173855b1932SVivien Didelot if (err) 3174855b1932SVivien Didelot return err; 3175855b1932SVivien Didelot 3176855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 3177855b1932SVivien Didelot 3178855b1932SVivien Didelot return 0; 3179855b1932SVivien Didelot } 3180855b1932SVivien Didelot 3181855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 3182855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3183855b1932SVivien Didelot { 318404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3185855b1932SVivien Didelot int err; 3186855b1932SVivien Didelot 3187ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 3188ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 3189ee4dc2e7SVivien Didelot 3190855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 3191855b1932SVivien Didelot return -EINVAL; 3192855b1932SVivien Didelot 3193c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3194ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 3195c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3196855b1932SVivien Didelot 3197855b1932SVivien Didelot return err; 3198855b1932SVivien Didelot } 3199855b1932SVivien Didelot 3200b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 32014b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 320293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 320393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3204cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3205b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 32067e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 32077e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 320808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3209f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3210ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 321156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3212601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 321356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3214ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 32150898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3216c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 32179dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 32182d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3219121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3220a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 322140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3222dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3223dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3224052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3225fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3226fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3227fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 322851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 32299e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3230a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3231a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 323217e708baSVivien Didelot .reset = mv88e6185_g1_reset, 32339e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3234f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 32350ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 32366c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 32371baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3238b3469dd8SVivien Didelot }; 3239b3469dd8SVivien Didelot 3240b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 32414b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 324293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 324393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3244b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 32457e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 32467e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 324708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3248f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 324956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3250601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3251a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 32522d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3253121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3254a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 325540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3256dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3257dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3258052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 325951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3260a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3261a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 326217e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3263f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 32640ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 32656c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 32661baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3267b3469dd8SVivien Didelot }; 3268b3469dd8SVivien Didelot 32697d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 327015da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 327193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 327293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3273cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 32747d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 32757d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 32767d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 32777d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 3278f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3279ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 328056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3281601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 328256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3283ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 32840898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3285c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 32869dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 32872d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3288121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 32897d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 329040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 32917d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 32927d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 32937d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 3294fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3295fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 329691eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 329751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 32989e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 329917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 33009e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 3301f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 33020ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 33036c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 33041baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 33057d381a02SStefan Eichenberger }; 33067d381a02SStefan Eichenberger 3307b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 33084b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 330993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 331093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3311cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3312b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3313ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3314ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 331508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3316f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 331756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3318601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3319c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 33209dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 33212d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3322121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 33230ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 332440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3325dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3326dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3327052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3328fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3329fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3330fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 333151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 33329e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 333317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 333423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 333523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3336f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 33370ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 33386c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 33391baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3340b3469dd8SVivien Didelot }; 3341b3469dd8SVivien Didelot 3342b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 33434b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 334493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 334593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3346b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 33477e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 33487e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 334908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3350f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3351ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 335256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3353601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 335456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3355a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 3356cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3357ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 33580898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 335954186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 33602d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3361121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3362a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 336340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3364dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3365dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3366052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3367fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3368fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3369fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 337051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 3371a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 337202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3373a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 337417e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3375f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 33760ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 33776c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3378b3469dd8SVivien Didelot }; 3379b3469dd8SVivien Didelot 3380990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 3381990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 338293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 338393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3384cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3385990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 3386990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 3387990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3388990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3389990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 3390990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3391990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3392f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 33937cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 3394990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 3395990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3396990e27b0SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 3397990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 3398cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3399990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 34000898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3401990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 3402990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34032d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 34047a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 3405121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3406990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 340740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3408990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3409990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 3410990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 3411fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3412fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 3413990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 3414990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 34159e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 3416990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 3417f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34180ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3419d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 3420d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 3421a5a6858bSRussell King /* Check status register pause & lpa register */ 3422a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3423a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3424a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3425a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 34264241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 342761a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3428907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 3429a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 3430e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 3431990e27b0SVivien Didelot }; 3432990e27b0SVivien Didelot 3433b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 34344b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 343593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 343693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3437cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3438b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3439ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 3440ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 344108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3442f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3443ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 344456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3445601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 344656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3447cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3448ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 34490898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3450c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34519dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34522d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3453121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3454a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 345540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3456dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3457dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3458052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3459fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3460fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3461fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 346251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34639e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 346417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 346523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 346623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3467f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 34680ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3469a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3470dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 34716c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3472b3469dd8SVivien Didelot }; 3473b3469dd8SVivien Didelot 3474b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 34754b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 347693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 347793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3478cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3479b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3480efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 3481efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 348208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3483f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3484c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 34859dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 34862d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3487121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3488a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 348940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3490dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3491dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3492052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3493fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3494fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3495fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 349651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 34979e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 349817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 349923e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 350023e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3501f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35020ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3503a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 3504dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 35056c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3506b3469dd8SVivien Didelot }; 3507b3469dd8SVivien Didelot 3508b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 35094b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 351093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 351193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3512cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3513b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3514b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3515b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 351608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 351794d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3518f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3519ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 352056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3521601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 352256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3523cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3524ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35250898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3526c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35279dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35282d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3529121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3530a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 353140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3532dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3533dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3534052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3535fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3536fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3537fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 353851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35399e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 354017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 354123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 354223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3543f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35440ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 35456c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3546b3469dd8SVivien Didelot }; 3547b3469dd8SVivien Didelot 3548b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 35494b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 355093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 355193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3552cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3553ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3554ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3555b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3556b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3557b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 355808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3559a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3560f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 3561ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3562f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 356356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3564601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 356556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3566cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3567ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 35680898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3569c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 35709dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 35712d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3572121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3573a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 357440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3575dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3576dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3577052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3578fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3579fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3580fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 358151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 35829e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 358317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 35849e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 358523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 358623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3587f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 35880ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 35899db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 3590a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 3591a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 3592a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 3593a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 35946d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 3595d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3596d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3597a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 35986c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3599b3469dd8SVivien Didelot }; 3600b3469dd8SVivien Didelot 3601b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 36024b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 360393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 360493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3605cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3606b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3607b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3608b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 360908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 361094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3611f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 3612ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 361356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3614601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 361556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3616cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3617ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36180898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3619c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36209dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36212d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3622121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3623a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 362440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3625dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3626dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3627052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3628fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3629fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3630fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 363151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36329e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 363317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 363423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 363523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3636f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36370ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 36386c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 3639b3469dd8SVivien Didelot }; 3640b3469dd8SVivien Didelot 3641b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 36424b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 364393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 364493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3645cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3646ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3647ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3648b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3649b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3650b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 365108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3652a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3653f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 3654ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3655f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 365656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3657601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 365856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3659cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3660ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 36610898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3662c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 36639dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 36642d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3665121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3666a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 366740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3668dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3669dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3670052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3671fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3672fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3673fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 367451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 36759e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 367617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 36779e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 367823e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 367923e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3680f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 36810ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 36829db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 3683a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 3684a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 3685a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 3686a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 36876d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 36884241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 368961a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 3690907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 3691d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3692d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3693a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 36946c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3695b3469dd8SVivien Didelot }; 3696b3469dd8SVivien Didelot 3697b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 36984b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 369993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 370093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3701b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 37027e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 37037e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 370408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3705f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 370656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 3707601aeed3SVivien Didelot .port_set_egress_floods = mv88e6185_port_set_egress_floods, 3708ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 3709a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 371054186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 37112d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 3712121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3713a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 371440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3715dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3716dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3717052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3718fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3719fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3720fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 372151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 372202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 3723a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 3724a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 372517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 3726f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 37270ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 37286c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 37291baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 3730b3469dd8SVivien Didelot }; 3731b3469dd8SVivien Didelot 37321a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 37334b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3734ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3735cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 373698fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 373798fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 37381a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 37391a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 37401a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 37411a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 37421a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3743f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 37447cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3745ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 3746f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 374756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3748601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 374956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3750e8b34c67SChris Packham .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 37510898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3752c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 37539dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 37542d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3755fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 3756121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 375779523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3758de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3759dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3760dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3761e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3762fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3763fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 376461303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 37656e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 37669e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 376717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 37689e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 376923e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 377023e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3771931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3772931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 37736335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 377417deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 3775a5a6858bSRussell King /* Check status register pause & lpa register */ 3776a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3777a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3778a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3779a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 37804241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 378161a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3782907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 37834262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 37844262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 3785bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3786bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 3787a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 37886c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 37891a3b39ecSAndrew Lunn }; 37901a3b39ecSAndrew Lunn 37911a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 37924b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3793ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3794cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 379598fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 379698fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 37971a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 37981a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 37991a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 38001a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 38011a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3802f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 38037cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 3804ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 3805f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 380656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3807601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 380856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3809e8b34c67SChris Packham .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 38100898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3811c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38129dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38132d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3814fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 3815121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 381679523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3817de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3818dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3819dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3820e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3821fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3822fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 382361303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 38246e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 38259e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 382617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38279e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 382823e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 382923e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3830931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3831931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3832d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 383317deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 3834a5a6858bSRussell King /* Check status register pause & lpa register */ 3835a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3836a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3837a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3838a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 38394241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 384061a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3841907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 38424262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 38434262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 3844bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3845bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 3846a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 38476c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 38481a3b39ecSAndrew Lunn }; 38491a3b39ecSAndrew Lunn 38501a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 38514b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 3852ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 3853cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 385498fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 385598fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 38561a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 38571a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 38581a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 38591a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 38601a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 3861f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 38627cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 3863ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 386456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3865601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 386656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 38670898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 3868c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 38699dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 38702d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3871fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 3872121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 387379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 3874de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 3875dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 3876dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 3877e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 3878fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 3879fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 388061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 38816e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 38829e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 388317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 38849e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 388523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 388623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3887931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 3888931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 38896335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 389017deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 3891a5a6858bSRussell King /* Check status register pause & lpa register */ 3892a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 3893a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 3894a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 3895a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 38964241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 389761a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 3898907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 38994262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 39004262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 3901bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 3902bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 39036d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 39046d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 39056c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 39061a3b39ecSAndrew Lunn }; 39071a3b39ecSAndrew Lunn 3908b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 39094b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 391093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 391193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 3912cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 3913ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 3914ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 3915b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 3916b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 3917b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 391808ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 3919a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3920f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 3921ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 3922f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 392356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 3924601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 392556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 3926cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 3927ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 39280898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 3929c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 39309dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39312d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 3932121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 3933a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 393440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 3935dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 3936dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 3937052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 3938fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 3939fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 3940fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 394151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 39429e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 394317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 39449e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 394523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 394623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 3947f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 39480ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 39499db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 3950a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 3951a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 3952a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 3953a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 39546d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 39554241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 395661a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 3957907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 3958d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 3959d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 3960a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 39610d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 39626d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 39636c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 3964b3469dd8SVivien Didelot }; 3965b3469dd8SVivien Didelot 39661f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = { 39671f71836fSRasmus Villemoes /* MV88E6XXX_FAMILY_6250 */ 39681f71836fSRasmus Villemoes .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 39691f71836fSRasmus Villemoes .ip_pri_map = mv88e6085_g1_ip_pri_map, 39701f71836fSRasmus Villemoes .irl_init_all = mv88e6352_g2_irl_init_all, 39711f71836fSRasmus Villemoes .get_eeprom = mv88e6xxx_g2_get_eeprom16, 39721f71836fSRasmus Villemoes .set_eeprom = mv88e6xxx_g2_set_eeprom16, 39731f71836fSRasmus Villemoes .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 39741f71836fSRasmus Villemoes .phy_read = mv88e6xxx_g2_smi_phy_read, 39751f71836fSRasmus Villemoes .phy_write = mv88e6xxx_g2_smi_phy_write, 39761f71836fSRasmus Villemoes .port_set_link = mv88e6xxx_port_set_link, 39771f71836fSRasmus Villemoes .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 3978f365c6f7SRussell King .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, 39791f71836fSRasmus Villemoes .port_tag_remap = mv88e6095_port_tag_remap, 39801f71836fSRasmus Villemoes .port_set_frame_mode = mv88e6351_port_set_frame_mode, 39811f71836fSRasmus Villemoes .port_set_egress_floods = mv88e6352_port_set_egress_floods, 39821f71836fSRasmus Villemoes .port_set_ether_type = mv88e6351_port_set_ether_type, 39831f71836fSRasmus Villemoes .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 39841f71836fSRasmus Villemoes .port_pause_limit = mv88e6097_port_pause_limit, 39851f71836fSRasmus Villemoes .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 39861f71836fSRasmus Villemoes .stats_snapshot = mv88e6320_g1_stats_snapshot, 39871f71836fSRasmus Villemoes .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 39881f71836fSRasmus Villemoes .stats_get_sset_count = mv88e6250_stats_get_sset_count, 39891f71836fSRasmus Villemoes .stats_get_strings = mv88e6250_stats_get_strings, 39901f71836fSRasmus Villemoes .stats_get_stats = mv88e6250_stats_get_stats, 39911f71836fSRasmus Villemoes .set_cpu_port = mv88e6095_g1_set_cpu_port, 39921f71836fSRasmus Villemoes .set_egress_port = mv88e6095_g1_set_egress_port, 39931f71836fSRasmus Villemoes .watchdog_ops = &mv88e6250_watchdog_ops, 39941f71836fSRasmus Villemoes .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 39951f71836fSRasmus Villemoes .pot_clear = mv88e6xxx_g2_pot_clear, 39961f71836fSRasmus Villemoes .reset = mv88e6250_g1_reset, 39971f71836fSRasmus Villemoes .vtu_getnext = mv88e6250_g1_vtu_getnext, 39981f71836fSRasmus Villemoes .vtu_loadpurge = mv88e6250_g1_vtu_loadpurge, 399971509614SHubert Feurstein .avb_ops = &mv88e6352_avb_ops, 400071509614SHubert Feurstein .ptp_ops = &mv88e6250_ptp_ops, 40011f71836fSRasmus Villemoes .phylink_validate = mv88e6065_phylink_validate, 40021f71836fSRasmus Villemoes }; 40031f71836fSRasmus Villemoes 40041a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 40054b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4006ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4007cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 400898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 400998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 40101a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 40111a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 40121a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 40131a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 40141a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4015f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 40167cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4017ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4018f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 401956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4020601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 402156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 40220898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4023c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40249dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40252d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4026fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4027121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 402879523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4029de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4030dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4031dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4032e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4033fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4034fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 403561303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 40366e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 40379e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 403817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 40399e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 404023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 404123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4042931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4043931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 40446335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 404517deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4046a5a6858bSRussell King /* Check status register pause & lpa register */ 4047a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4048a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4049a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4050a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 40514241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 405261a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4053907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 40544262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 40554262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4056bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4057bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4058a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 40590d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 40606d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 40616c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 40621a3b39ecSAndrew Lunn }; 40631a3b39ecSAndrew Lunn 4064b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 40654b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 406693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 406793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4068cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4069ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4070ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4071b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4072b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4073b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 407408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4075f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4076ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 407756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4078601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 407956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4080cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4081ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 40820898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4083c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40849dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40852d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4086121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4087a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 408840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4089dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4090dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4091052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4092fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4093fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 40949c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 409551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 40969e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 409717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4098f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 40990ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4100a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 41010d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 41026d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 41036c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4104b3469dd8SVivien Didelot }; 4105b3469dd8SVivien Didelot 4106b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 4107bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 410893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 410993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4110cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4111ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4112ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4113b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4114b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4115b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 411608ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4117f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4118ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 411956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4120601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 412156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4122cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4123ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 41240898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4125c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41269dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41272d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4128121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4129a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 413040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4131dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4132dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4133052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 4134fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4135fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 41369c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 413717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 4138f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 41390ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 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 = mv88e6185_phylink_validate, 4144b3469dd8SVivien Didelot }; 4145b3469dd8SVivien Didelot 414616e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 414716e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 414893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 414993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4150cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 415116e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 415216e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 415316e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 415416e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 415516e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 415616e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 415716e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4158f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 41597cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 416016e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 416116e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 416216e329aeSVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 416316e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 4164cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 416516e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 41660898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 416716e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 416816e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41692d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 41707a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 4171121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 417216e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 417340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 417416e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 417516e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 417616e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 4177fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4178fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 417916e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 418016e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 41819e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 418216e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 4183f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 41840ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4185d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 4186d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 4187a5a6858bSRussell King /* Check status register pause & lpa register */ 4188a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4189a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4190a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4191a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 41924241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 419361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4194907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4195a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 41960d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 41976d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4198e3af71a3SMarek Behún .phylink_validate = mv88e6341_phylink_validate, 419916e329aeSVivien Didelot }; 420016e329aeSVivien Didelot 4201b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 42024b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 420393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 420493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4205cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4206b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4207b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4208b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 420908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 421094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4211f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4212ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 421356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4214601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 421556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4216cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4217ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42180898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4219c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42209dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42212d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4222121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4223a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 422440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4225dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4226dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4227052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4228fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4229fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4230fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 423151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 42329e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 423317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 423423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 423523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4236f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 42370ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 42386c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4239b3469dd8SVivien Didelot }; 4240b3469dd8SVivien Didelot 4241b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 42424b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 424393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 424493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4245cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4246b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4247b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4248b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 424908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 425094d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4251f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4252ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 425356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4254601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 425556995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4256cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4257ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42580898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4259c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 42609dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42612d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4262121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4263a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 426440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4265dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4266dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4267052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4268fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4269fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4270fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 427151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 42729e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 427317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 427423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 427523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4276f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 42770ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 42780d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 42796d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 42806c422e34SRussell King .phylink_validate = mv88e6185_phylink_validate, 4281b3469dd8SVivien Didelot }; 4282b3469dd8SVivien Didelot 4283b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 42844b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 428593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 428693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4287cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4288ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4289ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4290b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4291b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4292b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 429308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 4294a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4295f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4296ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4297f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 429856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4299601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 430056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4301cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4302ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43030898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4304c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43059dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43062d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4307121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4308a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 430940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4310dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4311dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4312052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4313fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4314fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4315fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 431651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 43179e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 431817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 43199e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 432023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 432123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4322f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43230ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 43249db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4325a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4326a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4327a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4328a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 43296d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 43304241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 433161a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4332907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4333a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 43340d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 43356d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4336cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 4337cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 4338cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 4339d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4340d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 43416c422e34SRussell King .phylink_validate = mv88e6352_phylink_validate, 4342b3469dd8SVivien Didelot }; 4343b3469dd8SVivien Didelot 43441a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 43454b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4346ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4347cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 434898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 434998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 43501a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 43511a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 43521a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 43531a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 43541a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4355f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 43567cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4357ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4358f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 435956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4360601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 436156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4362cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4363ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43640898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4365c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43669dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43672d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4368fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4369121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 437079523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4371de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4372dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4373dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4374e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4375fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4376fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 437761303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 43786e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 43799e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 438017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 43819e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 438223e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 438323e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4384931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4385931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 43866335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 438717deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4388a5a6858bSRussell King /* Check status register pause & lpa register */ 4389a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4390a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4391a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4392a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 43934241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 439461a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4395907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4396a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 43970d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 43986d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 43990df95287SNikita Yushchenko .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 44000df95287SNikita Yushchenko .serdes_get_strings = mv88e6390_serdes_get_strings, 44010df95287SNikita Yushchenko .serdes_get_stats = mv88e6390_serdes_get_stats, 4402bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4403bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 44046c422e34SRussell King .phylink_validate = mv88e6390_phylink_validate, 44051a3b39ecSAndrew Lunn }; 44061a3b39ecSAndrew Lunn 44071a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 44084b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4409ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4410cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 441198fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 441298fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 44131a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 44141a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 44151a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 44161a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 44171a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4418f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 44197cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 4420ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4421f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 442256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4423601aeed3SVivien Didelot .port_set_egress_floods = mv88e6352_port_set_egress_floods, 442456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4425cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4426ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44270898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4428c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44299dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44302d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4431b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 4432121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 443379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4434de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4435dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4436dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4437e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4438fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4439fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 444061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 44416e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 44429e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 444317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 44449e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 444523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 444623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4447931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4448931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4449d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 445017deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 4451a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4452a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4453a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4454a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 44554241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 445661a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4457907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 44584262c38dSAndrew Lunn .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 44594262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 44604262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4461bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4462bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4463a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 44640d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 44656d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 44666c422e34SRussell King .phylink_validate = mv88e6390x_phylink_validate, 44671a3b39ecSAndrew Lunn }; 44681a3b39ecSAndrew Lunn 4469fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 4470fad09c73SVivien Didelot [MV88E6085] = { 4471107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 4472fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 4473fad09c73SVivien Didelot .name = "Marvell 88E6085", 4474fad09c73SVivien Didelot .num_databases = 4096, 4475d9ea5620SAndrew Lunn .num_macs = 8192, 4476fad09c73SVivien Didelot .num_ports = 10, 4477bc393155SAndrew Lunn .num_internal_phys = 5, 44783cf3c846SVivien Didelot .max_vid = 4095, 4479fad09c73SVivien Didelot .port_base_addr = 0x10, 44809255bacdSAndrew Lunn .phy_base_addr = 0x0, 4481a935c052SVivien Didelot .global1_addr = 0x1b, 44829069c13aSVivien Didelot .global2_addr = 0x1c, 4483acddbd21SVivien Didelot .age_time_coeff = 15000, 4484dc30c35bSAndrew Lunn .g1_irqs = 8, 4485d6c5e6afSVivien Didelot .g2_irqs = 10, 4486e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4487f3645652SVivien Didelot .pvt = true, 4488b3e05aa1SVivien Didelot .multi_chip = true, 4489443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4490b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 4491fad09c73SVivien Didelot }, 4492fad09c73SVivien Didelot 4493fad09c73SVivien Didelot [MV88E6095] = { 4494107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 4495fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 4496fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 4497fad09c73SVivien Didelot .num_databases = 256, 4498d9ea5620SAndrew Lunn .num_macs = 8192, 4499fad09c73SVivien Didelot .num_ports = 11, 4500bc393155SAndrew Lunn .num_internal_phys = 0, 45013cf3c846SVivien Didelot .max_vid = 4095, 4502fad09c73SVivien Didelot .port_base_addr = 0x10, 45039255bacdSAndrew Lunn .phy_base_addr = 0x0, 4504a935c052SVivien Didelot .global1_addr = 0x1b, 45059069c13aSVivien Didelot .global2_addr = 0x1c, 4506acddbd21SVivien Didelot .age_time_coeff = 15000, 4507dc30c35bSAndrew Lunn .g1_irqs = 8, 4508e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4509b3e05aa1SVivien Didelot .multi_chip = true, 4510443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4511b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 4512fad09c73SVivien Didelot }, 4513fad09c73SVivien Didelot 45147d381a02SStefan Eichenberger [MV88E6097] = { 4515107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 45167d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 45177d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 45187d381a02SStefan Eichenberger .num_databases = 4096, 4519d9ea5620SAndrew Lunn .num_macs = 8192, 45207d381a02SStefan Eichenberger .num_ports = 11, 4521bc393155SAndrew Lunn .num_internal_phys = 8, 45223cf3c846SVivien Didelot .max_vid = 4095, 45237d381a02SStefan Eichenberger .port_base_addr = 0x10, 45249255bacdSAndrew Lunn .phy_base_addr = 0x0, 45257d381a02SStefan Eichenberger .global1_addr = 0x1b, 45269069c13aSVivien Didelot .global2_addr = 0x1c, 45277d381a02SStefan Eichenberger .age_time_coeff = 15000, 4528c534178bSStefan Eichenberger .g1_irqs = 8, 4529d6c5e6afSVivien Didelot .g2_irqs = 10, 4530e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4531f3645652SVivien Didelot .pvt = true, 4532b3e05aa1SVivien Didelot .multi_chip = true, 45332bfcfcd3SStefan Eichenberger .tag_protocol = DSA_TAG_PROTO_EDSA, 45347d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 45357d381a02SStefan Eichenberger }, 45367d381a02SStefan Eichenberger 4537fad09c73SVivien Didelot [MV88E6123] = { 4538107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 4539fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4540fad09c73SVivien Didelot .name = "Marvell 88E6123", 4541fad09c73SVivien Didelot .num_databases = 4096, 4542d9ea5620SAndrew Lunn .num_macs = 1024, 4543fad09c73SVivien Didelot .num_ports = 3, 4544bc393155SAndrew Lunn .num_internal_phys = 5, 45453cf3c846SVivien Didelot .max_vid = 4095, 4546fad09c73SVivien Didelot .port_base_addr = 0x10, 45479255bacdSAndrew Lunn .phy_base_addr = 0x0, 4548a935c052SVivien Didelot .global1_addr = 0x1b, 45499069c13aSVivien Didelot .global2_addr = 0x1c, 4550acddbd21SVivien Didelot .age_time_coeff = 15000, 4551dc30c35bSAndrew Lunn .g1_irqs = 9, 4552d6c5e6afSVivien Didelot .g2_irqs = 10, 4553e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4554f3645652SVivien Didelot .pvt = true, 4555b3e05aa1SVivien Didelot .multi_chip = true, 45565ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4557b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 4558fad09c73SVivien Didelot }, 4559fad09c73SVivien Didelot 4560fad09c73SVivien Didelot [MV88E6131] = { 4561107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 4562fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4563fad09c73SVivien Didelot .name = "Marvell 88E6131", 4564fad09c73SVivien Didelot .num_databases = 256, 4565d9ea5620SAndrew Lunn .num_macs = 8192, 4566fad09c73SVivien Didelot .num_ports = 8, 4567bc393155SAndrew Lunn .num_internal_phys = 0, 45683cf3c846SVivien Didelot .max_vid = 4095, 4569fad09c73SVivien Didelot .port_base_addr = 0x10, 45709255bacdSAndrew Lunn .phy_base_addr = 0x0, 4571a935c052SVivien Didelot .global1_addr = 0x1b, 45729069c13aSVivien Didelot .global2_addr = 0x1c, 4573acddbd21SVivien Didelot .age_time_coeff = 15000, 4574dc30c35bSAndrew Lunn .g1_irqs = 9, 4575e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4576b3e05aa1SVivien Didelot .multi_chip = true, 4577443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4578b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 4579fad09c73SVivien Didelot }, 4580fad09c73SVivien Didelot 4581990e27b0SVivien Didelot [MV88E6141] = { 4582107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 4583990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 458479a68b26SUwe Kleine-König .name = "Marvell 88E6141", 4585990e27b0SVivien Didelot .num_databases = 4096, 4586d9ea5620SAndrew Lunn .num_macs = 2048, 4587990e27b0SVivien Didelot .num_ports = 6, 4588bc393155SAndrew Lunn .num_internal_phys = 5, 4589a73ccd61SBrandon Streiff .num_gpio = 11, 45903cf3c846SVivien Didelot .max_vid = 4095, 4591990e27b0SVivien Didelot .port_base_addr = 0x10, 45929255bacdSAndrew Lunn .phy_base_addr = 0x10, 4593990e27b0SVivien Didelot .global1_addr = 0x1b, 45949069c13aSVivien Didelot .global2_addr = 0x1c, 4595990e27b0SVivien Didelot .age_time_coeff = 3750, 4596990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 4597adfccf11SAndrew Lunn .g1_irqs = 9, 4598d6c5e6afSVivien Didelot .g2_irqs = 10, 4599f3645652SVivien Didelot .pvt = true, 4600b3e05aa1SVivien Didelot .multi_chip = true, 4601990e27b0SVivien Didelot .tag_protocol = DSA_TAG_PROTO_EDSA, 4602990e27b0SVivien Didelot .ops = &mv88e6141_ops, 4603990e27b0SVivien Didelot }, 4604990e27b0SVivien Didelot 4605fad09c73SVivien Didelot [MV88E6161] = { 4606107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 4607fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4608fad09c73SVivien Didelot .name = "Marvell 88E6161", 4609fad09c73SVivien Didelot .num_databases = 4096, 4610d9ea5620SAndrew Lunn .num_macs = 1024, 4611fad09c73SVivien Didelot .num_ports = 6, 4612bc393155SAndrew Lunn .num_internal_phys = 5, 46133cf3c846SVivien Didelot .max_vid = 4095, 4614fad09c73SVivien Didelot .port_base_addr = 0x10, 46159255bacdSAndrew Lunn .phy_base_addr = 0x0, 4616a935c052SVivien Didelot .global1_addr = 0x1b, 46179069c13aSVivien Didelot .global2_addr = 0x1c, 4618acddbd21SVivien Didelot .age_time_coeff = 15000, 4619dc30c35bSAndrew Lunn .g1_irqs = 9, 4620d6c5e6afSVivien Didelot .g2_irqs = 10, 4621e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4622f3645652SVivien Didelot .pvt = true, 4623b3e05aa1SVivien Didelot .multi_chip = true, 46245ebe31d7SAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4625dfa54348SAndrew Lunn .ptp_support = true, 4626b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 4627fad09c73SVivien Didelot }, 4628fad09c73SVivien Didelot 4629fad09c73SVivien Didelot [MV88E6165] = { 4630107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 4631fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 4632fad09c73SVivien Didelot .name = "Marvell 88E6165", 4633fad09c73SVivien Didelot .num_databases = 4096, 4634d9ea5620SAndrew Lunn .num_macs = 8192, 4635fad09c73SVivien Didelot .num_ports = 6, 4636bc393155SAndrew Lunn .num_internal_phys = 0, 46373cf3c846SVivien Didelot .max_vid = 4095, 4638fad09c73SVivien Didelot .port_base_addr = 0x10, 46399255bacdSAndrew Lunn .phy_base_addr = 0x0, 4640a935c052SVivien Didelot .global1_addr = 0x1b, 46419069c13aSVivien Didelot .global2_addr = 0x1c, 4642acddbd21SVivien Didelot .age_time_coeff = 15000, 4643dc30c35bSAndrew Lunn .g1_irqs = 9, 4644d6c5e6afSVivien Didelot .g2_irqs = 10, 4645e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4646f3645652SVivien Didelot .pvt = true, 4647b3e05aa1SVivien Didelot .multi_chip = true, 4648443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4649dfa54348SAndrew Lunn .ptp_support = true, 4650b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 4651fad09c73SVivien Didelot }, 4652fad09c73SVivien Didelot 4653fad09c73SVivien Didelot [MV88E6171] = { 4654107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 4655fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4656fad09c73SVivien Didelot .name = "Marvell 88E6171", 4657fad09c73SVivien Didelot .num_databases = 4096, 4658d9ea5620SAndrew Lunn .num_macs = 8192, 4659fad09c73SVivien Didelot .num_ports = 7, 4660bc393155SAndrew Lunn .num_internal_phys = 5, 46613cf3c846SVivien Didelot .max_vid = 4095, 4662fad09c73SVivien Didelot .port_base_addr = 0x10, 46639255bacdSAndrew Lunn .phy_base_addr = 0x0, 4664a935c052SVivien Didelot .global1_addr = 0x1b, 46659069c13aSVivien Didelot .global2_addr = 0x1c, 4666acddbd21SVivien Didelot .age_time_coeff = 15000, 4667dc30c35bSAndrew Lunn .g1_irqs = 9, 4668d6c5e6afSVivien Didelot .g2_irqs = 10, 4669e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4670f3645652SVivien Didelot .pvt = true, 4671b3e05aa1SVivien Didelot .multi_chip = true, 4672443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4673b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 4674fad09c73SVivien Didelot }, 4675fad09c73SVivien Didelot 4676fad09c73SVivien Didelot [MV88E6172] = { 4677107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 4678fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4679fad09c73SVivien Didelot .name = "Marvell 88E6172", 4680fad09c73SVivien Didelot .num_databases = 4096, 4681d9ea5620SAndrew Lunn .num_macs = 8192, 4682fad09c73SVivien Didelot .num_ports = 7, 4683bc393155SAndrew Lunn .num_internal_phys = 5, 4684a73ccd61SBrandon Streiff .num_gpio = 15, 46853cf3c846SVivien Didelot .max_vid = 4095, 4686fad09c73SVivien Didelot .port_base_addr = 0x10, 46879255bacdSAndrew Lunn .phy_base_addr = 0x0, 4688a935c052SVivien Didelot .global1_addr = 0x1b, 46899069c13aSVivien Didelot .global2_addr = 0x1c, 4690acddbd21SVivien Didelot .age_time_coeff = 15000, 4691dc30c35bSAndrew Lunn .g1_irqs = 9, 4692d6c5e6afSVivien Didelot .g2_irqs = 10, 4693e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4694f3645652SVivien Didelot .pvt = true, 4695b3e05aa1SVivien Didelot .multi_chip = true, 4696443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4697b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 4698fad09c73SVivien Didelot }, 4699fad09c73SVivien Didelot 4700fad09c73SVivien Didelot [MV88E6175] = { 4701107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 4702fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 4703fad09c73SVivien Didelot .name = "Marvell 88E6175", 4704fad09c73SVivien Didelot .num_databases = 4096, 4705d9ea5620SAndrew Lunn .num_macs = 8192, 4706fad09c73SVivien Didelot .num_ports = 7, 4707bc393155SAndrew Lunn .num_internal_phys = 5, 47083cf3c846SVivien Didelot .max_vid = 4095, 4709fad09c73SVivien Didelot .port_base_addr = 0x10, 47109255bacdSAndrew Lunn .phy_base_addr = 0x0, 4711a935c052SVivien Didelot .global1_addr = 0x1b, 47129069c13aSVivien Didelot .global2_addr = 0x1c, 4713acddbd21SVivien Didelot .age_time_coeff = 15000, 4714dc30c35bSAndrew Lunn .g1_irqs = 9, 4715d6c5e6afSVivien Didelot .g2_irqs = 10, 4716e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4717f3645652SVivien Didelot .pvt = true, 4718b3e05aa1SVivien Didelot .multi_chip = true, 4719443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4720b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 4721fad09c73SVivien Didelot }, 4722fad09c73SVivien Didelot 4723fad09c73SVivien Didelot [MV88E6176] = { 4724107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 4725fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4726fad09c73SVivien Didelot .name = "Marvell 88E6176", 4727fad09c73SVivien Didelot .num_databases = 4096, 4728d9ea5620SAndrew Lunn .num_macs = 8192, 4729fad09c73SVivien Didelot .num_ports = 7, 4730bc393155SAndrew Lunn .num_internal_phys = 5, 4731a73ccd61SBrandon Streiff .num_gpio = 15, 47323cf3c846SVivien Didelot .max_vid = 4095, 4733fad09c73SVivien Didelot .port_base_addr = 0x10, 47349255bacdSAndrew Lunn .phy_base_addr = 0x0, 4735a935c052SVivien Didelot .global1_addr = 0x1b, 47369069c13aSVivien Didelot .global2_addr = 0x1c, 4737acddbd21SVivien Didelot .age_time_coeff = 15000, 4738dc30c35bSAndrew Lunn .g1_irqs = 9, 4739d6c5e6afSVivien Didelot .g2_irqs = 10, 4740e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4741f3645652SVivien Didelot .pvt = true, 4742b3e05aa1SVivien Didelot .multi_chip = true, 4743443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4744b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 4745fad09c73SVivien Didelot }, 4746fad09c73SVivien Didelot 4747fad09c73SVivien Didelot [MV88E6185] = { 4748107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 4749fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 4750fad09c73SVivien Didelot .name = "Marvell 88E6185", 4751fad09c73SVivien Didelot .num_databases = 256, 4752d9ea5620SAndrew Lunn .num_macs = 8192, 4753fad09c73SVivien Didelot .num_ports = 10, 4754bc393155SAndrew Lunn .num_internal_phys = 0, 47553cf3c846SVivien Didelot .max_vid = 4095, 4756fad09c73SVivien Didelot .port_base_addr = 0x10, 47579255bacdSAndrew Lunn .phy_base_addr = 0x0, 4758a935c052SVivien Didelot .global1_addr = 0x1b, 47599069c13aSVivien Didelot .global2_addr = 0x1c, 4760acddbd21SVivien Didelot .age_time_coeff = 15000, 4761dc30c35bSAndrew Lunn .g1_irqs = 8, 4762e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4763b3e05aa1SVivien Didelot .multi_chip = true, 4764443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 4765b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 4766fad09c73SVivien Didelot }, 4767fad09c73SVivien Didelot 47681a3b39ecSAndrew Lunn [MV88E6190] = { 4769107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 47701a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 47711a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 47721a3b39ecSAndrew Lunn .num_databases = 4096, 4773d9ea5620SAndrew Lunn .num_macs = 16384, 47741a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 477595150f29SHeiner Kallweit .num_internal_phys = 9, 4776a73ccd61SBrandon Streiff .num_gpio = 16, 4777931d1822SVivien Didelot .max_vid = 8191, 47781a3b39ecSAndrew Lunn .port_base_addr = 0x0, 47799255bacdSAndrew Lunn .phy_base_addr = 0x0, 47801a3b39ecSAndrew Lunn .global1_addr = 0x1b, 47819069c13aSVivien Didelot .global2_addr = 0x1c, 4782443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 4783b91e055cSAndrew Lunn .age_time_coeff = 3750, 47841a3b39ecSAndrew Lunn .g1_irqs = 9, 4785d6c5e6afSVivien Didelot .g2_irqs = 14, 4786f3645652SVivien Didelot .pvt = true, 4787b3e05aa1SVivien Didelot .multi_chip = true, 4788e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 47891a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 47901a3b39ecSAndrew Lunn }, 47911a3b39ecSAndrew Lunn 47921a3b39ecSAndrew Lunn [MV88E6190X] = { 4793107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 47941a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 47951a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 47961a3b39ecSAndrew Lunn .num_databases = 4096, 4797d9ea5620SAndrew Lunn .num_macs = 16384, 47981a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 479995150f29SHeiner Kallweit .num_internal_phys = 9, 4800a73ccd61SBrandon Streiff .num_gpio = 16, 4801931d1822SVivien Didelot .max_vid = 8191, 48021a3b39ecSAndrew Lunn .port_base_addr = 0x0, 48039255bacdSAndrew Lunn .phy_base_addr = 0x0, 48041a3b39ecSAndrew Lunn .global1_addr = 0x1b, 48059069c13aSVivien Didelot .global2_addr = 0x1c, 4806b91e055cSAndrew Lunn .age_time_coeff = 3750, 48071a3b39ecSAndrew Lunn .g1_irqs = 9, 4808d6c5e6afSVivien Didelot .g2_irqs = 14, 4809e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4810f3645652SVivien Didelot .pvt = true, 4811b3e05aa1SVivien Didelot .multi_chip = true, 4812443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 48131a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 48141a3b39ecSAndrew Lunn }, 48151a3b39ecSAndrew Lunn 48161a3b39ecSAndrew Lunn [MV88E6191] = { 4817107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 48181a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 48191a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 48201a3b39ecSAndrew Lunn .num_databases = 4096, 4821d9ea5620SAndrew Lunn .num_macs = 16384, 48221a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 482395150f29SHeiner Kallweit .num_internal_phys = 9, 4824931d1822SVivien Didelot .max_vid = 8191, 48251a3b39ecSAndrew Lunn .port_base_addr = 0x0, 48269255bacdSAndrew Lunn .phy_base_addr = 0x0, 48271a3b39ecSAndrew Lunn .global1_addr = 0x1b, 48289069c13aSVivien Didelot .global2_addr = 0x1c, 4829b91e055cSAndrew Lunn .age_time_coeff = 3750, 4830443d5a1bSAndrew Lunn .g1_irqs = 9, 4831d6c5e6afSVivien Didelot .g2_irqs = 14, 4832e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4833f3645652SVivien Didelot .pvt = true, 4834b3e05aa1SVivien Didelot .multi_chip = true, 4835443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 48362fa8d3afSBrandon Streiff .ptp_support = true, 48372cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 48381a3b39ecSAndrew Lunn }, 48391a3b39ecSAndrew Lunn 484049022647SHubert Feurstein [MV88E6220] = { 484149022647SHubert Feurstein .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220, 484249022647SHubert Feurstein .family = MV88E6XXX_FAMILY_6250, 484349022647SHubert Feurstein .name = "Marvell 88E6220", 484449022647SHubert Feurstein .num_databases = 64, 484549022647SHubert Feurstein 484649022647SHubert Feurstein /* Ports 2-4 are not routed to pins 484749022647SHubert Feurstein * => usable ports 0, 1, 5, 6 484849022647SHubert Feurstein */ 484949022647SHubert Feurstein .num_ports = 7, 485049022647SHubert Feurstein .num_internal_phys = 2, 4851c857486aSHubert Feurstein .invalid_port_mask = BIT(2) | BIT(3) | BIT(4), 485249022647SHubert Feurstein .max_vid = 4095, 485349022647SHubert Feurstein .port_base_addr = 0x08, 485449022647SHubert Feurstein .phy_base_addr = 0x00, 485549022647SHubert Feurstein .global1_addr = 0x0f, 485649022647SHubert Feurstein .global2_addr = 0x07, 485749022647SHubert Feurstein .age_time_coeff = 15000, 485849022647SHubert Feurstein .g1_irqs = 9, 485949022647SHubert Feurstein .g2_irqs = 10, 486049022647SHubert Feurstein .atu_move_port_mask = 0xf, 486149022647SHubert Feurstein .dual_chip = true, 486249022647SHubert Feurstein .tag_protocol = DSA_TAG_PROTO_DSA, 486371509614SHubert Feurstein .ptp_support = true, 486449022647SHubert Feurstein .ops = &mv88e6250_ops, 486549022647SHubert Feurstein }, 486649022647SHubert Feurstein 4867fad09c73SVivien Didelot [MV88E6240] = { 4868107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 4869fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 4870fad09c73SVivien Didelot .name = "Marvell 88E6240", 4871fad09c73SVivien Didelot .num_databases = 4096, 4872d9ea5620SAndrew Lunn .num_macs = 8192, 4873fad09c73SVivien Didelot .num_ports = 7, 4874bc393155SAndrew Lunn .num_internal_phys = 5, 4875a73ccd61SBrandon Streiff .num_gpio = 15, 48763cf3c846SVivien Didelot .max_vid = 4095, 4877fad09c73SVivien Didelot .port_base_addr = 0x10, 48789255bacdSAndrew Lunn .phy_base_addr = 0x0, 4879a935c052SVivien Didelot .global1_addr = 0x1b, 48809069c13aSVivien Didelot .global2_addr = 0x1c, 4881acddbd21SVivien Didelot .age_time_coeff = 15000, 4882dc30c35bSAndrew Lunn .g1_irqs = 9, 4883d6c5e6afSVivien Didelot .g2_irqs = 10, 4884e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4885f3645652SVivien Didelot .pvt = true, 4886b3e05aa1SVivien Didelot .multi_chip = true, 4887443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 48882fa8d3afSBrandon Streiff .ptp_support = true, 4889b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 4890fad09c73SVivien Didelot }, 4891fad09c73SVivien Didelot 48921f71836fSRasmus Villemoes [MV88E6250] = { 48931f71836fSRasmus Villemoes .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 48941f71836fSRasmus Villemoes .family = MV88E6XXX_FAMILY_6250, 48951f71836fSRasmus Villemoes .name = "Marvell 88E6250", 48961f71836fSRasmus Villemoes .num_databases = 64, 48971f71836fSRasmus Villemoes .num_ports = 7, 48981f71836fSRasmus Villemoes .num_internal_phys = 5, 48991f71836fSRasmus Villemoes .max_vid = 4095, 49001f71836fSRasmus Villemoes .port_base_addr = 0x08, 49011f71836fSRasmus Villemoes .phy_base_addr = 0x00, 49021f71836fSRasmus Villemoes .global1_addr = 0x0f, 49031f71836fSRasmus Villemoes .global2_addr = 0x07, 49041f71836fSRasmus Villemoes .age_time_coeff = 15000, 49051f71836fSRasmus Villemoes .g1_irqs = 9, 49061f71836fSRasmus Villemoes .g2_irqs = 10, 49071f71836fSRasmus Villemoes .atu_move_port_mask = 0xf, 49081f71836fSRasmus Villemoes .dual_chip = true, 49091f71836fSRasmus Villemoes .tag_protocol = DSA_TAG_PROTO_DSA, 491071509614SHubert Feurstein .ptp_support = true, 49111f71836fSRasmus Villemoes .ops = &mv88e6250_ops, 49121f71836fSRasmus Villemoes }, 49131f71836fSRasmus Villemoes 49141a3b39ecSAndrew Lunn [MV88E6290] = { 4915107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 49161a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 49171a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 49181a3b39ecSAndrew Lunn .num_databases = 4096, 49191a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 492095150f29SHeiner Kallweit .num_internal_phys = 9, 4921a73ccd61SBrandon Streiff .num_gpio = 16, 4922931d1822SVivien Didelot .max_vid = 8191, 49231a3b39ecSAndrew Lunn .port_base_addr = 0x0, 49249255bacdSAndrew Lunn .phy_base_addr = 0x0, 49251a3b39ecSAndrew Lunn .global1_addr = 0x1b, 49269069c13aSVivien Didelot .global2_addr = 0x1c, 4927b91e055cSAndrew Lunn .age_time_coeff = 3750, 49281a3b39ecSAndrew Lunn .g1_irqs = 9, 4929d6c5e6afSVivien Didelot .g2_irqs = 14, 4930e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 4931f3645652SVivien Didelot .pvt = true, 4932b3e05aa1SVivien Didelot .multi_chip = true, 4933443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 49342fa8d3afSBrandon Streiff .ptp_support = true, 49351a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 49361a3b39ecSAndrew Lunn }, 49371a3b39ecSAndrew Lunn 4938fad09c73SVivien Didelot [MV88E6320] = { 4939107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 4940fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 4941fad09c73SVivien Didelot .name = "Marvell 88E6320", 4942fad09c73SVivien Didelot .num_databases = 4096, 4943d9ea5620SAndrew Lunn .num_macs = 8192, 4944fad09c73SVivien Didelot .num_ports = 7, 4945bc393155SAndrew Lunn .num_internal_phys = 5, 4946a73ccd61SBrandon Streiff .num_gpio = 15, 49473cf3c846SVivien Didelot .max_vid = 4095, 4948fad09c73SVivien Didelot .port_base_addr = 0x10, 49499255bacdSAndrew Lunn .phy_base_addr = 0x0, 4950a935c052SVivien Didelot .global1_addr = 0x1b, 49519069c13aSVivien Didelot .global2_addr = 0x1c, 4952acddbd21SVivien Didelot .age_time_coeff = 15000, 4953dc30c35bSAndrew Lunn .g1_irqs = 8, 4954bc393155SAndrew Lunn .g2_irqs = 10, 4955e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4956f3645652SVivien Didelot .pvt = true, 4957b3e05aa1SVivien Didelot .multi_chip = true, 4958443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 49592fa8d3afSBrandon Streiff .ptp_support = true, 4960b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 4961fad09c73SVivien Didelot }, 4962fad09c73SVivien Didelot 4963fad09c73SVivien Didelot [MV88E6321] = { 4964107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 4965fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 4966fad09c73SVivien Didelot .name = "Marvell 88E6321", 4967fad09c73SVivien Didelot .num_databases = 4096, 4968d9ea5620SAndrew Lunn .num_macs = 8192, 4969fad09c73SVivien Didelot .num_ports = 7, 4970bc393155SAndrew Lunn .num_internal_phys = 5, 4971a73ccd61SBrandon Streiff .num_gpio = 15, 49723cf3c846SVivien Didelot .max_vid = 4095, 4973fad09c73SVivien Didelot .port_base_addr = 0x10, 49749255bacdSAndrew Lunn .phy_base_addr = 0x0, 4975a935c052SVivien Didelot .global1_addr = 0x1b, 49769069c13aSVivien Didelot .global2_addr = 0x1c, 4977acddbd21SVivien Didelot .age_time_coeff = 15000, 4978dc30c35bSAndrew Lunn .g1_irqs = 8, 4979bc393155SAndrew Lunn .g2_irqs = 10, 4980e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 4981b3e05aa1SVivien Didelot .multi_chip = true, 4982443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 49832fa8d3afSBrandon Streiff .ptp_support = true, 4984b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 4985fad09c73SVivien Didelot }, 4986fad09c73SVivien Didelot 4987a75961d0SGregory CLEMENT [MV88E6341] = { 4988107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 4989a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 4990a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 4991a75961d0SGregory CLEMENT .num_databases = 4096, 4992d9ea5620SAndrew Lunn .num_macs = 2048, 4993bc393155SAndrew Lunn .num_internal_phys = 5, 4994a75961d0SGregory CLEMENT .num_ports = 6, 4995a73ccd61SBrandon Streiff .num_gpio = 11, 49963cf3c846SVivien Didelot .max_vid = 4095, 4997a75961d0SGregory CLEMENT .port_base_addr = 0x10, 49989255bacdSAndrew Lunn .phy_base_addr = 0x10, 4999a75961d0SGregory CLEMENT .global1_addr = 0x1b, 50009069c13aSVivien Didelot .global2_addr = 0x1c, 5001a75961d0SGregory CLEMENT .age_time_coeff = 3750, 5002e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5003adfccf11SAndrew Lunn .g1_irqs = 9, 5004d6c5e6afSVivien Didelot .g2_irqs = 10, 5005f3645652SVivien Didelot .pvt = true, 5006b3e05aa1SVivien Didelot .multi_chip = true, 5007a75961d0SGregory CLEMENT .tag_protocol = DSA_TAG_PROTO_EDSA, 50082fa8d3afSBrandon Streiff .ptp_support = true, 5009a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 5010a75961d0SGregory CLEMENT }, 5011a75961d0SGregory CLEMENT 5012fad09c73SVivien Didelot [MV88E6350] = { 5013107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 5014fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5015fad09c73SVivien Didelot .name = "Marvell 88E6350", 5016fad09c73SVivien Didelot .num_databases = 4096, 5017d9ea5620SAndrew Lunn .num_macs = 8192, 5018fad09c73SVivien Didelot .num_ports = 7, 5019bc393155SAndrew Lunn .num_internal_phys = 5, 50203cf3c846SVivien Didelot .max_vid = 4095, 5021fad09c73SVivien Didelot .port_base_addr = 0x10, 50229255bacdSAndrew Lunn .phy_base_addr = 0x0, 5023a935c052SVivien Didelot .global1_addr = 0x1b, 50249069c13aSVivien Didelot .global2_addr = 0x1c, 5025acddbd21SVivien Didelot .age_time_coeff = 15000, 5026dc30c35bSAndrew Lunn .g1_irqs = 9, 5027d6c5e6afSVivien Didelot .g2_irqs = 10, 5028e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5029f3645652SVivien Didelot .pvt = true, 5030b3e05aa1SVivien Didelot .multi_chip = true, 5031443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 5032b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 5033fad09c73SVivien Didelot }, 5034fad09c73SVivien Didelot 5035fad09c73SVivien Didelot [MV88E6351] = { 5036107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 5037fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5038fad09c73SVivien Didelot .name = "Marvell 88E6351", 5039fad09c73SVivien Didelot .num_databases = 4096, 5040d9ea5620SAndrew Lunn .num_macs = 8192, 5041fad09c73SVivien Didelot .num_ports = 7, 5042bc393155SAndrew Lunn .num_internal_phys = 5, 50433cf3c846SVivien Didelot .max_vid = 4095, 5044fad09c73SVivien Didelot .port_base_addr = 0x10, 50459255bacdSAndrew Lunn .phy_base_addr = 0x0, 5046a935c052SVivien Didelot .global1_addr = 0x1b, 50479069c13aSVivien Didelot .global2_addr = 0x1c, 5048acddbd21SVivien Didelot .age_time_coeff = 15000, 5049dc30c35bSAndrew Lunn .g1_irqs = 9, 5050d6c5e6afSVivien Didelot .g2_irqs = 10, 5051e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5052f3645652SVivien Didelot .pvt = true, 5053b3e05aa1SVivien Didelot .multi_chip = true, 5054443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 5055b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 5056fad09c73SVivien Didelot }, 5057fad09c73SVivien Didelot 5058fad09c73SVivien Didelot [MV88E6352] = { 5059107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 5060fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5061fad09c73SVivien Didelot .name = "Marvell 88E6352", 5062fad09c73SVivien Didelot .num_databases = 4096, 5063d9ea5620SAndrew Lunn .num_macs = 8192, 5064fad09c73SVivien Didelot .num_ports = 7, 5065bc393155SAndrew Lunn .num_internal_phys = 5, 5066a73ccd61SBrandon Streiff .num_gpio = 15, 50673cf3c846SVivien Didelot .max_vid = 4095, 5068fad09c73SVivien Didelot .port_base_addr = 0x10, 50699255bacdSAndrew Lunn .phy_base_addr = 0x0, 5070a935c052SVivien Didelot .global1_addr = 0x1b, 50719069c13aSVivien Didelot .global2_addr = 0x1c, 5072acddbd21SVivien Didelot .age_time_coeff = 15000, 5073dc30c35bSAndrew Lunn .g1_irqs = 9, 5074d6c5e6afSVivien Didelot .g2_irqs = 10, 5075e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5076f3645652SVivien Didelot .pvt = true, 5077b3e05aa1SVivien Didelot .multi_chip = true, 5078443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_EDSA, 50792fa8d3afSBrandon Streiff .ptp_support = true, 5080b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 5081fad09c73SVivien Didelot }, 50821a3b39ecSAndrew Lunn [MV88E6390] = { 5083107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 50841a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 50851a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 50861a3b39ecSAndrew Lunn .num_databases = 4096, 5087d9ea5620SAndrew Lunn .num_macs = 16384, 50881a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 508995150f29SHeiner Kallweit .num_internal_phys = 9, 5090a73ccd61SBrandon Streiff .num_gpio = 16, 5091931d1822SVivien Didelot .max_vid = 8191, 50921a3b39ecSAndrew Lunn .port_base_addr = 0x0, 50939255bacdSAndrew Lunn .phy_base_addr = 0x0, 50941a3b39ecSAndrew Lunn .global1_addr = 0x1b, 50959069c13aSVivien Didelot .global2_addr = 0x1c, 5096b91e055cSAndrew Lunn .age_time_coeff = 3750, 50971a3b39ecSAndrew Lunn .g1_irqs = 9, 5098d6c5e6afSVivien Didelot .g2_irqs = 14, 5099e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5100f3645652SVivien Didelot .pvt = true, 5101b3e05aa1SVivien Didelot .multi_chip = true, 5102443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 51032fa8d3afSBrandon Streiff .ptp_support = true, 51041a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 51051a3b39ecSAndrew Lunn }, 51061a3b39ecSAndrew Lunn [MV88E6390X] = { 5107107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 51081a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 51091a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 51101a3b39ecSAndrew Lunn .num_databases = 4096, 5111d9ea5620SAndrew Lunn .num_macs = 16384, 51121a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 511395150f29SHeiner Kallweit .num_internal_phys = 9, 5114a73ccd61SBrandon Streiff .num_gpio = 16, 5115931d1822SVivien Didelot .max_vid = 8191, 51161a3b39ecSAndrew Lunn .port_base_addr = 0x0, 51179255bacdSAndrew Lunn .phy_base_addr = 0x0, 51181a3b39ecSAndrew Lunn .global1_addr = 0x1b, 51199069c13aSVivien Didelot .global2_addr = 0x1c, 5120b91e055cSAndrew Lunn .age_time_coeff = 3750, 51211a3b39ecSAndrew Lunn .g1_irqs = 9, 5122d6c5e6afSVivien Didelot .g2_irqs = 14, 5123e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5124f3645652SVivien Didelot .pvt = true, 5125b3e05aa1SVivien Didelot .multi_chip = true, 5126443d5a1bSAndrew Lunn .tag_protocol = DSA_TAG_PROTO_DSA, 51272fa8d3afSBrandon Streiff .ptp_support = true, 51281a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 51291a3b39ecSAndrew Lunn }, 5130fad09c73SVivien Didelot }; 5131fad09c73SVivien Didelot 5132fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 5133fad09c73SVivien Didelot { 5134fad09c73SVivien Didelot int i; 5135fad09c73SVivien Didelot 5136fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 5137fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 5138fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 5139fad09c73SVivien Didelot 5140fad09c73SVivien Didelot return NULL; 5141fad09c73SVivien Didelot } 5142fad09c73SVivien Didelot 5143fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 5144fad09c73SVivien Didelot { 5145fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 51468f6345b2SVivien Didelot unsigned int prod_num, rev; 51478f6345b2SVivien Didelot u16 id; 51488f6345b2SVivien Didelot int err; 5149fad09c73SVivien Didelot 5150c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5151107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 5152c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 51538f6345b2SVivien Didelot if (err) 51548f6345b2SVivien Didelot return err; 5155fad09c73SVivien Didelot 5156107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 5157107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 5158fad09c73SVivien Didelot 5159fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 5160fad09c73SVivien Didelot if (!info) 5161fad09c73SVivien Didelot return -ENODEV; 5162fad09c73SVivien Didelot 5163fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 5164fad09c73SVivien Didelot chip->info = info; 5165fad09c73SVivien Didelot 5166ca070c10SVivien Didelot err = mv88e6xxx_g2_require(chip); 5167ca070c10SVivien Didelot if (err) 5168ca070c10SVivien Didelot return err; 5169ca070c10SVivien Didelot 5170fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 5171fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 5172fad09c73SVivien Didelot 5173fad09c73SVivien Didelot return 0; 5174fad09c73SVivien Didelot } 5175fad09c73SVivien Didelot 5176fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 5177fad09c73SVivien Didelot { 5178fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5179fad09c73SVivien Didelot 5180fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 5181fad09c73SVivien Didelot if (!chip) 5182fad09c73SVivien Didelot return NULL; 5183fad09c73SVivien Didelot 5184fad09c73SVivien Didelot chip->dev = dev; 5185fad09c73SVivien Didelot 5186fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 5187a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 5188da7dc875SVivien Didelot idr_init(&chip->policies); 5189fad09c73SVivien Didelot 5190fad09c73SVivien Didelot return chip; 5191fad09c73SVivien Didelot } 5192fad09c73SVivien Didelot 51935ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 51944d776482SFlorian Fainelli int port, 51954d776482SFlorian Fainelli enum dsa_tag_protocol m) 51967b314362SAndrew Lunn { 519704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 51982bbb33beSAndrew Lunn 5199443d5a1bSAndrew Lunn return chip->info->tag_protocol; 52007b314362SAndrew Lunn } 52017b314362SAndrew Lunn 52027df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_prepare(struct dsa_switch *ds, int port, 52033709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 52047df8fbddSVivien Didelot { 52057df8fbddSVivien Didelot /* We don't need any dynamic resource from the kernel (yet), 52067df8fbddSVivien Didelot * so skip the prepare phase. 52077df8fbddSVivien Didelot */ 52087df8fbddSVivien Didelot 52097df8fbddSVivien Didelot return 0; 52107df8fbddSVivien Didelot } 52117df8fbddSVivien Didelot 52127df8fbddSVivien Didelot static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 52133709aadcSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 52147df8fbddSVivien Didelot { 521504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 52167df8fbddSVivien Didelot 5217c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 52187df8fbddSVivien Didelot if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 521927c0e600SVivien Didelot MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC)) 5220774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", 5221774439e5SVivien Didelot port); 5222c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 52237df8fbddSVivien Didelot } 52247df8fbddSVivien Didelot 52257df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 52267df8fbddSVivien Didelot const struct switchdev_obj_port_mdb *mdb) 52277df8fbddSVivien Didelot { 522804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 52297df8fbddSVivien Didelot int err; 52307df8fbddSVivien Didelot 5231c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5232d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0); 5233c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 52347df8fbddSVivien Didelot 52357df8fbddSVivien Didelot return err; 52367df8fbddSVivien Didelot } 52377df8fbddSVivien Didelot 5238f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, 5239f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror, 5240f0942e00SIwan R Timmer bool ingress) 5241f0942e00SIwan R Timmer { 5242f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = ingress ? 5243f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5244f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5245f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5246f0942e00SIwan R Timmer bool other_mirrors = false; 5247f0942e00SIwan R Timmer int i; 5248f0942e00SIwan R Timmer int err; 5249f0942e00SIwan R Timmer 5250f0942e00SIwan R Timmer if (!chip->info->ops->set_egress_port) 5251f0942e00SIwan R Timmer return -EOPNOTSUPP; 5252f0942e00SIwan R Timmer 5253f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5254f0942e00SIwan R Timmer if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != 5255f0942e00SIwan R Timmer mirror->to_local_port) { 5256f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5257f0942e00SIwan R Timmer other_mirrors |= ingress ? 5258f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5259f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5260f0942e00SIwan R Timmer 5261f0942e00SIwan R Timmer /* Can't change egress port when other mirror is active */ 5262f0942e00SIwan R Timmer if (other_mirrors) { 5263f0942e00SIwan R Timmer err = -EBUSY; 5264f0942e00SIwan R Timmer goto out; 5265f0942e00SIwan R Timmer } 5266f0942e00SIwan R Timmer 5267f0942e00SIwan R Timmer err = chip->info->ops->set_egress_port(chip, 5268f0942e00SIwan R Timmer direction, 5269f0942e00SIwan R Timmer mirror->to_local_port); 5270f0942e00SIwan R Timmer if (err) 5271f0942e00SIwan R Timmer goto out; 5272f0942e00SIwan R Timmer } 5273f0942e00SIwan R Timmer 5274f0942e00SIwan R Timmer err = mv88e6xxx_port_set_mirror(chip, port, direction, true); 5275f0942e00SIwan R Timmer out: 5276f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5277f0942e00SIwan R Timmer 5278f0942e00SIwan R Timmer return err; 5279f0942e00SIwan R Timmer } 5280f0942e00SIwan R Timmer 5281f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, 5282f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror) 5283f0942e00SIwan R Timmer { 5284f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = mirror->ingress ? 5285f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 5286f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 5287f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 5288f0942e00SIwan R Timmer bool other_mirrors = false; 5289f0942e00SIwan R Timmer int i; 5290f0942e00SIwan R Timmer 5291f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 5292f0942e00SIwan R Timmer if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) 5293f0942e00SIwan R Timmer dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); 5294f0942e00SIwan R Timmer 5295f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 5296f0942e00SIwan R Timmer other_mirrors |= mirror->ingress ? 5297f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 5298f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 5299f0942e00SIwan R Timmer 5300f0942e00SIwan R Timmer /* Reset egress port when no other mirror is active */ 5301f0942e00SIwan R Timmer if (!other_mirrors) { 5302f0942e00SIwan R Timmer if (chip->info->ops->set_egress_port(chip, 5303f0942e00SIwan R Timmer direction, 5304f0942e00SIwan R Timmer dsa_upstream_port(ds, 53054e4637b1SColin Ian King port))) 5306f0942e00SIwan R Timmer dev_err(ds->dev, "failed to set egress port\n"); 5307f0942e00SIwan R Timmer } 5308f0942e00SIwan R Timmer 5309f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 5310f0942e00SIwan R Timmer } 5311f0942e00SIwan R Timmer 53124f85901fSRussell King static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, 53134f85901fSRussell King bool unicast, bool multicast) 53144f85901fSRussell King { 53154f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 53164f85901fSRussell King int err = -EOPNOTSUPP; 53174f85901fSRussell King 5318c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 53194f85901fSRussell King if (chip->info->ops->port_set_egress_floods) 53204f85901fSRussell King err = chip->info->ops->port_set_egress_floods(chip, port, 53214f85901fSRussell King unicast, 53224f85901fSRussell King multicast); 5323c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 53244f85901fSRussell King 53254f85901fSRussell King return err; 53264f85901fSRussell King } 53274f85901fSRussell King 5328a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 53297b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 5330fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 533123e8b470SAndrew Lunn .teardown = mv88e6xxx_teardown, 5332c9a2356fSRussell King .phylink_validate = mv88e6xxx_validate, 5333a5a6858bSRussell King .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, 5334c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 5335a5a6858bSRussell King .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, 5336c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 5337c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 5338fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 5339fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 5340fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 534104aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 534204aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 53432a550aecSAndrew Lunn .port_max_mtu = mv88e6xxx_get_max_mtu, 53442a550aecSAndrew Lunn .port_change_mtu = mv88e6xxx_change_mtu, 534508f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 534608f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 5347fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 5348fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 5349fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 5350fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 5351fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 5352da7dc875SVivien Didelot .get_rxnfc = mv88e6xxx_get_rxnfc, 5353da7dc875SVivien Didelot .set_rxnfc = mv88e6xxx_set_rxnfc, 53542cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 5355fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 5356fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 53574f85901fSRussell King .port_egress_floods = mv88e6xxx_port_egress_floods, 5358fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 5359749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 5360fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 5361fad09c73SVivien Didelot .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, 5362fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 5363fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 5364fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 5365fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 5366fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 53677df8fbddSVivien Didelot .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, 53687df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 53697df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 5370f0942e00SIwan R Timmer .port_mirror_add = mv88e6xxx_port_mirror_add, 5371f0942e00SIwan R Timmer .port_mirror_del = mv88e6xxx_port_mirror_del, 5372aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 5373aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 5374c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 5375c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 5376c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 5377c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 5378c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 537923e8b470SAndrew Lunn .devlink_param_get = mv88e6xxx_devlink_param_get, 538023e8b470SAndrew Lunn .devlink_param_set = mv88e6xxx_devlink_param_set, 5381fad09c73SVivien Didelot }; 5382fad09c73SVivien Didelot 538355ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 5384fad09c73SVivien Didelot { 5385fad09c73SVivien Didelot struct device *dev = chip->dev; 5386fad09c73SVivien Didelot struct dsa_switch *ds; 5387fad09c73SVivien Didelot 53887e99e347SVivien Didelot ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); 5389fad09c73SVivien Didelot if (!ds) 5390fad09c73SVivien Didelot return -ENOMEM; 5391fad09c73SVivien Didelot 53927e99e347SVivien Didelot ds->dev = dev; 53937e99e347SVivien Didelot ds->num_ports = mv88e6xxx_num_ports(chip); 5394fad09c73SVivien Didelot ds->priv = chip; 5395877b7cb0SAndrew Lunn ds->dev = dev; 53969d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 53979ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 53989ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 5399fad09c73SVivien Didelot 5400fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 5401fad09c73SVivien Didelot 540223c9ee49SVivien Didelot return dsa_register_switch(ds); 5403fad09c73SVivien Didelot } 5404fad09c73SVivien Didelot 5405fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 5406fad09c73SVivien Didelot { 5407fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 5408fad09c73SVivien Didelot } 5409fad09c73SVivien Didelot 5410877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 5411877b7cb0SAndrew Lunn { 5412877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 5413877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 5414877b7cb0SAndrew Lunn 5415877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 5416877b7cb0SAndrew Lunn matches++) { 5417877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 5418877b7cb0SAndrew Lunn return matches->data; 5419877b7cb0SAndrew Lunn } 5420877b7cb0SAndrew Lunn return NULL; 5421877b7cb0SAndrew Lunn } 5422877b7cb0SAndrew Lunn 5423bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 5424bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 5425bcd3d9d9SMiquel Raynal */ 5426bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 5427bcd3d9d9SMiquel Raynal { 5428bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 5429bcd3d9d9SMiquel Raynal } 5430bcd3d9d9SMiquel Raynal 5431bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 5432bcd3d9d9SMiquel Raynal { 5433bcd3d9d9SMiquel Raynal return 0; 5434bcd3d9d9SMiquel Raynal } 5435bcd3d9d9SMiquel Raynal 5436bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 5437bcd3d9d9SMiquel Raynal 5438fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 5439fad09c73SVivien Didelot { 5440877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 54417ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 5442fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 5443fad09c73SVivien Didelot struct device_node *np = dev->of_node; 5444fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 5445877b7cb0SAndrew Lunn int port; 5446fad09c73SVivien Didelot int err; 5447fad09c73SVivien Didelot 54487bb8c996SAndrew Lunn if (!np && !pdata) 54497bb8c996SAndrew Lunn return -EINVAL; 54507bb8c996SAndrew Lunn 5451877b7cb0SAndrew Lunn if (np) 5452fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 5453877b7cb0SAndrew Lunn 5454877b7cb0SAndrew Lunn if (pdata) { 5455877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 5456877b7cb0SAndrew Lunn 5457877b7cb0SAndrew Lunn if (!pdata->netdev) 5458877b7cb0SAndrew Lunn return -EINVAL; 5459877b7cb0SAndrew Lunn 5460877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 5461877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 5462877b7cb0SAndrew Lunn continue; 5463877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 5464877b7cb0SAndrew Lunn continue; 5465877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 5466877b7cb0SAndrew Lunn break; 5467877b7cb0SAndrew Lunn } 5468877b7cb0SAndrew Lunn } 5469877b7cb0SAndrew Lunn 5470fad09c73SVivien Didelot if (!compat_info) 5471fad09c73SVivien Didelot return -EINVAL; 5472fad09c73SVivien Didelot 5473fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 5474877b7cb0SAndrew Lunn if (!chip) { 5475877b7cb0SAndrew Lunn err = -ENOMEM; 5476877b7cb0SAndrew Lunn goto out; 5477877b7cb0SAndrew Lunn } 5478fad09c73SVivien Didelot 5479fad09c73SVivien Didelot chip->info = compat_info; 5480fad09c73SVivien Didelot 5481fad09c73SVivien Didelot err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 5482fad09c73SVivien Didelot if (err) 5483877b7cb0SAndrew Lunn goto out; 5484fad09c73SVivien Didelot 5485b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 5486877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 5487877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 5488877b7cb0SAndrew Lunn goto out; 5489877b7cb0SAndrew Lunn } 54907b75e49dSBaruch Siach if (chip->reset) 54917b75e49dSBaruch Siach usleep_range(1000, 2000); 5492b4308f04SAndrew Lunn 5493fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 5494fad09c73SVivien Didelot if (err) 5495877b7cb0SAndrew Lunn goto out; 5496fad09c73SVivien Didelot 5497e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 5498e57e5e77SVivien Didelot 549900baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 550000baabe5SAndrew Lunn if (np) 550100baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 550200baabe5SAndrew Lunn &chip->eeprom_len); 550300baabe5SAndrew Lunn else 550400baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 550500baabe5SAndrew Lunn } 5506fad09c73SVivien Didelot 5507c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5508dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 5509c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5510fad09c73SVivien Didelot if (err) 5511dc30c35bSAndrew Lunn goto out; 5512fad09c73SVivien Didelot 5513a27415deSAndrew Lunn if (np) { 5514dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 5515dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 5516dc30c35bSAndrew Lunn err = chip->irq; 5517dc30c35bSAndrew Lunn goto out; 5518fad09c73SVivien Didelot } 5519a27415deSAndrew Lunn } 5520a27415deSAndrew Lunn 5521a27415deSAndrew Lunn if (pdata) 5522a27415deSAndrew Lunn chip->irq = pdata->irq; 5523fad09c73SVivien Didelot 5524294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 5525a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 5526294d711eSAndrew Lunn * controllers 5527dc30c35bSAndrew Lunn */ 5528c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 5529294d711eSAndrew Lunn if (chip->irq > 0) 5530dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 5531294d711eSAndrew Lunn else 5532294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 5533c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 5534dc30c35bSAndrew Lunn 5535dc30c35bSAndrew Lunn if (err) 5536dc30c35bSAndrew Lunn goto out; 5537dc30c35bSAndrew Lunn 5538d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 5539dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 5540dc30c35bSAndrew Lunn if (err) 5541dc30c35bSAndrew Lunn goto out_g1_irq; 5542dc30c35bSAndrew Lunn } 55430977644cSAndrew Lunn 55440977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 55450977644cSAndrew Lunn if (err) 55460977644cSAndrew Lunn goto out_g2_irq; 554762eb1162SAndrew Lunn 554862eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 554962eb1162SAndrew Lunn if (err) 555062eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 5551dc30c35bSAndrew Lunn 5552a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 5553dc30c35bSAndrew Lunn if (err) 555462eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 5555dc30c35bSAndrew Lunn 555655ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 5557dc30c35bSAndrew Lunn if (err) 5558dc30c35bSAndrew Lunn goto out_mdio; 5559dc30c35bSAndrew Lunn 5560fad09c73SVivien Didelot return 0; 5561dc30c35bSAndrew Lunn 5562dc30c35bSAndrew Lunn out_mdio: 5563a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 556462eb1162SAndrew Lunn out_g1_vtu_prob_irq: 556562eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 55660977644cSAndrew Lunn out_g1_atu_prob_irq: 55670977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 5568dc30c35bSAndrew Lunn out_g2_irq: 5569294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 5570dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 5571dc30c35bSAndrew Lunn out_g1_irq: 5572294d711eSAndrew Lunn if (chip->irq > 0) 5573dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 5574294d711eSAndrew Lunn else 5575294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5576dc30c35bSAndrew Lunn out: 5577877b7cb0SAndrew Lunn if (pdata) 5578877b7cb0SAndrew Lunn dev_put(pdata->netdev); 5579877b7cb0SAndrew Lunn 5580dc30c35bSAndrew Lunn return err; 5581fad09c73SVivien Didelot } 5582fad09c73SVivien Didelot 5583fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 5584fad09c73SVivien Didelot { 5585fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 558604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 5587fad09c73SVivien Didelot 5588c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 5589c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 55902fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 5591c6fe0ad2SBrandon Streiff } 55922fa8d3afSBrandon Streiff 5593930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 5594fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 5595a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 5596dc30c35bSAndrew Lunn 559762eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 55980977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 559976f38f1fSAndrew Lunn 5600d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 5601dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 560276f38f1fSAndrew Lunn 560376f38f1fSAndrew Lunn if (chip->irq > 0) 5604dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 560576f38f1fSAndrew Lunn else 560676f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 5607fad09c73SVivien Didelot } 5608fad09c73SVivien Didelot 5609fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 5610fad09c73SVivien Didelot { 5611fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 5612fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 5613fad09c73SVivien Didelot }, 56141a3b39ecSAndrew Lunn { 56151a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 56161a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 56171a3b39ecSAndrew Lunn }, 56181f71836fSRasmus Villemoes { 56191f71836fSRasmus Villemoes .compatible = "marvell,mv88e6250", 56201f71836fSRasmus Villemoes .data = &mv88e6xxx_table[MV88E6250], 56211f71836fSRasmus Villemoes }, 5622fad09c73SVivien Didelot { /* sentinel */ }, 5623fad09c73SVivien Didelot }; 5624fad09c73SVivien Didelot 5625fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 5626fad09c73SVivien Didelot 5627fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 5628fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 5629fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 5630fad09c73SVivien Didelot .mdiodrv.driver = { 5631fad09c73SVivien Didelot .name = "mv88e6085", 5632fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 5633bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 5634fad09c73SVivien Didelot }, 5635fad09c73SVivien Didelot }; 5636fad09c73SVivien Didelot 56377324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver); 5638fad09c73SVivien Didelot 5639fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 5640fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 5641fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 5642