12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2fad09c73SVivien Didelot /* 3fad09c73SVivien Didelot * Marvell 88e6xxx Ethernet switch single-chip support 4fad09c73SVivien Didelot * 5fad09c73SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 6fad09c73SVivien Didelot * 7fad09c73SVivien Didelot * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 8fad09c73SVivien Didelot * 94333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 104333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 11fad09c73SVivien Didelot */ 12fad09c73SVivien Didelot 1319fb7f69SVivien Didelot #include <linux/bitfield.h> 14fad09c73SVivien Didelot #include <linux/delay.h> 155bded825SVladimir Oltean #include <linux/dsa/mv88e6xxx.h> 16fad09c73SVivien Didelot #include <linux/etherdevice.h> 17fad09c73SVivien Didelot #include <linux/ethtool.h> 18fad09c73SVivien Didelot #include <linux/if_bridge.h> 19dc30c35bSAndrew Lunn #include <linux/interrupt.h> 20dc30c35bSAndrew Lunn #include <linux/irq.h> 21dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 22fad09c73SVivien Didelot #include <linux/jiffies.h> 23fad09c73SVivien Didelot #include <linux/list.h> 24fad09c73SVivien Didelot #include <linux/mdio.h> 25fad09c73SVivien Didelot #include <linux/module.h> 26fad09c73SVivien Didelot #include <linux/of_device.h> 27dc30c35bSAndrew Lunn #include <linux/of_irq.h> 28fad09c73SVivien Didelot #include <linux/of_mdio.h> 29877b7cb0SAndrew Lunn #include <linux/platform_data/mv88e6xxx.h> 30fad09c73SVivien Didelot #include <linux/netdevice.h> 31fad09c73SVivien Didelot #include <linux/gpio/consumer.h> 32c9a2356fSRussell King #include <linux/phylink.h> 33fad09c73SVivien Didelot #include <net/dsa.h> 34ec561276SVivien Didelot 354d5f2ba7SVivien Didelot #include "chip.h" 369dd43aa2SAndrew Lunn #include "devlink.h" 37a935c052SVivien Didelot #include "global1.h" 38ec561276SVivien Didelot #include "global2.h" 39c6fe0ad2SBrandon Streiff #include "hwtstamp.h" 4010fa5bfcSAndrew Lunn #include "phy.h" 4118abed21SVivien Didelot #include "port.h" 422fa8d3afSBrandon Streiff #include "ptp.h" 436d91782fSAndrew Lunn #include "serdes.h" 44e7ba0fadSVivien Didelot #include "smi.h" 45fad09c73SVivien Didelot 46fad09c73SVivien Didelot static void assert_reg_lock(struct mv88e6xxx_chip *chip) 47fad09c73SVivien Didelot { 48fad09c73SVivien Didelot if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 49fad09c73SVivien Didelot dev_err(chip->dev, "Switch registers lock not held!\n"); 50fad09c73SVivien Didelot dump_stack(); 51fad09c73SVivien Didelot } 52fad09c73SVivien Didelot } 53fad09c73SVivien Didelot 54ec561276SVivien Didelot int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 55fad09c73SVivien Didelot { 56fad09c73SVivien Didelot int err; 57fad09c73SVivien Didelot 58fad09c73SVivien Didelot assert_reg_lock(chip); 59fad09c73SVivien Didelot 60fad09c73SVivien Didelot err = mv88e6xxx_smi_read(chip, addr, reg, val); 61fad09c73SVivien Didelot if (err) 62fad09c73SVivien Didelot return err; 63fad09c73SVivien Didelot 64fad09c73SVivien Didelot dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 65fad09c73SVivien Didelot addr, reg, *val); 66fad09c73SVivien Didelot 67fad09c73SVivien Didelot return 0; 68fad09c73SVivien Didelot } 69fad09c73SVivien Didelot 70ec561276SVivien Didelot int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 71fad09c73SVivien Didelot { 72fad09c73SVivien Didelot int err; 73fad09c73SVivien Didelot 74fad09c73SVivien Didelot assert_reg_lock(chip); 75fad09c73SVivien Didelot 76fad09c73SVivien Didelot err = mv88e6xxx_smi_write(chip, addr, reg, val); 77fad09c73SVivien Didelot if (err) 78fad09c73SVivien Didelot return err; 79fad09c73SVivien Didelot 80fad09c73SVivien Didelot dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 81fad09c73SVivien Didelot addr, reg, val); 82fad09c73SVivien Didelot 83fad09c73SVivien Didelot return 0; 84fad09c73SVivien Didelot } 85fad09c73SVivien Didelot 86683f2244SVivien Didelot int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, 87683f2244SVivien Didelot u16 mask, u16 val) 88683f2244SVivien Didelot { 8935da1dfdSTobias Waldekranz const unsigned long timeout = jiffies + msecs_to_jiffies(50); 90683f2244SVivien Didelot u16 data; 91683f2244SVivien Didelot int err; 92683f2244SVivien Didelot int i; 93683f2244SVivien Didelot 9435da1dfdSTobias Waldekranz /* There's no bus specific operation to wait for a mask. Even 9535da1dfdSTobias Waldekranz * if the initial poll takes longer than 50ms, always do at 9635da1dfdSTobias Waldekranz * least one more attempt. 9735da1dfdSTobias Waldekranz */ 9835da1dfdSTobias Waldekranz for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) { 99683f2244SVivien Didelot err = mv88e6xxx_read(chip, addr, reg, &data); 100683f2244SVivien Didelot if (err) 101683f2244SVivien Didelot return err; 102683f2244SVivien Didelot 103683f2244SVivien Didelot if ((data & mask) == val) 104683f2244SVivien Didelot return 0; 105683f2244SVivien Didelot 10635da1dfdSTobias Waldekranz if (i < 2) 10735da1dfdSTobias Waldekranz cpu_relax(); 10835da1dfdSTobias Waldekranz else 109683f2244SVivien Didelot usleep_range(1000, 2000); 110683f2244SVivien Didelot } 111683f2244SVivien Didelot 112683f2244SVivien Didelot dev_err(chip->dev, "Timeout while waiting for switch\n"); 113683f2244SVivien Didelot return -ETIMEDOUT; 114683f2244SVivien Didelot } 115683f2244SVivien Didelot 11619fb7f69SVivien Didelot int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, 11719fb7f69SVivien Didelot int bit, int val) 11819fb7f69SVivien Didelot { 11919fb7f69SVivien Didelot return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit), 12019fb7f69SVivien Didelot val ? BIT(bit) : 0x0000); 12119fb7f69SVivien Didelot } 12219fb7f69SVivien Didelot 12310fa5bfcSAndrew Lunn struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 124a3c53be5SAndrew Lunn { 125a3c53be5SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 126a3c53be5SAndrew Lunn 127a3c53be5SAndrew Lunn mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 128a3c53be5SAndrew Lunn list); 129a3c53be5SAndrew Lunn if (!mdio_bus) 130a3c53be5SAndrew Lunn return NULL; 131a3c53be5SAndrew Lunn 132a3c53be5SAndrew Lunn return mdio_bus->bus; 133a3c53be5SAndrew Lunn } 134a3c53be5SAndrew Lunn 135dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_mask(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 143dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 144dc30c35bSAndrew Lunn { 145dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 146dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 147dc30c35bSAndrew Lunn 148dc30c35bSAndrew Lunn chip->g1_irq.masked &= ~(1 << n); 149dc30c35bSAndrew Lunn } 150dc30c35bSAndrew Lunn 151294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 152dc30c35bSAndrew Lunn { 153dc30c35bSAndrew Lunn unsigned int nhandled = 0; 154dc30c35bSAndrew Lunn unsigned int sub_irq; 155dc30c35bSAndrew Lunn unsigned int n; 156dc30c35bSAndrew Lunn u16 reg; 1577c0db24cSJohn David Anglin u16 ctl1; 158dc30c35bSAndrew Lunn int err; 159dc30c35bSAndrew Lunn 160c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 16182466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 162c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 163dc30c35bSAndrew Lunn 164dc30c35bSAndrew Lunn if (err) 165dc30c35bSAndrew Lunn goto out; 166dc30c35bSAndrew Lunn 1677c0db24cSJohn David Anglin do { 168dc30c35bSAndrew Lunn for (n = 0; n < chip->g1_irq.nirqs; ++n) { 169dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1707c0db24cSJohn David Anglin sub_irq = irq_find_mapping(chip->g1_irq.domain, 1717c0db24cSJohn David Anglin n); 172dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 173dc30c35bSAndrew Lunn ++nhandled; 174dc30c35bSAndrew Lunn } 175dc30c35bSAndrew Lunn } 1767c0db24cSJohn David Anglin 177c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1787c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 1797c0db24cSJohn David Anglin if (err) 1807c0db24cSJohn David Anglin goto unlock; 1817c0db24cSJohn David Anglin err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 1827c0db24cSJohn David Anglin unlock: 183c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1847c0db24cSJohn David Anglin if (err) 1857c0db24cSJohn David Anglin goto out; 1867c0db24cSJohn David Anglin ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 1877c0db24cSJohn David Anglin } while (reg & ctl1); 1887c0db24cSJohn David Anglin 189dc30c35bSAndrew Lunn out: 190dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 191dc30c35bSAndrew Lunn } 192dc30c35bSAndrew Lunn 193294d711eSAndrew Lunn static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 194294d711eSAndrew Lunn { 195294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 196294d711eSAndrew Lunn 197294d711eSAndrew Lunn return mv88e6xxx_g1_irq_thread_work(chip); 198294d711eSAndrew Lunn } 199294d711eSAndrew Lunn 200dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 201dc30c35bSAndrew Lunn { 202dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 203dc30c35bSAndrew Lunn 204c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 205dc30c35bSAndrew Lunn } 206dc30c35bSAndrew Lunn 207dc30c35bSAndrew Lunn static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 208dc30c35bSAndrew Lunn { 209dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 210dc30c35bSAndrew Lunn u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 211dc30c35bSAndrew Lunn u16 reg; 212dc30c35bSAndrew Lunn int err; 213dc30c35bSAndrew Lunn 214d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 215dc30c35bSAndrew Lunn if (err) 216dc30c35bSAndrew Lunn goto out; 217dc30c35bSAndrew Lunn 218dc30c35bSAndrew Lunn reg &= ~mask; 219dc30c35bSAndrew Lunn reg |= (~chip->g1_irq.masked & mask); 220dc30c35bSAndrew Lunn 221d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 222dc30c35bSAndrew Lunn if (err) 223dc30c35bSAndrew Lunn goto out; 224dc30c35bSAndrew Lunn 225dc30c35bSAndrew Lunn out: 226c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 227dc30c35bSAndrew Lunn } 228dc30c35bSAndrew Lunn 2296eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g1_irq_chip = { 230dc30c35bSAndrew Lunn .name = "mv88e6xxx-g1", 231dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g1_irq_mask, 232dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g1_irq_unmask, 233dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 234dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 235dc30c35bSAndrew Lunn }; 236dc30c35bSAndrew Lunn 237dc30c35bSAndrew Lunn static int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 238dc30c35bSAndrew Lunn unsigned int irq, 239dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 240dc30c35bSAndrew Lunn { 241dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 242dc30c35bSAndrew Lunn 243dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 244dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 245dc30c35bSAndrew Lunn irq_set_noprobe(irq); 246dc30c35bSAndrew Lunn 247dc30c35bSAndrew Lunn return 0; 248dc30c35bSAndrew Lunn } 249dc30c35bSAndrew Lunn 250dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 251dc30c35bSAndrew Lunn .map = mv88e6xxx_g1_irq_domain_map, 252dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 253dc30c35bSAndrew Lunn }; 254dc30c35bSAndrew Lunn 2553d82475aSUwe Kleine-König /* To be called with reg_lock held */ 256294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 257dc30c35bSAndrew Lunn { 258dc30c35bSAndrew Lunn int irq, virq; 2593460a577SAndrew Lunn u16 mask; 2603460a577SAndrew Lunn 261d77f4321SVivien Didelot mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 2623d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 263d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 2643460a577SAndrew Lunn 2655edef2f2SAndreas Färber for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 266a3db3d3aSAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 267dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 268dc30c35bSAndrew Lunn } 269dc30c35bSAndrew Lunn 270a3db3d3aSAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 271dc30c35bSAndrew Lunn } 272dc30c35bSAndrew Lunn 273294d711eSAndrew Lunn static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 274294d711eSAndrew Lunn { 2753d82475aSUwe Kleine-König /* 2763d82475aSUwe Kleine-König * free_irq must be called without reg_lock taken because the irq 2773d82475aSUwe Kleine-König * handler takes this lock, too. 2783d82475aSUwe Kleine-König */ 279294d711eSAndrew Lunn free_irq(chip->irq, chip); 2803d82475aSUwe Kleine-König 281c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2823d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 283c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 284294d711eSAndrew Lunn } 285294d711eSAndrew Lunn 286294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 287dc30c35bSAndrew Lunn { 2883dd0ef05SAndrew Lunn int err, irq, virq; 2893dd0ef05SAndrew Lunn u16 reg, mask; 290dc30c35bSAndrew Lunn 291dc30c35bSAndrew Lunn chip->g1_irq.nirqs = chip->info->g1_irqs; 292dc30c35bSAndrew Lunn chip->g1_irq.domain = irq_domain_add_simple( 293dc30c35bSAndrew Lunn NULL, chip->g1_irq.nirqs, 0, 294dc30c35bSAndrew Lunn &mv88e6xxx_g1_irq_domain_ops, chip); 295dc30c35bSAndrew Lunn if (!chip->g1_irq.domain) 296dc30c35bSAndrew Lunn return -ENOMEM; 297dc30c35bSAndrew Lunn 298dc30c35bSAndrew Lunn for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 299dc30c35bSAndrew Lunn irq_create_mapping(chip->g1_irq.domain, irq); 300dc30c35bSAndrew Lunn 301dc30c35bSAndrew Lunn chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 302dc30c35bSAndrew Lunn chip->g1_irq.masked = ~0; 303dc30c35bSAndrew Lunn 304d77f4321SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 305dc30c35bSAndrew Lunn if (err) 3063dd0ef05SAndrew Lunn goto out_mapping; 307dc30c35bSAndrew Lunn 3083dd0ef05SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 309dc30c35bSAndrew Lunn 310d77f4321SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 311dc30c35bSAndrew Lunn if (err) 3123dd0ef05SAndrew Lunn goto out_disable; 313dc30c35bSAndrew Lunn 314dc30c35bSAndrew Lunn /* Reading the interrupt status clears (most of) them */ 31582466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 316dc30c35bSAndrew Lunn if (err) 3173dd0ef05SAndrew Lunn goto out_disable; 318dc30c35bSAndrew Lunn 319dc30c35bSAndrew Lunn return 0; 320dc30c35bSAndrew Lunn 3213dd0ef05SAndrew Lunn out_disable: 3223d5fdba1SAndrew Lunn mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 323d77f4321SVivien Didelot mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 3243dd0ef05SAndrew Lunn 3253dd0ef05SAndrew Lunn out_mapping: 3263dd0ef05SAndrew Lunn for (irq = 0; irq < 16; irq++) { 3273dd0ef05SAndrew Lunn virq = irq_find_mapping(chip->g1_irq.domain, irq); 3283dd0ef05SAndrew Lunn irq_dispose_mapping(virq); 3293dd0ef05SAndrew Lunn } 3303dd0ef05SAndrew Lunn 3313dd0ef05SAndrew Lunn irq_domain_remove(chip->g1_irq.domain); 332dc30c35bSAndrew Lunn 333dc30c35bSAndrew Lunn return err; 334dc30c35bSAndrew Lunn } 335dc30c35bSAndrew Lunn 336294d711eSAndrew Lunn static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 337294d711eSAndrew Lunn { 338f6d9758bSAndrew Lunn static struct lock_class_key lock_key; 339f6d9758bSAndrew Lunn static struct lock_class_key request_key; 340294d711eSAndrew Lunn int err; 341294d711eSAndrew Lunn 342294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 343294d711eSAndrew Lunn if (err) 344294d711eSAndrew Lunn return err; 345294d711eSAndrew Lunn 346f6d9758bSAndrew Lunn /* These lock classes tells lockdep that global 1 irqs are in 347f6d9758bSAndrew Lunn * a different category than their parent GPIO, so it won't 348f6d9758bSAndrew Lunn * report false recursion. 349f6d9758bSAndrew Lunn */ 350f6d9758bSAndrew Lunn irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 351f6d9758bSAndrew Lunn 3523095383aSAndrew Lunn snprintf(chip->irq_name, sizeof(chip->irq_name), 3533095383aSAndrew Lunn "mv88e6xxx-%s", dev_name(chip->dev)); 3543095383aSAndrew Lunn 355c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 356294d711eSAndrew Lunn err = request_threaded_irq(chip->irq, NULL, 357294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_fn, 3580340376eSMarek Behún IRQF_ONESHOT | IRQF_SHARED, 3593095383aSAndrew Lunn chip->irq_name, chip); 360c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 361294d711eSAndrew Lunn if (err) 362294d711eSAndrew Lunn mv88e6xxx_g1_irq_free_common(chip); 363294d711eSAndrew Lunn 364294d711eSAndrew Lunn return err; 365294d711eSAndrew Lunn } 366294d711eSAndrew Lunn 367294d711eSAndrew Lunn static void mv88e6xxx_irq_poll(struct kthread_work *work) 368294d711eSAndrew Lunn { 369294d711eSAndrew Lunn struct mv88e6xxx_chip *chip = container_of(work, 370294d711eSAndrew Lunn struct mv88e6xxx_chip, 371294d711eSAndrew Lunn irq_poll_work.work); 372294d711eSAndrew Lunn mv88e6xxx_g1_irq_thread_work(chip); 373294d711eSAndrew Lunn 374294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 375294d711eSAndrew Lunn msecs_to_jiffies(100)); 376294d711eSAndrew Lunn } 377294d711eSAndrew Lunn 378294d711eSAndrew Lunn static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 379294d711eSAndrew Lunn { 380294d711eSAndrew Lunn int err; 381294d711eSAndrew Lunn 382294d711eSAndrew Lunn err = mv88e6xxx_g1_irq_setup_common(chip); 383294d711eSAndrew Lunn if (err) 384294d711eSAndrew Lunn return err; 385294d711eSAndrew Lunn 386294d711eSAndrew Lunn kthread_init_delayed_work(&chip->irq_poll_work, 387294d711eSAndrew Lunn mv88e6xxx_irq_poll); 388294d711eSAndrew Lunn 3893f8b8696SFlorian Fainelli chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 390294d711eSAndrew Lunn if (IS_ERR(chip->kworker)) 391294d711eSAndrew Lunn return PTR_ERR(chip->kworker); 392294d711eSAndrew Lunn 393294d711eSAndrew Lunn kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 394294d711eSAndrew Lunn msecs_to_jiffies(100)); 395294d711eSAndrew Lunn 396294d711eSAndrew Lunn return 0; 397294d711eSAndrew Lunn } 398294d711eSAndrew Lunn 399294d711eSAndrew Lunn static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 400294d711eSAndrew Lunn { 401294d711eSAndrew Lunn kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 402294d711eSAndrew Lunn kthread_destroy_worker(chip->kworker); 4033d82475aSUwe Kleine-König 404c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 4053d82475aSUwe Kleine-König mv88e6xxx_g1_irq_free_common(chip); 406c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 407294d711eSAndrew Lunn } 408294d711eSAndrew Lunn 40964d47d50SRussell King static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, 41064d47d50SRussell King int port, phy_interface_t interface) 41164d47d50SRussell King { 41264d47d50SRussell King int err; 41364d47d50SRussell King 41464d47d50SRussell King if (chip->info->ops->port_set_rgmii_delay) { 41564d47d50SRussell King err = chip->info->ops->port_set_rgmii_delay(chip, port, 41664d47d50SRussell King interface); 41764d47d50SRussell King if (err && err != -EOPNOTSUPP) 41864d47d50SRussell King return err; 41964d47d50SRussell King } 42064d47d50SRussell King 42164d47d50SRussell King if (chip->info->ops->port_set_cmode) { 42264d47d50SRussell King err = chip->info->ops->port_set_cmode(chip, port, 42364d47d50SRussell King interface); 42464d47d50SRussell King if (err && err != -EOPNOTSUPP) 42564d47d50SRussell King return err; 42664d47d50SRussell King } 42764d47d50SRussell King 42864d47d50SRussell King return 0; 42964d47d50SRussell King } 43064d47d50SRussell King 431a5a6858bSRussell King static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, 432a5a6858bSRussell King int link, int speed, int duplex, int pause, 433d78343d2SVivien Didelot phy_interface_t mode) 434d78343d2SVivien Didelot { 435d78343d2SVivien Didelot int err; 436d78343d2SVivien Didelot 437d78343d2SVivien Didelot if (!chip->info->ops->port_set_link) 438d78343d2SVivien Didelot return 0; 439d78343d2SVivien Didelot 440d78343d2SVivien Didelot /* Port's MAC control must not be changed unless the link is down */ 44143c8e0aeSHubert Feurstein err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 442d78343d2SVivien Didelot if (err) 443d78343d2SVivien Didelot return err; 444d78343d2SVivien Didelot 445f365c6f7SRussell King if (chip->info->ops->port_set_speed_duplex) { 446f365c6f7SRussell King err = chip->info->ops->port_set_speed_duplex(chip, port, 447f365c6f7SRussell King speed, duplex); 448d78343d2SVivien Didelot if (err && err != -EOPNOTSUPP) 449d78343d2SVivien Didelot goto restore_link; 450d78343d2SVivien Didelot } 451d78343d2SVivien Didelot 4527cbbee05SAndrew Lunn if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode) 4537cbbee05SAndrew Lunn mode = chip->info->ops->port_max_speed_mode(port); 4547cbbee05SAndrew Lunn 45554186b91SAndrew Lunn if (chip->info->ops->port_set_pause) { 45654186b91SAndrew Lunn err = chip->info->ops->port_set_pause(chip, port, pause); 45754186b91SAndrew Lunn if (err) 45854186b91SAndrew Lunn goto restore_link; 45954186b91SAndrew Lunn } 46054186b91SAndrew Lunn 46164d47d50SRussell King err = mv88e6xxx_port_config_interface(chip, port, mode); 462d78343d2SVivien Didelot restore_link: 463d78343d2SVivien Didelot if (chip->info->ops->port_set_link(chip, port, link)) 464774439e5SVivien Didelot dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 465d78343d2SVivien Didelot 466d78343d2SVivien Didelot return err; 467d78343d2SVivien Didelot } 468d78343d2SVivien Didelot 469d700ec41SMarek Vasut static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) 470d700ec41SMarek Vasut { 471d700ec41SMarek Vasut struct mv88e6xxx_chip *chip = ds->priv; 472d700ec41SMarek Vasut 473d700ec41SMarek Vasut return port < chip->info->num_internal_phys; 474d700ec41SMarek Vasut } 475d700ec41SMarek Vasut 4765d5b231dSRussell King static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) 4775d5b231dSRussell King { 4785d5b231dSRussell King u16 reg; 4795d5b231dSRussell King int err; 4805d5b231dSRussell King 4812b29cb9eSRussell King (Oracle) /* The 88e6250 family does not have the PHY detect bit. Instead, 4822b29cb9eSRussell King (Oracle) * report whether the port is internal. 4832b29cb9eSRussell King (Oracle) */ 4842b29cb9eSRussell King (Oracle) if (chip->info->family == MV88E6XXX_FAMILY_6250) 4852b29cb9eSRussell King (Oracle) return port < chip->info->num_internal_phys; 4862b29cb9eSRussell King (Oracle) 4875d5b231dSRussell King err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4885d5b231dSRussell King if (err) { 4895d5b231dSRussell King dev_err(chip->dev, 4905d5b231dSRussell King "p%d: %s: failed to read port status\n", 4915d5b231dSRussell King port, __func__); 4925d5b231dSRussell King return err; 4935d5b231dSRussell King } 4945d5b231dSRussell King 4955d5b231dSRussell King return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT); 4965d5b231dSRussell King } 4975d5b231dSRussell King 498a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, 499a5a6858bSRussell King struct phylink_link_state *state) 500a5a6858bSRussell King { 501a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 502193c5b26SPavana Sharma int lane; 503a5a6858bSRussell King int err; 504a5a6858bSRussell King 505a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 506a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 507193c5b26SPavana Sharma if (lane >= 0 && chip->info->ops->serdes_pcs_get_state) 508a5a6858bSRussell King err = chip->info->ops->serdes_pcs_get_state(chip, port, lane, 509a5a6858bSRussell King state); 510a5a6858bSRussell King else 511a5a6858bSRussell King err = -EOPNOTSUPP; 512a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 513a5a6858bSRussell King 514a5a6858bSRussell King return err; 515a5a6858bSRussell King } 516a5a6858bSRussell King 517a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, 518a5a6858bSRussell King unsigned int mode, 519a5a6858bSRussell King phy_interface_t interface, 520a5a6858bSRussell King const unsigned long *advertise) 521a5a6858bSRussell King { 522a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 523193c5b26SPavana Sharma int lane; 524a5a6858bSRussell King 525a5a6858bSRussell King if (ops->serdes_pcs_config) { 526a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 527193c5b26SPavana Sharma if (lane >= 0) 528a5a6858bSRussell King return ops->serdes_pcs_config(chip, port, lane, mode, 529a5a6858bSRussell King interface, advertise); 530a5a6858bSRussell King } 531a5a6858bSRussell King 532a5a6858bSRussell King return 0; 533a5a6858bSRussell King } 534a5a6858bSRussell King 535a5a6858bSRussell King static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port) 536a5a6858bSRussell King { 537a5a6858bSRussell King struct mv88e6xxx_chip *chip = ds->priv; 538a5a6858bSRussell King const struct mv88e6xxx_ops *ops; 539a5a6858bSRussell King int err = 0; 540193c5b26SPavana Sharma int lane; 541a5a6858bSRussell King 542a5a6858bSRussell King ops = chip->info->ops; 543a5a6858bSRussell King 544a5a6858bSRussell King if (ops->serdes_pcs_an_restart) { 545a5a6858bSRussell King mv88e6xxx_reg_lock(chip); 546a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 547193c5b26SPavana Sharma if (lane >= 0) 548a5a6858bSRussell King err = ops->serdes_pcs_an_restart(chip, port, lane); 549a5a6858bSRussell King mv88e6xxx_reg_unlock(chip); 550a5a6858bSRussell King 551a5a6858bSRussell King if (err) 552a5a6858bSRussell King dev_err(ds->dev, "p%d: failed to restart AN\n", port); 553a5a6858bSRussell King } 554a5a6858bSRussell King } 555a5a6858bSRussell King 556a5a6858bSRussell King static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, 557a5a6858bSRussell King unsigned int mode, 558a5a6858bSRussell King int speed, int duplex) 559a5a6858bSRussell King { 560a5a6858bSRussell King const struct mv88e6xxx_ops *ops = chip->info->ops; 561193c5b26SPavana Sharma int lane; 562a5a6858bSRussell King 563a5a6858bSRussell King if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) { 564a5a6858bSRussell King lane = mv88e6xxx_serdes_get_lane(chip, port); 565193c5b26SPavana Sharma if (lane >= 0) 566a5a6858bSRussell King return ops->serdes_pcs_link_up(chip, port, lane, 567a5a6858bSRussell King speed, duplex); 568a5a6858bSRussell King } 569a5a6858bSRussell King 570a5a6858bSRussell King return 0; 571a5a6858bSRussell King } 572a5a6858bSRussell King 573d4ebf12bSRussell King (Oracle) static const u8 mv88e6185_phy_interface_modes[] = { 574d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_GMII_FD] = PHY_INTERFACE_MODE_GMII, 575d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII, 576d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_MII_100] = PHY_INTERFACE_MODE_MII, 577d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_MII_10] = PHY_INTERFACE_MODE_MII, 578d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_SERDES] = PHY_INTERFACE_MODE_1000BASEX, 579d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_1000BASE_X] = PHY_INTERFACE_MODE_1000BASEX, 580d4ebf12bSRussell King (Oracle) [MV88E6185_PORT_STS_CMODE_PHY] = PHY_INTERFACE_MODE_SGMII, 581d4ebf12bSRussell King (Oracle) }; 582d4ebf12bSRussell King (Oracle) 583d0b78ab1STobias Waldekranz static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 584d0b78ab1STobias Waldekranz struct phylink_config *config) 585d0b78ab1STobias Waldekranz { 586d0b78ab1STobias Waldekranz u8 cmode = chip->ports[port].cmode; 587d0b78ab1STobias Waldekranz 588d0b78ab1STobias Waldekranz config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; 589d0b78ab1STobias Waldekranz 590d0b78ab1STobias Waldekranz if (mv88e6xxx_phy_is_internal(chip->ds, port)) { 591d0b78ab1STobias Waldekranz __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); 592d0b78ab1STobias Waldekranz } else { 593d0b78ab1STobias Waldekranz if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) && 594d0b78ab1STobias Waldekranz mv88e6185_phy_interface_modes[cmode]) 595d0b78ab1STobias Waldekranz __set_bit(mv88e6185_phy_interface_modes[cmode], 596d0b78ab1STobias Waldekranz config->supported_interfaces); 597d0b78ab1STobias Waldekranz 598d0b78ab1STobias Waldekranz config->mac_capabilities |= MAC_1000FD; 599d0b78ab1STobias Waldekranz } 600d0b78ab1STobias Waldekranz } 601d0b78ab1STobias Waldekranz 602d4ebf12bSRussell King (Oracle) static void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 603d4ebf12bSRussell King (Oracle) struct phylink_config *config) 604d4ebf12bSRussell King (Oracle) { 605d4ebf12bSRussell King (Oracle) u8 cmode = chip->ports[port].cmode; 606d4ebf12bSRussell King (Oracle) 607dde41a69SDan Carpenter if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) && 608d4ebf12bSRussell King (Oracle) mv88e6185_phy_interface_modes[cmode]) 609d4ebf12bSRussell King (Oracle) __set_bit(mv88e6185_phy_interface_modes[cmode], 610d4ebf12bSRussell King (Oracle) config->supported_interfaces); 611d4ebf12bSRussell King (Oracle) 612d4ebf12bSRussell King (Oracle) config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 613d4ebf12bSRussell King (Oracle) MAC_1000FD; 614d4ebf12bSRussell King (Oracle) } 615d4ebf12bSRussell King (Oracle) 616d4ebf12bSRussell King (Oracle) static const u8 mv88e6xxx_phy_interface_modes[] = { 617d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_MII_PHY] = PHY_INTERFACE_MODE_MII, 618d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_MII] = PHY_INTERFACE_MODE_MII, 619d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_GMII] = PHY_INTERFACE_MODE_GMII, 620d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_RMII_PHY] = PHY_INTERFACE_MODE_RMII, 621d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_RMII] = PHY_INTERFACE_MODE_RMII, 622d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_100BASEX] = PHY_INTERFACE_MODE_100BASEX, 623d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_1000BASEX] = PHY_INTERFACE_MODE_1000BASEX, 624d4ebf12bSRussell King (Oracle) [MV88E6XXX_PORT_STS_CMODE_SGMII] = PHY_INTERFACE_MODE_SGMII, 625d4ebf12bSRussell King (Oracle) /* higher interface modes are not needed here, since ports supporting 626d4ebf12bSRussell King (Oracle) * them are writable, and so the supported interfaces are filled in the 627d4ebf12bSRussell King (Oracle) * corresponding .phylink_set_interfaces() implementation below 6286c422e34SRussell King */ 629d4ebf12bSRussell King (Oracle) }; 630d4ebf12bSRussell King (Oracle) 631d4ebf12bSRussell King (Oracle) static void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported) 632d4ebf12bSRussell King (Oracle) { 633d4ebf12bSRussell King (Oracle) if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) && 634d4ebf12bSRussell King (Oracle) mv88e6xxx_phy_interface_modes[cmode]) 635d4ebf12bSRussell King (Oracle) __set_bit(mv88e6xxx_phy_interface_modes[cmode], supported); 636d4ebf12bSRussell King (Oracle) else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII) 637d4ebf12bSRussell King (Oracle) phy_interface_set_rgmii(supported); 638d4ebf12bSRussell King (Oracle) } 639d4ebf12bSRussell King (Oracle) 640d4ebf12bSRussell King (Oracle) static void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 641d4ebf12bSRussell King (Oracle) struct phylink_config *config) 642d4ebf12bSRussell King (Oracle) { 643d4ebf12bSRussell King (Oracle) unsigned long *supported = config->supported_interfaces; 644d4ebf12bSRussell King (Oracle) 645d4ebf12bSRussell King (Oracle) /* Translate the default cmode */ 646d4ebf12bSRussell King (Oracle) mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 647d4ebf12bSRussell King (Oracle) 648d4ebf12bSRussell King (Oracle) config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; 649d4ebf12bSRussell King (Oracle) } 650d4ebf12bSRussell King (Oracle) 651d4ebf12bSRussell King (Oracle) static int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip) 652d4ebf12bSRussell King (Oracle) { 653d4ebf12bSRussell King (Oracle) u16 reg, val; 654d4ebf12bSRussell King (Oracle) int err; 655d4ebf12bSRussell King (Oracle) 656d4ebf12bSRussell King (Oracle) err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, ®); 657d4ebf12bSRussell King (Oracle) if (err) 658d4ebf12bSRussell King (Oracle) return err; 659d4ebf12bSRussell King (Oracle) 660d4ebf12bSRussell King (Oracle) /* If PHY_DETECT is zero, then we are not in auto-media mode */ 661d4ebf12bSRussell King (Oracle) if (!(reg & MV88E6XXX_PORT_STS_PHY_DETECT)) 662d4ebf12bSRussell King (Oracle) return 0xf; 663d4ebf12bSRussell King (Oracle) 664d4ebf12bSRussell King (Oracle) val = reg & ~MV88E6XXX_PORT_STS_PHY_DETECT; 665d4ebf12bSRussell King (Oracle) err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, val); 666d4ebf12bSRussell King (Oracle) if (err) 667d4ebf12bSRussell King (Oracle) return err; 668d4ebf12bSRussell King (Oracle) 669d4ebf12bSRussell King (Oracle) err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &val); 670d4ebf12bSRussell King (Oracle) if (err) 671d4ebf12bSRussell King (Oracle) return err; 672d4ebf12bSRussell King (Oracle) 673d4ebf12bSRussell King (Oracle) /* Restore PHY_DETECT value */ 674d4ebf12bSRussell King (Oracle) err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, reg); 675d4ebf12bSRussell King (Oracle) if (err) 676d4ebf12bSRussell King (Oracle) return err; 677d4ebf12bSRussell King (Oracle) 678d4ebf12bSRussell King (Oracle) return val & MV88E6XXX_PORT_STS_CMODE_MASK; 679d4ebf12bSRussell King (Oracle) } 680d4ebf12bSRussell King (Oracle) 681d4ebf12bSRussell King (Oracle) static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 682d4ebf12bSRussell King (Oracle) struct phylink_config *config) 683d4ebf12bSRussell King (Oracle) { 684d4ebf12bSRussell King (Oracle) unsigned long *supported = config->supported_interfaces; 685d4ebf12bSRussell King (Oracle) int err, cmode; 686d4ebf12bSRussell King (Oracle) 687d4ebf12bSRussell King (Oracle) /* Translate the default cmode */ 688d4ebf12bSRussell King (Oracle) mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 689d4ebf12bSRussell King (Oracle) 690d4ebf12bSRussell King (Oracle) config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 691d4ebf12bSRussell King (Oracle) MAC_1000FD; 692d4ebf12bSRussell King (Oracle) 693d4ebf12bSRussell King (Oracle) /* Port 4 supports automedia if the serdes is associated with it. */ 694d4ebf12bSRussell King (Oracle) if (port == 4) { 695d4ebf12bSRussell King (Oracle) mv88e6xxx_reg_lock(chip); 696d4ebf12bSRussell King (Oracle) err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 697d4ebf12bSRussell King (Oracle) if (err < 0) 698d4ebf12bSRussell King (Oracle) dev_err(chip->dev, "p%d: failed to read scratch\n", 699d4ebf12bSRussell King (Oracle) port); 700d4ebf12bSRussell King (Oracle) if (err <= 0) 701d4ebf12bSRussell King (Oracle) goto unlock; 702d4ebf12bSRussell King (Oracle) 703d4ebf12bSRussell King (Oracle) cmode = mv88e6352_get_port4_serdes_cmode(chip); 704d4ebf12bSRussell King (Oracle) if (cmode < 0) 705d4ebf12bSRussell King (Oracle) dev_err(chip->dev, "p%d: failed to read serdes cmode\n", 706d4ebf12bSRussell King (Oracle) port); 707d4ebf12bSRussell King (Oracle) else 708d4ebf12bSRussell King (Oracle) mv88e6xxx_translate_cmode(cmode, supported); 709d4ebf12bSRussell King (Oracle) unlock: 710d4ebf12bSRussell King (Oracle) mv88e6xxx_reg_unlock(chip); 711d4ebf12bSRussell King (Oracle) } 712d4ebf12bSRussell King (Oracle) } 713d4ebf12bSRussell King (Oracle) 714d4ebf12bSRussell King (Oracle) static void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 715d4ebf12bSRussell King (Oracle) struct phylink_config *config) 716d4ebf12bSRussell King (Oracle) { 717d4ebf12bSRussell King (Oracle) unsigned long *supported = config->supported_interfaces; 718d4ebf12bSRussell King (Oracle) 719d4ebf12bSRussell King (Oracle) /* Translate the default cmode */ 720d4ebf12bSRussell King (Oracle) mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 721d4ebf12bSRussell King (Oracle) 722d4ebf12bSRussell King (Oracle) /* No ethtool bits for 200Mbps */ 723d4ebf12bSRussell King (Oracle) config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 724d4ebf12bSRussell King (Oracle) MAC_1000FD; 725d4ebf12bSRussell King (Oracle) 726d4ebf12bSRussell King (Oracle) /* The C_Mode field is programmable on port 5 */ 727d4ebf12bSRussell King (Oracle) if (port == 5) { 728d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_SGMII, supported); 729d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 730d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); 731d4ebf12bSRussell King (Oracle) 732d4ebf12bSRussell King (Oracle) config->mac_capabilities |= MAC_2500FD; 733d4ebf12bSRussell King (Oracle) } 734d4ebf12bSRussell King (Oracle) } 735d4ebf12bSRussell King (Oracle) 736d4ebf12bSRussell King (Oracle) static void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 737d4ebf12bSRussell King (Oracle) struct phylink_config *config) 738d4ebf12bSRussell King (Oracle) { 739d4ebf12bSRussell King (Oracle) unsigned long *supported = config->supported_interfaces; 740d4ebf12bSRussell King (Oracle) 741d4ebf12bSRussell King (Oracle) /* Translate the default cmode */ 742d4ebf12bSRussell King (Oracle) mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 743d4ebf12bSRussell King (Oracle) 744d4ebf12bSRussell King (Oracle) /* No ethtool bits for 200Mbps */ 745d4ebf12bSRussell King (Oracle) config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 746d4ebf12bSRussell King (Oracle) MAC_1000FD; 747d4ebf12bSRussell King (Oracle) 748d4ebf12bSRussell King (Oracle) /* The C_Mode field is programmable on ports 9 and 10 */ 749d4ebf12bSRussell King (Oracle) if (port == 9 || port == 10) { 750d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_SGMII, supported); 751d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 752d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); 753d4ebf12bSRussell King (Oracle) 754d4ebf12bSRussell King (Oracle) config->mac_capabilities |= MAC_2500FD; 755d4ebf12bSRussell King (Oracle) } 756d4ebf12bSRussell King (Oracle) } 757d4ebf12bSRussell King (Oracle) 758d4ebf12bSRussell King (Oracle) static void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 759d4ebf12bSRussell King (Oracle) struct phylink_config *config) 760d4ebf12bSRussell King (Oracle) { 761d4ebf12bSRussell King (Oracle) unsigned long *supported = config->supported_interfaces; 762d4ebf12bSRussell King (Oracle) 763d4ebf12bSRussell King (Oracle) mv88e6390_phylink_get_caps(chip, port, config); 764d4ebf12bSRussell King (Oracle) 765d4ebf12bSRussell King (Oracle) /* For the 6x90X, ports 2-7 can be in automedia mode. 766d4ebf12bSRussell King (Oracle) * (Note that 6x90 doesn't support RXAUI nor XAUI). 767d4ebf12bSRussell King (Oracle) * 768d4ebf12bSRussell King (Oracle) * Port 2 can also support 1000BASE-X in automedia mode if port 9 is 769d4ebf12bSRussell King (Oracle) * configured for 1000BASE-X, SGMII or 2500BASE-X. 770d4ebf12bSRussell King (Oracle) * Port 3-4 can also support 1000BASE-X in automedia mode if port 9 is 771d4ebf12bSRussell King (Oracle) * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X. 772d4ebf12bSRussell King (Oracle) * 773d4ebf12bSRussell King (Oracle) * Port 5 can also support 1000BASE-X in automedia mode if port 10 is 774d4ebf12bSRussell King (Oracle) * configured for 1000BASE-X, SGMII or 2500BASE-X. 775d4ebf12bSRussell King (Oracle) * Port 6-7 can also support 1000BASE-X in automedia mode if port 10 is 776d4ebf12bSRussell King (Oracle) * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X. 777d4ebf12bSRussell King (Oracle) * 778d4ebf12bSRussell King (Oracle) * For now, be permissive (as the old code was) and allow 1000BASE-X 779d4ebf12bSRussell King (Oracle) * on ports 2..7. 780d4ebf12bSRussell King (Oracle) */ 781d4ebf12bSRussell King (Oracle) if (port >= 2 && port <= 7) 782d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 783d4ebf12bSRussell King (Oracle) 784d4ebf12bSRussell King (Oracle) /* The C_Mode field can also be programmed for 10G speeds */ 785d4ebf12bSRussell King (Oracle) if (port == 9 || port == 10) { 786d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_XAUI, supported); 787d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_RXAUI, supported); 788d4ebf12bSRussell King (Oracle) 789d4ebf12bSRussell King (Oracle) config->mac_capabilities |= MAC_10000FD; 790d4ebf12bSRussell King (Oracle) } 791d4ebf12bSRussell King (Oracle) } 792d4ebf12bSRussell King (Oracle) 793d4ebf12bSRussell King (Oracle) static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 794d4ebf12bSRussell King (Oracle) struct phylink_config *config) 795d4ebf12bSRussell King (Oracle) { 796d4ebf12bSRussell King (Oracle) unsigned long *supported = config->supported_interfaces; 797d4ebf12bSRussell King (Oracle) bool is_6191x = 798d4ebf12bSRussell King (Oracle) chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X; 799d4ebf12bSRussell King (Oracle) 800d4ebf12bSRussell King (Oracle) mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 801d4ebf12bSRussell King (Oracle) 802d4ebf12bSRussell King (Oracle) config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 803d4ebf12bSRussell King (Oracle) MAC_1000FD; 804d4ebf12bSRussell King (Oracle) 805d4ebf12bSRussell King (Oracle) /* The C_Mode field can be programmed for ports 0, 9 and 10 */ 806d4ebf12bSRussell King (Oracle) if (port == 0 || port == 9 || port == 10) { 807d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_SGMII, supported); 808d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 809d4ebf12bSRussell King (Oracle) 810d4ebf12bSRussell King (Oracle) /* 6191X supports >1G modes only on port 10 */ 811d4ebf12bSRussell King (Oracle) if (!is_6191x || port == 10) { 812d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); 813d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); 814d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); 815d4ebf12bSRussell King (Oracle) /* FIXME: USXGMII is not supported yet */ 816d4ebf12bSRussell King (Oracle) /* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */ 817d4ebf12bSRussell King (Oracle) 818d4ebf12bSRussell King (Oracle) config->mac_capabilities |= MAC_2500FD | MAC_5000FD | 819d4ebf12bSRussell King (Oracle) MAC_10000FD; 820d4ebf12bSRussell King (Oracle) } 821d4ebf12bSRussell King (Oracle) } 822d4ebf12bSRussell King (Oracle) } 823d4ebf12bSRussell King (Oracle) 824d4ebf12bSRussell King (Oracle) static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, 825d4ebf12bSRussell King (Oracle) struct phylink_config *config) 826d4ebf12bSRussell King (Oracle) { 827d4ebf12bSRussell King (Oracle) struct mv88e6xxx_chip *chip = ds->priv; 828d4ebf12bSRussell King (Oracle) 829d4ebf12bSRussell King (Oracle) chip->info->ops->phylink_get_caps(chip, port, config); 830d4ebf12bSRussell King (Oracle) 831d4ebf12bSRussell King (Oracle) /* Internal ports need GMII for PHYLIB */ 832d4ebf12bSRussell King (Oracle) if (mv88e6xxx_phy_is_internal(ds, port)) 833d4ebf12bSRussell King (Oracle) __set_bit(PHY_INTERFACE_MODE_GMII, 834d4ebf12bSRussell King (Oracle) config->supported_interfaces); 835c9a2356fSRussell King } 836c9a2356fSRussell King 837c9a2356fSRussell King static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 838c9a2356fSRussell King unsigned int mode, 839c9a2356fSRussell King const struct phylink_link_state *state) 840c9a2356fSRussell King { 841c9a2356fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 842fad58190SRussell King struct mv88e6xxx_port *p; 84304ec4e62SRussell King (Oracle) int err = 0; 844c9a2356fSRussell King 845fad58190SRussell King p = &chip->ports[port]; 846fad58190SRussell King 847c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 848fad58190SRussell King 84904ec4e62SRussell King (Oracle) if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) { 85004ec4e62SRussell King (Oracle) /* In inband mode, the link may come up at any time while the 85104ec4e62SRussell King (Oracle) * link is not forced down. Force the link down while we 85204ec4e62SRussell King (Oracle) * reconfigure the interface mode. 85304ec4e62SRussell King (Oracle) */ 85404ec4e62SRussell King (Oracle) if (mode == MLO_AN_INBAND && 85504ec4e62SRussell King (Oracle) p->interface != state->interface && 85604ec4e62SRussell King (Oracle) chip->info->ops->port_set_link) 85704ec4e62SRussell King (Oracle) chip->info->ops->port_set_link(chip, port, 85804ec4e62SRussell King (Oracle) LINK_FORCED_DOWN); 85904ec4e62SRussell King (Oracle) 86004ec4e62SRussell King (Oracle) err = mv88e6xxx_port_config_interface(chip, port, 86104ec4e62SRussell King (Oracle) state->interface); 862a5a6858bSRussell King if (err && err != -EOPNOTSUPP) 863a5a6858bSRussell King goto err_unlock; 864a5a6858bSRussell King 86504ec4e62SRussell King (Oracle) err = mv88e6xxx_serdes_pcs_config(chip, port, mode, 86604ec4e62SRussell King (Oracle) state->interface, 867a5a6858bSRussell King state->advertising); 86804ec4e62SRussell King (Oracle) /* FIXME: we should restart negotiation if something changed - 86904ec4e62SRussell King (Oracle) * which is something we get if we convert to using phylinks 87004ec4e62SRussell King (Oracle) * PCS operations. 871a5a6858bSRussell King */ 872a5a6858bSRussell King if (err > 0) 873a5a6858bSRussell King err = 0; 87404ec4e62SRussell King (Oracle) } 875a5a6858bSRussell King 876fad58190SRussell King /* Undo the forced down state above after completing configuration 87704ec4e62SRussell King (Oracle) * irrespective of its state on entry, which allows the link to come 87804ec4e62SRussell King (Oracle) * up in the in-band case where there is no separate SERDES. Also 87904ec4e62SRussell King (Oracle) * ensure that the link can come up if the PPU is in use and we are 88004ec4e62SRussell King (Oracle) * in PHY mode (we treat the PPU as an effective in-band mechanism.) 881fad58190SRussell King */ 88204ec4e62SRussell King (Oracle) if (chip->info->ops->port_set_link && 88304ec4e62SRussell King (Oracle) ((mode == MLO_AN_INBAND && p->interface != state->interface) || 88404ec4e62SRussell King (Oracle) (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port)))) 885fad58190SRussell King chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); 886fad58190SRussell King 887fad58190SRussell King p->interface = state->interface; 888fad58190SRussell King 889a5a6858bSRussell King err_unlock: 890c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 891c9a2356fSRussell King 892c9a2356fSRussell King if (err && err != -EOPNOTSUPP) 89364d47d50SRussell King dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); 894c9a2356fSRussell King } 895c9a2356fSRussell King 896c9a2356fSRussell King static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 897c9a2356fSRussell King unsigned int mode, 898c9a2356fSRussell King phy_interface_t interface) 899c9a2356fSRussell King { 90030c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 90130c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 90230c4a5b0SRussell King int err = 0; 90330c4a5b0SRussell King 90430c4a5b0SRussell King ops = chip->info->ops; 90530c4a5b0SRussell King 90630c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 9072b29cb9eSRussell King (Oracle) /* Force the link down if we know the port may not be automatically 9082b29cb9eSRussell King (Oracle) * updated by the switch or if we are using fixed-link mode. 9094a3e0aedSMaarten Zanders */ 9102b29cb9eSRussell King (Oracle) if ((!mv88e6xxx_port_ppu_updates(chip, port) || 9114efe7662SChris Packham mode == MLO_AN_FIXED) && ops->port_sync_link) 9124efe7662SChris Packham err = ops->port_sync_link(chip, port, mode, false); 9139d591fc0SMarek Behún 9149d591fc0SMarek Behún if (!err && ops->port_set_speed_duplex) 9159d591fc0SMarek Behún err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED, 9169d591fc0SMarek Behún DUPLEX_UNFORCED); 91730c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 91830c4a5b0SRussell King 91930c4a5b0SRussell King if (err) 92030c4a5b0SRussell King dev_err(chip->dev, 92130c4a5b0SRussell King "p%d: failed to force MAC link down\n", port); 92230c4a5b0SRussell King } 923c9a2356fSRussell King 924c9a2356fSRussell King static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 925c9a2356fSRussell King unsigned int mode, phy_interface_t interface, 9265b502a7bSRussell King struct phy_device *phydev, 9275b502a7bSRussell King int speed, int duplex, 9285b502a7bSRussell King bool tx_pause, bool rx_pause) 929c9a2356fSRussell King { 93030c4a5b0SRussell King struct mv88e6xxx_chip *chip = ds->priv; 93130c4a5b0SRussell King const struct mv88e6xxx_ops *ops; 93230c4a5b0SRussell King int err = 0; 93330c4a5b0SRussell King 93430c4a5b0SRussell King ops = chip->info->ops; 93530c4a5b0SRussell King 93630c4a5b0SRussell King mv88e6xxx_reg_lock(chip); 9372b29cb9eSRussell King (Oracle) /* Configure and force the link up if we know that the port may not 9382b29cb9eSRussell King (Oracle) * automatically updated by the switch or if we are using fixed-link 9392b29cb9eSRussell King (Oracle) * mode. 9404a3e0aedSMaarten Zanders */ 9412b29cb9eSRussell King (Oracle) if (!mv88e6xxx_port_ppu_updates(chip, port) || 9424a3e0aedSMaarten Zanders mode == MLO_AN_FIXED) { 94330c4a5b0SRussell King /* FIXME: for an automedia port, should we force the link 94430c4a5b0SRussell King * down here - what if the link comes up due to "other" media 94530c4a5b0SRussell King * while we're bringing the port up, how is the exclusivity 946a5a6858bSRussell King * handled in the Marvell hardware? E.g. port 2 on 88E6390 94730c4a5b0SRussell King * shared between internal PHY and Serdes. 94830c4a5b0SRussell King */ 949a5a6858bSRussell King err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed, 950a5a6858bSRussell King duplex); 951a5a6858bSRussell King if (err) 952a5a6858bSRussell King goto error; 953a5a6858bSRussell King 954f365c6f7SRussell King if (ops->port_set_speed_duplex) { 955f365c6f7SRussell King err = ops->port_set_speed_duplex(chip, port, 956f365c6f7SRussell King speed, duplex); 95730c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 95830c4a5b0SRussell King goto error; 95930c4a5b0SRussell King } 96030c4a5b0SRussell King 9614efe7662SChris Packham if (ops->port_sync_link) 9624efe7662SChris Packham err = ops->port_sync_link(chip, port, mode, true); 9635d5b231dSRussell King } 96430c4a5b0SRussell King error: 96530c4a5b0SRussell King mv88e6xxx_reg_unlock(chip); 96630c4a5b0SRussell King 96730c4a5b0SRussell King if (err && err != -EOPNOTSUPP) 96830c4a5b0SRussell King dev_err(ds->dev, 96930c4a5b0SRussell King "p%d: failed to configure MAC link up\n", port); 97030c4a5b0SRussell King } 971c9a2356fSRussell King 972a605a0feSAndrew Lunn static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 973fad09c73SVivien Didelot { 974a605a0feSAndrew Lunn if (!chip->info->ops->stats_snapshot) 975a605a0feSAndrew Lunn return -EOPNOTSUPP; 976fad09c73SVivien Didelot 977a605a0feSAndrew Lunn return chip->info->ops->stats_snapshot(chip, port); 978fad09c73SVivien Didelot } 979fad09c73SVivien Didelot 980fad09c73SVivien Didelot static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 981dfafe449SAndrew Lunn { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 982dfafe449SAndrew Lunn { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 983dfafe449SAndrew Lunn { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 984dfafe449SAndrew Lunn { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 985dfafe449SAndrew Lunn { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 986dfafe449SAndrew Lunn { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 987dfafe449SAndrew Lunn { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 988dfafe449SAndrew Lunn { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 989dfafe449SAndrew Lunn { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 990dfafe449SAndrew Lunn { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 991dfafe449SAndrew Lunn { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 992dfafe449SAndrew Lunn { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 993dfafe449SAndrew Lunn { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 994dfafe449SAndrew Lunn { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 995dfafe449SAndrew Lunn { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 996dfafe449SAndrew Lunn { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 997dfafe449SAndrew Lunn { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 998dfafe449SAndrew Lunn { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 999dfafe449SAndrew Lunn { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 1000dfafe449SAndrew Lunn { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 1001dfafe449SAndrew Lunn { "single", 4, 0x14, STATS_TYPE_BANK0, }, 1002dfafe449SAndrew Lunn { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 1003dfafe449SAndrew Lunn { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 1004dfafe449SAndrew Lunn { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 1005dfafe449SAndrew Lunn { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 1006dfafe449SAndrew Lunn { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 1007dfafe449SAndrew Lunn { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 1008dfafe449SAndrew Lunn { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 1009dfafe449SAndrew Lunn { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 1010dfafe449SAndrew Lunn { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 1011dfafe449SAndrew Lunn { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 1012dfafe449SAndrew Lunn { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 1013dfafe449SAndrew Lunn { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 1014dfafe449SAndrew Lunn { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 1015dfafe449SAndrew Lunn { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 1016dfafe449SAndrew Lunn { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 1017dfafe449SAndrew Lunn { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 1018dfafe449SAndrew Lunn { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 1019dfafe449SAndrew Lunn { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 1020dfafe449SAndrew Lunn { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 1021dfafe449SAndrew Lunn { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 1022dfafe449SAndrew Lunn { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 1023dfafe449SAndrew Lunn { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 1024dfafe449SAndrew Lunn { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 1025dfafe449SAndrew Lunn { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 1026dfafe449SAndrew Lunn { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 1027dfafe449SAndrew Lunn { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 1028dfafe449SAndrew Lunn { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 1029dfafe449SAndrew Lunn { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 1030dfafe449SAndrew Lunn { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 1031dfafe449SAndrew Lunn { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 1032dfafe449SAndrew Lunn { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 1033dfafe449SAndrew Lunn { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 1034dfafe449SAndrew Lunn { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 1035dfafe449SAndrew Lunn { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 1036dfafe449SAndrew Lunn { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 1037dfafe449SAndrew Lunn { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 1038dfafe449SAndrew Lunn { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 1039dfafe449SAndrew Lunn { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 1040fad09c73SVivien Didelot }; 1041fad09c73SVivien Didelot 1042fad09c73SVivien Didelot static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 1043fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *s, 1044e0d8b615SAndrew Lunn int port, u16 bank1_select, 1045e0d8b615SAndrew Lunn u16 histogram) 1046fad09c73SVivien Didelot { 1047fad09c73SVivien Didelot u32 low; 1048fad09c73SVivien Didelot u32 high = 0; 1049dfafe449SAndrew Lunn u16 reg = 0; 10500e7b9925SAndrew Lunn int err; 1051fad09c73SVivien Didelot u64 value; 1052fad09c73SVivien Didelot 1053fad09c73SVivien Didelot switch (s->type) { 1054dfafe449SAndrew Lunn case STATS_TYPE_PORT: 10550e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg, ®); 10560e7b9925SAndrew Lunn if (err) 10576c3442f5SJisheng Zhang return U64_MAX; 1058fad09c73SVivien Didelot 10590e7b9925SAndrew Lunn low = reg; 1060cda9f4aaSAndrew Lunn if (s->size == 4) { 10610e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 10620e7b9925SAndrew Lunn if (err) 10636c3442f5SJisheng Zhang return U64_MAX; 106484b3fd1fSRasmus Villemoes low |= ((u32)reg) << 16; 1065fad09c73SVivien Didelot } 1066fad09c73SVivien Didelot break; 1067dfafe449SAndrew Lunn case STATS_TYPE_BANK1: 1068e0d8b615SAndrew Lunn reg = bank1_select; 1069df561f66SGustavo A. R. Silva fallthrough; 1070dfafe449SAndrew Lunn case STATS_TYPE_BANK0: 1071e0d8b615SAndrew Lunn reg |= s->reg | histogram; 10727f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg, &low); 1073cda9f4aaSAndrew Lunn if (s->size == 8) 10747f9ef3afSAndrew Lunn mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 10759fc3e4dcSGustavo A. R. Silva break; 10769fc3e4dcSGustavo A. R. Silva default: 10776c3442f5SJisheng Zhang return U64_MAX; 1078fad09c73SVivien Didelot } 10796e46e2d8SAndrew Lunn value = (((u64)high) << 32) | low; 1080fad09c73SVivien Didelot return value; 1081fad09c73SVivien Didelot } 1082fad09c73SVivien Didelot 1083436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 1084dfafe449SAndrew Lunn uint8_t *data, int types) 1085fad09c73SVivien Didelot { 1086fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 1087fad09c73SVivien Didelot int i, j; 1088fad09c73SVivien Didelot 1089fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1090fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 1091dfafe449SAndrew Lunn if (stat->type & types) { 1092fad09c73SVivien Didelot memcpy(data + j * ETH_GSTRING_LEN, stat->string, 1093fad09c73SVivien Didelot ETH_GSTRING_LEN); 1094fad09c73SVivien Didelot j++; 1095fad09c73SVivien Didelot } 1096fad09c73SVivien Didelot } 1097436fe17dSAndrew Lunn 1098436fe17dSAndrew Lunn return j; 1099fad09c73SVivien Didelot } 1100fad09c73SVivien Didelot 1101436fe17dSAndrew Lunn static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 1102dfafe449SAndrew Lunn uint8_t *data) 1103dfafe449SAndrew Lunn { 1104436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 1105dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT); 1106dfafe449SAndrew Lunn } 1107dfafe449SAndrew Lunn 11081f71836fSRasmus Villemoes static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 11091f71836fSRasmus Villemoes uint8_t *data) 11101f71836fSRasmus Villemoes { 11111f71836fSRasmus Villemoes return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 11121f71836fSRasmus Villemoes } 11131f71836fSRasmus Villemoes 1114436fe17dSAndrew Lunn static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 1115dfafe449SAndrew Lunn uint8_t *data) 1116dfafe449SAndrew Lunn { 1117436fe17dSAndrew Lunn return mv88e6xxx_stats_get_strings(chip, data, 1118dfafe449SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 1119dfafe449SAndrew Lunn } 1120dfafe449SAndrew Lunn 112165f60e45SAndrew Lunn static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 112265f60e45SAndrew Lunn "atu_member_violation", 112365f60e45SAndrew Lunn "atu_miss_violation", 112465f60e45SAndrew Lunn "atu_full_violation", 112565f60e45SAndrew Lunn "vtu_member_violation", 112665f60e45SAndrew Lunn "vtu_miss_violation", 112765f60e45SAndrew Lunn }; 112865f60e45SAndrew Lunn 112965f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 113065f60e45SAndrew Lunn { 113165f60e45SAndrew Lunn unsigned int i; 113265f60e45SAndrew Lunn 113365f60e45SAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 113465f60e45SAndrew Lunn strlcpy(data + i * ETH_GSTRING_LEN, 113565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_stats_strings[i], 113665f60e45SAndrew Lunn ETH_GSTRING_LEN); 113765f60e45SAndrew Lunn } 113865f60e45SAndrew Lunn 1139dfafe449SAndrew Lunn static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 114089f09048SFlorian Fainelli u32 stringset, uint8_t *data) 1141fad09c73SVivien Didelot { 114204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1143436fe17dSAndrew Lunn int count = 0; 1144dfafe449SAndrew Lunn 114589f09048SFlorian Fainelli if (stringset != ETH_SS_STATS) 114689f09048SFlorian Fainelli return; 114789f09048SFlorian Fainelli 1148c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1149c6c8cd5eSAndrew Lunn 1150dfafe449SAndrew Lunn if (chip->info->ops->stats_get_strings) 1151436fe17dSAndrew Lunn count = chip->info->ops->stats_get_strings(chip, data); 1152436fe17dSAndrew Lunn 1153436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_strings) { 1154436fe17dSAndrew Lunn data += count * ETH_GSTRING_LEN; 115565f60e45SAndrew Lunn count = chip->info->ops->serdes_get_strings(chip, port, data); 1156436fe17dSAndrew Lunn } 1157c6c8cd5eSAndrew Lunn 115865f60e45SAndrew Lunn data += count * ETH_GSTRING_LEN; 115965f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_strings(data); 116065f60e45SAndrew Lunn 1161c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1162dfafe449SAndrew Lunn } 1163dfafe449SAndrew Lunn 1164dfafe449SAndrew Lunn static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 1165dfafe449SAndrew Lunn int types) 1166dfafe449SAndrew Lunn { 1167fad09c73SVivien Didelot struct mv88e6xxx_hw_stat *stat; 1168fad09c73SVivien Didelot int i, j; 1169fad09c73SVivien Didelot 1170fad09c73SVivien Didelot for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1171fad09c73SVivien Didelot stat = &mv88e6xxx_hw_stats[i]; 1172dfafe449SAndrew Lunn if (stat->type & types) 1173fad09c73SVivien Didelot j++; 1174fad09c73SVivien Didelot } 1175fad09c73SVivien Didelot return j; 1176fad09c73SVivien Didelot } 1177fad09c73SVivien Didelot 1178dfafe449SAndrew Lunn static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1179dfafe449SAndrew Lunn { 1180dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1181dfafe449SAndrew Lunn STATS_TYPE_PORT); 1182dfafe449SAndrew Lunn } 1183dfafe449SAndrew Lunn 11841f71836fSRasmus Villemoes static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 11851f71836fSRasmus Villemoes { 11861f71836fSRasmus Villemoes return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 11871f71836fSRasmus Villemoes } 11881f71836fSRasmus Villemoes 1189dfafe449SAndrew Lunn static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 1190dfafe449SAndrew Lunn { 1191dfafe449SAndrew Lunn return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 1192dfafe449SAndrew Lunn STATS_TYPE_BANK1); 1193dfafe449SAndrew Lunn } 1194dfafe449SAndrew Lunn 119589f09048SFlorian Fainelli static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 1196dfafe449SAndrew Lunn { 1197dfafe449SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 1198436fe17dSAndrew Lunn int serdes_count = 0; 1199436fe17dSAndrew Lunn int count = 0; 1200dfafe449SAndrew Lunn 120189f09048SFlorian Fainelli if (sset != ETH_SS_STATS) 120289f09048SFlorian Fainelli return 0; 120389f09048SFlorian Fainelli 1204c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1205dfafe449SAndrew Lunn if (chip->info->ops->stats_get_sset_count) 1206436fe17dSAndrew Lunn count = chip->info->ops->stats_get_sset_count(chip); 1207436fe17dSAndrew Lunn if (count < 0) 1208436fe17dSAndrew Lunn goto out; 1209436fe17dSAndrew Lunn 1210436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_sset_count) 1211436fe17dSAndrew Lunn serdes_count = chip->info->ops->serdes_get_sset_count(chip, 1212436fe17dSAndrew Lunn port); 121365f60e45SAndrew Lunn if (serdes_count < 0) { 1214436fe17dSAndrew Lunn count = serdes_count; 121565f60e45SAndrew Lunn goto out; 121665f60e45SAndrew Lunn } 1217436fe17dSAndrew Lunn count += serdes_count; 121865f60e45SAndrew Lunn count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 121965f60e45SAndrew Lunn 1220436fe17dSAndrew Lunn out: 1221c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1222dfafe449SAndrew Lunn 1223436fe17dSAndrew Lunn return count; 1224dfafe449SAndrew Lunn } 1225dfafe449SAndrew Lunn 1226436fe17dSAndrew Lunn static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1227e0d8b615SAndrew Lunn uint64_t *data, int types, 1228e0d8b615SAndrew Lunn u16 bank1_select, u16 histogram) 1229052f947fSAndrew Lunn { 1230052f947fSAndrew Lunn struct mv88e6xxx_hw_stat *stat; 1231052f947fSAndrew Lunn int i, j; 1232052f947fSAndrew Lunn 1233052f947fSAndrew Lunn for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 1234052f947fSAndrew Lunn stat = &mv88e6xxx_hw_stats[i]; 1235052f947fSAndrew Lunn if (stat->type & types) { 1236c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1237e0d8b615SAndrew Lunn data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 1238e0d8b615SAndrew Lunn bank1_select, 1239e0d8b615SAndrew Lunn histogram); 1240c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1241377cda13SAndrew Lunn 1242052f947fSAndrew Lunn j++; 1243052f947fSAndrew Lunn } 1244052f947fSAndrew Lunn } 1245436fe17dSAndrew Lunn return j; 1246052f947fSAndrew Lunn } 1247052f947fSAndrew Lunn 1248436fe17dSAndrew Lunn static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1249052f947fSAndrew Lunn uint64_t *data) 1250052f947fSAndrew Lunn { 1251052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1252e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_PORT, 125357d1ef38SVivien Didelot 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1254052f947fSAndrew Lunn } 1255052f947fSAndrew Lunn 12561f71836fSRasmus Villemoes static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 12571f71836fSRasmus Villemoes uint64_t *data) 12581f71836fSRasmus Villemoes { 12591f71836fSRasmus Villemoes return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 12601f71836fSRasmus Villemoes 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 12611f71836fSRasmus Villemoes } 12621f71836fSRasmus Villemoes 1263436fe17dSAndrew Lunn static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1264052f947fSAndrew Lunn uint64_t *data) 1265052f947fSAndrew Lunn { 1266052f947fSAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1267e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 126857d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 126957d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 1270e0d8b615SAndrew Lunn } 1271e0d8b615SAndrew Lunn 1272436fe17dSAndrew Lunn static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 1273e0d8b615SAndrew Lunn uint64_t *data) 1274e0d8b615SAndrew Lunn { 1275e0d8b615SAndrew Lunn return mv88e6xxx_stats_get_stats(chip, port, data, 1276e0d8b615SAndrew Lunn STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 127757d1ef38SVivien Didelot MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 127857d1ef38SVivien Didelot 0); 1279052f947fSAndrew Lunn } 1280052f947fSAndrew Lunn 128165f60e45SAndrew Lunn static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 128265f60e45SAndrew Lunn uint64_t *data) 128365f60e45SAndrew Lunn { 128465f60e45SAndrew Lunn *data++ = chip->ports[port].atu_member_violation; 128565f60e45SAndrew Lunn *data++ = chip->ports[port].atu_miss_violation; 128665f60e45SAndrew Lunn *data++ = chip->ports[port].atu_full_violation; 128765f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_member_violation; 128865f60e45SAndrew Lunn *data++ = chip->ports[port].vtu_miss_violation; 128965f60e45SAndrew Lunn } 129065f60e45SAndrew Lunn 1291052f947fSAndrew Lunn static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 1292052f947fSAndrew Lunn uint64_t *data) 1293052f947fSAndrew Lunn { 1294436fe17dSAndrew Lunn int count = 0; 1295436fe17dSAndrew Lunn 1296052f947fSAndrew Lunn if (chip->info->ops->stats_get_stats) 1297436fe17dSAndrew Lunn count = chip->info->ops->stats_get_stats(chip, port, data); 1298436fe17dSAndrew Lunn 1299c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1300436fe17dSAndrew Lunn if (chip->info->ops->serdes_get_stats) { 1301436fe17dSAndrew Lunn data += count; 130265f60e45SAndrew Lunn count = chip->info->ops->serdes_get_stats(chip, port, data); 1303436fe17dSAndrew Lunn } 130465f60e45SAndrew Lunn data += count; 130565f60e45SAndrew Lunn mv88e6xxx_atu_vtu_get_stats(chip, port, data); 1306c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1307052f947fSAndrew Lunn } 1308052f947fSAndrew Lunn 1309fad09c73SVivien Didelot static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 1310fad09c73SVivien Didelot uint64_t *data) 1311fad09c73SVivien Didelot { 131204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1313fad09c73SVivien Didelot int ret; 1314fad09c73SVivien Didelot 1315c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1316fad09c73SVivien Didelot 1317a605a0feSAndrew Lunn ret = mv88e6xxx_stats_snapshot(chip, port); 1318c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1319377cda13SAndrew Lunn 1320377cda13SAndrew Lunn if (ret < 0) 1321fad09c73SVivien Didelot return; 1322052f947fSAndrew Lunn 1323052f947fSAndrew Lunn mv88e6xxx_get_stats(chip, port, data); 1324fad09c73SVivien Didelot 1325fad09c73SVivien Didelot } 1326fad09c73SVivien Didelot 1327fad09c73SVivien Didelot static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 1328fad09c73SVivien Didelot { 13290d30bbd0SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 13300d30bbd0SAndrew Lunn int len; 13310d30bbd0SAndrew Lunn 13320d30bbd0SAndrew Lunn len = 32 * sizeof(u16); 13330d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs_len) 13340d30bbd0SAndrew Lunn len += chip->info->ops->serdes_get_regs_len(chip, port); 13350d30bbd0SAndrew Lunn 13360d30bbd0SAndrew Lunn return len; 1337fad09c73SVivien Didelot } 1338fad09c73SVivien Didelot 1339fad09c73SVivien Didelot static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 1340fad09c73SVivien Didelot struct ethtool_regs *regs, void *_p) 1341fad09c73SVivien Didelot { 134204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 13430e7b9925SAndrew Lunn int err; 13440e7b9925SAndrew Lunn u16 reg; 1345fad09c73SVivien Didelot u16 *p = _p; 1346fad09c73SVivien Didelot int i; 1347fad09c73SVivien Didelot 1348a5f39326SVivien Didelot regs->version = chip->info->prod_num; 1349fad09c73SVivien Didelot 1350fad09c73SVivien Didelot memset(p, 0xff, 32 * sizeof(u16)); 1351fad09c73SVivien Didelot 1352c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1353fad09c73SVivien Didelot 1354fad09c73SVivien Didelot for (i = 0; i < 32; i++) { 1355fad09c73SVivien Didelot 13560e7b9925SAndrew Lunn err = mv88e6xxx_port_read(chip, port, i, ®); 13570e7b9925SAndrew Lunn if (!err) 13580e7b9925SAndrew Lunn p[i] = reg; 1359fad09c73SVivien Didelot } 1360fad09c73SVivien Didelot 13610d30bbd0SAndrew Lunn if (chip->info->ops->serdes_get_regs) 13620d30bbd0SAndrew Lunn chip->info->ops->serdes_get_regs(chip, port, &p[i]); 13630d30bbd0SAndrew Lunn 1364c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1365fad09c73SVivien Didelot } 1366fad09c73SVivien Didelot 136708f50061SVivien Didelot static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 1368fad09c73SVivien Didelot struct ethtool_eee *e) 1369fad09c73SVivien Didelot { 13705480db69SVivien Didelot /* Nothing to do on the port's MAC */ 13715480db69SVivien Didelot return 0; 1372fad09c73SVivien Didelot } 1373fad09c73SVivien Didelot 137408f50061SVivien Didelot static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 137546587e4aSVivien Didelot struct ethtool_eee *e) 1376fad09c73SVivien Didelot { 13775480db69SVivien Didelot /* Nothing to do on the port's MAC */ 13785480db69SVivien Didelot return 0; 1379fad09c73SVivien Didelot } 1380fad09c73SVivien Didelot 13819dc8b13eSVivien Didelot /* Mask of the local ports allowed to receive frames from a given fabric port */ 1382e5887a2aSVivien Didelot static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 1383fad09c73SVivien Didelot { 13849dc8b13eSVivien Didelot struct dsa_switch *ds = chip->ds; 13859dc8b13eSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 138665144067SVladimir Oltean struct dsa_port *dp, *other_dp; 13879dc8b13eSVivien Didelot bool found = false; 1388e5887a2aSVivien Didelot u16 pvlan; 1389fad09c73SVivien Didelot 1390ce5df689SVladimir Oltean /* dev is a physical switch */ 1391ce5df689SVladimir Oltean if (dev <= dst->last_switch) { 13929dc8b13eSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 13939dc8b13eSVivien Didelot if (dp->ds->index == dev && dp->index == port) { 1394ce5df689SVladimir Oltean /* dp might be a DSA link or a user port, so it 139565144067SVladimir Oltean * might or might not have a bridge. 139665144067SVladimir Oltean * Use the "found" variable for both cases. 1397ce5df689SVladimir Oltean */ 1398ce5df689SVladimir Oltean found = true; 1399ce5df689SVladimir Oltean break; 1400ce5df689SVladimir Oltean } 1401ce5df689SVladimir Oltean } 1402ce5df689SVladimir Oltean /* dev is a virtual bridge */ 1403ce5df689SVladimir Oltean } else { 1404ce5df689SVladimir Oltean list_for_each_entry(dp, &dst->ports, list) { 140541fb0cf1SVladimir Oltean unsigned int bridge_num = dsa_port_bridge_num_get(dp); 140641fb0cf1SVladimir Oltean 140741fb0cf1SVladimir Oltean if (!bridge_num) 1408ce5df689SVladimir Oltean continue; 1409ce5df689SVladimir Oltean 141041fb0cf1SVladimir Oltean if (bridge_num + dst->last_switch != dev) 1411ce5df689SVladimir Oltean continue; 1412ce5df689SVladimir Oltean 14139dc8b13eSVivien Didelot found = true; 14149dc8b13eSVivien Didelot break; 14159dc8b13eSVivien Didelot } 14169dc8b13eSVivien Didelot } 1417fad09c73SVivien Didelot 1418ce5df689SVladimir Oltean /* Prevent frames from unknown switch or virtual bridge */ 14199dc8b13eSVivien Didelot if (!found) 1420e5887a2aSVivien Didelot return 0; 1421e5887a2aSVivien Didelot 1422e5887a2aSVivien Didelot /* Frames from DSA links and CPU ports can egress any local port */ 14239dc8b13eSVivien Didelot if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) 1424e5887a2aSVivien Didelot return mv88e6xxx_port_mask(chip); 1425e5887a2aSVivien Didelot 1426e5887a2aSVivien Didelot pvlan = 0; 1427e5887a2aSVivien Didelot 14287af4a361STobias Waldekranz /* Frames from standalone user ports can only egress on the 14297af4a361STobias Waldekranz * upstream port. 14307af4a361STobias Waldekranz */ 14317af4a361STobias Waldekranz if (!dsa_port_bridge_dev_get(dp)) 14327af4a361STobias Waldekranz return BIT(dsa_switch_upstream_port(ds)); 14337af4a361STobias Waldekranz 14347af4a361STobias Waldekranz /* Frames from bridged user ports can egress any local DSA 14357af4a361STobias Waldekranz * links and CPU ports, as well as any local member of their 14367af4a361STobias Waldekranz * bridge group. 1437e5887a2aSVivien Didelot */ 143865144067SVladimir Oltean dsa_switch_for_each_port(other_dp, ds) 143965144067SVladimir Oltean if (other_dp->type == DSA_PORT_TYPE_CPU || 144065144067SVladimir Oltean other_dp->type == DSA_PORT_TYPE_DSA || 144141fb0cf1SVladimir Oltean dsa_port_bridge_same(dp, other_dp)) 144265144067SVladimir Oltean pvlan |= BIT(other_dp->index); 1443e5887a2aSVivien Didelot 1444e5887a2aSVivien Didelot return pvlan; 1445fad09c73SVivien Didelot } 1446e5887a2aSVivien Didelot 1447240ea3efSVivien Didelot static int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 1448e5887a2aSVivien Didelot { 1449e5887a2aSVivien Didelot u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 1450fad09c73SVivien Didelot 1451fad09c73SVivien Didelot /* prevent frames from going back out of the port they came in on */ 1452fad09c73SVivien Didelot output_ports &= ~BIT(port); 1453fad09c73SVivien Didelot 14545a7921f4SVivien Didelot return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 1455fad09c73SVivien Didelot } 1456fad09c73SVivien Didelot 1457fad09c73SVivien Didelot static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 1458fad09c73SVivien Didelot u8 state) 1459fad09c73SVivien Didelot { 146004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1461fad09c73SVivien Didelot int err; 1462fad09c73SVivien Didelot 1463c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1464f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, port, state); 1465c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1466fad09c73SVivien Didelot 1467fad09c73SVivien Didelot if (err) 1468774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to update state\n", port); 1469fad09c73SVivien Didelot } 1470fad09c73SVivien Didelot 147193e18d61SVivien Didelot static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 147293e18d61SVivien Didelot { 147393e18d61SVivien Didelot int err; 147493e18d61SVivien Didelot 147593e18d61SVivien Didelot if (chip->info->ops->ieee_pri_map) { 147693e18d61SVivien Didelot err = chip->info->ops->ieee_pri_map(chip); 147793e18d61SVivien Didelot if (err) 147893e18d61SVivien Didelot return err; 147993e18d61SVivien Didelot } 148093e18d61SVivien Didelot 148193e18d61SVivien Didelot if (chip->info->ops->ip_pri_map) { 148293e18d61SVivien Didelot err = chip->info->ops->ip_pri_map(chip); 148393e18d61SVivien Didelot if (err) 148493e18d61SVivien Didelot return err; 148593e18d61SVivien Didelot } 148693e18d61SVivien Didelot 148793e18d61SVivien Didelot return 0; 148893e18d61SVivien Didelot } 148993e18d61SVivien Didelot 1490c7f047b6SVivien Didelot static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 1491c7f047b6SVivien Didelot { 1492c5f51765SVivien Didelot struct dsa_switch *ds = chip->ds; 1493c7f047b6SVivien Didelot int target, port; 1494c7f047b6SVivien Didelot int err; 1495c7f047b6SVivien Didelot 1496c7f047b6SVivien Didelot if (!chip->info->global2_addr) 1497c7f047b6SVivien Didelot return 0; 1498c7f047b6SVivien Didelot 1499c7f047b6SVivien Didelot /* Initialize the routing port to the 32 possible target devices */ 1500c7f047b6SVivien Didelot for (target = 0; target < 32; target++) { 1501c5f51765SVivien Didelot port = dsa_routing_port(ds, target); 1502c5f51765SVivien Didelot if (port == ds->num_ports) 1503c7f047b6SVivien Didelot port = 0x1f; 1504c7f047b6SVivien Didelot 1505c7f047b6SVivien Didelot err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 1506c7f047b6SVivien Didelot if (err) 1507c7f047b6SVivien Didelot return err; 1508c7f047b6SVivien Didelot } 1509c7f047b6SVivien Didelot 151002317e68SVivien Didelot if (chip->info->ops->set_cascade_port) { 151102317e68SVivien Didelot port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 151202317e68SVivien Didelot err = chip->info->ops->set_cascade_port(chip, port); 151302317e68SVivien Didelot if (err) 151402317e68SVivien Didelot return err; 151502317e68SVivien Didelot } 151602317e68SVivien Didelot 151723c98919SVivien Didelot err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 151823c98919SVivien Didelot if (err) 151923c98919SVivien Didelot return err; 152023c98919SVivien Didelot 1521c7f047b6SVivien Didelot return 0; 1522c7f047b6SVivien Didelot } 1523c7f047b6SVivien Didelot 1524b28f872dSVivien Didelot static int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 1525b28f872dSVivien Didelot { 1526b28f872dSVivien Didelot /* Clear all trunk masks and mapping */ 1527b28f872dSVivien Didelot if (chip->info->global2_addr) 1528b28f872dSVivien Didelot return mv88e6xxx_g2_trunk_clear(chip); 1529b28f872dSVivien Didelot 1530b28f872dSVivien Didelot return 0; 1531b28f872dSVivien Didelot } 1532b28f872dSVivien Didelot 15339e5baf9bSVivien Didelot static int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 15349e5baf9bSVivien Didelot { 15359e5baf9bSVivien Didelot if (chip->info->ops->rmu_disable) 15369e5baf9bSVivien Didelot return chip->info->ops->rmu_disable(chip); 15379e5baf9bSVivien Didelot 15389e5baf9bSVivien Didelot return 0; 15399e5baf9bSVivien Didelot } 15409e5baf9bSVivien Didelot 15419e907d73SVivien Didelot static int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 15429e907d73SVivien Didelot { 15439e907d73SVivien Didelot if (chip->info->ops->pot_clear) 15449e907d73SVivien Didelot return chip->info->ops->pot_clear(chip); 15459e907d73SVivien Didelot 15469e907d73SVivien Didelot return 0; 15479e907d73SVivien Didelot } 15489e907d73SVivien Didelot 154951c901a7SVivien Didelot static int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 155051c901a7SVivien Didelot { 155151c901a7SVivien Didelot if (chip->info->ops->mgmt_rsvd2cpu) 155251c901a7SVivien Didelot return chip->info->ops->mgmt_rsvd2cpu(chip); 155351c901a7SVivien Didelot 155451c901a7SVivien Didelot return 0; 155551c901a7SVivien Didelot } 155651c901a7SVivien Didelot 1557a2ac29d2SVivien Didelot static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 1558a2ac29d2SVivien Didelot { 1559c3a7d4adSVivien Didelot int err; 1560c3a7d4adSVivien Didelot 1561daefc943SVivien Didelot err = mv88e6xxx_g1_atu_flush(chip, 0, true); 1562daefc943SVivien Didelot if (err) 1563daefc943SVivien Didelot return err; 1564daefc943SVivien Didelot 156549506a9bSRasmus Villemoes /* The chips that have a "learn2all" bit in Global1, ATU 156649506a9bSRasmus Villemoes * Control are precisely those whose port registers have a 156749506a9bSRasmus Villemoes * Message Port bit in Port Control 1 and hence implement 156849506a9bSRasmus Villemoes * ->port_setup_message_port. 156949506a9bSRasmus Villemoes */ 157049506a9bSRasmus Villemoes if (chip->info->ops->port_setup_message_port) { 1571c3a7d4adSVivien Didelot err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 1572c3a7d4adSVivien Didelot if (err) 1573c3a7d4adSVivien Didelot return err; 157449506a9bSRasmus Villemoes } 1575c3a7d4adSVivien Didelot 1576a2ac29d2SVivien Didelot return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 1577a2ac29d2SVivien Didelot } 1578a2ac29d2SVivien Didelot 1579cd8da8bbSVivien Didelot static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 1580cd8da8bbSVivien Didelot { 1581cd8da8bbSVivien Didelot int port; 1582cd8da8bbSVivien Didelot int err; 1583cd8da8bbSVivien Didelot 1584cd8da8bbSVivien Didelot if (!chip->info->ops->irl_init_all) 1585cd8da8bbSVivien Didelot return 0; 1586cd8da8bbSVivien Didelot 1587cd8da8bbSVivien Didelot for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 1588cd8da8bbSVivien Didelot /* Disable ingress rate limiting by resetting all per port 1589cd8da8bbSVivien Didelot * ingress rate limit resources to their initial state. 1590cd8da8bbSVivien Didelot */ 1591cd8da8bbSVivien Didelot err = chip->info->ops->irl_init_all(chip, port); 1592cd8da8bbSVivien Didelot if (err) 1593cd8da8bbSVivien Didelot return err; 1594cd8da8bbSVivien Didelot } 1595cd8da8bbSVivien Didelot 1596cd8da8bbSVivien Didelot return 0; 1597cd8da8bbSVivien Didelot } 1598cd8da8bbSVivien Didelot 159904a69a17SVivien Didelot static int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 160004a69a17SVivien Didelot { 160104a69a17SVivien Didelot if (chip->info->ops->set_switch_mac) { 160204a69a17SVivien Didelot u8 addr[ETH_ALEN]; 160304a69a17SVivien Didelot 160404a69a17SVivien Didelot eth_random_addr(addr); 160504a69a17SVivien Didelot 160604a69a17SVivien Didelot return chip->info->ops->set_switch_mac(chip, addr); 160704a69a17SVivien Didelot } 160804a69a17SVivien Didelot 160904a69a17SVivien Didelot return 0; 161004a69a17SVivien Didelot } 161104a69a17SVivien Didelot 161217a1594eSVivien Didelot static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 161317a1594eSVivien Didelot { 161457e661aaSTobias Waldekranz struct dsa_switch_tree *dst = chip->ds->dst; 161557e661aaSTobias Waldekranz struct dsa_switch *ds; 161657e661aaSTobias Waldekranz struct dsa_port *dp; 161717a1594eSVivien Didelot u16 pvlan = 0; 161817a1594eSVivien Didelot 161917a1594eSVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 1620d14939beSVivien Didelot return 0; 162117a1594eSVivien Didelot 162217a1594eSVivien Didelot /* Skip the local source device, which uses in-chip port VLAN */ 162357e661aaSTobias Waldekranz if (dev != chip->ds->index) { 1624aec5ac88SVivien Didelot pvlan = mv88e6xxx_port_vlan(chip, dev, port); 162517a1594eSVivien Didelot 162657e661aaSTobias Waldekranz ds = dsa_switch_find(dst->index, dev); 162757e661aaSTobias Waldekranz dp = ds ? dsa_to_port(ds, port) : NULL; 1628dedd6a00SVladimir Oltean if (dp && dp->lag) { 162957e661aaSTobias Waldekranz /* As the PVT is used to limit flooding of 163057e661aaSTobias Waldekranz * FORWARD frames, which use the LAG ID as the 163157e661aaSTobias Waldekranz * source port, we must translate dev/port to 163257e661aaSTobias Waldekranz * the special "LAG device" in the PVT, using 16333d4a0a2aSVladimir Oltean * the LAG ID (one-based) as the port number 16343d4a0a2aSVladimir Oltean * (zero-based). 163557e661aaSTobias Waldekranz */ 163678e70dbcSTobias Waldekranz dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK; 1637dedd6a00SVladimir Oltean port = dsa_port_lag_id_get(dp) - 1; 163857e661aaSTobias Waldekranz } 163957e661aaSTobias Waldekranz } 164057e661aaSTobias Waldekranz 164117a1594eSVivien Didelot return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 164217a1594eSVivien Didelot } 164317a1594eSVivien Didelot 164481228996SVivien Didelot static int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 164581228996SVivien Didelot { 164617a1594eSVivien Didelot int dev, port; 164717a1594eSVivien Didelot int err; 164817a1594eSVivien Didelot 164981228996SVivien Didelot if (!mv88e6xxx_has_pvt(chip)) 165081228996SVivien Didelot return 0; 165181228996SVivien Didelot 165281228996SVivien Didelot /* Clear 5 Bit Port for usage with Marvell Link Street devices: 165381228996SVivien Didelot * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 165481228996SVivien Didelot */ 165517a1594eSVivien Didelot err = mv88e6xxx_g2_misc_4_bit_port(chip); 165617a1594eSVivien Didelot if (err) 165717a1594eSVivien Didelot return err; 165817a1594eSVivien Didelot 165917a1594eSVivien Didelot for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 166017a1594eSVivien Didelot for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 166117a1594eSVivien Didelot err = mv88e6xxx_pvt_map(chip, dev, port); 166217a1594eSVivien Didelot if (err) 166317a1594eSVivien Didelot return err; 166417a1594eSVivien Didelot } 166517a1594eSVivien Didelot } 166617a1594eSVivien Didelot 166717a1594eSVivien Didelot return 0; 166881228996SVivien Didelot } 166981228996SVivien Didelot 1670acaf4d2eSTobias Waldekranz static int mv88e6xxx_port_fast_age_fid(struct mv88e6xxx_chip *chip, int port, 1671acaf4d2eSTobias Waldekranz u16 fid) 1672acaf4d2eSTobias Waldekranz { 1673acaf4d2eSTobias Waldekranz if (dsa_to_port(chip->ds, port)->lag) 1674acaf4d2eSTobias Waldekranz /* Hardware is incapable of fast-aging a LAG through a 1675acaf4d2eSTobias Waldekranz * regular ATU move operation. Until we have something 1676acaf4d2eSTobias Waldekranz * more fancy in place this is a no-op. 1677acaf4d2eSTobias Waldekranz */ 1678acaf4d2eSTobias Waldekranz return -EOPNOTSUPP; 1679acaf4d2eSTobias Waldekranz 1680acaf4d2eSTobias Waldekranz return mv88e6xxx_g1_atu_remove(chip, fid, port, false); 1681acaf4d2eSTobias Waldekranz } 1682acaf4d2eSTobias Waldekranz 1683749efcb8SVivien Didelot static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 1684749efcb8SVivien Didelot { 1685749efcb8SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1686749efcb8SVivien Didelot int err; 1687749efcb8SVivien Didelot 1688c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1689acaf4d2eSTobias Waldekranz err = mv88e6xxx_port_fast_age_fid(chip, port, 0); 1690c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1691749efcb8SVivien Didelot 1692749efcb8SVivien Didelot if (err) 1693acaf4d2eSTobias Waldekranz dev_err(chip->ds->dev, "p%d: failed to flush ATU: %d\n", 1694acaf4d2eSTobias Waldekranz port, err); 1695749efcb8SVivien Didelot } 1696749efcb8SVivien Didelot 1697b486d7c9SVivien Didelot static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 1698b486d7c9SVivien Didelot { 1699e545f865STobias Waldekranz if (!mv88e6xxx_max_vid(chip)) 1700b486d7c9SVivien Didelot return 0; 1701b486d7c9SVivien Didelot 1702b486d7c9SVivien Didelot return mv88e6xxx_g1_vtu_flush(chip); 1703b486d7c9SVivien Didelot } 1704b486d7c9SVivien Didelot 170534065c58STobias Waldekranz static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 1706f1394b78SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 1707f1394b78SVivien Didelot { 170834065c58STobias Waldekranz int err; 170934065c58STobias Waldekranz 1710f1394b78SVivien Didelot if (!chip->info->ops->vtu_getnext) 1711f1394b78SVivien Didelot return -EOPNOTSUPP; 1712f1394b78SVivien Didelot 171334065c58STobias Waldekranz entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip); 171434065c58STobias Waldekranz entry->valid = false; 171534065c58STobias Waldekranz 171634065c58STobias Waldekranz err = chip->info->ops->vtu_getnext(chip, entry); 171734065c58STobias Waldekranz 171834065c58STobias Waldekranz if (entry->vid != vid) 171934065c58STobias Waldekranz entry->valid = false; 172034065c58STobias Waldekranz 172134065c58STobias Waldekranz return err; 1722f1394b78SVivien Didelot } 1723f1394b78SVivien Didelot 1724d89ef4b8STobias Waldekranz static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip, 1725d89ef4b8STobias Waldekranz int (*cb)(struct mv88e6xxx_chip *chip, 1726d89ef4b8STobias Waldekranz const struct mv88e6xxx_vtu_entry *entry, 1727d89ef4b8STobias Waldekranz void *priv), 1728d89ef4b8STobias Waldekranz void *priv) 1729d89ef4b8STobias Waldekranz { 1730d89ef4b8STobias Waldekranz struct mv88e6xxx_vtu_entry entry = { 1731d89ef4b8STobias Waldekranz .vid = mv88e6xxx_max_vid(chip), 1732d89ef4b8STobias Waldekranz .valid = false, 1733d89ef4b8STobias Waldekranz }; 1734d89ef4b8STobias Waldekranz int err; 1735d89ef4b8STobias Waldekranz 1736d89ef4b8STobias Waldekranz if (!chip->info->ops->vtu_getnext) 1737d89ef4b8STobias Waldekranz return -EOPNOTSUPP; 1738d89ef4b8STobias Waldekranz 1739d89ef4b8STobias Waldekranz do { 1740d89ef4b8STobias Waldekranz err = chip->info->ops->vtu_getnext(chip, &entry); 1741d89ef4b8STobias Waldekranz if (err) 1742d89ef4b8STobias Waldekranz return err; 1743d89ef4b8STobias Waldekranz 1744d89ef4b8STobias Waldekranz if (!entry.valid) 1745d89ef4b8STobias Waldekranz break; 1746d89ef4b8STobias Waldekranz 1747d89ef4b8STobias Waldekranz err = cb(chip, &entry, priv); 1748d89ef4b8STobias Waldekranz if (err) 1749d89ef4b8STobias Waldekranz return err; 1750d89ef4b8STobias Waldekranz } while (entry.vid < mv88e6xxx_max_vid(chip)); 1751d89ef4b8STobias Waldekranz 1752d89ef4b8STobias Waldekranz return 0; 1753d89ef4b8STobias Waldekranz } 1754d89ef4b8STobias Waldekranz 17550ad5daf6SVivien Didelot static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 17560ad5daf6SVivien Didelot struct mv88e6xxx_vtu_entry *entry) 17570ad5daf6SVivien Didelot { 17580ad5daf6SVivien Didelot if (!chip->info->ops->vtu_loadpurge) 17590ad5daf6SVivien Didelot return -EOPNOTSUPP; 17600ad5daf6SVivien Didelot 17610ad5daf6SVivien Didelot return chip->info->ops->vtu_loadpurge(chip, entry); 17620ad5daf6SVivien Didelot } 17630ad5daf6SVivien Didelot 1764d89ef4b8STobias Waldekranz static int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip, 1765d89ef4b8STobias Waldekranz const struct mv88e6xxx_vtu_entry *entry, 1766d89ef4b8STobias Waldekranz void *_fid_bitmap) 1767d89ef4b8STobias Waldekranz { 1768d89ef4b8STobias Waldekranz unsigned long *fid_bitmap = _fid_bitmap; 1769d89ef4b8STobias Waldekranz 1770d89ef4b8STobias Waldekranz set_bit(entry->fid, fid_bitmap); 1771d89ef4b8STobias Waldekranz return 0; 1772d89ef4b8STobias Waldekranz } 1773d89ef4b8STobias Waldekranz 177490b6dbdfSAndrew Lunn int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap) 1775fad09c73SVivien Didelot { 1776fad09c73SVivien Didelot bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 1777fad09c73SVivien Didelot 1778d352b20fSTobias Waldekranz /* Every FID has an associated VID, so walking the VTU 1779d352b20fSTobias Waldekranz * will discover the full set of FIDs in use. 1780d352b20fSTobias Waldekranz */ 1781d89ef4b8STobias Waldekranz return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap); 178290b6dbdfSAndrew Lunn } 178390b6dbdfSAndrew Lunn 178490b6dbdfSAndrew Lunn static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 178590b6dbdfSAndrew Lunn { 178690b6dbdfSAndrew Lunn DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 178790b6dbdfSAndrew Lunn int err; 178890b6dbdfSAndrew Lunn 178990b6dbdfSAndrew Lunn err = mv88e6xxx_fid_map(chip, fid_bitmap); 179090b6dbdfSAndrew Lunn if (err) 179190b6dbdfSAndrew Lunn return err; 179290b6dbdfSAndrew Lunn 1793d352b20fSTobias Waldekranz *fid = find_first_zero_bit(fid_bitmap, MV88E6XXX_N_FID); 1794fad09c73SVivien Didelot if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 1795fad09c73SVivien Didelot return -ENOSPC; 1796fad09c73SVivien Didelot 1797fad09c73SVivien Didelot /* Clear the database */ 1798daefc943SVivien Didelot return mv88e6xxx_g1_atu_flush(chip, *fid, true); 1799fad09c73SVivien Didelot } 1800fad09c73SVivien Didelot 180149c98c1dSTobias Waldekranz static int mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip, 180249c98c1dSTobias Waldekranz struct mv88e6xxx_stu_entry *entry) 180349c98c1dSTobias Waldekranz { 180449c98c1dSTobias Waldekranz if (!chip->info->ops->stu_loadpurge) 180549c98c1dSTobias Waldekranz return -EOPNOTSUPP; 180649c98c1dSTobias Waldekranz 180749c98c1dSTobias Waldekranz return chip->info->ops->stu_loadpurge(chip, entry); 180849c98c1dSTobias Waldekranz } 180949c98c1dSTobias Waldekranz 181049c98c1dSTobias Waldekranz static int mv88e6xxx_stu_setup(struct mv88e6xxx_chip *chip) 181149c98c1dSTobias Waldekranz { 181249c98c1dSTobias Waldekranz struct mv88e6xxx_stu_entry stu = { 181349c98c1dSTobias Waldekranz .valid = true, 181449c98c1dSTobias Waldekranz .sid = 0 181549c98c1dSTobias Waldekranz }; 181649c98c1dSTobias Waldekranz 181749c98c1dSTobias Waldekranz if (!mv88e6xxx_has_stu(chip)) 181849c98c1dSTobias Waldekranz return 0; 181949c98c1dSTobias Waldekranz 182049c98c1dSTobias Waldekranz /* Make sure that SID 0 is always valid. This is used by VTU 182149c98c1dSTobias Waldekranz * entries that do not make use of the STU, e.g. when creating 182249c98c1dSTobias Waldekranz * a VLAN upper on a port that is also part of a VLAN 182349c98c1dSTobias Waldekranz * filtering bridge. 182449c98c1dSTobias Waldekranz */ 182549c98c1dSTobias Waldekranz return mv88e6xxx_stu_loadpurge(chip, &stu); 182649c98c1dSTobias Waldekranz } 182749c98c1dSTobias Waldekranz 1828acaf4d2eSTobias Waldekranz static int mv88e6xxx_sid_get(struct mv88e6xxx_chip *chip, u8 *sid) 1829acaf4d2eSTobias Waldekranz { 1830acaf4d2eSTobias Waldekranz DECLARE_BITMAP(busy, MV88E6XXX_N_SID) = { 0 }; 1831acaf4d2eSTobias Waldekranz struct mv88e6xxx_mst *mst; 1832acaf4d2eSTobias Waldekranz 1833acaf4d2eSTobias Waldekranz __set_bit(0, busy); 1834acaf4d2eSTobias Waldekranz 1835acaf4d2eSTobias Waldekranz list_for_each_entry(mst, &chip->msts, node) 1836acaf4d2eSTobias Waldekranz __set_bit(mst->stu.sid, busy); 1837acaf4d2eSTobias Waldekranz 1838acaf4d2eSTobias Waldekranz *sid = find_first_zero_bit(busy, MV88E6XXX_N_SID); 1839acaf4d2eSTobias Waldekranz 1840acaf4d2eSTobias Waldekranz return (*sid >= mv88e6xxx_max_sid(chip)) ? -ENOSPC : 0; 1841acaf4d2eSTobias Waldekranz } 1842acaf4d2eSTobias Waldekranz 1843acaf4d2eSTobias Waldekranz static int mv88e6xxx_mst_put(struct mv88e6xxx_chip *chip, u8 sid) 1844acaf4d2eSTobias Waldekranz { 1845acaf4d2eSTobias Waldekranz struct mv88e6xxx_mst *mst, *tmp; 1846acaf4d2eSTobias Waldekranz int err; 1847acaf4d2eSTobias Waldekranz 1848acaf4d2eSTobias Waldekranz if (!sid) 1849acaf4d2eSTobias Waldekranz return 0; 1850acaf4d2eSTobias Waldekranz 1851acaf4d2eSTobias Waldekranz list_for_each_entry_safe(mst, tmp, &chip->msts, node) { 1852acaf4d2eSTobias Waldekranz if (mst->stu.sid != sid) 1853acaf4d2eSTobias Waldekranz continue; 1854acaf4d2eSTobias Waldekranz 1855acaf4d2eSTobias Waldekranz if (!refcount_dec_and_test(&mst->refcnt)) 1856acaf4d2eSTobias Waldekranz return 0; 1857acaf4d2eSTobias Waldekranz 1858acaf4d2eSTobias Waldekranz mst->stu.valid = false; 1859acaf4d2eSTobias Waldekranz err = mv88e6xxx_stu_loadpurge(chip, &mst->stu); 1860acaf4d2eSTobias Waldekranz if (err) { 1861acaf4d2eSTobias Waldekranz refcount_set(&mst->refcnt, 1); 1862acaf4d2eSTobias Waldekranz return err; 1863acaf4d2eSTobias Waldekranz } 1864acaf4d2eSTobias Waldekranz 1865acaf4d2eSTobias Waldekranz list_del(&mst->node); 1866acaf4d2eSTobias Waldekranz kfree(mst); 1867acaf4d2eSTobias Waldekranz return 0; 1868acaf4d2eSTobias Waldekranz } 1869acaf4d2eSTobias Waldekranz 1870acaf4d2eSTobias Waldekranz return -ENOENT; 1871acaf4d2eSTobias Waldekranz } 1872acaf4d2eSTobias Waldekranz 1873acaf4d2eSTobias Waldekranz static int mv88e6xxx_mst_get(struct mv88e6xxx_chip *chip, struct net_device *br, 1874acaf4d2eSTobias Waldekranz u16 msti, u8 *sid) 1875acaf4d2eSTobias Waldekranz { 1876acaf4d2eSTobias Waldekranz struct mv88e6xxx_mst *mst; 1877acaf4d2eSTobias Waldekranz int err, i; 1878acaf4d2eSTobias Waldekranz 1879acaf4d2eSTobias Waldekranz if (!mv88e6xxx_has_stu(chip)) { 1880acaf4d2eSTobias Waldekranz err = -EOPNOTSUPP; 1881acaf4d2eSTobias Waldekranz goto err; 1882acaf4d2eSTobias Waldekranz } 1883acaf4d2eSTobias Waldekranz 1884acaf4d2eSTobias Waldekranz if (!msti) { 1885acaf4d2eSTobias Waldekranz *sid = 0; 1886acaf4d2eSTobias Waldekranz return 0; 1887acaf4d2eSTobias Waldekranz } 1888acaf4d2eSTobias Waldekranz 1889acaf4d2eSTobias Waldekranz list_for_each_entry(mst, &chip->msts, node) { 1890acaf4d2eSTobias Waldekranz if (mst->br == br && mst->msti == msti) { 1891acaf4d2eSTobias Waldekranz refcount_inc(&mst->refcnt); 1892acaf4d2eSTobias Waldekranz *sid = mst->stu.sid; 1893acaf4d2eSTobias Waldekranz return 0; 1894acaf4d2eSTobias Waldekranz } 1895acaf4d2eSTobias Waldekranz } 1896acaf4d2eSTobias Waldekranz 1897acaf4d2eSTobias Waldekranz err = mv88e6xxx_sid_get(chip, sid); 1898acaf4d2eSTobias Waldekranz if (err) 1899acaf4d2eSTobias Waldekranz goto err; 1900acaf4d2eSTobias Waldekranz 1901acaf4d2eSTobias Waldekranz mst = kzalloc(sizeof(*mst), GFP_KERNEL); 1902acaf4d2eSTobias Waldekranz if (!mst) { 1903acaf4d2eSTobias Waldekranz err = -ENOMEM; 1904acaf4d2eSTobias Waldekranz goto err; 1905acaf4d2eSTobias Waldekranz } 1906acaf4d2eSTobias Waldekranz 1907acaf4d2eSTobias Waldekranz INIT_LIST_HEAD(&mst->node); 1908acaf4d2eSTobias Waldekranz refcount_set(&mst->refcnt, 1); 1909acaf4d2eSTobias Waldekranz mst->br = br; 1910acaf4d2eSTobias Waldekranz mst->msti = msti; 1911acaf4d2eSTobias Waldekranz mst->stu.valid = true; 1912acaf4d2eSTobias Waldekranz mst->stu.sid = *sid; 1913acaf4d2eSTobias Waldekranz 1914acaf4d2eSTobias Waldekranz /* The bridge starts out all ports in the disabled state. But 1915acaf4d2eSTobias Waldekranz * a STU state of disabled means to go by the port-global 1916acaf4d2eSTobias Waldekranz * state. So we set all user port's initial state to blocking, 1917acaf4d2eSTobias Waldekranz * to match the bridge's behavior. 1918acaf4d2eSTobias Waldekranz */ 1919acaf4d2eSTobias Waldekranz for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 1920acaf4d2eSTobias Waldekranz mst->stu.state[i] = dsa_is_user_port(chip->ds, i) ? 1921acaf4d2eSTobias Waldekranz MV88E6XXX_PORT_CTL0_STATE_BLOCKING : 1922acaf4d2eSTobias Waldekranz MV88E6XXX_PORT_CTL0_STATE_DISABLED; 1923acaf4d2eSTobias Waldekranz 1924acaf4d2eSTobias Waldekranz err = mv88e6xxx_stu_loadpurge(chip, &mst->stu); 1925acaf4d2eSTobias Waldekranz if (err) 1926acaf4d2eSTobias Waldekranz goto err_free; 1927acaf4d2eSTobias Waldekranz 1928acaf4d2eSTobias Waldekranz list_add_tail(&mst->node, &chip->msts); 1929acaf4d2eSTobias Waldekranz return 0; 1930acaf4d2eSTobias Waldekranz 1931acaf4d2eSTobias Waldekranz err_free: 1932acaf4d2eSTobias Waldekranz kfree(mst); 1933acaf4d2eSTobias Waldekranz err: 1934acaf4d2eSTobias Waldekranz return err; 1935acaf4d2eSTobias Waldekranz } 1936acaf4d2eSTobias Waldekranz 1937acaf4d2eSTobias Waldekranz static int mv88e6xxx_port_mst_state_set(struct dsa_switch *ds, int port, 1938acaf4d2eSTobias Waldekranz const struct switchdev_mst_state *st) 1939acaf4d2eSTobias Waldekranz { 1940acaf4d2eSTobias Waldekranz struct dsa_port *dp = dsa_to_port(ds, port); 1941acaf4d2eSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 1942acaf4d2eSTobias Waldekranz struct mv88e6xxx_mst *mst; 1943acaf4d2eSTobias Waldekranz u8 state; 1944acaf4d2eSTobias Waldekranz int err; 1945acaf4d2eSTobias Waldekranz 1946acaf4d2eSTobias Waldekranz if (!mv88e6xxx_has_stu(chip)) 1947acaf4d2eSTobias Waldekranz return -EOPNOTSUPP; 1948acaf4d2eSTobias Waldekranz 1949acaf4d2eSTobias Waldekranz switch (st->state) { 1950acaf4d2eSTobias Waldekranz case BR_STATE_DISABLED: 1951acaf4d2eSTobias Waldekranz case BR_STATE_BLOCKING: 1952acaf4d2eSTobias Waldekranz case BR_STATE_LISTENING: 1953acaf4d2eSTobias Waldekranz state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; 1954acaf4d2eSTobias Waldekranz break; 1955acaf4d2eSTobias Waldekranz case BR_STATE_LEARNING: 1956acaf4d2eSTobias Waldekranz state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; 1957acaf4d2eSTobias Waldekranz break; 1958acaf4d2eSTobias Waldekranz case BR_STATE_FORWARDING: 1959acaf4d2eSTobias Waldekranz state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 1960acaf4d2eSTobias Waldekranz break; 1961acaf4d2eSTobias Waldekranz default: 1962acaf4d2eSTobias Waldekranz return -EINVAL; 1963acaf4d2eSTobias Waldekranz } 1964acaf4d2eSTobias Waldekranz 1965acaf4d2eSTobias Waldekranz list_for_each_entry(mst, &chip->msts, node) { 1966acaf4d2eSTobias Waldekranz if (mst->br == dsa_port_bridge_dev_get(dp) && 1967acaf4d2eSTobias Waldekranz mst->msti == st->msti) { 1968acaf4d2eSTobias Waldekranz if (mst->stu.state[port] == state) 1969acaf4d2eSTobias Waldekranz return 0; 1970acaf4d2eSTobias Waldekranz 1971acaf4d2eSTobias Waldekranz mst->stu.state[port] = state; 1972acaf4d2eSTobias Waldekranz mv88e6xxx_reg_lock(chip); 1973acaf4d2eSTobias Waldekranz err = mv88e6xxx_stu_loadpurge(chip, &mst->stu); 1974acaf4d2eSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 1975acaf4d2eSTobias Waldekranz return err; 1976acaf4d2eSTobias Waldekranz } 1977acaf4d2eSTobias Waldekranz } 1978acaf4d2eSTobias Waldekranz 1979acaf4d2eSTobias Waldekranz return -ENOENT; 1980acaf4d2eSTobias Waldekranz } 1981acaf4d2eSTobias Waldekranz 1982fad09c73SVivien Didelot static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 1983b7a9e0daSVladimir Oltean u16 vid) 1984fad09c73SVivien Didelot { 19850493fa79SVladimir Oltean struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; 198604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 1987425d2d37SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 19880493fa79SVladimir Oltean int err; 1989fad09c73SVivien Didelot 1990db06ae41SAndrew Lunn /* DSA and CPU ports have to be members of multiple vlans */ 19910493fa79SVladimir Oltean if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) 1992db06ae41SAndrew Lunn return 0; 1993db06ae41SAndrew Lunn 199434065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 1995fad09c73SVivien Didelot if (err) 19967095a4c4SVivien Didelot return err; 1997fad09c73SVivien Didelot 1998fad09c73SVivien Didelot if (!vlan.valid) 1999b7a9e0daSVladimir Oltean return 0; 2000fad09c73SVivien Didelot 20010493fa79SVladimir Oltean dsa_switch_for_each_user_port(other_dp, ds) { 200241fb0cf1SVladimir Oltean struct net_device *other_br; 200341fb0cf1SVladimir Oltean 20040493fa79SVladimir Oltean if (vlan.member[other_dp->index] == 20057ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 2006fad09c73SVivien Didelot continue; 2007fad09c73SVivien Didelot 200841fb0cf1SVladimir Oltean if (dsa_port_bridge_same(dp, other_dp)) 2009fad09c73SVivien Didelot break; /* same bridge, check next VLAN */ 2010fad09c73SVivien Didelot 201141fb0cf1SVladimir Oltean other_br = dsa_port_bridge_dev_get(other_dp); 201241fb0cf1SVladimir Oltean if (!other_br) 201366e2809dSAndrew Lunn continue; 201466e2809dSAndrew Lunn 2015743fcc28SAndrew Lunn dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 201641fb0cf1SVladimir Oltean port, vlan.vid, other_dp->index, netdev_name(other_br)); 20177095a4c4SVivien Didelot return -EOPNOTSUPP; 2018fad09c73SVivien Didelot } 2019fad09c73SVivien Didelot 20207095a4c4SVivien Didelot return 0; 2021fad09c73SVivien Didelot } 2022fad09c73SVivien Didelot 20238b6836d8SVladimir Oltean static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port) 20248b6836d8SVladimir Oltean { 20258b6836d8SVladimir Oltean struct dsa_port *dp = dsa_to_port(chip->ds, port); 202641fb0cf1SVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 20278b6836d8SVladimir Oltean struct mv88e6xxx_port *p = &chip->ports[port]; 20285bded825SVladimir Oltean u16 pvid = MV88E6XXX_VID_STANDALONE; 20298b6836d8SVladimir Oltean bool drop_untagged = false; 20308b6836d8SVladimir Oltean int err; 20318b6836d8SVladimir Oltean 203241fb0cf1SVladimir Oltean if (br) { 203341fb0cf1SVladimir Oltean if (br_vlan_enabled(br)) { 20348b6836d8SVladimir Oltean pvid = p->bridge_pvid.vid; 20358b6836d8SVladimir Oltean drop_untagged = !p->bridge_pvid.valid; 20365bded825SVladimir Oltean } else { 20375bded825SVladimir Oltean pvid = MV88E6XXX_VID_BRIDGED; 20385bded825SVladimir Oltean } 20398b6836d8SVladimir Oltean } 20408b6836d8SVladimir Oltean 20418b6836d8SVladimir Oltean err = mv88e6xxx_port_set_pvid(chip, port, pvid); 20428b6836d8SVladimir Oltean if (err) 20438b6836d8SVladimir Oltean return err; 20448b6836d8SVladimir Oltean 20458b6836d8SVladimir Oltean return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged); 20468b6836d8SVladimir Oltean } 20478b6836d8SVladimir Oltean 2048fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 204989153ed6SVladimir Oltean bool vlan_filtering, 205089153ed6SVladimir Oltean struct netlink_ext_ack *extack) 2051fad09c73SVivien Didelot { 205204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 205381c6edb2SVivien Didelot u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 205481c6edb2SVivien Didelot MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 20550e7b9925SAndrew Lunn int err; 2056fad09c73SVivien Didelot 2057bae33f2bSVladimir Oltean if (!mv88e6xxx_max_vid(chip)) 2058bae33f2bSVladimir Oltean return -EOPNOTSUPP; 2059fad09c73SVivien Didelot 2060c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 20618b6836d8SVladimir Oltean 2062385a0995SVivien Didelot err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 20638b6836d8SVladimir Oltean if (err) 20648b6836d8SVladimir Oltean goto unlock; 20658b6836d8SVladimir Oltean 20668b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 20678b6836d8SVladimir Oltean if (err) 20688b6836d8SVladimir Oltean goto unlock; 20698b6836d8SVladimir Oltean 20708b6836d8SVladimir Oltean unlock: 2071c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2072fad09c73SVivien Didelot 20730e7b9925SAndrew Lunn return err; 2074fad09c73SVivien Didelot } 2075fad09c73SVivien Didelot 2076fad09c73SVivien Didelot static int 2077fad09c73SVivien Didelot mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 207880e02360SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 2079fad09c73SVivien Didelot { 208004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2081fad09c73SVivien Didelot int err; 2082fad09c73SVivien Didelot 2083e545f865STobias Waldekranz if (!mv88e6xxx_max_vid(chip)) 2084fad09c73SVivien Didelot return -EOPNOTSUPP; 2085fad09c73SVivien Didelot 2086fad09c73SVivien Didelot /* If the requested port doesn't belong to the same bridge as the VLAN 2087fad09c73SVivien Didelot * members, do not support it (yet) and fallback to software VLAN. 2088fad09c73SVivien Didelot */ 20897095a4c4SVivien Didelot mv88e6xxx_reg_lock(chip); 2090b7a9e0daSVladimir Oltean err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid); 20917095a4c4SVivien Didelot mv88e6xxx_reg_unlock(chip); 2092fad09c73SVivien Didelot 20937095a4c4SVivien Didelot return err; 2094fad09c73SVivien Didelot } 2095fad09c73SVivien Didelot 2096a4c93ae1SAndrew Lunn static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 2097a4c93ae1SAndrew Lunn const unsigned char *addr, u16 vid, 2098a4c93ae1SAndrew Lunn u8 state) 2099a4c93ae1SAndrew Lunn { 2100a4c93ae1SAndrew Lunn struct mv88e6xxx_atu_entry entry; 21015ef8d249SVivien Didelot struct mv88e6xxx_vtu_entry vlan; 21025ef8d249SVivien Didelot u16 fid; 2103a4c93ae1SAndrew Lunn int err; 2104a4c93ae1SAndrew Lunn 21055bded825SVladimir Oltean /* Ports have two private address databases: one for when the port is 21065bded825SVladimir Oltean * standalone and one for when the port is under a bridge and the 21075bded825SVladimir Oltean * 802.1Q mode is disabled. When the port is standalone, DSA wants its 21085bded825SVladimir Oltean * address database to remain 100% empty, so we never load an ATU entry 21095bded825SVladimir Oltean * into a standalone port's database. Therefore, translate the null 21105bded825SVladimir Oltean * VLAN ID into the port's database used for VLAN-unaware bridging. 21115bded825SVladimir Oltean */ 21125ef8d249SVivien Didelot if (vid == 0) { 21135bded825SVladimir Oltean fid = MV88E6XXX_FID_BRIDGED; 21145ef8d249SVivien Didelot } else { 211534065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 21165ef8d249SVivien Didelot if (err) 21175ef8d249SVivien Didelot return err; 21185ef8d249SVivien Didelot 21195ef8d249SVivien Didelot /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 212034065c58STobias Waldekranz if (!vlan.valid) 21215ef8d249SVivien Didelot return -EOPNOTSUPP; 21225ef8d249SVivien Didelot 21235ef8d249SVivien Didelot fid = vlan.fid; 21245ef8d249SVivien Didelot } 2125a4c93ae1SAndrew Lunn 2126d8291a95SVivien Didelot entry.state = 0; 2127a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 2128a4c93ae1SAndrew Lunn eth_addr_dec(entry.mac); 2129a4c93ae1SAndrew Lunn 21305ef8d249SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry); 2131a4c93ae1SAndrew Lunn if (err) 2132a4c93ae1SAndrew Lunn return err; 2133a4c93ae1SAndrew Lunn 2134a4c93ae1SAndrew Lunn /* Initialize a fresh ATU entry if it isn't found */ 2135d8291a95SVivien Didelot if (!entry.state || !ether_addr_equal(entry.mac, addr)) { 2136a4c93ae1SAndrew Lunn memset(&entry, 0, sizeof(entry)); 2137a4c93ae1SAndrew Lunn ether_addr_copy(entry.mac, addr); 2138a4c93ae1SAndrew Lunn } 2139a4c93ae1SAndrew Lunn 2140a4c93ae1SAndrew Lunn /* Purge the ATU entry only if no port is using it anymore */ 2141d8291a95SVivien Didelot if (!state) { 2142a4c93ae1SAndrew Lunn entry.portvec &= ~BIT(port); 2143a4c93ae1SAndrew Lunn if (!entry.portvec) 2144d8291a95SVivien Didelot entry.state = 0; 2145a4c93ae1SAndrew Lunn } else { 2146f72f2fb8SDENG Qingfang if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC) 2147f72f2fb8SDENG Qingfang entry.portvec = BIT(port); 2148f72f2fb8SDENG Qingfang else 2149a4c93ae1SAndrew Lunn entry.portvec |= BIT(port); 2150f72f2fb8SDENG Qingfang 2151a4c93ae1SAndrew Lunn entry.state = state; 2152a4c93ae1SAndrew Lunn } 2153a4c93ae1SAndrew Lunn 21545ef8d249SVivien Didelot return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry); 2155a4c93ae1SAndrew Lunn } 2156a4c93ae1SAndrew Lunn 2157da7dc875SVivien Didelot static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port, 2158da7dc875SVivien Didelot const struct mv88e6xxx_policy *policy) 2159da7dc875SVivien Didelot { 2160da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping = policy->mapping; 2161da7dc875SVivien Didelot enum mv88e6xxx_policy_action action = policy->action; 2162da7dc875SVivien Didelot const u8 *addr = policy->addr; 2163da7dc875SVivien Didelot u16 vid = policy->vid; 2164da7dc875SVivien Didelot u8 state; 2165da7dc875SVivien Didelot int err; 2166da7dc875SVivien Didelot int id; 2167da7dc875SVivien Didelot 2168da7dc875SVivien Didelot if (!chip->info->ops->port_set_policy) 2169da7dc875SVivien Didelot return -EOPNOTSUPP; 2170da7dc875SVivien Didelot 2171da7dc875SVivien Didelot switch (mapping) { 2172da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_DA: 2173da7dc875SVivien Didelot case MV88E6XXX_POLICY_MAPPING_SA: 2174da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 2175da7dc875SVivien Didelot state = 0; /* Dissociate the port and address */ 2176da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 2177da7dc875SVivien Didelot is_multicast_ether_addr(addr)) 2178da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY; 2179da7dc875SVivien Didelot else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 2180da7dc875SVivien Didelot is_unicast_ether_addr(addr)) 2181da7dc875SVivien Didelot state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY; 2182da7dc875SVivien Didelot else 2183da7dc875SVivien Didelot return -EOPNOTSUPP; 2184da7dc875SVivien Didelot 2185da7dc875SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 2186da7dc875SVivien Didelot state); 2187da7dc875SVivien Didelot if (err) 2188da7dc875SVivien Didelot return err; 2189da7dc875SVivien Didelot break; 2190da7dc875SVivien Didelot default: 2191da7dc875SVivien Didelot return -EOPNOTSUPP; 2192da7dc875SVivien Didelot } 2193da7dc875SVivien Didelot 2194da7dc875SVivien Didelot /* Skip the port's policy clearing if the mapping is still in use */ 2195da7dc875SVivien Didelot if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 2196da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 2197da7dc875SVivien Didelot if (policy->port == port && 2198da7dc875SVivien Didelot policy->mapping == mapping && 2199da7dc875SVivien Didelot policy->action != action) 2200da7dc875SVivien Didelot return 0; 2201da7dc875SVivien Didelot 2202da7dc875SVivien Didelot return chip->info->ops->port_set_policy(chip, port, mapping, action); 2203da7dc875SVivien Didelot } 2204da7dc875SVivien Didelot 2205da7dc875SVivien Didelot static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port, 2206da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs) 2207da7dc875SVivien Didelot { 2208da7dc875SVivien Didelot struct ethhdr *mac_entry = &fs->h_u.ether_spec; 2209da7dc875SVivien Didelot struct ethhdr *mac_mask = &fs->m_u.ether_spec; 2210da7dc875SVivien Didelot enum mv88e6xxx_policy_mapping mapping; 2211da7dc875SVivien Didelot enum mv88e6xxx_policy_action action; 2212da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 2213da7dc875SVivien Didelot u16 vid = 0; 2214da7dc875SVivien Didelot u8 *addr; 2215da7dc875SVivien Didelot int err; 2216da7dc875SVivien Didelot int id; 2217da7dc875SVivien Didelot 2218da7dc875SVivien Didelot if (fs->location != RX_CLS_LOC_ANY) 2219da7dc875SVivien Didelot return -EINVAL; 2220da7dc875SVivien Didelot 2221da7dc875SVivien Didelot if (fs->ring_cookie == RX_CLS_FLOW_DISC) 2222da7dc875SVivien Didelot action = MV88E6XXX_POLICY_ACTION_DISCARD; 2223da7dc875SVivien Didelot else 2224da7dc875SVivien Didelot return -EOPNOTSUPP; 2225da7dc875SVivien Didelot 2226da7dc875SVivien Didelot switch (fs->flow_type & ~FLOW_EXT) { 2227da7dc875SVivien Didelot case ETHER_FLOW: 2228da7dc875SVivien Didelot if (!is_zero_ether_addr(mac_mask->h_dest) && 2229da7dc875SVivien Didelot is_zero_ether_addr(mac_mask->h_source)) { 2230da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_DA; 2231da7dc875SVivien Didelot addr = mac_entry->h_dest; 2232da7dc875SVivien Didelot } else if (is_zero_ether_addr(mac_mask->h_dest) && 2233da7dc875SVivien Didelot !is_zero_ether_addr(mac_mask->h_source)) { 2234da7dc875SVivien Didelot mapping = MV88E6XXX_POLICY_MAPPING_SA; 2235da7dc875SVivien Didelot addr = mac_entry->h_source; 2236da7dc875SVivien Didelot } else { 2237da7dc875SVivien Didelot /* Cannot support DA and SA mapping in the same rule */ 2238da7dc875SVivien Didelot return -EOPNOTSUPP; 2239da7dc875SVivien Didelot } 2240da7dc875SVivien Didelot break; 2241da7dc875SVivien Didelot default: 2242da7dc875SVivien Didelot return -EOPNOTSUPP; 2243da7dc875SVivien Didelot } 2244da7dc875SVivien Didelot 2245da7dc875SVivien Didelot if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) { 224604844280SAndrew Lunn if (fs->m_ext.vlan_tci != htons(0xffff)) 2247da7dc875SVivien Didelot return -EOPNOTSUPP; 2248da7dc875SVivien Didelot vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; 2249da7dc875SVivien Didelot } 2250da7dc875SVivien Didelot 2251da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) { 2252da7dc875SVivien Didelot if (policy->port == port && policy->mapping == mapping && 2253da7dc875SVivien Didelot policy->action == action && policy->vid == vid && 2254da7dc875SVivien Didelot ether_addr_equal(policy->addr, addr)) 2255da7dc875SVivien Didelot return -EEXIST; 2256da7dc875SVivien Didelot } 2257da7dc875SVivien Didelot 2258da7dc875SVivien Didelot policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL); 2259da7dc875SVivien Didelot if (!policy) 2260da7dc875SVivien Didelot return -ENOMEM; 2261da7dc875SVivien Didelot 2262da7dc875SVivien Didelot fs->location = 0; 2263da7dc875SVivien Didelot err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff, 2264da7dc875SVivien Didelot GFP_KERNEL); 2265da7dc875SVivien Didelot if (err) { 2266da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 2267da7dc875SVivien Didelot return err; 2268da7dc875SVivien Didelot } 2269da7dc875SVivien Didelot 2270da7dc875SVivien Didelot memcpy(&policy->fs, fs, sizeof(*fs)); 2271da7dc875SVivien Didelot ether_addr_copy(policy->addr, addr); 2272da7dc875SVivien Didelot policy->mapping = mapping; 2273da7dc875SVivien Didelot policy->action = action; 2274da7dc875SVivien Didelot policy->port = port; 2275da7dc875SVivien Didelot policy->vid = vid; 2276da7dc875SVivien Didelot 2277da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 2278da7dc875SVivien Didelot if (err) { 2279da7dc875SVivien Didelot idr_remove(&chip->policies, fs->location); 2280da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 2281da7dc875SVivien Didelot return err; 2282da7dc875SVivien Didelot } 2283da7dc875SVivien Didelot 2284da7dc875SVivien Didelot return 0; 2285da7dc875SVivien Didelot } 2286da7dc875SVivien Didelot 2287da7dc875SVivien Didelot static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, 2288da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 2289da7dc875SVivien Didelot { 2290da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 2291da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2292da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 2293da7dc875SVivien Didelot int err; 2294da7dc875SVivien Didelot int id; 2295da7dc875SVivien Didelot 2296da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 2297da7dc875SVivien Didelot 2298da7dc875SVivien Didelot switch (rxnfc->cmd) { 2299da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLCNT: 2300da7dc875SVivien Didelot rxnfc->data = 0; 2301da7dc875SVivien Didelot rxnfc->data |= RX_CLS_LOC_SPECIAL; 2302da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 2303da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 2304da7dc875SVivien Didelot if (policy->port == port) 2305da7dc875SVivien Didelot rxnfc->rule_cnt++; 2306da7dc875SVivien Didelot err = 0; 2307da7dc875SVivien Didelot break; 2308da7dc875SVivien Didelot case ETHTOOL_GRXCLSRULE: 2309da7dc875SVivien Didelot err = -ENOENT; 2310da7dc875SVivien Didelot policy = idr_find(&chip->policies, fs->location); 2311da7dc875SVivien Didelot if (policy) { 2312da7dc875SVivien Didelot memcpy(fs, &policy->fs, sizeof(*fs)); 2313da7dc875SVivien Didelot err = 0; 2314da7dc875SVivien Didelot } 2315da7dc875SVivien Didelot break; 2316da7dc875SVivien Didelot case ETHTOOL_GRXCLSRLALL: 2317da7dc875SVivien Didelot rxnfc->data = 0; 2318da7dc875SVivien Didelot rxnfc->rule_cnt = 0; 2319da7dc875SVivien Didelot idr_for_each_entry(&chip->policies, policy, id) 2320da7dc875SVivien Didelot if (policy->port == port) 2321da7dc875SVivien Didelot rule_locs[rxnfc->rule_cnt++] = id; 2322da7dc875SVivien Didelot err = 0; 2323da7dc875SVivien Didelot break; 2324da7dc875SVivien Didelot default: 2325da7dc875SVivien Didelot err = -EOPNOTSUPP; 2326da7dc875SVivien Didelot break; 2327da7dc875SVivien Didelot } 2328da7dc875SVivien Didelot 2329da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 2330da7dc875SVivien Didelot 2331da7dc875SVivien Didelot return err; 2332da7dc875SVivien Didelot } 2333da7dc875SVivien Didelot 2334da7dc875SVivien Didelot static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, 2335da7dc875SVivien Didelot struct ethtool_rxnfc *rxnfc) 2336da7dc875SVivien Didelot { 2337da7dc875SVivien Didelot struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 2338da7dc875SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2339da7dc875SVivien Didelot struct mv88e6xxx_policy *policy; 2340da7dc875SVivien Didelot int err; 2341da7dc875SVivien Didelot 2342da7dc875SVivien Didelot mv88e6xxx_reg_lock(chip); 2343da7dc875SVivien Didelot 2344da7dc875SVivien Didelot switch (rxnfc->cmd) { 2345da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLINS: 2346da7dc875SVivien Didelot err = mv88e6xxx_policy_insert(chip, port, fs); 2347da7dc875SVivien Didelot break; 2348da7dc875SVivien Didelot case ETHTOOL_SRXCLSRLDEL: 2349da7dc875SVivien Didelot err = -ENOENT; 2350da7dc875SVivien Didelot policy = idr_remove(&chip->policies, fs->location); 2351da7dc875SVivien Didelot if (policy) { 2352da7dc875SVivien Didelot policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; 2353da7dc875SVivien Didelot err = mv88e6xxx_policy_apply(chip, port, policy); 2354da7dc875SVivien Didelot devm_kfree(chip->dev, policy); 2355da7dc875SVivien Didelot } 2356da7dc875SVivien Didelot break; 2357da7dc875SVivien Didelot default: 2358da7dc875SVivien Didelot err = -EOPNOTSUPP; 2359da7dc875SVivien Didelot break; 2360da7dc875SVivien Didelot } 2361da7dc875SVivien Didelot 2362da7dc875SVivien Didelot mv88e6xxx_reg_unlock(chip); 2363da7dc875SVivien Didelot 2364da7dc875SVivien Didelot return err; 2365da7dc875SVivien Didelot } 2366da7dc875SVivien Didelot 236787fa886eSAndrew Lunn static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 236887fa886eSAndrew Lunn u16 vid) 236987fa886eSAndrew Lunn { 237087fa886eSAndrew Lunn u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 23710806dd46STobias Waldekranz u8 broadcast[ETH_ALEN]; 23720806dd46STobias Waldekranz 23730806dd46STobias Waldekranz eth_broadcast_addr(broadcast); 237487fa886eSAndrew Lunn 237587fa886eSAndrew Lunn return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 237687fa886eSAndrew Lunn } 237787fa886eSAndrew Lunn 237887fa886eSAndrew Lunn static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 237987fa886eSAndrew Lunn { 238087fa886eSAndrew Lunn int port; 238187fa886eSAndrew Lunn int err; 238287fa886eSAndrew Lunn 238387fa886eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 23848d1d8298STobias Waldekranz struct dsa_port *dp = dsa_to_port(chip->ds, port); 23858d1d8298STobias Waldekranz struct net_device *brport; 23868d1d8298STobias Waldekranz 23878d1d8298STobias Waldekranz if (dsa_is_unused_port(chip->ds, port)) 23888d1d8298STobias Waldekranz continue; 23898d1d8298STobias Waldekranz 23908d1d8298STobias Waldekranz brport = dsa_port_to_bridge_port(dp); 23918d1d8298STobias Waldekranz if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD)) 23928d1d8298STobias Waldekranz /* Skip bridged user ports where broadcast 23938d1d8298STobias Waldekranz * flooding is disabled. 23948d1d8298STobias Waldekranz */ 23958d1d8298STobias Waldekranz continue; 23968d1d8298STobias Waldekranz 239787fa886eSAndrew Lunn err = mv88e6xxx_port_add_broadcast(chip, port, vid); 239887fa886eSAndrew Lunn if (err) 239987fa886eSAndrew Lunn return err; 240087fa886eSAndrew Lunn } 240187fa886eSAndrew Lunn 240287fa886eSAndrew Lunn return 0; 240387fa886eSAndrew Lunn } 240487fa886eSAndrew Lunn 24058d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx { 24068d1d8298STobias Waldekranz int port; 24078d1d8298STobias Waldekranz bool flood; 24088d1d8298STobias Waldekranz }; 24098d1d8298STobias Waldekranz 24108d1d8298STobias Waldekranz static int 24118d1d8298STobias Waldekranz mv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip, 24128d1d8298STobias Waldekranz const struct mv88e6xxx_vtu_entry *vlan, 24138d1d8298STobias Waldekranz void *_ctx) 24148d1d8298STobias Waldekranz { 24158d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx; 24168d1d8298STobias Waldekranz u8 broadcast[ETH_ALEN]; 24178d1d8298STobias Waldekranz u8 state; 24188d1d8298STobias Waldekranz 24198d1d8298STobias Waldekranz if (ctx->flood) 24208d1d8298STobias Waldekranz state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 24218d1d8298STobias Waldekranz else 24228d1d8298STobias Waldekranz state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED; 24238d1d8298STobias Waldekranz 24248d1d8298STobias Waldekranz eth_broadcast_addr(broadcast); 24258d1d8298STobias Waldekranz 24268d1d8298STobias Waldekranz return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast, 24278d1d8298STobias Waldekranz vlan->vid, state); 24288d1d8298STobias Waldekranz } 24298d1d8298STobias Waldekranz 24308d1d8298STobias Waldekranz static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port, 24318d1d8298STobias Waldekranz bool flood) 24328d1d8298STobias Waldekranz { 24338d1d8298STobias Waldekranz struct mv88e6xxx_port_broadcast_sync_ctx ctx = { 24348d1d8298STobias Waldekranz .port = port, 24358d1d8298STobias Waldekranz .flood = flood, 24368d1d8298STobias Waldekranz }; 24378d1d8298STobias Waldekranz struct mv88e6xxx_vtu_entry vid0 = { 24388d1d8298STobias Waldekranz .vid = 0, 24398d1d8298STobias Waldekranz }; 24408d1d8298STobias Waldekranz int err; 24418d1d8298STobias Waldekranz 24428d1d8298STobias Waldekranz /* Update the port's private database... */ 24438d1d8298STobias Waldekranz err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx); 24448d1d8298STobias Waldekranz if (err) 24458d1d8298STobias Waldekranz return err; 24468d1d8298STobias Waldekranz 24478d1d8298STobias Waldekranz /* ...and the database for all VLANs. */ 24488d1d8298STobias Waldekranz return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan, 24498d1d8298STobias Waldekranz &ctx); 24508d1d8298STobias Waldekranz } 24518d1d8298STobias Waldekranz 2452b1ac6fb4SVivien Didelot static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, 2453933b4425SRussell King u16 vid, u8 member, bool warn) 2454fad09c73SVivien Didelot { 2455b1ac6fb4SVivien Didelot const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 2456b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 2457b1ac6fb4SVivien Didelot int i, err; 2458fad09c73SVivien Didelot 245934065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 2460fad09c73SVivien Didelot if (err) 2461fad09c73SVivien Didelot return err; 2462fad09c73SVivien Didelot 246334065c58STobias Waldekranz if (!vlan.valid) { 2464b1ac6fb4SVivien Didelot memset(&vlan, 0, sizeof(vlan)); 2465b1ac6fb4SVivien Didelot 2466d352b20fSTobias Waldekranz if (vid == MV88E6XXX_VID_STANDALONE) 2467d352b20fSTobias Waldekranz vlan.policy = true; 2468d352b20fSTobias Waldekranz 2469b1ac6fb4SVivien Didelot err = mv88e6xxx_atu_new(chip, &vlan.fid); 2470b1ac6fb4SVivien Didelot if (err) 2471b1ac6fb4SVivien Didelot return err; 2472b1ac6fb4SVivien Didelot 2473b1ac6fb4SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 2474b1ac6fb4SVivien Didelot if (i == port) 2475b1ac6fb4SVivien Didelot vlan.member[i] = member; 2476b1ac6fb4SVivien Didelot else 2477b1ac6fb4SVivien Didelot vlan.member[i] = non_member; 2478b1ac6fb4SVivien Didelot 2479b1ac6fb4SVivien Didelot vlan.vid = vid; 24801cb9dfcaSRasmus Villemoes vlan.valid = true; 2481fad09c73SVivien Didelot 248287fa886eSAndrew Lunn err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 248387fa886eSAndrew Lunn if (err) 248487fa886eSAndrew Lunn return err; 248587fa886eSAndrew Lunn 2486b1ac6fb4SVivien Didelot err = mv88e6xxx_broadcast_setup(chip, vlan.vid); 2487b1ac6fb4SVivien Didelot if (err) 2488b1ac6fb4SVivien Didelot return err; 2489b1ac6fb4SVivien Didelot } else if (vlan.member[port] != member) { 2490b1ac6fb4SVivien Didelot vlan.member[port] = member; 2491b1ac6fb4SVivien Didelot 2492b1ac6fb4SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2493b1ac6fb4SVivien Didelot if (err) 2494b1ac6fb4SVivien Didelot return err; 2495933b4425SRussell King } else if (warn) { 2496b1ac6fb4SVivien Didelot dev_info(chip->dev, "p%d: already a member of VLAN %d\n", 2497b1ac6fb4SVivien Didelot port, vid); 2498b1ac6fb4SVivien Didelot } 2499b1ac6fb4SVivien Didelot 2500b1ac6fb4SVivien Didelot return 0; 2501fad09c73SVivien Didelot } 2502fad09c73SVivien Didelot 25031958d581SVladimir Oltean static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 250431046a5fSVladimir Oltean const struct switchdev_obj_port_vlan *vlan, 250531046a5fSVladimir Oltean struct netlink_ext_ack *extack) 2506fad09c73SVivien Didelot { 250704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2508fad09c73SVivien Didelot bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 2509fad09c73SVivien Didelot bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 25108b6836d8SVladimir Oltean struct mv88e6xxx_port *p = &chip->ports[port]; 2511933b4425SRussell King bool warn; 2512c91498e1SVivien Didelot u8 member; 25131958d581SVladimir Oltean int err; 2514fad09c73SVivien Didelot 2515b8b79c41SEldar Gasanov if (!vlan->vid) 2516b8b79c41SEldar Gasanov return 0; 2517b8b79c41SEldar Gasanov 25181958d581SVladimir Oltean err = mv88e6xxx_port_vlan_prepare(ds, port, vlan); 25191958d581SVladimir Oltean if (err) 25201958d581SVladimir Oltean return err; 2521fad09c73SVivien Didelot 2522c91498e1SVivien Didelot if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 25237ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 2524c91498e1SVivien Didelot else if (untagged) 25257ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 2526c91498e1SVivien Didelot else 25277ec60d6eSVivien Didelot member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 2528c91498e1SVivien Didelot 2529933b4425SRussell King /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port 2530933b4425SRussell King * and then the CPU port. Do not warn for duplicates for the CPU port. 2531933b4425SRussell King */ 2532933b4425SRussell King warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); 2533933b4425SRussell King 2534c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2535fad09c73SVivien Didelot 25361958d581SVladimir Oltean err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn); 25371958d581SVladimir Oltean if (err) { 2538774439e5SVivien Didelot dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 2539b7a9e0daSVladimir Oltean vlan->vid, untagged ? 'u' : 't'); 25401958d581SVladimir Oltean goto out; 25411958d581SVladimir Oltean } 2542fad09c73SVivien Didelot 25431958d581SVladimir Oltean if (pvid) { 25448b6836d8SVladimir Oltean p->bridge_pvid.vid = vlan->vid; 25458b6836d8SVladimir Oltean p->bridge_pvid.valid = true; 25468b6836d8SVladimir Oltean 25478b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 25488b6836d8SVladimir Oltean if (err) 25498b6836d8SVladimir Oltean goto out; 25508b6836d8SVladimir Oltean } else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) { 25518b6836d8SVladimir Oltean /* The old pvid was reinstalled as a non-pvid VLAN */ 25528b6836d8SVladimir Oltean p->bridge_pvid.valid = false; 25538b6836d8SVladimir Oltean 25548b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 25558b6836d8SVladimir Oltean if (err) 25561958d581SVladimir Oltean goto out; 25571958d581SVladimir Oltean } 25588b6836d8SVladimir Oltean 25591958d581SVladimir Oltean out: 2560c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 25611958d581SVladimir Oltean 25621958d581SVladimir Oltean return err; 2563fad09c73SVivien Didelot } 2564fad09c73SVivien Didelot 256552109892SVivien Didelot static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, 2566fad09c73SVivien Didelot int port, u16 vid) 2567fad09c73SVivien Didelot { 2568b4e47c0fSVivien Didelot struct mv88e6xxx_vtu_entry vlan; 2569fad09c73SVivien Didelot int i, err; 2570fad09c73SVivien Didelot 257152109892SVivien Didelot if (!vid) 2572c92c7413SVladimir Oltean return 0; 257352109892SVivien Didelot 257434065c58STobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 2575fad09c73SVivien Didelot if (err) 2576fad09c73SVivien Didelot return err; 2577fad09c73SVivien Didelot 257852109892SVivien Didelot /* If the VLAN doesn't exist in hardware or the port isn't a member, 257952109892SVivien Didelot * tell switchdev that this VLAN is likely handled in software. 258052109892SVivien Didelot */ 258134065c58STobias Waldekranz if (!vlan.valid || 258252109892SVivien Didelot vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 2583fad09c73SVivien Didelot return -EOPNOTSUPP; 2584fad09c73SVivien Didelot 25857ec60d6eSVivien Didelot vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 2586fad09c73SVivien Didelot 2587fad09c73SVivien Didelot /* keep the VLAN unless all ports are excluded */ 2588fad09c73SVivien Didelot vlan.valid = false; 2589370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 25907ec60d6eSVivien Didelot if (vlan.member[i] != 25917ec60d6eSVivien Didelot MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 2592fad09c73SVivien Didelot vlan.valid = true; 2593fad09c73SVivien Didelot break; 2594fad09c73SVivien Didelot } 2595fad09c73SVivien Didelot } 2596fad09c73SVivien Didelot 25970ad5daf6SVivien Didelot err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2598fad09c73SVivien Didelot if (err) 2599fad09c73SVivien Didelot return err; 2600fad09c73SVivien Didelot 2601acaf4d2eSTobias Waldekranz if (!vlan.valid) { 2602acaf4d2eSTobias Waldekranz err = mv88e6xxx_mst_put(chip, vlan.sid); 2603acaf4d2eSTobias Waldekranz if (err) 2604acaf4d2eSTobias Waldekranz return err; 2605acaf4d2eSTobias Waldekranz } 2606acaf4d2eSTobias Waldekranz 2607e606ca36SVivien Didelot return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 2608fad09c73SVivien Didelot } 2609fad09c73SVivien Didelot 2610fad09c73SVivien Didelot static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 2611fad09c73SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 2612fad09c73SVivien Didelot { 261304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 26148b6836d8SVladimir Oltean struct mv88e6xxx_port *p = &chip->ports[port]; 2615fad09c73SVivien Didelot int err = 0; 2616b7a9e0daSVladimir Oltean u16 pvid; 2617fad09c73SVivien Didelot 2618e545f865STobias Waldekranz if (!mv88e6xxx_max_vid(chip)) 2619fad09c73SVivien Didelot return -EOPNOTSUPP; 2620fad09c73SVivien Didelot 2621a2614140SVladimir Oltean /* The ATU removal procedure needs the FID to be mapped in the VTU, 2622a2614140SVladimir Oltean * but FDB deletion runs concurrently with VLAN deletion. Flush the DSA 2623a2614140SVladimir Oltean * switchdev workqueue to ensure that all FDB entries are deleted 2624a2614140SVladimir Oltean * before we remove the VLAN. 2625a2614140SVladimir Oltean */ 2626a2614140SVladimir Oltean dsa_flush_workqueue(); 2627a2614140SVladimir Oltean 2628c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2629fad09c73SVivien Didelot 263077064f37SVivien Didelot err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 2631fad09c73SVivien Didelot if (err) 2632fad09c73SVivien Didelot goto unlock; 2633fad09c73SVivien Didelot 2634b7a9e0daSVladimir Oltean err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid); 2635fad09c73SVivien Didelot if (err) 2636fad09c73SVivien Didelot goto unlock; 2637fad09c73SVivien Didelot 2638b7a9e0daSVladimir Oltean if (vlan->vid == pvid) { 26398b6836d8SVladimir Oltean p->bridge_pvid.valid = false; 26408b6836d8SVladimir Oltean 26418b6836d8SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 2642fad09c73SVivien Didelot if (err) 2643fad09c73SVivien Didelot goto unlock; 2644fad09c73SVivien Didelot } 2645fad09c73SVivien Didelot 2646fad09c73SVivien Didelot unlock: 2647c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2648fad09c73SVivien Didelot 2649fad09c73SVivien Didelot return err; 2650fad09c73SVivien Didelot } 2651fad09c73SVivien Didelot 2652acaf4d2eSTobias Waldekranz static int mv88e6xxx_port_vlan_fast_age(struct dsa_switch *ds, int port, u16 vid) 2653acaf4d2eSTobias Waldekranz { 2654acaf4d2eSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 2655acaf4d2eSTobias Waldekranz struct mv88e6xxx_vtu_entry vlan; 2656acaf4d2eSTobias Waldekranz int err; 2657acaf4d2eSTobias Waldekranz 2658acaf4d2eSTobias Waldekranz mv88e6xxx_reg_lock(chip); 2659acaf4d2eSTobias Waldekranz 2660acaf4d2eSTobias Waldekranz err = mv88e6xxx_vtu_get(chip, vid, &vlan); 2661acaf4d2eSTobias Waldekranz if (err) 2662acaf4d2eSTobias Waldekranz goto unlock; 2663acaf4d2eSTobias Waldekranz 2664acaf4d2eSTobias Waldekranz err = mv88e6xxx_port_fast_age_fid(chip, port, vlan.fid); 2665acaf4d2eSTobias Waldekranz 2666acaf4d2eSTobias Waldekranz unlock: 2667acaf4d2eSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 2668acaf4d2eSTobias Waldekranz 2669acaf4d2eSTobias Waldekranz return err; 2670acaf4d2eSTobias Waldekranz } 2671acaf4d2eSTobias Waldekranz 2672acaf4d2eSTobias Waldekranz static int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds, 2673acaf4d2eSTobias Waldekranz struct dsa_bridge bridge, 2674acaf4d2eSTobias Waldekranz const struct switchdev_vlan_msti *msti) 2675acaf4d2eSTobias Waldekranz { 2676acaf4d2eSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 2677acaf4d2eSTobias Waldekranz struct mv88e6xxx_vtu_entry vlan; 2678acaf4d2eSTobias Waldekranz u8 old_sid, new_sid; 2679acaf4d2eSTobias Waldekranz int err; 2680acaf4d2eSTobias Waldekranz 2681bd48b911STobias Waldekranz if (!mv88e6xxx_has_stu(chip)) 2682bd48b911STobias Waldekranz return -EOPNOTSUPP; 2683bd48b911STobias Waldekranz 2684acaf4d2eSTobias Waldekranz mv88e6xxx_reg_lock(chip); 2685acaf4d2eSTobias Waldekranz 2686acaf4d2eSTobias Waldekranz err = mv88e6xxx_vtu_get(chip, msti->vid, &vlan); 2687acaf4d2eSTobias Waldekranz if (err) 2688acaf4d2eSTobias Waldekranz goto unlock; 2689acaf4d2eSTobias Waldekranz 2690acaf4d2eSTobias Waldekranz if (!vlan.valid) { 2691acaf4d2eSTobias Waldekranz err = -EINVAL; 2692acaf4d2eSTobias Waldekranz goto unlock; 2693acaf4d2eSTobias Waldekranz } 2694acaf4d2eSTobias Waldekranz 2695acaf4d2eSTobias Waldekranz old_sid = vlan.sid; 2696acaf4d2eSTobias Waldekranz 2697acaf4d2eSTobias Waldekranz err = mv88e6xxx_mst_get(chip, bridge.dev, msti->msti, &new_sid); 2698acaf4d2eSTobias Waldekranz if (err) 2699acaf4d2eSTobias Waldekranz goto unlock; 2700acaf4d2eSTobias Waldekranz 2701acaf4d2eSTobias Waldekranz if (new_sid != old_sid) { 2702acaf4d2eSTobias Waldekranz vlan.sid = new_sid; 2703acaf4d2eSTobias Waldekranz 2704acaf4d2eSTobias Waldekranz err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 2705acaf4d2eSTobias Waldekranz if (err) { 2706acaf4d2eSTobias Waldekranz mv88e6xxx_mst_put(chip, new_sid); 2707acaf4d2eSTobias Waldekranz goto unlock; 2708acaf4d2eSTobias Waldekranz } 2709acaf4d2eSTobias Waldekranz } 2710acaf4d2eSTobias Waldekranz 2711acaf4d2eSTobias Waldekranz err = mv88e6xxx_mst_put(chip, old_sid); 2712acaf4d2eSTobias Waldekranz 2713acaf4d2eSTobias Waldekranz unlock: 2714acaf4d2eSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 2715acaf4d2eSTobias Waldekranz return err; 2716acaf4d2eSTobias Waldekranz } 2717acaf4d2eSTobias Waldekranz 27181b6dd556SArkadi Sharshevsky static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 2719c2693363SVladimir Oltean const unsigned char *addr, u16 vid, 2720c2693363SVladimir Oltean struct dsa_db db) 2721fad09c73SVivien Didelot { 272204bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 27231b6dd556SArkadi Sharshevsky int err; 2724fad09c73SVivien Didelot 2725c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 27261b6dd556SArkadi Sharshevsky err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 27271b6dd556SArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 2728c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 27291b6dd556SArkadi Sharshevsky 27301b6dd556SArkadi Sharshevsky return err; 2731fad09c73SVivien Didelot } 2732fad09c73SVivien Didelot 2733fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 2734c2693363SVladimir Oltean const unsigned char *addr, u16 vid, 2735c2693363SVladimir Oltean struct dsa_db db) 2736fad09c73SVivien Didelot { 273704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 273883dabd1fSVivien Didelot int err; 2739fad09c73SVivien Didelot 2740c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2741d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); 2742c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2743fad09c73SVivien Didelot 274483dabd1fSVivien Didelot return err; 2745fad09c73SVivien Didelot } 2746fad09c73SVivien Didelot 274783dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 2748fad09c73SVivien Didelot u16 fid, u16 vid, int port, 27492bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2750fad09c73SVivien Didelot { 2751dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry addr; 27522bedde1aSArkadi Sharshevsky bool is_static; 2753fad09c73SVivien Didelot int err; 2754fad09c73SVivien Didelot 2755d8291a95SVivien Didelot addr.state = 0; 2756dabc1a96SVivien Didelot eth_broadcast_addr(addr.mac); 2757fad09c73SVivien Didelot 2758fad09c73SVivien Didelot do { 2759dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 2760fad09c73SVivien Didelot if (err) 276183dabd1fSVivien Didelot return err; 2762fad09c73SVivien Didelot 2763d8291a95SVivien Didelot if (!addr.state) 2764fad09c73SVivien Didelot break; 2765fad09c73SVivien Didelot 276601bd96c8SVivien Didelot if (addr.trunk || (addr.portvec & BIT(port)) == 0) 276783dabd1fSVivien Didelot continue; 2768fad09c73SVivien Didelot 276983dabd1fSVivien Didelot if (!is_unicast_ether_addr(addr.mac)) 277083dabd1fSVivien Didelot continue; 277183dabd1fSVivien Didelot 27722bedde1aSArkadi Sharshevsky is_static = (addr.state == 27732bedde1aSArkadi Sharshevsky MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 27742bedde1aSArkadi Sharshevsky err = cb(addr.mac, vid, is_static, data); 277583dabd1fSVivien Didelot if (err) 277683dabd1fSVivien Didelot return err; 2777fad09c73SVivien Didelot } while (!is_broadcast_ether_addr(addr.mac)); 2778fad09c73SVivien Didelot 2779fad09c73SVivien Didelot return err; 2780fad09c73SVivien Didelot } 2781fad09c73SVivien Didelot 2782d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx { 2783d89ef4b8STobias Waldekranz int port; 2784d89ef4b8STobias Waldekranz dsa_fdb_dump_cb_t *cb; 2785d89ef4b8STobias Waldekranz void *data; 2786d89ef4b8STobias Waldekranz }; 2787d89ef4b8STobias Waldekranz 2788d89ef4b8STobias Waldekranz static int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip, 2789d89ef4b8STobias Waldekranz const struct mv88e6xxx_vtu_entry *entry, 2790d89ef4b8STobias Waldekranz void *_data) 2791d89ef4b8STobias Waldekranz { 2792d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data; 2793d89ef4b8STobias Waldekranz 2794d89ef4b8STobias Waldekranz return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid, 2795d89ef4b8STobias Waldekranz ctx->port, ctx->cb, ctx->data); 2796d89ef4b8STobias Waldekranz } 2797d89ef4b8STobias Waldekranz 279883dabd1fSVivien Didelot static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 27992bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 280083dabd1fSVivien Didelot { 2801d89ef4b8STobias Waldekranz struct mv88e6xxx_port_db_dump_vlan_ctx ctx = { 2802d89ef4b8STobias Waldekranz .port = port, 2803d89ef4b8STobias Waldekranz .cb = cb, 2804d89ef4b8STobias Waldekranz .data = data, 2805d89ef4b8STobias Waldekranz }; 280683dabd1fSVivien Didelot u16 fid; 280783dabd1fSVivien Didelot int err; 280883dabd1fSVivien Didelot 280983dabd1fSVivien Didelot /* Dump port's default Filtering Information Database (VLAN ID 0) */ 2810b4e48c50SVivien Didelot err = mv88e6xxx_port_get_fid(chip, port, &fid); 281183dabd1fSVivien Didelot if (err) 281283dabd1fSVivien Didelot return err; 281383dabd1fSVivien Didelot 28142bedde1aSArkadi Sharshevsky err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 281583dabd1fSVivien Didelot if (err) 281683dabd1fSVivien Didelot return err; 281783dabd1fSVivien Didelot 2818d89ef4b8STobias Waldekranz return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx); 281983dabd1fSVivien Didelot } 282083dabd1fSVivien Didelot 2821fad09c73SVivien Didelot static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 28222bedde1aSArkadi Sharshevsky dsa_fdb_dump_cb_t *cb, void *data) 2823fad09c73SVivien Didelot { 282404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2825fcf15367SVivien Didelot int err; 2826fad09c73SVivien Didelot 2827c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2828fcf15367SVivien Didelot err = mv88e6xxx_port_db_dump(chip, port, cb, data); 2829c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2830fcf15367SVivien Didelot 2831fcf15367SVivien Didelot return err; 2832fad09c73SVivien Didelot } 2833fad09c73SVivien Didelot 2834240ea3efSVivien Didelot static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 2835d3eed0e5SVladimir Oltean struct dsa_bridge bridge) 2836240ea3efSVivien Didelot { 2837ef2025ecSVivien Didelot struct dsa_switch *ds = chip->ds; 2838ef2025ecSVivien Didelot struct dsa_switch_tree *dst = ds->dst; 2839ef2025ecSVivien Didelot struct dsa_port *dp; 2840240ea3efSVivien Didelot int err; 2841240ea3efSVivien Didelot 2842ef2025ecSVivien Didelot list_for_each_entry(dp, &dst->ports, list) { 2843d3eed0e5SVladimir Oltean if (dsa_port_offloads_bridge(dp, &bridge)) { 2844ef2025ecSVivien Didelot if (dp->ds == ds) { 2845ef2025ecSVivien Didelot /* This is a local bridge group member, 2846ef2025ecSVivien Didelot * remap its Port VLAN Map. 2847ef2025ecSVivien Didelot */ 2848ef2025ecSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, dp->index); 2849240ea3efSVivien Didelot if (err) 2850240ea3efSVivien Didelot return err; 2851ef2025ecSVivien Didelot } else { 2852ef2025ecSVivien Didelot /* This is an external bridge group member, 2853ef2025ecSVivien Didelot * remap its cross-chip Port VLAN Table entry. 2854ef2025ecSVivien Didelot */ 2855ef2025ecSVivien Didelot err = mv88e6xxx_pvt_map(chip, dp->ds->index, 2856ef2025ecSVivien Didelot dp->index); 2857e96a6e02SVivien Didelot if (err) 2858e96a6e02SVivien Didelot return err; 2859e96a6e02SVivien Didelot } 2860e96a6e02SVivien Didelot } 2861e96a6e02SVivien Didelot } 2862e96a6e02SVivien Didelot 2863240ea3efSVivien Didelot return 0; 2864240ea3efSVivien Didelot } 2865240ea3efSVivien Didelot 2866857fdd74SVladimir Oltean /* Treat the software bridge as a virtual single-port switch behind the 2867857fdd74SVladimir Oltean * CPU and map in the PVT. First dst->last_switch elements are taken by 2868857fdd74SVladimir Oltean * physical switches, so start from beyond that range. 2869857fdd74SVladimir Oltean */ 2870857fdd74SVladimir Oltean static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds, 2871857fdd74SVladimir Oltean unsigned int bridge_num) 2872857fdd74SVladimir Oltean { 2873857fdd74SVladimir Oltean u8 dev = bridge_num + ds->dst->last_switch; 2874857fdd74SVladimir Oltean struct mv88e6xxx_chip *chip = ds->priv; 2875857fdd74SVladimir Oltean 2876857fdd74SVladimir Oltean return mv88e6xxx_pvt_map(chip, dev, 0); 2877857fdd74SVladimir Oltean } 2878857fdd74SVladimir Oltean 2879fad09c73SVivien Didelot static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 2880b079922bSVladimir Oltean struct dsa_bridge bridge, 288106b9cce4SVladimir Oltean bool *tx_fwd_offload, 288206b9cce4SVladimir Oltean struct netlink_ext_ack *extack) 2883fad09c73SVivien Didelot { 288404bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2885240ea3efSVivien Didelot int err; 2886fad09c73SVivien Didelot 2887c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 28885bded825SVladimir Oltean 2889d3eed0e5SVladimir Oltean err = mv88e6xxx_bridge_map(chip, bridge); 28905bded825SVladimir Oltean if (err) 28915bded825SVladimir Oltean goto unlock; 28925bded825SVladimir Oltean 28937af4a361STobias Waldekranz err = mv88e6xxx_port_set_map_da(chip, port, true); 28947af4a361STobias Waldekranz if (err) 2895ff624338SDan Carpenter goto unlock; 28967af4a361STobias Waldekranz 28975bded825SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 28985bded825SVladimir Oltean if (err) 28995bded825SVladimir Oltean goto unlock; 29005bded825SVladimir Oltean 2901857fdd74SVladimir Oltean if (mv88e6xxx_has_pvt(chip)) { 2902857fdd74SVladimir Oltean err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num); 2903857fdd74SVladimir Oltean if (err) 2904857fdd74SVladimir Oltean goto unlock; 2905857fdd74SVladimir Oltean 2906857fdd74SVladimir Oltean *tx_fwd_offload = true; 2907857fdd74SVladimir Oltean } 2908857fdd74SVladimir Oltean 29095bded825SVladimir Oltean unlock: 2910c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2911fad09c73SVivien Didelot 2912fad09c73SVivien Didelot return err; 2913fad09c73SVivien Didelot } 2914fad09c73SVivien Didelot 2915f123f2fbSVivien Didelot static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 2916d3eed0e5SVladimir Oltean struct dsa_bridge bridge) 2917fad09c73SVivien Didelot { 291804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 29195bded825SVladimir Oltean int err; 2920fad09c73SVivien Didelot 2921c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 29225bded825SVladimir Oltean 2923857fdd74SVladimir Oltean if (bridge.tx_fwd_offload && 2924857fdd74SVladimir Oltean mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num)) 2925857fdd74SVladimir Oltean dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2926857fdd74SVladimir Oltean 2927d3eed0e5SVladimir Oltean if (mv88e6xxx_bridge_map(chip, bridge) || 2928240ea3efSVivien Didelot mv88e6xxx_port_vlan_map(chip, port)) 2929240ea3efSVivien Didelot dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 29305bded825SVladimir Oltean 29317af4a361STobias Waldekranz err = mv88e6xxx_port_set_map_da(chip, port, false); 29327af4a361STobias Waldekranz if (err) 29337af4a361STobias Waldekranz dev_err(ds->dev, 29347af4a361STobias Waldekranz "port %d failed to restore map-DA: %pe\n", 29357af4a361STobias Waldekranz port, ERR_PTR(err)); 29367af4a361STobias Waldekranz 29375bded825SVladimir Oltean err = mv88e6xxx_port_commit_pvid(chip, port); 29385bded825SVladimir Oltean if (err) 29395bded825SVladimir Oltean dev_err(ds->dev, 29405bded825SVladimir Oltean "port %d failed to restore standalone pvid: %pe\n", 29415bded825SVladimir Oltean port, ERR_PTR(err)); 29425bded825SVladimir Oltean 2943c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2944fad09c73SVivien Didelot } 2945fad09c73SVivien Didelot 2946f66a6a69SVladimir Oltean static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, 2947f66a6a69SVladimir Oltean int tree_index, int sw_index, 294806b9cce4SVladimir Oltean int port, struct dsa_bridge bridge, 294906b9cce4SVladimir Oltean struct netlink_ext_ack *extack) 2950aec5ac88SVivien Didelot { 2951aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2952aec5ac88SVivien Didelot int err; 2953aec5ac88SVivien Didelot 2954f66a6a69SVladimir Oltean if (tree_index != ds->dst->index) 2955f66a6a69SVladimir Oltean return 0; 2956f66a6a69SVladimir Oltean 2957c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2958f66a6a69SVladimir Oltean err = mv88e6xxx_pvt_map(chip, sw_index, port); 2959e0068620STobias Waldekranz err = err ? : mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num); 2960c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2961aec5ac88SVivien Didelot 2962aec5ac88SVivien Didelot return err; 2963aec5ac88SVivien Didelot } 2964aec5ac88SVivien Didelot 2965f66a6a69SVladimir Oltean static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, 2966f66a6a69SVladimir Oltean int tree_index, int sw_index, 2967d3eed0e5SVladimir Oltean int port, struct dsa_bridge bridge) 2968aec5ac88SVivien Didelot { 2969aec5ac88SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 2970aec5ac88SVivien Didelot 2971f66a6a69SVladimir Oltean if (tree_index != ds->dst->index) 2972f66a6a69SVladimir Oltean return; 2973f66a6a69SVladimir Oltean 2974c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 2975e0068620STobias Waldekranz if (mv88e6xxx_pvt_map(chip, sw_index, port) || 2976e0068620STobias Waldekranz mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num)) 2977aec5ac88SVivien Didelot dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 2978c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 2979aec5ac88SVivien Didelot } 2980aec5ac88SVivien Didelot 298117e708baSVivien Didelot static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 298217e708baSVivien Didelot { 298317e708baSVivien Didelot if (chip->info->ops->reset) 298417e708baSVivien Didelot return chip->info->ops->reset(chip); 298517e708baSVivien Didelot 298617e708baSVivien Didelot return 0; 298717e708baSVivien Didelot } 298817e708baSVivien Didelot 2989309eca6dSVivien Didelot static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 2990309eca6dSVivien Didelot { 2991309eca6dSVivien Didelot struct gpio_desc *gpiod = chip->reset; 2992309eca6dSVivien Didelot 2993309eca6dSVivien Didelot /* If there is a GPIO connected to the reset pin, toggle it */ 2994309eca6dSVivien Didelot if (gpiod) { 2995309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 1); 2996309eca6dSVivien Didelot usleep_range(10000, 20000); 2997309eca6dSVivien Didelot gpiod_set_value_cansleep(gpiod, 0); 2998309eca6dSVivien Didelot usleep_range(10000, 20000); 2999a3dcb3e7SAndrew Lunn 3000a3dcb3e7SAndrew Lunn mv88e6xxx_g1_wait_eeprom_done(chip); 3001309eca6dSVivien Didelot } 3002309eca6dSVivien Didelot } 3003309eca6dSVivien Didelot 30044ac4b5a6SVivien Didelot static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 30054ac4b5a6SVivien Didelot { 30064ac4b5a6SVivien Didelot int i, err; 30074ac4b5a6SVivien Didelot 30084ac4b5a6SVivien Didelot /* Set all ports to the Disabled state */ 30094ac4b5a6SVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 3010f894c29cSVivien Didelot err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 30114ac4b5a6SVivien Didelot if (err) 30124ac4b5a6SVivien Didelot return err; 30134ac4b5a6SVivien Didelot } 30144ac4b5a6SVivien Didelot 30154ac4b5a6SVivien Didelot /* Wait for transmit queues to drain, 30164ac4b5a6SVivien Didelot * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 30174ac4b5a6SVivien Didelot */ 30184ac4b5a6SVivien Didelot usleep_range(2000, 4000); 30194ac4b5a6SVivien Didelot 30204ac4b5a6SVivien Didelot return 0; 30214ac4b5a6SVivien Didelot } 30224ac4b5a6SVivien Didelot 3023fad09c73SVivien Didelot static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 3024fad09c73SVivien Didelot { 3025a935c052SVivien Didelot int err; 3026fad09c73SVivien Didelot 30274ac4b5a6SVivien Didelot err = mv88e6xxx_disable_ports(chip); 30280e7b9925SAndrew Lunn if (err) 30290e7b9925SAndrew Lunn return err; 3030fad09c73SVivien Didelot 3031309eca6dSVivien Didelot mv88e6xxx_hardware_reset(chip); 3032fad09c73SVivien Didelot 303317e708baSVivien Didelot return mv88e6xxx_software_reset(chip); 3034fad09c73SVivien Didelot } 3035fad09c73SVivien Didelot 30364314557cSVivien Didelot static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 303731bef4e9SVivien Didelot enum mv88e6xxx_frame_mode frame, 303831bef4e9SVivien Didelot enum mv88e6xxx_egress_mode egress, u16 etype) 303956995cbcSAndrew Lunn { 304056995cbcSAndrew Lunn int err; 304156995cbcSAndrew Lunn 30424314557cSVivien Didelot if (!chip->info->ops->port_set_frame_mode) 30434314557cSVivien Didelot return -EOPNOTSUPP; 30444314557cSVivien Didelot 30454314557cSVivien Didelot err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 304656995cbcSAndrew Lunn if (err) 304756995cbcSAndrew Lunn return err; 304856995cbcSAndrew Lunn 30494314557cSVivien Didelot err = chip->info->ops->port_set_frame_mode(chip, port, frame); 30504314557cSVivien Didelot if (err) 30514314557cSVivien Didelot return err; 30524314557cSVivien Didelot 30534314557cSVivien Didelot if (chip->info->ops->port_set_ether_type) 30544314557cSVivien Didelot return chip->info->ops->port_set_ether_type(chip, port, etype); 30554314557cSVivien Didelot 30564314557cSVivien Didelot return 0; 30574314557cSVivien Didelot } 30584314557cSVivien Didelot 30594314557cSVivien Didelot static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 30604314557cSVivien Didelot { 30614314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 306231bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 3063b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 30644314557cSVivien Didelot } 30654314557cSVivien Didelot 30664314557cSVivien Didelot static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 30674314557cSVivien Didelot { 30684314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 306931bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_UNMODIFIED, 3070b8109594SVivien Didelot MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 30714314557cSVivien Didelot } 30724314557cSVivien Didelot 30734314557cSVivien Didelot static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 30744314557cSVivien Didelot { 30754314557cSVivien Didelot return mv88e6xxx_set_port_mode(chip, port, 30764314557cSVivien Didelot MV88E6XXX_FRAME_MODE_ETHERTYPE, 307731bef4e9SVivien Didelot MV88E6XXX_EGRESS_MODE_ETHERTYPE, 307831bef4e9SVivien Didelot ETH_P_EDSA); 30794314557cSVivien Didelot } 30804314557cSVivien Didelot 30814314557cSVivien Didelot static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 30824314557cSVivien Didelot { 30834314557cSVivien Didelot if (dsa_is_dsa_port(chip->ds, port)) 30844314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 30854314557cSVivien Didelot 30862b3e9891SVivien Didelot if (dsa_is_user_port(chip->ds, port)) 30874314557cSVivien Didelot return mv88e6xxx_set_port_mode_normal(chip, port); 30884314557cSVivien Didelot 30894314557cSVivien Didelot /* Setup CPU port mode depending on its supported tag format */ 3090670bb80fSTobias Waldekranz if (chip->tag_protocol == DSA_TAG_PROTO_DSA) 30914314557cSVivien Didelot return mv88e6xxx_set_port_mode_dsa(chip, port); 30924314557cSVivien Didelot 3093670bb80fSTobias Waldekranz if (chip->tag_protocol == DSA_TAG_PROTO_EDSA) 30944314557cSVivien Didelot return mv88e6xxx_set_port_mode_edsa(chip, port); 30954314557cSVivien Didelot 30964314557cSVivien Didelot return -EINVAL; 30974314557cSVivien Didelot } 30984314557cSVivien Didelot 3099ea698f4fSVivien Didelot static int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 3100ea698f4fSVivien Didelot { 3101ea698f4fSVivien Didelot bool message = dsa_is_dsa_port(chip->ds, port); 3102ea698f4fSVivien Didelot 3103ea698f4fSVivien Didelot return mv88e6xxx_port_set_message_port(chip, port, message); 3104ea698f4fSVivien Didelot } 3105ea698f4fSVivien Didelot 3106601aeed3SVivien Didelot static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 3107601aeed3SVivien Didelot { 3108a8b659e7SVladimir Oltean int err; 3109601aeed3SVivien Didelot 3110a8b659e7SVladimir Oltean if (chip->info->ops->port_set_ucast_flood) { 31117b9f16feSTobias Waldekranz err = chip->info->ops->port_set_ucast_flood(chip, port, true); 3112a8b659e7SVladimir Oltean if (err) 3113a8b659e7SVladimir Oltean return err; 3114a8b659e7SVladimir Oltean } 3115a8b659e7SVladimir Oltean if (chip->info->ops->port_set_mcast_flood) { 31167b9f16feSTobias Waldekranz err = chip->info->ops->port_set_mcast_flood(chip, port, true); 3117a8b659e7SVladimir Oltean if (err) 3118a8b659e7SVladimir Oltean return err; 3119a8b659e7SVladimir Oltean } 3120407308f6SDavid S. Miller 3121601aeed3SVivien Didelot return 0; 3122601aeed3SVivien Didelot } 3123601aeed3SVivien Didelot 312445de77ffSVivien Didelot static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id) 312545de77ffSVivien Didelot { 312645de77ffSVivien Didelot struct mv88e6xxx_port *mvp = dev_id; 312745de77ffSVivien Didelot struct mv88e6xxx_chip *chip = mvp->chip; 312845de77ffSVivien Didelot irqreturn_t ret = IRQ_NONE; 312945de77ffSVivien Didelot int port = mvp->port; 3130193c5b26SPavana Sharma int lane; 313145de77ffSVivien Didelot 313245de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 313345de77ffSVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 3134193c5b26SPavana Sharma if (lane >= 0) 313545de77ffSVivien Didelot ret = mv88e6xxx_serdes_irq_status(chip, port, lane); 313645de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 313745de77ffSVivien Didelot 313845de77ffSVivien Didelot return ret; 313945de77ffSVivien Didelot } 314045de77ffSVivien Didelot 314145de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port, 3142193c5b26SPavana Sharma int lane) 314345de77ffSVivien Didelot { 314445de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 314545de77ffSVivien Didelot unsigned int irq; 314645de77ffSVivien Didelot int err; 314745de77ffSVivien Didelot 314845de77ffSVivien Didelot /* Nothing to request if this SERDES port has no IRQ */ 314945de77ffSVivien Didelot irq = mv88e6xxx_serdes_irq_mapping(chip, port); 315045de77ffSVivien Didelot if (!irq) 315145de77ffSVivien Didelot return 0; 315245de77ffSVivien Didelot 3153e6f2f6b8SAndrew Lunn snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name), 3154e6f2f6b8SAndrew Lunn "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port); 3155e6f2f6b8SAndrew Lunn 315645de77ffSVivien Didelot /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */ 315745de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 315845de77ffSVivien Didelot err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn, 3159e6f2f6b8SAndrew Lunn IRQF_ONESHOT, dev_id->serdes_irq_name, 3160e6f2f6b8SAndrew Lunn dev_id); 316145de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 316245de77ffSVivien Didelot if (err) 316345de77ffSVivien Didelot return err; 316445de77ffSVivien Didelot 316545de77ffSVivien Didelot dev_id->serdes_irq = irq; 316645de77ffSVivien Didelot 316745de77ffSVivien Didelot return mv88e6xxx_serdes_irq_enable(chip, port, lane); 316845de77ffSVivien Didelot } 316945de77ffSVivien Didelot 317045de77ffSVivien Didelot static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port, 3171193c5b26SPavana Sharma int lane) 317245de77ffSVivien Didelot { 317345de77ffSVivien Didelot struct mv88e6xxx_port *dev_id = &chip->ports[port]; 317445de77ffSVivien Didelot unsigned int irq = dev_id->serdes_irq; 317545de77ffSVivien Didelot int err; 317645de77ffSVivien Didelot 317745de77ffSVivien Didelot /* Nothing to free if no IRQ has been requested */ 317845de77ffSVivien Didelot if (!irq) 317945de77ffSVivien Didelot return 0; 318045de77ffSVivien Didelot 318145de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 318245de77ffSVivien Didelot 318345de77ffSVivien Didelot /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */ 318445de77ffSVivien Didelot mv88e6xxx_reg_unlock(chip); 318545de77ffSVivien Didelot free_irq(irq, dev_id); 318645de77ffSVivien Didelot mv88e6xxx_reg_lock(chip); 318745de77ffSVivien Didelot 318845de77ffSVivien Didelot dev_id->serdes_irq = 0; 318945de77ffSVivien Didelot 319045de77ffSVivien Didelot return err; 319145de77ffSVivien Didelot } 319245de77ffSVivien Didelot 31936d91782fSAndrew Lunn static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 31946d91782fSAndrew Lunn bool on) 31956d91782fSAndrew Lunn { 3196193c5b26SPavana Sharma int lane; 3197fc0bc019SVivien Didelot int err; 31986d91782fSAndrew Lunn 3199dc272f60SVivien Didelot lane = mv88e6xxx_serdes_get_lane(chip, port); 3200193c5b26SPavana Sharma if (lane < 0) 3201523a8904SVivien Didelot return 0; 3202fc0bc019SVivien Didelot 3203fc0bc019SVivien Didelot if (on) { 3204dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_up(chip, port, lane); 3205fc0bc019SVivien Didelot if (err) 3206fc0bc019SVivien Didelot return err; 3207fc0bc019SVivien Didelot 320845de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_request(chip, port, lane); 3209fc0bc019SVivien Didelot } else { 321045de77ffSVivien Didelot err = mv88e6xxx_serdes_irq_free(chip, port, lane); 321145de77ffSVivien Didelot if (err) 321245de77ffSVivien Didelot return err; 3213fc0bc019SVivien Didelot 3214dc272f60SVivien Didelot err = mv88e6xxx_serdes_power_down(chip, port, lane); 3215fc0bc019SVivien Didelot } 3216fc0bc019SVivien Didelot 3217fc0bc019SVivien Didelot return err; 32186d91782fSAndrew Lunn } 32196d91782fSAndrew Lunn 32202fda45f0SMarek Behún static int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip, 32212fda45f0SMarek Behún enum mv88e6xxx_egress_direction direction, 32222fda45f0SMarek Behún int port) 32232fda45f0SMarek Behún { 32242fda45f0SMarek Behún int err; 32252fda45f0SMarek Behún 32262fda45f0SMarek Behún if (!chip->info->ops->set_egress_port) 32272fda45f0SMarek Behún return -EOPNOTSUPP; 32282fda45f0SMarek Behún 32292fda45f0SMarek Behún err = chip->info->ops->set_egress_port(chip, direction, port); 32302fda45f0SMarek Behún if (err) 32312fda45f0SMarek Behún return err; 32322fda45f0SMarek Behún 32332fda45f0SMarek Behún if (direction == MV88E6XXX_EGRESS_DIR_INGRESS) 32342fda45f0SMarek Behún chip->ingress_dest_port = port; 32352fda45f0SMarek Behún else 32362fda45f0SMarek Behún chip->egress_dest_port = port; 32372fda45f0SMarek Behún 32382fda45f0SMarek Behún return 0; 32392fda45f0SMarek Behún } 32402fda45f0SMarek Behún 3241fa371c80SVivien Didelot static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 3242fa371c80SVivien Didelot { 3243fa371c80SVivien Didelot struct dsa_switch *ds = chip->ds; 3244fa371c80SVivien Didelot int upstream_port; 3245fa371c80SVivien Didelot int err; 3246fa371c80SVivien Didelot 324707073c79SVivien Didelot upstream_port = dsa_upstream_port(ds, port); 3248fa371c80SVivien Didelot if (chip->info->ops->port_set_upstream_port) { 3249fa371c80SVivien Didelot err = chip->info->ops->port_set_upstream_port(chip, port, 3250fa371c80SVivien Didelot upstream_port); 3251fa371c80SVivien Didelot if (err) 3252fa371c80SVivien Didelot return err; 3253fa371c80SVivien Didelot } 3254fa371c80SVivien Didelot 32550ea54ddaSVivien Didelot if (port == upstream_port) { 32560ea54ddaSVivien Didelot if (chip->info->ops->set_cpu_port) { 32570ea54ddaSVivien Didelot err = chip->info->ops->set_cpu_port(chip, 32580ea54ddaSVivien Didelot upstream_port); 32590ea54ddaSVivien Didelot if (err) 32600ea54ddaSVivien Didelot return err; 32610ea54ddaSVivien Didelot } 32620ea54ddaSVivien Didelot 32632fda45f0SMarek Behún err = mv88e6xxx_set_egress_port(chip, 32645c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS, 32655c74c54cSIwan R Timmer upstream_port); 32662fda45f0SMarek Behún if (err && err != -EOPNOTSUPP) 32675c74c54cSIwan R Timmer return err; 32685c74c54cSIwan R Timmer 32692fda45f0SMarek Behún err = mv88e6xxx_set_egress_port(chip, 32705c74c54cSIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS, 32710ea54ddaSVivien Didelot upstream_port); 32722fda45f0SMarek Behún if (err && err != -EOPNOTSUPP) 32730ea54ddaSVivien Didelot return err; 32740ea54ddaSVivien Didelot } 32750ea54ddaSVivien Didelot 3276fa371c80SVivien Didelot return 0; 3277fa371c80SVivien Didelot } 3278fa371c80SVivien Didelot 3279fad09c73SVivien Didelot static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 3280fad09c73SVivien Didelot { 3281926eae60SHolger Brunck struct device_node *phy_handle = NULL; 3282fad09c73SVivien Didelot struct dsa_switch *ds = chip->ds; 3283926eae60SHolger Brunck struct dsa_port *dp; 3284926eae60SHolger Brunck int tx_amp; 32850e7b9925SAndrew Lunn int err; 3286fad09c73SVivien Didelot u16 reg; 3287fad09c73SVivien Didelot 32887b898469SAndrew Lunn chip->ports[port].chip = chip; 32897b898469SAndrew Lunn chip->ports[port].port = port; 32907b898469SAndrew Lunn 3291d78343d2SVivien Didelot /* MAC Forcing register: don't force link, speed, duplex or flow control 3292d78343d2SVivien Didelot * state to any particular values on physical ports, but force the CPU 3293d78343d2SVivien Didelot * port and all DSA ports to their maximum bandwidth and full duplex. 3294fad09c73SVivien Didelot */ 3295d78343d2SVivien Didelot if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) 3296d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP, 3297d78343d2SVivien Didelot SPEED_MAX, DUPLEX_FULL, 329854186b91SAndrew Lunn PAUSE_OFF, 3299d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 3300fad09c73SVivien Didelot else 3301d78343d2SVivien Didelot err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 3302d78343d2SVivien Didelot SPEED_UNFORCED, DUPLEX_UNFORCED, 330354186b91SAndrew Lunn PAUSE_ON, 3304d78343d2SVivien Didelot PHY_INTERFACE_MODE_NA); 33050e7b9925SAndrew Lunn if (err) 33060e7b9925SAndrew Lunn return err; 3307fad09c73SVivien Didelot 3308fad09c73SVivien Didelot /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 3309fad09c73SVivien Didelot * disable Header mode, enable IGMP/MLD snooping, disable VLAN 3310fad09c73SVivien Didelot * tunneling, determine priority by looking at 802.1p and IP 3311fad09c73SVivien Didelot * priority fields (IP prio has precedence), and set STP state 3312fad09c73SVivien Didelot * to Forwarding. 3313fad09c73SVivien Didelot * 3314fad09c73SVivien Didelot * If this is the CPU link, use DSA or EDSA tagging depending 3315fad09c73SVivien Didelot * on which tagging mode was configured. 3316fad09c73SVivien Didelot * 3317fad09c73SVivien Didelot * If this is a link to another switch, use DSA tagging mode. 3318fad09c73SVivien Didelot * 3319fad09c73SVivien Didelot * If this is the upstream port for this switch, enable 3320fad09c73SVivien Didelot * forwarding of unknown unicasts and multicasts. 3321fad09c73SVivien Didelot */ 3322a89b433bSVivien Didelot reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | 3323a89b433bSVivien Didelot MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 3324a89b433bSVivien Didelot MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 3325a89b433bSVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 33260e7b9925SAndrew Lunn if (err) 33270e7b9925SAndrew Lunn return err; 332856995cbcSAndrew Lunn 3329601aeed3SVivien Didelot err = mv88e6xxx_setup_port_mode(chip, port); 333056995cbcSAndrew Lunn if (err) 333156995cbcSAndrew Lunn return err; 3332fad09c73SVivien Didelot 3333601aeed3SVivien Didelot err = mv88e6xxx_setup_egress_floods(chip, port); 33344314557cSVivien Didelot if (err) 33354314557cSVivien Didelot return err; 33364314557cSVivien Didelot 3337b92ce2f5SAndrew Lunn /* Port Control 2: don't force a good FCS, set the MTU size to 33387af4a361STobias Waldekranz * 10222 bytes, disable 802.1q tags checking, don't discard 33397af4a361STobias Waldekranz * tagged or untagged frames on this port, skip destination 33407af4a361STobias Waldekranz * address lookup on user ports, disable ARP mirroring and don't 33417af4a361STobias Waldekranz * send a copy of all transmitted/received frames on this port 33427af4a361STobias Waldekranz * to the CPU. 3343fad09c73SVivien Didelot */ 33447af4a361STobias Waldekranz err = mv88e6xxx_port_set_map_da(chip, port, !dsa_is_user_port(ds, port)); 3345a23b2961SAndrew Lunn if (err) 3346a23b2961SAndrew Lunn return err; 3347a23b2961SAndrew Lunn 3348fa371c80SVivien Didelot err = mv88e6xxx_setup_upstream_port(chip, port); 33490e7b9925SAndrew Lunn if (err) 33500e7b9925SAndrew Lunn return err; 3351fad09c73SVivien Didelot 3352d352b20fSTobias Waldekranz /* On chips that support it, set all downstream DSA ports' 3353d352b20fSTobias Waldekranz * VLAN policy to TRAP. In combination with loading 3354d352b20fSTobias Waldekranz * MV88E6XXX_VID_STANDALONE as a policy entry in the VTU, this 3355d352b20fSTobias Waldekranz * provides a better isolation barrier between standalone 3356d352b20fSTobias Waldekranz * ports, as the ATU is bypassed on any intermediate switches 3357d352b20fSTobias Waldekranz * between the incoming port and the CPU. 3358d352b20fSTobias Waldekranz */ 3359d352b20fSTobias Waldekranz if (dsa_is_downstream_port(ds, port) && 3360d352b20fSTobias Waldekranz chip->info->ops->port_set_policy) { 3361d352b20fSTobias Waldekranz err = chip->info->ops->port_set_policy(chip, port, 3362d352b20fSTobias Waldekranz MV88E6XXX_POLICY_MAPPING_VTU, 3363d352b20fSTobias Waldekranz MV88E6XXX_POLICY_ACTION_TRAP); 3364d352b20fSTobias Waldekranz if (err) 3365d352b20fSTobias Waldekranz return err; 3366d352b20fSTobias Waldekranz } 3367d352b20fSTobias Waldekranz 3368d352b20fSTobias Waldekranz /* User ports start out in standalone mode and 802.1Q is 3369d352b20fSTobias Waldekranz * therefore disabled. On DSA ports, all valid VIDs are always 3370d352b20fSTobias Waldekranz * loaded in the VTU - therefore, enable 802.1Q in order to take 3371d352b20fSTobias Waldekranz * advantage of VLAN policy on chips that supports it. 3372d352b20fSTobias Waldekranz */ 3373a23b2961SAndrew Lunn err = mv88e6xxx_port_set_8021q_mode(chip, port, 3374d352b20fSTobias Waldekranz dsa_is_user_port(ds, port) ? 3375d352b20fSTobias Waldekranz MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED : 3376d352b20fSTobias Waldekranz MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE); 3377d352b20fSTobias Waldekranz if (err) 3378d352b20fSTobias Waldekranz return err; 3379d352b20fSTobias Waldekranz 3380d352b20fSTobias Waldekranz /* Bind MV88E6XXX_VID_STANDALONE to MV88E6XXX_FID_STANDALONE by 3381d352b20fSTobias Waldekranz * virtue of the fact that mv88e6xxx_atu_new() will pick it as 3382d352b20fSTobias Waldekranz * the first free FID. This will be used as the private PVID for 3383d352b20fSTobias Waldekranz * unbridged ports. Shared (DSA and CPU) ports must also be 3384d352b20fSTobias Waldekranz * members of this VID, in order to trap all frames assigned to 3385d352b20fSTobias Waldekranz * it to the CPU. 3386d352b20fSTobias Waldekranz */ 3387d352b20fSTobias Waldekranz err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_STANDALONE, 3388d352b20fSTobias Waldekranz MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED, 3389d352b20fSTobias Waldekranz false); 3390a23b2961SAndrew Lunn if (err) 3391a23b2961SAndrew Lunn return err; 3392a23b2961SAndrew Lunn 33935bded825SVladimir Oltean /* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the 33945bded825SVladimir Oltean * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as 33955bded825SVladimir Oltean * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used 33965bded825SVladimir Oltean * as the private PVID on ports under a VLAN-unaware bridge. 33975bded825SVladimir Oltean * Shared (DSA and CPU) ports must also be members of it, to translate 33985bded825SVladimir Oltean * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of 33995bded825SVladimir Oltean * relying on their port default FID. 34005bded825SVladimir Oltean */ 34015bded825SVladimir Oltean err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED, 3402d352b20fSTobias Waldekranz MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED, 34035bded825SVladimir Oltean false); 34045bded825SVladimir Oltean if (err) 34055bded825SVladimir Oltean return err; 34065bded825SVladimir Oltean 3407cd782656SVivien Didelot if (chip->info->ops->port_set_jumbo_size) { 3408b92ce2f5SAndrew Lunn err = chip->info->ops->port_set_jumbo_size(chip, port, 10218); 34095f436666SAndrew Lunn if (err) 34105f436666SAndrew Lunn return err; 34115f436666SAndrew Lunn } 34125f436666SAndrew Lunn 3413041bd545STobias Waldekranz /* Port Association Vector: disable automatic address learning 3414041bd545STobias Waldekranz * on all user ports since they start out in standalone 3415041bd545STobias Waldekranz * mode. When joining a bridge, learning will be configured to 3416041bd545STobias Waldekranz * match the bridge port settings. Enable learning on all 3417041bd545STobias Waldekranz * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the 3418041bd545STobias Waldekranz * learning process. 3419041bd545STobias Waldekranz * 3420041bd545STobias Waldekranz * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData, 3421041bd545STobias Waldekranz * and RefreshLocked. I.e. setup standard automatic learning. 3422fad09c73SVivien Didelot */ 3423041bd545STobias Waldekranz if (dsa_is_user_port(ds, port)) 3424fad09c73SVivien Didelot reg = 0; 3425041bd545STobias Waldekranz else 3426041bd545STobias Waldekranz reg = 1 << port; 3427fad09c73SVivien Didelot 34282a4614e4SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 34292a4614e4SVivien Didelot reg); 34300e7b9925SAndrew Lunn if (err) 34310e7b9925SAndrew Lunn return err; 3432fad09c73SVivien Didelot 3433fad09c73SVivien Didelot /* Egress rate control 2: disable egress rate control. */ 34342cb8cb14SVivien Didelot err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 34352cb8cb14SVivien Didelot 0x0000); 34360e7b9925SAndrew Lunn if (err) 34370e7b9925SAndrew Lunn return err; 3438fad09c73SVivien Didelot 34390898432cSVivien Didelot if (chip->info->ops->port_pause_limit) { 34400898432cSVivien Didelot err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 3441b35d322aSAndrew Lunn if (err) 3442b35d322aSAndrew Lunn return err; 3443b35d322aSAndrew Lunn } 3444b35d322aSAndrew Lunn 3445c8c94891SVivien Didelot if (chip->info->ops->port_disable_learn_limit) { 3446c8c94891SVivien Didelot err = chip->info->ops->port_disable_learn_limit(chip, port); 3447c8c94891SVivien Didelot if (err) 3448c8c94891SVivien Didelot return err; 3449c8c94891SVivien Didelot } 3450c8c94891SVivien Didelot 34519dbfb4e1SVivien Didelot if (chip->info->ops->port_disable_pri_override) { 34529dbfb4e1SVivien Didelot err = chip->info->ops->port_disable_pri_override(chip, port); 34530e7b9925SAndrew Lunn if (err) 34540e7b9925SAndrew Lunn return err; 3455ef0a7318SAndrew Lunn } 34562bbb33beSAndrew Lunn 3457ef0a7318SAndrew Lunn if (chip->info->ops->port_tag_remap) { 3458ef0a7318SAndrew Lunn err = chip->info->ops->port_tag_remap(chip, port); 34590e7b9925SAndrew Lunn if (err) 34600e7b9925SAndrew Lunn return err; 3461fad09c73SVivien Didelot } 3462fad09c73SVivien Didelot 3463ef70b111SAndrew Lunn if (chip->info->ops->port_egress_rate_limiting) { 3464ef70b111SAndrew Lunn err = chip->info->ops->port_egress_rate_limiting(chip, port); 34650e7b9925SAndrew Lunn if (err) 34660e7b9925SAndrew Lunn return err; 3467fad09c73SVivien Didelot } 3468fad09c73SVivien Didelot 3469121b8fe2SHubert Feurstein if (chip->info->ops->port_setup_message_port) { 3470121b8fe2SHubert Feurstein err = chip->info->ops->port_setup_message_port(chip, port); 34710e7b9925SAndrew Lunn if (err) 34720e7b9925SAndrew Lunn return err; 3473121b8fe2SHubert Feurstein } 3474fad09c73SVivien Didelot 3475926eae60SHolger Brunck if (chip->info->ops->serdes_set_tx_amplitude) { 3476926eae60SHolger Brunck dp = dsa_to_port(ds, port); 3477926eae60SHolger Brunck if (dp) 3478926eae60SHolger Brunck phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0); 3479926eae60SHolger Brunck 3480926eae60SHolger Brunck if (phy_handle && !of_property_read_u32(phy_handle, 3481926eae60SHolger Brunck "tx-p2p-microvolt", 3482926eae60SHolger Brunck &tx_amp)) 3483926eae60SHolger Brunck err = chip->info->ops->serdes_set_tx_amplitude(chip, 3484926eae60SHolger Brunck port, tx_amp); 3485926eae60SHolger Brunck if (phy_handle) { 3486926eae60SHolger Brunck of_node_put(phy_handle); 3487926eae60SHolger Brunck if (err) 3488926eae60SHolger Brunck return err; 3489926eae60SHolger Brunck } 3490926eae60SHolger Brunck } 3491926eae60SHolger Brunck 3492fad09c73SVivien Didelot /* Port based VLAN map: give each port the same default address 3493fad09c73SVivien Didelot * database, and allow bidirectional communication between the 3494fad09c73SVivien Didelot * CPU and DSA port(s), and the other ports. 3495fad09c73SVivien Didelot */ 34965bded825SVladimir Oltean err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE); 34970e7b9925SAndrew Lunn if (err) 34980e7b9925SAndrew Lunn return err; 3499fad09c73SVivien Didelot 3500240ea3efSVivien Didelot err = mv88e6xxx_port_vlan_map(chip, port); 35010e7b9925SAndrew Lunn if (err) 35020e7b9925SAndrew Lunn return err; 3503fad09c73SVivien Didelot 3504fad09c73SVivien Didelot /* Default VLAN ID and priority: don't set a default VLAN 3505fad09c73SVivien Didelot * ID, and set the default packet priority to zero. 3506fad09c73SVivien Didelot */ 3507b7929fb3SVivien Didelot return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 3508fad09c73SVivien Didelot } 3509fad09c73SVivien Didelot 35102a550aecSAndrew Lunn static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port) 35112a550aecSAndrew Lunn { 35122a550aecSAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 35132a550aecSAndrew Lunn 35142a550aecSAndrew Lunn if (chip->info->ops->port_set_jumbo_size) 3515b9c587feSAndrew Lunn return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 35161baf0facSChris Packham else if (chip->info->ops->set_max_frame_size) 3517b9c587feSAndrew Lunn return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 3518b9c587feSAndrew Lunn return 1522 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 35192a550aecSAndrew Lunn } 35202a550aecSAndrew Lunn 35212a550aecSAndrew Lunn static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 35222a550aecSAndrew Lunn { 35232a550aecSAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 35242a550aecSAndrew Lunn int ret = 0; 35252a550aecSAndrew Lunn 3526b9c587feSAndrew Lunn if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 3527b9c587feSAndrew Lunn new_mtu += EDSA_HLEN; 3528b9c587feSAndrew Lunn 35292a550aecSAndrew Lunn mv88e6xxx_reg_lock(chip); 35302a550aecSAndrew Lunn if (chip->info->ops->port_set_jumbo_size) 35312a550aecSAndrew Lunn ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu); 35321baf0facSChris Packham else if (chip->info->ops->set_max_frame_size) 35331baf0facSChris Packham ret = chip->info->ops->set_max_frame_size(chip, new_mtu); 35342a550aecSAndrew Lunn else 35352a550aecSAndrew Lunn if (new_mtu > 1522) 35362a550aecSAndrew Lunn ret = -EINVAL; 35372a550aecSAndrew Lunn mv88e6xxx_reg_unlock(chip); 35382a550aecSAndrew Lunn 35392a550aecSAndrew Lunn return ret; 35402a550aecSAndrew Lunn } 35412a550aecSAndrew Lunn 354204aca993SAndrew Lunn static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, 354304aca993SAndrew Lunn struct phy_device *phydev) 354404aca993SAndrew Lunn { 354504aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 3546523a8904SVivien Didelot int err; 354704aca993SAndrew Lunn 3548c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3549523a8904SVivien Didelot err = mv88e6xxx_serdes_power(chip, port, true); 3550c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 355104aca993SAndrew Lunn 355204aca993SAndrew Lunn return err; 355304aca993SAndrew Lunn } 355404aca993SAndrew Lunn 355575104db0SAndrew Lunn static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port) 355604aca993SAndrew Lunn { 355704aca993SAndrew Lunn struct mv88e6xxx_chip *chip = ds->priv; 355804aca993SAndrew Lunn 3559c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3560523a8904SVivien Didelot if (mv88e6xxx_serdes_power(chip, port, false)) 3561523a8904SVivien Didelot dev_err(chip->dev, "failed to power off SERDES\n"); 3562c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 356304aca993SAndrew Lunn } 356404aca993SAndrew Lunn 35652cfcd964SVivien Didelot static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 35662cfcd964SVivien Didelot unsigned int ageing_time) 35672cfcd964SVivien Didelot { 356804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 35692cfcd964SVivien Didelot int err; 35702cfcd964SVivien Didelot 3571c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3572720c6343SVivien Didelot err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 3573c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 35742cfcd964SVivien Didelot 35752cfcd964SVivien Didelot return err; 35762cfcd964SVivien Didelot } 35772cfcd964SVivien Didelot 3578447b1bb8SVivien Didelot static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 3579fad09c73SVivien Didelot { 3580fad09c73SVivien Didelot int err; 3581fad09c73SVivien Didelot 3582de227387SAndrew Lunn /* Initialize the statistics unit */ 3583447b1bb8SVivien Didelot if (chip->info->ops->stats_set_histogram) { 3584447b1bb8SVivien Didelot err = chip->info->ops->stats_set_histogram(chip); 3585de227387SAndrew Lunn if (err) 3586de227387SAndrew Lunn return err; 3587447b1bb8SVivien Didelot } 3588de227387SAndrew Lunn 358940cff8fcSAndrew Lunn return mv88e6xxx_g1_stats_clear(chip); 35909729934cSVivien Didelot } 35919729934cSVivien Didelot 3592ea89098eSAndrew Lunn /* Check if the errata has already been applied. */ 3593ea89098eSAndrew Lunn static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 3594ea89098eSAndrew Lunn { 3595ea89098eSAndrew Lunn int port; 3596ea89098eSAndrew Lunn int err; 3597ea89098eSAndrew Lunn u16 val; 3598ea89098eSAndrew Lunn 3599ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 360060907013SMarek Behún err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val); 3601ea89098eSAndrew Lunn if (err) { 3602ea89098eSAndrew Lunn dev_err(chip->dev, 3603ea89098eSAndrew Lunn "Error reading hidden register: %d\n", err); 3604ea89098eSAndrew Lunn return false; 3605ea89098eSAndrew Lunn } 3606ea89098eSAndrew Lunn if (val != 0x01c0) 3607ea89098eSAndrew Lunn return false; 3608ea89098eSAndrew Lunn } 3609ea89098eSAndrew Lunn 3610ea89098eSAndrew Lunn return true; 3611ea89098eSAndrew Lunn } 3612ea89098eSAndrew Lunn 3613ea89098eSAndrew Lunn /* The 6390 copper ports have an errata which require poking magic 3614ea89098eSAndrew Lunn * values into undocumented hidden registers and then performing a 3615ea89098eSAndrew Lunn * software reset. 3616ea89098eSAndrew Lunn */ 3617ea89098eSAndrew Lunn static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 3618ea89098eSAndrew Lunn { 3619ea89098eSAndrew Lunn int port; 3620ea89098eSAndrew Lunn int err; 3621ea89098eSAndrew Lunn 3622ea89098eSAndrew Lunn if (mv88e6390_setup_errata_applied(chip)) 3623ea89098eSAndrew Lunn return 0; 3624ea89098eSAndrew Lunn 3625ea89098eSAndrew Lunn /* Set the ports into blocking mode */ 3626ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 3627ea89098eSAndrew Lunn err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 3628ea89098eSAndrew Lunn if (err) 3629ea89098eSAndrew Lunn return err; 3630ea89098eSAndrew Lunn } 3631ea89098eSAndrew Lunn 3632ea89098eSAndrew Lunn for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 363360907013SMarek Behún err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0); 3634ea89098eSAndrew Lunn if (err) 3635ea89098eSAndrew Lunn return err; 3636ea89098eSAndrew Lunn } 3637ea89098eSAndrew Lunn 3638ea89098eSAndrew Lunn return mv88e6xxx_software_reset(chip); 3639ea89098eSAndrew Lunn } 3640ea89098eSAndrew Lunn 364123e8b470SAndrew Lunn static void mv88e6xxx_teardown(struct dsa_switch *ds) 364223e8b470SAndrew Lunn { 364323e8b470SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 3644e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3645fd292c18SVladimir Oltean mv88e6xxx_teardown_devlink_regions_global(ds); 364623e8b470SAndrew Lunn } 364723e8b470SAndrew Lunn 3648fad09c73SVivien Didelot static int mv88e6xxx_setup(struct dsa_switch *ds) 3649fad09c73SVivien Didelot { 365004bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 36512d2e1dd2SAndrew Lunn u8 cmode; 3652fad09c73SVivien Didelot int err; 3653fad09c73SVivien Didelot int i; 3654fad09c73SVivien Didelot 3655fad09c73SVivien Didelot chip->ds = ds; 3656a3c53be5SAndrew Lunn ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 3657fad09c73SVivien Didelot 3658ce5df689SVladimir Oltean /* Since virtual bridges are mapped in the PVT, the number we support 3659ce5df689SVladimir Oltean * depends on the physical switch topology. We need to let DSA figure 3660ce5df689SVladimir Oltean * that out and therefore we cannot set this at dsa_register_switch() 3661ce5df689SVladimir Oltean * time. 3662ce5df689SVladimir Oltean */ 3663ce5df689SVladimir Oltean if (mv88e6xxx_has_pvt(chip)) 3664947c8746SVladimir Oltean ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES - 3665ce5df689SVladimir Oltean ds->dst->last_switch - 1; 3666ce5df689SVladimir Oltean 3667c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3668fad09c73SVivien Didelot 3669ea89098eSAndrew Lunn if (chip->info->ops->setup_errata) { 3670ea89098eSAndrew Lunn err = chip->info->ops->setup_errata(chip); 3671ea89098eSAndrew Lunn if (err) 3672ea89098eSAndrew Lunn goto unlock; 3673ea89098eSAndrew Lunn } 3674ea89098eSAndrew Lunn 36752d2e1dd2SAndrew Lunn /* Cache the cmode of each port. */ 36762d2e1dd2SAndrew Lunn for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 36772d2e1dd2SAndrew Lunn if (chip->info->ops->port_get_cmode) { 36782d2e1dd2SAndrew Lunn err = chip->info->ops->port_get_cmode(chip, i, &cmode); 36792d2e1dd2SAndrew Lunn if (err) 3680e29129fcSDan Carpenter goto unlock; 36812d2e1dd2SAndrew Lunn 36822d2e1dd2SAndrew Lunn chip->ports[i].cmode = cmode; 36832d2e1dd2SAndrew Lunn } 36842d2e1dd2SAndrew Lunn } 36852d2e1dd2SAndrew Lunn 36865bded825SVladimir Oltean err = mv88e6xxx_vtu_setup(chip); 36875bded825SVladimir Oltean if (err) 36885bded825SVladimir Oltean goto unlock; 36895bded825SVladimir Oltean 369049c98c1dSTobias Waldekranz /* Must be called after mv88e6xxx_vtu_setup (which flushes the 369149c98c1dSTobias Waldekranz * VTU, thereby also flushing the STU). 369249c98c1dSTobias Waldekranz */ 369349c98c1dSTobias Waldekranz err = mv88e6xxx_stu_setup(chip); 369449c98c1dSTobias Waldekranz if (err) 369549c98c1dSTobias Waldekranz goto unlock; 369649c98c1dSTobias Waldekranz 36979729934cSVivien Didelot /* Setup Switch Port Registers */ 3698370b4ffbSVivien Didelot for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 3699b759f528SVivien Didelot if (dsa_is_unused_port(ds, i)) 3700b759f528SVivien Didelot continue; 3701b759f528SVivien Didelot 3702c857486aSHubert Feurstein /* Prevent the use of an invalid port. */ 3703b759f528SVivien Didelot if (mv88e6xxx_is_invalid_port(chip, i)) { 3704c857486aSHubert Feurstein dev_err(chip->dev, "port %d is invalid\n", i); 3705c857486aSHubert Feurstein err = -EINVAL; 3706c857486aSHubert Feurstein goto unlock; 3707c857486aSHubert Feurstein } 3708c857486aSHubert Feurstein 37099729934cSVivien Didelot err = mv88e6xxx_setup_port(chip, i); 37109729934cSVivien Didelot if (err) 37119729934cSVivien Didelot goto unlock; 37129729934cSVivien Didelot } 37139729934cSVivien Didelot 3714cd8da8bbSVivien Didelot err = mv88e6xxx_irl_setup(chip); 3715cd8da8bbSVivien Didelot if (err) 3716cd8da8bbSVivien Didelot goto unlock; 3717cd8da8bbSVivien Didelot 371804a69a17SVivien Didelot err = mv88e6xxx_mac_setup(chip); 371904a69a17SVivien Didelot if (err) 372004a69a17SVivien Didelot goto unlock; 372104a69a17SVivien Didelot 37221b17aedfSVivien Didelot err = mv88e6xxx_phy_setup(chip); 37231b17aedfSVivien Didelot if (err) 37241b17aedfSVivien Didelot goto unlock; 37251b17aedfSVivien Didelot 372681228996SVivien Didelot err = mv88e6xxx_pvt_setup(chip); 372781228996SVivien Didelot if (err) 372881228996SVivien Didelot goto unlock; 372981228996SVivien Didelot 3730a2ac29d2SVivien Didelot err = mv88e6xxx_atu_setup(chip); 3731a2ac29d2SVivien Didelot if (err) 3732a2ac29d2SVivien Didelot goto unlock; 3733a2ac29d2SVivien Didelot 373487fa886eSAndrew Lunn err = mv88e6xxx_broadcast_setup(chip, 0); 373587fa886eSAndrew Lunn if (err) 373687fa886eSAndrew Lunn goto unlock; 373787fa886eSAndrew Lunn 37389e907d73SVivien Didelot err = mv88e6xxx_pot_setup(chip); 37399e907d73SVivien Didelot if (err) 37409e907d73SVivien Didelot goto unlock; 37419e907d73SVivien Didelot 37429e5baf9bSVivien Didelot err = mv88e6xxx_rmu_setup(chip); 37439e5baf9bSVivien Didelot if (err) 37449e5baf9bSVivien Didelot goto unlock; 37459e5baf9bSVivien Didelot 374651c901a7SVivien Didelot err = mv88e6xxx_rsvd2cpu_setup(chip); 37476e55f698SAndrew Lunn if (err) 37486e55f698SAndrew Lunn goto unlock; 37496e55f698SAndrew Lunn 3750b28f872dSVivien Didelot err = mv88e6xxx_trunk_setup(chip); 3751b28f872dSVivien Didelot if (err) 3752b28f872dSVivien Didelot goto unlock; 3753b28f872dSVivien Didelot 3754c7f047b6SVivien Didelot err = mv88e6xxx_devmap_setup(chip); 3755c7f047b6SVivien Didelot if (err) 3756c7f047b6SVivien Didelot goto unlock; 3757c7f047b6SVivien Didelot 375893e18d61SVivien Didelot err = mv88e6xxx_pri_setup(chip); 375993e18d61SVivien Didelot if (err) 376093e18d61SVivien Didelot goto unlock; 376193e18d61SVivien Didelot 3762c6fe0ad2SBrandon Streiff /* Setup PTP Hardware Clock and timestamping */ 37632fa8d3afSBrandon Streiff if (chip->info->ptp_support) { 37642fa8d3afSBrandon Streiff err = mv88e6xxx_ptp_setup(chip); 37652fa8d3afSBrandon Streiff if (err) 37662fa8d3afSBrandon Streiff goto unlock; 3767c6fe0ad2SBrandon Streiff 3768c6fe0ad2SBrandon Streiff err = mv88e6xxx_hwtstamp_setup(chip); 3769c6fe0ad2SBrandon Streiff if (err) 3770c6fe0ad2SBrandon Streiff goto unlock; 37712fa8d3afSBrandon Streiff } 37722fa8d3afSBrandon Streiff 3773447b1bb8SVivien Didelot err = mv88e6xxx_stats_setup(chip); 3774447b1bb8SVivien Didelot if (err) 3775447b1bb8SVivien Didelot goto unlock; 3776447b1bb8SVivien Didelot 3777fad09c73SVivien Didelot unlock: 3778c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3779fad09c73SVivien Didelot 3780e0c69ca7SAndrew Lunn if (err) 3781e0c69ca7SAndrew Lunn return err; 3782e0c69ca7SAndrew Lunn 3783e0c69ca7SAndrew Lunn /* Have to be called without holding the register lock, since 3784e0c69ca7SAndrew Lunn * they take the devlink lock, and we later take the locks in 3785e0c69ca7SAndrew Lunn * the reverse order when getting/setting parameters or 3786e0c69ca7SAndrew Lunn * resource occupancy. 378723e8b470SAndrew Lunn */ 3788e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_resources(ds); 3789e0c69ca7SAndrew Lunn if (err) 3790e0c69ca7SAndrew Lunn return err; 3791e0c69ca7SAndrew Lunn 3792e0c69ca7SAndrew Lunn err = mv88e6xxx_setup_devlink_params(ds); 3793e0c69ca7SAndrew Lunn if (err) 3794bfb25542SAndrew Lunn goto out_resources; 3795bfb25542SAndrew Lunn 3796fd292c18SVladimir Oltean err = mv88e6xxx_setup_devlink_regions_global(ds); 3797bfb25542SAndrew Lunn if (err) 3798bfb25542SAndrew Lunn goto out_params; 3799bfb25542SAndrew Lunn 3800bfb25542SAndrew Lunn return 0; 3801bfb25542SAndrew Lunn 3802bfb25542SAndrew Lunn out_params: 3803bfb25542SAndrew Lunn mv88e6xxx_teardown_devlink_params(ds); 3804bfb25542SAndrew Lunn out_resources: 3805e0c69ca7SAndrew Lunn dsa_devlink_resources_unregister(ds); 3806e0c69ca7SAndrew Lunn 3807e0c69ca7SAndrew Lunn return err; 3808fad09c73SVivien Didelot } 3809fad09c73SVivien Didelot 3810fd292c18SVladimir Oltean static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port) 3811fd292c18SVladimir Oltean { 3812fd292c18SVladimir Oltean return mv88e6xxx_setup_devlink_regions_port(ds, port); 3813fd292c18SVladimir Oltean } 3814fd292c18SVladimir Oltean 3815fd292c18SVladimir Oltean static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port) 3816fd292c18SVladimir Oltean { 3817fd292c18SVladimir Oltean mv88e6xxx_teardown_devlink_regions_port(ds, port); 3818fd292c18SVladimir Oltean } 3819fd292c18SVladimir Oltean 38201fe976d3SPali Rohár /* prod_id for switch families which do not have a PHY model number */ 38211fe976d3SPali Rohár static const u16 family_prod_id_table[] = { 38221fe976d3SPali Rohár [MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 38231fe976d3SPali Rohár [MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 3824c5d015b0SMarek Behún [MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, 38251fe976d3SPali Rohár }; 38261fe976d3SPali Rohár 3827e57e5e77SVivien Didelot static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 3828fad09c73SVivien Didelot { 38290dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 38300dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 38311fe976d3SPali Rohár u16 prod_id; 3832e57e5e77SVivien Didelot u16 val; 3833e57e5e77SVivien Didelot int err; 3834fad09c73SVivien Didelot 3835ee26a228SAndrew Lunn if (!chip->info->ops->phy_read) 3836ee26a228SAndrew Lunn return -EOPNOTSUPP; 3837ee26a228SAndrew Lunn 3838c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3839ee26a228SAndrew Lunn err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 3840c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3841e57e5e77SVivien Didelot 3842ddc49acbSAndrew Lunn /* Some internal PHYs don't have a model number. */ 38431fe976d3SPali Rohár if (reg == MII_PHYSID2 && !(val & 0x3f0) && 38441fe976d3SPali Rohár chip->info->family < ARRAY_SIZE(family_prod_id_table)) { 38451fe976d3SPali Rohár prod_id = family_prod_id_table[chip->info->family]; 38461fe976d3SPali Rohár if (prod_id) 38471fe976d3SPali Rohár val |= prod_id >> 4; 3848da9f3301SAndrew Lunn } 3849da9f3301SAndrew Lunn 3850e57e5e77SVivien Didelot return err ? err : val; 3851fad09c73SVivien Didelot } 3852fad09c73SVivien Didelot 3853e57e5e77SVivien Didelot static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 3854fad09c73SVivien Didelot { 38550dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 38560dd12d54SAndrew Lunn struct mv88e6xxx_chip *chip = mdio_bus->chip; 3857e57e5e77SVivien Didelot int err; 3858fad09c73SVivien Didelot 3859ee26a228SAndrew Lunn if (!chip->info->ops->phy_write) 3860ee26a228SAndrew Lunn return -EOPNOTSUPP; 3861ee26a228SAndrew Lunn 3862c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 3863ee26a228SAndrew Lunn err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 3864c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 3865e57e5e77SVivien Didelot 3866e57e5e77SVivien Didelot return err; 3867fad09c73SVivien Didelot } 3868fad09c73SVivien Didelot 3869fad09c73SVivien Didelot static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 3870a3c53be5SAndrew Lunn struct device_node *np, 3871a3c53be5SAndrew Lunn bool external) 3872fad09c73SVivien Didelot { 3873fad09c73SVivien Didelot static int index; 38740dd12d54SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus; 3875fad09c73SVivien Didelot struct mii_bus *bus; 3876fad09c73SVivien Didelot int err; 3877fad09c73SVivien Didelot 38782510babcSAndrew Lunn if (external) { 3879c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 38802510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 3881c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 38822510babcSAndrew Lunn 38832510babcSAndrew Lunn if (err) 38842510babcSAndrew Lunn return err; 38852510babcSAndrew Lunn } 38862510babcSAndrew Lunn 3887f53a2ce8SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_bus)); 3888fad09c73SVivien Didelot if (!bus) 3889fad09c73SVivien Didelot return -ENOMEM; 3890fad09c73SVivien Didelot 38910dd12d54SAndrew Lunn mdio_bus = bus->priv; 3892a3c53be5SAndrew Lunn mdio_bus->bus = bus; 38930dd12d54SAndrew Lunn mdio_bus->chip = chip; 3894a3c53be5SAndrew Lunn INIT_LIST_HEAD(&mdio_bus->list); 3895a3c53be5SAndrew Lunn mdio_bus->external = external; 38960dd12d54SAndrew Lunn 3897fad09c73SVivien Didelot if (np) { 3898fad09c73SVivien Didelot bus->name = np->full_name; 3899f7ce9103SRob Herring snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 3900fad09c73SVivien Didelot } else { 3901fad09c73SVivien Didelot bus->name = "mv88e6xxx SMI"; 3902fad09c73SVivien Didelot snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 3903fad09c73SVivien Didelot } 3904fad09c73SVivien Didelot 3905fad09c73SVivien Didelot bus->read = mv88e6xxx_mdio_read; 3906fad09c73SVivien Didelot bus->write = mv88e6xxx_mdio_write; 3907fad09c73SVivien Didelot bus->parent = chip->dev; 3908fad09c73SVivien Didelot 39096f88284fSAndrew Lunn if (!external) { 39106f88284fSAndrew Lunn err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 39116f88284fSAndrew Lunn if (err) 3912f53a2ce8SVladimir Oltean goto out; 39136f88284fSAndrew Lunn } 39146f88284fSAndrew Lunn 3915a3c53be5SAndrew Lunn err = of_mdiobus_register(bus, np); 3916fad09c73SVivien Didelot if (err) { 3917fad09c73SVivien Didelot dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 39186f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 3919f53a2ce8SVladimir Oltean goto out; 3920fad09c73SVivien Didelot } 3921fad09c73SVivien Didelot 3922a3c53be5SAndrew Lunn if (external) 3923a3c53be5SAndrew Lunn list_add_tail(&mdio_bus->list, &chip->mdios); 3924a3c53be5SAndrew Lunn else 3925a3c53be5SAndrew Lunn list_add(&mdio_bus->list, &chip->mdios); 3926a3c53be5SAndrew Lunn 3927a3c53be5SAndrew Lunn return 0; 3928f53a2ce8SVladimir Oltean 3929f53a2ce8SVladimir Oltean out: 3930f53a2ce8SVladimir Oltean mdiobus_free(bus); 3931f53a2ce8SVladimir Oltean return err; 3932a3c53be5SAndrew Lunn } 3933a3c53be5SAndrew Lunn 39343126aeecSAndrew Lunn static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 39353126aeecSAndrew Lunn 39363126aeecSAndrew Lunn { 393751a04ebfSVladimir Oltean struct mv88e6xxx_mdio_bus *mdio_bus, *p; 39383126aeecSAndrew Lunn struct mii_bus *bus; 39393126aeecSAndrew Lunn 394051a04ebfSVladimir Oltean list_for_each_entry_safe(mdio_bus, p, &chip->mdios, list) { 39413126aeecSAndrew Lunn bus = mdio_bus->bus; 39423126aeecSAndrew Lunn 39436f88284fSAndrew Lunn if (!mdio_bus->external) 39446f88284fSAndrew Lunn mv88e6xxx_g2_irq_mdio_free(chip, bus); 39456f88284fSAndrew Lunn 39463126aeecSAndrew Lunn mdiobus_unregister(bus); 3947f53a2ce8SVladimir Oltean mdiobus_free(bus); 39483126aeecSAndrew Lunn } 39493126aeecSAndrew Lunn } 39503126aeecSAndrew Lunn 3951a3c53be5SAndrew Lunn static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, 3952a3c53be5SAndrew Lunn struct device_node *np) 3953a3c53be5SAndrew Lunn { 3954a3c53be5SAndrew Lunn struct device_node *child; 3955a3c53be5SAndrew Lunn int err; 3956a3c53be5SAndrew Lunn 3957a3c53be5SAndrew Lunn /* Always register one mdio bus for the internal/default mdio 3958a3c53be5SAndrew Lunn * bus. This maybe represented in the device tree, but is 3959a3c53be5SAndrew Lunn * optional. 3960a3c53be5SAndrew Lunn */ 3961a3c53be5SAndrew Lunn child = of_get_child_by_name(np, "mdio"); 3962a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, false); 3963a3c53be5SAndrew Lunn if (err) 3964a3c53be5SAndrew Lunn return err; 3965a3c53be5SAndrew Lunn 3966a3c53be5SAndrew Lunn /* Walk the device tree, and see if there are any other nodes 3967a3c53be5SAndrew Lunn * which say they are compatible with the external mdio 3968a3c53be5SAndrew Lunn * bus. 3969a3c53be5SAndrew Lunn */ 3970a3c53be5SAndrew Lunn for_each_available_child_of_node(np, child) { 3971ceb96faeSAndrew Lunn if (of_device_is_compatible( 3972ceb96faeSAndrew Lunn child, "marvell,mv88e6xxx-mdio-external")) { 3973a3c53be5SAndrew Lunn err = mv88e6xxx_mdio_register(chip, child, true); 39743126aeecSAndrew Lunn if (err) { 39753126aeecSAndrew Lunn mv88e6xxx_mdios_unregister(chip); 397678e42040SNishka Dasgupta of_node_put(child); 3977a3c53be5SAndrew Lunn return err; 3978a3c53be5SAndrew Lunn } 3979a3c53be5SAndrew Lunn } 39803126aeecSAndrew Lunn } 3981a3c53be5SAndrew Lunn 3982a3c53be5SAndrew Lunn return 0; 3983a3c53be5SAndrew Lunn } 3984a3c53be5SAndrew Lunn 3985855b1932SVivien Didelot static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 3986855b1932SVivien Didelot { 398704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3988855b1932SVivien Didelot 3989855b1932SVivien Didelot return chip->eeprom_len; 3990855b1932SVivien Didelot } 3991855b1932SVivien Didelot 3992855b1932SVivien Didelot static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 3993855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 3994855b1932SVivien Didelot { 399504bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 3996855b1932SVivien Didelot int err; 3997855b1932SVivien Didelot 3998ee4dc2e7SVivien Didelot if (!chip->info->ops->get_eeprom) 3999ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 4000ee4dc2e7SVivien Didelot 4001c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 4002ee4dc2e7SVivien Didelot err = chip->info->ops->get_eeprom(chip, eeprom, data); 4003c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 4004855b1932SVivien Didelot 4005855b1932SVivien Didelot if (err) 4006855b1932SVivien Didelot return err; 4007855b1932SVivien Didelot 4008855b1932SVivien Didelot eeprom->magic = 0xc3ec4951; 4009855b1932SVivien Didelot 4010855b1932SVivien Didelot return 0; 4011855b1932SVivien Didelot } 4012855b1932SVivien Didelot 4013855b1932SVivien Didelot static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 4014855b1932SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 4015855b1932SVivien Didelot { 401604bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 4017855b1932SVivien Didelot int err; 4018855b1932SVivien Didelot 4019ee4dc2e7SVivien Didelot if (!chip->info->ops->set_eeprom) 4020ee4dc2e7SVivien Didelot return -EOPNOTSUPP; 4021ee4dc2e7SVivien Didelot 4022855b1932SVivien Didelot if (eeprom->magic != 0xc3ec4951) 4023855b1932SVivien Didelot return -EINVAL; 4024855b1932SVivien Didelot 4025c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 4026ee4dc2e7SVivien Didelot err = chip->info->ops->set_eeprom(chip, eeprom, data); 4027c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 4028855b1932SVivien Didelot 4029855b1932SVivien Didelot return err; 4030855b1932SVivien Didelot } 4031855b1932SVivien Didelot 4032b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6085_ops = { 40334b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6097 */ 403493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 403593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4036cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4037b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 40387e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 40397e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 404008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 40414efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4042f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4043ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 404456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4045a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4046a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 404756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4048ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 40490898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4050c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 40519dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 40522d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4053121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4054a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 405540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4056dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4057dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4058052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4059fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4060fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4061fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 406251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 40639e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 4064a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 4065a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 406617e708baSVivien Didelot .reset = mv88e6185_g1_reset, 40679e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 4068f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 40690ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4070c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4071c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4072d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 40731baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 4074b3469dd8SVivien Didelot }; 4075b3469dd8SVivien Didelot 4076b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6095_ops = { 40774b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6095 */ 407893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 407993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4080b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 40817e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 40827e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 408308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 40844efe7662SChris Packham .port_sync_link = mv88e6185_port_sync_link, 4085f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 408656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 4087a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 4088a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6185_port_set_default_forward, 4089a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 40902d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4091121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4092a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 409340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4094dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4095dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4096052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 409751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 4098f5be107cSChris Packham .serdes_power = mv88e6185_serdes_power, 4099f5be107cSChris Packham .serdes_get_lane = mv88e6185_serdes_get_lane, 4100f5be107cSChris Packham .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state, 4101a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 4102a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 410317e708baSVivien Didelot .reset = mv88e6185_g1_reset, 4104f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 41050ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4106d0b78ab1STobias Waldekranz .phylink_get_caps = mv88e6095_phylink_get_caps, 41071baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 4108b3469dd8SVivien Didelot }; 4109b3469dd8SVivien Didelot 41107d381a02SStefan Eichenberger static const struct mv88e6xxx_ops mv88e6097_ops = { 411115da3cc8SStefan Eichenberger /* MV88E6XXX_FAMILY_6097 */ 411293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 411393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4114cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 41157d381a02SStefan Eichenberger .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 41167d381a02SStefan Eichenberger .phy_read = mv88e6xxx_g2_smi_phy_read, 41177d381a02SStefan Eichenberger .phy_write = mv88e6xxx_g2_smi_phy_write, 41187d381a02SStefan Eichenberger .port_set_link = mv88e6xxx_port_set_link, 41194efe7662SChris Packham .port_sync_link = mv88e6185_port_sync_link, 4120f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4121ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4122585d42bbSTobias Waldekranz .port_set_policy = mv88e6352_port_set_policy, 412356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4124a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4125a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 412656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4127ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 41280898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4129c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41309dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41312d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4132121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 41337d381a02SStefan Eichenberger .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 413440cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 41357d381a02SStefan Eichenberger .stats_get_sset_count = mv88e6095_stats_get_sset_count, 41367d381a02SStefan Eichenberger .stats_get_strings = mv88e6095_stats_get_strings, 41377d381a02SStefan Eichenberger .stats_get_stats = mv88e6095_stats_get_stats, 4138fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4139fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 414091eaa475SVolodymyr Bendiuga .watchdog_ops = &mv88e6097_watchdog_ops, 414151c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 4142f5be107cSChris Packham .serdes_power = mv88e6185_serdes_power, 4143f5be107cSChris Packham .serdes_get_lane = mv88e6185_serdes_get_lane, 4144f5be107cSChris Packham .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state, 41455c19bc8bSChris Packham .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 41465c19bc8bSChris Packham .serdes_irq_enable = mv88e6097_serdes_irq_enable, 41475c19bc8bSChris Packham .serdes_irq_status = mv88e6097_serdes_irq_status, 41489e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 414917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 41509e5baf9bSVivien Didelot .rmu_disable = mv88e6085_g1_rmu_disable, 4151f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 41520ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4153d0b78ab1STobias Waldekranz .phylink_get_caps = mv88e6095_phylink_get_caps, 415449c98c1dSTobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 415549c98c1dSTobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 41561baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 41577d381a02SStefan Eichenberger }; 41587d381a02SStefan Eichenberger 4159b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6123_ops = { 41604b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 416193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 416293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4163cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4164b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4165ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 4166ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 416708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 41684efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4169f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 417056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 4171a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4172a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 4173c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 41749dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 41752d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4176121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 41770ac64c39SAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 417840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4179dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4180dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4181052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4182fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4183fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4184fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 418551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 41869e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 418717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 418823e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 418923e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4190f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 41910ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4192c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4193c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4194d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 41951baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 4196b3469dd8SVivien Didelot }; 4197b3469dd8SVivien Didelot 4198b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6131_ops = { 41994b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 420093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 420193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4202b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 42037e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 42047e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 420508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 42064efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4207f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4208ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 420956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4210a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 4211a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6185_port_set_default_forward, 421256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4213a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 4214cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4215ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42160898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 421754186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 42182d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4219121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4220a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 422140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4222dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4223dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4224052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4225fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4226fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4227fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 422851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 4229a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 423002317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 4231a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 423217e708baSVivien Didelot .reset = mv88e6185_g1_reset, 4233f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 42340ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4235d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 4236b3469dd8SVivien Didelot }; 4237b3469dd8SVivien Didelot 4238990e27b0SVivien Didelot static const struct mv88e6xxx_ops mv88e6141_ops = { 4239990e27b0SVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 424093e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 424193e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4242cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4243990e27b0SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 4244990e27b0SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 4245990e27b0SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4246990e27b0SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4247990e27b0SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 4248990e27b0SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 42494efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4250990e27b0SVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4251f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 42527cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 4253990e27b0SVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 42547da467d8SMarek Behún .port_set_policy = mv88e6352_port_set_policy, 4255990e27b0SVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4256a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4257a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 4258990e27b0SVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 4259cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4260990e27b0SVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 42610898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4262990e27b0SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 4263990e27b0SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 42642d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 42657a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 4266121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4267990e27b0SVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 426811527f3cSMarek Behún .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4269990e27b0SVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4270990e27b0SVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 4271990e27b0SVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 4272fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4273fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 4274990e27b0SVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 4275990e27b0SVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 42769e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 4277990e27b0SVivien Didelot .reset = mv88e6352_g1_reset, 427837094887SMarek Behún .rmu_disable = mv88e6390_g1_rmu_disable, 4279c07fff34SMarek Behún .atu_get_hash = mv88e6165_g1_atu_get_hash, 4280c07fff34SMarek Behún .atu_set_hash = mv88e6165_g1_atu_set_hash, 4281f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 42820ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4283c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4284c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4285d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 4286d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 4287a5a6858bSRussell King /* Check status register pause & lpa register */ 4288a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4289a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4290a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4291a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 42924241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 429361a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4294907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 4295a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 4296a03b98d6SMarek Behún .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 4297a03b98d6SMarek Behún .serdes_get_strings = mv88e6390_serdes_get_strings, 4298a03b98d6SMarek Behún .serdes_get_stats = mv88e6390_serdes_get_stats, 4299953b0dcbSMarek Behún .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4300953b0dcbSMarek Behún .serdes_get_regs = mv88e6390_serdes_get_regs, 4301d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6341_phylink_get_caps, 4302990e27b0SVivien Didelot }; 4303990e27b0SVivien Didelot 4304b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6161_ops = { 43054b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 430693e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 430793e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4308cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4309b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4310ec8378bbSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 4311ec8378bbSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 431208ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 43134efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4314f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4315ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 431656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4317a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4318a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 431956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4320ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 43210898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4322c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43239dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43242d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4325121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4326a6da21bbSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 432740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4328dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4329dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4330052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4331fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4332fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4333fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 433451c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 43359e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 433617e708baSVivien Didelot .reset = mv88e6352_g1_reset, 433723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 433823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4339f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43400ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4341c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4342c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4343a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 4344dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 4345d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 4346fe230361SAndrew Lunn .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 4347b3469dd8SVivien Didelot }; 4348b3469dd8SVivien Didelot 4349b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6165_ops = { 43504b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6165 */ 435193e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 435293e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4353cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4354b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4355efb3e74dSAndrew Lunn .phy_read = mv88e6165_phy_read, 4356efb3e74dSAndrew Lunn .phy_write = mv88e6165_phy_write, 435708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 43584efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4359f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4360c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 43619dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 43622d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4363121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4364a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 436540cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4366dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4367dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4368052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4369fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4370fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4371fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 437251c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 43739e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 437417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 437523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 437623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4377f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 43780ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4379c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4380c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4381a469a612SAndrew Lunn .avb_ops = &mv88e6165_avb_ops, 4382dfa54348SAndrew Lunn .ptp_ops = &mv88e6165_ptp_ops, 4383d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 4384b3469dd8SVivien Didelot }; 4385b3469dd8SVivien Didelot 4386b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6171_ops = { 43874b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 438893e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 438993e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4390cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4391b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4392b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4393b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 439408ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 43954efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 439694d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4397f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4398ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 439956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4400a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4401a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 440256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4403cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4404ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44050898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4406c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44079dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44082d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4409121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4410a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 441140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4412dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4413dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4414052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4415fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4416fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4417fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 441851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44199e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 442017e708baSVivien Didelot .reset = mv88e6352_g1_reset, 442123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 442223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4423f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 44240ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4425c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4426c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4427d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 4428b3469dd8SVivien Didelot }; 4429b3469dd8SVivien Didelot 4430b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6172_ops = { 44314b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 443293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 443393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4434cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4435ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4436ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4437b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4438b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4439b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 444008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 44414efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4442a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4443f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4444ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4445f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 444656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4447a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4448a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 444956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4450cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4451ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 44520898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4453c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 44549dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 44552d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4456121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4457a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 445840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4459dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4460dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4461052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4462fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4463fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4464fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 446551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 44669e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 446717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 44689e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 446923e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 447023e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4471f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 44720ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4473c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4474c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 44759db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4476a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4477a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4478a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4479a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 44806d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 4481d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4482d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4483a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 4484d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6352_phylink_get_caps, 4485b3469dd8SVivien Didelot }; 4486b3469dd8SVivien Didelot 4487b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6175_ops = { 44884b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 448993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 449093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4491cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4492b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4493b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4494b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 449508ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 44964efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 449794d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4498f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 4499ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 450056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4501a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4502a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 450356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4504cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4505ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 45060898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4507c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 45089dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45092d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4510121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4511a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 451240cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4513dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4514dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4515052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4516fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4517fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4518fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 451951c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 45209e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 452117e708baSVivien Didelot .reset = mv88e6352_g1_reset, 452223e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 452323e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4524f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 45250ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4526c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4527c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 4528d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 4529b3469dd8SVivien Didelot }; 4530b3469dd8SVivien Didelot 4531b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6176_ops = { 45324b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 453393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 453493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4535cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4536ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4537ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4538b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4539b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4540b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 454108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 45424efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4543a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4544f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4545ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4546f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 454756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4548a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4549a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 455056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4551cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4552ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 45530898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4554c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 45559dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 45562d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4557121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4558a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 455940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4560dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4561dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4562052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4563fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4564fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4565fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 456651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 45679e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 456817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 45699e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 457023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 457123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4572f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 45730ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4574c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4575c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 45769db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4577a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4578a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4579a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4580a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 45816d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 45824241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 458361a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4584907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4585d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4586d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4587926eae60SHolger Brunck .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, 4588a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 4589d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6352_phylink_get_caps, 4590b3469dd8SVivien Didelot }; 4591b3469dd8SVivien Didelot 4592b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6185_ops = { 45934b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6185 */ 459493e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 459593e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4596b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 45977e20cfb5SVivien Didelot .phy_read = mv88e6185_phy_ppu_read, 45987e20cfb5SVivien Didelot .phy_write = mv88e6185_phy_ppu_write, 459908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 46004efe7662SChris Packham .port_sync_link = mv88e6185_port_sync_link, 4601f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 460256995cbcSAndrew Lunn .port_set_frame_mode = mv88e6085_port_set_frame_mode, 4603a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 4604a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6185_port_set_default_forward, 4605ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 4606a23b2961SAndrew Lunn .port_set_upstream_port = mv88e6095_port_set_upstream_port, 460754186b91SAndrew Lunn .port_set_pause = mv88e6185_port_set_pause, 46082d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6185_port_get_cmode, 4609121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4610a605a0feSAndrew Lunn .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 461140cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4612dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4613dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4614052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4615fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4616fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4617fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 461851c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 4619f5be107cSChris Packham .serdes_power = mv88e6185_serdes_power, 4620f5be107cSChris Packham .serdes_get_lane = mv88e6185_serdes_get_lane, 4621f5be107cSChris Packham .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state, 462202317e68SVivien Didelot .set_cascade_port = mv88e6185_g1_set_cascade_port, 4623a199d8b6SVivien Didelot .ppu_enable = mv88e6185_g1_ppu_enable, 4624a199d8b6SVivien Didelot .ppu_disable = mv88e6185_g1_ppu_disable, 462517e708baSVivien Didelot .reset = mv88e6185_g1_reset, 4626f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 46270ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 4628d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 46291baf0facSChris Packham .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 4630b3469dd8SVivien Didelot }; 4631b3469dd8SVivien Didelot 46321a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190_ops = { 46334b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4634ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4635cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 463698fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 463798fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 46381a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 46391a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 46401a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 46411a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 46424efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 46431a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4644f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 46457cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4646ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4647f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 464856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4649a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4650a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 465156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4652e8b34c67SChris Packham .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 46530898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4654c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 46559dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 46562d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4657fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4658121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 465979523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4660de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4661dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4662dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4663e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4664fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4665fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 466661303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 46676e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 46689e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 466917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 46709e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 467123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 467223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4673931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4674931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4675c050f5e9STobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 4676c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 46776335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 467817deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4679a5a6858bSRussell King /* Check status register pause & lpa register */ 4680a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4681a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4682a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4683a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 46844241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 468561a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4686907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 46874262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 46884262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4689bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4690bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4691a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 4692d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6390_phylink_get_caps, 46931a3b39ecSAndrew Lunn }; 46941a3b39ecSAndrew Lunn 46951a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6190x_ops = { 46964b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4697ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4698cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 469998fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 470098fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 47011a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 47021a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 47031a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 47041a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 47054efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 47061a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4707f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 47087cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 4709ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4710f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 471156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4712a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4713a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 471456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4715e8b34c67SChris Packham .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 47160898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4717c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 47189dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 47192d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4720fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 4721121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 472279523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4723de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4724dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4725dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4726e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4727fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4728fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 472961303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 47306e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 47319e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 473217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 47339e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 473423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 473523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4736931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4737931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4738c050f5e9STobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 4739c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 4740d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 474117deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 4742a5a6858bSRussell King /* Check status register pause & lpa register */ 4743a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4744a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4745a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4746a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 47474241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 474861a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4749907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 47504262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 47514262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4752bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4753bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4754a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 4755d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6390x_phylink_get_caps, 47561a3b39ecSAndrew Lunn }; 47571a3b39ecSAndrew Lunn 47581a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6191_ops = { 47594b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4760ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4761cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 476298fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 476398fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 47641a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 47651a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 47661a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 47671a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 47684efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 47691a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4770f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 47717cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4772ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 477356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4774a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4775a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 477656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 47770898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4778c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 47799dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 47802d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4781fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4782121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 478379523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4784de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4785dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4786dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4787e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4788fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4789fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 479061303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 47916e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 47929e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 479317e708baSVivien Didelot .reset = mv88e6352_g1_reset, 47949e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 479523e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 479623e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4797931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4798931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4799c050f5e9STobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 4800c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 48016335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 480217deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4803a5a6858bSRussell King /* Check status register pause & lpa register */ 4804a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4805a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4806a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4807a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 48084241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 480961a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4810907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 48114262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 48124262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4813bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4814bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 48156d2ac8eeSAndrew Lunn .avb_ops = &mv88e6390_avb_ops, 48166d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4817d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6390_phylink_get_caps, 48181a3b39ecSAndrew Lunn }; 48191a3b39ecSAndrew Lunn 4820b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6240_ops = { 48214b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 482293e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 482393e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4824cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4825ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4826ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4827b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4828b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4829b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 483008ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 48314efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4832a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4833f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 4834ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 4835f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 483656995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4837a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4838a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 483956995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 4840cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 4841ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 48420898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 4843c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 48449dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 48452d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4846121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 4847a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 484840cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 4849dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 4850dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 4851052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 4852fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 4853fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 4854fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 485551c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 48569e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 485717e708baSVivien Didelot .reset = mv88e6352_g1_reset, 48589e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 485923e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 486023e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4861f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 48620ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 4863c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 4864c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 48659db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 4866a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 4867a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 4868a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 4869a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 48706d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 48714241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 487261a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 4873907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 4874d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 4875d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 4876926eae60SHolger Brunck .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, 4877a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 48780d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 48796d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4880d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6352_phylink_get_caps, 4881b3469dd8SVivien Didelot }; 4882b3469dd8SVivien Didelot 48831f71836fSRasmus Villemoes static const struct mv88e6xxx_ops mv88e6250_ops = { 48841f71836fSRasmus Villemoes /* MV88E6XXX_FAMILY_6250 */ 48851f71836fSRasmus Villemoes .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 48861f71836fSRasmus Villemoes .ip_pri_map = mv88e6085_g1_ip_pri_map, 48871f71836fSRasmus Villemoes .irl_init_all = mv88e6352_g2_irl_init_all, 48881f71836fSRasmus Villemoes .get_eeprom = mv88e6xxx_g2_get_eeprom16, 48891f71836fSRasmus Villemoes .set_eeprom = mv88e6xxx_g2_set_eeprom16, 48901f71836fSRasmus Villemoes .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 48911f71836fSRasmus Villemoes .phy_read = mv88e6xxx_g2_smi_phy_read, 48921f71836fSRasmus Villemoes .phy_write = mv88e6xxx_g2_smi_phy_write, 48931f71836fSRasmus Villemoes .port_set_link = mv88e6xxx_port_set_link, 48944efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 48951f71836fSRasmus Villemoes .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 4896f365c6f7SRussell King .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, 48971f71836fSRasmus Villemoes .port_tag_remap = mv88e6095_port_tag_remap, 48981f71836fSRasmus Villemoes .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4899a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4900a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 49011f71836fSRasmus Villemoes .port_set_ether_type = mv88e6351_port_set_ether_type, 49021f71836fSRasmus Villemoes .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 49031f71836fSRasmus Villemoes .port_pause_limit = mv88e6097_port_pause_limit, 49041f71836fSRasmus Villemoes .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 49051f71836fSRasmus Villemoes .stats_snapshot = mv88e6320_g1_stats_snapshot, 49061f71836fSRasmus Villemoes .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 49071f71836fSRasmus Villemoes .stats_get_sset_count = mv88e6250_stats_get_sset_count, 49081f71836fSRasmus Villemoes .stats_get_strings = mv88e6250_stats_get_strings, 49091f71836fSRasmus Villemoes .stats_get_stats = mv88e6250_stats_get_stats, 49101f71836fSRasmus Villemoes .set_cpu_port = mv88e6095_g1_set_cpu_port, 49111f71836fSRasmus Villemoes .set_egress_port = mv88e6095_g1_set_egress_port, 49121f71836fSRasmus Villemoes .watchdog_ops = &mv88e6250_watchdog_ops, 49131f71836fSRasmus Villemoes .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 49141f71836fSRasmus Villemoes .pot_clear = mv88e6xxx_g2_pot_clear, 49151f71836fSRasmus Villemoes .reset = mv88e6250_g1_reset, 491667c9ed1cSRasmus Villemoes .vtu_getnext = mv88e6185_g1_vtu_getnext, 4917b28f3f3cSRasmus Villemoes .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 491871509614SHubert Feurstein .avb_ops = &mv88e6352_avb_ops, 491971509614SHubert Feurstein .ptp_ops = &mv88e6250_ptp_ops, 4920d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6250_phylink_get_caps, 49211f71836fSRasmus Villemoes }; 49221f71836fSRasmus Villemoes 49231a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6290_ops = { 49244b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 4925ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 4926cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 492798fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 492898fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 49291a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 49301a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 49311a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 49321a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 49334efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 49341a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 4935f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 49367cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 4937ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 4938f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 493956995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 4940a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 4941a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 494256995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 49430898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 4944c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 49459dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 49462d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 4947fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 4948121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 494979523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 4950de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 4951dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 4952dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 4953e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 4954fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 4955fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 495661303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 49576e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 49589e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 495917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 49609e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 496123e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 496223e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 4963931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 4964931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 4965c050f5e9STobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 4966c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 49676335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 496817deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 4969a5a6858bSRussell King /* Check status register pause & lpa register */ 4970a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 4971a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 4972a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 4973a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 49744241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 497561a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 4976907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 49774262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 49784262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 4979bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 4980bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 4981a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 49820d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 49836d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 4984d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6390_phylink_get_caps, 49851a3b39ecSAndrew Lunn }; 49861a3b39ecSAndrew Lunn 4987b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6320_ops = { 49884b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6320 */ 498993e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 499093e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 4991cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 4992ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 4993ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 4994b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 4995b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 4996b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 499708ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 49984efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 4999f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 5000ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 500156995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5002a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5003a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 500456995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5005cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5006ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 50070898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 5008c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 50099dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 50102d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5011121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 5012a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 501340cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 5014dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 5015dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 5016052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 5017fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 5018fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 50199c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 502051c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 50219e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 502217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 5023f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 50240ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 5025a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 50260d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 50276d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 5028d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 5029b3469dd8SVivien Didelot }; 5030b3469dd8SVivien Didelot 5031b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6321_ops = { 5032bd807204SVivien Didelot /* MV88E6XXX_FAMILY_6320 */ 503393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 503493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 5035cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 5036ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 5037ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 5038b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 5039b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 5040b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 504108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 50424efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 5043f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 5044ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 504556995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5046a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5047a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 504856995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5049cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5050ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 50510898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 5052c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 50539dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 50542d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5055121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 5056a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 505740cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 5058dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 5059dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 5060052f947fSAndrew Lunn .stats_get_stats = mv88e6320_stats_get_stats, 5061fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 5062fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 50639c7f37e5SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 506417e708baSVivien Didelot .reset = mv88e6352_g1_reset, 5065f1394b78SVivien Didelot .vtu_getnext = mv88e6185_g1_vtu_getnext, 50660ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 5067a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 50680d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 50696d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 5070d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 5071b3469dd8SVivien Didelot }; 5072b3469dd8SVivien Didelot 507316e329aeSVivien Didelot static const struct mv88e6xxx_ops mv88e6341_ops = { 507416e329aeSVivien Didelot /* MV88E6XXX_FAMILY_6341 */ 507593e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 507693e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 5077cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 507816e329aeSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 507916e329aeSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 508016e329aeSVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 508116e329aeSVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 508216e329aeSVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 508316e329aeSVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 50844efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 508516e329aeSVivien Didelot .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 5086f365c6f7SRussell King .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 50877cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6341_port_max_speed_mode, 508816e329aeSVivien Didelot .port_tag_remap = mv88e6095_port_tag_remap, 50897da467d8SMarek Behún .port_set_policy = mv88e6352_port_set_policy, 509016e329aeSVivien Didelot .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5091a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5092a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 509316e329aeSVivien Didelot .port_set_ether_type = mv88e6351_port_set_ether_type, 5094cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 509516e329aeSVivien Didelot .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 50960898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 509716e329aeSVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 509816e329aeSVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 50992d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 51007a3007d2SMarek Behún .port_set_cmode = mv88e6341_port_set_cmode, 5101121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 510216e329aeSVivien Didelot .stats_snapshot = mv88e6390_g1_stats_snapshot, 510311527f3cSMarek Behún .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 510416e329aeSVivien Didelot .stats_get_sset_count = mv88e6320_stats_get_sset_count, 510516e329aeSVivien Didelot .stats_get_strings = mv88e6320_stats_get_strings, 510616e329aeSVivien Didelot .stats_get_stats = mv88e6390_stats_get_stats, 5107fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 5108fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 510916e329aeSVivien Didelot .watchdog_ops = &mv88e6390_watchdog_ops, 511016e329aeSVivien Didelot .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 51119e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 511216e329aeSVivien Didelot .reset = mv88e6352_g1_reset, 511337094887SMarek Behún .rmu_disable = mv88e6390_g1_rmu_disable, 5114c07fff34SMarek Behún .atu_get_hash = mv88e6165_g1_atu_get_hash, 5115c07fff34SMarek Behún .atu_set_hash = mv88e6165_g1_atu_set_hash, 5116f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 51170ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 5118c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 5119c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 5120d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 5121d3cf7d8fSMarek Behún .serdes_get_lane = mv88e6341_serdes_get_lane, 5122a5a6858bSRussell King /* Check status register pause & lpa register */ 5123a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 5124a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 5125a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 5126a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 51274241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 512861a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 5129907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 5130a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 51310d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 51326d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 5133a03b98d6SMarek Behún .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 5134a03b98d6SMarek Behún .serdes_get_strings = mv88e6390_serdes_get_strings, 5135a03b98d6SMarek Behún .serdes_get_stats = mv88e6390_serdes_get_stats, 5136953b0dcbSMarek Behún .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 5137953b0dcbSMarek Behún .serdes_get_regs = mv88e6390_serdes_get_regs, 5138d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6341_phylink_get_caps, 513916e329aeSVivien Didelot }; 514016e329aeSVivien Didelot 5141b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6350_ops = { 51424b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 514393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 514493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 5145cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 5146b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 5147b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 5148b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 514908ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 51504efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 515194d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 5152f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 5153ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 515456995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5155a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5156a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 515756995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5158cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5159ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 51600898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 5161c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 51629dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 51632d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5164121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 5165a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 516640cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 5167dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 5168dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 5169052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 5170fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 5171fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 5172fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 517351c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 51749e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 517517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 517623e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 517723e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 5178f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 51790ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 5180c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 5181c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 5182d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 5183b3469dd8SVivien Didelot }; 5184b3469dd8SVivien Didelot 5185b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6351_ops = { 51864b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6351 */ 518793e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 518893e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 5189cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 5190b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 5191b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 5192b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 519308ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 51944efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 519594d66ae6SAndrew Lunn .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 5196f365c6f7SRussell King .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 5197ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 519856995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5199a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5200a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 520156995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5202cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5203ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 52040898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 5205c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 52069dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 52072d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5208121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 5209a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 521040cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 5211dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 5212dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 5213052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 5214fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 5215fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 5216fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 521751c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 52189e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 521917e708baSVivien Didelot .reset = mv88e6352_g1_reset, 522023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 522123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 5222f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 52230ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 5224c050f5e9STobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 5225c050f5e9STobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 52260d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 52276d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 5228d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6185_phylink_get_caps, 5229b3469dd8SVivien Didelot }; 5230b3469dd8SVivien Didelot 5231b3469dd8SVivien Didelot static const struct mv88e6xxx_ops mv88e6352_ops = { 52324b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6352 */ 523393e18d61SVivien Didelot .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 523493e18d61SVivien Didelot .ip_pri_map = mv88e6085_g1_ip_pri_map, 5235cd8da8bbSVivien Didelot .irl_init_all = mv88e6352_g2_irl_init_all, 5236ee4dc2e7SVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom16, 5237ee4dc2e7SVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom16, 5238b073d4e2SVivien Didelot .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 5239b3469dd8SVivien Didelot .phy_read = mv88e6xxx_g2_smi_phy_read, 5240b3469dd8SVivien Didelot .phy_write = mv88e6xxx_g2_smi_phy_write, 524108ef7f10SVivien Didelot .port_set_link = mv88e6xxx_port_set_link, 52424efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 5243a0a0f622SVivien Didelot .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 5244f365c6f7SRussell King .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 5245ef0a7318SAndrew Lunn .port_tag_remap = mv88e6095_port_tag_remap, 5246f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 524756995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5248a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5249a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 525056995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5251cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5252ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 52530898432cSVivien Didelot .port_pause_limit = mv88e6097_port_pause_limit, 5254c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 52559dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 52562d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5257121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 5258a605a0feSAndrew Lunn .stats_snapshot = mv88e6320_g1_stats_snapshot, 525940cff8fcSAndrew Lunn .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 5260dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6095_stats_get_sset_count, 5261dfafe449SAndrew Lunn .stats_get_strings = mv88e6095_stats_get_strings, 5262052f947fSAndrew Lunn .stats_get_stats = mv88e6095_stats_get_stats, 5263fa8d1179SVivien Didelot .set_cpu_port = mv88e6095_g1_set_cpu_port, 5264fa8d1179SVivien Didelot .set_egress_port = mv88e6095_g1_set_egress_port, 5265fcd25166SAndrew Lunn .watchdog_ops = &mv88e6097_watchdog_ops, 526651c901a7SVivien Didelot .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 52679e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 526817e708baSVivien Didelot .reset = mv88e6352_g1_reset, 52699e5baf9bSVivien Didelot .rmu_disable = mv88e6352_g1_rmu_disable, 527023e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 527123e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 5272f1394b78SVivien Didelot .vtu_getnext = mv88e6352_g1_vtu_getnext, 52730ad5daf6SVivien Didelot .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 527449c98c1dSTobias Waldekranz .stu_getnext = mv88e6352_g1_stu_getnext, 527549c98c1dSTobias Waldekranz .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 52769db4a725SVivien Didelot .serdes_get_lane = mv88e6352_serdes_get_lane, 5277a5a6858bSRussell King .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, 5278a5a6858bSRussell King .serdes_pcs_config = mv88e6352_serdes_pcs_config, 5279a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, 5280a5a6858bSRussell King .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, 52816d91782fSAndrew Lunn .serdes_power = mv88e6352_serdes_power, 52824241ef52SVivien Didelot .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 528361a46b41SVivien Didelot .serdes_irq_enable = mv88e6352_serdes_irq_enable, 5284907b9b9fSVivien Didelot .serdes_irq_status = mv88e6352_serdes_irq_status, 5285a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 52860d632c3dSBrandon Streiff .avb_ops = &mv88e6352_avb_ops, 52876d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 5288cda9f4aaSAndrew Lunn .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 5289cda9f4aaSAndrew Lunn .serdes_get_strings = mv88e6352_serdes_get_strings, 5290cda9f4aaSAndrew Lunn .serdes_get_stats = mv88e6352_serdes_get_stats, 5291d3f88a24SAndrew Lunn .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 5292d3f88a24SAndrew Lunn .serdes_get_regs = mv88e6352_serdes_get_regs, 5293926eae60SHolger Brunck .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, 5294d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6352_phylink_get_caps, 5295b3469dd8SVivien Didelot }; 5296b3469dd8SVivien Didelot 52971a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390_ops = { 52984b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 5299ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 5300cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 530198fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 530298fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 53031a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 53041a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 53051a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 53061a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 53074efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 53081a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 5309f365c6f7SRussell King .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 53107cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390_port_max_speed_mode, 5311ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 5312f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 531356995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5314a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5315a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 531656995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5317cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5318ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 53190898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 5320c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 53219dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 53222d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5323fdc71eeaSAndrew Lunn .port_set_cmode = mv88e6390_port_set_cmode, 5324121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 532579523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 5326de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 5327dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 5328dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 5329e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 5330fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 5331fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 533261303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 53336e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 53349e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 533517e708baSVivien Didelot .reset = mv88e6352_g1_reset, 53369e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 533723e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 533823e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 5339931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 5340931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 534149c98c1dSTobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 534249c98c1dSTobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 53436335e9f2SAndrew Lunn .serdes_power = mv88e6390_serdes_power, 534417deaf5cSMarek Behún .serdes_get_lane = mv88e6390_serdes_get_lane, 5345a5a6858bSRussell King /* Check status register pause & lpa register */ 5346a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 5347a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 5348a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 5349a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 53504241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 535161a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 5352907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 5353a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 53540d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 53556d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 53560df95287SNikita Yushchenko .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 53570df95287SNikita Yushchenko .serdes_get_strings = mv88e6390_serdes_get_strings, 53580df95287SNikita Yushchenko .serdes_get_stats = mv88e6390_serdes_get_stats, 5359bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 5360bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 5361d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6390_phylink_get_caps, 53621a3b39ecSAndrew Lunn }; 53631a3b39ecSAndrew Lunn 53641a3b39ecSAndrew Lunn static const struct mv88e6xxx_ops mv88e6390x_ops = { 53654b325d8cSAndrew Lunn /* MV88E6XXX_FAMILY_6390 */ 5366ea89098eSAndrew Lunn .setup_errata = mv88e6390_setup_errata, 5367cd8da8bbSVivien Didelot .irl_init_all = mv88e6390_g2_irl_init_all, 536898fc3c6fSVivien Didelot .get_eeprom = mv88e6xxx_g2_get_eeprom8, 536998fc3c6fSVivien Didelot .set_eeprom = mv88e6xxx_g2_set_eeprom8, 53701a3b39ecSAndrew Lunn .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 53711a3b39ecSAndrew Lunn .phy_read = mv88e6xxx_g2_smi_phy_read, 53721a3b39ecSAndrew Lunn .phy_write = mv88e6xxx_g2_smi_phy_write, 53731a3b39ecSAndrew Lunn .port_set_link = mv88e6xxx_port_set_link, 53744efe7662SChris Packham .port_sync_link = mv88e6xxx_port_sync_link, 53751a3b39ecSAndrew Lunn .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 5376f365c6f7SRussell King .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 53777cbbee05SAndrew Lunn .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 5378ef0a7318SAndrew Lunn .port_tag_remap = mv88e6390_port_tag_remap, 5379f3a2cd32SVivien Didelot .port_set_policy = mv88e6352_port_set_policy, 538056995cbcSAndrew Lunn .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5381a8b659e7SVladimir Oltean .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5382a8b659e7SVladimir Oltean .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 538356995cbcSAndrew Lunn .port_set_ether_type = mv88e6351_port_set_ether_type, 5384cd782656SVivien Didelot .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5385ef70b111SAndrew Lunn .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 53860898432cSVivien Didelot .port_pause_limit = mv88e6390_port_pause_limit, 5387c8c94891SVivien Didelot .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 53889dbfb4e1SVivien Didelot .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 53892d2e1dd2SAndrew Lunn .port_get_cmode = mv88e6352_port_get_cmode, 5390b3dce4daSAndrew Lunn .port_set_cmode = mv88e6390x_port_set_cmode, 5391121b8fe2SHubert Feurstein .port_setup_message_port = mv88e6xxx_setup_message_port, 539279523473SAndrew Lunn .stats_snapshot = mv88e6390_g1_stats_snapshot, 5393de227387SAndrew Lunn .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 5394dfafe449SAndrew Lunn .stats_get_sset_count = mv88e6320_stats_get_sset_count, 5395dfafe449SAndrew Lunn .stats_get_strings = mv88e6320_stats_get_strings, 5396e0d8b615SAndrew Lunn .stats_get_stats = mv88e6390_stats_get_stats, 5397fa8d1179SVivien Didelot .set_cpu_port = mv88e6390_g1_set_cpu_port, 5398fa8d1179SVivien Didelot .set_egress_port = mv88e6390_g1_set_egress_port, 539961303736SAndrew Lunn .watchdog_ops = &mv88e6390_watchdog_ops, 54006e55f698SAndrew Lunn .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 54019e907d73SVivien Didelot .pot_clear = mv88e6xxx_g2_pot_clear, 540217e708baSVivien Didelot .reset = mv88e6352_g1_reset, 54039e5baf9bSVivien Didelot .rmu_disable = mv88e6390_g1_rmu_disable, 540423e8b470SAndrew Lunn .atu_get_hash = mv88e6165_g1_atu_get_hash, 540523e8b470SAndrew Lunn .atu_set_hash = mv88e6165_g1_atu_set_hash, 5406931d1822SVivien Didelot .vtu_getnext = mv88e6390_g1_vtu_getnext, 5407931d1822SVivien Didelot .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 540849c98c1dSTobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 540949c98c1dSTobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 5410d3cf7d8fSMarek Behún .serdes_power = mv88e6390_serdes_power, 541117deaf5cSMarek Behún .serdes_get_lane = mv88e6390x_serdes_get_lane, 5412a5a6858bSRussell King .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, 5413a5a6858bSRussell King .serdes_pcs_config = mv88e6390_serdes_pcs_config, 5414a5a6858bSRussell King .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 5415a5a6858bSRussell King .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 54164241ef52SVivien Didelot .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 541761a46b41SVivien Didelot .serdes_irq_enable = mv88e6390_serdes_irq_enable, 5418907b9b9fSVivien Didelot .serdes_irq_status = mv88e6390_serdes_irq_status, 54194262c38dSAndrew Lunn .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 54204262c38dSAndrew Lunn .serdes_get_strings = mv88e6390_serdes_get_strings, 54214262c38dSAndrew Lunn .serdes_get_stats = mv88e6390_serdes_get_stats, 5422bf3504ceSAndrew Lunn .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 5423bf3504ceSAndrew Lunn .serdes_get_regs = mv88e6390_serdes_get_regs, 5424a73ccd61SBrandon Streiff .gpio_ops = &mv88e6352_gpio_ops, 54250d632c3dSBrandon Streiff .avb_ops = &mv88e6390_avb_ops, 54266d2ac8eeSAndrew Lunn .ptp_ops = &mv88e6352_ptp_ops, 5427d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6390x_phylink_get_caps, 54281a3b39ecSAndrew Lunn }; 54291a3b39ecSAndrew Lunn 5430de776d0dSPavana Sharma static const struct mv88e6xxx_ops mv88e6393x_ops = { 5431de776d0dSPavana Sharma /* MV88E6XXX_FAMILY_6393 */ 5432de776d0dSPavana Sharma .setup_errata = mv88e6393x_serdes_setup_errata, 5433de776d0dSPavana Sharma .irl_init_all = mv88e6390_g2_irl_init_all, 5434de776d0dSPavana Sharma .get_eeprom = mv88e6xxx_g2_get_eeprom8, 5435de776d0dSPavana Sharma .set_eeprom = mv88e6xxx_g2_set_eeprom8, 5436de776d0dSPavana Sharma .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 5437de776d0dSPavana Sharma .phy_read = mv88e6xxx_g2_smi_phy_read, 5438de776d0dSPavana Sharma .phy_write = mv88e6xxx_g2_smi_phy_write, 5439de776d0dSPavana Sharma .port_set_link = mv88e6xxx_port_set_link, 5440de776d0dSPavana Sharma .port_sync_link = mv88e6xxx_port_sync_link, 5441de776d0dSPavana Sharma .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 5442de776d0dSPavana Sharma .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex, 5443de776d0dSPavana Sharma .port_max_speed_mode = mv88e6393x_port_max_speed_mode, 5444de776d0dSPavana Sharma .port_tag_remap = mv88e6390_port_tag_remap, 54456584b260SMarek Behún .port_set_policy = mv88e6393x_port_set_policy, 5446de776d0dSPavana Sharma .port_set_frame_mode = mv88e6351_port_set_frame_mode, 5447de776d0dSPavana Sharma .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 5448de776d0dSPavana Sharma .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 5449de776d0dSPavana Sharma .port_set_ether_type = mv88e6393x_port_set_ether_type, 5450de776d0dSPavana Sharma .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 5451de776d0dSPavana Sharma .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 5452de776d0dSPavana Sharma .port_pause_limit = mv88e6390_port_pause_limit, 5453de776d0dSPavana Sharma .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 5454de776d0dSPavana Sharma .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 5455de776d0dSPavana Sharma .port_get_cmode = mv88e6352_port_get_cmode, 5456de776d0dSPavana Sharma .port_set_cmode = mv88e6393x_port_set_cmode, 5457de776d0dSPavana Sharma .port_setup_message_port = mv88e6xxx_setup_message_port, 5458de776d0dSPavana Sharma .port_set_upstream_port = mv88e6393x_port_set_upstream_port, 5459de776d0dSPavana Sharma .stats_snapshot = mv88e6390_g1_stats_snapshot, 5460de776d0dSPavana Sharma .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 5461de776d0dSPavana Sharma .stats_get_sset_count = mv88e6320_stats_get_sset_count, 5462de776d0dSPavana Sharma .stats_get_strings = mv88e6320_stats_get_strings, 5463de776d0dSPavana Sharma .stats_get_stats = mv88e6390_stats_get_stats, 5464de776d0dSPavana Sharma /* .set_cpu_port is missing because this family does not support a global 5465de776d0dSPavana Sharma * CPU port, only per port CPU port which is set via 5466de776d0dSPavana Sharma * .port_set_upstream_port method. 5467de776d0dSPavana Sharma */ 5468de776d0dSPavana Sharma .set_egress_port = mv88e6393x_set_egress_port, 5469de776d0dSPavana Sharma .watchdog_ops = &mv88e6390_watchdog_ops, 5470de776d0dSPavana Sharma .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, 5471de776d0dSPavana Sharma .pot_clear = mv88e6xxx_g2_pot_clear, 5472de776d0dSPavana Sharma .reset = mv88e6352_g1_reset, 5473de776d0dSPavana Sharma .rmu_disable = mv88e6390_g1_rmu_disable, 5474de776d0dSPavana Sharma .atu_get_hash = mv88e6165_g1_atu_get_hash, 5475de776d0dSPavana Sharma .atu_set_hash = mv88e6165_g1_atu_set_hash, 5476de776d0dSPavana Sharma .vtu_getnext = mv88e6390_g1_vtu_getnext, 5477de776d0dSPavana Sharma .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 547849c98c1dSTobias Waldekranz .stu_getnext = mv88e6390_g1_stu_getnext, 547949c98c1dSTobias Waldekranz .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 5480de776d0dSPavana Sharma .serdes_power = mv88e6393x_serdes_power, 5481de776d0dSPavana Sharma .serdes_get_lane = mv88e6393x_serdes_get_lane, 5482de776d0dSPavana Sharma .serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state, 5483de776d0dSPavana Sharma .serdes_pcs_config = mv88e6390_serdes_pcs_config, 5484de776d0dSPavana Sharma .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, 5485de776d0dSPavana Sharma .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, 5486de776d0dSPavana Sharma .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 5487de776d0dSPavana Sharma .serdes_irq_enable = mv88e6393x_serdes_irq_enable, 5488de776d0dSPavana Sharma .serdes_irq_status = mv88e6393x_serdes_irq_status, 5489de776d0dSPavana Sharma /* TODO: serdes stats */ 5490de776d0dSPavana Sharma .gpio_ops = &mv88e6352_gpio_ops, 5491de776d0dSPavana Sharma .avb_ops = &mv88e6390_avb_ops, 5492de776d0dSPavana Sharma .ptp_ops = &mv88e6352_ptp_ops, 5493d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6393x_phylink_get_caps, 5494de776d0dSPavana Sharma }; 5495de776d0dSPavana Sharma 5496fad09c73SVivien Didelot static const struct mv88e6xxx_info mv88e6xxx_table[] = { 5497fad09c73SVivien Didelot [MV88E6085] = { 5498107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 5499fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6097, 5500fad09c73SVivien Didelot .name = "Marvell 88E6085", 5501fad09c73SVivien Didelot .num_databases = 4096, 5502d9ea5620SAndrew Lunn .num_macs = 8192, 5503fad09c73SVivien Didelot .num_ports = 10, 5504bc393155SAndrew Lunn .num_internal_phys = 5, 55053cf3c846SVivien Didelot .max_vid = 4095, 5506c050f5e9STobias Waldekranz .max_sid = 63, 5507fad09c73SVivien Didelot .port_base_addr = 0x10, 55089255bacdSAndrew Lunn .phy_base_addr = 0x0, 5509a935c052SVivien Didelot .global1_addr = 0x1b, 55109069c13aSVivien Didelot .global2_addr = 0x1c, 5511acddbd21SVivien Didelot .age_time_coeff = 15000, 5512dc30c35bSAndrew Lunn .g1_irqs = 8, 5513d6c5e6afSVivien Didelot .g2_irqs = 10, 5514e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5515f3645652SVivien Didelot .pvt = true, 5516b3e05aa1SVivien Didelot .multi_chip = true, 5517b3469dd8SVivien Didelot .ops = &mv88e6085_ops, 5518fad09c73SVivien Didelot }, 5519fad09c73SVivien Didelot 5520fad09c73SVivien Didelot [MV88E6095] = { 5521107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 5522fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6095, 5523fad09c73SVivien Didelot .name = "Marvell 88E6095/88E6095F", 5524fad09c73SVivien Didelot .num_databases = 256, 5525d9ea5620SAndrew Lunn .num_macs = 8192, 5526fad09c73SVivien Didelot .num_ports = 11, 5527bc393155SAndrew Lunn .num_internal_phys = 0, 55283cf3c846SVivien Didelot .max_vid = 4095, 5529fad09c73SVivien Didelot .port_base_addr = 0x10, 55309255bacdSAndrew Lunn .phy_base_addr = 0x0, 5531a935c052SVivien Didelot .global1_addr = 0x1b, 55329069c13aSVivien Didelot .global2_addr = 0x1c, 5533acddbd21SVivien Didelot .age_time_coeff = 15000, 5534dc30c35bSAndrew Lunn .g1_irqs = 8, 5535e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5536b3e05aa1SVivien Didelot .multi_chip = true, 5537b3469dd8SVivien Didelot .ops = &mv88e6095_ops, 5538fad09c73SVivien Didelot }, 5539fad09c73SVivien Didelot 55407d381a02SStefan Eichenberger [MV88E6097] = { 5541107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 55427d381a02SStefan Eichenberger .family = MV88E6XXX_FAMILY_6097, 55437d381a02SStefan Eichenberger .name = "Marvell 88E6097/88E6097F", 55447d381a02SStefan Eichenberger .num_databases = 4096, 5545d9ea5620SAndrew Lunn .num_macs = 8192, 55467d381a02SStefan Eichenberger .num_ports = 11, 5547bc393155SAndrew Lunn .num_internal_phys = 8, 55483cf3c846SVivien Didelot .max_vid = 4095, 554949c98c1dSTobias Waldekranz .max_sid = 63, 55507d381a02SStefan Eichenberger .port_base_addr = 0x10, 55519255bacdSAndrew Lunn .phy_base_addr = 0x0, 55527d381a02SStefan Eichenberger .global1_addr = 0x1b, 55539069c13aSVivien Didelot .global2_addr = 0x1c, 55547d381a02SStefan Eichenberger .age_time_coeff = 15000, 5555c534178bSStefan Eichenberger .g1_irqs = 8, 5556d6c5e6afSVivien Didelot .g2_irqs = 10, 5557e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5558f3645652SVivien Didelot .pvt = true, 5559b3e05aa1SVivien Didelot .multi_chip = true, 5560670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 55617d381a02SStefan Eichenberger .ops = &mv88e6097_ops, 55627d381a02SStefan Eichenberger }, 55637d381a02SStefan Eichenberger 5564fad09c73SVivien Didelot [MV88E6123] = { 5565107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 5566fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 5567fad09c73SVivien Didelot .name = "Marvell 88E6123", 5568fad09c73SVivien Didelot .num_databases = 4096, 5569d9ea5620SAndrew Lunn .num_macs = 1024, 5570fad09c73SVivien Didelot .num_ports = 3, 5571bc393155SAndrew Lunn .num_internal_phys = 5, 55723cf3c846SVivien Didelot .max_vid = 4095, 5573c050f5e9STobias Waldekranz .max_sid = 63, 5574fad09c73SVivien Didelot .port_base_addr = 0x10, 55759255bacdSAndrew Lunn .phy_base_addr = 0x0, 5576a935c052SVivien Didelot .global1_addr = 0x1b, 55779069c13aSVivien Didelot .global2_addr = 0x1c, 5578acddbd21SVivien Didelot .age_time_coeff = 15000, 5579dc30c35bSAndrew Lunn .g1_irqs = 9, 5580d6c5e6afSVivien Didelot .g2_irqs = 10, 5581e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5582f3645652SVivien Didelot .pvt = true, 5583b3e05aa1SVivien Didelot .multi_chip = true, 5584670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5585b3469dd8SVivien Didelot .ops = &mv88e6123_ops, 5586fad09c73SVivien Didelot }, 5587fad09c73SVivien Didelot 5588fad09c73SVivien Didelot [MV88E6131] = { 5589107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 5590fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 5591fad09c73SVivien Didelot .name = "Marvell 88E6131", 5592fad09c73SVivien Didelot .num_databases = 256, 5593d9ea5620SAndrew Lunn .num_macs = 8192, 5594fad09c73SVivien Didelot .num_ports = 8, 5595bc393155SAndrew Lunn .num_internal_phys = 0, 55963cf3c846SVivien Didelot .max_vid = 4095, 5597fad09c73SVivien Didelot .port_base_addr = 0x10, 55989255bacdSAndrew Lunn .phy_base_addr = 0x0, 5599a935c052SVivien Didelot .global1_addr = 0x1b, 56009069c13aSVivien Didelot .global2_addr = 0x1c, 5601acddbd21SVivien Didelot .age_time_coeff = 15000, 5602dc30c35bSAndrew Lunn .g1_irqs = 9, 5603e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5604b3e05aa1SVivien Didelot .multi_chip = true, 5605b3469dd8SVivien Didelot .ops = &mv88e6131_ops, 5606fad09c73SVivien Didelot }, 5607fad09c73SVivien Didelot 5608990e27b0SVivien Didelot [MV88E6141] = { 5609107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 5610990e27b0SVivien Didelot .family = MV88E6XXX_FAMILY_6341, 561179a68b26SUwe Kleine-König .name = "Marvell 88E6141", 5612990e27b0SVivien Didelot .num_databases = 4096, 5613d9ea5620SAndrew Lunn .num_macs = 2048, 5614990e27b0SVivien Didelot .num_ports = 6, 5615bc393155SAndrew Lunn .num_internal_phys = 5, 5616a73ccd61SBrandon Streiff .num_gpio = 11, 56173cf3c846SVivien Didelot .max_vid = 4095, 5618c050f5e9STobias Waldekranz .max_sid = 63, 5619990e27b0SVivien Didelot .port_base_addr = 0x10, 56209255bacdSAndrew Lunn .phy_base_addr = 0x10, 5621990e27b0SVivien Didelot .global1_addr = 0x1b, 56229069c13aSVivien Didelot .global2_addr = 0x1c, 5623990e27b0SVivien Didelot .age_time_coeff = 3750, 5624990e27b0SVivien Didelot .atu_move_port_mask = 0x1f, 5625adfccf11SAndrew Lunn .g1_irqs = 9, 5626d6c5e6afSVivien Didelot .g2_irqs = 10, 5627f3645652SVivien Didelot .pvt = true, 5628b3e05aa1SVivien Didelot .multi_chip = true, 5629670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5630990e27b0SVivien Didelot .ops = &mv88e6141_ops, 5631990e27b0SVivien Didelot }, 5632990e27b0SVivien Didelot 5633fad09c73SVivien Didelot [MV88E6161] = { 5634107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 5635fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 5636fad09c73SVivien Didelot .name = "Marvell 88E6161", 5637fad09c73SVivien Didelot .num_databases = 4096, 5638d9ea5620SAndrew Lunn .num_macs = 1024, 5639fad09c73SVivien Didelot .num_ports = 6, 5640bc393155SAndrew Lunn .num_internal_phys = 5, 56413cf3c846SVivien Didelot .max_vid = 4095, 5642c050f5e9STobias Waldekranz .max_sid = 63, 5643fad09c73SVivien Didelot .port_base_addr = 0x10, 56449255bacdSAndrew Lunn .phy_base_addr = 0x0, 5645a935c052SVivien Didelot .global1_addr = 0x1b, 56469069c13aSVivien Didelot .global2_addr = 0x1c, 5647acddbd21SVivien Didelot .age_time_coeff = 15000, 5648dc30c35bSAndrew Lunn .g1_irqs = 9, 5649d6c5e6afSVivien Didelot .g2_irqs = 10, 5650e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5651f3645652SVivien Didelot .pvt = true, 5652b3e05aa1SVivien Didelot .multi_chip = true, 5653670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5654dfa54348SAndrew Lunn .ptp_support = true, 5655b3469dd8SVivien Didelot .ops = &mv88e6161_ops, 5656fad09c73SVivien Didelot }, 5657fad09c73SVivien Didelot 5658fad09c73SVivien Didelot [MV88E6165] = { 5659107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 5660fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6165, 5661fad09c73SVivien Didelot .name = "Marvell 88E6165", 5662fad09c73SVivien Didelot .num_databases = 4096, 5663d9ea5620SAndrew Lunn .num_macs = 8192, 5664fad09c73SVivien Didelot .num_ports = 6, 5665bc393155SAndrew Lunn .num_internal_phys = 0, 56663cf3c846SVivien Didelot .max_vid = 4095, 5667c050f5e9STobias Waldekranz .max_sid = 63, 5668fad09c73SVivien Didelot .port_base_addr = 0x10, 56699255bacdSAndrew Lunn .phy_base_addr = 0x0, 5670a935c052SVivien Didelot .global1_addr = 0x1b, 56719069c13aSVivien Didelot .global2_addr = 0x1c, 5672acddbd21SVivien Didelot .age_time_coeff = 15000, 5673dc30c35bSAndrew Lunn .g1_irqs = 9, 5674d6c5e6afSVivien Didelot .g2_irqs = 10, 5675e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5676f3645652SVivien Didelot .pvt = true, 5677b3e05aa1SVivien Didelot .multi_chip = true, 5678dfa54348SAndrew Lunn .ptp_support = true, 5679b3469dd8SVivien Didelot .ops = &mv88e6165_ops, 5680fad09c73SVivien Didelot }, 5681fad09c73SVivien Didelot 5682fad09c73SVivien Didelot [MV88E6171] = { 5683107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 5684fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5685fad09c73SVivien Didelot .name = "Marvell 88E6171", 5686fad09c73SVivien Didelot .num_databases = 4096, 5687d9ea5620SAndrew Lunn .num_macs = 8192, 5688fad09c73SVivien Didelot .num_ports = 7, 5689bc393155SAndrew Lunn .num_internal_phys = 5, 56903cf3c846SVivien Didelot .max_vid = 4095, 5691c050f5e9STobias Waldekranz .max_sid = 63, 5692fad09c73SVivien Didelot .port_base_addr = 0x10, 56939255bacdSAndrew Lunn .phy_base_addr = 0x0, 5694a935c052SVivien Didelot .global1_addr = 0x1b, 56959069c13aSVivien Didelot .global2_addr = 0x1c, 5696acddbd21SVivien Didelot .age_time_coeff = 15000, 5697dc30c35bSAndrew Lunn .g1_irqs = 9, 5698d6c5e6afSVivien Didelot .g2_irqs = 10, 5699e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5700f3645652SVivien Didelot .pvt = true, 5701b3e05aa1SVivien Didelot .multi_chip = true, 5702670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5703b3469dd8SVivien Didelot .ops = &mv88e6171_ops, 5704fad09c73SVivien Didelot }, 5705fad09c73SVivien Didelot 5706fad09c73SVivien Didelot [MV88E6172] = { 5707107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 5708fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5709fad09c73SVivien Didelot .name = "Marvell 88E6172", 5710fad09c73SVivien Didelot .num_databases = 4096, 5711d9ea5620SAndrew Lunn .num_macs = 8192, 5712fad09c73SVivien Didelot .num_ports = 7, 5713bc393155SAndrew Lunn .num_internal_phys = 5, 5714a73ccd61SBrandon Streiff .num_gpio = 15, 57153cf3c846SVivien Didelot .max_vid = 4095, 5716c050f5e9STobias Waldekranz .max_sid = 63, 5717fad09c73SVivien Didelot .port_base_addr = 0x10, 57189255bacdSAndrew Lunn .phy_base_addr = 0x0, 5719a935c052SVivien Didelot .global1_addr = 0x1b, 57209069c13aSVivien Didelot .global2_addr = 0x1c, 5721acddbd21SVivien Didelot .age_time_coeff = 15000, 5722dc30c35bSAndrew Lunn .g1_irqs = 9, 5723d6c5e6afSVivien Didelot .g2_irqs = 10, 5724e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5725f3645652SVivien Didelot .pvt = true, 5726b3e05aa1SVivien Didelot .multi_chip = true, 5727670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5728b3469dd8SVivien Didelot .ops = &mv88e6172_ops, 5729fad09c73SVivien Didelot }, 5730fad09c73SVivien Didelot 5731fad09c73SVivien Didelot [MV88E6175] = { 5732107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 5733fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 5734fad09c73SVivien Didelot .name = "Marvell 88E6175", 5735fad09c73SVivien Didelot .num_databases = 4096, 5736d9ea5620SAndrew Lunn .num_macs = 8192, 5737fad09c73SVivien Didelot .num_ports = 7, 5738bc393155SAndrew Lunn .num_internal_phys = 5, 57393cf3c846SVivien Didelot .max_vid = 4095, 5740c050f5e9STobias Waldekranz .max_sid = 63, 5741fad09c73SVivien Didelot .port_base_addr = 0x10, 57429255bacdSAndrew Lunn .phy_base_addr = 0x0, 5743a935c052SVivien Didelot .global1_addr = 0x1b, 57449069c13aSVivien Didelot .global2_addr = 0x1c, 5745acddbd21SVivien Didelot .age_time_coeff = 15000, 5746dc30c35bSAndrew Lunn .g1_irqs = 9, 5747d6c5e6afSVivien Didelot .g2_irqs = 10, 5748e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5749f3645652SVivien Didelot .pvt = true, 5750b3e05aa1SVivien Didelot .multi_chip = true, 5751670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5752b3469dd8SVivien Didelot .ops = &mv88e6175_ops, 5753fad09c73SVivien Didelot }, 5754fad09c73SVivien Didelot 5755fad09c73SVivien Didelot [MV88E6176] = { 5756107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 5757fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5758fad09c73SVivien Didelot .name = "Marvell 88E6176", 5759fad09c73SVivien Didelot .num_databases = 4096, 5760d9ea5620SAndrew Lunn .num_macs = 8192, 5761fad09c73SVivien Didelot .num_ports = 7, 5762bc393155SAndrew Lunn .num_internal_phys = 5, 5763a73ccd61SBrandon Streiff .num_gpio = 15, 57643cf3c846SVivien Didelot .max_vid = 4095, 5765c050f5e9STobias Waldekranz .max_sid = 63, 5766fad09c73SVivien Didelot .port_base_addr = 0x10, 57679255bacdSAndrew Lunn .phy_base_addr = 0x0, 5768a935c052SVivien Didelot .global1_addr = 0x1b, 57699069c13aSVivien Didelot .global2_addr = 0x1c, 5770acddbd21SVivien Didelot .age_time_coeff = 15000, 5771dc30c35bSAndrew Lunn .g1_irqs = 9, 5772d6c5e6afSVivien Didelot .g2_irqs = 10, 5773e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5774f3645652SVivien Didelot .pvt = true, 5775b3e05aa1SVivien Didelot .multi_chip = true, 5776670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5777b3469dd8SVivien Didelot .ops = &mv88e6176_ops, 5778fad09c73SVivien Didelot }, 5779fad09c73SVivien Didelot 5780fad09c73SVivien Didelot [MV88E6185] = { 5781107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 5782fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6185, 5783fad09c73SVivien Didelot .name = "Marvell 88E6185", 5784fad09c73SVivien Didelot .num_databases = 256, 5785d9ea5620SAndrew Lunn .num_macs = 8192, 5786fad09c73SVivien Didelot .num_ports = 10, 5787bc393155SAndrew Lunn .num_internal_phys = 0, 57883cf3c846SVivien Didelot .max_vid = 4095, 5789fad09c73SVivien Didelot .port_base_addr = 0x10, 57909255bacdSAndrew Lunn .phy_base_addr = 0x0, 5791a935c052SVivien Didelot .global1_addr = 0x1b, 57929069c13aSVivien Didelot .global2_addr = 0x1c, 5793acddbd21SVivien Didelot .age_time_coeff = 15000, 5794dc30c35bSAndrew Lunn .g1_irqs = 8, 5795e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5796b3e05aa1SVivien Didelot .multi_chip = true, 5797670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 5798b3469dd8SVivien Didelot .ops = &mv88e6185_ops, 5799fad09c73SVivien Didelot }, 5800fad09c73SVivien Didelot 58011a3b39ecSAndrew Lunn [MV88E6190] = { 5802107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 58031a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 58041a3b39ecSAndrew Lunn .name = "Marvell 88E6190", 58051a3b39ecSAndrew Lunn .num_databases = 4096, 5806d9ea5620SAndrew Lunn .num_macs = 16384, 58071a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 580895150f29SHeiner Kallweit .num_internal_phys = 9, 5809a73ccd61SBrandon Streiff .num_gpio = 16, 5810931d1822SVivien Didelot .max_vid = 8191, 581149c98c1dSTobias Waldekranz .max_sid = 63, 58121a3b39ecSAndrew Lunn .port_base_addr = 0x0, 58139255bacdSAndrew Lunn .phy_base_addr = 0x0, 58141a3b39ecSAndrew Lunn .global1_addr = 0x1b, 58159069c13aSVivien Didelot .global2_addr = 0x1c, 5816b91e055cSAndrew Lunn .age_time_coeff = 3750, 58171a3b39ecSAndrew Lunn .g1_irqs = 9, 5818d6c5e6afSVivien Didelot .g2_irqs = 14, 5819f3645652SVivien Didelot .pvt = true, 5820b3e05aa1SVivien Didelot .multi_chip = true, 5821e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 58221a3b39ecSAndrew Lunn .ops = &mv88e6190_ops, 58231a3b39ecSAndrew Lunn }, 58241a3b39ecSAndrew Lunn 58251a3b39ecSAndrew Lunn [MV88E6190X] = { 5826107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 58271a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 58281a3b39ecSAndrew Lunn .name = "Marvell 88E6190X", 58291a3b39ecSAndrew Lunn .num_databases = 4096, 5830d9ea5620SAndrew Lunn .num_macs = 16384, 58311a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 583295150f29SHeiner Kallweit .num_internal_phys = 9, 5833a73ccd61SBrandon Streiff .num_gpio = 16, 5834931d1822SVivien Didelot .max_vid = 8191, 583549c98c1dSTobias Waldekranz .max_sid = 63, 58361a3b39ecSAndrew Lunn .port_base_addr = 0x0, 58379255bacdSAndrew Lunn .phy_base_addr = 0x0, 58381a3b39ecSAndrew Lunn .global1_addr = 0x1b, 58399069c13aSVivien Didelot .global2_addr = 0x1c, 5840b91e055cSAndrew Lunn .age_time_coeff = 3750, 58411a3b39ecSAndrew Lunn .g1_irqs = 9, 5842d6c5e6afSVivien Didelot .g2_irqs = 14, 5843e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5844f3645652SVivien Didelot .pvt = true, 5845b3e05aa1SVivien Didelot .multi_chip = true, 58461a3b39ecSAndrew Lunn .ops = &mv88e6190x_ops, 58471a3b39ecSAndrew Lunn }, 58481a3b39ecSAndrew Lunn 58491a3b39ecSAndrew Lunn [MV88E6191] = { 5850107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 58511a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 58521a3b39ecSAndrew Lunn .name = "Marvell 88E6191", 58531a3b39ecSAndrew Lunn .num_databases = 4096, 5854d9ea5620SAndrew Lunn .num_macs = 16384, 58551a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 585695150f29SHeiner Kallweit .num_internal_phys = 9, 5857931d1822SVivien Didelot .max_vid = 8191, 585849c98c1dSTobias Waldekranz .max_sid = 63, 58591a3b39ecSAndrew Lunn .port_base_addr = 0x0, 58609255bacdSAndrew Lunn .phy_base_addr = 0x0, 58611a3b39ecSAndrew Lunn .global1_addr = 0x1b, 58629069c13aSVivien Didelot .global2_addr = 0x1c, 5863b91e055cSAndrew Lunn .age_time_coeff = 3750, 5864443d5a1bSAndrew Lunn .g1_irqs = 9, 5865d6c5e6afSVivien Didelot .g2_irqs = 14, 5866e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 5867f3645652SVivien Didelot .pvt = true, 5868b3e05aa1SVivien Didelot .multi_chip = true, 58692fa8d3afSBrandon Streiff .ptp_support = true, 58702cf4cefbSVivien Didelot .ops = &mv88e6191_ops, 58711a3b39ecSAndrew Lunn }, 58721a3b39ecSAndrew Lunn 5873de776d0dSPavana Sharma [MV88E6191X] = { 5874de776d0dSPavana Sharma .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X, 5875de776d0dSPavana Sharma .family = MV88E6XXX_FAMILY_6393, 5876de776d0dSPavana Sharma .name = "Marvell 88E6191X", 5877de776d0dSPavana Sharma .num_databases = 4096, 5878de776d0dSPavana Sharma .num_ports = 11, /* 10 + Z80 */ 5879de776d0dSPavana Sharma .num_internal_phys = 9, 5880de776d0dSPavana Sharma .max_vid = 8191, 588149c98c1dSTobias Waldekranz .max_sid = 63, 5882de776d0dSPavana Sharma .port_base_addr = 0x0, 5883de776d0dSPavana Sharma .phy_base_addr = 0x0, 5884de776d0dSPavana Sharma .global1_addr = 0x1b, 5885de776d0dSPavana Sharma .global2_addr = 0x1c, 5886de776d0dSPavana Sharma .age_time_coeff = 3750, 5887de776d0dSPavana Sharma .g1_irqs = 10, 5888de776d0dSPavana Sharma .g2_irqs = 14, 5889de776d0dSPavana Sharma .atu_move_port_mask = 0x1f, 5890de776d0dSPavana Sharma .pvt = true, 5891de776d0dSPavana Sharma .multi_chip = true, 5892de776d0dSPavana Sharma .ptp_support = true, 5893de776d0dSPavana Sharma .ops = &mv88e6393x_ops, 5894de776d0dSPavana Sharma }, 5895de776d0dSPavana Sharma 5896de776d0dSPavana Sharma [MV88E6193X] = { 5897de776d0dSPavana Sharma .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X, 5898de776d0dSPavana Sharma .family = MV88E6XXX_FAMILY_6393, 5899de776d0dSPavana Sharma .name = "Marvell 88E6193X", 5900de776d0dSPavana Sharma .num_databases = 4096, 5901de776d0dSPavana Sharma .num_ports = 11, /* 10 + Z80 */ 5902de776d0dSPavana Sharma .num_internal_phys = 9, 5903de776d0dSPavana Sharma .max_vid = 8191, 590449c98c1dSTobias Waldekranz .max_sid = 63, 5905de776d0dSPavana Sharma .port_base_addr = 0x0, 5906de776d0dSPavana Sharma .phy_base_addr = 0x0, 5907de776d0dSPavana Sharma .global1_addr = 0x1b, 5908de776d0dSPavana Sharma .global2_addr = 0x1c, 5909de776d0dSPavana Sharma .age_time_coeff = 3750, 5910de776d0dSPavana Sharma .g1_irqs = 10, 5911de776d0dSPavana Sharma .g2_irqs = 14, 5912de776d0dSPavana Sharma .atu_move_port_mask = 0x1f, 5913de776d0dSPavana Sharma .pvt = true, 5914de776d0dSPavana Sharma .multi_chip = true, 5915de776d0dSPavana Sharma .ptp_support = true, 5916de776d0dSPavana Sharma .ops = &mv88e6393x_ops, 5917de776d0dSPavana Sharma }, 5918de776d0dSPavana Sharma 591949022647SHubert Feurstein [MV88E6220] = { 592049022647SHubert Feurstein .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220, 592149022647SHubert Feurstein .family = MV88E6XXX_FAMILY_6250, 592249022647SHubert Feurstein .name = "Marvell 88E6220", 592349022647SHubert Feurstein .num_databases = 64, 592449022647SHubert Feurstein 592549022647SHubert Feurstein /* Ports 2-4 are not routed to pins 592649022647SHubert Feurstein * => usable ports 0, 1, 5, 6 592749022647SHubert Feurstein */ 592849022647SHubert Feurstein .num_ports = 7, 592949022647SHubert Feurstein .num_internal_phys = 2, 5930c857486aSHubert Feurstein .invalid_port_mask = BIT(2) | BIT(3) | BIT(4), 593149022647SHubert Feurstein .max_vid = 4095, 593249022647SHubert Feurstein .port_base_addr = 0x08, 593349022647SHubert Feurstein .phy_base_addr = 0x00, 593449022647SHubert Feurstein .global1_addr = 0x0f, 593549022647SHubert Feurstein .global2_addr = 0x07, 593649022647SHubert Feurstein .age_time_coeff = 15000, 593749022647SHubert Feurstein .g1_irqs = 9, 593849022647SHubert Feurstein .g2_irqs = 10, 593949022647SHubert Feurstein .atu_move_port_mask = 0xf, 594049022647SHubert Feurstein .dual_chip = true, 594171509614SHubert Feurstein .ptp_support = true, 594249022647SHubert Feurstein .ops = &mv88e6250_ops, 594349022647SHubert Feurstein }, 594449022647SHubert Feurstein 5945fad09c73SVivien Didelot [MV88E6240] = { 5946107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 5947fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 5948fad09c73SVivien Didelot .name = "Marvell 88E6240", 5949fad09c73SVivien Didelot .num_databases = 4096, 5950d9ea5620SAndrew Lunn .num_macs = 8192, 5951fad09c73SVivien Didelot .num_ports = 7, 5952bc393155SAndrew Lunn .num_internal_phys = 5, 5953a73ccd61SBrandon Streiff .num_gpio = 15, 59543cf3c846SVivien Didelot .max_vid = 4095, 5955c050f5e9STobias Waldekranz .max_sid = 63, 5956fad09c73SVivien Didelot .port_base_addr = 0x10, 59579255bacdSAndrew Lunn .phy_base_addr = 0x0, 5958a935c052SVivien Didelot .global1_addr = 0x1b, 59599069c13aSVivien Didelot .global2_addr = 0x1c, 5960acddbd21SVivien Didelot .age_time_coeff = 15000, 5961dc30c35bSAndrew Lunn .g1_irqs = 9, 5962d6c5e6afSVivien Didelot .g2_irqs = 10, 5963e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 5964f3645652SVivien Didelot .pvt = true, 5965b3e05aa1SVivien Didelot .multi_chip = true, 5966670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 59672fa8d3afSBrandon Streiff .ptp_support = true, 5968b3469dd8SVivien Didelot .ops = &mv88e6240_ops, 5969fad09c73SVivien Didelot }, 5970fad09c73SVivien Didelot 59711f71836fSRasmus Villemoes [MV88E6250] = { 59721f71836fSRasmus Villemoes .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 59731f71836fSRasmus Villemoes .family = MV88E6XXX_FAMILY_6250, 59741f71836fSRasmus Villemoes .name = "Marvell 88E6250", 59751f71836fSRasmus Villemoes .num_databases = 64, 59761f71836fSRasmus Villemoes .num_ports = 7, 59771f71836fSRasmus Villemoes .num_internal_phys = 5, 59781f71836fSRasmus Villemoes .max_vid = 4095, 59791f71836fSRasmus Villemoes .port_base_addr = 0x08, 59801f71836fSRasmus Villemoes .phy_base_addr = 0x00, 59811f71836fSRasmus Villemoes .global1_addr = 0x0f, 59821f71836fSRasmus Villemoes .global2_addr = 0x07, 59831f71836fSRasmus Villemoes .age_time_coeff = 15000, 59841f71836fSRasmus Villemoes .g1_irqs = 9, 59851f71836fSRasmus Villemoes .g2_irqs = 10, 59861f71836fSRasmus Villemoes .atu_move_port_mask = 0xf, 59871f71836fSRasmus Villemoes .dual_chip = true, 598871509614SHubert Feurstein .ptp_support = true, 59891f71836fSRasmus Villemoes .ops = &mv88e6250_ops, 59901f71836fSRasmus Villemoes }, 59911f71836fSRasmus Villemoes 59921a3b39ecSAndrew Lunn [MV88E6290] = { 5993107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 59941a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 59951a3b39ecSAndrew Lunn .name = "Marvell 88E6290", 59961a3b39ecSAndrew Lunn .num_databases = 4096, 59971a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 599895150f29SHeiner Kallweit .num_internal_phys = 9, 5999a73ccd61SBrandon Streiff .num_gpio = 16, 6000931d1822SVivien Didelot .max_vid = 8191, 6001c050f5e9STobias Waldekranz .max_sid = 63, 60021a3b39ecSAndrew Lunn .port_base_addr = 0x0, 60039255bacdSAndrew Lunn .phy_base_addr = 0x0, 60041a3b39ecSAndrew Lunn .global1_addr = 0x1b, 60059069c13aSVivien Didelot .global2_addr = 0x1c, 6006b91e055cSAndrew Lunn .age_time_coeff = 3750, 60071a3b39ecSAndrew Lunn .g1_irqs = 9, 6008d6c5e6afSVivien Didelot .g2_irqs = 14, 6009e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 6010f3645652SVivien Didelot .pvt = true, 6011b3e05aa1SVivien Didelot .multi_chip = true, 60122fa8d3afSBrandon Streiff .ptp_support = true, 60131a3b39ecSAndrew Lunn .ops = &mv88e6290_ops, 60141a3b39ecSAndrew Lunn }, 60151a3b39ecSAndrew Lunn 6016fad09c73SVivien Didelot [MV88E6320] = { 6017107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 6018fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 6019fad09c73SVivien Didelot .name = "Marvell 88E6320", 6020fad09c73SVivien Didelot .num_databases = 4096, 6021d9ea5620SAndrew Lunn .num_macs = 8192, 6022fad09c73SVivien Didelot .num_ports = 7, 6023bc393155SAndrew Lunn .num_internal_phys = 5, 6024a73ccd61SBrandon Streiff .num_gpio = 15, 60253cf3c846SVivien Didelot .max_vid = 4095, 6026fad09c73SVivien Didelot .port_base_addr = 0x10, 60279255bacdSAndrew Lunn .phy_base_addr = 0x0, 6028a935c052SVivien Didelot .global1_addr = 0x1b, 60299069c13aSVivien Didelot .global2_addr = 0x1c, 6030acddbd21SVivien Didelot .age_time_coeff = 15000, 6031dc30c35bSAndrew Lunn .g1_irqs = 8, 6032bc393155SAndrew Lunn .g2_irqs = 10, 6033e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 6034f3645652SVivien Didelot .pvt = true, 6035b3e05aa1SVivien Didelot .multi_chip = true, 6036670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 60372fa8d3afSBrandon Streiff .ptp_support = true, 6038b3469dd8SVivien Didelot .ops = &mv88e6320_ops, 6039fad09c73SVivien Didelot }, 6040fad09c73SVivien Didelot 6041fad09c73SVivien Didelot [MV88E6321] = { 6042107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 6043fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6320, 6044fad09c73SVivien Didelot .name = "Marvell 88E6321", 6045fad09c73SVivien Didelot .num_databases = 4096, 6046d9ea5620SAndrew Lunn .num_macs = 8192, 6047fad09c73SVivien Didelot .num_ports = 7, 6048bc393155SAndrew Lunn .num_internal_phys = 5, 6049a73ccd61SBrandon Streiff .num_gpio = 15, 60503cf3c846SVivien Didelot .max_vid = 4095, 6051fad09c73SVivien Didelot .port_base_addr = 0x10, 60529255bacdSAndrew Lunn .phy_base_addr = 0x0, 6053a935c052SVivien Didelot .global1_addr = 0x1b, 60549069c13aSVivien Didelot .global2_addr = 0x1c, 6055acddbd21SVivien Didelot .age_time_coeff = 15000, 6056dc30c35bSAndrew Lunn .g1_irqs = 8, 6057bc393155SAndrew Lunn .g2_irqs = 10, 6058e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 6059b3e05aa1SVivien Didelot .multi_chip = true, 6060670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 60612fa8d3afSBrandon Streiff .ptp_support = true, 6062b3469dd8SVivien Didelot .ops = &mv88e6321_ops, 6063fad09c73SVivien Didelot }, 6064fad09c73SVivien Didelot 6065a75961d0SGregory CLEMENT [MV88E6341] = { 6066107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 6067a75961d0SGregory CLEMENT .family = MV88E6XXX_FAMILY_6341, 6068a75961d0SGregory CLEMENT .name = "Marvell 88E6341", 6069a75961d0SGregory CLEMENT .num_databases = 4096, 6070d9ea5620SAndrew Lunn .num_macs = 2048, 6071bc393155SAndrew Lunn .num_internal_phys = 5, 6072a75961d0SGregory CLEMENT .num_ports = 6, 6073a73ccd61SBrandon Streiff .num_gpio = 11, 60743cf3c846SVivien Didelot .max_vid = 4095, 6075c050f5e9STobias Waldekranz .max_sid = 63, 6076a75961d0SGregory CLEMENT .port_base_addr = 0x10, 60779255bacdSAndrew Lunn .phy_base_addr = 0x10, 6078a75961d0SGregory CLEMENT .global1_addr = 0x1b, 60799069c13aSVivien Didelot .global2_addr = 0x1c, 6080a75961d0SGregory CLEMENT .age_time_coeff = 3750, 6081e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 6082adfccf11SAndrew Lunn .g1_irqs = 9, 6083d6c5e6afSVivien Didelot .g2_irqs = 10, 6084f3645652SVivien Didelot .pvt = true, 6085b3e05aa1SVivien Didelot .multi_chip = true, 6086670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 60872fa8d3afSBrandon Streiff .ptp_support = true, 6088a75961d0SGregory CLEMENT .ops = &mv88e6341_ops, 6089a75961d0SGregory CLEMENT }, 6090a75961d0SGregory CLEMENT 6091fad09c73SVivien Didelot [MV88E6350] = { 6092107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 6093fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 6094fad09c73SVivien Didelot .name = "Marvell 88E6350", 6095fad09c73SVivien Didelot .num_databases = 4096, 6096d9ea5620SAndrew Lunn .num_macs = 8192, 6097fad09c73SVivien Didelot .num_ports = 7, 6098bc393155SAndrew Lunn .num_internal_phys = 5, 60993cf3c846SVivien Didelot .max_vid = 4095, 6100c050f5e9STobias Waldekranz .max_sid = 63, 6101fad09c73SVivien Didelot .port_base_addr = 0x10, 61029255bacdSAndrew Lunn .phy_base_addr = 0x0, 6103a935c052SVivien Didelot .global1_addr = 0x1b, 61049069c13aSVivien Didelot .global2_addr = 0x1c, 6105acddbd21SVivien Didelot .age_time_coeff = 15000, 6106dc30c35bSAndrew Lunn .g1_irqs = 9, 6107d6c5e6afSVivien Didelot .g2_irqs = 10, 6108e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 6109f3645652SVivien Didelot .pvt = true, 6110b3e05aa1SVivien Didelot .multi_chip = true, 6111670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 6112b3469dd8SVivien Didelot .ops = &mv88e6350_ops, 6113fad09c73SVivien Didelot }, 6114fad09c73SVivien Didelot 6115fad09c73SVivien Didelot [MV88E6351] = { 6116107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 6117fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6351, 6118fad09c73SVivien Didelot .name = "Marvell 88E6351", 6119fad09c73SVivien Didelot .num_databases = 4096, 6120d9ea5620SAndrew Lunn .num_macs = 8192, 6121fad09c73SVivien Didelot .num_ports = 7, 6122bc393155SAndrew Lunn .num_internal_phys = 5, 61233cf3c846SVivien Didelot .max_vid = 4095, 6124c050f5e9STobias Waldekranz .max_sid = 63, 6125fad09c73SVivien Didelot .port_base_addr = 0x10, 61269255bacdSAndrew Lunn .phy_base_addr = 0x0, 6127a935c052SVivien Didelot .global1_addr = 0x1b, 61289069c13aSVivien Didelot .global2_addr = 0x1c, 6129acddbd21SVivien Didelot .age_time_coeff = 15000, 6130dc30c35bSAndrew Lunn .g1_irqs = 9, 6131d6c5e6afSVivien Didelot .g2_irqs = 10, 6132e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 6133f3645652SVivien Didelot .pvt = true, 6134b3e05aa1SVivien Didelot .multi_chip = true, 6135670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 6136b3469dd8SVivien Didelot .ops = &mv88e6351_ops, 6137fad09c73SVivien Didelot }, 6138fad09c73SVivien Didelot 6139fad09c73SVivien Didelot [MV88E6352] = { 6140107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 6141fad09c73SVivien Didelot .family = MV88E6XXX_FAMILY_6352, 6142fad09c73SVivien Didelot .name = "Marvell 88E6352", 6143fad09c73SVivien Didelot .num_databases = 4096, 6144d9ea5620SAndrew Lunn .num_macs = 8192, 6145fad09c73SVivien Didelot .num_ports = 7, 6146bc393155SAndrew Lunn .num_internal_phys = 5, 6147a73ccd61SBrandon Streiff .num_gpio = 15, 61483cf3c846SVivien Didelot .max_vid = 4095, 614949c98c1dSTobias Waldekranz .max_sid = 63, 6150fad09c73SVivien Didelot .port_base_addr = 0x10, 61519255bacdSAndrew Lunn .phy_base_addr = 0x0, 6152a935c052SVivien Didelot .global1_addr = 0x1b, 61539069c13aSVivien Didelot .global2_addr = 0x1c, 6154acddbd21SVivien Didelot .age_time_coeff = 15000, 6155dc30c35bSAndrew Lunn .g1_irqs = 9, 6156d6c5e6afSVivien Didelot .g2_irqs = 10, 6157e606ca36SVivien Didelot .atu_move_port_mask = 0xf, 6158f3645652SVivien Didelot .pvt = true, 6159b3e05aa1SVivien Didelot .multi_chip = true, 6160670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 61612fa8d3afSBrandon Streiff .ptp_support = true, 6162b3469dd8SVivien Didelot .ops = &mv88e6352_ops, 6163fad09c73SVivien Didelot }, 61641a3b39ecSAndrew Lunn [MV88E6390] = { 6165107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 61661a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 61671a3b39ecSAndrew Lunn .name = "Marvell 88E6390", 61681a3b39ecSAndrew Lunn .num_databases = 4096, 6169d9ea5620SAndrew Lunn .num_macs = 16384, 61701a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 617195150f29SHeiner Kallweit .num_internal_phys = 9, 6172a73ccd61SBrandon Streiff .num_gpio = 16, 6173931d1822SVivien Didelot .max_vid = 8191, 617449c98c1dSTobias Waldekranz .max_sid = 63, 61751a3b39ecSAndrew Lunn .port_base_addr = 0x0, 61769255bacdSAndrew Lunn .phy_base_addr = 0x0, 61771a3b39ecSAndrew Lunn .global1_addr = 0x1b, 61789069c13aSVivien Didelot .global2_addr = 0x1c, 6179b91e055cSAndrew Lunn .age_time_coeff = 3750, 61801a3b39ecSAndrew Lunn .g1_irqs = 9, 6181d6c5e6afSVivien Didelot .g2_irqs = 14, 6182e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 6183f3645652SVivien Didelot .pvt = true, 6184b3e05aa1SVivien Didelot .multi_chip = true, 6185670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED, 61862fa8d3afSBrandon Streiff .ptp_support = true, 61871a3b39ecSAndrew Lunn .ops = &mv88e6390_ops, 61881a3b39ecSAndrew Lunn }, 61891a3b39ecSAndrew Lunn [MV88E6390X] = { 6190107fcc10SVivien Didelot .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 61911a3b39ecSAndrew Lunn .family = MV88E6XXX_FAMILY_6390, 61921a3b39ecSAndrew Lunn .name = "Marvell 88E6390X", 61931a3b39ecSAndrew Lunn .num_databases = 4096, 6194d9ea5620SAndrew Lunn .num_macs = 16384, 61951a3b39ecSAndrew Lunn .num_ports = 11, /* 10 + Z80 */ 619695150f29SHeiner Kallweit .num_internal_phys = 9, 6197a73ccd61SBrandon Streiff .num_gpio = 16, 6198931d1822SVivien Didelot .max_vid = 8191, 619949c98c1dSTobias Waldekranz .max_sid = 63, 62001a3b39ecSAndrew Lunn .port_base_addr = 0x0, 62019255bacdSAndrew Lunn .phy_base_addr = 0x0, 62021a3b39ecSAndrew Lunn .global1_addr = 0x1b, 62039069c13aSVivien Didelot .global2_addr = 0x1c, 6204b91e055cSAndrew Lunn .age_time_coeff = 3750, 62051a3b39ecSAndrew Lunn .g1_irqs = 9, 6206d6c5e6afSVivien Didelot .g2_irqs = 14, 6207e606ca36SVivien Didelot .atu_move_port_mask = 0x1f, 6208f3645652SVivien Didelot .pvt = true, 6209b3e05aa1SVivien Didelot .multi_chip = true, 6210670bb80fSTobias Waldekranz .edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED, 62112fa8d3afSBrandon Streiff .ptp_support = true, 62121a3b39ecSAndrew Lunn .ops = &mv88e6390x_ops, 62131a3b39ecSAndrew Lunn }, 6214de776d0dSPavana Sharma 6215de776d0dSPavana Sharma [MV88E6393X] = { 6216de776d0dSPavana Sharma .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, 6217de776d0dSPavana Sharma .family = MV88E6XXX_FAMILY_6393, 6218de776d0dSPavana Sharma .name = "Marvell 88E6393X", 6219de776d0dSPavana Sharma .num_databases = 4096, 6220de776d0dSPavana Sharma .num_ports = 11, /* 10 + Z80 */ 6221de776d0dSPavana Sharma .num_internal_phys = 9, 6222de776d0dSPavana Sharma .max_vid = 8191, 622349c98c1dSTobias Waldekranz .max_sid = 63, 6224de776d0dSPavana Sharma .port_base_addr = 0x0, 6225de776d0dSPavana Sharma .phy_base_addr = 0x0, 6226de776d0dSPavana Sharma .global1_addr = 0x1b, 6227de776d0dSPavana Sharma .global2_addr = 0x1c, 6228de776d0dSPavana Sharma .age_time_coeff = 3750, 6229de776d0dSPavana Sharma .g1_irqs = 10, 6230de776d0dSPavana Sharma .g2_irqs = 14, 6231de776d0dSPavana Sharma .atu_move_port_mask = 0x1f, 6232de776d0dSPavana Sharma .pvt = true, 6233de776d0dSPavana Sharma .multi_chip = true, 6234de776d0dSPavana Sharma .ptp_support = true, 6235de776d0dSPavana Sharma .ops = &mv88e6393x_ops, 6236de776d0dSPavana Sharma }, 6237fad09c73SVivien Didelot }; 6238fad09c73SVivien Didelot 6239fad09c73SVivien Didelot static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 6240fad09c73SVivien Didelot { 6241fad09c73SVivien Didelot int i; 6242fad09c73SVivien Didelot 6243fad09c73SVivien Didelot for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 6244fad09c73SVivien Didelot if (mv88e6xxx_table[i].prod_num == prod_num) 6245fad09c73SVivien Didelot return &mv88e6xxx_table[i]; 6246fad09c73SVivien Didelot 6247fad09c73SVivien Didelot return NULL; 6248fad09c73SVivien Didelot } 6249fad09c73SVivien Didelot 6250fad09c73SVivien Didelot static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 6251fad09c73SVivien Didelot { 6252fad09c73SVivien Didelot const struct mv88e6xxx_info *info; 62538f6345b2SVivien Didelot unsigned int prod_num, rev; 62548f6345b2SVivien Didelot u16 id; 62558f6345b2SVivien Didelot int err; 6256fad09c73SVivien Didelot 6257c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6258107fcc10SVivien Didelot err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 6259c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 62608f6345b2SVivien Didelot if (err) 62618f6345b2SVivien Didelot return err; 6262fad09c73SVivien Didelot 6263107fcc10SVivien Didelot prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 6264107fcc10SVivien Didelot rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 6265fad09c73SVivien Didelot 6266fad09c73SVivien Didelot info = mv88e6xxx_lookup_info(prod_num); 6267fad09c73SVivien Didelot if (!info) 6268fad09c73SVivien Didelot return -ENODEV; 6269fad09c73SVivien Didelot 6270fad09c73SVivien Didelot /* Update the compatible info with the probed one */ 6271fad09c73SVivien Didelot chip->info = info; 6272fad09c73SVivien Didelot 6273fad09c73SVivien Didelot dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 6274fad09c73SVivien Didelot chip->info->prod_num, chip->info->name, rev); 6275fad09c73SVivien Didelot 6276fad09c73SVivien Didelot return 0; 6277fad09c73SVivien Didelot } 6278fad09c73SVivien Didelot 62795da66099SNathan Rossi static int mv88e6xxx_single_chip_detect(struct mv88e6xxx_chip *chip, 62805da66099SNathan Rossi struct mdio_device *mdiodev) 62815da66099SNathan Rossi { 62825da66099SNathan Rossi int err; 62835da66099SNathan Rossi 62845da66099SNathan Rossi /* dual_chip takes precedence over single/multi-chip modes */ 62855da66099SNathan Rossi if (chip->info->dual_chip) 62865da66099SNathan Rossi return -EINVAL; 62875da66099SNathan Rossi 62885da66099SNathan Rossi /* If the mdio addr is 16 indicating the first port address of a switch 62895da66099SNathan Rossi * (e.g. mv88e6*41) in single chip addressing mode the device may be 62905da66099SNathan Rossi * configured in single chip addressing mode. Setup the smi access as 62915da66099SNathan Rossi * single chip addressing mode and attempt to detect the model of the 62925da66099SNathan Rossi * switch, if this fails the device is not configured in single chip 62935da66099SNathan Rossi * addressing mode. 62945da66099SNathan Rossi */ 62955da66099SNathan Rossi if (mdiodev->addr != 16) 62965da66099SNathan Rossi return -EINVAL; 62975da66099SNathan Rossi 62985da66099SNathan Rossi err = mv88e6xxx_smi_init(chip, mdiodev->bus, 0); 62995da66099SNathan Rossi if (err) 63005da66099SNathan Rossi return err; 63015da66099SNathan Rossi 63025da66099SNathan Rossi return mv88e6xxx_detect(chip); 63035da66099SNathan Rossi } 63045da66099SNathan Rossi 6305fad09c73SVivien Didelot static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 6306fad09c73SVivien Didelot { 6307fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 6308fad09c73SVivien Didelot 6309fad09c73SVivien Didelot chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 6310fad09c73SVivien Didelot if (!chip) 6311fad09c73SVivien Didelot return NULL; 6312fad09c73SVivien Didelot 6313fad09c73SVivien Didelot chip->dev = dev; 6314fad09c73SVivien Didelot 6315fad09c73SVivien Didelot mutex_init(&chip->reg_lock); 6316a3c53be5SAndrew Lunn INIT_LIST_HEAD(&chip->mdios); 6317da7dc875SVivien Didelot idr_init(&chip->policies); 6318acaf4d2eSTobias Waldekranz INIT_LIST_HEAD(&chip->msts); 6319fad09c73SVivien Didelot 6320fad09c73SVivien Didelot return chip; 6321fad09c73SVivien Didelot } 6322fad09c73SVivien Didelot 63235ed4e3ebSFlorian Fainelli static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 63244d776482SFlorian Fainelli int port, 63254d776482SFlorian Fainelli enum dsa_tag_protocol m) 63267b314362SAndrew Lunn { 632704bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 63282bbb33beSAndrew Lunn 6329670bb80fSTobias Waldekranz return chip->tag_protocol; 63307b314362SAndrew Lunn } 63317b314362SAndrew Lunn 6332*bacf93b0SVladimir Oltean static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds, 63339a99bef5STobias Waldekranz enum dsa_tag_protocol proto) 63349a99bef5STobias Waldekranz { 63359a99bef5STobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 63369a99bef5STobias Waldekranz enum dsa_tag_protocol old_protocol; 6337*bacf93b0SVladimir Oltean struct dsa_port *cpu_dp; 63389a99bef5STobias Waldekranz int err; 63399a99bef5STobias Waldekranz 63409a99bef5STobias Waldekranz switch (proto) { 63419a99bef5STobias Waldekranz case DSA_TAG_PROTO_EDSA: 63429a99bef5STobias Waldekranz switch (chip->info->edsa_support) { 63439a99bef5STobias Waldekranz case MV88E6XXX_EDSA_UNSUPPORTED: 63449a99bef5STobias Waldekranz return -EPROTONOSUPPORT; 63459a99bef5STobias Waldekranz case MV88E6XXX_EDSA_UNDOCUMENTED: 63469a99bef5STobias Waldekranz dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n"); 63479a99bef5STobias Waldekranz fallthrough; 63489a99bef5STobias Waldekranz case MV88E6XXX_EDSA_SUPPORTED: 63499a99bef5STobias Waldekranz break; 63509a99bef5STobias Waldekranz } 63519a99bef5STobias Waldekranz break; 63529a99bef5STobias Waldekranz case DSA_TAG_PROTO_DSA: 63539a99bef5STobias Waldekranz break; 63549a99bef5STobias Waldekranz default: 63559a99bef5STobias Waldekranz return -EPROTONOSUPPORT; 63569a99bef5STobias Waldekranz } 63579a99bef5STobias Waldekranz 63589a99bef5STobias Waldekranz old_protocol = chip->tag_protocol; 63599a99bef5STobias Waldekranz chip->tag_protocol = proto; 63609a99bef5STobias Waldekranz 63619a99bef5STobias Waldekranz mv88e6xxx_reg_lock(chip); 6362*bacf93b0SVladimir Oltean dsa_switch_for_each_cpu_port(cpu_dp, ds) { 6363*bacf93b0SVladimir Oltean err = mv88e6xxx_setup_port_mode(chip, cpu_dp->index); 6364*bacf93b0SVladimir Oltean if (err) { 6365*bacf93b0SVladimir Oltean mv88e6xxx_reg_unlock(chip); 6366*bacf93b0SVladimir Oltean goto unwind; 6367*bacf93b0SVladimir Oltean } 6368*bacf93b0SVladimir Oltean } 63699a99bef5STobias Waldekranz mv88e6xxx_reg_unlock(chip); 63709a99bef5STobias Waldekranz 6371*bacf93b0SVladimir Oltean return 0; 6372*bacf93b0SVladimir Oltean 6373*bacf93b0SVladimir Oltean unwind: 63749a99bef5STobias Waldekranz chip->tag_protocol = old_protocol; 63759a99bef5STobias Waldekranz 6376*bacf93b0SVladimir Oltean mv88e6xxx_reg_lock(chip); 6377*bacf93b0SVladimir Oltean dsa_switch_for_each_cpu_port_continue_reverse(cpu_dp, ds) 6378*bacf93b0SVladimir Oltean mv88e6xxx_setup_port_mode(chip, cpu_dp->index); 6379*bacf93b0SVladimir Oltean mv88e6xxx_reg_unlock(chip); 6380*bacf93b0SVladimir Oltean 63819a99bef5STobias Waldekranz return err; 63829a99bef5STobias Waldekranz } 63839a99bef5STobias Waldekranz 6384a52b2da7SVladimir Oltean static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 6385c2693363SVladimir Oltean const struct switchdev_obj_port_mdb *mdb, 6386c2693363SVladimir Oltean struct dsa_db db) 63877df8fbddSVivien Didelot { 638804bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 6389a52b2da7SVladimir Oltean int err; 63907df8fbddSVivien Didelot 6391c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6392a52b2da7SVladimir Oltean err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 6393a52b2da7SVladimir Oltean MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC); 6394c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 6395a52b2da7SVladimir Oltean 6396a52b2da7SVladimir Oltean return err; 63977df8fbddSVivien Didelot } 63987df8fbddSVivien Didelot 63997df8fbddSVivien Didelot static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 6400c2693363SVladimir Oltean const struct switchdev_obj_port_mdb *mdb, 6401c2693363SVladimir Oltean struct dsa_db db) 64027df8fbddSVivien Didelot { 640304bed143SVivien Didelot struct mv88e6xxx_chip *chip = ds->priv; 64047df8fbddSVivien Didelot int err; 64057df8fbddSVivien Didelot 6406c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6407d8291a95SVivien Didelot err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0); 6408c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 64097df8fbddSVivien Didelot 64107df8fbddSVivien Didelot return err; 64117df8fbddSVivien Didelot } 64127df8fbddSVivien Didelot 6413f0942e00SIwan R Timmer static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, 6414f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror, 64150148bb50SVladimir Oltean bool ingress, 64160148bb50SVladimir Oltean struct netlink_ext_ack *extack) 6417f0942e00SIwan R Timmer { 6418f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = ingress ? 6419f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 6420f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 6421f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 6422f0942e00SIwan R Timmer bool other_mirrors = false; 6423f0942e00SIwan R Timmer int i; 6424f0942e00SIwan R Timmer int err; 6425f0942e00SIwan R Timmer 6426f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 6427f0942e00SIwan R Timmer if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != 6428f0942e00SIwan R Timmer mirror->to_local_port) { 6429f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 6430f0942e00SIwan R Timmer other_mirrors |= ingress ? 6431f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 6432f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 6433f0942e00SIwan R Timmer 6434f0942e00SIwan R Timmer /* Can't change egress port when other mirror is active */ 6435f0942e00SIwan R Timmer if (other_mirrors) { 6436f0942e00SIwan R Timmer err = -EBUSY; 6437f0942e00SIwan R Timmer goto out; 6438f0942e00SIwan R Timmer } 6439f0942e00SIwan R Timmer 64402fda45f0SMarek Behún err = mv88e6xxx_set_egress_port(chip, direction, 6441f0942e00SIwan R Timmer mirror->to_local_port); 6442f0942e00SIwan R Timmer if (err) 6443f0942e00SIwan R Timmer goto out; 6444f0942e00SIwan R Timmer } 6445f0942e00SIwan R Timmer 6446f0942e00SIwan R Timmer err = mv88e6xxx_port_set_mirror(chip, port, direction, true); 6447f0942e00SIwan R Timmer out: 6448f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 6449f0942e00SIwan R Timmer 6450f0942e00SIwan R Timmer return err; 6451f0942e00SIwan R Timmer } 6452f0942e00SIwan R Timmer 6453f0942e00SIwan R Timmer static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, 6454f0942e00SIwan R Timmer struct dsa_mall_mirror_tc_entry *mirror) 6455f0942e00SIwan R Timmer { 6456f0942e00SIwan R Timmer enum mv88e6xxx_egress_direction direction = mirror->ingress ? 6457f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_INGRESS : 6458f0942e00SIwan R Timmer MV88E6XXX_EGRESS_DIR_EGRESS; 6459f0942e00SIwan R Timmer struct mv88e6xxx_chip *chip = ds->priv; 6460f0942e00SIwan R Timmer bool other_mirrors = false; 6461f0942e00SIwan R Timmer int i; 6462f0942e00SIwan R Timmer 6463f0942e00SIwan R Timmer mutex_lock(&chip->reg_lock); 6464f0942e00SIwan R Timmer if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) 6465f0942e00SIwan R Timmer dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); 6466f0942e00SIwan R Timmer 6467f0942e00SIwan R Timmer for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 6468f0942e00SIwan R Timmer other_mirrors |= mirror->ingress ? 6469f0942e00SIwan R Timmer chip->ports[i].mirror_ingress : 6470f0942e00SIwan R Timmer chip->ports[i].mirror_egress; 6471f0942e00SIwan R Timmer 6472f0942e00SIwan R Timmer /* Reset egress port when no other mirror is active */ 6473f0942e00SIwan R Timmer if (!other_mirrors) { 64742fda45f0SMarek Behún if (mv88e6xxx_set_egress_port(chip, direction, 64752fda45f0SMarek Behún dsa_upstream_port(ds, port))) 6476f0942e00SIwan R Timmer dev_err(ds->dev, "failed to set egress port\n"); 6477f0942e00SIwan R Timmer } 6478f0942e00SIwan R Timmer 6479f0942e00SIwan R Timmer mutex_unlock(&chip->reg_lock); 6480f0942e00SIwan R Timmer } 6481f0942e00SIwan R Timmer 6482a8b659e7SVladimir Oltean static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port, 6483a8b659e7SVladimir Oltean struct switchdev_brport_flags flags, 6484a8b659e7SVladimir Oltean struct netlink_ext_ack *extack) 6485a8b659e7SVladimir Oltean { 6486a8b659e7SVladimir Oltean struct mv88e6xxx_chip *chip = ds->priv; 6487a8b659e7SVladimir Oltean const struct mv88e6xxx_ops *ops; 6488a8b659e7SVladimir Oltean 64898d1d8298STobias Waldekranz if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | 649034ea415fSHans Schultz BR_BCAST_FLOOD | BR_PORT_LOCKED)) 6491a8b659e7SVladimir Oltean return -EINVAL; 6492a8b659e7SVladimir Oltean 6493a8b659e7SVladimir Oltean ops = chip->info->ops; 6494a8b659e7SVladimir Oltean 6495a8b659e7SVladimir Oltean if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood) 6496a8b659e7SVladimir Oltean return -EINVAL; 6497a8b659e7SVladimir Oltean 6498a8b659e7SVladimir Oltean if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood) 6499a8b659e7SVladimir Oltean return -EINVAL; 6500a8b659e7SVladimir Oltean 6501a8b659e7SVladimir Oltean return 0; 6502a8b659e7SVladimir Oltean } 6503a8b659e7SVladimir Oltean 6504a8b659e7SVladimir Oltean static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, 6505a8b659e7SVladimir Oltean struct switchdev_brport_flags flags, 6506a8b659e7SVladimir Oltean struct netlink_ext_ack *extack) 65074f85901fSRussell King { 65084f85901fSRussell King struct mv88e6xxx_chip *chip = ds->priv; 65094f85901fSRussell King int err = -EOPNOTSUPP; 65104f85901fSRussell King 6511c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 6512a8b659e7SVladimir Oltean 6513041bd545STobias Waldekranz if (flags.mask & BR_LEARNING) { 6514041bd545STobias Waldekranz bool learning = !!(flags.val & BR_LEARNING); 6515041bd545STobias Waldekranz u16 pav = learning ? (1 << port) : 0; 6516041bd545STobias Waldekranz 6517041bd545STobias Waldekranz err = mv88e6xxx_port_set_assoc_vector(chip, port, pav); 6518041bd545STobias Waldekranz if (err) 6519041bd545STobias Waldekranz goto out; 6520041bd545STobias Waldekranz } 6521041bd545STobias Waldekranz 6522a8b659e7SVladimir Oltean if (flags.mask & BR_FLOOD) { 6523a8b659e7SVladimir Oltean bool unicast = !!(flags.val & BR_FLOOD); 6524a8b659e7SVladimir Oltean 6525a8b659e7SVladimir Oltean err = chip->info->ops->port_set_ucast_flood(chip, port, 6526a8b659e7SVladimir Oltean unicast); 6527a8b659e7SVladimir Oltean if (err) 6528a8b659e7SVladimir Oltean goto out; 6529a8b659e7SVladimir Oltean } 6530a8b659e7SVladimir Oltean 6531a8b659e7SVladimir Oltean if (flags.mask & BR_MCAST_FLOOD) { 6532a8b659e7SVladimir Oltean bool multicast = !!(flags.val & BR_MCAST_FLOOD); 6533a8b659e7SVladimir Oltean 6534a8b659e7SVladimir Oltean err = chip->info->ops->port_set_mcast_flood(chip, port, 65354f85901fSRussell King multicast); 6536a8b659e7SVladimir Oltean if (err) 6537a8b659e7SVladimir Oltean goto out; 6538a8b659e7SVladimir Oltean } 6539a8b659e7SVladimir Oltean 65408d1d8298STobias Waldekranz if (flags.mask & BR_BCAST_FLOOD) { 65418d1d8298STobias Waldekranz bool broadcast = !!(flags.val & BR_BCAST_FLOOD); 65428d1d8298STobias Waldekranz 65438d1d8298STobias Waldekranz err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast); 65448d1d8298STobias Waldekranz if (err) 65458d1d8298STobias Waldekranz goto out; 65468d1d8298STobias Waldekranz } 65478d1d8298STobias Waldekranz 654834ea415fSHans Schultz if (flags.mask & BR_PORT_LOCKED) { 654934ea415fSHans Schultz bool locked = !!(flags.val & BR_PORT_LOCKED); 655034ea415fSHans Schultz 655134ea415fSHans Schultz err = mv88e6xxx_port_set_lock(chip, port, locked); 655234ea415fSHans Schultz if (err) 655334ea415fSHans Schultz goto out; 655434ea415fSHans Schultz } 6555a8b659e7SVladimir Oltean out: 6556a8b659e7SVladimir Oltean mv88e6xxx_reg_unlock(chip); 6557a8b659e7SVladimir Oltean 6558a8b659e7SVladimir Oltean return err; 6559a8b659e7SVladimir Oltean } 6560a8b659e7SVladimir Oltean 656157e661aaSTobias Waldekranz static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, 6562dedd6a00SVladimir Oltean struct dsa_lag lag, 656357e661aaSTobias Waldekranz struct netdev_lag_upper_info *info) 656457e661aaSTobias Waldekranz { 6565b80dc51bSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 656657e661aaSTobias Waldekranz struct dsa_port *dp; 6567dedd6a00SVladimir Oltean int members = 0; 656857e661aaSTobias Waldekranz 6569b80dc51bSTobias Waldekranz if (!mv88e6xxx_has_lag(chip)) 6570b80dc51bSTobias Waldekranz return false; 6571b80dc51bSTobias Waldekranz 6572dedd6a00SVladimir Oltean if (!lag.id) 657357e661aaSTobias Waldekranz return false; 657457e661aaSTobias Waldekranz 6575dedd6a00SVladimir Oltean dsa_lag_foreach_port(dp, ds->dst, &lag) 657657e661aaSTobias Waldekranz /* Includes the port joining the LAG */ 657757e661aaSTobias Waldekranz members++; 657857e661aaSTobias Waldekranz 657957e661aaSTobias Waldekranz if (members > 8) 658057e661aaSTobias Waldekranz return false; 658157e661aaSTobias Waldekranz 658257e661aaSTobias Waldekranz /* We could potentially relax this to include active 658357e661aaSTobias Waldekranz * backup in the future. 658457e661aaSTobias Waldekranz */ 658557e661aaSTobias Waldekranz if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) 658657e661aaSTobias Waldekranz return false; 658757e661aaSTobias Waldekranz 658857e661aaSTobias Waldekranz /* Ideally we would also validate that the hash type matches 658957e661aaSTobias Waldekranz * the hardware. Alas, this is always set to unknown on team 659057e661aaSTobias Waldekranz * interfaces. 659157e661aaSTobias Waldekranz */ 659257e661aaSTobias Waldekranz return true; 659357e661aaSTobias Waldekranz } 659457e661aaSTobias Waldekranz 6595dedd6a00SVladimir Oltean static int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct dsa_lag lag) 659657e661aaSTobias Waldekranz { 659757e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 659857e661aaSTobias Waldekranz struct dsa_port *dp; 659957e661aaSTobias Waldekranz u16 map = 0; 660057e661aaSTobias Waldekranz int id; 660157e661aaSTobias Waldekranz 66023d4a0a2aSVladimir Oltean /* DSA LAG IDs are one-based, hardware is zero-based */ 6603dedd6a00SVladimir Oltean id = lag.id - 1; 660457e661aaSTobias Waldekranz 660557e661aaSTobias Waldekranz /* Build the map of all ports to distribute flows destined for 660657e661aaSTobias Waldekranz * this LAG. This can be either a local user port, or a DSA 660757e661aaSTobias Waldekranz * port if the LAG port is on a remote chip. 660857e661aaSTobias Waldekranz */ 6609dedd6a00SVladimir Oltean dsa_lag_foreach_port(dp, ds->dst, &lag) 661057e661aaSTobias Waldekranz map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index)); 661157e661aaSTobias Waldekranz 661257e661aaSTobias Waldekranz return mv88e6xxx_g2_trunk_mapping_write(chip, id, map); 661357e661aaSTobias Waldekranz } 661457e661aaSTobias Waldekranz 661557e661aaSTobias Waldekranz static const u8 mv88e6xxx_lag_mask_table[8][8] = { 661657e661aaSTobias Waldekranz /* Row number corresponds to the number of active members in a 661757e661aaSTobias Waldekranz * LAG. Each column states which of the eight hash buckets are 661857e661aaSTobias Waldekranz * mapped to the column:th port in the LAG. 661957e661aaSTobias Waldekranz * 662057e661aaSTobias Waldekranz * Example: In a LAG with three active ports, the second port 662157e661aaSTobias Waldekranz * ([2][1]) would be selected for traffic mapped to buckets 662257e661aaSTobias Waldekranz * 3,4,5 (0x38). 662357e661aaSTobias Waldekranz */ 662457e661aaSTobias Waldekranz { 0xff, 0, 0, 0, 0, 0, 0, 0 }, 662557e661aaSTobias Waldekranz { 0x0f, 0xf0, 0, 0, 0, 0, 0, 0 }, 662657e661aaSTobias Waldekranz { 0x07, 0x38, 0xc0, 0, 0, 0, 0, 0 }, 662757e661aaSTobias Waldekranz { 0x03, 0x0c, 0x30, 0xc0, 0, 0, 0, 0 }, 662857e661aaSTobias Waldekranz { 0x03, 0x0c, 0x30, 0x40, 0x80, 0, 0, 0 }, 662957e661aaSTobias Waldekranz { 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80, 0, 0 }, 663057e661aaSTobias Waldekranz { 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0 }, 663157e661aaSTobias Waldekranz { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, 663257e661aaSTobias Waldekranz }; 663357e661aaSTobias Waldekranz 663457e661aaSTobias Waldekranz static void mv88e6xxx_lag_set_port_mask(u16 *mask, int port, 663557e661aaSTobias Waldekranz int num_tx, int nth) 663657e661aaSTobias Waldekranz { 663757e661aaSTobias Waldekranz u8 active = 0; 663857e661aaSTobias Waldekranz int i; 663957e661aaSTobias Waldekranz 664057e661aaSTobias Waldekranz num_tx = num_tx <= 8 ? num_tx : 8; 664157e661aaSTobias Waldekranz if (nth < num_tx) 664257e661aaSTobias Waldekranz active = mv88e6xxx_lag_mask_table[num_tx - 1][nth]; 664357e661aaSTobias Waldekranz 664457e661aaSTobias Waldekranz for (i = 0; i < 8; i++) { 664557e661aaSTobias Waldekranz if (BIT(i) & active) 664657e661aaSTobias Waldekranz mask[i] |= BIT(port); 664757e661aaSTobias Waldekranz } 664857e661aaSTobias Waldekranz } 664957e661aaSTobias Waldekranz 665057e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds) 665157e661aaSTobias Waldekranz { 665257e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 665357e661aaSTobias Waldekranz unsigned int id, num_tx; 665457e661aaSTobias Waldekranz struct dsa_port *dp; 6655dedd6a00SVladimir Oltean struct dsa_lag *lag; 665657e661aaSTobias Waldekranz int i, err, nth; 665757e661aaSTobias Waldekranz u16 mask[8]; 665857e661aaSTobias Waldekranz u16 ivec; 665957e661aaSTobias Waldekranz 666057e661aaSTobias Waldekranz /* Assume no port is a member of any LAG. */ 666157e661aaSTobias Waldekranz ivec = BIT(mv88e6xxx_num_ports(chip)) - 1; 666257e661aaSTobias Waldekranz 666357e661aaSTobias Waldekranz /* Disable all masks for ports that _are_ members of a LAG. */ 6664b99dbdf0SVladimir Oltean dsa_switch_for_each_port(dp, ds) { 6665dedd6a00SVladimir Oltean if (!dp->lag) 666657e661aaSTobias Waldekranz continue; 666757e661aaSTobias Waldekranz 666857e661aaSTobias Waldekranz ivec &= ~BIT(dp->index); 666957e661aaSTobias Waldekranz } 667057e661aaSTobias Waldekranz 667157e661aaSTobias Waldekranz for (i = 0; i < 8; i++) 667257e661aaSTobias Waldekranz mask[i] = ivec; 667357e661aaSTobias Waldekranz 667457e661aaSTobias Waldekranz /* Enable the correct subset of masks for all LAG ports that 667557e661aaSTobias Waldekranz * are in the Tx set. 667657e661aaSTobias Waldekranz */ 667757e661aaSTobias Waldekranz dsa_lags_foreach_id(id, ds->dst) { 6678dedd6a00SVladimir Oltean lag = dsa_lag_by_id(ds->dst, id); 6679dedd6a00SVladimir Oltean if (!lag) 668057e661aaSTobias Waldekranz continue; 668157e661aaSTobias Waldekranz 668257e661aaSTobias Waldekranz num_tx = 0; 6683dedd6a00SVladimir Oltean dsa_lag_foreach_port(dp, ds->dst, lag) { 668457e661aaSTobias Waldekranz if (dp->lag_tx_enabled) 668557e661aaSTobias Waldekranz num_tx++; 668657e661aaSTobias Waldekranz } 668757e661aaSTobias Waldekranz 668857e661aaSTobias Waldekranz if (!num_tx) 668957e661aaSTobias Waldekranz continue; 669057e661aaSTobias Waldekranz 669157e661aaSTobias Waldekranz nth = 0; 6692dedd6a00SVladimir Oltean dsa_lag_foreach_port(dp, ds->dst, lag) { 669357e661aaSTobias Waldekranz if (!dp->lag_tx_enabled) 669457e661aaSTobias Waldekranz continue; 669557e661aaSTobias Waldekranz 669657e661aaSTobias Waldekranz if (dp->ds == ds) 669757e661aaSTobias Waldekranz mv88e6xxx_lag_set_port_mask(mask, dp->index, 669857e661aaSTobias Waldekranz num_tx, nth); 669957e661aaSTobias Waldekranz 670057e661aaSTobias Waldekranz nth++; 670157e661aaSTobias Waldekranz } 670257e661aaSTobias Waldekranz } 670357e661aaSTobias Waldekranz 670457e661aaSTobias Waldekranz for (i = 0; i < 8; i++) { 670557e661aaSTobias Waldekranz err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]); 670657e661aaSTobias Waldekranz if (err) 670757e661aaSTobias Waldekranz return err; 670857e661aaSTobias Waldekranz } 670957e661aaSTobias Waldekranz 671057e661aaSTobias Waldekranz return 0; 671157e661aaSTobias Waldekranz } 671257e661aaSTobias Waldekranz 671357e661aaSTobias Waldekranz static int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds, 6714dedd6a00SVladimir Oltean struct dsa_lag lag) 671557e661aaSTobias Waldekranz { 671657e661aaSTobias Waldekranz int err; 671757e661aaSTobias Waldekranz 671857e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks(ds); 671957e661aaSTobias Waldekranz 672057e661aaSTobias Waldekranz if (!err) 6721dedd6a00SVladimir Oltean err = mv88e6xxx_lag_sync_map(ds, lag); 672257e661aaSTobias Waldekranz 672357e661aaSTobias Waldekranz return err; 672457e661aaSTobias Waldekranz } 672557e661aaSTobias Waldekranz 672657e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port) 672757e661aaSTobias Waldekranz { 672857e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 672957e661aaSTobias Waldekranz int err; 673057e661aaSTobias Waldekranz 673157e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 673257e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks(ds); 673357e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 673457e661aaSTobias Waldekranz return err; 673557e661aaSTobias Waldekranz } 673657e661aaSTobias Waldekranz 673757e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port, 6738dedd6a00SVladimir Oltean struct dsa_lag lag, 673957e661aaSTobias Waldekranz struct netdev_lag_upper_info *info) 674057e661aaSTobias Waldekranz { 674157e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 674257e661aaSTobias Waldekranz int err, id; 674357e661aaSTobias Waldekranz 6744dedd6a00SVladimir Oltean if (!mv88e6xxx_lag_can_offload(ds, lag, info)) 674557e661aaSTobias Waldekranz return -EOPNOTSUPP; 674657e661aaSTobias Waldekranz 67473d4a0a2aSVladimir Oltean /* DSA LAG IDs are one-based */ 6748dedd6a00SVladimir Oltean id = lag.id - 1; 674957e661aaSTobias Waldekranz 675057e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 675157e661aaSTobias Waldekranz 675257e661aaSTobias Waldekranz err = mv88e6xxx_port_set_trunk(chip, port, true, id); 675357e661aaSTobias Waldekranz if (err) 675457e661aaSTobias Waldekranz goto err_unlock; 675557e661aaSTobias Waldekranz 6756dedd6a00SVladimir Oltean err = mv88e6xxx_lag_sync_masks_map(ds, lag); 675757e661aaSTobias Waldekranz if (err) 675857e661aaSTobias Waldekranz goto err_clear_trunk; 675957e661aaSTobias Waldekranz 676057e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 676157e661aaSTobias Waldekranz return 0; 676257e661aaSTobias Waldekranz 676357e661aaSTobias Waldekranz err_clear_trunk: 676457e661aaSTobias Waldekranz mv88e6xxx_port_set_trunk(chip, port, false, 0); 676557e661aaSTobias Waldekranz err_unlock: 676657e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 676757e661aaSTobias Waldekranz return err; 676857e661aaSTobias Waldekranz } 676957e661aaSTobias Waldekranz 677057e661aaSTobias Waldekranz static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port, 6771dedd6a00SVladimir Oltean struct dsa_lag lag) 677257e661aaSTobias Waldekranz { 677357e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 677457e661aaSTobias Waldekranz int err_sync, err_trunk; 677557e661aaSTobias Waldekranz 677657e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 6777dedd6a00SVladimir Oltean err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag); 677857e661aaSTobias Waldekranz err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0); 677957e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 678057e661aaSTobias Waldekranz return err_sync ? : err_trunk; 678157e661aaSTobias Waldekranz } 678257e661aaSTobias Waldekranz 678357e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index, 678457e661aaSTobias Waldekranz int port) 678557e661aaSTobias Waldekranz { 678657e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 678757e661aaSTobias Waldekranz int err; 678857e661aaSTobias Waldekranz 678957e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 679057e661aaSTobias Waldekranz err = mv88e6xxx_lag_sync_masks(ds); 679157e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 679257e661aaSTobias Waldekranz return err; 679357e661aaSTobias Waldekranz } 679457e661aaSTobias Waldekranz 679557e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index, 6796dedd6a00SVladimir Oltean int port, struct dsa_lag lag, 679757e661aaSTobias Waldekranz struct netdev_lag_upper_info *info) 679857e661aaSTobias Waldekranz { 679957e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 680057e661aaSTobias Waldekranz int err; 680157e661aaSTobias Waldekranz 6802dedd6a00SVladimir Oltean if (!mv88e6xxx_lag_can_offload(ds, lag, info)) 680357e661aaSTobias Waldekranz return -EOPNOTSUPP; 680457e661aaSTobias Waldekranz 680557e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 680657e661aaSTobias Waldekranz 6807dedd6a00SVladimir Oltean err = mv88e6xxx_lag_sync_masks_map(ds, lag); 680857e661aaSTobias Waldekranz if (err) 680957e661aaSTobias Waldekranz goto unlock; 681057e661aaSTobias Waldekranz 681157e661aaSTobias Waldekranz err = mv88e6xxx_pvt_map(chip, sw_index, port); 681257e661aaSTobias Waldekranz 681357e661aaSTobias Waldekranz unlock: 681457e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 681557e661aaSTobias Waldekranz return err; 681657e661aaSTobias Waldekranz } 681757e661aaSTobias Waldekranz 681857e661aaSTobias Waldekranz static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index, 6819dedd6a00SVladimir Oltean int port, struct dsa_lag lag) 682057e661aaSTobias Waldekranz { 682157e661aaSTobias Waldekranz struct mv88e6xxx_chip *chip = ds->priv; 682257e661aaSTobias Waldekranz int err_sync, err_pvt; 682357e661aaSTobias Waldekranz 682457e661aaSTobias Waldekranz mv88e6xxx_reg_lock(chip); 6825dedd6a00SVladimir Oltean err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag); 682657e661aaSTobias Waldekranz err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port); 682757e661aaSTobias Waldekranz mv88e6xxx_reg_unlock(chip); 682857e661aaSTobias Waldekranz return err_sync ? : err_pvt; 682957e661aaSTobias Waldekranz } 683057e661aaSTobias Waldekranz 6831a82f67afSFlorian Fainelli static const struct dsa_switch_ops mv88e6xxx_switch_ops = { 68327b314362SAndrew Lunn .get_tag_protocol = mv88e6xxx_get_tag_protocol, 68339a99bef5STobias Waldekranz .change_tag_protocol = mv88e6xxx_change_tag_protocol, 6834fad09c73SVivien Didelot .setup = mv88e6xxx_setup, 683523e8b470SAndrew Lunn .teardown = mv88e6xxx_teardown, 6836fd292c18SVladimir Oltean .port_setup = mv88e6xxx_port_setup, 6837fd292c18SVladimir Oltean .port_teardown = mv88e6xxx_port_teardown, 6838d4ebf12bSRussell King (Oracle) .phylink_get_caps = mv88e6xxx_get_caps, 6839a5a6858bSRussell King .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, 6840c9a2356fSRussell King .phylink_mac_config = mv88e6xxx_mac_config, 6841a5a6858bSRussell King .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, 6842c9a2356fSRussell King .phylink_mac_link_down = mv88e6xxx_mac_link_down, 6843c9a2356fSRussell King .phylink_mac_link_up = mv88e6xxx_mac_link_up, 6844fad09c73SVivien Didelot .get_strings = mv88e6xxx_get_strings, 6845fad09c73SVivien Didelot .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 6846fad09c73SVivien Didelot .get_sset_count = mv88e6xxx_get_sset_count, 684704aca993SAndrew Lunn .port_enable = mv88e6xxx_port_enable, 684804aca993SAndrew Lunn .port_disable = mv88e6xxx_port_disable, 68492a550aecSAndrew Lunn .port_max_mtu = mv88e6xxx_get_max_mtu, 68502a550aecSAndrew Lunn .port_change_mtu = mv88e6xxx_change_mtu, 685108f50061SVivien Didelot .get_mac_eee = mv88e6xxx_get_mac_eee, 685208f50061SVivien Didelot .set_mac_eee = mv88e6xxx_set_mac_eee, 6853fad09c73SVivien Didelot .get_eeprom_len = mv88e6xxx_get_eeprom_len, 6854fad09c73SVivien Didelot .get_eeprom = mv88e6xxx_get_eeprom, 6855fad09c73SVivien Didelot .set_eeprom = mv88e6xxx_set_eeprom, 6856fad09c73SVivien Didelot .get_regs_len = mv88e6xxx_get_regs_len, 6857fad09c73SVivien Didelot .get_regs = mv88e6xxx_get_regs, 6858da7dc875SVivien Didelot .get_rxnfc = mv88e6xxx_get_rxnfc, 6859da7dc875SVivien Didelot .set_rxnfc = mv88e6xxx_set_rxnfc, 68602cfcd964SVivien Didelot .set_ageing_time = mv88e6xxx_set_ageing_time, 6861fad09c73SVivien Didelot .port_bridge_join = mv88e6xxx_port_bridge_join, 6862fad09c73SVivien Didelot .port_bridge_leave = mv88e6xxx_port_bridge_leave, 6863a8b659e7SVladimir Oltean .port_pre_bridge_flags = mv88e6xxx_port_pre_bridge_flags, 6864a8b659e7SVladimir Oltean .port_bridge_flags = mv88e6xxx_port_bridge_flags, 6865fad09c73SVivien Didelot .port_stp_state_set = mv88e6xxx_port_stp_state_set, 6866acaf4d2eSTobias Waldekranz .port_mst_state_set = mv88e6xxx_port_mst_state_set, 6867749efcb8SVivien Didelot .port_fast_age = mv88e6xxx_port_fast_age, 6868acaf4d2eSTobias Waldekranz .port_vlan_fast_age = mv88e6xxx_port_vlan_fast_age, 6869fad09c73SVivien Didelot .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 6870fad09c73SVivien Didelot .port_vlan_add = mv88e6xxx_port_vlan_add, 6871fad09c73SVivien Didelot .port_vlan_del = mv88e6xxx_port_vlan_del, 6872acaf4d2eSTobias Waldekranz .vlan_msti_set = mv88e6xxx_vlan_msti_set, 6873fad09c73SVivien Didelot .port_fdb_add = mv88e6xxx_port_fdb_add, 6874fad09c73SVivien Didelot .port_fdb_del = mv88e6xxx_port_fdb_del, 6875fad09c73SVivien Didelot .port_fdb_dump = mv88e6xxx_port_fdb_dump, 68767df8fbddSVivien Didelot .port_mdb_add = mv88e6xxx_port_mdb_add, 68777df8fbddSVivien Didelot .port_mdb_del = mv88e6xxx_port_mdb_del, 6878f0942e00SIwan R Timmer .port_mirror_add = mv88e6xxx_port_mirror_add, 6879f0942e00SIwan R Timmer .port_mirror_del = mv88e6xxx_port_mirror_del, 6880aec5ac88SVivien Didelot .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 6881aec5ac88SVivien Didelot .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 6882c6fe0ad2SBrandon Streiff .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 6883c6fe0ad2SBrandon Streiff .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 6884c6fe0ad2SBrandon Streiff .port_txtstamp = mv88e6xxx_port_txtstamp, 6885c6fe0ad2SBrandon Streiff .port_rxtstamp = mv88e6xxx_port_rxtstamp, 6886c6fe0ad2SBrandon Streiff .get_ts_info = mv88e6xxx_get_ts_info, 688723e8b470SAndrew Lunn .devlink_param_get = mv88e6xxx_devlink_param_get, 688823e8b470SAndrew Lunn .devlink_param_set = mv88e6xxx_devlink_param_set, 688993157307SAndrew Lunn .devlink_info_get = mv88e6xxx_devlink_info_get, 689057e661aaSTobias Waldekranz .port_lag_change = mv88e6xxx_port_lag_change, 689157e661aaSTobias Waldekranz .port_lag_join = mv88e6xxx_port_lag_join, 689257e661aaSTobias Waldekranz .port_lag_leave = mv88e6xxx_port_lag_leave, 689357e661aaSTobias Waldekranz .crosschip_lag_change = mv88e6xxx_crosschip_lag_change, 689457e661aaSTobias Waldekranz .crosschip_lag_join = mv88e6xxx_crosschip_lag_join, 689557e661aaSTobias Waldekranz .crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave, 6896fad09c73SVivien Didelot }; 6897fad09c73SVivien Didelot 689855ed0ce0SFlorian Fainelli static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 6899fad09c73SVivien Didelot { 6900fad09c73SVivien Didelot struct device *dev = chip->dev; 6901fad09c73SVivien Didelot struct dsa_switch *ds; 6902fad09c73SVivien Didelot 69037e99e347SVivien Didelot ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); 6904fad09c73SVivien Didelot if (!ds) 6905fad09c73SVivien Didelot return -ENOMEM; 6906fad09c73SVivien Didelot 69077e99e347SVivien Didelot ds->dev = dev; 69087e99e347SVivien Didelot ds->num_ports = mv88e6xxx_num_ports(chip); 6909fad09c73SVivien Didelot ds->priv = chip; 6910877b7cb0SAndrew Lunn ds->dev = dev; 69119d490b4eSVivien Didelot ds->ops = &mv88e6xxx_switch_ops; 69129ff74f24SVivien Didelot ds->ageing_time_min = chip->info->age_time_coeff; 69139ff74f24SVivien Didelot ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 6914fad09c73SVivien Didelot 691557e661aaSTobias Waldekranz /* Some chips support up to 32, but that requires enabling the 691657e661aaSTobias Waldekranz * 5-bit port mode, which we do not support. 640k^W16 ought to 691757e661aaSTobias Waldekranz * be enough for anyone. 691857e661aaSTobias Waldekranz */ 6919b80dc51bSTobias Waldekranz ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0; 692057e661aaSTobias Waldekranz 6921fad09c73SVivien Didelot dev_set_drvdata(dev, ds); 6922fad09c73SVivien Didelot 692323c9ee49SVivien Didelot return dsa_register_switch(ds); 6924fad09c73SVivien Didelot } 6925fad09c73SVivien Didelot 6926fad09c73SVivien Didelot static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 6927fad09c73SVivien Didelot { 6928fad09c73SVivien Didelot dsa_unregister_switch(chip->ds); 6929fad09c73SVivien Didelot } 6930fad09c73SVivien Didelot 6931877b7cb0SAndrew Lunn static const void *pdata_device_get_match_data(struct device *dev) 6932877b7cb0SAndrew Lunn { 6933877b7cb0SAndrew Lunn const struct of_device_id *matches = dev->driver->of_match_table; 6934877b7cb0SAndrew Lunn const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 6935877b7cb0SAndrew Lunn 6936877b7cb0SAndrew Lunn for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 6937877b7cb0SAndrew Lunn matches++) { 6938877b7cb0SAndrew Lunn if (!strcmp(pdata->compatible, matches->compatible)) 6939877b7cb0SAndrew Lunn return matches->data; 6940877b7cb0SAndrew Lunn } 6941877b7cb0SAndrew Lunn return NULL; 6942877b7cb0SAndrew Lunn } 6943877b7cb0SAndrew Lunn 6944bcd3d9d9SMiquel Raynal /* There is no suspend to RAM support at DSA level yet, the switch configuration 6945bcd3d9d9SMiquel Raynal * would be lost after a power cycle so prevent it to be suspended. 6946bcd3d9d9SMiquel Raynal */ 6947bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_suspend(struct device *dev) 6948bcd3d9d9SMiquel Raynal { 6949bcd3d9d9SMiquel Raynal return -EOPNOTSUPP; 6950bcd3d9d9SMiquel Raynal } 6951bcd3d9d9SMiquel Raynal 6952bcd3d9d9SMiquel Raynal static int __maybe_unused mv88e6xxx_resume(struct device *dev) 6953bcd3d9d9SMiquel Raynal { 6954bcd3d9d9SMiquel Raynal return 0; 6955bcd3d9d9SMiquel Raynal } 6956bcd3d9d9SMiquel Raynal 6957bcd3d9d9SMiquel Raynal static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 6958bcd3d9d9SMiquel Raynal 6959fad09c73SVivien Didelot static int mv88e6xxx_probe(struct mdio_device *mdiodev) 6960fad09c73SVivien Didelot { 6961877b7cb0SAndrew Lunn struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 69627ddae24fSDavid S. Miller const struct mv88e6xxx_info *compat_info = NULL; 6963fad09c73SVivien Didelot struct device *dev = &mdiodev->dev; 6964fad09c73SVivien Didelot struct device_node *np = dev->of_node; 6965fad09c73SVivien Didelot struct mv88e6xxx_chip *chip; 6966877b7cb0SAndrew Lunn int port; 6967fad09c73SVivien Didelot int err; 6968fad09c73SVivien Didelot 69697bb8c996SAndrew Lunn if (!np && !pdata) 69707bb8c996SAndrew Lunn return -EINVAL; 69717bb8c996SAndrew Lunn 6972877b7cb0SAndrew Lunn if (np) 6973fad09c73SVivien Didelot compat_info = of_device_get_match_data(dev); 6974877b7cb0SAndrew Lunn 6975877b7cb0SAndrew Lunn if (pdata) { 6976877b7cb0SAndrew Lunn compat_info = pdata_device_get_match_data(dev); 6977877b7cb0SAndrew Lunn 6978877b7cb0SAndrew Lunn if (!pdata->netdev) 6979877b7cb0SAndrew Lunn return -EINVAL; 6980877b7cb0SAndrew Lunn 6981877b7cb0SAndrew Lunn for (port = 0; port < DSA_MAX_PORTS; port++) { 6982877b7cb0SAndrew Lunn if (!(pdata->enabled_ports & (1 << port))) 6983877b7cb0SAndrew Lunn continue; 6984877b7cb0SAndrew Lunn if (strcmp(pdata->cd.port_names[port], "cpu")) 6985877b7cb0SAndrew Lunn continue; 6986877b7cb0SAndrew Lunn pdata->cd.netdev[port] = &pdata->netdev->dev; 6987877b7cb0SAndrew Lunn break; 6988877b7cb0SAndrew Lunn } 6989877b7cb0SAndrew Lunn } 6990877b7cb0SAndrew Lunn 6991fad09c73SVivien Didelot if (!compat_info) 6992fad09c73SVivien Didelot return -EINVAL; 6993fad09c73SVivien Didelot 6994fad09c73SVivien Didelot chip = mv88e6xxx_alloc_chip(dev); 6995877b7cb0SAndrew Lunn if (!chip) { 6996877b7cb0SAndrew Lunn err = -ENOMEM; 6997877b7cb0SAndrew Lunn goto out; 6998877b7cb0SAndrew Lunn } 6999fad09c73SVivien Didelot 7000fad09c73SVivien Didelot chip->info = compat_info; 7001fad09c73SVivien Didelot 7002b4308f04SAndrew Lunn chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 7003877b7cb0SAndrew Lunn if (IS_ERR(chip->reset)) { 7004877b7cb0SAndrew Lunn err = PTR_ERR(chip->reset); 7005877b7cb0SAndrew Lunn goto out; 7006877b7cb0SAndrew Lunn } 70077b75e49dSBaruch Siach if (chip->reset) 70087b75e49dSBaruch Siach usleep_range(1000, 2000); 7009b4308f04SAndrew Lunn 70105da66099SNathan Rossi /* Detect if the device is configured in single chip addressing mode, 70115da66099SNathan Rossi * otherwise continue with address specific smi init/detection. 70125da66099SNathan Rossi */ 70135da66099SNathan Rossi err = mv88e6xxx_single_chip_detect(chip, mdiodev); 70145da66099SNathan Rossi if (err) { 70155da66099SNathan Rossi err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 70165da66099SNathan Rossi if (err) 70175da66099SNathan Rossi goto out; 70185da66099SNathan Rossi 7019fad09c73SVivien Didelot err = mv88e6xxx_detect(chip); 7020fad09c73SVivien Didelot if (err) 7021877b7cb0SAndrew Lunn goto out; 70225da66099SNathan Rossi } 7023fad09c73SVivien Didelot 7024670bb80fSTobias Waldekranz if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED) 7025670bb80fSTobias Waldekranz chip->tag_protocol = DSA_TAG_PROTO_EDSA; 7026670bb80fSTobias Waldekranz else 7027670bb80fSTobias Waldekranz chip->tag_protocol = DSA_TAG_PROTO_DSA; 7028670bb80fSTobias Waldekranz 7029e57e5e77SVivien Didelot mv88e6xxx_phy_init(chip); 7030e57e5e77SVivien Didelot 703100baabe5SAndrew Lunn if (chip->info->ops->get_eeprom) { 703200baabe5SAndrew Lunn if (np) 703300baabe5SAndrew Lunn of_property_read_u32(np, "eeprom-length", 703400baabe5SAndrew Lunn &chip->eeprom_len); 703500baabe5SAndrew Lunn else 703600baabe5SAndrew Lunn chip->eeprom_len = pdata->eeprom_len; 703700baabe5SAndrew Lunn } 7038fad09c73SVivien Didelot 7039c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 7040dc30c35bSAndrew Lunn err = mv88e6xxx_switch_reset(chip); 7041c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 7042fad09c73SVivien Didelot if (err) 7043dc30c35bSAndrew Lunn goto out; 7044fad09c73SVivien Didelot 7045a27415deSAndrew Lunn if (np) { 7046dc30c35bSAndrew Lunn chip->irq = of_irq_get(np, 0); 7047dc30c35bSAndrew Lunn if (chip->irq == -EPROBE_DEFER) { 7048dc30c35bSAndrew Lunn err = chip->irq; 7049dc30c35bSAndrew Lunn goto out; 7050fad09c73SVivien Didelot } 7051a27415deSAndrew Lunn } 7052a27415deSAndrew Lunn 7053a27415deSAndrew Lunn if (pdata) 7054a27415deSAndrew Lunn chip->irq = pdata->irq; 7055fad09c73SVivien Didelot 7056294d711eSAndrew Lunn /* Has to be performed before the MDIO bus is created, because 7057a708767eSUwe Kleine-König * the PHYs will link their interrupts to these interrupt 7058294d711eSAndrew Lunn * controllers 7059dc30c35bSAndrew Lunn */ 7060c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 7061294d711eSAndrew Lunn if (chip->irq > 0) 7062dc30c35bSAndrew Lunn err = mv88e6xxx_g1_irq_setup(chip); 7063294d711eSAndrew Lunn else 7064294d711eSAndrew Lunn err = mv88e6xxx_irq_poll_setup(chip); 7065c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 7066dc30c35bSAndrew Lunn 7067dc30c35bSAndrew Lunn if (err) 7068dc30c35bSAndrew Lunn goto out; 7069dc30c35bSAndrew Lunn 7070d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) { 7071dc30c35bSAndrew Lunn err = mv88e6xxx_g2_irq_setup(chip); 7072dc30c35bSAndrew Lunn if (err) 7073dc30c35bSAndrew Lunn goto out_g1_irq; 7074dc30c35bSAndrew Lunn } 70750977644cSAndrew Lunn 70760977644cSAndrew Lunn err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 70770977644cSAndrew Lunn if (err) 70780977644cSAndrew Lunn goto out_g2_irq; 707962eb1162SAndrew Lunn 708062eb1162SAndrew Lunn err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 708162eb1162SAndrew Lunn if (err) 708262eb1162SAndrew Lunn goto out_g1_atu_prob_irq; 7083dc30c35bSAndrew Lunn 7084a3c53be5SAndrew Lunn err = mv88e6xxx_mdios_register(chip, np); 7085dc30c35bSAndrew Lunn if (err) 708662eb1162SAndrew Lunn goto out_g1_vtu_prob_irq; 7087dc30c35bSAndrew Lunn 708855ed0ce0SFlorian Fainelli err = mv88e6xxx_register_switch(chip); 7089dc30c35bSAndrew Lunn if (err) 7090dc30c35bSAndrew Lunn goto out_mdio; 7091dc30c35bSAndrew Lunn 7092fad09c73SVivien Didelot return 0; 7093dc30c35bSAndrew Lunn 7094dc30c35bSAndrew Lunn out_mdio: 7095a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 709662eb1162SAndrew Lunn out_g1_vtu_prob_irq: 709762eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 70980977644cSAndrew Lunn out_g1_atu_prob_irq: 70990977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 7100dc30c35bSAndrew Lunn out_g2_irq: 7101294d711eSAndrew Lunn if (chip->info->g2_irqs > 0) 7102dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 7103dc30c35bSAndrew Lunn out_g1_irq: 7104294d711eSAndrew Lunn if (chip->irq > 0) 7105dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 7106294d711eSAndrew Lunn else 7107294d711eSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 7108dc30c35bSAndrew Lunn out: 7109877b7cb0SAndrew Lunn if (pdata) 7110877b7cb0SAndrew Lunn dev_put(pdata->netdev); 7111877b7cb0SAndrew Lunn 7112dc30c35bSAndrew Lunn return err; 7113fad09c73SVivien Didelot } 7114fad09c73SVivien Didelot 7115fad09c73SVivien Didelot static void mv88e6xxx_remove(struct mdio_device *mdiodev) 7116fad09c73SVivien Didelot { 7117fad09c73SVivien Didelot struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 71180650bf52SVladimir Oltean struct mv88e6xxx_chip *chip; 71190650bf52SVladimir Oltean 71200650bf52SVladimir Oltean if (!ds) 71210650bf52SVladimir Oltean return; 71220650bf52SVladimir Oltean 71230650bf52SVladimir Oltean chip = ds->priv; 7124fad09c73SVivien Didelot 7125c6fe0ad2SBrandon Streiff if (chip->info->ptp_support) { 7126c6fe0ad2SBrandon Streiff mv88e6xxx_hwtstamp_free(chip); 71272fa8d3afSBrandon Streiff mv88e6xxx_ptp_free(chip); 7128c6fe0ad2SBrandon Streiff } 71292fa8d3afSBrandon Streiff 7130930188ceSAndrew Lunn mv88e6xxx_phy_destroy(chip); 7131fad09c73SVivien Didelot mv88e6xxx_unregister_switch(chip); 7132a3c53be5SAndrew Lunn mv88e6xxx_mdios_unregister(chip); 7133dc30c35bSAndrew Lunn 713462eb1162SAndrew Lunn mv88e6xxx_g1_vtu_prob_irq_free(chip); 71350977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_free(chip); 713676f38f1fSAndrew Lunn 7137d6c5e6afSVivien Didelot if (chip->info->g2_irqs > 0) 7138dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_free(chip); 713976f38f1fSAndrew Lunn 714076f38f1fSAndrew Lunn if (chip->irq > 0) 7141dc30c35bSAndrew Lunn mv88e6xxx_g1_irq_free(chip); 714276f38f1fSAndrew Lunn else 714376f38f1fSAndrew Lunn mv88e6xxx_irq_poll_free(chip); 71440650bf52SVladimir Oltean 71450650bf52SVladimir Oltean dev_set_drvdata(&mdiodev->dev, NULL); 71460650bf52SVladimir Oltean } 71470650bf52SVladimir Oltean 71480650bf52SVladimir Oltean static void mv88e6xxx_shutdown(struct mdio_device *mdiodev) 71490650bf52SVladimir Oltean { 71500650bf52SVladimir Oltean struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 71510650bf52SVladimir Oltean 71520650bf52SVladimir Oltean if (!ds) 71530650bf52SVladimir Oltean return; 71540650bf52SVladimir Oltean 71550650bf52SVladimir Oltean dsa_switch_shutdown(ds); 71560650bf52SVladimir Oltean 71570650bf52SVladimir Oltean dev_set_drvdata(&mdiodev->dev, NULL); 7158fad09c73SVivien Didelot } 7159fad09c73SVivien Didelot 7160fad09c73SVivien Didelot static const struct of_device_id mv88e6xxx_of_match[] = { 7161fad09c73SVivien Didelot { 7162fad09c73SVivien Didelot .compatible = "marvell,mv88e6085", 7163fad09c73SVivien Didelot .data = &mv88e6xxx_table[MV88E6085], 7164fad09c73SVivien Didelot }, 71651a3b39ecSAndrew Lunn { 71661a3b39ecSAndrew Lunn .compatible = "marvell,mv88e6190", 71671a3b39ecSAndrew Lunn .data = &mv88e6xxx_table[MV88E6190], 71681a3b39ecSAndrew Lunn }, 71691f71836fSRasmus Villemoes { 71701f71836fSRasmus Villemoes .compatible = "marvell,mv88e6250", 71711f71836fSRasmus Villemoes .data = &mv88e6xxx_table[MV88E6250], 71721f71836fSRasmus Villemoes }, 7173fad09c73SVivien Didelot { /* sentinel */ }, 7174fad09c73SVivien Didelot }; 7175fad09c73SVivien Didelot 7176fad09c73SVivien Didelot MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 7177fad09c73SVivien Didelot 7178fad09c73SVivien Didelot static struct mdio_driver mv88e6xxx_driver = { 7179fad09c73SVivien Didelot .probe = mv88e6xxx_probe, 7180fad09c73SVivien Didelot .remove = mv88e6xxx_remove, 71810650bf52SVladimir Oltean .shutdown = mv88e6xxx_shutdown, 7182fad09c73SVivien Didelot .mdiodrv.driver = { 7183fad09c73SVivien Didelot .name = "mv88e6085", 7184fad09c73SVivien Didelot .of_match_table = mv88e6xxx_of_match, 7185bcd3d9d9SMiquel Raynal .pm = &mv88e6xxx_pm_ops, 7186fad09c73SVivien Didelot }, 7187fad09c73SVivien Didelot }; 7188fad09c73SVivien Didelot 71897324d50eSAndrew Lunn mdio_module_driver(mv88e6xxx_driver); 7190fad09c73SVivien Didelot 7191fad09c73SVivien Didelot MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 7192fad09c73SVivien Didelot MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 7193fad09c73SVivien Didelot MODULE_LICENSE("GPL"); 7194