162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Marvell 88e6xxx Ethernet switch single-chip support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2008 Marvell Semiconductor 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 1062306a36Sopenharmony_ci * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/bitfield.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/dsa/mv88e6xxx.h> 1662306a36Sopenharmony_ci#include <linux/etherdevice.h> 1762306a36Sopenharmony_ci#include <linux/ethtool.h> 1862306a36Sopenharmony_ci#include <linux/if_bridge.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/irq.h> 2162306a36Sopenharmony_ci#include <linux/irqdomain.h> 2262306a36Sopenharmony_ci#include <linux/jiffies.h> 2362306a36Sopenharmony_ci#include <linux/list.h> 2462306a36Sopenharmony_ci#include <linux/mdio.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/of.h> 2762306a36Sopenharmony_ci#include <linux/of_irq.h> 2862306a36Sopenharmony_ci#include <linux/of_mdio.h> 2962306a36Sopenharmony_ci#include <linux/platform_data/mv88e6xxx.h> 3062306a36Sopenharmony_ci#include <linux/netdevice.h> 3162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3262306a36Sopenharmony_ci#include <linux/phylink.h> 3362306a36Sopenharmony_ci#include <net/dsa.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "chip.h" 3662306a36Sopenharmony_ci#include "devlink.h" 3762306a36Sopenharmony_ci#include "global1.h" 3862306a36Sopenharmony_ci#include "global2.h" 3962306a36Sopenharmony_ci#include "hwtstamp.h" 4062306a36Sopenharmony_ci#include "phy.h" 4162306a36Sopenharmony_ci#include "port.h" 4262306a36Sopenharmony_ci#include "ptp.h" 4362306a36Sopenharmony_ci#include "serdes.h" 4462306a36Sopenharmony_ci#include "smi.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void assert_reg_lock(struct mv88e6xxx_chip *chip) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci if (unlikely(!mutex_is_locked(&chip->reg_lock))) { 4962306a36Sopenharmony_ci dev_err(chip->dev, "Switch registers lock not held!\n"); 5062306a36Sopenharmony_ci dump_stack(); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciint mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci int err; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci assert_reg_lock(chip); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci err = mv88e6xxx_smi_read(chip, addr, reg, val); 6162306a36Sopenharmony_ci if (err) 6262306a36Sopenharmony_ci return err; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 6562306a36Sopenharmony_ci addr, reg, *val); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciint mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci int err; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci assert_reg_lock(chip); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci err = mv88e6xxx_smi_write(chip, addr, reg, val); 7762306a36Sopenharmony_ci if (err) 7862306a36Sopenharmony_ci return err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", 8162306a36Sopenharmony_ci addr, reg, val); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciint mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, 8762306a36Sopenharmony_ci u16 mask, u16 val) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci const unsigned long timeout = jiffies + msecs_to_jiffies(50); 9062306a36Sopenharmony_ci u16 data; 9162306a36Sopenharmony_ci int err; 9262306a36Sopenharmony_ci int i; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* There's no bus specific operation to wait for a mask. Even 9562306a36Sopenharmony_ci * if the initial poll takes longer than 50ms, always do at 9662306a36Sopenharmony_ci * least one more attempt. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) { 9962306a36Sopenharmony_ci err = mv88e6xxx_read(chip, addr, reg, &data); 10062306a36Sopenharmony_ci if (err) 10162306a36Sopenharmony_ci return err; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if ((data & mask) == val) 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (i < 2) 10762306a36Sopenharmony_ci cpu_relax(); 10862306a36Sopenharmony_ci else 10962306a36Sopenharmony_ci usleep_range(1000, 2000); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci err = mv88e6xxx_read(chip, addr, reg, &data); 11362306a36Sopenharmony_ci if (err) 11462306a36Sopenharmony_ci return err; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if ((data & mask) == val) 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci dev_err(chip->dev, "Timeout while waiting for switch\n"); 12062306a36Sopenharmony_ci return -ETIMEDOUT; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ciint mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, 12462306a36Sopenharmony_ci int bit, int val) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit), 12762306a36Sopenharmony_ci val ? BIT(bit) : 0x0000); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistruct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci mdio_bus = list_first_entry(&chip->mdios, struct mv88e6xxx_mdio_bus, 13562306a36Sopenharmony_ci list); 13662306a36Sopenharmony_ci if (!mdio_bus) 13762306a36Sopenharmony_ci return NULL; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return mdio_bus->bus; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_mask(struct irq_data *d) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 14562306a36Sopenharmony_ci unsigned int n = d->hwirq; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci chip->g1_irq.masked |= (1 << n); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_unmask(struct irq_data *d) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 15362306a36Sopenharmony_ci unsigned int n = d->hwirq; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci chip->g1_irq.masked &= ~(1 << n); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci unsigned int nhandled = 0; 16162306a36Sopenharmony_ci unsigned int sub_irq; 16262306a36Sopenharmony_ci unsigned int n; 16362306a36Sopenharmony_ci u16 reg; 16462306a36Sopenharmony_ci u16 ctl1; 16562306a36Sopenharmony_ci int err; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 16862306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 16962306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (err) 17262306a36Sopenharmony_ci goto out; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci do { 17562306a36Sopenharmony_ci for (n = 0; n < chip->g1_irq.nirqs; ++n) { 17662306a36Sopenharmony_ci if (reg & (1 << n)) { 17762306a36Sopenharmony_ci sub_irq = irq_find_mapping(chip->g1_irq.domain, 17862306a36Sopenharmony_ci n); 17962306a36Sopenharmony_ci handle_nested_irq(sub_irq); 18062306a36Sopenharmony_ci ++nhandled; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 18562306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); 18662306a36Sopenharmony_ci if (err) 18762306a36Sopenharmony_ci goto unlock; 18862306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 18962306a36Sopenharmony_ciunlock: 19062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 19162306a36Sopenharmony_ci if (err) 19262306a36Sopenharmony_ci goto out; 19362306a36Sopenharmony_ci ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); 19462306a36Sopenharmony_ci } while (reg & ctl1); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciout: 19762306a36Sopenharmony_ci return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = dev_id; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return mv88e6xxx_g1_irq_thread_work(chip); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 21762306a36Sopenharmony_ci u16 mask = GENMASK(chip->g1_irq.nirqs, 0); 21862306a36Sopenharmony_ci u16 reg; 21962306a36Sopenharmony_ci int err; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); 22262306a36Sopenharmony_ci if (err) 22362306a36Sopenharmony_ci goto out; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci reg &= ~mask; 22662306a36Sopenharmony_ci reg |= (~chip->g1_irq.masked & mask); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); 22962306a36Sopenharmony_ci if (err) 23062306a36Sopenharmony_ci goto out; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciout: 23362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct irq_chip mv88e6xxx_g1_irq_chip = { 23762306a36Sopenharmony_ci .name = "mv88e6xxx-g1", 23862306a36Sopenharmony_ci .irq_mask = mv88e6xxx_g1_irq_mask, 23962306a36Sopenharmony_ci .irq_unmask = mv88e6xxx_g1_irq_unmask, 24062306a36Sopenharmony_ci .irq_bus_lock = mv88e6xxx_g1_irq_bus_lock, 24162306a36Sopenharmony_ci .irq_bus_sync_unlock = mv88e6xxx_g1_irq_bus_sync_unlock, 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int mv88e6xxx_g1_irq_domain_map(struct irq_domain *d, 24562306a36Sopenharmony_ci unsigned int irq, 24662306a36Sopenharmony_ci irq_hw_number_t hwirq) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = d->host_data; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci irq_set_chip_data(irq, d->host_data); 25162306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &chip->g1_irq.chip, handle_level_irq); 25262306a36Sopenharmony_ci irq_set_noprobe(irq); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { 25862306a36Sopenharmony_ci .map = mv88e6xxx_g1_irq_domain_map, 25962306a36Sopenharmony_ci .xlate = irq_domain_xlate_twocell, 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* To be called with reg_lock held */ 26362306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci int irq, virq; 26662306a36Sopenharmony_ci u16 mask; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 26962306a36Sopenharmony_ci mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 27062306a36Sopenharmony_ci mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { 27362306a36Sopenharmony_ci virq = irq_find_mapping(chip->g1_irq.domain, irq); 27462306a36Sopenharmony_ci irq_dispose_mapping(virq); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci irq_domain_remove(chip->g1_irq.domain); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * free_irq must be called without reg_lock taken because the irq 28462306a36Sopenharmony_ci * handler takes this lock, too. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci free_irq(chip->irq, chip); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 28962306a36Sopenharmony_ci mv88e6xxx_g1_irq_free_common(chip); 29062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci int err, irq, virq; 29662306a36Sopenharmony_ci u16 reg, mask; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci chip->g1_irq.nirqs = chip->info->g1_irqs; 29962306a36Sopenharmony_ci chip->g1_irq.domain = irq_domain_add_simple( 30062306a36Sopenharmony_ci NULL, chip->g1_irq.nirqs, 0, 30162306a36Sopenharmony_ci &mv88e6xxx_g1_irq_domain_ops, chip); 30262306a36Sopenharmony_ci if (!chip->g1_irq.domain) 30362306a36Sopenharmony_ci return -ENOMEM; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (irq = 0; irq < chip->g1_irq.nirqs; irq++) 30662306a36Sopenharmony_ci irq_create_mapping(chip->g1_irq.domain, irq); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; 30962306a36Sopenharmony_ci chip->g1_irq.masked = ~0; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); 31262306a36Sopenharmony_ci if (err) 31362306a36Sopenharmony_ci goto out_mapping; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 31862306a36Sopenharmony_ci if (err) 31962306a36Sopenharmony_ci goto out_disable; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Reading the interrupt status clears (most of) them */ 32262306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); 32362306a36Sopenharmony_ci if (err) 32462306a36Sopenharmony_ci goto out_disable; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ciout_disable: 32962306a36Sopenharmony_ci mask &= ~GENMASK(chip->g1_irq.nirqs, 0); 33062306a36Sopenharmony_ci mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciout_mapping: 33362306a36Sopenharmony_ci for (irq = 0; irq < 16; irq++) { 33462306a36Sopenharmony_ci virq = irq_find_mapping(chip->g1_irq.domain, irq); 33562306a36Sopenharmony_ci irq_dispose_mapping(virq); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci irq_domain_remove(chip->g1_irq.domain); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci static struct lock_class_key lock_key; 34662306a36Sopenharmony_ci static struct lock_class_key request_key; 34762306a36Sopenharmony_ci int err; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci err = mv88e6xxx_g1_irq_setup_common(chip); 35062306a36Sopenharmony_ci if (err) 35162306a36Sopenharmony_ci return err; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* These lock classes tells lockdep that global 1 irqs are in 35462306a36Sopenharmony_ci * a different category than their parent GPIO, so it won't 35562306a36Sopenharmony_ci * report false recursion. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci irq_set_lockdep_class(chip->irq, &lock_key, &request_key); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci snprintf(chip->irq_name, sizeof(chip->irq_name), 36062306a36Sopenharmony_ci "mv88e6xxx-%s", dev_name(chip->dev)); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 36362306a36Sopenharmony_ci err = request_threaded_irq(chip->irq, NULL, 36462306a36Sopenharmony_ci mv88e6xxx_g1_irq_thread_fn, 36562306a36Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED, 36662306a36Sopenharmony_ci chip->irq_name, chip); 36762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 36862306a36Sopenharmony_ci if (err) 36962306a36Sopenharmony_ci mv88e6xxx_g1_irq_free_common(chip); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return err; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void mv88e6xxx_irq_poll(struct kthread_work *work) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = container_of(work, 37762306a36Sopenharmony_ci struct mv88e6xxx_chip, 37862306a36Sopenharmony_ci irq_poll_work.work); 37962306a36Sopenharmony_ci mv88e6xxx_g1_irq_thread_work(chip); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 38262306a36Sopenharmony_ci msecs_to_jiffies(100)); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci int err; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci err = mv88e6xxx_g1_irq_setup_common(chip); 39062306a36Sopenharmony_ci if (err) 39162306a36Sopenharmony_ci return err; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci kthread_init_delayed_work(&chip->irq_poll_work, 39462306a36Sopenharmony_ci mv88e6xxx_irq_poll); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev)); 39762306a36Sopenharmony_ci if (IS_ERR(chip->kworker)) 39862306a36Sopenharmony_ci return PTR_ERR(chip->kworker); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, 40162306a36Sopenharmony_ci msecs_to_jiffies(100)); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci kthread_cancel_delayed_work_sync(&chip->irq_poll_work); 40962306a36Sopenharmony_ci kthread_destroy_worker(chip->kworker); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 41262306a36Sopenharmony_ci mv88e6xxx_g1_irq_free_common(chip); 41362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, 41762306a36Sopenharmony_ci int port, phy_interface_t interface) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int err; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (chip->info->ops->port_set_rgmii_delay) { 42262306a36Sopenharmony_ci err = chip->info->ops->port_set_rgmii_delay(chip, port, 42362306a36Sopenharmony_ci interface); 42462306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 42562306a36Sopenharmony_ci return err; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (chip->info->ops->port_set_cmode) { 42962306a36Sopenharmony_ci err = chip->info->ops->port_set_cmode(chip, port, 43062306a36Sopenharmony_ci interface); 43162306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 43262306a36Sopenharmony_ci return err; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, 43962306a36Sopenharmony_ci int link, int speed, int duplex, int pause, 44062306a36Sopenharmony_ci phy_interface_t mode) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci int err; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!chip->info->ops->port_set_link) 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* Port's MAC control must not be changed unless the link is down */ 44862306a36Sopenharmony_ci err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN); 44962306a36Sopenharmony_ci if (err) 45062306a36Sopenharmony_ci return err; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (chip->info->ops->port_set_speed_duplex) { 45362306a36Sopenharmony_ci err = chip->info->ops->port_set_speed_duplex(chip, port, 45462306a36Sopenharmony_ci speed, duplex); 45562306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 45662306a36Sopenharmony_ci goto restore_link; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (chip->info->ops->port_set_pause) { 46062306a36Sopenharmony_ci err = chip->info->ops->port_set_pause(chip, port, pause); 46162306a36Sopenharmony_ci if (err) 46262306a36Sopenharmony_ci goto restore_link; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci err = mv88e6xxx_port_config_interface(chip, port, mode); 46662306a36Sopenharmony_cirestore_link: 46762306a36Sopenharmony_ci if (chip->info->ops->port_set_link(chip, port, link)) 46862306a36Sopenharmony_ci dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return err; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int mv88e6xxx_phy_is_internal(struct mv88e6xxx_chip *chip, int port) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci return port >= chip->info->internal_phys_offset && 47662306a36Sopenharmony_ci port < chip->info->num_internal_phys + 47762306a36Sopenharmony_ci chip->info->internal_phys_offset; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci u16 reg; 48362306a36Sopenharmony_ci int err; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* The 88e6250 family does not have the PHY detect bit. Instead, 48662306a36Sopenharmony_ci * report whether the port is internal. 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci if (chip->info->family == MV88E6XXX_FAMILY_6250) 48962306a36Sopenharmony_ci return mv88e6xxx_phy_is_internal(chip, port); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 49262306a36Sopenharmony_ci if (err) { 49362306a36Sopenharmony_ci dev_err(chip->dev, 49462306a36Sopenharmony_ci "p%d: %s: failed to read port status\n", 49562306a36Sopenharmony_ci port, __func__); 49662306a36Sopenharmony_ci return err; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic const u8 mv88e6185_phy_interface_modes[] = { 50362306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_GMII_FD] = PHY_INTERFACE_MODE_GMII, 50462306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII, 50562306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_MII_100] = PHY_INTERFACE_MODE_MII, 50662306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_MII_10] = PHY_INTERFACE_MODE_MII, 50762306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_SERDES] = PHY_INTERFACE_MODE_1000BASEX, 50862306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_1000BASE_X] = PHY_INTERFACE_MODE_1000BASEX, 50962306a36Sopenharmony_ci [MV88E6185_PORT_STS_CMODE_PHY] = PHY_INTERFACE_MODE_SGMII, 51062306a36Sopenharmony_ci}; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 51362306a36Sopenharmony_ci struct phylink_config *config) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci u8 cmode = chip->ports[port].cmode; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (mv88e6xxx_phy_is_internal(chip, port)) { 52062306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); 52162306a36Sopenharmony_ci } else { 52262306a36Sopenharmony_ci if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) && 52362306a36Sopenharmony_ci mv88e6185_phy_interface_modes[cmode]) 52462306a36Sopenharmony_ci __set_bit(mv88e6185_phy_interface_modes[cmode], 52562306a36Sopenharmony_ci config->supported_interfaces); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci config->mac_capabilities |= MAC_1000FD; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 53262306a36Sopenharmony_ci struct phylink_config *config) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci u8 cmode = chip->ports[port].cmode; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) && 53762306a36Sopenharmony_ci mv88e6185_phy_interface_modes[cmode]) 53862306a36Sopenharmony_ci __set_bit(mv88e6185_phy_interface_modes[cmode], 53962306a36Sopenharmony_ci config->supported_interfaces); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 54262306a36Sopenharmony_ci MAC_1000FD; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic const u8 mv88e6xxx_phy_interface_modes[] = { 54662306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_MII_PHY] = PHY_INTERFACE_MODE_REVMII, 54762306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_MII] = PHY_INTERFACE_MODE_MII, 54862306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_GMII] = PHY_INTERFACE_MODE_GMII, 54962306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_RMII_PHY] = PHY_INTERFACE_MODE_REVRMII, 55062306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_RMII] = PHY_INTERFACE_MODE_RMII, 55162306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_100BASEX] = PHY_INTERFACE_MODE_100BASEX, 55262306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_1000BASEX] = PHY_INTERFACE_MODE_1000BASEX, 55362306a36Sopenharmony_ci [MV88E6XXX_PORT_STS_CMODE_SGMII] = PHY_INTERFACE_MODE_SGMII, 55462306a36Sopenharmony_ci /* higher interface modes are not needed here, since ports supporting 55562306a36Sopenharmony_ci * them are writable, and so the supported interfaces are filled in the 55662306a36Sopenharmony_ci * corresponding .phylink_set_interfaces() implementation below 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) && 56362306a36Sopenharmony_ci mv88e6xxx_phy_interface_modes[cmode]) 56462306a36Sopenharmony_ci __set_bit(mv88e6xxx_phy_interface_modes[cmode], supported); 56562306a36Sopenharmony_ci else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII) 56662306a36Sopenharmony_ci phy_interface_set_rgmii(supported); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 57062306a36Sopenharmony_ci struct phylink_config *config) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Translate the default cmode */ 57562306a36Sopenharmony_ci mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void mv88e6351_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 58162306a36Sopenharmony_ci struct phylink_config *config) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* Translate the default cmode */ 58662306a36Sopenharmony_ci mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 58962306a36Sopenharmony_ci MAC_1000FD; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci u16 reg, val; 59562306a36Sopenharmony_ci int err; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, ®); 59862306a36Sopenharmony_ci if (err) 59962306a36Sopenharmony_ci return err; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* If PHY_DETECT is zero, then we are not in auto-media mode */ 60262306a36Sopenharmony_ci if (!(reg & MV88E6XXX_PORT_STS_PHY_DETECT)) 60362306a36Sopenharmony_ci return 0xf; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci val = reg & ~MV88E6XXX_PORT_STS_PHY_DETECT; 60662306a36Sopenharmony_ci err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, val); 60762306a36Sopenharmony_ci if (err) 60862306a36Sopenharmony_ci return err; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, 4, MV88E6XXX_PORT_STS, &val); 61162306a36Sopenharmony_ci if (err) 61262306a36Sopenharmony_ci return err; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* Restore PHY_DETECT value */ 61562306a36Sopenharmony_ci err = mv88e6xxx_port_write(chip, 4, MV88E6XXX_PORT_STS, reg); 61662306a36Sopenharmony_ci if (err) 61762306a36Sopenharmony_ci return err; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return val & MV88E6XXX_PORT_STS_CMODE_MASK; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 62362306a36Sopenharmony_ci struct phylink_config *config) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 62662306a36Sopenharmony_ci int err, cmode; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Translate the default cmode */ 62962306a36Sopenharmony_ci mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 63262306a36Sopenharmony_ci MAC_1000FD; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* Port 4 supports automedia if the serdes is associated with it. */ 63562306a36Sopenharmony_ci if (port == 4) { 63662306a36Sopenharmony_ci err = mv88e6352_g2_scratch_port_has_serdes(chip, port); 63762306a36Sopenharmony_ci if (err < 0) 63862306a36Sopenharmony_ci dev_err(chip->dev, "p%d: failed to read scratch\n", 63962306a36Sopenharmony_ci port); 64062306a36Sopenharmony_ci if (err <= 0) 64162306a36Sopenharmony_ci return; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci cmode = mv88e6352_get_port4_serdes_cmode(chip); 64462306a36Sopenharmony_ci if (cmode < 0) 64562306a36Sopenharmony_ci dev_err(chip->dev, "p%d: failed to read serdes cmode\n", 64662306a36Sopenharmony_ci port); 64762306a36Sopenharmony_ci else 64862306a36Sopenharmony_ci mv88e6xxx_translate_cmode(cmode, supported); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 65362306a36Sopenharmony_ci struct phylink_config *config) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Translate the default cmode */ 65862306a36Sopenharmony_ci mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* No ethtool bits for 200Mbps */ 66162306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 66262306a36Sopenharmony_ci MAC_1000FD; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* The C_Mode field is programmable on port 5 */ 66562306a36Sopenharmony_ci if (port == 5) { 66662306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_SGMII, supported); 66762306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 66862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci config->mac_capabilities |= MAC_2500FD; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 67562306a36Sopenharmony_ci struct phylink_config *config) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* Translate the default cmode */ 68062306a36Sopenharmony_ci mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci /* No ethtool bits for 200Mbps */ 68362306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 68462306a36Sopenharmony_ci MAC_1000FD; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* The C_Mode field is programmable on ports 9 and 10 */ 68762306a36Sopenharmony_ci if (port == 9 || port == 10) { 68862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_SGMII, supported); 68962306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 69062306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci config->mac_capabilities |= MAC_2500FD; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 69762306a36Sopenharmony_ci struct phylink_config *config) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci mv88e6390_phylink_get_caps(chip, port, config); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* For the 6x90X, ports 2-7 can be in automedia mode. 70462306a36Sopenharmony_ci * (Note that 6x90 doesn't support RXAUI nor XAUI). 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci * Port 2 can also support 1000BASE-X in automedia mode if port 9 is 70762306a36Sopenharmony_ci * configured for 1000BASE-X, SGMII or 2500BASE-X. 70862306a36Sopenharmony_ci * Port 3-4 can also support 1000BASE-X in automedia mode if port 9 is 70962306a36Sopenharmony_ci * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X. 71062306a36Sopenharmony_ci * 71162306a36Sopenharmony_ci * Port 5 can also support 1000BASE-X in automedia mode if port 10 is 71262306a36Sopenharmony_ci * configured for 1000BASE-X, SGMII or 2500BASE-X. 71362306a36Sopenharmony_ci * Port 6-7 can also support 1000BASE-X in automedia mode if port 10 is 71462306a36Sopenharmony_ci * configured for RXAUI, 1000BASE-X, SGMII or 2500BASE-X. 71562306a36Sopenharmony_ci * 71662306a36Sopenharmony_ci * For now, be permissive (as the old code was) and allow 1000BASE-X 71762306a36Sopenharmony_ci * on ports 2..7. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci if (port >= 2 && port <= 7) 72062306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* The C_Mode field can also be programmed for 10G speeds */ 72362306a36Sopenharmony_ci if (port == 9 || port == 10) { 72462306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_XAUI, supported); 72562306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RXAUI, supported); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci config->mac_capabilities |= MAC_10000FD; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, 73262306a36Sopenharmony_ci struct phylink_config *config) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci unsigned long *supported = config->supported_interfaces; 73562306a36Sopenharmony_ci bool is_6191x = 73662306a36Sopenharmony_ci chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X; 73762306a36Sopenharmony_ci bool is_6361 = 73862306a36Sopenharmony_ci chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | 74362306a36Sopenharmony_ci MAC_1000FD; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* The C_Mode field can be programmed for ports 0, 9 and 10 */ 74662306a36Sopenharmony_ci if (port == 0 || port == 9 || port == 10) { 74762306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_SGMII, supported); 74862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_1000BASEX, supported); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* 6191X supports >1G modes only on port 10 */ 75162306a36Sopenharmony_ci if (!is_6191x || port == 10) { 75262306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); 75362306a36Sopenharmony_ci config->mac_capabilities |= MAC_2500FD; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* 6361 only supports up to 2500BaseX */ 75662306a36Sopenharmony_ci if (!is_6361) { 75762306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); 75862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); 75962306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); 76062306a36Sopenharmony_ci config->mac_capabilities |= MAC_5000FD | 76162306a36Sopenharmony_ci MAC_10000FD; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (port == 0) { 76762306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RMII, supported); 76862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RGMII, supported); 76962306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RGMII_ID, supported); 77062306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, supported); 77162306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RGMII_TXID, supported); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, 77662306a36Sopenharmony_ci struct phylink_config *config) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 78162306a36Sopenharmony_ci chip->info->ops->phylink_get_caps(chip, port, config); 78262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (mv88e6xxx_phy_is_internal(chip, port)) { 78562306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_INTERNAL, 78662306a36Sopenharmony_ci config->supported_interfaces); 78762306a36Sopenharmony_ci /* Internal ports with no phy-mode need GMII for PHYLIB */ 78862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_GMII, 78962306a36Sopenharmony_ci config->supported_interfaces); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic struct phylink_pcs *mv88e6xxx_mac_select_pcs(struct dsa_switch *ds, 79462306a36Sopenharmony_ci int port, 79562306a36Sopenharmony_ci phy_interface_t interface) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 79862306a36Sopenharmony_ci struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (chip->info->ops->pcs_ops) 80162306a36Sopenharmony_ci pcs = chip->info->ops->pcs_ops->pcs_select(chip, port, 80262306a36Sopenharmony_ci interface); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return pcs; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port, 80862306a36Sopenharmony_ci unsigned int mode, phy_interface_t interface) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 81162306a36Sopenharmony_ci int err = 0; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* In inband mode, the link may come up at any time while the link 81462306a36Sopenharmony_ci * is not forced down. Force the link down while we reconfigure the 81562306a36Sopenharmony_ci * interface mode. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci if (mode == MLO_AN_INBAND && 81862306a36Sopenharmony_ci chip->ports[port].interface != interface && 81962306a36Sopenharmony_ci chip->info->ops->port_set_link) { 82062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 82162306a36Sopenharmony_ci err = chip->info->ops->port_set_link(chip, port, 82262306a36Sopenharmony_ci LINK_FORCED_DOWN); 82362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return err; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, 83062306a36Sopenharmony_ci unsigned int mode, 83162306a36Sopenharmony_ci const struct phylink_link_state *state) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 83462306a36Sopenharmony_ci int err = 0; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(chip, port)) { 83962306a36Sopenharmony_ci err = mv88e6xxx_port_config_interface(chip, port, 84062306a36Sopenharmony_ci state->interface); 84162306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 84262306a36Sopenharmony_ci goto err_unlock; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cierr_unlock: 84662306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 84962306a36Sopenharmony_ci dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port, 85362306a36Sopenharmony_ci unsigned int mode, phy_interface_t interface) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 85662306a36Sopenharmony_ci int err = 0; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci /* Undo the forced down state above after completing configuration 85962306a36Sopenharmony_ci * irrespective of its state on entry, which allows the link to come 86062306a36Sopenharmony_ci * up in the in-band case where there is no separate SERDES. Also 86162306a36Sopenharmony_ci * ensure that the link can come up if the PPU is in use and we are 86262306a36Sopenharmony_ci * in PHY mode (we treat the PPU as an effective in-band mechanism.) 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (chip->info->ops->port_set_link && 86762306a36Sopenharmony_ci ((mode == MLO_AN_INBAND && 86862306a36Sopenharmony_ci chip->ports[port].interface != interface) || 86962306a36Sopenharmony_ci (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port)))) 87062306a36Sopenharmony_ci err = chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci chip->ports[port].interface = interface; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return err; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, 88062306a36Sopenharmony_ci unsigned int mode, 88162306a36Sopenharmony_ci phy_interface_t interface) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 88462306a36Sopenharmony_ci const struct mv88e6xxx_ops *ops; 88562306a36Sopenharmony_ci int err = 0; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci ops = chip->info->ops; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 89062306a36Sopenharmony_ci /* Force the link down if we know the port may not be automatically 89162306a36Sopenharmony_ci * updated by the switch or if we are using fixed-link mode. 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_ci if ((!mv88e6xxx_port_ppu_updates(chip, port) || 89462306a36Sopenharmony_ci mode == MLO_AN_FIXED) && ops->port_sync_link) 89562306a36Sopenharmony_ci err = ops->port_sync_link(chip, port, mode, false); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (!err && ops->port_set_speed_duplex) 89862306a36Sopenharmony_ci err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED, 89962306a36Sopenharmony_ci DUPLEX_UNFORCED); 90062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (err) 90362306a36Sopenharmony_ci dev_err(chip->dev, 90462306a36Sopenharmony_ci "p%d: failed to force MAC link down\n", port); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, 90862306a36Sopenharmony_ci unsigned int mode, phy_interface_t interface, 90962306a36Sopenharmony_ci struct phy_device *phydev, 91062306a36Sopenharmony_ci int speed, int duplex, 91162306a36Sopenharmony_ci bool tx_pause, bool rx_pause) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 91462306a36Sopenharmony_ci const struct mv88e6xxx_ops *ops; 91562306a36Sopenharmony_ci int err = 0; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ops = chip->info->ops; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 92062306a36Sopenharmony_ci /* Configure and force the link up if we know that the port may not 92162306a36Sopenharmony_ci * automatically updated by the switch or if we are using fixed-link 92262306a36Sopenharmony_ci * mode. 92362306a36Sopenharmony_ci */ 92462306a36Sopenharmony_ci if (!mv88e6xxx_port_ppu_updates(chip, port) || 92562306a36Sopenharmony_ci mode == MLO_AN_FIXED) { 92662306a36Sopenharmony_ci if (ops->port_set_speed_duplex) { 92762306a36Sopenharmony_ci err = ops->port_set_speed_duplex(chip, port, 92862306a36Sopenharmony_ci speed, duplex); 92962306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 93062306a36Sopenharmony_ci goto error; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (ops->port_sync_link) 93462306a36Sopenharmony_ci err = ops->port_sync_link(chip, port, mode, true); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_cierror: 93762306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 94062306a36Sopenharmony_ci dev_err(ds->dev, 94162306a36Sopenharmony_ci "p%d: failed to configure MAC link up\n", port); 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci if (!chip->info->ops->stats_snapshot) 94762306a36Sopenharmony_ci return -EOPNOTSUPP; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci return chip->info->ops->stats_snapshot(chip, port); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { 95362306a36Sopenharmony_ci { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, }, 95462306a36Sopenharmony_ci { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, }, 95562306a36Sopenharmony_ci { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, }, 95662306a36Sopenharmony_ci { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, }, 95762306a36Sopenharmony_ci { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, }, 95862306a36Sopenharmony_ci { "in_pause", 4, 0x16, STATS_TYPE_BANK0, }, 95962306a36Sopenharmony_ci { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, }, 96062306a36Sopenharmony_ci { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, }, 96162306a36Sopenharmony_ci { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, }, 96262306a36Sopenharmony_ci { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, }, 96362306a36Sopenharmony_ci { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, }, 96462306a36Sopenharmony_ci { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, }, 96562306a36Sopenharmony_ci { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, }, 96662306a36Sopenharmony_ci { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, }, 96762306a36Sopenharmony_ci { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, }, 96862306a36Sopenharmony_ci { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, }, 96962306a36Sopenharmony_ci { "out_pause", 4, 0x15, STATS_TYPE_BANK0, }, 97062306a36Sopenharmony_ci { "excessive", 4, 0x11, STATS_TYPE_BANK0, }, 97162306a36Sopenharmony_ci { "collisions", 4, 0x1e, STATS_TYPE_BANK0, }, 97262306a36Sopenharmony_ci { "deferred", 4, 0x05, STATS_TYPE_BANK0, }, 97362306a36Sopenharmony_ci { "single", 4, 0x14, STATS_TYPE_BANK0, }, 97462306a36Sopenharmony_ci { "multiple", 4, 0x17, STATS_TYPE_BANK0, }, 97562306a36Sopenharmony_ci { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, }, 97662306a36Sopenharmony_ci { "late", 4, 0x1f, STATS_TYPE_BANK0, }, 97762306a36Sopenharmony_ci { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, }, 97862306a36Sopenharmony_ci { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, }, 97962306a36Sopenharmony_ci { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, }, 98062306a36Sopenharmony_ci { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, }, 98162306a36Sopenharmony_ci { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, }, 98262306a36Sopenharmony_ci { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, }, 98362306a36Sopenharmony_ci { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, }, 98462306a36Sopenharmony_ci { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, }, 98562306a36Sopenharmony_ci { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, }, 98662306a36Sopenharmony_ci { "in_discards", 4, 0x00, STATS_TYPE_BANK1, }, 98762306a36Sopenharmony_ci { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, }, 98862306a36Sopenharmony_ci { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, }, 98962306a36Sopenharmony_ci { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, }, 99062306a36Sopenharmony_ci { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, }, 99162306a36Sopenharmony_ci { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, }, 99262306a36Sopenharmony_ci { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, }, 99362306a36Sopenharmony_ci { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, }, 99462306a36Sopenharmony_ci { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, }, 99562306a36Sopenharmony_ci { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, }, 99662306a36Sopenharmony_ci { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, }, 99762306a36Sopenharmony_ci { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, }, 99862306a36Sopenharmony_ci { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, }, 99962306a36Sopenharmony_ci { "in_management", 4, 0x0f, STATS_TYPE_BANK1, }, 100062306a36Sopenharmony_ci { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, }, 100162306a36Sopenharmony_ci { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, }, 100262306a36Sopenharmony_ci { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, }, 100362306a36Sopenharmony_ci { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, }, 100462306a36Sopenharmony_ci { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, }, 100562306a36Sopenharmony_ci { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, }, 100662306a36Sopenharmony_ci { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, }, 100762306a36Sopenharmony_ci { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, }, 100862306a36Sopenharmony_ci { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, }, 100962306a36Sopenharmony_ci { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, }, 101062306a36Sopenharmony_ci { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, }, 101162306a36Sopenharmony_ci { "out_management", 4, 0x1f, STATS_TYPE_BANK1, }, 101262306a36Sopenharmony_ci}; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, 101562306a36Sopenharmony_ci struct mv88e6xxx_hw_stat *s, 101662306a36Sopenharmony_ci int port, u16 bank1_select, 101762306a36Sopenharmony_ci u16 histogram) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci u32 low; 102062306a36Sopenharmony_ci u32 high = 0; 102162306a36Sopenharmony_ci u16 reg = 0; 102262306a36Sopenharmony_ci int err; 102362306a36Sopenharmony_ci u64 value; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci switch (s->type) { 102662306a36Sopenharmony_ci case STATS_TYPE_PORT: 102762306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, s->reg, ®); 102862306a36Sopenharmony_ci if (err) 102962306a36Sopenharmony_ci return U64_MAX; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci low = reg; 103262306a36Sopenharmony_ci if (s->size == 4) { 103362306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); 103462306a36Sopenharmony_ci if (err) 103562306a36Sopenharmony_ci return U64_MAX; 103662306a36Sopenharmony_ci low |= ((u32)reg) << 16; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci break; 103962306a36Sopenharmony_ci case STATS_TYPE_BANK1: 104062306a36Sopenharmony_ci reg = bank1_select; 104162306a36Sopenharmony_ci fallthrough; 104262306a36Sopenharmony_ci case STATS_TYPE_BANK0: 104362306a36Sopenharmony_ci reg |= s->reg | histogram; 104462306a36Sopenharmony_ci mv88e6xxx_g1_stats_read(chip, reg, &low); 104562306a36Sopenharmony_ci if (s->size == 8) 104662306a36Sopenharmony_ci mv88e6xxx_g1_stats_read(chip, reg + 1, &high); 104762306a36Sopenharmony_ci break; 104862306a36Sopenharmony_ci default: 104962306a36Sopenharmony_ci return U64_MAX; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci value = (((u64)high) << 32) | low; 105262306a36Sopenharmony_ci return value; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, 105662306a36Sopenharmony_ci uint8_t *data, int types) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct mv88e6xxx_hw_stat *stat; 105962306a36Sopenharmony_ci int i, j; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 106262306a36Sopenharmony_ci stat = &mv88e6xxx_hw_stats[i]; 106362306a36Sopenharmony_ci if (stat->type & types) { 106462306a36Sopenharmony_ci memcpy(data + j * ETH_GSTRING_LEN, stat->string, 106562306a36Sopenharmony_ci ETH_GSTRING_LEN); 106662306a36Sopenharmony_ci j++; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci return j; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, 107462306a36Sopenharmony_ci uint8_t *data) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci return mv88e6xxx_stats_get_strings(chip, data, 107762306a36Sopenharmony_ci STATS_TYPE_BANK0 | STATS_TYPE_PORT); 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, 108162306a36Sopenharmony_ci uint8_t *data) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, 108762306a36Sopenharmony_ci uint8_t *data) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci return mv88e6xxx_stats_get_strings(chip, data, 109062306a36Sopenharmony_ci STATS_TYPE_BANK0 | STATS_TYPE_BANK1); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { 109462306a36Sopenharmony_ci "atu_member_violation", 109562306a36Sopenharmony_ci "atu_miss_violation", 109662306a36Sopenharmony_ci "atu_full_violation", 109762306a36Sopenharmony_ci "vtu_member_violation", 109862306a36Sopenharmony_ci "vtu_miss_violation", 109962306a36Sopenharmony_ci}; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cistatic void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci unsigned int i; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) 110662306a36Sopenharmony_ci strscpy(data + i * ETH_GSTRING_LEN, 110762306a36Sopenharmony_ci mv88e6xxx_atu_vtu_stats_strings[i], 110862306a36Sopenharmony_ci ETH_GSTRING_LEN); 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, 111262306a36Sopenharmony_ci u32 stringset, uint8_t *data) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 111562306a36Sopenharmony_ci int count = 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (stringset != ETH_SS_STATS) 111862306a36Sopenharmony_ci return; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (chip->info->ops->stats_get_strings) 112362306a36Sopenharmony_ci count = chip->info->ops->stats_get_strings(chip, data); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (chip->info->ops->serdes_get_strings) { 112662306a36Sopenharmony_ci data += count * ETH_GSTRING_LEN; 112762306a36Sopenharmony_ci count = chip->info->ops->serdes_get_strings(chip, port, data); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci data += count * ETH_GSTRING_LEN; 113162306a36Sopenharmony_ci mv88e6xxx_atu_vtu_get_strings(data); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, 113762306a36Sopenharmony_ci int types) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct mv88e6xxx_hw_stat *stat; 114062306a36Sopenharmony_ci int i, j; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 114362306a36Sopenharmony_ci stat = &mv88e6xxx_hw_stats[i]; 114462306a36Sopenharmony_ci if (stat->type & types) 114562306a36Sopenharmony_ci j++; 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci return j; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 115362306a36Sopenharmony_ci STATS_TYPE_PORT); 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0); 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 | 116462306a36Sopenharmony_ci STATS_TYPE_BANK1); 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_cistatic int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 117062306a36Sopenharmony_ci int serdes_count = 0; 117162306a36Sopenharmony_ci int count = 0; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (sset != ETH_SS_STATS) 117462306a36Sopenharmony_ci return 0; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 117762306a36Sopenharmony_ci if (chip->info->ops->stats_get_sset_count) 117862306a36Sopenharmony_ci count = chip->info->ops->stats_get_sset_count(chip); 117962306a36Sopenharmony_ci if (count < 0) 118062306a36Sopenharmony_ci goto out; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (chip->info->ops->serdes_get_sset_count) 118362306a36Sopenharmony_ci serdes_count = chip->info->ops->serdes_get_sset_count(chip, 118462306a36Sopenharmony_ci port); 118562306a36Sopenharmony_ci if (serdes_count < 0) { 118662306a36Sopenharmony_ci count = serdes_count; 118762306a36Sopenharmony_ci goto out; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci count += serdes_count; 119062306a36Sopenharmony_ci count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ciout: 119362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci return count; 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 119962306a36Sopenharmony_ci uint64_t *data, int types, 120062306a36Sopenharmony_ci u16 bank1_select, u16 histogram) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct mv88e6xxx_hw_stat *stat; 120362306a36Sopenharmony_ci int i, j; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { 120662306a36Sopenharmony_ci stat = &mv88e6xxx_hw_stats[i]; 120762306a36Sopenharmony_ci if (stat->type & types) { 120862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 120962306a36Sopenharmony_ci data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 121062306a36Sopenharmony_ci bank1_select, 121162306a36Sopenharmony_ci histogram); 121262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci j++; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci return j; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 122162306a36Sopenharmony_ci uint64_t *data) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci return mv88e6xxx_stats_get_stats(chip, port, data, 122462306a36Sopenharmony_ci STATS_TYPE_BANK0 | STATS_TYPE_PORT, 122562306a36Sopenharmony_ci 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 122962306a36Sopenharmony_ci uint64_t *data) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0, 123262306a36Sopenharmony_ci 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 123662306a36Sopenharmony_ci uint64_t *data) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci return mv88e6xxx_stats_get_stats(chip, port, data, 123962306a36Sopenharmony_ci STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 124062306a36Sopenharmony_ci MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, 124162306a36Sopenharmony_ci MV88E6XXX_G1_STATS_OP_HIST_RX_TX); 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 124562306a36Sopenharmony_ci uint64_t *data) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci return mv88e6xxx_stats_get_stats(chip, port, data, 124862306a36Sopenharmony_ci STATS_TYPE_BANK0 | STATS_TYPE_BANK1, 124962306a36Sopenharmony_ci MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, 125062306a36Sopenharmony_ci 0); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, 125462306a36Sopenharmony_ci uint64_t *data) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci *data++ = chip->ports[port].atu_member_violation; 125762306a36Sopenharmony_ci *data++ = chip->ports[port].atu_miss_violation; 125862306a36Sopenharmony_ci *data++ = chip->ports[port].atu_full_violation; 125962306a36Sopenharmony_ci *data++ = chip->ports[port].vtu_member_violation; 126062306a36Sopenharmony_ci *data++ = chip->ports[port].vtu_miss_violation; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, 126462306a36Sopenharmony_ci uint64_t *data) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci int count = 0; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci if (chip->info->ops->stats_get_stats) 126962306a36Sopenharmony_ci count = chip->info->ops->stats_get_stats(chip, port, data); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 127262306a36Sopenharmony_ci if (chip->info->ops->serdes_get_stats) { 127362306a36Sopenharmony_ci data += count; 127462306a36Sopenharmony_ci count = chip->info->ops->serdes_get_stats(chip, port, data); 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci data += count; 127762306a36Sopenharmony_ci mv88e6xxx_atu_vtu_get_stats(chip, port, data); 127862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, 128262306a36Sopenharmony_ci uint64_t *data) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 128562306a36Sopenharmony_ci int ret; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci ret = mv88e6xxx_stats_snapshot(chip, port); 129062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (ret < 0) 129362306a36Sopenharmony_ci return; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci mv88e6xxx_get_stats(chip, port, data); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 130262306a36Sopenharmony_ci int len; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci len = 32 * sizeof(u16); 130562306a36Sopenharmony_ci if (chip->info->ops->serdes_get_regs_len) 130662306a36Sopenharmony_ci len += chip->info->ops->serdes_get_regs_len(chip, port); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return len; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, 131262306a36Sopenharmony_ci struct ethtool_regs *regs, void *_p) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 131562306a36Sopenharmony_ci int err; 131662306a36Sopenharmony_ci u16 reg; 131762306a36Sopenharmony_ci u16 *p = _p; 131862306a36Sopenharmony_ci int i; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci regs->version = chip->info->prod_num; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci memset(p, 0xff, 32 * sizeof(u16)); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, i, ®); 132962306a36Sopenharmony_ci if (!err) 133062306a36Sopenharmony_ci p[i] = reg; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (chip->info->ops->serdes_get_regs) 133462306a36Sopenharmony_ci chip->info->ops->serdes_get_regs(chip, port, &p[i]); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_cistatic int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, 134062306a36Sopenharmony_ci struct ethtool_eee *e) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci /* Nothing to do on the port's MAC */ 134362306a36Sopenharmony_ci return 0; 134462306a36Sopenharmony_ci} 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_cistatic int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, 134762306a36Sopenharmony_ci struct ethtool_eee *e) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci /* Nothing to do on the port's MAC */ 135062306a36Sopenharmony_ci return 0; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci/* Mask of the local ports allowed to receive frames from a given fabric port */ 135462306a36Sopenharmony_cistatic u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct dsa_switch *ds = chip->ds; 135762306a36Sopenharmony_ci struct dsa_switch_tree *dst = ds->dst; 135862306a36Sopenharmony_ci struct dsa_port *dp, *other_dp; 135962306a36Sopenharmony_ci bool found = false; 136062306a36Sopenharmony_ci u16 pvlan; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* dev is a physical switch */ 136362306a36Sopenharmony_ci if (dev <= dst->last_switch) { 136462306a36Sopenharmony_ci list_for_each_entry(dp, &dst->ports, list) { 136562306a36Sopenharmony_ci if (dp->ds->index == dev && dp->index == port) { 136662306a36Sopenharmony_ci /* dp might be a DSA link or a user port, so it 136762306a36Sopenharmony_ci * might or might not have a bridge. 136862306a36Sopenharmony_ci * Use the "found" variable for both cases. 136962306a36Sopenharmony_ci */ 137062306a36Sopenharmony_ci found = true; 137162306a36Sopenharmony_ci break; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci /* dev is a virtual bridge */ 137562306a36Sopenharmony_ci } else { 137662306a36Sopenharmony_ci list_for_each_entry(dp, &dst->ports, list) { 137762306a36Sopenharmony_ci unsigned int bridge_num = dsa_port_bridge_num_get(dp); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (!bridge_num) 138062306a36Sopenharmony_ci continue; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (bridge_num + dst->last_switch != dev) 138362306a36Sopenharmony_ci continue; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci found = true; 138662306a36Sopenharmony_ci break; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* Prevent frames from unknown switch or virtual bridge */ 139162306a36Sopenharmony_ci if (!found) 139262306a36Sopenharmony_ci return 0; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci /* Frames from DSA links and CPU ports can egress any local port */ 139562306a36Sopenharmony_ci if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) 139662306a36Sopenharmony_ci return mv88e6xxx_port_mask(chip); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci pvlan = 0; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* Frames from standalone user ports can only egress on the 140162306a36Sopenharmony_ci * upstream port. 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_ci if (!dsa_port_bridge_dev_get(dp)) 140462306a36Sopenharmony_ci return BIT(dsa_switch_upstream_port(ds)); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* Frames from bridged user ports can egress any local DSA 140762306a36Sopenharmony_ci * links and CPU ports, as well as any local member of their 140862306a36Sopenharmony_ci * bridge group. 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci dsa_switch_for_each_port(other_dp, ds) 141162306a36Sopenharmony_ci if (other_dp->type == DSA_PORT_TYPE_CPU || 141262306a36Sopenharmony_ci other_dp->type == DSA_PORT_TYPE_DSA || 141362306a36Sopenharmony_ci dsa_port_bridge_same(dp, other_dp)) 141462306a36Sopenharmony_ci pvlan |= BIT(other_dp->index); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci return pvlan; 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_map(struct mv88e6xxx_chip *chip, int port) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci u16 output_ports = mv88e6xxx_port_vlan(chip, chip->ds->index, port); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* prevent frames from going back out of the port they came in on */ 142462306a36Sopenharmony_ci output_ports &= ~BIT(port); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci return mv88e6xxx_port_set_vlan_map(chip, port, output_ports); 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, 143062306a36Sopenharmony_ci u8 state) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 143362306a36Sopenharmony_ci int err; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 143662306a36Sopenharmony_ci err = mv88e6xxx_port_set_state(chip, port, state); 143762306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (err) 144062306a36Sopenharmony_ci dev_err(ds->dev, "p%d: failed to update state\n", port); 144162306a36Sopenharmony_ci} 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_cistatic int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) 144462306a36Sopenharmony_ci{ 144562306a36Sopenharmony_ci int err; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (chip->info->ops->ieee_pri_map) { 144862306a36Sopenharmony_ci err = chip->info->ops->ieee_pri_map(chip); 144962306a36Sopenharmony_ci if (err) 145062306a36Sopenharmony_ci return err; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (chip->info->ops->ip_pri_map) { 145462306a36Sopenharmony_ci err = chip->info->ops->ip_pri_map(chip); 145562306a36Sopenharmony_ci if (err) 145662306a36Sopenharmony_ci return err; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci return 0; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci struct dsa_switch *ds = chip->ds; 146562306a36Sopenharmony_ci int target, port; 146662306a36Sopenharmony_ci int err; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (!chip->info->global2_addr) 146962306a36Sopenharmony_ci return 0; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* Initialize the routing port to the 32 possible target devices */ 147262306a36Sopenharmony_ci for (target = 0; target < 32; target++) { 147362306a36Sopenharmony_ci port = dsa_routing_port(ds, target); 147462306a36Sopenharmony_ci if (port == ds->num_ports) 147562306a36Sopenharmony_ci port = 0x1f; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci err = mv88e6xxx_g2_device_mapping_write(chip, target, port); 147862306a36Sopenharmony_ci if (err) 147962306a36Sopenharmony_ci return err; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci if (chip->info->ops->set_cascade_port) { 148362306a36Sopenharmony_ci port = MV88E6XXX_CASCADE_PORT_MULTIPLE; 148462306a36Sopenharmony_ci err = chip->info->ops->set_cascade_port(chip, port); 148562306a36Sopenharmony_ci if (err) 148662306a36Sopenharmony_ci return err; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci err = mv88e6xxx_g1_set_device_number(chip, chip->ds->index); 149062306a36Sopenharmony_ci if (err) 149162306a36Sopenharmony_ci return err; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci return 0; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int mv88e6xxx_trunk_setup(struct mv88e6xxx_chip *chip) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci /* Clear all trunk masks and mapping */ 149962306a36Sopenharmony_ci if (chip->info->global2_addr) 150062306a36Sopenharmony_ci return mv88e6xxx_g2_trunk_clear(chip); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci return 0; 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cistatic int mv88e6xxx_rmu_setup(struct mv88e6xxx_chip *chip) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci if (chip->info->ops->rmu_disable) 150862306a36Sopenharmony_ci return chip->info->ops->rmu_disable(chip); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic int mv88e6xxx_pot_setup(struct mv88e6xxx_chip *chip) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci if (chip->info->ops->pot_clear) 151662306a36Sopenharmony_ci return chip->info->ops->pot_clear(chip); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci return 0; 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cistatic int mv88e6xxx_rsvd2cpu_setup(struct mv88e6xxx_chip *chip) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci if (chip->info->ops->mgmt_rsvd2cpu) 152462306a36Sopenharmony_ci return chip->info->ops->mgmt_rsvd2cpu(chip); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci return 0; 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci int err; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_flush(chip, 0, true); 153462306a36Sopenharmony_ci if (err) 153562306a36Sopenharmony_ci return err; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* The chips that have a "learn2all" bit in Global1, ATU 153862306a36Sopenharmony_ci * Control are precisely those whose port registers have a 153962306a36Sopenharmony_ci * Message Port bit in Port Control 1 and hence implement 154062306a36Sopenharmony_ci * ->port_setup_message_port. 154162306a36Sopenharmony_ci */ 154262306a36Sopenharmony_ci if (chip->info->ops->port_setup_message_port) { 154362306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_set_learn2all(chip, true); 154462306a36Sopenharmony_ci if (err) 154562306a36Sopenharmony_ci return err; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci return mv88e6xxx_g1_atu_set_age_time(chip, 300000); 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci int port; 155462306a36Sopenharmony_ci int err; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (!chip->info->ops->irl_init_all) 155762306a36Sopenharmony_ci return 0; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 156062306a36Sopenharmony_ci /* Disable ingress rate limiting by resetting all per port 156162306a36Sopenharmony_ci * ingress rate limit resources to their initial state. 156262306a36Sopenharmony_ci */ 156362306a36Sopenharmony_ci err = chip->info->ops->irl_init_all(chip, port); 156462306a36Sopenharmony_ci if (err) 156562306a36Sopenharmony_ci return err; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return 0; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic int mv88e6xxx_mac_setup(struct mv88e6xxx_chip *chip) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci if (chip->info->ops->set_switch_mac) { 157462306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci eth_random_addr(addr); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci return chip->info->ops->set_switch_mac(chip, addr); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci return 0; 158262306a36Sopenharmony_ci} 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_cistatic int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) 158562306a36Sopenharmony_ci{ 158662306a36Sopenharmony_ci struct dsa_switch_tree *dst = chip->ds->dst; 158762306a36Sopenharmony_ci struct dsa_switch *ds; 158862306a36Sopenharmony_ci struct dsa_port *dp; 158962306a36Sopenharmony_ci u16 pvlan = 0; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci if (!mv88e6xxx_has_pvt(chip)) 159262306a36Sopenharmony_ci return 0; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci /* Skip the local source device, which uses in-chip port VLAN */ 159562306a36Sopenharmony_ci if (dev != chip->ds->index) { 159662306a36Sopenharmony_ci pvlan = mv88e6xxx_port_vlan(chip, dev, port); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci ds = dsa_switch_find(dst->index, dev); 159962306a36Sopenharmony_ci dp = ds ? dsa_to_port(ds, port) : NULL; 160062306a36Sopenharmony_ci if (dp && dp->lag) { 160162306a36Sopenharmony_ci /* As the PVT is used to limit flooding of 160262306a36Sopenharmony_ci * FORWARD frames, which use the LAG ID as the 160362306a36Sopenharmony_ci * source port, we must translate dev/port to 160462306a36Sopenharmony_ci * the special "LAG device" in the PVT, using 160562306a36Sopenharmony_ci * the LAG ID (one-based) as the port number 160662306a36Sopenharmony_ci * (zero-based). 160762306a36Sopenharmony_ci */ 160862306a36Sopenharmony_ci dev = MV88E6XXX_G2_PVT_ADDR_DEV_TRUNK; 160962306a36Sopenharmony_ci port = dsa_port_lag_id_get(dp) - 1; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return mv88e6xxx_g2_pvt_write(chip, dev, port, pvlan); 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic int mv88e6xxx_pvt_setup(struct mv88e6xxx_chip *chip) 161762306a36Sopenharmony_ci{ 161862306a36Sopenharmony_ci int dev, port; 161962306a36Sopenharmony_ci int err; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (!mv88e6xxx_has_pvt(chip)) 162262306a36Sopenharmony_ci return 0; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* Clear 5 Bit Port for usage with Marvell Link Street devices: 162562306a36Sopenharmony_ci * use 4 bits for the Src_Port/Src_Trunk and 5 bits for the Src_Dev. 162662306a36Sopenharmony_ci */ 162762306a36Sopenharmony_ci err = mv88e6xxx_g2_misc_4_bit_port(chip); 162862306a36Sopenharmony_ci if (err) 162962306a36Sopenharmony_ci return err; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; ++dev) { 163262306a36Sopenharmony_ci for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; ++port) { 163362306a36Sopenharmony_ci err = mv88e6xxx_pvt_map(chip, dev, port); 163462306a36Sopenharmony_ci if (err) 163562306a36Sopenharmony_ci return err; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci return 0; 164062306a36Sopenharmony_ci} 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_cistatic int mv88e6xxx_port_fast_age_fid(struct mv88e6xxx_chip *chip, int port, 164362306a36Sopenharmony_ci u16 fid) 164462306a36Sopenharmony_ci{ 164562306a36Sopenharmony_ci if (dsa_to_port(chip->ds, port)->lag) 164662306a36Sopenharmony_ci /* Hardware is incapable of fast-aging a LAG through a 164762306a36Sopenharmony_ci * regular ATU move operation. Until we have something 164862306a36Sopenharmony_ci * more fancy in place this is a no-op. 164962306a36Sopenharmony_ci */ 165062306a36Sopenharmony_ci return -EOPNOTSUPP; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci return mv88e6xxx_g1_atu_remove(chip, fid, port, false); 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_cistatic void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 165862306a36Sopenharmony_ci int err; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 166162306a36Sopenharmony_ci err = mv88e6xxx_port_fast_age_fid(chip, port, 0); 166262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (err) 166562306a36Sopenharmony_ci dev_err(chip->ds->dev, "p%d: failed to flush ATU: %d\n", 166662306a36Sopenharmony_ci port, err); 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cistatic int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci if (!mv88e6xxx_max_vid(chip)) 167262306a36Sopenharmony_ci return 0; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci return mv88e6xxx_g1_vtu_flush(chip); 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_cistatic int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, 167862306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry *entry) 167962306a36Sopenharmony_ci{ 168062306a36Sopenharmony_ci int err; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (!chip->info->ops->vtu_getnext) 168362306a36Sopenharmony_ci return -EOPNOTSUPP; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci entry->vid = vid ? vid - 1 : mv88e6xxx_max_vid(chip); 168662306a36Sopenharmony_ci entry->valid = false; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci err = chip->info->ops->vtu_getnext(chip, entry); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci if (entry->vid != vid) 169162306a36Sopenharmony_ci entry->valid = false; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci return err; 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ciint mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip, 169762306a36Sopenharmony_ci int (*cb)(struct mv88e6xxx_chip *chip, 169862306a36Sopenharmony_ci const struct mv88e6xxx_vtu_entry *entry, 169962306a36Sopenharmony_ci void *priv), 170062306a36Sopenharmony_ci void *priv) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry entry = { 170362306a36Sopenharmony_ci .vid = mv88e6xxx_max_vid(chip), 170462306a36Sopenharmony_ci .valid = false, 170562306a36Sopenharmony_ci }; 170662306a36Sopenharmony_ci int err; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci if (!chip->info->ops->vtu_getnext) 170962306a36Sopenharmony_ci return -EOPNOTSUPP; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci do { 171262306a36Sopenharmony_ci err = chip->info->ops->vtu_getnext(chip, &entry); 171362306a36Sopenharmony_ci if (err) 171462306a36Sopenharmony_ci return err; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci if (!entry.valid) 171762306a36Sopenharmony_ci break; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci err = cb(chip, &entry, priv); 172062306a36Sopenharmony_ci if (err) 172162306a36Sopenharmony_ci return err; 172262306a36Sopenharmony_ci } while (entry.vid < mv88e6xxx_max_vid(chip)); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci return 0; 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, 172862306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry *entry) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci if (!chip->info->ops->vtu_loadpurge) 173162306a36Sopenharmony_ci return -EOPNOTSUPP; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci return chip->info->ops->vtu_loadpurge(chip, entry); 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cistatic int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip, 173762306a36Sopenharmony_ci const struct mv88e6xxx_vtu_entry *entry, 173862306a36Sopenharmony_ci void *_fid_bitmap) 173962306a36Sopenharmony_ci{ 174062306a36Sopenharmony_ci unsigned long *fid_bitmap = _fid_bitmap; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci set_bit(entry->fid, fid_bitmap); 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ciint mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci /* Every FID has an associated VID, so walking the VTU 175162306a36Sopenharmony_ci * will discover the full set of FIDs in use. 175262306a36Sopenharmony_ci */ 175362306a36Sopenharmony_ci return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap); 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 175962306a36Sopenharmony_ci int err; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci err = mv88e6xxx_fid_map(chip, fid_bitmap); 176262306a36Sopenharmony_ci if (err) 176362306a36Sopenharmony_ci return err; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci *fid = find_first_zero_bit(fid_bitmap, MV88E6XXX_N_FID); 176662306a36Sopenharmony_ci if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) 176762306a36Sopenharmony_ci return -ENOSPC; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci /* Clear the database */ 177062306a36Sopenharmony_ci return mv88e6xxx_g1_atu_flush(chip, *fid, true); 177162306a36Sopenharmony_ci} 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_cistatic int mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip, 177462306a36Sopenharmony_ci struct mv88e6xxx_stu_entry *entry) 177562306a36Sopenharmony_ci{ 177662306a36Sopenharmony_ci if (!chip->info->ops->stu_loadpurge) 177762306a36Sopenharmony_ci return -EOPNOTSUPP; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci return chip->info->ops->stu_loadpurge(chip, entry); 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic int mv88e6xxx_stu_setup(struct mv88e6xxx_chip *chip) 178362306a36Sopenharmony_ci{ 178462306a36Sopenharmony_ci struct mv88e6xxx_stu_entry stu = { 178562306a36Sopenharmony_ci .valid = true, 178662306a36Sopenharmony_ci .sid = 0 178762306a36Sopenharmony_ci }; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci if (!mv88e6xxx_has_stu(chip)) 179062306a36Sopenharmony_ci return 0; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci /* Make sure that SID 0 is always valid. This is used by VTU 179362306a36Sopenharmony_ci * entries that do not make use of the STU, e.g. when creating 179462306a36Sopenharmony_ci * a VLAN upper on a port that is also part of a VLAN 179562306a36Sopenharmony_ci * filtering bridge. 179662306a36Sopenharmony_ci */ 179762306a36Sopenharmony_ci return mv88e6xxx_stu_loadpurge(chip, &stu); 179862306a36Sopenharmony_ci} 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_cistatic int mv88e6xxx_sid_get(struct mv88e6xxx_chip *chip, u8 *sid) 180162306a36Sopenharmony_ci{ 180262306a36Sopenharmony_ci DECLARE_BITMAP(busy, MV88E6XXX_N_SID) = { 0 }; 180362306a36Sopenharmony_ci struct mv88e6xxx_mst *mst; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci __set_bit(0, busy); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci list_for_each_entry(mst, &chip->msts, node) 180862306a36Sopenharmony_ci __set_bit(mst->stu.sid, busy); 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci *sid = find_first_zero_bit(busy, MV88E6XXX_N_SID); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci return (*sid >= mv88e6xxx_max_sid(chip)) ? -ENOSPC : 0; 181362306a36Sopenharmony_ci} 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_cistatic int mv88e6xxx_mst_put(struct mv88e6xxx_chip *chip, u8 sid) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci struct mv88e6xxx_mst *mst, *tmp; 181862306a36Sopenharmony_ci int err; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci if (!sid) 182162306a36Sopenharmony_ci return 0; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci list_for_each_entry_safe(mst, tmp, &chip->msts, node) { 182462306a36Sopenharmony_ci if (mst->stu.sid != sid) 182562306a36Sopenharmony_ci continue; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci if (!refcount_dec_and_test(&mst->refcnt)) 182862306a36Sopenharmony_ci return 0; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci mst->stu.valid = false; 183162306a36Sopenharmony_ci err = mv88e6xxx_stu_loadpurge(chip, &mst->stu); 183262306a36Sopenharmony_ci if (err) { 183362306a36Sopenharmony_ci refcount_set(&mst->refcnt, 1); 183462306a36Sopenharmony_ci return err; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci list_del(&mst->node); 183862306a36Sopenharmony_ci kfree(mst); 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci return -ENOENT; 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_cistatic int mv88e6xxx_mst_get(struct mv88e6xxx_chip *chip, struct net_device *br, 184662306a36Sopenharmony_ci u16 msti, u8 *sid) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci struct mv88e6xxx_mst *mst; 184962306a36Sopenharmony_ci int err, i; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci if (!mv88e6xxx_has_stu(chip)) { 185262306a36Sopenharmony_ci err = -EOPNOTSUPP; 185362306a36Sopenharmony_ci goto err; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (!msti) { 185762306a36Sopenharmony_ci *sid = 0; 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci list_for_each_entry(mst, &chip->msts, node) { 186262306a36Sopenharmony_ci if (mst->br == br && mst->msti == msti) { 186362306a36Sopenharmony_ci refcount_inc(&mst->refcnt); 186462306a36Sopenharmony_ci *sid = mst->stu.sid; 186562306a36Sopenharmony_ci return 0; 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci err = mv88e6xxx_sid_get(chip, sid); 187062306a36Sopenharmony_ci if (err) 187162306a36Sopenharmony_ci goto err; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci mst = kzalloc(sizeof(*mst), GFP_KERNEL); 187462306a36Sopenharmony_ci if (!mst) { 187562306a36Sopenharmony_ci err = -ENOMEM; 187662306a36Sopenharmony_ci goto err; 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci INIT_LIST_HEAD(&mst->node); 188062306a36Sopenharmony_ci refcount_set(&mst->refcnt, 1); 188162306a36Sopenharmony_ci mst->br = br; 188262306a36Sopenharmony_ci mst->msti = msti; 188362306a36Sopenharmony_ci mst->stu.valid = true; 188462306a36Sopenharmony_ci mst->stu.sid = *sid; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci /* The bridge starts out all ports in the disabled state. But 188762306a36Sopenharmony_ci * a STU state of disabled means to go by the port-global 188862306a36Sopenharmony_ci * state. So we set all user port's initial state to blocking, 188962306a36Sopenharmony_ci * to match the bridge's behavior. 189062306a36Sopenharmony_ci */ 189162306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 189262306a36Sopenharmony_ci mst->stu.state[i] = dsa_is_user_port(chip->ds, i) ? 189362306a36Sopenharmony_ci MV88E6XXX_PORT_CTL0_STATE_BLOCKING : 189462306a36Sopenharmony_ci MV88E6XXX_PORT_CTL0_STATE_DISABLED; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci err = mv88e6xxx_stu_loadpurge(chip, &mst->stu); 189762306a36Sopenharmony_ci if (err) 189862306a36Sopenharmony_ci goto err_free; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci list_add_tail(&mst->node, &chip->msts); 190162306a36Sopenharmony_ci return 0; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_cierr_free: 190462306a36Sopenharmony_ci kfree(mst); 190562306a36Sopenharmony_cierr: 190662306a36Sopenharmony_ci return err; 190762306a36Sopenharmony_ci} 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_cistatic int mv88e6xxx_port_mst_state_set(struct dsa_switch *ds, int port, 191062306a36Sopenharmony_ci const struct switchdev_mst_state *st) 191162306a36Sopenharmony_ci{ 191262306a36Sopenharmony_ci struct dsa_port *dp = dsa_to_port(ds, port); 191362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 191462306a36Sopenharmony_ci struct mv88e6xxx_mst *mst; 191562306a36Sopenharmony_ci u8 state; 191662306a36Sopenharmony_ci int err; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (!mv88e6xxx_has_stu(chip)) 191962306a36Sopenharmony_ci return -EOPNOTSUPP; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci switch (st->state) { 192262306a36Sopenharmony_ci case BR_STATE_DISABLED: 192362306a36Sopenharmony_ci case BR_STATE_BLOCKING: 192462306a36Sopenharmony_ci case BR_STATE_LISTENING: 192562306a36Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; 192662306a36Sopenharmony_ci break; 192762306a36Sopenharmony_ci case BR_STATE_LEARNING: 192862306a36Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; 192962306a36Sopenharmony_ci break; 193062306a36Sopenharmony_ci case BR_STATE_FORWARDING: 193162306a36Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 193262306a36Sopenharmony_ci break; 193362306a36Sopenharmony_ci default: 193462306a36Sopenharmony_ci return -EINVAL; 193562306a36Sopenharmony_ci } 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci list_for_each_entry(mst, &chip->msts, node) { 193862306a36Sopenharmony_ci if (mst->br == dsa_port_bridge_dev_get(dp) && 193962306a36Sopenharmony_ci mst->msti == st->msti) { 194062306a36Sopenharmony_ci if (mst->stu.state[port] == state) 194162306a36Sopenharmony_ci return 0; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci mst->stu.state[port] = state; 194462306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 194562306a36Sopenharmony_ci err = mv88e6xxx_stu_loadpurge(chip, &mst->stu); 194662306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 194762306a36Sopenharmony_ci return err; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci return -ENOENT; 195262306a36Sopenharmony_ci} 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cistatic int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, 195562306a36Sopenharmony_ci u16 vid) 195662306a36Sopenharmony_ci{ 195762306a36Sopenharmony_ci struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; 195862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 195962306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 196062306a36Sopenharmony_ci int err; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci /* DSA and CPU ports have to be members of multiple vlans */ 196362306a36Sopenharmony_ci if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) 196462306a36Sopenharmony_ci return 0; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci err = mv88e6xxx_vtu_get(chip, vid, &vlan); 196762306a36Sopenharmony_ci if (err) 196862306a36Sopenharmony_ci return err; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (!vlan.valid) 197162306a36Sopenharmony_ci return 0; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci dsa_switch_for_each_user_port(other_dp, ds) { 197462306a36Sopenharmony_ci struct net_device *other_br; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci if (vlan.member[other_dp->index] == 197762306a36Sopenharmony_ci MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 197862306a36Sopenharmony_ci continue; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (dsa_port_bridge_same(dp, other_dp)) 198162306a36Sopenharmony_ci break; /* same bridge, check next VLAN */ 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci other_br = dsa_port_bridge_dev_get(other_dp); 198462306a36Sopenharmony_ci if (!other_br) 198562306a36Sopenharmony_ci continue; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n", 198862306a36Sopenharmony_ci port, vlan.vid, other_dp->index, netdev_name(other_br)); 198962306a36Sopenharmony_ci return -EOPNOTSUPP; 199062306a36Sopenharmony_ci } 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci return 0; 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_cistatic int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port) 199662306a36Sopenharmony_ci{ 199762306a36Sopenharmony_ci struct dsa_port *dp = dsa_to_port(chip->ds, port); 199862306a36Sopenharmony_ci struct net_device *br = dsa_port_bridge_dev_get(dp); 199962306a36Sopenharmony_ci struct mv88e6xxx_port *p = &chip->ports[port]; 200062306a36Sopenharmony_ci u16 pvid = MV88E6XXX_VID_STANDALONE; 200162306a36Sopenharmony_ci bool drop_untagged = false; 200262306a36Sopenharmony_ci int err; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci if (br) { 200562306a36Sopenharmony_ci if (br_vlan_enabled(br)) { 200662306a36Sopenharmony_ci pvid = p->bridge_pvid.vid; 200762306a36Sopenharmony_ci drop_untagged = !p->bridge_pvid.valid; 200862306a36Sopenharmony_ci } else { 200962306a36Sopenharmony_ci pvid = MV88E6XXX_VID_BRIDGED; 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci err = mv88e6xxx_port_set_pvid(chip, port, pvid); 201462306a36Sopenharmony_ci if (err) 201562306a36Sopenharmony_ci return err; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged); 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 202162306a36Sopenharmony_ci bool vlan_filtering, 202262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 202362306a36Sopenharmony_ci{ 202462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 202562306a36Sopenharmony_ci u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : 202662306a36Sopenharmony_ci MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; 202762306a36Sopenharmony_ci int err; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (!mv88e6xxx_max_vid(chip)) 203062306a36Sopenharmony_ci return -EOPNOTSUPP; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); 203562306a36Sopenharmony_ci if (err) 203662306a36Sopenharmony_ci goto unlock; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci err = mv88e6xxx_port_commit_pvid(chip, port); 203962306a36Sopenharmony_ci if (err) 204062306a36Sopenharmony_ci goto unlock; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ciunlock: 204362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci return err; 204662306a36Sopenharmony_ci} 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_cistatic int 204962306a36Sopenharmony_cimv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, 205062306a36Sopenharmony_ci const struct switchdev_obj_port_vlan *vlan) 205162306a36Sopenharmony_ci{ 205262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 205362306a36Sopenharmony_ci int err; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci if (!mv88e6xxx_max_vid(chip)) 205662306a36Sopenharmony_ci return -EOPNOTSUPP; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci /* If the requested port doesn't belong to the same bridge as the VLAN 205962306a36Sopenharmony_ci * members, do not support it (yet) and fallback to software VLAN. 206062306a36Sopenharmony_ci */ 206162306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 206262306a36Sopenharmony_ci err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid); 206362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci return err; 206662306a36Sopenharmony_ci} 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_cistatic int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, 206962306a36Sopenharmony_ci const unsigned char *addr, u16 vid, 207062306a36Sopenharmony_ci u8 state) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci struct mv88e6xxx_atu_entry entry; 207362306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 207462306a36Sopenharmony_ci u16 fid; 207562306a36Sopenharmony_ci int err; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci /* Ports have two private address databases: one for when the port is 207862306a36Sopenharmony_ci * standalone and one for when the port is under a bridge and the 207962306a36Sopenharmony_ci * 802.1Q mode is disabled. When the port is standalone, DSA wants its 208062306a36Sopenharmony_ci * address database to remain 100% empty, so we never load an ATU entry 208162306a36Sopenharmony_ci * into a standalone port's database. Therefore, translate the null 208262306a36Sopenharmony_ci * VLAN ID into the port's database used for VLAN-unaware bridging. 208362306a36Sopenharmony_ci */ 208462306a36Sopenharmony_ci if (vid == 0) { 208562306a36Sopenharmony_ci fid = MV88E6XXX_FID_BRIDGED; 208662306a36Sopenharmony_ci } else { 208762306a36Sopenharmony_ci err = mv88e6xxx_vtu_get(chip, vid, &vlan); 208862306a36Sopenharmony_ci if (err) 208962306a36Sopenharmony_ci return err; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* switchdev expects -EOPNOTSUPP to honor software VLANs */ 209262306a36Sopenharmony_ci if (!vlan.valid) 209362306a36Sopenharmony_ci return -EOPNOTSUPP; 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci fid = vlan.fid; 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci entry.state = 0; 209962306a36Sopenharmony_ci ether_addr_copy(entry.mac, addr); 210062306a36Sopenharmony_ci eth_addr_dec(entry.mac); 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry); 210362306a36Sopenharmony_ci if (err) 210462306a36Sopenharmony_ci return err; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci /* Initialize a fresh ATU entry if it isn't found */ 210762306a36Sopenharmony_ci if (!entry.state || !ether_addr_equal(entry.mac, addr)) { 210862306a36Sopenharmony_ci memset(&entry, 0, sizeof(entry)); 210962306a36Sopenharmony_ci ether_addr_copy(entry.mac, addr); 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci /* Purge the ATU entry only if no port is using it anymore */ 211362306a36Sopenharmony_ci if (!state) { 211462306a36Sopenharmony_ci entry.portvec &= ~BIT(port); 211562306a36Sopenharmony_ci if (!entry.portvec) 211662306a36Sopenharmony_ci entry.state = 0; 211762306a36Sopenharmony_ci } else { 211862306a36Sopenharmony_ci if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC) 211962306a36Sopenharmony_ci entry.portvec = BIT(port); 212062306a36Sopenharmony_ci else 212162306a36Sopenharmony_ci entry.portvec |= BIT(port); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci entry.state = state; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry); 212762306a36Sopenharmony_ci} 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_cistatic int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port, 213062306a36Sopenharmony_ci const struct mv88e6xxx_policy *policy) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci enum mv88e6xxx_policy_mapping mapping = policy->mapping; 213362306a36Sopenharmony_ci enum mv88e6xxx_policy_action action = policy->action; 213462306a36Sopenharmony_ci const u8 *addr = policy->addr; 213562306a36Sopenharmony_ci u16 vid = policy->vid; 213662306a36Sopenharmony_ci u8 state; 213762306a36Sopenharmony_ci int err; 213862306a36Sopenharmony_ci int id; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (!chip->info->ops->port_set_policy) 214162306a36Sopenharmony_ci return -EOPNOTSUPP; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci switch (mapping) { 214462306a36Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_DA: 214562306a36Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_SA: 214662306a36Sopenharmony_ci if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 214762306a36Sopenharmony_ci state = 0; /* Dissociate the port and address */ 214862306a36Sopenharmony_ci else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 214962306a36Sopenharmony_ci is_multicast_ether_addr(addr)) 215062306a36Sopenharmony_ci state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY; 215162306a36Sopenharmony_ci else if (action == MV88E6XXX_POLICY_ACTION_DISCARD && 215262306a36Sopenharmony_ci is_unicast_ether_addr(addr)) 215362306a36Sopenharmony_ci state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY; 215462306a36Sopenharmony_ci else 215562306a36Sopenharmony_ci return -EOPNOTSUPP; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 215862306a36Sopenharmony_ci state); 215962306a36Sopenharmony_ci if (err) 216062306a36Sopenharmony_ci return err; 216162306a36Sopenharmony_ci break; 216262306a36Sopenharmony_ci default: 216362306a36Sopenharmony_ci return -EOPNOTSUPP; 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci /* Skip the port's policy clearing if the mapping is still in use */ 216762306a36Sopenharmony_ci if (action == MV88E6XXX_POLICY_ACTION_NORMAL) 216862306a36Sopenharmony_ci idr_for_each_entry(&chip->policies, policy, id) 216962306a36Sopenharmony_ci if (policy->port == port && 217062306a36Sopenharmony_ci policy->mapping == mapping && 217162306a36Sopenharmony_ci policy->action != action) 217262306a36Sopenharmony_ci return 0; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci return chip->info->ops->port_set_policy(chip, port, mapping, action); 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_cistatic int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port, 217862306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fs) 217962306a36Sopenharmony_ci{ 218062306a36Sopenharmony_ci struct ethhdr *mac_entry = &fs->h_u.ether_spec; 218162306a36Sopenharmony_ci struct ethhdr *mac_mask = &fs->m_u.ether_spec; 218262306a36Sopenharmony_ci enum mv88e6xxx_policy_mapping mapping; 218362306a36Sopenharmony_ci enum mv88e6xxx_policy_action action; 218462306a36Sopenharmony_ci struct mv88e6xxx_policy *policy; 218562306a36Sopenharmony_ci u16 vid = 0; 218662306a36Sopenharmony_ci u8 *addr; 218762306a36Sopenharmony_ci int err; 218862306a36Sopenharmony_ci int id; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci if (fs->location != RX_CLS_LOC_ANY) 219162306a36Sopenharmony_ci return -EINVAL; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci if (fs->ring_cookie == RX_CLS_FLOW_DISC) 219462306a36Sopenharmony_ci action = MV88E6XXX_POLICY_ACTION_DISCARD; 219562306a36Sopenharmony_ci else 219662306a36Sopenharmony_ci return -EOPNOTSUPP; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci switch (fs->flow_type & ~FLOW_EXT) { 219962306a36Sopenharmony_ci case ETHER_FLOW: 220062306a36Sopenharmony_ci if (!is_zero_ether_addr(mac_mask->h_dest) && 220162306a36Sopenharmony_ci is_zero_ether_addr(mac_mask->h_source)) { 220262306a36Sopenharmony_ci mapping = MV88E6XXX_POLICY_MAPPING_DA; 220362306a36Sopenharmony_ci addr = mac_entry->h_dest; 220462306a36Sopenharmony_ci } else if (is_zero_ether_addr(mac_mask->h_dest) && 220562306a36Sopenharmony_ci !is_zero_ether_addr(mac_mask->h_source)) { 220662306a36Sopenharmony_ci mapping = MV88E6XXX_POLICY_MAPPING_SA; 220762306a36Sopenharmony_ci addr = mac_entry->h_source; 220862306a36Sopenharmony_ci } else { 220962306a36Sopenharmony_ci /* Cannot support DA and SA mapping in the same rule */ 221062306a36Sopenharmony_ci return -EOPNOTSUPP; 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci break; 221362306a36Sopenharmony_ci default: 221462306a36Sopenharmony_ci return -EOPNOTSUPP; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) { 221862306a36Sopenharmony_ci if (fs->m_ext.vlan_tci != htons(0xffff)) 221962306a36Sopenharmony_ci return -EOPNOTSUPP; 222062306a36Sopenharmony_ci vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK; 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci idr_for_each_entry(&chip->policies, policy, id) { 222462306a36Sopenharmony_ci if (policy->port == port && policy->mapping == mapping && 222562306a36Sopenharmony_ci policy->action == action && policy->vid == vid && 222662306a36Sopenharmony_ci ether_addr_equal(policy->addr, addr)) 222762306a36Sopenharmony_ci return -EEXIST; 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL); 223162306a36Sopenharmony_ci if (!policy) 223262306a36Sopenharmony_ci return -ENOMEM; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci fs->location = 0; 223562306a36Sopenharmony_ci err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff, 223662306a36Sopenharmony_ci GFP_KERNEL); 223762306a36Sopenharmony_ci if (err) { 223862306a36Sopenharmony_ci devm_kfree(chip->dev, policy); 223962306a36Sopenharmony_ci return err; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci memcpy(&policy->fs, fs, sizeof(*fs)); 224362306a36Sopenharmony_ci ether_addr_copy(policy->addr, addr); 224462306a36Sopenharmony_ci policy->mapping = mapping; 224562306a36Sopenharmony_ci policy->action = action; 224662306a36Sopenharmony_ci policy->port = port; 224762306a36Sopenharmony_ci policy->vid = vid; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci err = mv88e6xxx_policy_apply(chip, port, policy); 225062306a36Sopenharmony_ci if (err) { 225162306a36Sopenharmony_ci idr_remove(&chip->policies, fs->location); 225262306a36Sopenharmony_ci devm_kfree(chip->dev, policy); 225362306a36Sopenharmony_ci return err; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci return 0; 225762306a36Sopenharmony_ci} 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_cistatic int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, 226062306a36Sopenharmony_ci struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 226162306a36Sopenharmony_ci{ 226262306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 226362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 226462306a36Sopenharmony_ci struct mv88e6xxx_policy *policy; 226562306a36Sopenharmony_ci int err; 226662306a36Sopenharmony_ci int id; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci switch (rxnfc->cmd) { 227162306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 227262306a36Sopenharmony_ci rxnfc->data = 0; 227362306a36Sopenharmony_ci rxnfc->data |= RX_CLS_LOC_SPECIAL; 227462306a36Sopenharmony_ci rxnfc->rule_cnt = 0; 227562306a36Sopenharmony_ci idr_for_each_entry(&chip->policies, policy, id) 227662306a36Sopenharmony_ci if (policy->port == port) 227762306a36Sopenharmony_ci rxnfc->rule_cnt++; 227862306a36Sopenharmony_ci err = 0; 227962306a36Sopenharmony_ci break; 228062306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 228162306a36Sopenharmony_ci err = -ENOENT; 228262306a36Sopenharmony_ci policy = idr_find(&chip->policies, fs->location); 228362306a36Sopenharmony_ci if (policy) { 228462306a36Sopenharmony_ci memcpy(fs, &policy->fs, sizeof(*fs)); 228562306a36Sopenharmony_ci err = 0; 228662306a36Sopenharmony_ci } 228762306a36Sopenharmony_ci break; 228862306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 228962306a36Sopenharmony_ci rxnfc->data = 0; 229062306a36Sopenharmony_ci rxnfc->rule_cnt = 0; 229162306a36Sopenharmony_ci idr_for_each_entry(&chip->policies, policy, id) 229262306a36Sopenharmony_ci if (policy->port == port) 229362306a36Sopenharmony_ci rule_locs[rxnfc->rule_cnt++] = id; 229462306a36Sopenharmony_ci err = 0; 229562306a36Sopenharmony_ci break; 229662306a36Sopenharmony_ci default: 229762306a36Sopenharmony_ci err = -EOPNOTSUPP; 229862306a36Sopenharmony_ci break; 229962306a36Sopenharmony_ci } 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci return err; 230462306a36Sopenharmony_ci} 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_cistatic int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, 230762306a36Sopenharmony_ci struct ethtool_rxnfc *rxnfc) 230862306a36Sopenharmony_ci{ 230962306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fs = &rxnfc->fs; 231062306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 231162306a36Sopenharmony_ci struct mv88e6xxx_policy *policy; 231262306a36Sopenharmony_ci int err; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci switch (rxnfc->cmd) { 231762306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 231862306a36Sopenharmony_ci err = mv88e6xxx_policy_insert(chip, port, fs); 231962306a36Sopenharmony_ci break; 232062306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 232162306a36Sopenharmony_ci err = -ENOENT; 232262306a36Sopenharmony_ci policy = idr_remove(&chip->policies, fs->location); 232362306a36Sopenharmony_ci if (policy) { 232462306a36Sopenharmony_ci policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; 232562306a36Sopenharmony_ci err = mv88e6xxx_policy_apply(chip, port, policy); 232662306a36Sopenharmony_ci devm_kfree(chip->dev, policy); 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci break; 232962306a36Sopenharmony_ci default: 233062306a36Sopenharmony_ci err = -EOPNOTSUPP; 233162306a36Sopenharmony_ci break; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci return err; 233762306a36Sopenharmony_ci} 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_cistatic int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port, 234062306a36Sopenharmony_ci u16 vid) 234162306a36Sopenharmony_ci{ 234262306a36Sopenharmony_ci u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 234362306a36Sopenharmony_ci u8 broadcast[ETH_ALEN]; 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci eth_broadcast_addr(broadcast); 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state); 234862306a36Sopenharmony_ci} 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_cistatic int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid) 235162306a36Sopenharmony_ci{ 235262306a36Sopenharmony_ci int port; 235362306a36Sopenharmony_ci int err; 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 235662306a36Sopenharmony_ci struct dsa_port *dp = dsa_to_port(chip->ds, port); 235762306a36Sopenharmony_ci struct net_device *brport; 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci if (dsa_is_unused_port(chip->ds, port)) 236062306a36Sopenharmony_ci continue; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci brport = dsa_port_to_bridge_port(dp); 236362306a36Sopenharmony_ci if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD)) 236462306a36Sopenharmony_ci /* Skip bridged user ports where broadcast 236562306a36Sopenharmony_ci * flooding is disabled. 236662306a36Sopenharmony_ci */ 236762306a36Sopenharmony_ci continue; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci err = mv88e6xxx_port_add_broadcast(chip, port, vid); 237062306a36Sopenharmony_ci if (err) 237162306a36Sopenharmony_ci return err; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci return 0; 237562306a36Sopenharmony_ci} 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_cistruct mv88e6xxx_port_broadcast_sync_ctx { 237862306a36Sopenharmony_ci int port; 237962306a36Sopenharmony_ci bool flood; 238062306a36Sopenharmony_ci}; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic int 238362306a36Sopenharmony_cimv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip, 238462306a36Sopenharmony_ci const struct mv88e6xxx_vtu_entry *vlan, 238562306a36Sopenharmony_ci void *_ctx) 238662306a36Sopenharmony_ci{ 238762306a36Sopenharmony_ci struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx; 238862306a36Sopenharmony_ci u8 broadcast[ETH_ALEN]; 238962306a36Sopenharmony_ci u8 state; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (ctx->flood) 239262306a36Sopenharmony_ci state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC; 239362306a36Sopenharmony_ci else 239462306a36Sopenharmony_ci state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci eth_broadcast_addr(broadcast); 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast, 239962306a36Sopenharmony_ci vlan->vid, state); 240062306a36Sopenharmony_ci} 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_cistatic int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port, 240362306a36Sopenharmony_ci bool flood) 240462306a36Sopenharmony_ci{ 240562306a36Sopenharmony_ci struct mv88e6xxx_port_broadcast_sync_ctx ctx = { 240662306a36Sopenharmony_ci .port = port, 240762306a36Sopenharmony_ci .flood = flood, 240862306a36Sopenharmony_ci }; 240962306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vid0 = { 241062306a36Sopenharmony_ci .vid = 0, 241162306a36Sopenharmony_ci }; 241262306a36Sopenharmony_ci int err; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci /* Update the port's private database... */ 241562306a36Sopenharmony_ci err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx); 241662306a36Sopenharmony_ci if (err) 241762306a36Sopenharmony_ci return err; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci /* ...and the database for all VLANs. */ 242062306a36Sopenharmony_ci return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan, 242162306a36Sopenharmony_ci &ctx); 242262306a36Sopenharmony_ci} 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, 242562306a36Sopenharmony_ci u16 vid, u8 member, bool warn) 242662306a36Sopenharmony_ci{ 242762306a36Sopenharmony_ci const u8 non_member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 242862306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 242962306a36Sopenharmony_ci int i, err; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci err = mv88e6xxx_vtu_get(chip, vid, &vlan); 243262306a36Sopenharmony_ci if (err) 243362306a36Sopenharmony_ci return err; 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci if (!vlan.valid) { 243662306a36Sopenharmony_ci memset(&vlan, 0, sizeof(vlan)); 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci if (vid == MV88E6XXX_VID_STANDALONE) 243962306a36Sopenharmony_ci vlan.policy = true; 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci err = mv88e6xxx_atu_new(chip, &vlan.fid); 244262306a36Sopenharmony_ci if (err) 244362306a36Sopenharmony_ci return err; 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) 244662306a36Sopenharmony_ci if (i == port) 244762306a36Sopenharmony_ci vlan.member[i] = member; 244862306a36Sopenharmony_ci else 244962306a36Sopenharmony_ci vlan.member[i] = non_member; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci vlan.vid = vid; 245262306a36Sopenharmony_ci vlan.valid = true; 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 245562306a36Sopenharmony_ci if (err) 245662306a36Sopenharmony_ci return err; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci err = mv88e6xxx_broadcast_setup(chip, vlan.vid); 245962306a36Sopenharmony_ci if (err) 246062306a36Sopenharmony_ci return err; 246162306a36Sopenharmony_ci } else if (vlan.member[port] != member) { 246262306a36Sopenharmony_ci vlan.member[port] = member; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 246562306a36Sopenharmony_ci if (err) 246662306a36Sopenharmony_ci return err; 246762306a36Sopenharmony_ci } else if (warn) { 246862306a36Sopenharmony_ci dev_info(chip->dev, "p%d: already a member of VLAN %d\n", 246962306a36Sopenharmony_ci port, vid); 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci return 0; 247362306a36Sopenharmony_ci} 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, 247662306a36Sopenharmony_ci const struct switchdev_obj_port_vlan *vlan, 247762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 247862306a36Sopenharmony_ci{ 247962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 248062306a36Sopenharmony_ci bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 248162306a36Sopenharmony_ci bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 248262306a36Sopenharmony_ci struct mv88e6xxx_port *p = &chip->ports[port]; 248362306a36Sopenharmony_ci bool warn; 248462306a36Sopenharmony_ci u8 member; 248562306a36Sopenharmony_ci int err; 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci if (!vlan->vid) 248862306a36Sopenharmony_ci return 0; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_prepare(ds, port, vlan); 249162306a36Sopenharmony_ci if (err) 249262306a36Sopenharmony_ci return err; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 249562306a36Sopenharmony_ci member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; 249662306a36Sopenharmony_ci else if (untagged) 249762306a36Sopenharmony_ci member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; 249862306a36Sopenharmony_ci else 249962306a36Sopenharmony_ci member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port 250262306a36Sopenharmony_ci * and then the CPU port. Do not warn for duplicates for the CPU port. 250362306a36Sopenharmony_ci */ 250462306a36Sopenharmony_ci warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_join(chip, port, vlan->vid, member, warn); 250962306a36Sopenharmony_ci if (err) { 251062306a36Sopenharmony_ci dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, 251162306a36Sopenharmony_ci vlan->vid, untagged ? 'u' : 't'); 251262306a36Sopenharmony_ci goto out; 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci if (pvid) { 251662306a36Sopenharmony_ci p->bridge_pvid.vid = vlan->vid; 251762306a36Sopenharmony_ci p->bridge_pvid.valid = true; 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci err = mv88e6xxx_port_commit_pvid(chip, port); 252062306a36Sopenharmony_ci if (err) 252162306a36Sopenharmony_ci goto out; 252262306a36Sopenharmony_ci } else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) { 252362306a36Sopenharmony_ci /* The old pvid was reinstalled as a non-pvid VLAN */ 252462306a36Sopenharmony_ci p->bridge_pvid.valid = false; 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci err = mv88e6xxx_port_commit_pvid(chip, port); 252762306a36Sopenharmony_ci if (err) 252862306a36Sopenharmony_ci goto out; 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ciout: 253262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci return err; 253562306a36Sopenharmony_ci} 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, 253862306a36Sopenharmony_ci int port, u16 vid) 253962306a36Sopenharmony_ci{ 254062306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 254162306a36Sopenharmony_ci int i, err; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci if (!vid) 254462306a36Sopenharmony_ci return 0; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci err = mv88e6xxx_vtu_get(chip, vid, &vlan); 254762306a36Sopenharmony_ci if (err) 254862306a36Sopenharmony_ci return err; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci /* If the VLAN doesn't exist in hardware or the port isn't a member, 255162306a36Sopenharmony_ci * tell switchdev that this VLAN is likely handled in software. 255262306a36Sopenharmony_ci */ 255362306a36Sopenharmony_ci if (!vlan.valid || 255462306a36Sopenharmony_ci vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) 255562306a36Sopenharmony_ci return -EOPNOTSUPP; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci /* keep the VLAN unless all ports are excluded */ 256062306a36Sopenharmony_ci vlan.valid = false; 256162306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 256262306a36Sopenharmony_ci if (vlan.member[i] != 256362306a36Sopenharmony_ci MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { 256462306a36Sopenharmony_ci vlan.valid = true; 256562306a36Sopenharmony_ci break; 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 257062306a36Sopenharmony_ci if (err) 257162306a36Sopenharmony_ci return err; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci if (!vlan.valid) { 257462306a36Sopenharmony_ci err = mv88e6xxx_mst_put(chip, vlan.sid); 257562306a36Sopenharmony_ci if (err) 257662306a36Sopenharmony_ci return err; 257762306a36Sopenharmony_ci } 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); 258062306a36Sopenharmony_ci} 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, 258362306a36Sopenharmony_ci const struct switchdev_obj_port_vlan *vlan) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 258662306a36Sopenharmony_ci struct mv88e6xxx_port *p = &chip->ports[port]; 258762306a36Sopenharmony_ci int err = 0; 258862306a36Sopenharmony_ci u16 pvid; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci if (!mv88e6xxx_max_vid(chip)) 259162306a36Sopenharmony_ci return -EOPNOTSUPP; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci /* The ATU removal procedure needs the FID to be mapped in the VTU, 259462306a36Sopenharmony_ci * but FDB deletion runs concurrently with VLAN deletion. Flush the DSA 259562306a36Sopenharmony_ci * switchdev workqueue to ensure that all FDB entries are deleted 259662306a36Sopenharmony_ci * before we remove the VLAN. 259762306a36Sopenharmony_ci */ 259862306a36Sopenharmony_ci dsa_flush_workqueue(); 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci err = mv88e6xxx_port_get_pvid(chip, port, &pvid); 260362306a36Sopenharmony_ci if (err) 260462306a36Sopenharmony_ci goto unlock; 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_leave(chip, port, vlan->vid); 260762306a36Sopenharmony_ci if (err) 260862306a36Sopenharmony_ci goto unlock; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci if (vlan->vid == pvid) { 261162306a36Sopenharmony_ci p->bridge_pvid.valid = false; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci err = mv88e6xxx_port_commit_pvid(chip, port); 261462306a36Sopenharmony_ci if (err) 261562306a36Sopenharmony_ci goto unlock; 261662306a36Sopenharmony_ci } 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ciunlock: 261962306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci return err; 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_cistatic int mv88e6xxx_port_vlan_fast_age(struct dsa_switch *ds, int port, u16 vid) 262562306a36Sopenharmony_ci{ 262662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 262762306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 262862306a36Sopenharmony_ci int err; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci err = mv88e6xxx_vtu_get(chip, vid, &vlan); 263362306a36Sopenharmony_ci if (err) 263462306a36Sopenharmony_ci goto unlock; 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci err = mv88e6xxx_port_fast_age_fid(chip, port, vlan.fid); 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ciunlock: 263962306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci return err; 264262306a36Sopenharmony_ci} 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_cistatic int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds, 264562306a36Sopenharmony_ci struct dsa_bridge bridge, 264662306a36Sopenharmony_ci const struct switchdev_vlan_msti *msti) 264762306a36Sopenharmony_ci{ 264862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 264962306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 265062306a36Sopenharmony_ci u8 old_sid, new_sid; 265162306a36Sopenharmony_ci int err; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci if (!mv88e6xxx_has_stu(chip)) 265462306a36Sopenharmony_ci return -EOPNOTSUPP; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci err = mv88e6xxx_vtu_get(chip, msti->vid, &vlan); 265962306a36Sopenharmony_ci if (err) 266062306a36Sopenharmony_ci goto unlock; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci if (!vlan.valid) { 266362306a36Sopenharmony_ci err = -EINVAL; 266462306a36Sopenharmony_ci goto unlock; 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci old_sid = vlan.sid; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci err = mv88e6xxx_mst_get(chip, bridge.dev, msti->msti, &new_sid); 267062306a36Sopenharmony_ci if (err) 267162306a36Sopenharmony_ci goto unlock; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci if (new_sid != old_sid) { 267462306a36Sopenharmony_ci vlan.sid = new_sid; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci err = mv88e6xxx_vtu_loadpurge(chip, &vlan); 267762306a36Sopenharmony_ci if (err) { 267862306a36Sopenharmony_ci mv88e6xxx_mst_put(chip, new_sid); 267962306a36Sopenharmony_ci goto unlock; 268062306a36Sopenharmony_ci } 268162306a36Sopenharmony_ci } 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci err = mv88e6xxx_mst_put(chip, old_sid); 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ciunlock: 268662306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 268762306a36Sopenharmony_ci return err; 268862306a36Sopenharmony_ci} 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_cistatic int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, 269162306a36Sopenharmony_ci const unsigned char *addr, u16 vid, 269262306a36Sopenharmony_ci struct dsa_db db) 269362306a36Sopenharmony_ci{ 269462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 269562306a36Sopenharmony_ci int err; 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 269862306a36Sopenharmony_ci err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 269962306a36Sopenharmony_ci MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 270062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci return err; 270362306a36Sopenharmony_ci} 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_cistatic int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, 270662306a36Sopenharmony_ci const unsigned char *addr, u16 vid, 270762306a36Sopenharmony_ci struct dsa_db db) 270862306a36Sopenharmony_ci{ 270962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 271062306a36Sopenharmony_ci int err; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 271362306a36Sopenharmony_ci err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); 271462306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci return err; 271762306a36Sopenharmony_ci} 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_cistatic int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, 272062306a36Sopenharmony_ci u16 fid, u16 vid, int port, 272162306a36Sopenharmony_ci dsa_fdb_dump_cb_t *cb, void *data) 272262306a36Sopenharmony_ci{ 272362306a36Sopenharmony_ci struct mv88e6xxx_atu_entry addr; 272462306a36Sopenharmony_ci bool is_static; 272562306a36Sopenharmony_ci int err; 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci addr.state = 0; 272862306a36Sopenharmony_ci eth_broadcast_addr(addr.mac); 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci do { 273162306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 273262306a36Sopenharmony_ci if (err) 273362306a36Sopenharmony_ci return err; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci if (!addr.state) 273662306a36Sopenharmony_ci break; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci if (addr.trunk || (addr.portvec & BIT(port)) == 0) 273962306a36Sopenharmony_ci continue; 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci if (!is_unicast_ether_addr(addr.mac)) 274262306a36Sopenharmony_ci continue; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci is_static = (addr.state == 274562306a36Sopenharmony_ci MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); 274662306a36Sopenharmony_ci err = cb(addr.mac, vid, is_static, data); 274762306a36Sopenharmony_ci if (err) 274862306a36Sopenharmony_ci return err; 274962306a36Sopenharmony_ci } while (!is_broadcast_ether_addr(addr.mac)); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci return err; 275262306a36Sopenharmony_ci} 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_cistruct mv88e6xxx_port_db_dump_vlan_ctx { 275562306a36Sopenharmony_ci int port; 275662306a36Sopenharmony_ci dsa_fdb_dump_cb_t *cb; 275762306a36Sopenharmony_ci void *data; 275862306a36Sopenharmony_ci}; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_cistatic int mv88e6xxx_port_db_dump_vlan(struct mv88e6xxx_chip *chip, 276162306a36Sopenharmony_ci const struct mv88e6xxx_vtu_entry *entry, 276262306a36Sopenharmony_ci void *_data) 276362306a36Sopenharmony_ci{ 276462306a36Sopenharmony_ci struct mv88e6xxx_port_db_dump_vlan_ctx *ctx = _data; 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci return mv88e6xxx_port_db_dump_fid(chip, entry->fid, entry->vid, 276762306a36Sopenharmony_ci ctx->port, ctx->cb, ctx->data); 276862306a36Sopenharmony_ci} 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_cistatic int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, 277162306a36Sopenharmony_ci dsa_fdb_dump_cb_t *cb, void *data) 277262306a36Sopenharmony_ci{ 277362306a36Sopenharmony_ci struct mv88e6xxx_port_db_dump_vlan_ctx ctx = { 277462306a36Sopenharmony_ci .port = port, 277562306a36Sopenharmony_ci .cb = cb, 277662306a36Sopenharmony_ci .data = data, 277762306a36Sopenharmony_ci }; 277862306a36Sopenharmony_ci u16 fid; 277962306a36Sopenharmony_ci int err; 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci /* Dump port's default Filtering Information Database (VLAN ID 0) */ 278262306a36Sopenharmony_ci err = mv88e6xxx_port_get_fid(chip, port, &fid); 278362306a36Sopenharmony_ci if (err) 278462306a36Sopenharmony_ci return err; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci err = mv88e6xxx_port_db_dump_fid(chip, fid, 0, port, cb, data); 278762306a36Sopenharmony_ci if (err) 278862306a36Sopenharmony_ci return err; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_db_dump_vlan, &ctx); 279162306a36Sopenharmony_ci} 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_cistatic int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, 279462306a36Sopenharmony_ci dsa_fdb_dump_cb_t *cb, void *data) 279562306a36Sopenharmony_ci{ 279662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 279762306a36Sopenharmony_ci int err; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 280062306a36Sopenharmony_ci err = mv88e6xxx_port_db_dump(chip, port, cb, data); 280162306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci return err; 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_cistatic int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, 280762306a36Sopenharmony_ci struct dsa_bridge bridge) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci struct dsa_switch *ds = chip->ds; 281062306a36Sopenharmony_ci struct dsa_switch_tree *dst = ds->dst; 281162306a36Sopenharmony_ci struct dsa_port *dp; 281262306a36Sopenharmony_ci int err; 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci list_for_each_entry(dp, &dst->ports, list) { 281562306a36Sopenharmony_ci if (dsa_port_offloads_bridge(dp, &bridge)) { 281662306a36Sopenharmony_ci if (dp->ds == ds) { 281762306a36Sopenharmony_ci /* This is a local bridge group member, 281862306a36Sopenharmony_ci * remap its Port VLAN Map. 281962306a36Sopenharmony_ci */ 282062306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_map(chip, dp->index); 282162306a36Sopenharmony_ci if (err) 282262306a36Sopenharmony_ci return err; 282362306a36Sopenharmony_ci } else { 282462306a36Sopenharmony_ci /* This is an external bridge group member, 282562306a36Sopenharmony_ci * remap its cross-chip Port VLAN Table entry. 282662306a36Sopenharmony_ci */ 282762306a36Sopenharmony_ci err = mv88e6xxx_pvt_map(chip, dp->ds->index, 282862306a36Sopenharmony_ci dp->index); 282962306a36Sopenharmony_ci if (err) 283062306a36Sopenharmony_ci return err; 283162306a36Sopenharmony_ci } 283262306a36Sopenharmony_ci } 283362306a36Sopenharmony_ci } 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci return 0; 283662306a36Sopenharmony_ci} 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci/* Treat the software bridge as a virtual single-port switch behind the 283962306a36Sopenharmony_ci * CPU and map in the PVT. First dst->last_switch elements are taken by 284062306a36Sopenharmony_ci * physical switches, so start from beyond that range. 284162306a36Sopenharmony_ci */ 284262306a36Sopenharmony_cistatic int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds, 284362306a36Sopenharmony_ci unsigned int bridge_num) 284462306a36Sopenharmony_ci{ 284562306a36Sopenharmony_ci u8 dev = bridge_num + ds->dst->last_switch; 284662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci return mv88e6xxx_pvt_map(chip, dev, 0); 284962306a36Sopenharmony_ci} 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_cistatic int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, 285262306a36Sopenharmony_ci struct dsa_bridge bridge, 285362306a36Sopenharmony_ci bool *tx_fwd_offload, 285462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 285562306a36Sopenharmony_ci{ 285662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 285762306a36Sopenharmony_ci int err; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci err = mv88e6xxx_bridge_map(chip, bridge); 286262306a36Sopenharmony_ci if (err) 286362306a36Sopenharmony_ci goto unlock; 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_ci err = mv88e6xxx_port_set_map_da(chip, port, true); 286662306a36Sopenharmony_ci if (err) 286762306a36Sopenharmony_ci goto unlock; 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci err = mv88e6xxx_port_commit_pvid(chip, port); 287062306a36Sopenharmony_ci if (err) 287162306a36Sopenharmony_ci goto unlock; 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci if (mv88e6xxx_has_pvt(chip)) { 287462306a36Sopenharmony_ci err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num); 287562306a36Sopenharmony_ci if (err) 287662306a36Sopenharmony_ci goto unlock; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci *tx_fwd_offload = true; 287962306a36Sopenharmony_ci } 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ciunlock: 288262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci return err; 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_cistatic void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, 288862306a36Sopenharmony_ci struct dsa_bridge bridge) 288962306a36Sopenharmony_ci{ 289062306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 289162306a36Sopenharmony_ci int err; 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci if (bridge.tx_fwd_offload && 289662306a36Sopenharmony_ci mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num)) 289762306a36Sopenharmony_ci dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci if (mv88e6xxx_bridge_map(chip, bridge) || 290062306a36Sopenharmony_ci mv88e6xxx_port_vlan_map(chip, port)) 290162306a36Sopenharmony_ci dev_err(ds->dev, "failed to remap in-chip Port VLAN\n"); 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci err = mv88e6xxx_port_set_map_da(chip, port, false); 290462306a36Sopenharmony_ci if (err) 290562306a36Sopenharmony_ci dev_err(ds->dev, 290662306a36Sopenharmony_ci "port %d failed to restore map-DA: %pe\n", 290762306a36Sopenharmony_ci port, ERR_PTR(err)); 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci err = mv88e6xxx_port_commit_pvid(chip, port); 291062306a36Sopenharmony_ci if (err) 291162306a36Sopenharmony_ci dev_err(ds->dev, 291262306a36Sopenharmony_ci "port %d failed to restore standalone pvid: %pe\n", 291362306a36Sopenharmony_ci port, ERR_PTR(err)); 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 291662306a36Sopenharmony_ci} 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, 291962306a36Sopenharmony_ci int tree_index, int sw_index, 292062306a36Sopenharmony_ci int port, struct dsa_bridge bridge, 292162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 292262306a36Sopenharmony_ci{ 292362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 292462306a36Sopenharmony_ci int err; 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci if (tree_index != ds->dst->index) 292762306a36Sopenharmony_ci return 0; 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 293062306a36Sopenharmony_ci err = mv88e6xxx_pvt_map(chip, sw_index, port); 293162306a36Sopenharmony_ci err = err ? : mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num); 293262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci return err; 293562306a36Sopenharmony_ci} 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_cistatic void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, 293862306a36Sopenharmony_ci int tree_index, int sw_index, 293962306a36Sopenharmony_ci int port, struct dsa_bridge bridge) 294062306a36Sopenharmony_ci{ 294162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci if (tree_index != ds->dst->index) 294462306a36Sopenharmony_ci return; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 294762306a36Sopenharmony_ci if (mv88e6xxx_pvt_map(chip, sw_index, port) || 294862306a36Sopenharmony_ci mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num)) 294962306a36Sopenharmony_ci dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); 295062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 295162306a36Sopenharmony_ci} 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_cistatic int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) 295462306a36Sopenharmony_ci{ 295562306a36Sopenharmony_ci if (chip->info->ops->reset) 295662306a36Sopenharmony_ci return chip->info->ops->reset(chip); 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci return 0; 295962306a36Sopenharmony_ci} 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_cistatic void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) 296262306a36Sopenharmony_ci{ 296362306a36Sopenharmony_ci struct gpio_desc *gpiod = chip->reset; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci /* If there is a GPIO connected to the reset pin, toggle it */ 296662306a36Sopenharmony_ci if (gpiod) { 296762306a36Sopenharmony_ci /* If the switch has just been reset and not yet completed 296862306a36Sopenharmony_ci * loading EEPROM, the reset may interrupt the I2C transaction 296962306a36Sopenharmony_ci * mid-byte, causing the first EEPROM read after the reset 297062306a36Sopenharmony_ci * from the wrong location resulting in the switch booting 297162306a36Sopenharmony_ci * to wrong mode and inoperable. 297262306a36Sopenharmony_ci */ 297362306a36Sopenharmony_ci if (chip->info->ops->get_eeprom) 297462306a36Sopenharmony_ci mv88e6xxx_g2_eeprom_wait(chip); 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci gpiod_set_value_cansleep(gpiod, 1); 297762306a36Sopenharmony_ci usleep_range(10000, 20000); 297862306a36Sopenharmony_ci gpiod_set_value_cansleep(gpiod, 0); 297962306a36Sopenharmony_ci usleep_range(10000, 20000); 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci if (chip->info->ops->get_eeprom) 298262306a36Sopenharmony_ci mv88e6xxx_g2_eeprom_wait(chip); 298362306a36Sopenharmony_ci } 298462306a36Sopenharmony_ci} 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_cistatic int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) 298762306a36Sopenharmony_ci{ 298862306a36Sopenharmony_ci int i, err; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci /* Set all ports to the Disabled state */ 299162306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 299262306a36Sopenharmony_ci err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); 299362306a36Sopenharmony_ci if (err) 299462306a36Sopenharmony_ci return err; 299562306a36Sopenharmony_ci } 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci /* Wait for transmit queues to drain, 299862306a36Sopenharmony_ci * i.e. 2ms for a maximum frame to be transmitted at 10 Mbps. 299962306a36Sopenharmony_ci */ 300062306a36Sopenharmony_ci usleep_range(2000, 4000); 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci return 0; 300362306a36Sopenharmony_ci} 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_cistatic int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) 300662306a36Sopenharmony_ci{ 300762306a36Sopenharmony_ci int err; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci err = mv88e6xxx_disable_ports(chip); 301062306a36Sopenharmony_ci if (err) 301162306a36Sopenharmony_ci return err; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci mv88e6xxx_hardware_reset(chip); 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ci return mv88e6xxx_software_reset(chip); 301662306a36Sopenharmony_ci} 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, 301962306a36Sopenharmony_ci enum mv88e6xxx_frame_mode frame, 302062306a36Sopenharmony_ci enum mv88e6xxx_egress_mode egress, u16 etype) 302162306a36Sopenharmony_ci{ 302262306a36Sopenharmony_ci int err; 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci if (!chip->info->ops->port_set_frame_mode) 302562306a36Sopenharmony_ci return -EOPNOTSUPP; 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci err = mv88e6xxx_port_set_egress_mode(chip, port, egress); 302862306a36Sopenharmony_ci if (err) 302962306a36Sopenharmony_ci return err; 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci err = chip->info->ops->port_set_frame_mode(chip, port, frame); 303262306a36Sopenharmony_ci if (err) 303362306a36Sopenharmony_ci return err; 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci if (chip->info->ops->port_set_ether_type) 303662306a36Sopenharmony_ci return chip->info->ops->port_set_ether_type(chip, port, etype); 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci return 0; 303962306a36Sopenharmony_ci} 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) 304262306a36Sopenharmony_ci{ 304362306a36Sopenharmony_ci return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, 304462306a36Sopenharmony_ci MV88E6XXX_EGRESS_MODE_UNMODIFIED, 304562306a36Sopenharmony_ci MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 304662306a36Sopenharmony_ci} 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) 304962306a36Sopenharmony_ci{ 305062306a36Sopenharmony_ci return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, 305162306a36Sopenharmony_ci MV88E6XXX_EGRESS_MODE_UNMODIFIED, 305262306a36Sopenharmony_ci MV88E6XXX_PORT_ETH_TYPE_DEFAULT); 305362306a36Sopenharmony_ci} 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_cistatic int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) 305662306a36Sopenharmony_ci{ 305762306a36Sopenharmony_ci return mv88e6xxx_set_port_mode(chip, port, 305862306a36Sopenharmony_ci MV88E6XXX_FRAME_MODE_ETHERTYPE, 305962306a36Sopenharmony_ci MV88E6XXX_EGRESS_MODE_ETHERTYPE, 306062306a36Sopenharmony_ci ETH_P_EDSA); 306162306a36Sopenharmony_ci} 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_cistatic int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) 306462306a36Sopenharmony_ci{ 306562306a36Sopenharmony_ci if (dsa_is_dsa_port(chip->ds, port)) 306662306a36Sopenharmony_ci return mv88e6xxx_set_port_mode_dsa(chip, port); 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci if (dsa_is_user_port(chip->ds, port)) 306962306a36Sopenharmony_ci return mv88e6xxx_set_port_mode_normal(chip, port); 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci /* Setup CPU port mode depending on its supported tag format */ 307262306a36Sopenharmony_ci if (chip->tag_protocol == DSA_TAG_PROTO_DSA) 307362306a36Sopenharmony_ci return mv88e6xxx_set_port_mode_dsa(chip, port); 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci if (chip->tag_protocol == DSA_TAG_PROTO_EDSA) 307662306a36Sopenharmony_ci return mv88e6xxx_set_port_mode_edsa(chip, port); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci return -EINVAL; 307962306a36Sopenharmony_ci} 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_cistatic int mv88e6xxx_setup_message_port(struct mv88e6xxx_chip *chip, int port) 308262306a36Sopenharmony_ci{ 308362306a36Sopenharmony_ci bool message = dsa_is_dsa_port(chip->ds, port); 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci return mv88e6xxx_port_set_message_port(chip, port, message); 308662306a36Sopenharmony_ci} 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_cistatic int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) 308962306a36Sopenharmony_ci{ 309062306a36Sopenharmony_ci int err; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci if (chip->info->ops->port_set_ucast_flood) { 309362306a36Sopenharmony_ci err = chip->info->ops->port_set_ucast_flood(chip, port, true); 309462306a36Sopenharmony_ci if (err) 309562306a36Sopenharmony_ci return err; 309662306a36Sopenharmony_ci } 309762306a36Sopenharmony_ci if (chip->info->ops->port_set_mcast_flood) { 309862306a36Sopenharmony_ci err = chip->info->ops->port_set_mcast_flood(chip, port, true); 309962306a36Sopenharmony_ci if (err) 310062306a36Sopenharmony_ci return err; 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci return 0; 310462306a36Sopenharmony_ci} 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_cistatic int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip, 310762306a36Sopenharmony_ci enum mv88e6xxx_egress_direction direction, 310862306a36Sopenharmony_ci int port) 310962306a36Sopenharmony_ci{ 311062306a36Sopenharmony_ci int err; 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci if (!chip->info->ops->set_egress_port) 311362306a36Sopenharmony_ci return -EOPNOTSUPP; 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci err = chip->info->ops->set_egress_port(chip, direction, port); 311662306a36Sopenharmony_ci if (err) 311762306a36Sopenharmony_ci return err; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (direction == MV88E6XXX_EGRESS_DIR_INGRESS) 312062306a36Sopenharmony_ci chip->ingress_dest_port = port; 312162306a36Sopenharmony_ci else 312262306a36Sopenharmony_ci chip->egress_dest_port = port; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci return 0; 312562306a36Sopenharmony_ci} 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_cistatic int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) 312862306a36Sopenharmony_ci{ 312962306a36Sopenharmony_ci struct dsa_switch *ds = chip->ds; 313062306a36Sopenharmony_ci int upstream_port; 313162306a36Sopenharmony_ci int err; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci upstream_port = dsa_upstream_port(ds, port); 313462306a36Sopenharmony_ci if (chip->info->ops->port_set_upstream_port) { 313562306a36Sopenharmony_ci err = chip->info->ops->port_set_upstream_port(chip, port, 313662306a36Sopenharmony_ci upstream_port); 313762306a36Sopenharmony_ci if (err) 313862306a36Sopenharmony_ci return err; 313962306a36Sopenharmony_ci } 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci if (port == upstream_port) { 314262306a36Sopenharmony_ci if (chip->info->ops->set_cpu_port) { 314362306a36Sopenharmony_ci err = chip->info->ops->set_cpu_port(chip, 314462306a36Sopenharmony_ci upstream_port); 314562306a36Sopenharmony_ci if (err) 314662306a36Sopenharmony_ci return err; 314762306a36Sopenharmony_ci } 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci err = mv88e6xxx_set_egress_port(chip, 315062306a36Sopenharmony_ci MV88E6XXX_EGRESS_DIR_INGRESS, 315162306a36Sopenharmony_ci upstream_port); 315262306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 315362306a36Sopenharmony_ci return err; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci err = mv88e6xxx_set_egress_port(chip, 315662306a36Sopenharmony_ci MV88E6XXX_EGRESS_DIR_EGRESS, 315762306a36Sopenharmony_ci upstream_port); 315862306a36Sopenharmony_ci if (err && err != -EOPNOTSUPP) 315962306a36Sopenharmony_ci return err; 316062306a36Sopenharmony_ci } 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci return 0; 316362306a36Sopenharmony_ci} 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_cistatic int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) 316662306a36Sopenharmony_ci{ 316762306a36Sopenharmony_ci struct device_node *phy_handle = NULL; 316862306a36Sopenharmony_ci struct dsa_switch *ds = chip->ds; 316962306a36Sopenharmony_ci struct dsa_port *dp; 317062306a36Sopenharmony_ci int tx_amp; 317162306a36Sopenharmony_ci int err; 317262306a36Sopenharmony_ci u16 reg; 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci chip->ports[port].chip = chip; 317562306a36Sopenharmony_ci chip->ports[port].port = port; 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, 317862306a36Sopenharmony_ci SPEED_UNFORCED, DUPLEX_UNFORCED, 317962306a36Sopenharmony_ci PAUSE_ON, PHY_INTERFACE_MODE_NA); 318062306a36Sopenharmony_ci if (err) 318162306a36Sopenharmony_ci return err; 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, 318462306a36Sopenharmony_ci * disable Header mode, enable IGMP/MLD snooping, disable VLAN 318562306a36Sopenharmony_ci * tunneling, determine priority by looking at 802.1p and IP 318662306a36Sopenharmony_ci * priority fields (IP prio has precedence), and set STP state 318762306a36Sopenharmony_ci * to Forwarding. 318862306a36Sopenharmony_ci * 318962306a36Sopenharmony_ci * If this is the CPU link, use DSA or EDSA tagging depending 319062306a36Sopenharmony_ci * on which tagging mode was configured. 319162306a36Sopenharmony_ci * 319262306a36Sopenharmony_ci * If this is a link to another switch, use DSA tagging mode. 319362306a36Sopenharmony_ci * 319462306a36Sopenharmony_ci * If this is the upstream port for this switch, enable 319562306a36Sopenharmony_ci * forwarding of unknown unicasts and multicasts. 319662306a36Sopenharmony_ci */ 319762306a36Sopenharmony_ci reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | 319862306a36Sopenharmony_ci MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 319962306a36Sopenharmony_ci /* Forward any IPv4 IGMP or IPv6 MLD frames received 320062306a36Sopenharmony_ci * by a USER port to the CPU port to allow snooping. 320162306a36Sopenharmony_ci */ 320262306a36Sopenharmony_ci if (dsa_is_user_port(ds, port)) 320362306a36Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP; 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 320662306a36Sopenharmony_ci if (err) 320762306a36Sopenharmony_ci return err; 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci err = mv88e6xxx_setup_port_mode(chip, port); 321062306a36Sopenharmony_ci if (err) 321162306a36Sopenharmony_ci return err; 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ci err = mv88e6xxx_setup_egress_floods(chip, port); 321462306a36Sopenharmony_ci if (err) 321562306a36Sopenharmony_ci return err; 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci /* Port Control 2: don't force a good FCS, set the MTU size to 321862306a36Sopenharmony_ci * 10222 bytes, disable 802.1q tags checking, don't discard 321962306a36Sopenharmony_ci * tagged or untagged frames on this port, skip destination 322062306a36Sopenharmony_ci * address lookup on user ports, disable ARP mirroring and don't 322162306a36Sopenharmony_ci * send a copy of all transmitted/received frames on this port 322262306a36Sopenharmony_ci * to the CPU. 322362306a36Sopenharmony_ci */ 322462306a36Sopenharmony_ci err = mv88e6xxx_port_set_map_da(chip, port, !dsa_is_user_port(ds, port)); 322562306a36Sopenharmony_ci if (err) 322662306a36Sopenharmony_ci return err; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci err = mv88e6xxx_setup_upstream_port(chip, port); 322962306a36Sopenharmony_ci if (err) 323062306a36Sopenharmony_ci return err; 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_ci /* On chips that support it, set all downstream DSA ports' 323362306a36Sopenharmony_ci * VLAN policy to TRAP. In combination with loading 323462306a36Sopenharmony_ci * MV88E6XXX_VID_STANDALONE as a policy entry in the VTU, this 323562306a36Sopenharmony_ci * provides a better isolation barrier between standalone 323662306a36Sopenharmony_ci * ports, as the ATU is bypassed on any intermediate switches 323762306a36Sopenharmony_ci * between the incoming port and the CPU. 323862306a36Sopenharmony_ci */ 323962306a36Sopenharmony_ci if (dsa_is_downstream_port(ds, port) && 324062306a36Sopenharmony_ci chip->info->ops->port_set_policy) { 324162306a36Sopenharmony_ci err = chip->info->ops->port_set_policy(chip, port, 324262306a36Sopenharmony_ci MV88E6XXX_POLICY_MAPPING_VTU, 324362306a36Sopenharmony_ci MV88E6XXX_POLICY_ACTION_TRAP); 324462306a36Sopenharmony_ci if (err) 324562306a36Sopenharmony_ci return err; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci /* User ports start out in standalone mode and 802.1Q is 324962306a36Sopenharmony_ci * therefore disabled. On DSA ports, all valid VIDs are always 325062306a36Sopenharmony_ci * loaded in the VTU - therefore, enable 802.1Q in order to take 325162306a36Sopenharmony_ci * advantage of VLAN policy on chips that supports it. 325262306a36Sopenharmony_ci */ 325362306a36Sopenharmony_ci err = mv88e6xxx_port_set_8021q_mode(chip, port, 325462306a36Sopenharmony_ci dsa_is_user_port(ds, port) ? 325562306a36Sopenharmony_ci MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED : 325662306a36Sopenharmony_ci MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE); 325762306a36Sopenharmony_ci if (err) 325862306a36Sopenharmony_ci return err; 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci /* Bind MV88E6XXX_VID_STANDALONE to MV88E6XXX_FID_STANDALONE by 326162306a36Sopenharmony_ci * virtue of the fact that mv88e6xxx_atu_new() will pick it as 326262306a36Sopenharmony_ci * the first free FID. This will be used as the private PVID for 326362306a36Sopenharmony_ci * unbridged ports. Shared (DSA and CPU) ports must also be 326462306a36Sopenharmony_ci * members of this VID, in order to trap all frames assigned to 326562306a36Sopenharmony_ci * it to the CPU. 326662306a36Sopenharmony_ci */ 326762306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_STANDALONE, 326862306a36Sopenharmony_ci MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED, 326962306a36Sopenharmony_ci false); 327062306a36Sopenharmony_ci if (err) 327162306a36Sopenharmony_ci return err; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci /* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the 327462306a36Sopenharmony_ci * ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as 327562306a36Sopenharmony_ci * the first free FID after MV88E6XXX_FID_STANDALONE. This will be used 327662306a36Sopenharmony_ci * as the private PVID on ports under a VLAN-unaware bridge. 327762306a36Sopenharmony_ci * Shared (DSA and CPU) ports must also be members of it, to translate 327862306a36Sopenharmony_ci * the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of 327962306a36Sopenharmony_ci * relying on their port default FID. 328062306a36Sopenharmony_ci */ 328162306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED, 328262306a36Sopenharmony_ci MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED, 328362306a36Sopenharmony_ci false); 328462306a36Sopenharmony_ci if (err) 328562306a36Sopenharmony_ci return err; 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci if (chip->info->ops->port_set_jumbo_size) { 328862306a36Sopenharmony_ci err = chip->info->ops->port_set_jumbo_size(chip, port, 10218); 328962306a36Sopenharmony_ci if (err) 329062306a36Sopenharmony_ci return err; 329162306a36Sopenharmony_ci } 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci /* Port Association Vector: disable automatic address learning 329462306a36Sopenharmony_ci * on all user ports since they start out in standalone 329562306a36Sopenharmony_ci * mode. When joining a bridge, learning will be configured to 329662306a36Sopenharmony_ci * match the bridge port settings. Enable learning on all 329762306a36Sopenharmony_ci * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the 329862306a36Sopenharmony_ci * learning process. 329962306a36Sopenharmony_ci * 330062306a36Sopenharmony_ci * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData, 330162306a36Sopenharmony_ci * and RefreshLocked. I.e. setup standard automatic learning. 330262306a36Sopenharmony_ci */ 330362306a36Sopenharmony_ci if (dsa_is_user_port(ds, port)) 330462306a36Sopenharmony_ci reg = 0; 330562306a36Sopenharmony_ci else 330662306a36Sopenharmony_ci reg = 1 << port; 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, 330962306a36Sopenharmony_ci reg); 331062306a36Sopenharmony_ci if (err) 331162306a36Sopenharmony_ci return err; 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_ci /* Egress rate control 2: disable egress rate control. */ 331462306a36Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, 331562306a36Sopenharmony_ci 0x0000); 331662306a36Sopenharmony_ci if (err) 331762306a36Sopenharmony_ci return err; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci if (chip->info->ops->port_pause_limit) { 332062306a36Sopenharmony_ci err = chip->info->ops->port_pause_limit(chip, port, 0, 0); 332162306a36Sopenharmony_ci if (err) 332262306a36Sopenharmony_ci return err; 332362306a36Sopenharmony_ci } 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci if (chip->info->ops->port_disable_learn_limit) { 332662306a36Sopenharmony_ci err = chip->info->ops->port_disable_learn_limit(chip, port); 332762306a36Sopenharmony_ci if (err) 332862306a36Sopenharmony_ci return err; 332962306a36Sopenharmony_ci } 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci if (chip->info->ops->port_disable_pri_override) { 333262306a36Sopenharmony_ci err = chip->info->ops->port_disable_pri_override(chip, port); 333362306a36Sopenharmony_ci if (err) 333462306a36Sopenharmony_ci return err; 333562306a36Sopenharmony_ci } 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci if (chip->info->ops->port_tag_remap) { 333862306a36Sopenharmony_ci err = chip->info->ops->port_tag_remap(chip, port); 333962306a36Sopenharmony_ci if (err) 334062306a36Sopenharmony_ci return err; 334162306a36Sopenharmony_ci } 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci if (chip->info->ops->port_egress_rate_limiting) { 334462306a36Sopenharmony_ci err = chip->info->ops->port_egress_rate_limiting(chip, port); 334562306a36Sopenharmony_ci if (err) 334662306a36Sopenharmony_ci return err; 334762306a36Sopenharmony_ci } 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci if (chip->info->ops->port_setup_message_port) { 335062306a36Sopenharmony_ci err = chip->info->ops->port_setup_message_port(chip, port); 335162306a36Sopenharmony_ci if (err) 335262306a36Sopenharmony_ci return err; 335362306a36Sopenharmony_ci } 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci if (chip->info->ops->serdes_set_tx_amplitude) { 335662306a36Sopenharmony_ci dp = dsa_to_port(ds, port); 335762306a36Sopenharmony_ci if (dp) 335862306a36Sopenharmony_ci phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0); 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci if (phy_handle && !of_property_read_u32(phy_handle, 336162306a36Sopenharmony_ci "tx-p2p-microvolt", 336262306a36Sopenharmony_ci &tx_amp)) 336362306a36Sopenharmony_ci err = chip->info->ops->serdes_set_tx_amplitude(chip, 336462306a36Sopenharmony_ci port, tx_amp); 336562306a36Sopenharmony_ci if (phy_handle) { 336662306a36Sopenharmony_ci of_node_put(phy_handle); 336762306a36Sopenharmony_ci if (err) 336862306a36Sopenharmony_ci return err; 336962306a36Sopenharmony_ci } 337062306a36Sopenharmony_ci } 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci /* Port based VLAN map: give each port the same default address 337362306a36Sopenharmony_ci * database, and allow bidirectional communication between the 337462306a36Sopenharmony_ci * CPU and DSA port(s), and the other ports. 337562306a36Sopenharmony_ci */ 337662306a36Sopenharmony_ci err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE); 337762306a36Sopenharmony_ci if (err) 337862306a36Sopenharmony_ci return err; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci err = mv88e6xxx_port_vlan_map(chip, port); 338162306a36Sopenharmony_ci if (err) 338262306a36Sopenharmony_ci return err; 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci /* Default VLAN ID and priority: don't set a default VLAN 338562306a36Sopenharmony_ci * ID, and set the default packet priority to zero. 338662306a36Sopenharmony_ci */ 338762306a36Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); 338862306a36Sopenharmony_ci} 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_cistatic int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port) 339162306a36Sopenharmony_ci{ 339262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci if (chip->info->ops->port_set_jumbo_size) 339562306a36Sopenharmony_ci return 10240 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 339662306a36Sopenharmony_ci else if (chip->info->ops->set_max_frame_size) 339762306a36Sopenharmony_ci return 1632 - VLAN_ETH_HLEN - EDSA_HLEN - ETH_FCS_LEN; 339862306a36Sopenharmony_ci return ETH_DATA_LEN; 339962306a36Sopenharmony_ci} 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_cistatic int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 340262306a36Sopenharmony_ci{ 340362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 340462306a36Sopenharmony_ci int ret = 0; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci /* For families where we don't know how to alter the MTU, 340762306a36Sopenharmony_ci * just accept any value up to ETH_DATA_LEN 340862306a36Sopenharmony_ci */ 340962306a36Sopenharmony_ci if (!chip->info->ops->port_set_jumbo_size && 341062306a36Sopenharmony_ci !chip->info->ops->set_max_frame_size) { 341162306a36Sopenharmony_ci if (new_mtu > ETH_DATA_LEN) 341262306a36Sopenharmony_ci return -EINVAL; 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci return 0; 341562306a36Sopenharmony_ci } 341662306a36Sopenharmony_ci 341762306a36Sopenharmony_ci if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) 341862306a36Sopenharmony_ci new_mtu += EDSA_HLEN; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 342162306a36Sopenharmony_ci if (chip->info->ops->port_set_jumbo_size) 342262306a36Sopenharmony_ci ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu); 342362306a36Sopenharmony_ci else if (chip->info->ops->set_max_frame_size) 342462306a36Sopenharmony_ci ret = chip->info->ops->set_max_frame_size(chip, new_mtu); 342562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci return ret; 342862306a36Sopenharmony_ci} 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_cistatic int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, 343162306a36Sopenharmony_ci unsigned int ageing_time) 343262306a36Sopenharmony_ci{ 343362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 343462306a36Sopenharmony_ci int err; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 343762306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time); 343862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci return err; 344162306a36Sopenharmony_ci} 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_cistatic int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) 344462306a36Sopenharmony_ci{ 344562306a36Sopenharmony_ci int err; 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci /* Initialize the statistics unit */ 344862306a36Sopenharmony_ci if (chip->info->ops->stats_set_histogram) { 344962306a36Sopenharmony_ci err = chip->info->ops->stats_set_histogram(chip); 345062306a36Sopenharmony_ci if (err) 345162306a36Sopenharmony_ci return err; 345262306a36Sopenharmony_ci } 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci return mv88e6xxx_g1_stats_clear(chip); 345562306a36Sopenharmony_ci} 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci/* Check if the errata has already been applied. */ 345862306a36Sopenharmony_cistatic bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) 345962306a36Sopenharmony_ci{ 346062306a36Sopenharmony_ci int port; 346162306a36Sopenharmony_ci int err; 346262306a36Sopenharmony_ci u16 val; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 346562306a36Sopenharmony_ci err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val); 346662306a36Sopenharmony_ci if (err) { 346762306a36Sopenharmony_ci dev_err(chip->dev, 346862306a36Sopenharmony_ci "Error reading hidden register: %d\n", err); 346962306a36Sopenharmony_ci return false; 347062306a36Sopenharmony_ci } 347162306a36Sopenharmony_ci if (val != 0x01c0) 347262306a36Sopenharmony_ci return false; 347362306a36Sopenharmony_ci } 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci return true; 347662306a36Sopenharmony_ci} 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci/* The 6390 copper ports have an errata which require poking magic 347962306a36Sopenharmony_ci * values into undocumented hidden registers and then performing a 348062306a36Sopenharmony_ci * software reset. 348162306a36Sopenharmony_ci */ 348262306a36Sopenharmony_cistatic int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) 348362306a36Sopenharmony_ci{ 348462306a36Sopenharmony_ci int port; 348562306a36Sopenharmony_ci int err; 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci if (mv88e6390_setup_errata_applied(chip)) 348862306a36Sopenharmony_ci return 0; 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci /* Set the ports into blocking mode */ 349162306a36Sopenharmony_ci for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 349262306a36Sopenharmony_ci err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); 349362306a36Sopenharmony_ci if (err) 349462306a36Sopenharmony_ci return err; 349562306a36Sopenharmony_ci } 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 349862306a36Sopenharmony_ci err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0); 349962306a36Sopenharmony_ci if (err) 350062306a36Sopenharmony_ci return err; 350162306a36Sopenharmony_ci } 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci return mv88e6xxx_software_reset(chip); 350462306a36Sopenharmony_ci} 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ci/* prod_id for switch families which do not have a PHY model number */ 350762306a36Sopenharmony_cistatic const u16 family_prod_id_table[] = { 350862306a36Sopenharmony_ci [MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 350962306a36Sopenharmony_ci [MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 351062306a36Sopenharmony_ci [MV88E6XXX_FAMILY_6393] = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, 351162306a36Sopenharmony_ci}; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_cistatic int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 351462306a36Sopenharmony_ci{ 351562306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 351662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = mdio_bus->chip; 351762306a36Sopenharmony_ci u16 prod_id; 351862306a36Sopenharmony_ci u16 val; 351962306a36Sopenharmony_ci int err; 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci if (!chip->info->ops->phy_read) 352262306a36Sopenharmony_ci return -EOPNOTSUPP; 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 352562306a36Sopenharmony_ci err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 352662306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci /* Some internal PHYs don't have a model number. */ 352962306a36Sopenharmony_ci if (reg == MII_PHYSID2 && !(val & 0x3f0) && 353062306a36Sopenharmony_ci chip->info->family < ARRAY_SIZE(family_prod_id_table)) { 353162306a36Sopenharmony_ci prod_id = family_prod_id_table[chip->info->family]; 353262306a36Sopenharmony_ci if (prod_id) 353362306a36Sopenharmony_ci val |= prod_id >> 4; 353462306a36Sopenharmony_ci } 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_ci return err ? err : val; 353762306a36Sopenharmony_ci} 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_cistatic int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad, 354062306a36Sopenharmony_ci int reg) 354162306a36Sopenharmony_ci{ 354262306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 354362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = mdio_bus->chip; 354462306a36Sopenharmony_ci u16 val; 354562306a36Sopenharmony_ci int err; 354662306a36Sopenharmony_ci 354762306a36Sopenharmony_ci if (!chip->info->ops->phy_read_c45) 354862306a36Sopenharmony_ci return 0xffff; 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 355162306a36Sopenharmony_ci err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val); 355262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci return err ? err : val; 355562306a36Sopenharmony_ci} 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_cistatic int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 355862306a36Sopenharmony_ci{ 355962306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 356062306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = mdio_bus->chip; 356162306a36Sopenharmony_ci int err; 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_ci if (!chip->info->ops->phy_write) 356462306a36Sopenharmony_ci return -EOPNOTSUPP; 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 356762306a36Sopenharmony_ci err = chip->info->ops->phy_write(chip, bus, phy, reg, val); 356862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci return err; 357162306a36Sopenharmony_ci} 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_cistatic int mv88e6xxx_mdio_write_c45(struct mii_bus *bus, int phy, int devad, 357462306a36Sopenharmony_ci int reg, u16 val) 357562306a36Sopenharmony_ci{ 357662306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 357762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = mdio_bus->chip; 357862306a36Sopenharmony_ci int err; 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci if (!chip->info->ops->phy_write_c45) 358162306a36Sopenharmony_ci return -EOPNOTSUPP; 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 358462306a36Sopenharmony_ci err = chip->info->ops->phy_write_c45(chip, bus, phy, devad, reg, val); 358562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci return err; 358862306a36Sopenharmony_ci} 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_cistatic int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, 359162306a36Sopenharmony_ci struct device_node *np, 359262306a36Sopenharmony_ci bool external) 359362306a36Sopenharmony_ci{ 359462306a36Sopenharmony_ci static int index; 359562306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus; 359662306a36Sopenharmony_ci struct mii_bus *bus; 359762306a36Sopenharmony_ci int err; 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_ci if (external) { 360062306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 360162306a36Sopenharmony_ci err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); 360262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci if (err) 360562306a36Sopenharmony_ci return err; 360662306a36Sopenharmony_ci } 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci bus = mdiobus_alloc_size(sizeof(*mdio_bus)); 360962306a36Sopenharmony_ci if (!bus) 361062306a36Sopenharmony_ci return -ENOMEM; 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci mdio_bus = bus->priv; 361362306a36Sopenharmony_ci mdio_bus->bus = bus; 361462306a36Sopenharmony_ci mdio_bus->chip = chip; 361562306a36Sopenharmony_ci INIT_LIST_HEAD(&mdio_bus->list); 361662306a36Sopenharmony_ci mdio_bus->external = external; 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci if (np) { 361962306a36Sopenharmony_ci bus->name = np->full_name; 362062306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%pOF", np); 362162306a36Sopenharmony_ci } else { 362262306a36Sopenharmony_ci bus->name = "mv88e6xxx SMI"; 362362306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "mv88e6xxx-%d", index++); 362462306a36Sopenharmony_ci } 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci bus->read = mv88e6xxx_mdio_read; 362762306a36Sopenharmony_ci bus->write = mv88e6xxx_mdio_write; 362862306a36Sopenharmony_ci bus->read_c45 = mv88e6xxx_mdio_read_c45; 362962306a36Sopenharmony_ci bus->write_c45 = mv88e6xxx_mdio_write_c45; 363062306a36Sopenharmony_ci bus->parent = chip->dev; 363162306a36Sopenharmony_ci bus->phy_mask = ~GENMASK(chip->info->phy_base_addr + 363262306a36Sopenharmony_ci mv88e6xxx_num_ports(chip) - 1, 363362306a36Sopenharmony_ci chip->info->phy_base_addr); 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci if (!external) { 363662306a36Sopenharmony_ci err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); 363762306a36Sopenharmony_ci if (err) 363862306a36Sopenharmony_ci goto out; 363962306a36Sopenharmony_ci } 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci err = of_mdiobus_register(bus, np); 364262306a36Sopenharmony_ci if (err) { 364362306a36Sopenharmony_ci dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); 364462306a36Sopenharmony_ci mv88e6xxx_g2_irq_mdio_free(chip, bus); 364562306a36Sopenharmony_ci goto out; 364662306a36Sopenharmony_ci } 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci if (external) 364962306a36Sopenharmony_ci list_add_tail(&mdio_bus->list, &chip->mdios); 365062306a36Sopenharmony_ci else 365162306a36Sopenharmony_ci list_add(&mdio_bus->list, &chip->mdios); 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci return 0; 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ciout: 365662306a36Sopenharmony_ci mdiobus_free(bus); 365762306a36Sopenharmony_ci return err; 365862306a36Sopenharmony_ci} 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_cistatic void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci{ 366362306a36Sopenharmony_ci struct mv88e6xxx_mdio_bus *mdio_bus, *p; 366462306a36Sopenharmony_ci struct mii_bus *bus; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci list_for_each_entry_safe(mdio_bus, p, &chip->mdios, list) { 366762306a36Sopenharmony_ci bus = mdio_bus->bus; 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci if (!mdio_bus->external) 367062306a36Sopenharmony_ci mv88e6xxx_g2_irq_mdio_free(chip, bus); 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_ci mdiobus_unregister(bus); 367362306a36Sopenharmony_ci mdiobus_free(bus); 367462306a36Sopenharmony_ci } 367562306a36Sopenharmony_ci} 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_cistatic int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip) 367862306a36Sopenharmony_ci{ 367962306a36Sopenharmony_ci struct device_node *np = chip->dev->of_node; 368062306a36Sopenharmony_ci struct device_node *child; 368162306a36Sopenharmony_ci int err; 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci /* Always register one mdio bus for the internal/default mdio 368462306a36Sopenharmony_ci * bus. This maybe represented in the device tree, but is 368562306a36Sopenharmony_ci * optional. 368662306a36Sopenharmony_ci */ 368762306a36Sopenharmony_ci child = of_get_child_by_name(np, "mdio"); 368862306a36Sopenharmony_ci err = mv88e6xxx_mdio_register(chip, child, false); 368962306a36Sopenharmony_ci of_node_put(child); 369062306a36Sopenharmony_ci if (err) 369162306a36Sopenharmony_ci return err; 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci /* Walk the device tree, and see if there are any other nodes 369462306a36Sopenharmony_ci * which say they are compatible with the external mdio 369562306a36Sopenharmony_ci * bus. 369662306a36Sopenharmony_ci */ 369762306a36Sopenharmony_ci for_each_available_child_of_node(np, child) { 369862306a36Sopenharmony_ci if (of_device_is_compatible( 369962306a36Sopenharmony_ci child, "marvell,mv88e6xxx-mdio-external")) { 370062306a36Sopenharmony_ci err = mv88e6xxx_mdio_register(chip, child, true); 370162306a36Sopenharmony_ci if (err) { 370262306a36Sopenharmony_ci mv88e6xxx_mdios_unregister(chip); 370362306a36Sopenharmony_ci of_node_put(child); 370462306a36Sopenharmony_ci return err; 370562306a36Sopenharmony_ci } 370662306a36Sopenharmony_ci } 370762306a36Sopenharmony_ci } 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci return 0; 371062306a36Sopenharmony_ci} 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_cistatic void mv88e6xxx_teardown(struct dsa_switch *ds) 371362306a36Sopenharmony_ci{ 371462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci mv88e6xxx_teardown_devlink_params(ds); 371762306a36Sopenharmony_ci dsa_devlink_resources_unregister(ds); 371862306a36Sopenharmony_ci mv88e6xxx_teardown_devlink_regions_global(ds); 371962306a36Sopenharmony_ci mv88e6xxx_mdios_unregister(chip); 372062306a36Sopenharmony_ci} 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_cistatic int mv88e6xxx_setup(struct dsa_switch *ds) 372362306a36Sopenharmony_ci{ 372462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 372562306a36Sopenharmony_ci u8 cmode; 372662306a36Sopenharmony_ci int err; 372762306a36Sopenharmony_ci int i; 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci err = mv88e6xxx_mdios_register(chip); 373062306a36Sopenharmony_ci if (err) 373162306a36Sopenharmony_ci return err; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci chip->ds = ds; 373462306a36Sopenharmony_ci ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci /* Since virtual bridges are mapped in the PVT, the number we support 373762306a36Sopenharmony_ci * depends on the physical switch topology. We need to let DSA figure 373862306a36Sopenharmony_ci * that out and therefore we cannot set this at dsa_register_switch() 373962306a36Sopenharmony_ci * time. 374062306a36Sopenharmony_ci */ 374162306a36Sopenharmony_ci if (mv88e6xxx_has_pvt(chip)) 374262306a36Sopenharmony_ci ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES - 374362306a36Sopenharmony_ci ds->dst->last_switch - 1; 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 374662306a36Sopenharmony_ci 374762306a36Sopenharmony_ci if (chip->info->ops->setup_errata) { 374862306a36Sopenharmony_ci err = chip->info->ops->setup_errata(chip); 374962306a36Sopenharmony_ci if (err) 375062306a36Sopenharmony_ci goto unlock; 375162306a36Sopenharmony_ci } 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci /* Cache the cmode of each port. */ 375462306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 375562306a36Sopenharmony_ci if (chip->info->ops->port_get_cmode) { 375662306a36Sopenharmony_ci err = chip->info->ops->port_get_cmode(chip, i, &cmode); 375762306a36Sopenharmony_ci if (err) 375862306a36Sopenharmony_ci goto unlock; 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci chip->ports[i].cmode = cmode; 376162306a36Sopenharmony_ci } 376262306a36Sopenharmony_ci } 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci err = mv88e6xxx_vtu_setup(chip); 376562306a36Sopenharmony_ci if (err) 376662306a36Sopenharmony_ci goto unlock; 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci /* Must be called after mv88e6xxx_vtu_setup (which flushes the 376962306a36Sopenharmony_ci * VTU, thereby also flushing the STU). 377062306a36Sopenharmony_ci */ 377162306a36Sopenharmony_ci err = mv88e6xxx_stu_setup(chip); 377262306a36Sopenharmony_ci if (err) 377362306a36Sopenharmony_ci goto unlock; 377462306a36Sopenharmony_ci 377562306a36Sopenharmony_ci /* Setup Switch Port Registers */ 377662306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { 377762306a36Sopenharmony_ci if (dsa_is_unused_port(ds, i)) 377862306a36Sopenharmony_ci continue; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci /* Prevent the use of an invalid port. */ 378162306a36Sopenharmony_ci if (mv88e6xxx_is_invalid_port(chip, i)) { 378262306a36Sopenharmony_ci dev_err(chip->dev, "port %d is invalid\n", i); 378362306a36Sopenharmony_ci err = -EINVAL; 378462306a36Sopenharmony_ci goto unlock; 378562306a36Sopenharmony_ci } 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_ci err = mv88e6xxx_setup_port(chip, i); 378862306a36Sopenharmony_ci if (err) 378962306a36Sopenharmony_ci goto unlock; 379062306a36Sopenharmony_ci } 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci err = mv88e6xxx_irl_setup(chip); 379362306a36Sopenharmony_ci if (err) 379462306a36Sopenharmony_ci goto unlock; 379562306a36Sopenharmony_ci 379662306a36Sopenharmony_ci err = mv88e6xxx_mac_setup(chip); 379762306a36Sopenharmony_ci if (err) 379862306a36Sopenharmony_ci goto unlock; 379962306a36Sopenharmony_ci 380062306a36Sopenharmony_ci err = mv88e6xxx_phy_setup(chip); 380162306a36Sopenharmony_ci if (err) 380262306a36Sopenharmony_ci goto unlock; 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci err = mv88e6xxx_pvt_setup(chip); 380562306a36Sopenharmony_ci if (err) 380662306a36Sopenharmony_ci goto unlock; 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci err = mv88e6xxx_atu_setup(chip); 380962306a36Sopenharmony_ci if (err) 381062306a36Sopenharmony_ci goto unlock; 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci err = mv88e6xxx_broadcast_setup(chip, 0); 381362306a36Sopenharmony_ci if (err) 381462306a36Sopenharmony_ci goto unlock; 381562306a36Sopenharmony_ci 381662306a36Sopenharmony_ci err = mv88e6xxx_pot_setup(chip); 381762306a36Sopenharmony_ci if (err) 381862306a36Sopenharmony_ci goto unlock; 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ci err = mv88e6xxx_rmu_setup(chip); 382162306a36Sopenharmony_ci if (err) 382262306a36Sopenharmony_ci goto unlock; 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci err = mv88e6xxx_rsvd2cpu_setup(chip); 382562306a36Sopenharmony_ci if (err) 382662306a36Sopenharmony_ci goto unlock; 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci err = mv88e6xxx_trunk_setup(chip); 382962306a36Sopenharmony_ci if (err) 383062306a36Sopenharmony_ci goto unlock; 383162306a36Sopenharmony_ci 383262306a36Sopenharmony_ci err = mv88e6xxx_devmap_setup(chip); 383362306a36Sopenharmony_ci if (err) 383462306a36Sopenharmony_ci goto unlock; 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_ci err = mv88e6xxx_pri_setup(chip); 383762306a36Sopenharmony_ci if (err) 383862306a36Sopenharmony_ci goto unlock; 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_ci /* Setup PTP Hardware Clock and timestamping */ 384162306a36Sopenharmony_ci if (chip->info->ptp_support) { 384262306a36Sopenharmony_ci err = mv88e6xxx_ptp_setup(chip); 384362306a36Sopenharmony_ci if (err) 384462306a36Sopenharmony_ci goto unlock; 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci err = mv88e6xxx_hwtstamp_setup(chip); 384762306a36Sopenharmony_ci if (err) 384862306a36Sopenharmony_ci goto unlock; 384962306a36Sopenharmony_ci } 385062306a36Sopenharmony_ci 385162306a36Sopenharmony_ci err = mv88e6xxx_stats_setup(chip); 385262306a36Sopenharmony_ci if (err) 385362306a36Sopenharmony_ci goto unlock; 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ciunlock: 385662306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci if (err) 385962306a36Sopenharmony_ci goto out_mdios; 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci /* Have to be called without holding the register lock, since 386262306a36Sopenharmony_ci * they take the devlink lock, and we later take the locks in 386362306a36Sopenharmony_ci * the reverse order when getting/setting parameters or 386462306a36Sopenharmony_ci * resource occupancy. 386562306a36Sopenharmony_ci */ 386662306a36Sopenharmony_ci err = mv88e6xxx_setup_devlink_resources(ds); 386762306a36Sopenharmony_ci if (err) 386862306a36Sopenharmony_ci goto out_mdios; 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci err = mv88e6xxx_setup_devlink_params(ds); 387162306a36Sopenharmony_ci if (err) 387262306a36Sopenharmony_ci goto out_resources; 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci err = mv88e6xxx_setup_devlink_regions_global(ds); 387562306a36Sopenharmony_ci if (err) 387662306a36Sopenharmony_ci goto out_params; 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci return 0; 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ciout_params: 388162306a36Sopenharmony_ci mv88e6xxx_teardown_devlink_params(ds); 388262306a36Sopenharmony_ciout_resources: 388362306a36Sopenharmony_ci dsa_devlink_resources_unregister(ds); 388462306a36Sopenharmony_ciout_mdios: 388562306a36Sopenharmony_ci mv88e6xxx_mdios_unregister(chip); 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci return err; 388862306a36Sopenharmony_ci} 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_cistatic int mv88e6xxx_port_setup(struct dsa_switch *ds, int port) 389162306a36Sopenharmony_ci{ 389262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 389362306a36Sopenharmony_ci int err; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci if (chip->info->ops->pcs_ops && 389662306a36Sopenharmony_ci chip->info->ops->pcs_ops->pcs_init) { 389762306a36Sopenharmony_ci err = chip->info->ops->pcs_ops->pcs_init(chip, port); 389862306a36Sopenharmony_ci if (err) 389962306a36Sopenharmony_ci return err; 390062306a36Sopenharmony_ci } 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci return mv88e6xxx_setup_devlink_regions_port(ds, port); 390362306a36Sopenharmony_ci} 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_cistatic void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port) 390662306a36Sopenharmony_ci{ 390762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci mv88e6xxx_teardown_devlink_regions_port(ds, port); 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci if (chip->info->ops->pcs_ops && 391262306a36Sopenharmony_ci chip->info->ops->pcs_ops->pcs_teardown) 391362306a36Sopenharmony_ci chip->info->ops->pcs_ops->pcs_teardown(chip, port); 391462306a36Sopenharmony_ci} 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_cistatic int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) 391762306a36Sopenharmony_ci{ 391862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci return chip->eeprom_len; 392162306a36Sopenharmony_ci} 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_cistatic int mv88e6xxx_get_eeprom(struct dsa_switch *ds, 392462306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 392562306a36Sopenharmony_ci{ 392662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 392762306a36Sopenharmony_ci int err; 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci if (!chip->info->ops->get_eeprom) 393062306a36Sopenharmony_ci return -EOPNOTSUPP; 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 393362306a36Sopenharmony_ci err = chip->info->ops->get_eeprom(chip, eeprom, data); 393462306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci if (err) 393762306a36Sopenharmony_ci return err; 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci eeprom->magic = 0xc3ec4951; 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ci return 0; 394262306a36Sopenharmony_ci} 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_cistatic int mv88e6xxx_set_eeprom(struct dsa_switch *ds, 394562306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 394662306a36Sopenharmony_ci{ 394762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 394862306a36Sopenharmony_ci int err; 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci if (!chip->info->ops->set_eeprom) 395162306a36Sopenharmony_ci return -EOPNOTSUPP; 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ci if (eeprom->magic != 0xc3ec4951) 395462306a36Sopenharmony_ci return -EINVAL; 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 395762306a36Sopenharmony_ci err = chip->info->ops->set_eeprom(chip, eeprom, data); 395862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 395962306a36Sopenharmony_ci 396062306a36Sopenharmony_ci return err; 396162306a36Sopenharmony_ci} 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6085_ops = { 396462306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6097 */ 396562306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 396662306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 396762306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 396862306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 396962306a36Sopenharmony_ci .phy_read = mv88e6185_phy_ppu_read, 397062306a36Sopenharmony_ci .phy_write = mv88e6185_phy_ppu_write, 397162306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 397262306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 397362306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 397462306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 397562306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 397662306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 397762306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 397862306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 397962306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 398062306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 398162306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 398262306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 398362306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 398462306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 398562306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 398662306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 398762306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 398862306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 398962306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 399062306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 399162306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 399262306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 399362306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 399462306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 399562306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 399662306a36Sopenharmony_ci .ppu_enable = mv88e6185_g1_ppu_enable, 399762306a36Sopenharmony_ci .ppu_disable = mv88e6185_g1_ppu_disable, 399862306a36Sopenharmony_ci .reset = mv88e6185_g1_reset, 399962306a36Sopenharmony_ci .rmu_disable = mv88e6085_g1_rmu_disable, 400062306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 400162306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 400262306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 400362306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 400462306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 400562306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 400662306a36Sopenharmony_ci}; 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6095_ops = { 400962306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6095 */ 401062306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 401162306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 401262306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 401362306a36Sopenharmony_ci .phy_read = mv88e6185_phy_ppu_read, 401462306a36Sopenharmony_ci .phy_write = mv88e6185_phy_ppu_write, 401562306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 401662306a36Sopenharmony_ci .port_sync_link = mv88e6185_port_sync_link, 401762306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 401862306a36Sopenharmony_ci .port_set_frame_mode = mv88e6085_port_set_frame_mode, 401962306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 402062306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6185_port_set_default_forward, 402162306a36Sopenharmony_ci .port_set_upstream_port = mv88e6095_port_set_upstream_port, 402262306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 402362306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 402462306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 402562306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 402662306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 402762306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 402862306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 402962306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 403062306a36Sopenharmony_ci .ppu_enable = mv88e6185_g1_ppu_enable, 403162306a36Sopenharmony_ci .ppu_disable = mv88e6185_g1_ppu_disable, 403262306a36Sopenharmony_ci .reset = mv88e6185_g1_reset, 403362306a36Sopenharmony_ci .vtu_getnext = mv88e6185_g1_vtu_getnext, 403462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 403562306a36Sopenharmony_ci .phylink_get_caps = mv88e6095_phylink_get_caps, 403662306a36Sopenharmony_ci .pcs_ops = &mv88e6185_pcs_ops, 403762306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 403862306a36Sopenharmony_ci}; 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6097_ops = { 404162306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6097 */ 404262306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 404362306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 404462306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 404562306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 404662306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 404762306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 404862306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 404962306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 405062306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 405162306a36Sopenharmony_ci .port_sync_link = mv88e6185_port_sync_link, 405262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 405362306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 405462306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 405562306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 405662306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 405762306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 405862306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 405962306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 406062306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 406162306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 406262306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 406362306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 406462306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 406562306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 406662306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 406762306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 406862306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 406962306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 407062306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 407162306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 407262306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 407362306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 407462306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 407562306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 407662306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 407762306a36Sopenharmony_ci .rmu_disable = mv88e6085_g1_rmu_disable, 407862306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 407962306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 408062306a36Sopenharmony_ci .phylink_get_caps = mv88e6095_phylink_get_caps, 408162306a36Sopenharmony_ci .pcs_ops = &mv88e6185_pcs_ops, 408262306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 408362306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 408462306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 408562306a36Sopenharmony_ci}; 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6123_ops = { 408862306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6165 */ 408962306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 409062306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 409162306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 409262306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 409362306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 409462306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 409562306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 409662306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 409762306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 409862306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 409962306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 410062306a36Sopenharmony_ci .port_set_frame_mode = mv88e6085_port_set_frame_mode, 410162306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 410262306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 410362306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 410462306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 410562306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 410662306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 410762306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 410862306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 410962306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 411062306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 411162306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 411262306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 411362306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 411462306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 411562306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 411662306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 411762306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 411862306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 411962306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 412062306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 412162306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 412262306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 412362306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 412462306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 412562306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 412662306a36Sopenharmony_ci}; 412762306a36Sopenharmony_ci 412862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6131_ops = { 412962306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6185 */ 413062306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 413162306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 413262306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 413362306a36Sopenharmony_ci .phy_read = mv88e6185_phy_ppu_read, 413462306a36Sopenharmony_ci .phy_write = mv88e6185_phy_ppu_write, 413562306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 413662306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 413762306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 413862306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 413962306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 414062306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 414162306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6185_port_set_default_forward, 414262306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 414362306a36Sopenharmony_ci .port_set_upstream_port = mv88e6095_port_set_upstream_port, 414462306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 414562306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 414662306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 414762306a36Sopenharmony_ci .port_set_pause = mv88e6185_port_set_pause, 414862306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 414962306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 415062306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 415162306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 415262306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 415362306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 415462306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 415562306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 415662306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 415762306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 415862306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 415962306a36Sopenharmony_ci .ppu_enable = mv88e6185_g1_ppu_enable, 416062306a36Sopenharmony_ci .set_cascade_port = mv88e6185_g1_set_cascade_port, 416162306a36Sopenharmony_ci .ppu_disable = mv88e6185_g1_ppu_disable, 416262306a36Sopenharmony_ci .reset = mv88e6185_g1_reset, 416362306a36Sopenharmony_ci .vtu_getnext = mv88e6185_g1_vtu_getnext, 416462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 416562306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 416662306a36Sopenharmony_ci}; 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6141_ops = { 416962306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6341 */ 417062306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 417162306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 417262306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 417362306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 417462306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 417562306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 417662306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 417762306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 417862306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 417962306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 418062306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 418162306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 418262306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 418362306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 418462306a36Sopenharmony_ci .port_max_speed_mode = mv88e6341_port_max_speed_mode, 418562306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 418662306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 418762306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 418862306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 418962306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 419062306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 419162306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 419262306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 419362306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 419462306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 419562306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 419662306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 419762306a36Sopenharmony_ci .port_set_cmode = mv88e6341_port_set_cmode, 419862306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 419962306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 420062306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 420162306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 420262306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 420362306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 420462306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 420562306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 420662306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 420762306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 420862306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 420962306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 421062306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 421162306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 421262306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 421362306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 421462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 421562306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 421662306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 421762306a36Sopenharmony_ci .serdes_get_lane = mv88e6341_serdes_get_lane, 421862306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 421962306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 422062306a36Sopenharmony_ci .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 422162306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 422262306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 422362306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 422462306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 422562306a36Sopenharmony_ci .phylink_get_caps = mv88e6341_phylink_get_caps, 422662306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 422762306a36Sopenharmony_ci}; 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6161_ops = { 423062306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6165 */ 423162306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 423262306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 423362306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 423462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 423562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 423662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 423762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 423862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 423962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 424062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 424162306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 424262306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 424362306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 424462306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 424562306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 424662306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 424762306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 424862306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 424962306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 425062306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 425162306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 425262306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 425362306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 425462306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 425562306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 425662306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 425762306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 425862306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 425962306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 426062306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 426162306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 426262306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 426362306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 426462306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 426562306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 426662306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 426762306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 426862306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 426962306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 427062306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 427162306a36Sopenharmony_ci .avb_ops = &mv88e6165_avb_ops, 427262306a36Sopenharmony_ci .ptp_ops = &mv88e6165_ptp_ops, 427362306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 427462306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 427562306a36Sopenharmony_ci}; 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6165_ops = { 427862306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6165 */ 427962306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 428062306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 428162306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 428262306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 428362306a36Sopenharmony_ci .phy_read = mv88e6165_phy_read, 428462306a36Sopenharmony_ci .phy_write = mv88e6165_phy_write, 428562306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 428662306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 428762306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 428862306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 428962306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 429062306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 429162306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 429262306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 429362306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 429462306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 429562306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 429662306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 429762306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 429862306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 429962306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 430062306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 430162306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 430262306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 430362306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 430462306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 430562306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 430662306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 430762306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 430862306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 430962306a36Sopenharmony_ci .avb_ops = &mv88e6165_avb_ops, 431062306a36Sopenharmony_ci .ptp_ops = &mv88e6165_ptp_ops, 431162306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 431262306a36Sopenharmony_ci}; 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6171_ops = { 431562306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6351 */ 431662306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 431762306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 431862306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 431962306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 432062306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 432162306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 432262306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 432362306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 432462306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 432562306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 432662306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 432762306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 432862306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 432962306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 433062306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 433162306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 433262306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 433362306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 433462306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 433562306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 433662306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 433762306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 433862306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 433962306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 434062306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 434162306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 434262306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 434362306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 434462306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 434562306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 434662306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 434762306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 434862306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 434962306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 435062306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 435162306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 435262306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 435362306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 435462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 435562306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 435662306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 435762306a36Sopenharmony_ci .phylink_get_caps = mv88e6351_phylink_get_caps, 435862306a36Sopenharmony_ci}; 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6172_ops = { 436162306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6352 */ 436262306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 436362306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 436462306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 436562306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 436662306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 436762306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 436862306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 436962306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 437062306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 437162306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 437262306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 437362306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 437462306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 437562306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 437662306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 437762306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 437862306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 437962306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 438062306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 438162306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 438262306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 438362306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 438462306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 438562306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 438662306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 438762306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 438862306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 438962306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 439062306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 439162306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 439262306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 439362306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 439462306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 439562306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 439662306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 439762306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 439862306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 439962306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 440062306a36Sopenharmony_ci .rmu_disable = mv88e6352_g1_rmu_disable, 440162306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 440262306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 440362306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 440462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 440562306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 440662306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 440762306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 440862306a36Sopenharmony_ci .serdes_get_regs = mv88e6352_serdes_get_regs, 440962306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 441062306a36Sopenharmony_ci .phylink_get_caps = mv88e6352_phylink_get_caps, 441162306a36Sopenharmony_ci .pcs_ops = &mv88e6352_pcs_ops, 441262306a36Sopenharmony_ci}; 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6175_ops = { 441562306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6351 */ 441662306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 441762306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 441862306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 441962306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 442062306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 442162306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 442262306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 442362306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 442462306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 442562306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 442662306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 442762306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 442862306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 442962306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 443062306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 443162306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 443262306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 443362306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 443462306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 443562306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 443662306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 443762306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 443862306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 443962306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 444062306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 444162306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 444262306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 444362306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 444462306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 444562306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 444662306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 444762306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 444862306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 444962306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 445062306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 445162306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 445262306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 445362306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 445462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 445562306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 445662306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 445762306a36Sopenharmony_ci .phylink_get_caps = mv88e6351_phylink_get_caps, 445862306a36Sopenharmony_ci}; 445962306a36Sopenharmony_ci 446062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6176_ops = { 446162306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6352 */ 446262306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 446362306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 446462306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 446562306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 446662306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 446762306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 446862306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 446962306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 447062306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 447162306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 447262306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 447362306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 447462306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 447562306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 447662306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 447762306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 447862306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 447962306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 448062306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 448162306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 448262306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 448362306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 448462306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 448562306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 448662306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 448762306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 448862306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 448962306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 449062306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 449162306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 449262306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 449362306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 449462306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 449562306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 449662306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 449762306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 449862306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 449962306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 450062306a36Sopenharmony_ci .rmu_disable = mv88e6352_g1_rmu_disable, 450162306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 450262306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 450362306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 450462306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 450562306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 450662306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 450762306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 450862306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 450962306a36Sopenharmony_ci .serdes_get_regs = mv88e6352_serdes_get_regs, 451062306a36Sopenharmony_ci .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, 451162306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 451262306a36Sopenharmony_ci .phylink_get_caps = mv88e6352_phylink_get_caps, 451362306a36Sopenharmony_ci .pcs_ops = &mv88e6352_pcs_ops, 451462306a36Sopenharmony_ci}; 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6185_ops = { 451762306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6185 */ 451862306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 451962306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 452062306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g1_set_switch_mac, 452162306a36Sopenharmony_ci .phy_read = mv88e6185_phy_ppu_read, 452262306a36Sopenharmony_ci .phy_write = mv88e6185_phy_ppu_write, 452362306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 452462306a36Sopenharmony_ci .port_sync_link = mv88e6185_port_sync_link, 452562306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 452662306a36Sopenharmony_ci .port_set_frame_mode = mv88e6085_port_set_frame_mode, 452762306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, 452862306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6185_port_set_default_forward, 452962306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, 453062306a36Sopenharmony_ci .port_set_upstream_port = mv88e6095_port_set_upstream_port, 453162306a36Sopenharmony_ci .port_set_pause = mv88e6185_port_set_pause, 453262306a36Sopenharmony_ci .port_get_cmode = mv88e6185_port_get_cmode, 453362306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 453462306a36Sopenharmony_ci .stats_snapshot = mv88e6xxx_g1_stats_snapshot, 453562306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 453662306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 453762306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 453862306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 453962306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 454062306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 454162306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 454262306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu, 454362306a36Sopenharmony_ci .set_cascade_port = mv88e6185_g1_set_cascade_port, 454462306a36Sopenharmony_ci .ppu_enable = mv88e6185_g1_ppu_enable, 454562306a36Sopenharmony_ci .ppu_disable = mv88e6185_g1_ppu_disable, 454662306a36Sopenharmony_ci .reset = mv88e6185_g1_reset, 454762306a36Sopenharmony_ci .vtu_getnext = mv88e6185_g1_vtu_getnext, 454862306a36Sopenharmony_ci .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 454962306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 455062306a36Sopenharmony_ci .pcs_ops = &mv88e6185_pcs_ops, 455162306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 455262306a36Sopenharmony_ci}; 455362306a36Sopenharmony_ci 455462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6190_ops = { 455562306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6390 */ 455662306a36Sopenharmony_ci .setup_errata = mv88e6390_setup_errata, 455762306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 455862306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 455962306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 456062306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 456162306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 456262306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 456362306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 456462306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 456562306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 456662306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 456762306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 456862306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 456962306a36Sopenharmony_ci .port_max_speed_mode = mv88e6390_port_max_speed_mode, 457062306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 457162306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 457262306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 457362306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 457462306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 457562306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 457662306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 457762306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 457862306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 457962306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 458062306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 458162306a36Sopenharmony_ci .port_set_cmode = mv88e6390_port_set_cmode, 458262306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 458362306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 458462306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 458562306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 458662306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 458762306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 458862306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 458962306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 459062306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 459162306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 459262306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 459362306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 459462306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 459562306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 459662306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 459762306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 459862306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 459962306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 460062306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 460162306a36Sopenharmony_ci .serdes_get_lane = mv88e6390_serdes_get_lane, 460262306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 460362306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 460462306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 460562306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 460662306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 460762306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 460862306a36Sopenharmony_ci .phylink_get_caps = mv88e6390_phylink_get_caps, 460962306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 461062306a36Sopenharmony_ci}; 461162306a36Sopenharmony_ci 461262306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6190x_ops = { 461362306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6390 */ 461462306a36Sopenharmony_ci .setup_errata = mv88e6390_setup_errata, 461562306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 461662306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 461762306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 461862306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 461962306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 462062306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 462162306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 462262306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 462362306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 462462306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 462562306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 462662306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 462762306a36Sopenharmony_ci .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 462862306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 462962306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 463062306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 463162306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 463262306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 463362306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 463462306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 463562306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 463662306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 463762306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 463862306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 463962306a36Sopenharmony_ci .port_set_cmode = mv88e6390x_port_set_cmode, 464062306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 464162306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 464262306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 464362306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 464462306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 464562306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 464662306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 464762306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 464862306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 464962306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 465062306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 465162306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 465262306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 465362306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 465462306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 465562306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 465662306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 465762306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 465862306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 465962306a36Sopenharmony_ci .serdes_get_lane = mv88e6390x_serdes_get_lane, 466062306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 466162306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 466262306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 466362306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 466462306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 466562306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 466662306a36Sopenharmony_ci .phylink_get_caps = mv88e6390x_phylink_get_caps, 466762306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 466862306a36Sopenharmony_ci}; 466962306a36Sopenharmony_ci 467062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6191_ops = { 467162306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6390 */ 467262306a36Sopenharmony_ci .setup_errata = mv88e6390_setup_errata, 467362306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 467462306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 467562306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 467662306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 467762306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 467862306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 467962306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 468062306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 468162306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 468262306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 468362306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 468462306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 468562306a36Sopenharmony_ci .port_max_speed_mode = mv88e6390_port_max_speed_mode, 468662306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 468762306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 468862306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 468962306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 469062306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 469162306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 469262306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 469362306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 469462306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 469562306a36Sopenharmony_ci .port_set_cmode = mv88e6390_port_set_cmode, 469662306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 469762306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 469862306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 469962306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 470062306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 470162306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 470262306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 470362306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 470462306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 470562306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 470662306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 470762306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 470862306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 470962306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 471062306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 471162306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 471262306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 471362306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 471462306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 471562306a36Sopenharmony_ci .serdes_get_lane = mv88e6390_serdes_get_lane, 471662306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 471762306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 471862306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 471962306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 472062306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 472162306a36Sopenharmony_ci .avb_ops = &mv88e6390_avb_ops, 472262306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 472362306a36Sopenharmony_ci .phylink_get_caps = mv88e6390_phylink_get_caps, 472462306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 472562306a36Sopenharmony_ci}; 472662306a36Sopenharmony_ci 472762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6240_ops = { 472862306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6352 */ 472962306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 473062306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 473162306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 473262306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 473362306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 473462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 473562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 473662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 473762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 473862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 473962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 474062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 474162306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 474262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 474362306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 474462306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 474562306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 474662306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 474762306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 474862306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 474962306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 475062306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 475162306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 475262306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 475362306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 475462306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 475562306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 475662306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 475762306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 475862306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 475962306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 476062306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 476162306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 476262306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 476362306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 476462306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 476562306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 476662306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 476762306a36Sopenharmony_ci .rmu_disable = mv88e6352_g1_rmu_disable, 476862306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 476962306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 477062306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 477162306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 477262306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 477362306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 477462306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 477562306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 477662306a36Sopenharmony_ci .serdes_get_regs = mv88e6352_serdes_get_regs, 477762306a36Sopenharmony_ci .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, 477862306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 477962306a36Sopenharmony_ci .avb_ops = &mv88e6352_avb_ops, 478062306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 478162306a36Sopenharmony_ci .phylink_get_caps = mv88e6352_phylink_get_caps, 478262306a36Sopenharmony_ci .pcs_ops = &mv88e6352_pcs_ops, 478362306a36Sopenharmony_ci}; 478462306a36Sopenharmony_ci 478562306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6250_ops = { 478662306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6250 */ 478762306a36Sopenharmony_ci .ieee_pri_map = mv88e6250_g1_ieee_pri_map, 478862306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 478962306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 479062306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 479162306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 479262306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 479362306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 479462306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 479562306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 479662306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 479762306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 479862306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 479962306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 480062306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, 480162306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 480262306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 480362306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 480462306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 480562306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 480662306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 480762306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 480862306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 480962306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 481062306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 481162306a36Sopenharmony_ci .stats_get_sset_count = mv88e6250_stats_get_sset_count, 481262306a36Sopenharmony_ci .stats_get_strings = mv88e6250_stats_get_strings, 481362306a36Sopenharmony_ci .stats_get_stats = mv88e6250_stats_get_stats, 481462306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 481562306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 481662306a36Sopenharmony_ci .watchdog_ops = &mv88e6250_watchdog_ops, 481762306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 481862306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 481962306a36Sopenharmony_ci .reset = mv88e6250_g1_reset, 482062306a36Sopenharmony_ci .vtu_getnext = mv88e6185_g1_vtu_getnext, 482162306a36Sopenharmony_ci .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 482262306a36Sopenharmony_ci .avb_ops = &mv88e6352_avb_ops, 482362306a36Sopenharmony_ci .ptp_ops = &mv88e6250_ptp_ops, 482462306a36Sopenharmony_ci .phylink_get_caps = mv88e6250_phylink_get_caps, 482562306a36Sopenharmony_ci .set_max_frame_size = mv88e6185_g1_set_max_frame_size, 482662306a36Sopenharmony_ci}; 482762306a36Sopenharmony_ci 482862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6290_ops = { 482962306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6390 */ 483062306a36Sopenharmony_ci .setup_errata = mv88e6390_setup_errata, 483162306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 483262306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 483362306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 483462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 483562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 483662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 483762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 483862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 483962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 484062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 484162306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 484262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 484362306a36Sopenharmony_ci .port_max_speed_mode = mv88e6390_port_max_speed_mode, 484462306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 484562306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 484662306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 484762306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 484862306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 484962306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 485062306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 485162306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 485262306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 485362306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 485462306a36Sopenharmony_ci .port_set_cmode = mv88e6390_port_set_cmode, 485562306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 485662306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 485762306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 485862306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 485962306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 486062306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 486162306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 486262306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 486362306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 486462306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 486562306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 486662306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 486762306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 486862306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 486962306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 487062306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 487162306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 487262306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 487362306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 487462306a36Sopenharmony_ci .serdes_get_lane = mv88e6390_serdes_get_lane, 487562306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 487662306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 487762306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 487862306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 487962306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 488062306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 488162306a36Sopenharmony_ci .avb_ops = &mv88e6390_avb_ops, 488262306a36Sopenharmony_ci .ptp_ops = &mv88e6390_ptp_ops, 488362306a36Sopenharmony_ci .phylink_get_caps = mv88e6390_phylink_get_caps, 488462306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 488562306a36Sopenharmony_ci}; 488662306a36Sopenharmony_ci 488762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6320_ops = { 488862306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6320 */ 488962306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 489062306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 489162306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 489262306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 489362306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 489462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 489562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 489662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 489762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 489862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 489962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 490062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 490162306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, 490262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 490362306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 490462306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 490562306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 490662306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 490762306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 490862306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 490962306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 491062306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 491162306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 491262306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 491362306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 491462306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 491562306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 491662306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 491762306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 491862306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 491962306a36Sopenharmony_ci .stats_get_stats = mv88e6320_stats_get_stats, 492062306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 492162306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 492262306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 492362306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 492462306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 492562306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 492662306a36Sopenharmony_ci .vtu_getnext = mv88e6185_g1_vtu_getnext, 492762306a36Sopenharmony_ci .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 492862306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 492962306a36Sopenharmony_ci .avb_ops = &mv88e6352_avb_ops, 493062306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 493162306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 493262306a36Sopenharmony_ci}; 493362306a36Sopenharmony_ci 493462306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6321_ops = { 493562306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6320 */ 493662306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 493762306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 493862306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 493962306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 494062306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 494162306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 494262306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 494362306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 494462306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 494562306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 494662306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 494762306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 494862306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, 494962306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 495062306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 495162306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 495262306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 495362306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 495462306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 495562306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 495662306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 495762306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 495862306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 495962306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 496062306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 496162306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 496262306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 496362306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 496462306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 496562306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 496662306a36Sopenharmony_ci .stats_get_stats = mv88e6320_stats_get_stats, 496762306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 496862306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 496962306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 497062306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 497162306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 497262306a36Sopenharmony_ci .vtu_getnext = mv88e6185_g1_vtu_getnext, 497362306a36Sopenharmony_ci .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, 497462306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 497562306a36Sopenharmony_ci .avb_ops = &mv88e6352_avb_ops, 497662306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 497762306a36Sopenharmony_ci .phylink_get_caps = mv88e6185_phylink_get_caps, 497862306a36Sopenharmony_ci}; 497962306a36Sopenharmony_ci 498062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6341_ops = { 498162306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6341 */ 498262306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 498362306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 498462306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 498562306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 498662306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 498762306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 498862306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 498962306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 499062306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 499162306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 499262306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 499362306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 499462306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 499562306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, 499662306a36Sopenharmony_ci .port_max_speed_mode = mv88e6341_port_max_speed_mode, 499762306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 499862306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 499962306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 500062306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 500162306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 500262306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 500362306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 500462306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 500562306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 500662306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 500762306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 500862306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 500962306a36Sopenharmony_ci .port_set_cmode = mv88e6341_port_set_cmode, 501062306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 501162306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 501262306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 501362306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 501462306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 501562306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 501662306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 501762306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 501862306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 501962306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 502062306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 502162306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 502262306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 502362306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 502462306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 502562306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 502662306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 502762306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 502862306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 502962306a36Sopenharmony_ci .serdes_get_lane = mv88e6341_serdes_get_lane, 503062306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 503162306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 503262306a36Sopenharmony_ci .avb_ops = &mv88e6390_avb_ops, 503362306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 503462306a36Sopenharmony_ci .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 503562306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 503662306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 503762306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 503862306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 503962306a36Sopenharmony_ci .phylink_get_caps = mv88e6341_phylink_get_caps, 504062306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 504162306a36Sopenharmony_ci}; 504262306a36Sopenharmony_ci 504362306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6350_ops = { 504462306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6351 */ 504562306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 504662306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 504762306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 504862306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 504962306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 505062306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 505162306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 505262306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 505362306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 505462306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 505562306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 505662306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 505762306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 505862306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 505962306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 506062306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 506162306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 506262306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 506362306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 506462306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 506562306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 506662306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 506762306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 506862306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 506962306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 507062306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 507162306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 507262306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 507362306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 507462306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 507562306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 507662306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 507762306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 507862306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 507962306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 508062306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 508162306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 508262306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 508362306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 508462306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 508562306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 508662306a36Sopenharmony_ci .phylink_get_caps = mv88e6351_phylink_get_caps, 508762306a36Sopenharmony_ci}; 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6351_ops = { 509062306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6351 */ 509162306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 509262306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 509362306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 509462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 509562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 509662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 509762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 509862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 509962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 510062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 510162306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 510262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, 510362306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 510462306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 510562306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 510662306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 510762306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 510862306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 510962306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 511062306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 511162306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 511262306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 511362306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 511462306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 511562306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 511662306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 511762306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 511862306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 511962306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 512062306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 512162306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 512262306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 512362306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 512462306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 512562306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 512662306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 512762306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 512862306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 512962306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 513062306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 513162306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 513262306a36Sopenharmony_ci .avb_ops = &mv88e6352_avb_ops, 513362306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 513462306a36Sopenharmony_ci .phylink_get_caps = mv88e6351_phylink_get_caps, 513562306a36Sopenharmony_ci}; 513662306a36Sopenharmony_ci 513762306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6352_ops = { 513862306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6352 */ 513962306a36Sopenharmony_ci .ieee_pri_map = mv88e6085_g1_ieee_pri_map, 514062306a36Sopenharmony_ci .ip_pri_map = mv88e6085_g1_ip_pri_map, 514162306a36Sopenharmony_ci .irl_init_all = mv88e6352_g2_irl_init_all, 514262306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom16, 514362306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom16, 514462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 514562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 514662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 514762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 514862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 514962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 515062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 515162306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, 515262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, 515362306a36Sopenharmony_ci .port_tag_remap = mv88e6095_port_tag_remap, 515462306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 515562306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 515662306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 515762306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 515862306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 515962306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 516062306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 516162306a36Sopenharmony_ci .port_pause_limit = mv88e6097_port_pause_limit, 516262306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 516362306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 516462306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 516562306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 516662306a36Sopenharmony_ci .stats_snapshot = mv88e6320_g1_stats_snapshot, 516762306a36Sopenharmony_ci .stats_set_histogram = mv88e6095_g1_stats_set_histogram, 516862306a36Sopenharmony_ci .stats_get_sset_count = mv88e6095_stats_get_sset_count, 516962306a36Sopenharmony_ci .stats_get_strings = mv88e6095_stats_get_strings, 517062306a36Sopenharmony_ci .stats_get_stats = mv88e6095_stats_get_stats, 517162306a36Sopenharmony_ci .set_cpu_port = mv88e6095_g1_set_cpu_port, 517262306a36Sopenharmony_ci .set_egress_port = mv88e6095_g1_set_egress_port, 517362306a36Sopenharmony_ci .watchdog_ops = &mv88e6097_watchdog_ops, 517462306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, 517562306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 517662306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 517762306a36Sopenharmony_ci .rmu_disable = mv88e6352_g1_rmu_disable, 517862306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 517962306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 518062306a36Sopenharmony_ci .vtu_getnext = mv88e6352_g1_vtu_getnext, 518162306a36Sopenharmony_ci .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 518262306a36Sopenharmony_ci .stu_getnext = mv88e6352_g1_stu_getnext, 518362306a36Sopenharmony_ci .stu_loadpurge = mv88e6352_g1_stu_loadpurge, 518462306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, 518562306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 518662306a36Sopenharmony_ci .avb_ops = &mv88e6352_avb_ops, 518762306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 518862306a36Sopenharmony_ci .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, 518962306a36Sopenharmony_ci .serdes_get_strings = mv88e6352_serdes_get_strings, 519062306a36Sopenharmony_ci .serdes_get_stats = mv88e6352_serdes_get_stats, 519162306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, 519262306a36Sopenharmony_ci .serdes_get_regs = mv88e6352_serdes_get_regs, 519362306a36Sopenharmony_ci .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, 519462306a36Sopenharmony_ci .phylink_get_caps = mv88e6352_phylink_get_caps, 519562306a36Sopenharmony_ci .pcs_ops = &mv88e6352_pcs_ops, 519662306a36Sopenharmony_ci}; 519762306a36Sopenharmony_ci 519862306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6390_ops = { 519962306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6390 */ 520062306a36Sopenharmony_ci .setup_errata = mv88e6390_setup_errata, 520162306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 520262306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 520362306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 520462306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 520562306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 520662306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 520762306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 520862306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 520962306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 521062306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 521162306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 521262306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, 521362306a36Sopenharmony_ci .port_max_speed_mode = mv88e6390_port_max_speed_mode, 521462306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 521562306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 521662306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 521762306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 521862306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 521962306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 522062306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 522162306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 522262306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 522362306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 522462306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 522562306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 522662306a36Sopenharmony_ci .port_set_cmode = mv88e6390_port_set_cmode, 522762306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 522862306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 522962306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 523062306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 523162306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 523262306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 523362306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 523462306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 523562306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 523662306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 523762306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 523862306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 523962306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 524062306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 524162306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 524262306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 524362306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 524462306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 524562306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 524662306a36Sopenharmony_ci .serdes_get_lane = mv88e6390_serdes_get_lane, 524762306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 524862306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 524962306a36Sopenharmony_ci .avb_ops = &mv88e6390_avb_ops, 525062306a36Sopenharmony_ci .ptp_ops = &mv88e6390_ptp_ops, 525162306a36Sopenharmony_ci .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 525262306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 525362306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 525462306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 525562306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 525662306a36Sopenharmony_ci .phylink_get_caps = mv88e6390_phylink_get_caps, 525762306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 525862306a36Sopenharmony_ci}; 525962306a36Sopenharmony_ci 526062306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6390x_ops = { 526162306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6390 */ 526262306a36Sopenharmony_ci .setup_errata = mv88e6390_setup_errata, 526362306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 526462306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 526562306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 526662306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 526762306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 526862306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 526962306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 527062306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 527162306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 527262306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 527362306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 527462306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, 527562306a36Sopenharmony_ci .port_max_speed_mode = mv88e6390x_port_max_speed_mode, 527662306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 527762306a36Sopenharmony_ci .port_set_policy = mv88e6352_port_set_policy, 527862306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 527962306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 528062306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 528162306a36Sopenharmony_ci .port_set_ether_type = mv88e6351_port_set_ether_type, 528262306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 528362306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 528462306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 528562306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 528662306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 528762306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 528862306a36Sopenharmony_ci .port_set_cmode = mv88e6390x_port_set_cmode, 528962306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 529062306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 529162306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 529262306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 529362306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 529462306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 529562306a36Sopenharmony_ci .set_cpu_port = mv88e6390_g1_set_cpu_port, 529662306a36Sopenharmony_ci .set_egress_port = mv88e6390_g1_set_egress_port, 529762306a36Sopenharmony_ci .watchdog_ops = &mv88e6390_watchdog_ops, 529862306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, 529962306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 530062306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 530162306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 530262306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 530362306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 530462306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 530562306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 530662306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 530762306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 530862306a36Sopenharmony_ci .serdes_get_lane = mv88e6390x_serdes_get_lane, 530962306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 531062306a36Sopenharmony_ci .serdes_get_sset_count = mv88e6390_serdes_get_sset_count, 531162306a36Sopenharmony_ci .serdes_get_strings = mv88e6390_serdes_get_strings, 531262306a36Sopenharmony_ci .serdes_get_stats = mv88e6390_serdes_get_stats, 531362306a36Sopenharmony_ci .serdes_get_regs_len = mv88e6390_serdes_get_regs_len, 531462306a36Sopenharmony_ci .serdes_get_regs = mv88e6390_serdes_get_regs, 531562306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 531662306a36Sopenharmony_ci .avb_ops = &mv88e6390_avb_ops, 531762306a36Sopenharmony_ci .ptp_ops = &mv88e6390_ptp_ops, 531862306a36Sopenharmony_ci .phylink_get_caps = mv88e6390x_phylink_get_caps, 531962306a36Sopenharmony_ci .pcs_ops = &mv88e6390_pcs_ops, 532062306a36Sopenharmony_ci}; 532162306a36Sopenharmony_ci 532262306a36Sopenharmony_cistatic const struct mv88e6xxx_ops mv88e6393x_ops = { 532362306a36Sopenharmony_ci /* MV88E6XXX_FAMILY_6393 */ 532462306a36Sopenharmony_ci .irl_init_all = mv88e6390_g2_irl_init_all, 532562306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_g2_get_eeprom8, 532662306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_g2_set_eeprom8, 532762306a36Sopenharmony_ci .set_switch_mac = mv88e6xxx_g2_set_switch_mac, 532862306a36Sopenharmony_ci .phy_read = mv88e6xxx_g2_smi_phy_read_c22, 532962306a36Sopenharmony_ci .phy_write = mv88e6xxx_g2_smi_phy_write_c22, 533062306a36Sopenharmony_ci .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, 533162306a36Sopenharmony_ci .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, 533262306a36Sopenharmony_ci .port_set_link = mv88e6xxx_port_set_link, 533362306a36Sopenharmony_ci .port_sync_link = mv88e6xxx_port_sync_link, 533462306a36Sopenharmony_ci .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, 533562306a36Sopenharmony_ci .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex, 533662306a36Sopenharmony_ci .port_max_speed_mode = mv88e6393x_port_max_speed_mode, 533762306a36Sopenharmony_ci .port_tag_remap = mv88e6390_port_tag_remap, 533862306a36Sopenharmony_ci .port_set_policy = mv88e6393x_port_set_policy, 533962306a36Sopenharmony_ci .port_set_frame_mode = mv88e6351_port_set_frame_mode, 534062306a36Sopenharmony_ci .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, 534162306a36Sopenharmony_ci .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, 534262306a36Sopenharmony_ci .port_set_ether_type = mv88e6393x_port_set_ether_type, 534362306a36Sopenharmony_ci .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, 534462306a36Sopenharmony_ci .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, 534562306a36Sopenharmony_ci .port_pause_limit = mv88e6390_port_pause_limit, 534662306a36Sopenharmony_ci .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, 534762306a36Sopenharmony_ci .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, 534862306a36Sopenharmony_ci .port_get_cmode = mv88e6352_port_get_cmode, 534962306a36Sopenharmony_ci .port_set_cmode = mv88e6393x_port_set_cmode, 535062306a36Sopenharmony_ci .port_setup_message_port = mv88e6xxx_setup_message_port, 535162306a36Sopenharmony_ci .port_set_upstream_port = mv88e6393x_port_set_upstream_port, 535262306a36Sopenharmony_ci .stats_snapshot = mv88e6390_g1_stats_snapshot, 535362306a36Sopenharmony_ci .stats_set_histogram = mv88e6390_g1_stats_set_histogram, 535462306a36Sopenharmony_ci .stats_get_sset_count = mv88e6320_stats_get_sset_count, 535562306a36Sopenharmony_ci .stats_get_strings = mv88e6320_stats_get_strings, 535662306a36Sopenharmony_ci .stats_get_stats = mv88e6390_stats_get_stats, 535762306a36Sopenharmony_ci /* .set_cpu_port is missing because this family does not support a global 535862306a36Sopenharmony_ci * CPU port, only per port CPU port which is set via 535962306a36Sopenharmony_ci * .port_set_upstream_port method. 536062306a36Sopenharmony_ci */ 536162306a36Sopenharmony_ci .set_egress_port = mv88e6393x_set_egress_port, 536262306a36Sopenharmony_ci .watchdog_ops = &mv88e6393x_watchdog_ops, 536362306a36Sopenharmony_ci .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, 536462306a36Sopenharmony_ci .pot_clear = mv88e6xxx_g2_pot_clear, 536562306a36Sopenharmony_ci .reset = mv88e6352_g1_reset, 536662306a36Sopenharmony_ci .rmu_disable = mv88e6390_g1_rmu_disable, 536762306a36Sopenharmony_ci .atu_get_hash = mv88e6165_g1_atu_get_hash, 536862306a36Sopenharmony_ci .atu_set_hash = mv88e6165_g1_atu_set_hash, 536962306a36Sopenharmony_ci .vtu_getnext = mv88e6390_g1_vtu_getnext, 537062306a36Sopenharmony_ci .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 537162306a36Sopenharmony_ci .stu_getnext = mv88e6390_g1_stu_getnext, 537262306a36Sopenharmony_ci .stu_loadpurge = mv88e6390_g1_stu_loadpurge, 537362306a36Sopenharmony_ci .serdes_get_lane = mv88e6393x_serdes_get_lane, 537462306a36Sopenharmony_ci .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, 537562306a36Sopenharmony_ci /* TODO: serdes stats */ 537662306a36Sopenharmony_ci .gpio_ops = &mv88e6352_gpio_ops, 537762306a36Sopenharmony_ci .avb_ops = &mv88e6390_avb_ops, 537862306a36Sopenharmony_ci .ptp_ops = &mv88e6352_ptp_ops, 537962306a36Sopenharmony_ci .phylink_get_caps = mv88e6393x_phylink_get_caps, 538062306a36Sopenharmony_ci .pcs_ops = &mv88e6393x_pcs_ops, 538162306a36Sopenharmony_ci}; 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_cistatic const struct mv88e6xxx_info mv88e6xxx_table[] = { 538462306a36Sopenharmony_ci [MV88E6020] = { 538562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6020, 538662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6250, 538762306a36Sopenharmony_ci .name = "Marvell 88E6020", 538862306a36Sopenharmony_ci .num_databases = 64, 538962306a36Sopenharmony_ci .num_ports = 4, 539062306a36Sopenharmony_ci .num_internal_phys = 2, 539162306a36Sopenharmony_ci .max_vid = 4095, 539262306a36Sopenharmony_ci .port_base_addr = 0x8, 539362306a36Sopenharmony_ci .phy_base_addr = 0x0, 539462306a36Sopenharmony_ci .global1_addr = 0xf, 539562306a36Sopenharmony_ci .global2_addr = 0x7, 539662306a36Sopenharmony_ci .age_time_coeff = 15000, 539762306a36Sopenharmony_ci .g1_irqs = 9, 539862306a36Sopenharmony_ci .g2_irqs = 5, 539962306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 540062306a36Sopenharmony_ci .dual_chip = true, 540162306a36Sopenharmony_ci .ops = &mv88e6250_ops, 540262306a36Sopenharmony_ci }, 540362306a36Sopenharmony_ci 540462306a36Sopenharmony_ci [MV88E6071] = { 540562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6071, 540662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6250, 540762306a36Sopenharmony_ci .name = "Marvell 88E6071", 540862306a36Sopenharmony_ci .num_databases = 64, 540962306a36Sopenharmony_ci .num_ports = 7, 541062306a36Sopenharmony_ci .num_internal_phys = 5, 541162306a36Sopenharmony_ci .max_vid = 4095, 541262306a36Sopenharmony_ci .port_base_addr = 0x08, 541362306a36Sopenharmony_ci .phy_base_addr = 0x00, 541462306a36Sopenharmony_ci .global1_addr = 0x0f, 541562306a36Sopenharmony_ci .global2_addr = 0x07, 541662306a36Sopenharmony_ci .age_time_coeff = 15000, 541762306a36Sopenharmony_ci .g1_irqs = 9, 541862306a36Sopenharmony_ci .g2_irqs = 5, 541962306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 542062306a36Sopenharmony_ci .dual_chip = true, 542162306a36Sopenharmony_ci .ops = &mv88e6250_ops, 542262306a36Sopenharmony_ci }, 542362306a36Sopenharmony_ci 542462306a36Sopenharmony_ci [MV88E6085] = { 542562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, 542662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6097, 542762306a36Sopenharmony_ci .name = "Marvell 88E6085", 542862306a36Sopenharmony_ci .num_databases = 4096, 542962306a36Sopenharmony_ci .num_macs = 8192, 543062306a36Sopenharmony_ci .num_ports = 10, 543162306a36Sopenharmony_ci .num_internal_phys = 5, 543262306a36Sopenharmony_ci .max_vid = 4095, 543362306a36Sopenharmony_ci .max_sid = 63, 543462306a36Sopenharmony_ci .port_base_addr = 0x10, 543562306a36Sopenharmony_ci .phy_base_addr = 0x0, 543662306a36Sopenharmony_ci .global1_addr = 0x1b, 543762306a36Sopenharmony_ci .global2_addr = 0x1c, 543862306a36Sopenharmony_ci .age_time_coeff = 15000, 543962306a36Sopenharmony_ci .g1_irqs = 8, 544062306a36Sopenharmony_ci .g2_irqs = 10, 544162306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 544262306a36Sopenharmony_ci .pvt = true, 544362306a36Sopenharmony_ci .multi_chip = true, 544462306a36Sopenharmony_ci .ops = &mv88e6085_ops, 544562306a36Sopenharmony_ci }, 544662306a36Sopenharmony_ci 544762306a36Sopenharmony_ci [MV88E6095] = { 544862306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, 544962306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6095, 545062306a36Sopenharmony_ci .name = "Marvell 88E6095/88E6095F", 545162306a36Sopenharmony_ci .num_databases = 256, 545262306a36Sopenharmony_ci .num_macs = 8192, 545362306a36Sopenharmony_ci .num_ports = 11, 545462306a36Sopenharmony_ci .num_internal_phys = 0, 545562306a36Sopenharmony_ci .max_vid = 4095, 545662306a36Sopenharmony_ci .port_base_addr = 0x10, 545762306a36Sopenharmony_ci .phy_base_addr = 0x0, 545862306a36Sopenharmony_ci .global1_addr = 0x1b, 545962306a36Sopenharmony_ci .global2_addr = 0x1c, 546062306a36Sopenharmony_ci .age_time_coeff = 15000, 546162306a36Sopenharmony_ci .g1_irqs = 8, 546262306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 546362306a36Sopenharmony_ci .multi_chip = true, 546462306a36Sopenharmony_ci .ops = &mv88e6095_ops, 546562306a36Sopenharmony_ci }, 546662306a36Sopenharmony_ci 546762306a36Sopenharmony_ci [MV88E6097] = { 546862306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, 546962306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6097, 547062306a36Sopenharmony_ci .name = "Marvell 88E6097/88E6097F", 547162306a36Sopenharmony_ci .num_databases = 4096, 547262306a36Sopenharmony_ci .num_macs = 8192, 547362306a36Sopenharmony_ci .num_ports = 11, 547462306a36Sopenharmony_ci .num_internal_phys = 8, 547562306a36Sopenharmony_ci .max_vid = 4095, 547662306a36Sopenharmony_ci .max_sid = 63, 547762306a36Sopenharmony_ci .port_base_addr = 0x10, 547862306a36Sopenharmony_ci .phy_base_addr = 0x0, 547962306a36Sopenharmony_ci .global1_addr = 0x1b, 548062306a36Sopenharmony_ci .global2_addr = 0x1c, 548162306a36Sopenharmony_ci .age_time_coeff = 15000, 548262306a36Sopenharmony_ci .g1_irqs = 8, 548362306a36Sopenharmony_ci .g2_irqs = 10, 548462306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 548562306a36Sopenharmony_ci .pvt = true, 548662306a36Sopenharmony_ci .multi_chip = true, 548762306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 548862306a36Sopenharmony_ci .ops = &mv88e6097_ops, 548962306a36Sopenharmony_ci }, 549062306a36Sopenharmony_ci 549162306a36Sopenharmony_ci [MV88E6123] = { 549262306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, 549362306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6165, 549462306a36Sopenharmony_ci .name = "Marvell 88E6123", 549562306a36Sopenharmony_ci .num_databases = 4096, 549662306a36Sopenharmony_ci .num_macs = 1024, 549762306a36Sopenharmony_ci .num_ports = 3, 549862306a36Sopenharmony_ci .num_internal_phys = 5, 549962306a36Sopenharmony_ci .max_vid = 4095, 550062306a36Sopenharmony_ci .max_sid = 63, 550162306a36Sopenharmony_ci .port_base_addr = 0x10, 550262306a36Sopenharmony_ci .phy_base_addr = 0x0, 550362306a36Sopenharmony_ci .global1_addr = 0x1b, 550462306a36Sopenharmony_ci .global2_addr = 0x1c, 550562306a36Sopenharmony_ci .age_time_coeff = 15000, 550662306a36Sopenharmony_ci .g1_irqs = 9, 550762306a36Sopenharmony_ci .g2_irqs = 10, 550862306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 550962306a36Sopenharmony_ci .pvt = true, 551062306a36Sopenharmony_ci .multi_chip = true, 551162306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 551262306a36Sopenharmony_ci .ops = &mv88e6123_ops, 551362306a36Sopenharmony_ci }, 551462306a36Sopenharmony_ci 551562306a36Sopenharmony_ci [MV88E6131] = { 551662306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, 551762306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6185, 551862306a36Sopenharmony_ci .name = "Marvell 88E6131", 551962306a36Sopenharmony_ci .num_databases = 256, 552062306a36Sopenharmony_ci .num_macs = 8192, 552162306a36Sopenharmony_ci .num_ports = 8, 552262306a36Sopenharmony_ci .num_internal_phys = 0, 552362306a36Sopenharmony_ci .max_vid = 4095, 552462306a36Sopenharmony_ci .port_base_addr = 0x10, 552562306a36Sopenharmony_ci .phy_base_addr = 0x0, 552662306a36Sopenharmony_ci .global1_addr = 0x1b, 552762306a36Sopenharmony_ci .global2_addr = 0x1c, 552862306a36Sopenharmony_ci .age_time_coeff = 15000, 552962306a36Sopenharmony_ci .g1_irqs = 9, 553062306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 553162306a36Sopenharmony_ci .multi_chip = true, 553262306a36Sopenharmony_ci .ops = &mv88e6131_ops, 553362306a36Sopenharmony_ci }, 553462306a36Sopenharmony_ci 553562306a36Sopenharmony_ci [MV88E6141] = { 553662306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, 553762306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6341, 553862306a36Sopenharmony_ci .name = "Marvell 88E6141", 553962306a36Sopenharmony_ci .num_databases = 4096, 554062306a36Sopenharmony_ci .num_macs = 2048, 554162306a36Sopenharmony_ci .num_ports = 6, 554262306a36Sopenharmony_ci .num_internal_phys = 5, 554362306a36Sopenharmony_ci .num_gpio = 11, 554462306a36Sopenharmony_ci .max_vid = 4095, 554562306a36Sopenharmony_ci .max_sid = 63, 554662306a36Sopenharmony_ci .port_base_addr = 0x10, 554762306a36Sopenharmony_ci .phy_base_addr = 0x10, 554862306a36Sopenharmony_ci .global1_addr = 0x1b, 554962306a36Sopenharmony_ci .global2_addr = 0x1c, 555062306a36Sopenharmony_ci .age_time_coeff = 3750, 555162306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 555262306a36Sopenharmony_ci .g1_irqs = 9, 555362306a36Sopenharmony_ci .g2_irqs = 10, 555462306a36Sopenharmony_ci .pvt = true, 555562306a36Sopenharmony_ci .multi_chip = true, 555662306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 555762306a36Sopenharmony_ci .ops = &mv88e6141_ops, 555862306a36Sopenharmony_ci }, 555962306a36Sopenharmony_ci 556062306a36Sopenharmony_ci [MV88E6161] = { 556162306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, 556262306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6165, 556362306a36Sopenharmony_ci .name = "Marvell 88E6161", 556462306a36Sopenharmony_ci .num_databases = 4096, 556562306a36Sopenharmony_ci .num_macs = 1024, 556662306a36Sopenharmony_ci .num_ports = 6, 556762306a36Sopenharmony_ci .num_internal_phys = 5, 556862306a36Sopenharmony_ci .max_vid = 4095, 556962306a36Sopenharmony_ci .max_sid = 63, 557062306a36Sopenharmony_ci .port_base_addr = 0x10, 557162306a36Sopenharmony_ci .phy_base_addr = 0x0, 557262306a36Sopenharmony_ci .global1_addr = 0x1b, 557362306a36Sopenharmony_ci .global2_addr = 0x1c, 557462306a36Sopenharmony_ci .age_time_coeff = 15000, 557562306a36Sopenharmony_ci .g1_irqs = 9, 557662306a36Sopenharmony_ci .g2_irqs = 10, 557762306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 557862306a36Sopenharmony_ci .pvt = true, 557962306a36Sopenharmony_ci .multi_chip = true, 558062306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 558162306a36Sopenharmony_ci .ptp_support = true, 558262306a36Sopenharmony_ci .ops = &mv88e6161_ops, 558362306a36Sopenharmony_ci }, 558462306a36Sopenharmony_ci 558562306a36Sopenharmony_ci [MV88E6165] = { 558662306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, 558762306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6165, 558862306a36Sopenharmony_ci .name = "Marvell 88E6165", 558962306a36Sopenharmony_ci .num_databases = 4096, 559062306a36Sopenharmony_ci .num_macs = 8192, 559162306a36Sopenharmony_ci .num_ports = 6, 559262306a36Sopenharmony_ci .num_internal_phys = 0, 559362306a36Sopenharmony_ci .max_vid = 4095, 559462306a36Sopenharmony_ci .max_sid = 63, 559562306a36Sopenharmony_ci .port_base_addr = 0x10, 559662306a36Sopenharmony_ci .phy_base_addr = 0x0, 559762306a36Sopenharmony_ci .global1_addr = 0x1b, 559862306a36Sopenharmony_ci .global2_addr = 0x1c, 559962306a36Sopenharmony_ci .age_time_coeff = 15000, 560062306a36Sopenharmony_ci .g1_irqs = 9, 560162306a36Sopenharmony_ci .g2_irqs = 10, 560262306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 560362306a36Sopenharmony_ci .pvt = true, 560462306a36Sopenharmony_ci .multi_chip = true, 560562306a36Sopenharmony_ci .ptp_support = true, 560662306a36Sopenharmony_ci .ops = &mv88e6165_ops, 560762306a36Sopenharmony_ci }, 560862306a36Sopenharmony_ci 560962306a36Sopenharmony_ci [MV88E6171] = { 561062306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, 561162306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6351, 561262306a36Sopenharmony_ci .name = "Marvell 88E6171", 561362306a36Sopenharmony_ci .num_databases = 4096, 561462306a36Sopenharmony_ci .num_macs = 8192, 561562306a36Sopenharmony_ci .num_ports = 7, 561662306a36Sopenharmony_ci .num_internal_phys = 5, 561762306a36Sopenharmony_ci .max_vid = 4095, 561862306a36Sopenharmony_ci .max_sid = 63, 561962306a36Sopenharmony_ci .port_base_addr = 0x10, 562062306a36Sopenharmony_ci .phy_base_addr = 0x0, 562162306a36Sopenharmony_ci .global1_addr = 0x1b, 562262306a36Sopenharmony_ci .global2_addr = 0x1c, 562362306a36Sopenharmony_ci .age_time_coeff = 15000, 562462306a36Sopenharmony_ci .g1_irqs = 9, 562562306a36Sopenharmony_ci .g2_irqs = 10, 562662306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 562762306a36Sopenharmony_ci .pvt = true, 562862306a36Sopenharmony_ci .multi_chip = true, 562962306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 563062306a36Sopenharmony_ci .ops = &mv88e6171_ops, 563162306a36Sopenharmony_ci }, 563262306a36Sopenharmony_ci 563362306a36Sopenharmony_ci [MV88E6172] = { 563462306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, 563562306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6352, 563662306a36Sopenharmony_ci .name = "Marvell 88E6172", 563762306a36Sopenharmony_ci .num_databases = 4096, 563862306a36Sopenharmony_ci .num_macs = 8192, 563962306a36Sopenharmony_ci .num_ports = 7, 564062306a36Sopenharmony_ci .num_internal_phys = 5, 564162306a36Sopenharmony_ci .num_gpio = 15, 564262306a36Sopenharmony_ci .max_vid = 4095, 564362306a36Sopenharmony_ci .max_sid = 63, 564462306a36Sopenharmony_ci .port_base_addr = 0x10, 564562306a36Sopenharmony_ci .phy_base_addr = 0x0, 564662306a36Sopenharmony_ci .global1_addr = 0x1b, 564762306a36Sopenharmony_ci .global2_addr = 0x1c, 564862306a36Sopenharmony_ci .age_time_coeff = 15000, 564962306a36Sopenharmony_ci .g1_irqs = 9, 565062306a36Sopenharmony_ci .g2_irqs = 10, 565162306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 565262306a36Sopenharmony_ci .pvt = true, 565362306a36Sopenharmony_ci .multi_chip = true, 565462306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 565562306a36Sopenharmony_ci .ops = &mv88e6172_ops, 565662306a36Sopenharmony_ci }, 565762306a36Sopenharmony_ci 565862306a36Sopenharmony_ci [MV88E6175] = { 565962306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, 566062306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6351, 566162306a36Sopenharmony_ci .name = "Marvell 88E6175", 566262306a36Sopenharmony_ci .num_databases = 4096, 566362306a36Sopenharmony_ci .num_macs = 8192, 566462306a36Sopenharmony_ci .num_ports = 7, 566562306a36Sopenharmony_ci .num_internal_phys = 5, 566662306a36Sopenharmony_ci .max_vid = 4095, 566762306a36Sopenharmony_ci .max_sid = 63, 566862306a36Sopenharmony_ci .port_base_addr = 0x10, 566962306a36Sopenharmony_ci .phy_base_addr = 0x0, 567062306a36Sopenharmony_ci .global1_addr = 0x1b, 567162306a36Sopenharmony_ci .global2_addr = 0x1c, 567262306a36Sopenharmony_ci .age_time_coeff = 15000, 567362306a36Sopenharmony_ci .g1_irqs = 9, 567462306a36Sopenharmony_ci .g2_irqs = 10, 567562306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 567662306a36Sopenharmony_ci .pvt = true, 567762306a36Sopenharmony_ci .multi_chip = true, 567862306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 567962306a36Sopenharmony_ci .ops = &mv88e6175_ops, 568062306a36Sopenharmony_ci }, 568162306a36Sopenharmony_ci 568262306a36Sopenharmony_ci [MV88E6176] = { 568362306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, 568462306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6352, 568562306a36Sopenharmony_ci .name = "Marvell 88E6176", 568662306a36Sopenharmony_ci .num_databases = 4096, 568762306a36Sopenharmony_ci .num_macs = 8192, 568862306a36Sopenharmony_ci .num_ports = 7, 568962306a36Sopenharmony_ci .num_internal_phys = 5, 569062306a36Sopenharmony_ci .num_gpio = 15, 569162306a36Sopenharmony_ci .max_vid = 4095, 569262306a36Sopenharmony_ci .max_sid = 63, 569362306a36Sopenharmony_ci .port_base_addr = 0x10, 569462306a36Sopenharmony_ci .phy_base_addr = 0x0, 569562306a36Sopenharmony_ci .global1_addr = 0x1b, 569662306a36Sopenharmony_ci .global2_addr = 0x1c, 569762306a36Sopenharmony_ci .age_time_coeff = 15000, 569862306a36Sopenharmony_ci .g1_irqs = 9, 569962306a36Sopenharmony_ci .g2_irqs = 10, 570062306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 570162306a36Sopenharmony_ci .pvt = true, 570262306a36Sopenharmony_ci .multi_chip = true, 570362306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 570462306a36Sopenharmony_ci .ops = &mv88e6176_ops, 570562306a36Sopenharmony_ci }, 570662306a36Sopenharmony_ci 570762306a36Sopenharmony_ci [MV88E6185] = { 570862306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, 570962306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6185, 571062306a36Sopenharmony_ci .name = "Marvell 88E6185", 571162306a36Sopenharmony_ci .num_databases = 256, 571262306a36Sopenharmony_ci .num_macs = 8192, 571362306a36Sopenharmony_ci .num_ports = 10, 571462306a36Sopenharmony_ci .num_internal_phys = 0, 571562306a36Sopenharmony_ci .max_vid = 4095, 571662306a36Sopenharmony_ci .port_base_addr = 0x10, 571762306a36Sopenharmony_ci .phy_base_addr = 0x0, 571862306a36Sopenharmony_ci .global1_addr = 0x1b, 571962306a36Sopenharmony_ci .global2_addr = 0x1c, 572062306a36Sopenharmony_ci .age_time_coeff = 15000, 572162306a36Sopenharmony_ci .g1_irqs = 8, 572262306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 572362306a36Sopenharmony_ci .multi_chip = true, 572462306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 572562306a36Sopenharmony_ci .ops = &mv88e6185_ops, 572662306a36Sopenharmony_ci }, 572762306a36Sopenharmony_ci 572862306a36Sopenharmony_ci [MV88E6190] = { 572962306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, 573062306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6390, 573162306a36Sopenharmony_ci .name = "Marvell 88E6190", 573262306a36Sopenharmony_ci .num_databases = 4096, 573362306a36Sopenharmony_ci .num_macs = 16384, 573462306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 573562306a36Sopenharmony_ci .num_internal_phys = 9, 573662306a36Sopenharmony_ci .num_gpio = 16, 573762306a36Sopenharmony_ci .max_vid = 8191, 573862306a36Sopenharmony_ci .max_sid = 63, 573962306a36Sopenharmony_ci .port_base_addr = 0x0, 574062306a36Sopenharmony_ci .phy_base_addr = 0x0, 574162306a36Sopenharmony_ci .global1_addr = 0x1b, 574262306a36Sopenharmony_ci .global2_addr = 0x1c, 574362306a36Sopenharmony_ci .age_time_coeff = 3750, 574462306a36Sopenharmony_ci .g1_irqs = 9, 574562306a36Sopenharmony_ci .g2_irqs = 14, 574662306a36Sopenharmony_ci .pvt = true, 574762306a36Sopenharmony_ci .multi_chip = true, 574862306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 574962306a36Sopenharmony_ci .ops = &mv88e6190_ops, 575062306a36Sopenharmony_ci }, 575162306a36Sopenharmony_ci 575262306a36Sopenharmony_ci [MV88E6190X] = { 575362306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, 575462306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6390, 575562306a36Sopenharmony_ci .name = "Marvell 88E6190X", 575662306a36Sopenharmony_ci .num_databases = 4096, 575762306a36Sopenharmony_ci .num_macs = 16384, 575862306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 575962306a36Sopenharmony_ci .num_internal_phys = 9, 576062306a36Sopenharmony_ci .num_gpio = 16, 576162306a36Sopenharmony_ci .max_vid = 8191, 576262306a36Sopenharmony_ci .max_sid = 63, 576362306a36Sopenharmony_ci .port_base_addr = 0x0, 576462306a36Sopenharmony_ci .phy_base_addr = 0x0, 576562306a36Sopenharmony_ci .global1_addr = 0x1b, 576662306a36Sopenharmony_ci .global2_addr = 0x1c, 576762306a36Sopenharmony_ci .age_time_coeff = 3750, 576862306a36Sopenharmony_ci .g1_irqs = 9, 576962306a36Sopenharmony_ci .g2_irqs = 14, 577062306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 577162306a36Sopenharmony_ci .pvt = true, 577262306a36Sopenharmony_ci .multi_chip = true, 577362306a36Sopenharmony_ci .ops = &mv88e6190x_ops, 577462306a36Sopenharmony_ci }, 577562306a36Sopenharmony_ci 577662306a36Sopenharmony_ci [MV88E6191] = { 577762306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, 577862306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6390, 577962306a36Sopenharmony_ci .name = "Marvell 88E6191", 578062306a36Sopenharmony_ci .num_databases = 4096, 578162306a36Sopenharmony_ci .num_macs = 16384, 578262306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 578362306a36Sopenharmony_ci .num_internal_phys = 9, 578462306a36Sopenharmony_ci .max_vid = 8191, 578562306a36Sopenharmony_ci .max_sid = 63, 578662306a36Sopenharmony_ci .port_base_addr = 0x0, 578762306a36Sopenharmony_ci .phy_base_addr = 0x0, 578862306a36Sopenharmony_ci .global1_addr = 0x1b, 578962306a36Sopenharmony_ci .global2_addr = 0x1c, 579062306a36Sopenharmony_ci .age_time_coeff = 3750, 579162306a36Sopenharmony_ci .g1_irqs = 9, 579262306a36Sopenharmony_ci .g2_irqs = 14, 579362306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 579462306a36Sopenharmony_ci .pvt = true, 579562306a36Sopenharmony_ci .multi_chip = true, 579662306a36Sopenharmony_ci .ptp_support = true, 579762306a36Sopenharmony_ci .ops = &mv88e6191_ops, 579862306a36Sopenharmony_ci }, 579962306a36Sopenharmony_ci 580062306a36Sopenharmony_ci [MV88E6191X] = { 580162306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X, 580262306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6393, 580362306a36Sopenharmony_ci .name = "Marvell 88E6191X", 580462306a36Sopenharmony_ci .num_databases = 4096, 580562306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 580662306a36Sopenharmony_ci .num_internal_phys = 8, 580762306a36Sopenharmony_ci .internal_phys_offset = 1, 580862306a36Sopenharmony_ci .max_vid = 8191, 580962306a36Sopenharmony_ci .max_sid = 63, 581062306a36Sopenharmony_ci .port_base_addr = 0x0, 581162306a36Sopenharmony_ci .phy_base_addr = 0x0, 581262306a36Sopenharmony_ci .global1_addr = 0x1b, 581362306a36Sopenharmony_ci .global2_addr = 0x1c, 581462306a36Sopenharmony_ci .age_time_coeff = 3750, 581562306a36Sopenharmony_ci .g1_irqs = 10, 581662306a36Sopenharmony_ci .g2_irqs = 14, 581762306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 581862306a36Sopenharmony_ci .pvt = true, 581962306a36Sopenharmony_ci .multi_chip = true, 582062306a36Sopenharmony_ci .ptp_support = true, 582162306a36Sopenharmony_ci .ops = &mv88e6393x_ops, 582262306a36Sopenharmony_ci }, 582362306a36Sopenharmony_ci 582462306a36Sopenharmony_ci [MV88E6193X] = { 582562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X, 582662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6393, 582762306a36Sopenharmony_ci .name = "Marvell 88E6193X", 582862306a36Sopenharmony_ci .num_databases = 4096, 582962306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 583062306a36Sopenharmony_ci .num_internal_phys = 8, 583162306a36Sopenharmony_ci .internal_phys_offset = 1, 583262306a36Sopenharmony_ci .max_vid = 8191, 583362306a36Sopenharmony_ci .max_sid = 63, 583462306a36Sopenharmony_ci .port_base_addr = 0x0, 583562306a36Sopenharmony_ci .phy_base_addr = 0x0, 583662306a36Sopenharmony_ci .global1_addr = 0x1b, 583762306a36Sopenharmony_ci .global2_addr = 0x1c, 583862306a36Sopenharmony_ci .age_time_coeff = 3750, 583962306a36Sopenharmony_ci .g1_irqs = 10, 584062306a36Sopenharmony_ci .g2_irqs = 14, 584162306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 584262306a36Sopenharmony_ci .pvt = true, 584362306a36Sopenharmony_ci .multi_chip = true, 584462306a36Sopenharmony_ci .ptp_support = true, 584562306a36Sopenharmony_ci .ops = &mv88e6393x_ops, 584662306a36Sopenharmony_ci }, 584762306a36Sopenharmony_ci 584862306a36Sopenharmony_ci [MV88E6220] = { 584962306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220, 585062306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6250, 585162306a36Sopenharmony_ci .name = "Marvell 88E6220", 585262306a36Sopenharmony_ci .num_databases = 64, 585362306a36Sopenharmony_ci 585462306a36Sopenharmony_ci /* Ports 2-4 are not routed to pins 585562306a36Sopenharmony_ci * => usable ports 0, 1, 5, 6 585662306a36Sopenharmony_ci */ 585762306a36Sopenharmony_ci .num_ports = 7, 585862306a36Sopenharmony_ci .num_internal_phys = 2, 585962306a36Sopenharmony_ci .invalid_port_mask = BIT(2) | BIT(3) | BIT(4), 586062306a36Sopenharmony_ci .max_vid = 4095, 586162306a36Sopenharmony_ci .port_base_addr = 0x08, 586262306a36Sopenharmony_ci .phy_base_addr = 0x00, 586362306a36Sopenharmony_ci .global1_addr = 0x0f, 586462306a36Sopenharmony_ci .global2_addr = 0x07, 586562306a36Sopenharmony_ci .age_time_coeff = 15000, 586662306a36Sopenharmony_ci .g1_irqs = 9, 586762306a36Sopenharmony_ci .g2_irqs = 10, 586862306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 586962306a36Sopenharmony_ci .dual_chip = true, 587062306a36Sopenharmony_ci .ptp_support = true, 587162306a36Sopenharmony_ci .ops = &mv88e6250_ops, 587262306a36Sopenharmony_ci }, 587362306a36Sopenharmony_ci 587462306a36Sopenharmony_ci [MV88E6240] = { 587562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, 587662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6352, 587762306a36Sopenharmony_ci .name = "Marvell 88E6240", 587862306a36Sopenharmony_ci .num_databases = 4096, 587962306a36Sopenharmony_ci .num_macs = 8192, 588062306a36Sopenharmony_ci .num_ports = 7, 588162306a36Sopenharmony_ci .num_internal_phys = 5, 588262306a36Sopenharmony_ci .num_gpio = 15, 588362306a36Sopenharmony_ci .max_vid = 4095, 588462306a36Sopenharmony_ci .max_sid = 63, 588562306a36Sopenharmony_ci .port_base_addr = 0x10, 588662306a36Sopenharmony_ci .phy_base_addr = 0x0, 588762306a36Sopenharmony_ci .global1_addr = 0x1b, 588862306a36Sopenharmony_ci .global2_addr = 0x1c, 588962306a36Sopenharmony_ci .age_time_coeff = 15000, 589062306a36Sopenharmony_ci .g1_irqs = 9, 589162306a36Sopenharmony_ci .g2_irqs = 10, 589262306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 589362306a36Sopenharmony_ci .pvt = true, 589462306a36Sopenharmony_ci .multi_chip = true, 589562306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 589662306a36Sopenharmony_ci .ptp_support = true, 589762306a36Sopenharmony_ci .ops = &mv88e6240_ops, 589862306a36Sopenharmony_ci }, 589962306a36Sopenharmony_ci 590062306a36Sopenharmony_ci [MV88E6250] = { 590162306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250, 590262306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6250, 590362306a36Sopenharmony_ci .name = "Marvell 88E6250", 590462306a36Sopenharmony_ci .num_databases = 64, 590562306a36Sopenharmony_ci .num_ports = 7, 590662306a36Sopenharmony_ci .num_internal_phys = 5, 590762306a36Sopenharmony_ci .max_vid = 4095, 590862306a36Sopenharmony_ci .port_base_addr = 0x08, 590962306a36Sopenharmony_ci .phy_base_addr = 0x00, 591062306a36Sopenharmony_ci .global1_addr = 0x0f, 591162306a36Sopenharmony_ci .global2_addr = 0x07, 591262306a36Sopenharmony_ci .age_time_coeff = 15000, 591362306a36Sopenharmony_ci .g1_irqs = 9, 591462306a36Sopenharmony_ci .g2_irqs = 10, 591562306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 591662306a36Sopenharmony_ci .dual_chip = true, 591762306a36Sopenharmony_ci .ptp_support = true, 591862306a36Sopenharmony_ci .ops = &mv88e6250_ops, 591962306a36Sopenharmony_ci }, 592062306a36Sopenharmony_ci 592162306a36Sopenharmony_ci [MV88E6290] = { 592262306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, 592362306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6390, 592462306a36Sopenharmony_ci .name = "Marvell 88E6290", 592562306a36Sopenharmony_ci .num_databases = 4096, 592662306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 592762306a36Sopenharmony_ci .num_internal_phys = 9, 592862306a36Sopenharmony_ci .num_gpio = 16, 592962306a36Sopenharmony_ci .max_vid = 8191, 593062306a36Sopenharmony_ci .max_sid = 63, 593162306a36Sopenharmony_ci .port_base_addr = 0x0, 593262306a36Sopenharmony_ci .phy_base_addr = 0x0, 593362306a36Sopenharmony_ci .global1_addr = 0x1b, 593462306a36Sopenharmony_ci .global2_addr = 0x1c, 593562306a36Sopenharmony_ci .age_time_coeff = 3750, 593662306a36Sopenharmony_ci .g1_irqs = 9, 593762306a36Sopenharmony_ci .g2_irqs = 14, 593862306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 593962306a36Sopenharmony_ci .pvt = true, 594062306a36Sopenharmony_ci .multi_chip = true, 594162306a36Sopenharmony_ci .ptp_support = true, 594262306a36Sopenharmony_ci .ops = &mv88e6290_ops, 594362306a36Sopenharmony_ci }, 594462306a36Sopenharmony_ci 594562306a36Sopenharmony_ci [MV88E6320] = { 594662306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, 594762306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6320, 594862306a36Sopenharmony_ci .name = "Marvell 88E6320", 594962306a36Sopenharmony_ci .num_databases = 4096, 595062306a36Sopenharmony_ci .num_macs = 8192, 595162306a36Sopenharmony_ci .num_ports = 7, 595262306a36Sopenharmony_ci .num_internal_phys = 5, 595362306a36Sopenharmony_ci .num_gpio = 15, 595462306a36Sopenharmony_ci .max_vid = 4095, 595562306a36Sopenharmony_ci .port_base_addr = 0x10, 595662306a36Sopenharmony_ci .phy_base_addr = 0x0, 595762306a36Sopenharmony_ci .global1_addr = 0x1b, 595862306a36Sopenharmony_ci .global2_addr = 0x1c, 595962306a36Sopenharmony_ci .age_time_coeff = 15000, 596062306a36Sopenharmony_ci .g1_irqs = 8, 596162306a36Sopenharmony_ci .g2_irqs = 10, 596262306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 596362306a36Sopenharmony_ci .pvt = true, 596462306a36Sopenharmony_ci .multi_chip = true, 596562306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 596662306a36Sopenharmony_ci .ptp_support = true, 596762306a36Sopenharmony_ci .ops = &mv88e6320_ops, 596862306a36Sopenharmony_ci }, 596962306a36Sopenharmony_ci 597062306a36Sopenharmony_ci [MV88E6321] = { 597162306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, 597262306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6320, 597362306a36Sopenharmony_ci .name = "Marvell 88E6321", 597462306a36Sopenharmony_ci .num_databases = 4096, 597562306a36Sopenharmony_ci .num_macs = 8192, 597662306a36Sopenharmony_ci .num_ports = 7, 597762306a36Sopenharmony_ci .num_internal_phys = 5, 597862306a36Sopenharmony_ci .num_gpio = 15, 597962306a36Sopenharmony_ci .max_vid = 4095, 598062306a36Sopenharmony_ci .port_base_addr = 0x10, 598162306a36Sopenharmony_ci .phy_base_addr = 0x0, 598262306a36Sopenharmony_ci .global1_addr = 0x1b, 598362306a36Sopenharmony_ci .global2_addr = 0x1c, 598462306a36Sopenharmony_ci .age_time_coeff = 15000, 598562306a36Sopenharmony_ci .g1_irqs = 8, 598662306a36Sopenharmony_ci .g2_irqs = 10, 598762306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 598862306a36Sopenharmony_ci .multi_chip = true, 598962306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 599062306a36Sopenharmony_ci .ptp_support = true, 599162306a36Sopenharmony_ci .ops = &mv88e6321_ops, 599262306a36Sopenharmony_ci }, 599362306a36Sopenharmony_ci 599462306a36Sopenharmony_ci [MV88E6341] = { 599562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 599662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6341, 599762306a36Sopenharmony_ci .name = "Marvell 88E6341", 599862306a36Sopenharmony_ci .num_databases = 4096, 599962306a36Sopenharmony_ci .num_macs = 2048, 600062306a36Sopenharmony_ci .num_internal_phys = 5, 600162306a36Sopenharmony_ci .num_ports = 6, 600262306a36Sopenharmony_ci .num_gpio = 11, 600362306a36Sopenharmony_ci .max_vid = 4095, 600462306a36Sopenharmony_ci .max_sid = 63, 600562306a36Sopenharmony_ci .port_base_addr = 0x10, 600662306a36Sopenharmony_ci .phy_base_addr = 0x10, 600762306a36Sopenharmony_ci .global1_addr = 0x1b, 600862306a36Sopenharmony_ci .global2_addr = 0x1c, 600962306a36Sopenharmony_ci .age_time_coeff = 3750, 601062306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 601162306a36Sopenharmony_ci .g1_irqs = 9, 601262306a36Sopenharmony_ci .g2_irqs = 10, 601362306a36Sopenharmony_ci .pvt = true, 601462306a36Sopenharmony_ci .multi_chip = true, 601562306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 601662306a36Sopenharmony_ci .ptp_support = true, 601762306a36Sopenharmony_ci .ops = &mv88e6341_ops, 601862306a36Sopenharmony_ci }, 601962306a36Sopenharmony_ci 602062306a36Sopenharmony_ci [MV88E6350] = { 602162306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, 602262306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6351, 602362306a36Sopenharmony_ci .name = "Marvell 88E6350", 602462306a36Sopenharmony_ci .num_databases = 4096, 602562306a36Sopenharmony_ci .num_macs = 8192, 602662306a36Sopenharmony_ci .num_ports = 7, 602762306a36Sopenharmony_ci .num_internal_phys = 5, 602862306a36Sopenharmony_ci .max_vid = 4095, 602962306a36Sopenharmony_ci .max_sid = 63, 603062306a36Sopenharmony_ci .port_base_addr = 0x10, 603162306a36Sopenharmony_ci .phy_base_addr = 0x0, 603262306a36Sopenharmony_ci .global1_addr = 0x1b, 603362306a36Sopenharmony_ci .global2_addr = 0x1c, 603462306a36Sopenharmony_ci .age_time_coeff = 15000, 603562306a36Sopenharmony_ci .g1_irqs = 9, 603662306a36Sopenharmony_ci .g2_irqs = 10, 603762306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 603862306a36Sopenharmony_ci .pvt = true, 603962306a36Sopenharmony_ci .multi_chip = true, 604062306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 604162306a36Sopenharmony_ci .ops = &mv88e6350_ops, 604262306a36Sopenharmony_ci }, 604362306a36Sopenharmony_ci 604462306a36Sopenharmony_ci [MV88E6351] = { 604562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, 604662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6351, 604762306a36Sopenharmony_ci .name = "Marvell 88E6351", 604862306a36Sopenharmony_ci .num_databases = 4096, 604962306a36Sopenharmony_ci .num_macs = 8192, 605062306a36Sopenharmony_ci .num_ports = 7, 605162306a36Sopenharmony_ci .num_internal_phys = 5, 605262306a36Sopenharmony_ci .max_vid = 4095, 605362306a36Sopenharmony_ci .max_sid = 63, 605462306a36Sopenharmony_ci .port_base_addr = 0x10, 605562306a36Sopenharmony_ci .phy_base_addr = 0x0, 605662306a36Sopenharmony_ci .global1_addr = 0x1b, 605762306a36Sopenharmony_ci .global2_addr = 0x1c, 605862306a36Sopenharmony_ci .age_time_coeff = 15000, 605962306a36Sopenharmony_ci .g1_irqs = 9, 606062306a36Sopenharmony_ci .g2_irqs = 10, 606162306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 606262306a36Sopenharmony_ci .pvt = true, 606362306a36Sopenharmony_ci .multi_chip = true, 606462306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 606562306a36Sopenharmony_ci .ops = &mv88e6351_ops, 606662306a36Sopenharmony_ci }, 606762306a36Sopenharmony_ci 606862306a36Sopenharmony_ci [MV88E6352] = { 606962306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, 607062306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6352, 607162306a36Sopenharmony_ci .name = "Marvell 88E6352", 607262306a36Sopenharmony_ci .num_databases = 4096, 607362306a36Sopenharmony_ci .num_macs = 8192, 607462306a36Sopenharmony_ci .num_ports = 7, 607562306a36Sopenharmony_ci .num_internal_phys = 5, 607662306a36Sopenharmony_ci .num_gpio = 15, 607762306a36Sopenharmony_ci .max_vid = 4095, 607862306a36Sopenharmony_ci .max_sid = 63, 607962306a36Sopenharmony_ci .port_base_addr = 0x10, 608062306a36Sopenharmony_ci .phy_base_addr = 0x0, 608162306a36Sopenharmony_ci .global1_addr = 0x1b, 608262306a36Sopenharmony_ci .global2_addr = 0x1c, 608362306a36Sopenharmony_ci .age_time_coeff = 15000, 608462306a36Sopenharmony_ci .g1_irqs = 9, 608562306a36Sopenharmony_ci .g2_irqs = 10, 608662306a36Sopenharmony_ci .atu_move_port_mask = 0xf, 608762306a36Sopenharmony_ci .pvt = true, 608862306a36Sopenharmony_ci .multi_chip = true, 608962306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_SUPPORTED, 609062306a36Sopenharmony_ci .ptp_support = true, 609162306a36Sopenharmony_ci .ops = &mv88e6352_ops, 609262306a36Sopenharmony_ci }, 609362306a36Sopenharmony_ci [MV88E6361] = { 609462306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6361, 609562306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6393, 609662306a36Sopenharmony_ci .name = "Marvell 88E6361", 609762306a36Sopenharmony_ci .num_databases = 4096, 609862306a36Sopenharmony_ci .num_macs = 16384, 609962306a36Sopenharmony_ci .num_ports = 11, 610062306a36Sopenharmony_ci /* Ports 1, 2 and 8 are not routed */ 610162306a36Sopenharmony_ci .invalid_port_mask = BIT(1) | BIT(2) | BIT(8), 610262306a36Sopenharmony_ci .num_internal_phys = 5, 610362306a36Sopenharmony_ci .internal_phys_offset = 3, 610462306a36Sopenharmony_ci .max_vid = 4095, 610562306a36Sopenharmony_ci .max_sid = 63, 610662306a36Sopenharmony_ci .port_base_addr = 0x0, 610762306a36Sopenharmony_ci .phy_base_addr = 0x0, 610862306a36Sopenharmony_ci .global1_addr = 0x1b, 610962306a36Sopenharmony_ci .global2_addr = 0x1c, 611062306a36Sopenharmony_ci .age_time_coeff = 3750, 611162306a36Sopenharmony_ci .g1_irqs = 10, 611262306a36Sopenharmony_ci .g2_irqs = 14, 611362306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 611462306a36Sopenharmony_ci .pvt = true, 611562306a36Sopenharmony_ci .multi_chip = true, 611662306a36Sopenharmony_ci .ptp_support = true, 611762306a36Sopenharmony_ci .ops = &mv88e6393x_ops, 611862306a36Sopenharmony_ci }, 611962306a36Sopenharmony_ci [MV88E6390] = { 612062306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 612162306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6390, 612262306a36Sopenharmony_ci .name = "Marvell 88E6390", 612362306a36Sopenharmony_ci .num_databases = 4096, 612462306a36Sopenharmony_ci .num_macs = 16384, 612562306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 612662306a36Sopenharmony_ci .num_internal_phys = 9, 612762306a36Sopenharmony_ci .num_gpio = 16, 612862306a36Sopenharmony_ci .max_vid = 8191, 612962306a36Sopenharmony_ci .max_sid = 63, 613062306a36Sopenharmony_ci .port_base_addr = 0x0, 613162306a36Sopenharmony_ci .phy_base_addr = 0x0, 613262306a36Sopenharmony_ci .global1_addr = 0x1b, 613362306a36Sopenharmony_ci .global2_addr = 0x1c, 613462306a36Sopenharmony_ci .age_time_coeff = 3750, 613562306a36Sopenharmony_ci .g1_irqs = 9, 613662306a36Sopenharmony_ci .g2_irqs = 14, 613762306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 613862306a36Sopenharmony_ci .pvt = true, 613962306a36Sopenharmony_ci .multi_chip = true, 614062306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED, 614162306a36Sopenharmony_ci .ptp_support = true, 614262306a36Sopenharmony_ci .ops = &mv88e6390_ops, 614362306a36Sopenharmony_ci }, 614462306a36Sopenharmony_ci [MV88E6390X] = { 614562306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, 614662306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6390, 614762306a36Sopenharmony_ci .name = "Marvell 88E6390X", 614862306a36Sopenharmony_ci .num_databases = 4096, 614962306a36Sopenharmony_ci .num_macs = 16384, 615062306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 615162306a36Sopenharmony_ci .num_internal_phys = 9, 615262306a36Sopenharmony_ci .num_gpio = 16, 615362306a36Sopenharmony_ci .max_vid = 8191, 615462306a36Sopenharmony_ci .max_sid = 63, 615562306a36Sopenharmony_ci .port_base_addr = 0x0, 615662306a36Sopenharmony_ci .phy_base_addr = 0x0, 615762306a36Sopenharmony_ci .global1_addr = 0x1b, 615862306a36Sopenharmony_ci .global2_addr = 0x1c, 615962306a36Sopenharmony_ci .age_time_coeff = 3750, 616062306a36Sopenharmony_ci .g1_irqs = 9, 616162306a36Sopenharmony_ci .g2_irqs = 14, 616262306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 616362306a36Sopenharmony_ci .pvt = true, 616462306a36Sopenharmony_ci .multi_chip = true, 616562306a36Sopenharmony_ci .edsa_support = MV88E6XXX_EDSA_UNDOCUMENTED, 616662306a36Sopenharmony_ci .ptp_support = true, 616762306a36Sopenharmony_ci .ops = &mv88e6390x_ops, 616862306a36Sopenharmony_ci }, 616962306a36Sopenharmony_ci 617062306a36Sopenharmony_ci [MV88E6393X] = { 617162306a36Sopenharmony_ci .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, 617262306a36Sopenharmony_ci .family = MV88E6XXX_FAMILY_6393, 617362306a36Sopenharmony_ci .name = "Marvell 88E6393X", 617462306a36Sopenharmony_ci .num_databases = 4096, 617562306a36Sopenharmony_ci .num_ports = 11, /* 10 + Z80 */ 617662306a36Sopenharmony_ci .num_internal_phys = 8, 617762306a36Sopenharmony_ci .internal_phys_offset = 1, 617862306a36Sopenharmony_ci .max_vid = 8191, 617962306a36Sopenharmony_ci .max_sid = 63, 618062306a36Sopenharmony_ci .port_base_addr = 0x0, 618162306a36Sopenharmony_ci .phy_base_addr = 0x0, 618262306a36Sopenharmony_ci .global1_addr = 0x1b, 618362306a36Sopenharmony_ci .global2_addr = 0x1c, 618462306a36Sopenharmony_ci .age_time_coeff = 3750, 618562306a36Sopenharmony_ci .g1_irqs = 10, 618662306a36Sopenharmony_ci .g2_irqs = 14, 618762306a36Sopenharmony_ci .atu_move_port_mask = 0x1f, 618862306a36Sopenharmony_ci .pvt = true, 618962306a36Sopenharmony_ci .multi_chip = true, 619062306a36Sopenharmony_ci .ptp_support = true, 619162306a36Sopenharmony_ci .ops = &mv88e6393x_ops, 619262306a36Sopenharmony_ci }, 619362306a36Sopenharmony_ci}; 619462306a36Sopenharmony_ci 619562306a36Sopenharmony_cistatic const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) 619662306a36Sopenharmony_ci{ 619762306a36Sopenharmony_ci int i; 619862306a36Sopenharmony_ci 619962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) 620062306a36Sopenharmony_ci if (mv88e6xxx_table[i].prod_num == prod_num) 620162306a36Sopenharmony_ci return &mv88e6xxx_table[i]; 620262306a36Sopenharmony_ci 620362306a36Sopenharmony_ci return NULL; 620462306a36Sopenharmony_ci} 620562306a36Sopenharmony_ci 620662306a36Sopenharmony_cistatic int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) 620762306a36Sopenharmony_ci{ 620862306a36Sopenharmony_ci const struct mv88e6xxx_info *info; 620962306a36Sopenharmony_ci unsigned int prod_num, rev; 621062306a36Sopenharmony_ci u16 id; 621162306a36Sopenharmony_ci int err; 621262306a36Sopenharmony_ci 621362306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 621462306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); 621562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 621662306a36Sopenharmony_ci if (err) 621762306a36Sopenharmony_ci return err; 621862306a36Sopenharmony_ci 621962306a36Sopenharmony_ci prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; 622062306a36Sopenharmony_ci rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; 622162306a36Sopenharmony_ci 622262306a36Sopenharmony_ci info = mv88e6xxx_lookup_info(prod_num); 622362306a36Sopenharmony_ci if (!info) 622462306a36Sopenharmony_ci return -ENODEV; 622562306a36Sopenharmony_ci 622662306a36Sopenharmony_ci /* Update the compatible info with the probed one */ 622762306a36Sopenharmony_ci chip->info = info; 622862306a36Sopenharmony_ci 622962306a36Sopenharmony_ci dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n", 623062306a36Sopenharmony_ci chip->info->prod_num, chip->info->name, rev); 623162306a36Sopenharmony_ci 623262306a36Sopenharmony_ci return 0; 623362306a36Sopenharmony_ci} 623462306a36Sopenharmony_ci 623562306a36Sopenharmony_cistatic int mv88e6xxx_single_chip_detect(struct mv88e6xxx_chip *chip, 623662306a36Sopenharmony_ci struct mdio_device *mdiodev) 623762306a36Sopenharmony_ci{ 623862306a36Sopenharmony_ci int err; 623962306a36Sopenharmony_ci 624062306a36Sopenharmony_ci /* dual_chip takes precedence over single/multi-chip modes */ 624162306a36Sopenharmony_ci if (chip->info->dual_chip) 624262306a36Sopenharmony_ci return -EINVAL; 624362306a36Sopenharmony_ci 624462306a36Sopenharmony_ci /* If the mdio addr is 16 indicating the first port address of a switch 624562306a36Sopenharmony_ci * (e.g. mv88e6*41) in single chip addressing mode the device may be 624662306a36Sopenharmony_ci * configured in single chip addressing mode. Setup the smi access as 624762306a36Sopenharmony_ci * single chip addressing mode and attempt to detect the model of the 624862306a36Sopenharmony_ci * switch, if this fails the device is not configured in single chip 624962306a36Sopenharmony_ci * addressing mode. 625062306a36Sopenharmony_ci */ 625162306a36Sopenharmony_ci if (mdiodev->addr != 16) 625262306a36Sopenharmony_ci return -EINVAL; 625362306a36Sopenharmony_ci 625462306a36Sopenharmony_ci err = mv88e6xxx_smi_init(chip, mdiodev->bus, 0); 625562306a36Sopenharmony_ci if (err) 625662306a36Sopenharmony_ci return err; 625762306a36Sopenharmony_ci 625862306a36Sopenharmony_ci return mv88e6xxx_detect(chip); 625962306a36Sopenharmony_ci} 626062306a36Sopenharmony_ci 626162306a36Sopenharmony_cistatic struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) 626262306a36Sopenharmony_ci{ 626362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip; 626462306a36Sopenharmony_ci 626562306a36Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 626662306a36Sopenharmony_ci if (!chip) 626762306a36Sopenharmony_ci return NULL; 626862306a36Sopenharmony_ci 626962306a36Sopenharmony_ci chip->dev = dev; 627062306a36Sopenharmony_ci 627162306a36Sopenharmony_ci mutex_init(&chip->reg_lock); 627262306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->mdios); 627362306a36Sopenharmony_ci idr_init(&chip->policies); 627462306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->msts); 627562306a36Sopenharmony_ci 627662306a36Sopenharmony_ci return chip; 627762306a36Sopenharmony_ci} 627862306a36Sopenharmony_ci 627962306a36Sopenharmony_cistatic enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds, 628062306a36Sopenharmony_ci int port, 628162306a36Sopenharmony_ci enum dsa_tag_protocol m) 628262306a36Sopenharmony_ci{ 628362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 628462306a36Sopenharmony_ci 628562306a36Sopenharmony_ci return chip->tag_protocol; 628662306a36Sopenharmony_ci} 628762306a36Sopenharmony_ci 628862306a36Sopenharmony_cistatic int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds, 628962306a36Sopenharmony_ci enum dsa_tag_protocol proto) 629062306a36Sopenharmony_ci{ 629162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 629262306a36Sopenharmony_ci enum dsa_tag_protocol old_protocol; 629362306a36Sopenharmony_ci struct dsa_port *cpu_dp; 629462306a36Sopenharmony_ci int err; 629562306a36Sopenharmony_ci 629662306a36Sopenharmony_ci switch (proto) { 629762306a36Sopenharmony_ci case DSA_TAG_PROTO_EDSA: 629862306a36Sopenharmony_ci switch (chip->info->edsa_support) { 629962306a36Sopenharmony_ci case MV88E6XXX_EDSA_UNSUPPORTED: 630062306a36Sopenharmony_ci return -EPROTONOSUPPORT; 630162306a36Sopenharmony_ci case MV88E6XXX_EDSA_UNDOCUMENTED: 630262306a36Sopenharmony_ci dev_warn(chip->dev, "Relying on undocumented EDSA tagging behavior\n"); 630362306a36Sopenharmony_ci fallthrough; 630462306a36Sopenharmony_ci case MV88E6XXX_EDSA_SUPPORTED: 630562306a36Sopenharmony_ci break; 630662306a36Sopenharmony_ci } 630762306a36Sopenharmony_ci break; 630862306a36Sopenharmony_ci case DSA_TAG_PROTO_DSA: 630962306a36Sopenharmony_ci break; 631062306a36Sopenharmony_ci default: 631162306a36Sopenharmony_ci return -EPROTONOSUPPORT; 631262306a36Sopenharmony_ci } 631362306a36Sopenharmony_ci 631462306a36Sopenharmony_ci old_protocol = chip->tag_protocol; 631562306a36Sopenharmony_ci chip->tag_protocol = proto; 631662306a36Sopenharmony_ci 631762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 631862306a36Sopenharmony_ci dsa_switch_for_each_cpu_port(cpu_dp, ds) { 631962306a36Sopenharmony_ci err = mv88e6xxx_setup_port_mode(chip, cpu_dp->index); 632062306a36Sopenharmony_ci if (err) { 632162306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 632262306a36Sopenharmony_ci goto unwind; 632362306a36Sopenharmony_ci } 632462306a36Sopenharmony_ci } 632562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 632662306a36Sopenharmony_ci 632762306a36Sopenharmony_ci return 0; 632862306a36Sopenharmony_ci 632962306a36Sopenharmony_ciunwind: 633062306a36Sopenharmony_ci chip->tag_protocol = old_protocol; 633162306a36Sopenharmony_ci 633262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 633362306a36Sopenharmony_ci dsa_switch_for_each_cpu_port_continue_reverse(cpu_dp, ds) 633462306a36Sopenharmony_ci mv88e6xxx_setup_port_mode(chip, cpu_dp->index); 633562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 633662306a36Sopenharmony_ci 633762306a36Sopenharmony_ci return err; 633862306a36Sopenharmony_ci} 633962306a36Sopenharmony_ci 634062306a36Sopenharmony_cistatic int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, 634162306a36Sopenharmony_ci const struct switchdev_obj_port_mdb *mdb, 634262306a36Sopenharmony_ci struct dsa_db db) 634362306a36Sopenharmony_ci{ 634462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 634562306a36Sopenharmony_ci int err; 634662306a36Sopenharmony_ci 634762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 634862306a36Sopenharmony_ci err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 634962306a36Sopenharmony_ci MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC); 635062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 635162306a36Sopenharmony_ci 635262306a36Sopenharmony_ci return err; 635362306a36Sopenharmony_ci} 635462306a36Sopenharmony_ci 635562306a36Sopenharmony_cistatic int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, 635662306a36Sopenharmony_ci const struct switchdev_obj_port_mdb *mdb, 635762306a36Sopenharmony_ci struct dsa_db db) 635862306a36Sopenharmony_ci{ 635962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 636062306a36Sopenharmony_ci int err; 636162306a36Sopenharmony_ci 636262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 636362306a36Sopenharmony_ci err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0); 636462306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 636562306a36Sopenharmony_ci 636662306a36Sopenharmony_ci return err; 636762306a36Sopenharmony_ci} 636862306a36Sopenharmony_ci 636962306a36Sopenharmony_cistatic int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, 637062306a36Sopenharmony_ci struct dsa_mall_mirror_tc_entry *mirror, 637162306a36Sopenharmony_ci bool ingress, 637262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 637362306a36Sopenharmony_ci{ 637462306a36Sopenharmony_ci enum mv88e6xxx_egress_direction direction = ingress ? 637562306a36Sopenharmony_ci MV88E6XXX_EGRESS_DIR_INGRESS : 637662306a36Sopenharmony_ci MV88E6XXX_EGRESS_DIR_EGRESS; 637762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 637862306a36Sopenharmony_ci bool other_mirrors = false; 637962306a36Sopenharmony_ci int i; 638062306a36Sopenharmony_ci int err; 638162306a36Sopenharmony_ci 638262306a36Sopenharmony_ci mutex_lock(&chip->reg_lock); 638362306a36Sopenharmony_ci if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != 638462306a36Sopenharmony_ci mirror->to_local_port) { 638562306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 638662306a36Sopenharmony_ci other_mirrors |= ingress ? 638762306a36Sopenharmony_ci chip->ports[i].mirror_ingress : 638862306a36Sopenharmony_ci chip->ports[i].mirror_egress; 638962306a36Sopenharmony_ci 639062306a36Sopenharmony_ci /* Can't change egress port when other mirror is active */ 639162306a36Sopenharmony_ci if (other_mirrors) { 639262306a36Sopenharmony_ci err = -EBUSY; 639362306a36Sopenharmony_ci goto out; 639462306a36Sopenharmony_ci } 639562306a36Sopenharmony_ci 639662306a36Sopenharmony_ci err = mv88e6xxx_set_egress_port(chip, direction, 639762306a36Sopenharmony_ci mirror->to_local_port); 639862306a36Sopenharmony_ci if (err) 639962306a36Sopenharmony_ci goto out; 640062306a36Sopenharmony_ci } 640162306a36Sopenharmony_ci 640262306a36Sopenharmony_ci err = mv88e6xxx_port_set_mirror(chip, port, direction, true); 640362306a36Sopenharmony_ciout: 640462306a36Sopenharmony_ci mutex_unlock(&chip->reg_lock); 640562306a36Sopenharmony_ci 640662306a36Sopenharmony_ci return err; 640762306a36Sopenharmony_ci} 640862306a36Sopenharmony_ci 640962306a36Sopenharmony_cistatic void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, 641062306a36Sopenharmony_ci struct dsa_mall_mirror_tc_entry *mirror) 641162306a36Sopenharmony_ci{ 641262306a36Sopenharmony_ci enum mv88e6xxx_egress_direction direction = mirror->ingress ? 641362306a36Sopenharmony_ci MV88E6XXX_EGRESS_DIR_INGRESS : 641462306a36Sopenharmony_ci MV88E6XXX_EGRESS_DIR_EGRESS; 641562306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 641662306a36Sopenharmony_ci bool other_mirrors = false; 641762306a36Sopenharmony_ci int i; 641862306a36Sopenharmony_ci 641962306a36Sopenharmony_ci mutex_lock(&chip->reg_lock); 642062306a36Sopenharmony_ci if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) 642162306a36Sopenharmony_ci dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); 642262306a36Sopenharmony_ci 642362306a36Sopenharmony_ci for (i = 0; i < mv88e6xxx_num_ports(chip); i++) 642462306a36Sopenharmony_ci other_mirrors |= mirror->ingress ? 642562306a36Sopenharmony_ci chip->ports[i].mirror_ingress : 642662306a36Sopenharmony_ci chip->ports[i].mirror_egress; 642762306a36Sopenharmony_ci 642862306a36Sopenharmony_ci /* Reset egress port when no other mirror is active */ 642962306a36Sopenharmony_ci if (!other_mirrors) { 643062306a36Sopenharmony_ci if (mv88e6xxx_set_egress_port(chip, direction, 643162306a36Sopenharmony_ci dsa_upstream_port(ds, port))) 643262306a36Sopenharmony_ci dev_err(ds->dev, "failed to set egress port\n"); 643362306a36Sopenharmony_ci } 643462306a36Sopenharmony_ci 643562306a36Sopenharmony_ci mutex_unlock(&chip->reg_lock); 643662306a36Sopenharmony_ci} 643762306a36Sopenharmony_ci 643862306a36Sopenharmony_cistatic int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port, 643962306a36Sopenharmony_ci struct switchdev_brport_flags flags, 644062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 644162306a36Sopenharmony_ci{ 644262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 644362306a36Sopenharmony_ci const struct mv88e6xxx_ops *ops; 644462306a36Sopenharmony_ci 644562306a36Sopenharmony_ci if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | 644662306a36Sopenharmony_ci BR_BCAST_FLOOD | BR_PORT_LOCKED | BR_PORT_MAB)) 644762306a36Sopenharmony_ci return -EINVAL; 644862306a36Sopenharmony_ci 644962306a36Sopenharmony_ci ops = chip->info->ops; 645062306a36Sopenharmony_ci 645162306a36Sopenharmony_ci if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood) 645262306a36Sopenharmony_ci return -EINVAL; 645362306a36Sopenharmony_ci 645462306a36Sopenharmony_ci if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood) 645562306a36Sopenharmony_ci return -EINVAL; 645662306a36Sopenharmony_ci 645762306a36Sopenharmony_ci return 0; 645862306a36Sopenharmony_ci} 645962306a36Sopenharmony_ci 646062306a36Sopenharmony_cistatic int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, 646162306a36Sopenharmony_ci struct switchdev_brport_flags flags, 646262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 646362306a36Sopenharmony_ci{ 646462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 646562306a36Sopenharmony_ci int err = 0; 646662306a36Sopenharmony_ci 646762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 646862306a36Sopenharmony_ci 646962306a36Sopenharmony_ci if (flags.mask & BR_LEARNING) { 647062306a36Sopenharmony_ci bool learning = !!(flags.val & BR_LEARNING); 647162306a36Sopenharmony_ci u16 pav = learning ? (1 << port) : 0; 647262306a36Sopenharmony_ci 647362306a36Sopenharmony_ci err = mv88e6xxx_port_set_assoc_vector(chip, port, pav); 647462306a36Sopenharmony_ci if (err) 647562306a36Sopenharmony_ci goto out; 647662306a36Sopenharmony_ci } 647762306a36Sopenharmony_ci 647862306a36Sopenharmony_ci if (flags.mask & BR_FLOOD) { 647962306a36Sopenharmony_ci bool unicast = !!(flags.val & BR_FLOOD); 648062306a36Sopenharmony_ci 648162306a36Sopenharmony_ci err = chip->info->ops->port_set_ucast_flood(chip, port, 648262306a36Sopenharmony_ci unicast); 648362306a36Sopenharmony_ci if (err) 648462306a36Sopenharmony_ci goto out; 648562306a36Sopenharmony_ci } 648662306a36Sopenharmony_ci 648762306a36Sopenharmony_ci if (flags.mask & BR_MCAST_FLOOD) { 648862306a36Sopenharmony_ci bool multicast = !!(flags.val & BR_MCAST_FLOOD); 648962306a36Sopenharmony_ci 649062306a36Sopenharmony_ci err = chip->info->ops->port_set_mcast_flood(chip, port, 649162306a36Sopenharmony_ci multicast); 649262306a36Sopenharmony_ci if (err) 649362306a36Sopenharmony_ci goto out; 649462306a36Sopenharmony_ci } 649562306a36Sopenharmony_ci 649662306a36Sopenharmony_ci if (flags.mask & BR_BCAST_FLOOD) { 649762306a36Sopenharmony_ci bool broadcast = !!(flags.val & BR_BCAST_FLOOD); 649862306a36Sopenharmony_ci 649962306a36Sopenharmony_ci err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast); 650062306a36Sopenharmony_ci if (err) 650162306a36Sopenharmony_ci goto out; 650262306a36Sopenharmony_ci } 650362306a36Sopenharmony_ci 650462306a36Sopenharmony_ci if (flags.mask & BR_PORT_MAB) { 650562306a36Sopenharmony_ci bool mab = !!(flags.val & BR_PORT_MAB); 650662306a36Sopenharmony_ci 650762306a36Sopenharmony_ci mv88e6xxx_port_set_mab(chip, port, mab); 650862306a36Sopenharmony_ci } 650962306a36Sopenharmony_ci 651062306a36Sopenharmony_ci if (flags.mask & BR_PORT_LOCKED) { 651162306a36Sopenharmony_ci bool locked = !!(flags.val & BR_PORT_LOCKED); 651262306a36Sopenharmony_ci 651362306a36Sopenharmony_ci err = mv88e6xxx_port_set_lock(chip, port, locked); 651462306a36Sopenharmony_ci if (err) 651562306a36Sopenharmony_ci goto out; 651662306a36Sopenharmony_ci } 651762306a36Sopenharmony_ciout: 651862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 651962306a36Sopenharmony_ci 652062306a36Sopenharmony_ci return err; 652162306a36Sopenharmony_ci} 652262306a36Sopenharmony_ci 652362306a36Sopenharmony_cistatic bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, 652462306a36Sopenharmony_ci struct dsa_lag lag, 652562306a36Sopenharmony_ci struct netdev_lag_upper_info *info, 652662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 652762306a36Sopenharmony_ci{ 652862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 652962306a36Sopenharmony_ci struct dsa_port *dp; 653062306a36Sopenharmony_ci int members = 0; 653162306a36Sopenharmony_ci 653262306a36Sopenharmony_ci if (!mv88e6xxx_has_lag(chip)) { 653362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Chip does not support LAG offload"); 653462306a36Sopenharmony_ci return false; 653562306a36Sopenharmony_ci } 653662306a36Sopenharmony_ci 653762306a36Sopenharmony_ci if (!lag.id) 653862306a36Sopenharmony_ci return false; 653962306a36Sopenharmony_ci 654062306a36Sopenharmony_ci dsa_lag_foreach_port(dp, ds->dst, &lag) 654162306a36Sopenharmony_ci /* Includes the port joining the LAG */ 654262306a36Sopenharmony_ci members++; 654362306a36Sopenharmony_ci 654462306a36Sopenharmony_ci if (members > 8) { 654562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 654662306a36Sopenharmony_ci "Cannot offload more than 8 LAG ports"); 654762306a36Sopenharmony_ci return false; 654862306a36Sopenharmony_ci } 654962306a36Sopenharmony_ci 655062306a36Sopenharmony_ci /* We could potentially relax this to include active 655162306a36Sopenharmony_ci * backup in the future. 655262306a36Sopenharmony_ci */ 655362306a36Sopenharmony_ci if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { 655462306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 655562306a36Sopenharmony_ci "Can only offload LAG using hash TX type"); 655662306a36Sopenharmony_ci return false; 655762306a36Sopenharmony_ci } 655862306a36Sopenharmony_ci 655962306a36Sopenharmony_ci /* Ideally we would also validate that the hash type matches 656062306a36Sopenharmony_ci * the hardware. Alas, this is always set to unknown on team 656162306a36Sopenharmony_ci * interfaces. 656262306a36Sopenharmony_ci */ 656362306a36Sopenharmony_ci return true; 656462306a36Sopenharmony_ci} 656562306a36Sopenharmony_ci 656662306a36Sopenharmony_cistatic int mv88e6xxx_lag_sync_map(struct dsa_switch *ds, struct dsa_lag lag) 656762306a36Sopenharmony_ci{ 656862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 656962306a36Sopenharmony_ci struct dsa_port *dp; 657062306a36Sopenharmony_ci u16 map = 0; 657162306a36Sopenharmony_ci int id; 657262306a36Sopenharmony_ci 657362306a36Sopenharmony_ci /* DSA LAG IDs are one-based, hardware is zero-based */ 657462306a36Sopenharmony_ci id = lag.id - 1; 657562306a36Sopenharmony_ci 657662306a36Sopenharmony_ci /* Build the map of all ports to distribute flows destined for 657762306a36Sopenharmony_ci * this LAG. This can be either a local user port, or a DSA 657862306a36Sopenharmony_ci * port if the LAG port is on a remote chip. 657962306a36Sopenharmony_ci */ 658062306a36Sopenharmony_ci dsa_lag_foreach_port(dp, ds->dst, &lag) 658162306a36Sopenharmony_ci map |= BIT(dsa_towards_port(ds, dp->ds->index, dp->index)); 658262306a36Sopenharmony_ci 658362306a36Sopenharmony_ci return mv88e6xxx_g2_trunk_mapping_write(chip, id, map); 658462306a36Sopenharmony_ci} 658562306a36Sopenharmony_ci 658662306a36Sopenharmony_cistatic const u8 mv88e6xxx_lag_mask_table[8][8] = { 658762306a36Sopenharmony_ci /* Row number corresponds to the number of active members in a 658862306a36Sopenharmony_ci * LAG. Each column states which of the eight hash buckets are 658962306a36Sopenharmony_ci * mapped to the column:th port in the LAG. 659062306a36Sopenharmony_ci * 659162306a36Sopenharmony_ci * Example: In a LAG with three active ports, the second port 659262306a36Sopenharmony_ci * ([2][1]) would be selected for traffic mapped to buckets 659362306a36Sopenharmony_ci * 3,4,5 (0x38). 659462306a36Sopenharmony_ci */ 659562306a36Sopenharmony_ci { 0xff, 0, 0, 0, 0, 0, 0, 0 }, 659662306a36Sopenharmony_ci { 0x0f, 0xf0, 0, 0, 0, 0, 0, 0 }, 659762306a36Sopenharmony_ci { 0x07, 0x38, 0xc0, 0, 0, 0, 0, 0 }, 659862306a36Sopenharmony_ci { 0x03, 0x0c, 0x30, 0xc0, 0, 0, 0, 0 }, 659962306a36Sopenharmony_ci { 0x03, 0x0c, 0x30, 0x40, 0x80, 0, 0, 0 }, 660062306a36Sopenharmony_ci { 0x03, 0x0c, 0x10, 0x20, 0x40, 0x80, 0, 0 }, 660162306a36Sopenharmony_ci { 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0 }, 660262306a36Sopenharmony_ci { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, 660362306a36Sopenharmony_ci}; 660462306a36Sopenharmony_ci 660562306a36Sopenharmony_cistatic void mv88e6xxx_lag_set_port_mask(u16 *mask, int port, 660662306a36Sopenharmony_ci int num_tx, int nth) 660762306a36Sopenharmony_ci{ 660862306a36Sopenharmony_ci u8 active = 0; 660962306a36Sopenharmony_ci int i; 661062306a36Sopenharmony_ci 661162306a36Sopenharmony_ci num_tx = num_tx <= 8 ? num_tx : 8; 661262306a36Sopenharmony_ci if (nth < num_tx) 661362306a36Sopenharmony_ci active = mv88e6xxx_lag_mask_table[num_tx - 1][nth]; 661462306a36Sopenharmony_ci 661562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 661662306a36Sopenharmony_ci if (BIT(i) & active) 661762306a36Sopenharmony_ci mask[i] |= BIT(port); 661862306a36Sopenharmony_ci } 661962306a36Sopenharmony_ci} 662062306a36Sopenharmony_ci 662162306a36Sopenharmony_cistatic int mv88e6xxx_lag_sync_masks(struct dsa_switch *ds) 662262306a36Sopenharmony_ci{ 662362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 662462306a36Sopenharmony_ci unsigned int id, num_tx; 662562306a36Sopenharmony_ci struct dsa_port *dp; 662662306a36Sopenharmony_ci struct dsa_lag *lag; 662762306a36Sopenharmony_ci int i, err, nth; 662862306a36Sopenharmony_ci u16 mask[8]; 662962306a36Sopenharmony_ci u16 ivec; 663062306a36Sopenharmony_ci 663162306a36Sopenharmony_ci /* Assume no port is a member of any LAG. */ 663262306a36Sopenharmony_ci ivec = BIT(mv88e6xxx_num_ports(chip)) - 1; 663362306a36Sopenharmony_ci 663462306a36Sopenharmony_ci /* Disable all masks for ports that _are_ members of a LAG. */ 663562306a36Sopenharmony_ci dsa_switch_for_each_port(dp, ds) { 663662306a36Sopenharmony_ci if (!dp->lag) 663762306a36Sopenharmony_ci continue; 663862306a36Sopenharmony_ci 663962306a36Sopenharmony_ci ivec &= ~BIT(dp->index); 664062306a36Sopenharmony_ci } 664162306a36Sopenharmony_ci 664262306a36Sopenharmony_ci for (i = 0; i < 8; i++) 664362306a36Sopenharmony_ci mask[i] = ivec; 664462306a36Sopenharmony_ci 664562306a36Sopenharmony_ci /* Enable the correct subset of masks for all LAG ports that 664662306a36Sopenharmony_ci * are in the Tx set. 664762306a36Sopenharmony_ci */ 664862306a36Sopenharmony_ci dsa_lags_foreach_id(id, ds->dst) { 664962306a36Sopenharmony_ci lag = dsa_lag_by_id(ds->dst, id); 665062306a36Sopenharmony_ci if (!lag) 665162306a36Sopenharmony_ci continue; 665262306a36Sopenharmony_ci 665362306a36Sopenharmony_ci num_tx = 0; 665462306a36Sopenharmony_ci dsa_lag_foreach_port(dp, ds->dst, lag) { 665562306a36Sopenharmony_ci if (dp->lag_tx_enabled) 665662306a36Sopenharmony_ci num_tx++; 665762306a36Sopenharmony_ci } 665862306a36Sopenharmony_ci 665962306a36Sopenharmony_ci if (!num_tx) 666062306a36Sopenharmony_ci continue; 666162306a36Sopenharmony_ci 666262306a36Sopenharmony_ci nth = 0; 666362306a36Sopenharmony_ci dsa_lag_foreach_port(dp, ds->dst, lag) { 666462306a36Sopenharmony_ci if (!dp->lag_tx_enabled) 666562306a36Sopenharmony_ci continue; 666662306a36Sopenharmony_ci 666762306a36Sopenharmony_ci if (dp->ds == ds) 666862306a36Sopenharmony_ci mv88e6xxx_lag_set_port_mask(mask, dp->index, 666962306a36Sopenharmony_ci num_tx, nth); 667062306a36Sopenharmony_ci 667162306a36Sopenharmony_ci nth++; 667262306a36Sopenharmony_ci } 667362306a36Sopenharmony_ci } 667462306a36Sopenharmony_ci 667562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 667662306a36Sopenharmony_ci err = mv88e6xxx_g2_trunk_mask_write(chip, i, true, mask[i]); 667762306a36Sopenharmony_ci if (err) 667862306a36Sopenharmony_ci return err; 667962306a36Sopenharmony_ci } 668062306a36Sopenharmony_ci 668162306a36Sopenharmony_ci return 0; 668262306a36Sopenharmony_ci} 668362306a36Sopenharmony_ci 668462306a36Sopenharmony_cistatic int mv88e6xxx_lag_sync_masks_map(struct dsa_switch *ds, 668562306a36Sopenharmony_ci struct dsa_lag lag) 668662306a36Sopenharmony_ci{ 668762306a36Sopenharmony_ci int err; 668862306a36Sopenharmony_ci 668962306a36Sopenharmony_ci err = mv88e6xxx_lag_sync_masks(ds); 669062306a36Sopenharmony_ci 669162306a36Sopenharmony_ci if (!err) 669262306a36Sopenharmony_ci err = mv88e6xxx_lag_sync_map(ds, lag); 669362306a36Sopenharmony_ci 669462306a36Sopenharmony_ci return err; 669562306a36Sopenharmony_ci} 669662306a36Sopenharmony_ci 669762306a36Sopenharmony_cistatic int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port) 669862306a36Sopenharmony_ci{ 669962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 670062306a36Sopenharmony_ci int err; 670162306a36Sopenharmony_ci 670262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 670362306a36Sopenharmony_ci err = mv88e6xxx_lag_sync_masks(ds); 670462306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 670562306a36Sopenharmony_ci return err; 670662306a36Sopenharmony_ci} 670762306a36Sopenharmony_ci 670862306a36Sopenharmony_cistatic int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port, 670962306a36Sopenharmony_ci struct dsa_lag lag, 671062306a36Sopenharmony_ci struct netdev_lag_upper_info *info, 671162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 671262306a36Sopenharmony_ci{ 671362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 671462306a36Sopenharmony_ci int err, id; 671562306a36Sopenharmony_ci 671662306a36Sopenharmony_ci if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack)) 671762306a36Sopenharmony_ci return -EOPNOTSUPP; 671862306a36Sopenharmony_ci 671962306a36Sopenharmony_ci /* DSA LAG IDs are one-based */ 672062306a36Sopenharmony_ci id = lag.id - 1; 672162306a36Sopenharmony_ci 672262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 672362306a36Sopenharmony_ci 672462306a36Sopenharmony_ci err = mv88e6xxx_port_set_trunk(chip, port, true, id); 672562306a36Sopenharmony_ci if (err) 672662306a36Sopenharmony_ci goto err_unlock; 672762306a36Sopenharmony_ci 672862306a36Sopenharmony_ci err = mv88e6xxx_lag_sync_masks_map(ds, lag); 672962306a36Sopenharmony_ci if (err) 673062306a36Sopenharmony_ci goto err_clear_trunk; 673162306a36Sopenharmony_ci 673262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 673362306a36Sopenharmony_ci return 0; 673462306a36Sopenharmony_ci 673562306a36Sopenharmony_cierr_clear_trunk: 673662306a36Sopenharmony_ci mv88e6xxx_port_set_trunk(chip, port, false, 0); 673762306a36Sopenharmony_cierr_unlock: 673862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 673962306a36Sopenharmony_ci return err; 674062306a36Sopenharmony_ci} 674162306a36Sopenharmony_ci 674262306a36Sopenharmony_cistatic int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port, 674362306a36Sopenharmony_ci struct dsa_lag lag) 674462306a36Sopenharmony_ci{ 674562306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 674662306a36Sopenharmony_ci int err_sync, err_trunk; 674762306a36Sopenharmony_ci 674862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 674962306a36Sopenharmony_ci err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag); 675062306a36Sopenharmony_ci err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0); 675162306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 675262306a36Sopenharmony_ci return err_sync ? : err_trunk; 675362306a36Sopenharmony_ci} 675462306a36Sopenharmony_ci 675562306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index, 675662306a36Sopenharmony_ci int port) 675762306a36Sopenharmony_ci{ 675862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 675962306a36Sopenharmony_ci int err; 676062306a36Sopenharmony_ci 676162306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 676262306a36Sopenharmony_ci err = mv88e6xxx_lag_sync_masks(ds); 676362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 676462306a36Sopenharmony_ci return err; 676562306a36Sopenharmony_ci} 676662306a36Sopenharmony_ci 676762306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index, 676862306a36Sopenharmony_ci int port, struct dsa_lag lag, 676962306a36Sopenharmony_ci struct netdev_lag_upper_info *info, 677062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 677162306a36Sopenharmony_ci{ 677262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 677362306a36Sopenharmony_ci int err; 677462306a36Sopenharmony_ci 677562306a36Sopenharmony_ci if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack)) 677662306a36Sopenharmony_ci return -EOPNOTSUPP; 677762306a36Sopenharmony_ci 677862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 677962306a36Sopenharmony_ci 678062306a36Sopenharmony_ci err = mv88e6xxx_lag_sync_masks_map(ds, lag); 678162306a36Sopenharmony_ci if (err) 678262306a36Sopenharmony_ci goto unlock; 678362306a36Sopenharmony_ci 678462306a36Sopenharmony_ci err = mv88e6xxx_pvt_map(chip, sw_index, port); 678562306a36Sopenharmony_ci 678662306a36Sopenharmony_ciunlock: 678762306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 678862306a36Sopenharmony_ci return err; 678962306a36Sopenharmony_ci} 679062306a36Sopenharmony_ci 679162306a36Sopenharmony_cistatic int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index, 679262306a36Sopenharmony_ci int port, struct dsa_lag lag) 679362306a36Sopenharmony_ci{ 679462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 679562306a36Sopenharmony_ci int err_sync, err_pvt; 679662306a36Sopenharmony_ci 679762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 679862306a36Sopenharmony_ci err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag); 679962306a36Sopenharmony_ci err_pvt = mv88e6xxx_pvt_map(chip, sw_index, port); 680062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 680162306a36Sopenharmony_ci return err_sync ? : err_pvt; 680262306a36Sopenharmony_ci} 680362306a36Sopenharmony_ci 680462306a36Sopenharmony_cistatic const struct dsa_switch_ops mv88e6xxx_switch_ops = { 680562306a36Sopenharmony_ci .get_tag_protocol = mv88e6xxx_get_tag_protocol, 680662306a36Sopenharmony_ci .change_tag_protocol = mv88e6xxx_change_tag_protocol, 680762306a36Sopenharmony_ci .setup = mv88e6xxx_setup, 680862306a36Sopenharmony_ci .teardown = mv88e6xxx_teardown, 680962306a36Sopenharmony_ci .port_setup = mv88e6xxx_port_setup, 681062306a36Sopenharmony_ci .port_teardown = mv88e6xxx_port_teardown, 681162306a36Sopenharmony_ci .phylink_get_caps = mv88e6xxx_get_caps, 681262306a36Sopenharmony_ci .phylink_mac_select_pcs = mv88e6xxx_mac_select_pcs, 681362306a36Sopenharmony_ci .phylink_mac_prepare = mv88e6xxx_mac_prepare, 681462306a36Sopenharmony_ci .phylink_mac_config = mv88e6xxx_mac_config, 681562306a36Sopenharmony_ci .phylink_mac_finish = mv88e6xxx_mac_finish, 681662306a36Sopenharmony_ci .phylink_mac_link_down = mv88e6xxx_mac_link_down, 681762306a36Sopenharmony_ci .phylink_mac_link_up = mv88e6xxx_mac_link_up, 681862306a36Sopenharmony_ci .get_strings = mv88e6xxx_get_strings, 681962306a36Sopenharmony_ci .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 682062306a36Sopenharmony_ci .get_sset_count = mv88e6xxx_get_sset_count, 682162306a36Sopenharmony_ci .port_max_mtu = mv88e6xxx_get_max_mtu, 682262306a36Sopenharmony_ci .port_change_mtu = mv88e6xxx_change_mtu, 682362306a36Sopenharmony_ci .get_mac_eee = mv88e6xxx_get_mac_eee, 682462306a36Sopenharmony_ci .set_mac_eee = mv88e6xxx_set_mac_eee, 682562306a36Sopenharmony_ci .get_eeprom_len = mv88e6xxx_get_eeprom_len, 682662306a36Sopenharmony_ci .get_eeprom = mv88e6xxx_get_eeprom, 682762306a36Sopenharmony_ci .set_eeprom = mv88e6xxx_set_eeprom, 682862306a36Sopenharmony_ci .get_regs_len = mv88e6xxx_get_regs_len, 682962306a36Sopenharmony_ci .get_regs = mv88e6xxx_get_regs, 683062306a36Sopenharmony_ci .get_rxnfc = mv88e6xxx_get_rxnfc, 683162306a36Sopenharmony_ci .set_rxnfc = mv88e6xxx_set_rxnfc, 683262306a36Sopenharmony_ci .set_ageing_time = mv88e6xxx_set_ageing_time, 683362306a36Sopenharmony_ci .port_bridge_join = mv88e6xxx_port_bridge_join, 683462306a36Sopenharmony_ci .port_bridge_leave = mv88e6xxx_port_bridge_leave, 683562306a36Sopenharmony_ci .port_pre_bridge_flags = mv88e6xxx_port_pre_bridge_flags, 683662306a36Sopenharmony_ci .port_bridge_flags = mv88e6xxx_port_bridge_flags, 683762306a36Sopenharmony_ci .port_stp_state_set = mv88e6xxx_port_stp_state_set, 683862306a36Sopenharmony_ci .port_mst_state_set = mv88e6xxx_port_mst_state_set, 683962306a36Sopenharmony_ci .port_fast_age = mv88e6xxx_port_fast_age, 684062306a36Sopenharmony_ci .port_vlan_fast_age = mv88e6xxx_port_vlan_fast_age, 684162306a36Sopenharmony_ci .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, 684262306a36Sopenharmony_ci .port_vlan_add = mv88e6xxx_port_vlan_add, 684362306a36Sopenharmony_ci .port_vlan_del = mv88e6xxx_port_vlan_del, 684462306a36Sopenharmony_ci .vlan_msti_set = mv88e6xxx_vlan_msti_set, 684562306a36Sopenharmony_ci .port_fdb_add = mv88e6xxx_port_fdb_add, 684662306a36Sopenharmony_ci .port_fdb_del = mv88e6xxx_port_fdb_del, 684762306a36Sopenharmony_ci .port_fdb_dump = mv88e6xxx_port_fdb_dump, 684862306a36Sopenharmony_ci .port_mdb_add = mv88e6xxx_port_mdb_add, 684962306a36Sopenharmony_ci .port_mdb_del = mv88e6xxx_port_mdb_del, 685062306a36Sopenharmony_ci .port_mirror_add = mv88e6xxx_port_mirror_add, 685162306a36Sopenharmony_ci .port_mirror_del = mv88e6xxx_port_mirror_del, 685262306a36Sopenharmony_ci .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, 685362306a36Sopenharmony_ci .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, 685462306a36Sopenharmony_ci .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, 685562306a36Sopenharmony_ci .port_hwtstamp_get = mv88e6xxx_port_hwtstamp_get, 685662306a36Sopenharmony_ci .port_txtstamp = mv88e6xxx_port_txtstamp, 685762306a36Sopenharmony_ci .port_rxtstamp = mv88e6xxx_port_rxtstamp, 685862306a36Sopenharmony_ci .get_ts_info = mv88e6xxx_get_ts_info, 685962306a36Sopenharmony_ci .devlink_param_get = mv88e6xxx_devlink_param_get, 686062306a36Sopenharmony_ci .devlink_param_set = mv88e6xxx_devlink_param_set, 686162306a36Sopenharmony_ci .devlink_info_get = mv88e6xxx_devlink_info_get, 686262306a36Sopenharmony_ci .port_lag_change = mv88e6xxx_port_lag_change, 686362306a36Sopenharmony_ci .port_lag_join = mv88e6xxx_port_lag_join, 686462306a36Sopenharmony_ci .port_lag_leave = mv88e6xxx_port_lag_leave, 686562306a36Sopenharmony_ci .crosschip_lag_change = mv88e6xxx_crosschip_lag_change, 686662306a36Sopenharmony_ci .crosschip_lag_join = mv88e6xxx_crosschip_lag_join, 686762306a36Sopenharmony_ci .crosschip_lag_leave = mv88e6xxx_crosschip_lag_leave, 686862306a36Sopenharmony_ci}; 686962306a36Sopenharmony_ci 687062306a36Sopenharmony_cistatic int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) 687162306a36Sopenharmony_ci{ 687262306a36Sopenharmony_ci struct device *dev = chip->dev; 687362306a36Sopenharmony_ci struct dsa_switch *ds; 687462306a36Sopenharmony_ci 687562306a36Sopenharmony_ci ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); 687662306a36Sopenharmony_ci if (!ds) 687762306a36Sopenharmony_ci return -ENOMEM; 687862306a36Sopenharmony_ci 687962306a36Sopenharmony_ci ds->dev = dev; 688062306a36Sopenharmony_ci ds->num_ports = mv88e6xxx_num_ports(chip); 688162306a36Sopenharmony_ci ds->priv = chip; 688262306a36Sopenharmony_ci ds->dev = dev; 688362306a36Sopenharmony_ci ds->ops = &mv88e6xxx_switch_ops; 688462306a36Sopenharmony_ci ds->ageing_time_min = chip->info->age_time_coeff; 688562306a36Sopenharmony_ci ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; 688662306a36Sopenharmony_ci 688762306a36Sopenharmony_ci /* Some chips support up to 32, but that requires enabling the 688862306a36Sopenharmony_ci * 5-bit port mode, which we do not support. 640k^W16 ought to 688962306a36Sopenharmony_ci * be enough for anyone. 689062306a36Sopenharmony_ci */ 689162306a36Sopenharmony_ci ds->num_lag_ids = mv88e6xxx_has_lag(chip) ? 16 : 0; 689262306a36Sopenharmony_ci 689362306a36Sopenharmony_ci dev_set_drvdata(dev, ds); 689462306a36Sopenharmony_ci 689562306a36Sopenharmony_ci return dsa_register_switch(ds); 689662306a36Sopenharmony_ci} 689762306a36Sopenharmony_ci 689862306a36Sopenharmony_cistatic void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) 689962306a36Sopenharmony_ci{ 690062306a36Sopenharmony_ci dsa_unregister_switch(chip->ds); 690162306a36Sopenharmony_ci} 690262306a36Sopenharmony_ci 690362306a36Sopenharmony_cistatic const void *pdata_device_get_match_data(struct device *dev) 690462306a36Sopenharmony_ci{ 690562306a36Sopenharmony_ci const struct of_device_id *matches = dev->driver->of_match_table; 690662306a36Sopenharmony_ci const struct dsa_mv88e6xxx_pdata *pdata = dev->platform_data; 690762306a36Sopenharmony_ci 690862306a36Sopenharmony_ci for (; matches->name[0] || matches->type[0] || matches->compatible[0]; 690962306a36Sopenharmony_ci matches++) { 691062306a36Sopenharmony_ci if (!strcmp(pdata->compatible, matches->compatible)) 691162306a36Sopenharmony_ci return matches->data; 691262306a36Sopenharmony_ci } 691362306a36Sopenharmony_ci return NULL; 691462306a36Sopenharmony_ci} 691562306a36Sopenharmony_ci 691662306a36Sopenharmony_ci/* There is no suspend to RAM support at DSA level yet, the switch configuration 691762306a36Sopenharmony_ci * would be lost after a power cycle so prevent it to be suspended. 691862306a36Sopenharmony_ci */ 691962306a36Sopenharmony_cistatic int __maybe_unused mv88e6xxx_suspend(struct device *dev) 692062306a36Sopenharmony_ci{ 692162306a36Sopenharmony_ci return -EOPNOTSUPP; 692262306a36Sopenharmony_ci} 692362306a36Sopenharmony_ci 692462306a36Sopenharmony_cistatic int __maybe_unused mv88e6xxx_resume(struct device *dev) 692562306a36Sopenharmony_ci{ 692662306a36Sopenharmony_ci return 0; 692762306a36Sopenharmony_ci} 692862306a36Sopenharmony_ci 692962306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); 693062306a36Sopenharmony_ci 693162306a36Sopenharmony_cistatic int mv88e6xxx_probe(struct mdio_device *mdiodev) 693262306a36Sopenharmony_ci{ 693362306a36Sopenharmony_ci struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; 693462306a36Sopenharmony_ci const struct mv88e6xxx_info *compat_info = NULL; 693562306a36Sopenharmony_ci struct device *dev = &mdiodev->dev; 693662306a36Sopenharmony_ci struct device_node *np = dev->of_node; 693762306a36Sopenharmony_ci struct mv88e6xxx_chip *chip; 693862306a36Sopenharmony_ci int port; 693962306a36Sopenharmony_ci int err; 694062306a36Sopenharmony_ci 694162306a36Sopenharmony_ci if (!np && !pdata) 694262306a36Sopenharmony_ci return -EINVAL; 694362306a36Sopenharmony_ci 694462306a36Sopenharmony_ci if (np) 694562306a36Sopenharmony_ci compat_info = of_device_get_match_data(dev); 694662306a36Sopenharmony_ci 694762306a36Sopenharmony_ci if (pdata) { 694862306a36Sopenharmony_ci compat_info = pdata_device_get_match_data(dev); 694962306a36Sopenharmony_ci 695062306a36Sopenharmony_ci if (!pdata->netdev) 695162306a36Sopenharmony_ci return -EINVAL; 695262306a36Sopenharmony_ci 695362306a36Sopenharmony_ci for (port = 0; port < DSA_MAX_PORTS; port++) { 695462306a36Sopenharmony_ci if (!(pdata->enabled_ports & (1 << port))) 695562306a36Sopenharmony_ci continue; 695662306a36Sopenharmony_ci if (strcmp(pdata->cd.port_names[port], "cpu")) 695762306a36Sopenharmony_ci continue; 695862306a36Sopenharmony_ci pdata->cd.netdev[port] = &pdata->netdev->dev; 695962306a36Sopenharmony_ci break; 696062306a36Sopenharmony_ci } 696162306a36Sopenharmony_ci } 696262306a36Sopenharmony_ci 696362306a36Sopenharmony_ci if (!compat_info) 696462306a36Sopenharmony_ci return -EINVAL; 696562306a36Sopenharmony_ci 696662306a36Sopenharmony_ci chip = mv88e6xxx_alloc_chip(dev); 696762306a36Sopenharmony_ci if (!chip) { 696862306a36Sopenharmony_ci err = -ENOMEM; 696962306a36Sopenharmony_ci goto out; 697062306a36Sopenharmony_ci } 697162306a36Sopenharmony_ci 697262306a36Sopenharmony_ci chip->info = compat_info; 697362306a36Sopenharmony_ci 697462306a36Sopenharmony_ci chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 697562306a36Sopenharmony_ci if (IS_ERR(chip->reset)) { 697662306a36Sopenharmony_ci err = PTR_ERR(chip->reset); 697762306a36Sopenharmony_ci goto out; 697862306a36Sopenharmony_ci } 697962306a36Sopenharmony_ci if (chip->reset) 698062306a36Sopenharmony_ci usleep_range(10000, 20000); 698162306a36Sopenharmony_ci 698262306a36Sopenharmony_ci /* Detect if the device is configured in single chip addressing mode, 698362306a36Sopenharmony_ci * otherwise continue with address specific smi init/detection. 698462306a36Sopenharmony_ci */ 698562306a36Sopenharmony_ci err = mv88e6xxx_single_chip_detect(chip, mdiodev); 698662306a36Sopenharmony_ci if (err) { 698762306a36Sopenharmony_ci err = mv88e6xxx_smi_init(chip, mdiodev->bus, mdiodev->addr); 698862306a36Sopenharmony_ci if (err) 698962306a36Sopenharmony_ci goto out; 699062306a36Sopenharmony_ci 699162306a36Sopenharmony_ci err = mv88e6xxx_detect(chip); 699262306a36Sopenharmony_ci if (err) 699362306a36Sopenharmony_ci goto out; 699462306a36Sopenharmony_ci } 699562306a36Sopenharmony_ci 699662306a36Sopenharmony_ci if (chip->info->edsa_support == MV88E6XXX_EDSA_SUPPORTED) 699762306a36Sopenharmony_ci chip->tag_protocol = DSA_TAG_PROTO_EDSA; 699862306a36Sopenharmony_ci else 699962306a36Sopenharmony_ci chip->tag_protocol = DSA_TAG_PROTO_DSA; 700062306a36Sopenharmony_ci 700162306a36Sopenharmony_ci mv88e6xxx_phy_init(chip); 700262306a36Sopenharmony_ci 700362306a36Sopenharmony_ci if (chip->info->ops->get_eeprom) { 700462306a36Sopenharmony_ci if (np) 700562306a36Sopenharmony_ci of_property_read_u32(np, "eeprom-length", 700662306a36Sopenharmony_ci &chip->eeprom_len); 700762306a36Sopenharmony_ci else 700862306a36Sopenharmony_ci chip->eeprom_len = pdata->eeprom_len; 700962306a36Sopenharmony_ci } 701062306a36Sopenharmony_ci 701162306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 701262306a36Sopenharmony_ci err = mv88e6xxx_switch_reset(chip); 701362306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 701462306a36Sopenharmony_ci if (err) 701562306a36Sopenharmony_ci goto out; 701662306a36Sopenharmony_ci 701762306a36Sopenharmony_ci if (np) { 701862306a36Sopenharmony_ci chip->irq = of_irq_get(np, 0); 701962306a36Sopenharmony_ci if (chip->irq == -EPROBE_DEFER) { 702062306a36Sopenharmony_ci err = chip->irq; 702162306a36Sopenharmony_ci goto out; 702262306a36Sopenharmony_ci } 702362306a36Sopenharmony_ci } 702462306a36Sopenharmony_ci 702562306a36Sopenharmony_ci if (pdata) 702662306a36Sopenharmony_ci chip->irq = pdata->irq; 702762306a36Sopenharmony_ci 702862306a36Sopenharmony_ci /* Has to be performed before the MDIO bus is created, because 702962306a36Sopenharmony_ci * the PHYs will link their interrupts to these interrupt 703062306a36Sopenharmony_ci * controllers 703162306a36Sopenharmony_ci */ 703262306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 703362306a36Sopenharmony_ci if (chip->irq > 0) 703462306a36Sopenharmony_ci err = mv88e6xxx_g1_irq_setup(chip); 703562306a36Sopenharmony_ci else 703662306a36Sopenharmony_ci err = mv88e6xxx_irq_poll_setup(chip); 703762306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 703862306a36Sopenharmony_ci 703962306a36Sopenharmony_ci if (err) 704062306a36Sopenharmony_ci goto out; 704162306a36Sopenharmony_ci 704262306a36Sopenharmony_ci if (chip->info->g2_irqs > 0) { 704362306a36Sopenharmony_ci err = mv88e6xxx_g2_irq_setup(chip); 704462306a36Sopenharmony_ci if (err) 704562306a36Sopenharmony_ci goto out_g1_irq; 704662306a36Sopenharmony_ci } 704762306a36Sopenharmony_ci 704862306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_prob_irq_setup(chip); 704962306a36Sopenharmony_ci if (err) 705062306a36Sopenharmony_ci goto out_g2_irq; 705162306a36Sopenharmony_ci 705262306a36Sopenharmony_ci err = mv88e6xxx_g1_vtu_prob_irq_setup(chip); 705362306a36Sopenharmony_ci if (err) 705462306a36Sopenharmony_ci goto out_g1_atu_prob_irq; 705562306a36Sopenharmony_ci 705662306a36Sopenharmony_ci err = mv88e6xxx_register_switch(chip); 705762306a36Sopenharmony_ci if (err) 705862306a36Sopenharmony_ci goto out_g1_vtu_prob_irq; 705962306a36Sopenharmony_ci 706062306a36Sopenharmony_ci return 0; 706162306a36Sopenharmony_ci 706262306a36Sopenharmony_ciout_g1_vtu_prob_irq: 706362306a36Sopenharmony_ci mv88e6xxx_g1_vtu_prob_irq_free(chip); 706462306a36Sopenharmony_ciout_g1_atu_prob_irq: 706562306a36Sopenharmony_ci mv88e6xxx_g1_atu_prob_irq_free(chip); 706662306a36Sopenharmony_ciout_g2_irq: 706762306a36Sopenharmony_ci if (chip->info->g2_irqs > 0) 706862306a36Sopenharmony_ci mv88e6xxx_g2_irq_free(chip); 706962306a36Sopenharmony_ciout_g1_irq: 707062306a36Sopenharmony_ci if (chip->irq > 0) 707162306a36Sopenharmony_ci mv88e6xxx_g1_irq_free(chip); 707262306a36Sopenharmony_ci else 707362306a36Sopenharmony_ci mv88e6xxx_irq_poll_free(chip); 707462306a36Sopenharmony_ciout: 707562306a36Sopenharmony_ci if (pdata) 707662306a36Sopenharmony_ci dev_put(pdata->netdev); 707762306a36Sopenharmony_ci 707862306a36Sopenharmony_ci return err; 707962306a36Sopenharmony_ci} 708062306a36Sopenharmony_ci 708162306a36Sopenharmony_cistatic void mv88e6xxx_remove(struct mdio_device *mdiodev) 708262306a36Sopenharmony_ci{ 708362306a36Sopenharmony_ci struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 708462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip; 708562306a36Sopenharmony_ci 708662306a36Sopenharmony_ci if (!ds) 708762306a36Sopenharmony_ci return; 708862306a36Sopenharmony_ci 708962306a36Sopenharmony_ci chip = ds->priv; 709062306a36Sopenharmony_ci 709162306a36Sopenharmony_ci if (chip->info->ptp_support) { 709262306a36Sopenharmony_ci mv88e6xxx_hwtstamp_free(chip); 709362306a36Sopenharmony_ci mv88e6xxx_ptp_free(chip); 709462306a36Sopenharmony_ci } 709562306a36Sopenharmony_ci 709662306a36Sopenharmony_ci mv88e6xxx_phy_destroy(chip); 709762306a36Sopenharmony_ci mv88e6xxx_unregister_switch(chip); 709862306a36Sopenharmony_ci 709962306a36Sopenharmony_ci mv88e6xxx_g1_vtu_prob_irq_free(chip); 710062306a36Sopenharmony_ci mv88e6xxx_g1_atu_prob_irq_free(chip); 710162306a36Sopenharmony_ci 710262306a36Sopenharmony_ci if (chip->info->g2_irqs > 0) 710362306a36Sopenharmony_ci mv88e6xxx_g2_irq_free(chip); 710462306a36Sopenharmony_ci 710562306a36Sopenharmony_ci if (chip->irq > 0) 710662306a36Sopenharmony_ci mv88e6xxx_g1_irq_free(chip); 710762306a36Sopenharmony_ci else 710862306a36Sopenharmony_ci mv88e6xxx_irq_poll_free(chip); 710962306a36Sopenharmony_ci} 711062306a36Sopenharmony_ci 711162306a36Sopenharmony_cistatic void mv88e6xxx_shutdown(struct mdio_device *mdiodev) 711262306a36Sopenharmony_ci{ 711362306a36Sopenharmony_ci struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); 711462306a36Sopenharmony_ci 711562306a36Sopenharmony_ci if (!ds) 711662306a36Sopenharmony_ci return; 711762306a36Sopenharmony_ci 711862306a36Sopenharmony_ci dsa_switch_shutdown(ds); 711962306a36Sopenharmony_ci 712062306a36Sopenharmony_ci dev_set_drvdata(&mdiodev->dev, NULL); 712162306a36Sopenharmony_ci} 712262306a36Sopenharmony_ci 712362306a36Sopenharmony_cistatic const struct of_device_id mv88e6xxx_of_match[] = { 712462306a36Sopenharmony_ci { 712562306a36Sopenharmony_ci .compatible = "marvell,mv88e6085", 712662306a36Sopenharmony_ci .data = &mv88e6xxx_table[MV88E6085], 712762306a36Sopenharmony_ci }, 712862306a36Sopenharmony_ci { 712962306a36Sopenharmony_ci .compatible = "marvell,mv88e6190", 713062306a36Sopenharmony_ci .data = &mv88e6xxx_table[MV88E6190], 713162306a36Sopenharmony_ci }, 713262306a36Sopenharmony_ci { 713362306a36Sopenharmony_ci .compatible = "marvell,mv88e6250", 713462306a36Sopenharmony_ci .data = &mv88e6xxx_table[MV88E6250], 713562306a36Sopenharmony_ci }, 713662306a36Sopenharmony_ci { /* sentinel */ }, 713762306a36Sopenharmony_ci}; 713862306a36Sopenharmony_ci 713962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); 714062306a36Sopenharmony_ci 714162306a36Sopenharmony_cistatic struct mdio_driver mv88e6xxx_driver = { 714262306a36Sopenharmony_ci .probe = mv88e6xxx_probe, 714362306a36Sopenharmony_ci .remove = mv88e6xxx_remove, 714462306a36Sopenharmony_ci .shutdown = mv88e6xxx_shutdown, 714562306a36Sopenharmony_ci .mdiodrv.driver = { 714662306a36Sopenharmony_ci .name = "mv88e6085", 714762306a36Sopenharmony_ci .of_match_table = mv88e6xxx_of_match, 714862306a36Sopenharmony_ci .pm = &mv88e6xxx_pm_ops, 714962306a36Sopenharmony_ci }, 715062306a36Sopenharmony_ci}; 715162306a36Sopenharmony_ci 715262306a36Sopenharmony_cimdio_module_driver(mv88e6xxx_driver); 715362306a36Sopenharmony_ci 715462306a36Sopenharmony_ciMODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); 715562306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); 715662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 7157