From: Vladimir Oltean The KSZ switch families are sufficiently different that a common ds->ops->setup() - ksz_setup() with micro-managed dev_ops->reset(), dev_ops->pcs_create(), dev_ops->config_cpu_port(), dev_ops->enable_stp_addr(), dev_ops->setup() seems to be too convoluted. I am proposing to make each KSZ switch family part ways for dsa_switch_ops :: setup() and teardown(), to allow them greater flexibility. This here is the implementation for ksz8, which is nothing other than a copy of ksz_setup() with the dev_ops function pointers replaced with direct function calls. Signed-off-by: Vladimir Oltean Signed-off-by: Bastien Curutchet (Schneider Electric) --- drivers/net/dsa/microchip/ksz8.c | 139 +++++++++++++++++++++++++++++++++------ 1 file changed, 119 insertions(+), 20 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index ccbc3480717f0..acc898c68f985 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -1935,9 +1935,52 @@ static int ksz8_enable_stp_addr(struct ksz_device *dev) static int ksz8_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; - const u16 *regs = dev->info->regs; - int i, ret = 0; + u16 storm_mask, storm_rate; + struct dsa_port *dp; + struct ksz_port *p; + const u16 *regs; + int i, ret; + + regs = dev->info->regs; + + dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), + dev->info->num_vlans, GFP_KERNEL); + if (!dev->vlan_cache) + return -ENOMEM; + + ret = ksz8_reset_switch(dev); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + ret = ksz_parse_drive_strength(dev); + if (ret) + return ret; + + /* set broadcast storm protection 10% rate */ + storm_mask = BROADCAST_STORM_RATE; + storm_rate = (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100; + if (ksz_is_ksz8463(dev)) { + storm_mask = swab16(storm_mask); + storm_rate = swab16(storm_rate); + } + regmap_update_bits(ksz_regmap_16(dev), regs[S_BROADCAST_CTRL], + storm_mask, storm_rate); + + ksz8_config_cpu_port(ds); + + ksz8_enable_stp_addr(dev); + + ds->num_tx_queues = dev->info->num_tx_queues; + + regmap_update_bits(ksz_regmap_8(dev), regs[S_MULTICAST_CTRL], + MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE); + + ksz_init_mib_timer(dev); + ds->configure_vlan_while_not_filtering = false; + ds->dscp_prio_mapping_is_global = true; ds->mtu_enforcement_ingress = true; /* We rely on software untagging on the CPU port, so that we @@ -1987,12 +2030,80 @@ static int ksz8_setup(struct dsa_switch *ds) ret = ksz8_pme_write8(dev, regs[REG_SW_PME_CTRL], 0); if (!ret) ret = ksz_rmw8(dev, REG_INT_ENABLE, INT_PME, 0); + if (ret) + return ret; } - if (!ret) - return ksz8_handle_global_errata(ds); - else + ret = ksz8_handle_global_errata(ds); + if (ret) return ret; + + /* Start with learning disabled on standalone user ports, and enabled + * on the CPU port. In lack of other finer mechanisms, learning on the + * CPU port will avoid flooding bridge local addresses on the network + * in some cases. + */ + p = &dev->ports[dev->cpu_port]; + p->learning = true; + + if (dev->irq > 0) { + ret = ksz_girq_setup(dev); + if (ret) + return ret; + + dsa_switch_for_each_user_port(dp, dev->ds) { + ret = ksz_pirq_setup(dev, dp->index); + if (ret) + goto port_release; + + if (dev->info->ptp_capable) { + ret = ksz_ptp_irq_setup(ds, dp->index); + if (ret) + goto pirq_release; + } + } + } + + if (dev->info->ptp_capable) { + ret = ksz_ptp_clock_register(ds); + if (ret) { + dev_err(dev->dev, "Failed to register PTP clock: %d\n", + ret); + goto port_release; + } + } + + ret = ksz_mdio_register(dev); + if (ret < 0) { + dev_err(dev->dev, "failed to register the mdio"); + goto out_ptp_clock_unregister; + } + + ret = ksz_dcb_init(dev); + if (ret) + goto out_ptp_clock_unregister; + + /* start switch */ + regmap_update_bits(ksz_regmap_8(dev), regs[S_START_CTRL], + SW_START, SW_START); + + return 0; + +out_ptp_clock_unregister: + if (dev->info->ptp_capable) + ksz_ptp_clock_unregister(ds); +port_release: + if (dev->irq > 0) { + dsa_switch_for_each_user_port_continue_reverse(dp, dev->ds) { + if (dev->info->ptp_capable) + ksz_ptp_irq_free(ds, dp->index); +pirq_release: + ksz_irq_free(&dev->ports[dp->index].pirq); + } + ksz_irq_free(&dev->girq); + } + + return ret; } static void ksz8_phylink_get_caps(struct dsa_switch *ds, int port, @@ -2206,7 +2317,6 @@ const struct phylink_mac_ops ksz8_phylink_mac_ops = { }; const struct ksz_dev_ops ksz8463_dev_ops = { - .setup = ksz8_setup, .get_port_addr = ksz8463_get_port_addr, .cfg_port_member = ksz8_cfg_port_member, .port_setup = ksz8_port_setup, @@ -2217,14 +2327,10 @@ const struct ksz_dev_ops ksz8463_dev_ops = { .r_mib_stat64 = ksz88xx_r_mib_stats64, .freeze_mib = ksz8_freeze_mib, .port_init_cnt = ksz8_port_init_cnt, - .config_cpu_port = ksz8_config_cpu_port, - .enable_stp_addr = ksz8_enable_stp_addr, - .reset = ksz8_reset_switch, .init = ksz8_switch_init, }; const struct ksz_dev_ops ksz87xx_dev_ops = { - .setup = ksz8_setup, .get_port_addr = ksz8_get_port_addr, .cfg_port_member = ksz8_cfg_port_member, .port_setup = ksz8_port_setup, @@ -2235,9 +2341,6 @@ const struct ksz_dev_ops ksz87xx_dev_ops = { .r_mib_stat64 = ksz_r_mib_stats64, .freeze_mib = ksz8_freeze_mib, .port_init_cnt = ksz8_port_init_cnt, - .config_cpu_port = ksz8_config_cpu_port, - .enable_stp_addr = ksz8_enable_stp_addr, - .reset = ksz8_reset_switch, .init = ksz8_switch_init, .pme_write8 = ksz8_pme_write8, .pme_pread8 = ksz8_pme_pread8, @@ -2245,7 +2348,6 @@ const struct ksz_dev_ops ksz87xx_dev_ops = { }; const struct ksz_dev_ops ksz88xx_dev_ops = { - .setup = ksz8_setup, .get_port_addr = ksz8_get_port_addr, .cfg_port_member = ksz8_cfg_port_member, .port_setup = ksz8_port_setup, @@ -2256,9 +2358,6 @@ const struct ksz_dev_ops ksz88xx_dev_ops = { .r_mib_stat64 = ksz88xx_r_mib_stats64, .freeze_mib = ksz8_freeze_mib, .port_init_cnt = ksz8_port_init_cnt, - .config_cpu_port = ksz8_config_cpu_port, - .enable_stp_addr = ksz8_enable_stp_addr, - .reset = ksz8_reset_switch, .init = ksz8_switch_init, .pme_write8 = ksz8_pme_write8, .pme_pread8 = ksz8_pme_pread8, @@ -2269,7 +2368,7 @@ const struct dsa_switch_ops ksz8463_switch_ops = { .get_tag_protocol = ksz8463_get_tag_protocol, .connect_tag_protocol = ksz8463_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, - .setup = ksz_setup, + .setup = ksz8_setup, .teardown = ksz_teardown, .phy_read = ksz_phy_read16, .phy_write = ksz_phy_write16, @@ -2329,7 +2428,7 @@ const struct dsa_switch_ops ksz87xx_switch_ops = { .get_tag_protocol = ksz87xx_get_tag_protocol, .connect_tag_protocol = ksz87xx_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, - .setup = ksz_setup, + .setup = ksz8_setup, .teardown = ksz_teardown, .phy_read = ksz_phy_read16, .phy_write = ksz_phy_write16, @@ -2389,7 +2488,7 @@ const struct dsa_switch_ops ksz88xx_switch_ops = { .get_tag_protocol = ksz88xx_get_tag_protocol, .connect_tag_protocol = ksz88xx_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, - .setup = ksz_setup, + .setup = ksz8_setup, .teardown = ksz_teardown, .phy_read = ksz_phy_read16, .phy_write = ksz_phy_write16, -- 2.53.0