diff options
Diffstat (limited to 'drivers/net/dsa')
24 files changed, 2526 insertions, 132 deletions
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 63e02a54d537..78616787f2a3 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -852,7 +852,7 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) } EXPORT_SYMBOL(b53_get_ethtool_stats); -int b53_get_sset_count(struct dsa_switch *ds) +int b53_get_sset_count(struct dsa_switch *ds, int port) { struct b53_device *dev = ds->priv; diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index ef63d24fef81..c628d0980c0b 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -30,7 +30,8 @@ struct b53_mmap_priv { static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; *val = readb(regs + (page << 8) + reg); @@ -39,7 +40,8 @@ static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; if (WARN_ON(reg % 2)) return -EINVAL; @@ -54,7 +56,8 @@ static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; if (WARN_ON(reg % 4)) return -EINVAL; @@ -69,7 +72,8 @@ static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; if (WARN_ON(reg % 2)) return -EINVAL; @@ -107,7 +111,8 @@ static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; u32 hi, lo; if (WARN_ON(reg % 4)) @@ -128,7 +133,8 @@ static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; writeb(value, regs + (page << 8) + reg); @@ -138,7 +144,8 @@ static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; if (WARN_ON(reg % 2)) return -EINVAL; @@ -154,7 +161,8 @@ static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) { - u8 __iomem *regs = dev->priv; + struct b53_mmap_priv *priv = dev->priv; + void __iomem *regs = priv->regs; if (WARN_ON(reg % 4)) return -EINVAL; @@ -223,12 +231,19 @@ static const struct b53_io_ops b53_mmap_ops = { static int b53_mmap_probe(struct platform_device *pdev) { struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_mmap_priv *priv; struct b53_device *dev; if (!pdata) return -EINVAL; - dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regs = pdata->regs; + + dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv); if (!dev) return -ENOMEM; diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index d954cf36ecd8..1187ebd79287 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -288,7 +288,7 @@ void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port); int b53_configure_vlan(struct dsa_switch *ds); void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data); void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); -int b53_get_sset_count(struct dsa_switch *ds); +int b53_get_sset_count(struct dsa_switch *ds, int port); int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state); diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 7aa84ee4e771..f77be9f85cb3 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -86,7 +86,7 @@ static int dsa_loop_setup(struct dsa_switch *ds) return 0; } -static int dsa_loop_get_sset_count(struct dsa_switch *ds) +static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port) { return __DSA_LOOP_CNT_MAX; } diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index 6171c0853ff1..fefa454f3e56 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1007,7 +1007,7 @@ static void lan9303_get_ethtool_stats(struct dsa_switch *ds, int port, } } -static int lan9303_get_sset_count(struct dsa_switch *ds) +static int lan9303_get_sset_count(struct dsa_switch *ds, int port) { return ARRAY_SIZE(lan9303_mib); } diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 663b0d5b982b..bcb3e6c734f2 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -439,7 +439,7 @@ static void ksz_disable_port(struct dsa_switch *ds, int port, ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, true); } -static int ksz_sset_count(struct dsa_switch *ds) +static int ksz_sset_count(struct dsa_switch *ds, int port) { return TOTAL_SWITCH_COUNTER_NUM; } diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 8a0bb000d056..80a4dbc3a499 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -604,7 +604,7 @@ mt7530_get_ethtool_stats(struct dsa_switch *ds, int port, } static int -mt7530_get_sset_count(struct dsa_switch *ds) +mt7530_get_sset_count(struct dsa_switch *ds, int port) { return ARRAY_SIZE(mt7530_mib); } @@ -917,7 +917,7 @@ mt7530_port_fdb_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT); - ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); + ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL); mutex_unlock(&priv->reg_mutex); return ret; @@ -933,7 +933,7 @@ mt7530_port_fdb_del(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_EMP); - ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); + ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL); mutex_unlock(&priv->reg_mutex); return ret; @@ -1293,7 +1293,7 @@ mt7530_setup(struct dsa_switch *ds) } /* Flush the FDB table */ - ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0); + ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); if (ret < 0) return ret; @@ -1409,6 +1409,7 @@ static const struct of_device_id mt7530_of_match[] = { { .compatible = "mediatek,mt7530" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, mt7530_of_match); static struct mdio_driver mt7530_mdio_driver = { .probe = mt7530_probe, @@ -1424,4 +1425,3 @@ mdio_module_driver(mt7530_mdio_driver); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mediatek-mt7530"); diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig index 1aaa7a95ebc4..ae9e7f7cb31c 100644 --- a/drivers/net/dsa/mv88e6xxx/Kconfig +++ b/drivers/net/dsa/mv88e6xxx/Kconfig @@ -18,3 +18,13 @@ config NET_DSA_MV88E6XXX_GLOBAL2 It is required on most chips. If the chip you compile the support for doesn't have such registers set, say N here. In doubt, say Y. + +config NET_DSA_MV88E6XXX_PTP + bool "PTP support for Marvell 88E6xxx" + default n + depends on NET_DSA_MV88E6XXX_GLOBAL2 + imply NETWORK_PHY_TIMESTAMPING + imply PTP_1588_CLOCK + help + Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch + chips that support it. diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index 58a4a0014e59..50de304abe2f 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -5,6 +5,10 @@ mv88e6xxx-objs += global1.o mv88e6xxx-objs += global1_atu.o mv88e6xxx-objs += global1_vtu.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o +mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_avb.o +mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o +mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o mv88e6xxx-objs += phy.o mv88e6xxx-objs += port.o +mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o mv88e6xxx-objs += serdes.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index eb328bade225..3d2091099f7f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -36,8 +36,10 @@ #include "chip.h" #include "global1.h" #include "global2.h" +#include "hwtstamp.h" #include "phy.h" #include "port.h" +#include "ptp.h" #include "serdes.h" static void assert_reg_lock(struct mv88e6xxx_chip *chip) @@ -251,9 +253,8 @@ static void mv88e6xxx_g1_irq_unmask(struct irq_data *d) chip->g1_irq.masked &= ~(1 << n); } -static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) +static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) { - struct mv88e6xxx_chip *chip = dev_id; unsigned int nhandled = 0; unsigned int sub_irq; unsigned int n; @@ -278,6 +279,13 @@ out: return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); } +static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) +{ + struct mv88e6xxx_chip *chip = dev_id; + + return mv88e6xxx_g1_irq_thread_work(chip); +} + static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d) { struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); @@ -333,7 +341,7 @@ static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { .xlate = irq_domain_xlate_twocell, }; -static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) +static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip) { int irq, virq; u16 mask; @@ -342,8 +350,6 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) mask &= ~GENMASK(chip->g1_irq.nirqs, 0); mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); - free_irq(chip->irq, chip); - for (irq = 0; irq < chip->g1_irq.nirqs; irq++) { virq = irq_find_mapping(chip->g1_irq.domain, irq); irq_dispose_mapping(virq); @@ -352,7 +358,14 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) irq_domain_remove(chip->g1_irq.domain); } -static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) +static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) +{ + mv88e6xxx_g1_irq_free_common(chip); + + free_irq(chip->irq, chip); +} + +static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip) { int err, irq, virq; u16 reg, mask; @@ -385,13 +398,6 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) if (err) goto out_disable; - err = request_threaded_irq(chip->irq, NULL, - mv88e6xxx_g1_irq_thread_fn, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - dev_name(chip->dev), chip); - if (err) - goto out_disable; - return 0; out_disable: @@ -409,6 +415,64 @@ out_mapping: return err; } +static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) +{ + int err; + + err = mv88e6xxx_g1_irq_setup_common(chip); + if (err) + return err; + + err = request_threaded_irq(chip->irq, NULL, + mv88e6xxx_g1_irq_thread_fn, + IRQF_ONESHOT, + dev_name(chip->dev), chip); + if (err) + mv88e6xxx_g1_irq_free_common(chip); + + return err; +} + +static void mv88e6xxx_irq_poll(struct kthread_work *work) +{ + struct mv88e6xxx_chip *chip = container_of(work, + struct mv88e6xxx_chip, + irq_poll_work.work); + mv88e6xxx_g1_irq_thread_work(chip); + + kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, + msecs_to_jiffies(100)); +} + +static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) +{ + int err; + + err = mv88e6xxx_g1_irq_setup_common(chip); + if (err) + return err; + + kthread_init_delayed_work(&chip->irq_poll_work, + mv88e6xxx_irq_poll); + + chip->kworker = kthread_create_worker(0, dev_name(chip->dev)); + if (IS_ERR(chip->kworker)) + return PTR_ERR(chip->kworker); + + kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, + msecs_to_jiffies(100)); + + return 0; +} + +static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip) +{ + mv88e6xxx_g1_irq_free_common(chip); + + kthread_cancel_delayed_work_sync(&chip->irq_poll_work); + kthread_destroy_worker(chip->kworker); +} + int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask) { int i; @@ -604,7 +668,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, return UINT64_MAX; low = reg; - if (s->sizeof_stat == 4) { + if (s->size == 4) { err = mv88e6xxx_port_read(chip, port, s->reg + 1, ®); if (err) return UINT64_MAX; @@ -617,7 +681,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, case STATS_TYPE_BANK0: reg |= s->reg | histogram; mv88e6xxx_g1_stats_read(chip, reg, &low); - if (s->sizeof_stat == 8) + if (s->size == 8) mv88e6xxx_g1_stats_read(chip, reg + 1, &high); break; default: @@ -627,8 +691,8 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, return value; } -static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data, int types) +static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t *data, int types) { struct mv88e6xxx_hw_stat *stat; int i, j; @@ -641,29 +705,62 @@ static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, j++; } } + + return j; } -static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data) +static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t *data) { - mv88e6xxx_stats_get_strings(chip, data, - STATS_TYPE_BANK0 | STATS_TYPE_PORT); + return mv88e6xxx_stats_get_strings(chip, data, + STATS_TYPE_BANK0 | STATS_TYPE_PORT); } -static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data) +static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t *data) { - mv88e6xxx_stats_get_strings(chip, data, - STATS_TYPE_BANK0 | STATS_TYPE_BANK1); + return mv88e6xxx_stats_get_strings(chip, data, + STATS_TYPE_BANK0 | STATS_TYPE_BANK1); +} + +static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { + "atu_member_violation", + "atu_miss_violation", + "atu_full_violation", + "vtu_member_violation", + "vtu_miss_violation", +}; + +static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) + strlcpy(data + i * ETH_GSTRING_LEN, + mv88e6xxx_atu_vtu_stats_strings[i], + ETH_GSTRING_LEN); } static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data) { struct mv88e6xxx_chip *chip = ds->priv; + int count = 0; + + mutex_lock(&chip->reg_lock); if (chip->info->ops->stats_get_strings) - chip->info->ops->stats_get_strings(chip, data); + count = chip->info->ops->stats_get_strings(chip, data); + + if (chip->info->ops->serdes_get_strings) { + data += count * ETH_GSTRING_LEN; + count = chip->info->ops->serdes_get_strings(chip, port, data); + } + + data += count * ETH_GSTRING_LEN; + mv88e6xxx_atu_vtu_get_strings(data); + + mutex_unlock(&chip->reg_lock); } static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip, @@ -692,19 +789,37 @@ static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip) STATS_TYPE_BANK1); } -static int mv88e6xxx_get_sset_count(struct dsa_switch *ds) +static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port) { struct mv88e6xxx_chip *chip = ds->priv; + int serdes_count = 0; + int count = 0; + mutex_lock(&chip->reg_lock); if (chip->info->ops->stats_get_sset_count) - return chip->info->ops->stats_get_sset_count(chip); + count = chip->info->ops->stats_get_sset_count(chip); + if (count < 0) + goto out; - return 0; + if (chip->info->ops->serdes_get_sset_count) + serdes_count = chip->info->ops->serdes_get_sset_count(chip, + port); + if (serdes_count < 0) { + count = serdes_count; + goto out; + } + count += serdes_count; + count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); + +out: + mutex_unlock(&chip->reg_lock); + + return count; } -static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, - uint64_t *data, int types, - u16 bank1_select, u16 histogram) +static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data, int types, + u16 bank1_select, u16 histogram) { struct mv88e6xxx_hw_stat *stat; int i, j; @@ -712,24 +827,28 @@ static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port, for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { stat = &mv88e6xxx_hw_stats[i]; if (stat->type & types) { + mutex_lock(&chip->reg_lock); data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port, bank1_select, histogram); + mutex_unlock(&chip->reg_lock); + j++; } } + return j; } -static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, - uint64_t *data) +static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data) { return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0 | STATS_TYPE_PORT, 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); } -static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, - uint64_t *data) +static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data) { return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0 | STATS_TYPE_BANK1, @@ -737,8 +856,8 @@ static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); } -static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, - uint64_t *data) +static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data) { return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0 | STATS_TYPE_BANK1, @@ -746,11 +865,32 @@ static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 0); } +static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data) +{ + *data++ = chip->ports[port].atu_member_violation; + *data++ = chip->ports[port].atu_miss_violation; + *data++ = chip->ports[port].atu_full_violation; + *data++ = chip->ports[port].vtu_member_violation; + *data++ = chip->ports[port].vtu_miss_violation; +} + static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, uint64_t *data) { + int count = 0; + if (chip->info->ops->stats_get_stats) - chip->info->ops->stats_get_stats(chip, port, data); + count = chip->info->ops->stats_get_stats(chip, port, data); + + mutex_lock(&chip->reg_lock); + if (chip->info->ops->serdes_get_stats) { + data += count; + count = chip->info->ops->serdes_get_stats(chip, port, data); + } + data += count; + mv88e6xxx_atu_vtu_get_stats(chip, port, data); + mutex_unlock(&chip->reg_lock); } static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, @@ -762,14 +902,13 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); ret = mv88e6xxx_stats_snapshot(chip, port); - if (ret < 0) { - mutex_unlock(&chip->reg_lock); + mutex_unlock(&chip->reg_lock); + + if (ret < 0) return; - } mv88e6xxx_get_stats(chip, port, data); - mutex_unlock(&chip->reg_lock); } static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip) @@ -1433,7 +1572,9 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, eth_broadcast_addr(addr.mac); do { + mutex_lock(&chip->reg_lock); err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); + mutex_unlock(&chip->reg_lock); if (err) return err; @@ -1466,7 +1607,10 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, int err; /* Dump port's default Filtering Information Database (VLAN ID 0) */ + mutex_lock(&chip->reg_lock); err = mv88e6xxx_port_get_fid(chip, port, &fid); + mutex_unlock(&chip->reg_lock); + if (err) return err; @@ -1476,7 +1620,9 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, /* Dump VLANs' Filtering Information Databases */ do { + mutex_lock(&chip->reg_lock); err = mv88e6xxx_vtu_getnext(chip, &vlan); + mutex_unlock(&chip->reg_lock); if (err) return err; @@ -1496,13 +1642,8 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, void *data) { struct mv88e6xxx_chip *chip = ds->priv; - int err; - - mutex_lock(&chip->reg_lock); - err = mv88e6xxx_port_db_dump(chip, port, cb, data); - mutex_unlock(&chip->reg_lock); - return err; + return mv88e6xxx_port_db_dump(chip, port, cb, data); } static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, @@ -2092,6 +2233,17 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) if (err) goto unlock; + /* Setup PTP Hardware Clock and timestamping */ + if (chip->info->ptp_support) { + err = mv88e6xxx_ptp_setup(chip); + if (err) + goto unlock; + + err = mv88e6xxx_hwtstamp_setup(chip); + if (err) + goto unlock; + } + unlock: mutex_unlock(&chip->reg_lock); @@ -2148,6 +2300,15 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, struct mii_bus *bus; int err; + if (external) { + mutex_lock(&chip->reg_lock); + err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true); + mutex_unlock(&chip->reg_lock); + + if (err) + return err; + } + bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus)); if (!bus) return -ENOMEM; @@ -2170,12 +2331,19 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, bus->write = mv88e6xxx_mdio_write; bus->parent = chip->dev; + if (!external) { + err = mv88e6xxx_g2_irq_mdio_setup(chip, bus); + if (err) + return err; + } + if (np) err = of_mdiobus_register(bus, np); else err = mdiobus_register(bus); if (err) { dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err); + mv88e6xxx_g2_irq_mdio_free(chip, bus); return err; } @@ -2202,6 +2370,9 @@ static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) list_for_each_entry(mdio_bus, &chip->mdios, list) { bus = mdio_bus->bus; + if (!mdio_bus->external) + mv88e6xxx_g2_irq_mdio_free(chip, bus); + mdiobus_unregister(bus); } } @@ -2472,6 +2643,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, }; static const struct mv88e6xxx_ops mv88e6161_ops = { @@ -2602,6 +2774,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6352_serdes_power, + .gpio_ops = &mv88e6352_gpio_ops, }; static const struct mv88e6xxx_ops mv88e6175_ops = { @@ -2673,6 +2846,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6352_serdes_power, + .gpio_ops = &mv88e6352_gpio_ops, }; static const struct mv88e6xxx_ops mv88e6185_ops = { @@ -2736,6 +2910,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, + .gpio_ops = &mv88e6352_gpio_ops, }; static const struct mv88e6xxx_ops mv88e6190x_ops = { @@ -2771,6 +2946,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, + .gpio_ops = &mv88e6352_gpio_ops, }; static const struct mv88e6xxx_ops mv88e6191_ops = { @@ -2843,6 +3019,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6352_serdes_power, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, }; static const struct mv88e6xxx_ops mv88e6290_ops = { @@ -2879,6 +3057,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6390_avb_ops, }; static const struct mv88e6xxx_ops mv88e6320_ops = { @@ -2913,6 +3093,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, }; static const struct mv88e6xxx_ops mv88e6321_ops = { @@ -2945,6 +3127,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6352_avb_ops, }; static const struct mv88e6xxx_ops mv88e6341_ops = { @@ -2981,6 +3165,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .gpio_ops = |
