diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index 825133e9ce6e..0f84b2e7d25d 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -1057,6 +1057,19 @@ static int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) return 0; } +static int ksz8_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val = 0xffff; + int ret; + + ret = ksz8_r_phy(dev, addr, reg, &val); + if (ret) + return ret; + + return val; +} + /** * ksz8_w_phy_ctrl - Translates and writes to the SMI interface from a MIIM PHY * Control register (Reg. 31). @@ -1266,6 +1279,18 @@ static int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) return 0; } +static int ksz8_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) +{ + struct ksz_device *dev = ds->priv; + int ret; + + ret = ksz8_w_phy(dev, addr, reg, val); + if (ret) + return ret; + + return 0; +} + static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) { int offset = P_MIRROR_CTRL; @@ -1692,6 +1717,17 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) ksz8_pme_pwrite8(dev, port, regs[REG_PORT_PME_CTRL], 0); } +static int ksz8_dsa_port_setup(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + + if (!dsa_is_user_port(ds, port)) + return 0; + + ksz8_port_setup(dev, port, false); + return ksz_dcb_init_port(dev, port); +} + static void ksz88x3_config_rmii_clk(struct ksz_device *dev) { struct dsa_port *cpu_dp = dsa_to_port(dev->ds, dev->cpu_port); @@ -1935,9 +1971,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 +2066,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, @@ -2072,6 +2219,19 @@ static int ksz8463_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) return 0; } +static int ksz8463_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val = 0xffff; + int ret; + + ret = ksz8463_r_phy(dev, addr, reg, &val); + if (ret) + return ret; + + return val; +} + static int ksz8463_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) { u16 sw_reg = 0; @@ -2100,6 +2260,18 @@ static int ksz8463_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) return 0; } +static int ksz8463_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) +{ + struct ksz_device *dev = ds->priv; + int ret; + + ret = ksz8463_w_phy(dev, addr, reg, val); + if (ret) + return ret; + + return 0; +} + static int ksz8_switch_init(struct ksz_device *dev) { dev->cpu_port = fls(dev->info->cpu_ports) - 1; @@ -2109,11 +2281,6 @@ static int ksz8_switch_init(struct ksz_device *dev) return 0; } -static void ksz8_switch_exit(struct ksz_device *dev) -{ - ksz8_reset_switch(dev); -} - static enum dsa_tag_protocol ksz8463_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp) @@ -2211,63 +2378,39 @@ 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, - .r_phy = ksz8463_r_phy, - .w_phy = ksz8463_w_phy, .r_mib_cnt = ksz8_r_mib_cnt, .r_mib_pkt = ksz8_r_mib_pkt, .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, - .exit = ksz8_switch_exit, }; 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, - .r_phy = ksz8_r_phy, - .w_phy = ksz8_w_phy, .r_mib_cnt = ksz8_r_mib_cnt, .r_mib_pkt = ksz8_r_mib_pkt, .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, - .exit = ksz8_switch_exit, .pme_write8 = ksz8_pme_write8, .pme_pread8 = ksz8_pme_pread8, .pme_pwrite8 = ksz8_pme_pwrite8, }; 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, - .r_phy = ksz8_r_phy, - .w_phy = ksz8_w_phy, .r_mib_cnt = ksz8_r_mib_cnt, .r_mib_pkt = ksz8_r_mib_pkt, .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, - .exit = ksz8_switch_exit, .pme_write8 = ksz8_pme_write8, .pme_pread8 = ksz8_pme_pread8, .pme_pwrite8 = ksz8_pme_pwrite8, @@ -2277,12 +2420,12 @@ 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, + .phy_read = ksz8463_phy_read16, + .phy_write = ksz8463_phy_write16, .phylink_get_caps = ksz8_phylink_get_caps, - .port_setup = ksz_port_setup, + .port_setup = ksz8_dsa_port_setup, .get_strings = ksz_get_strings, .get_ethtool_stats = ksz_get_ethtool_stats, .get_sset_count = ksz_sset_count, @@ -2337,12 +2480,12 @@ 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, + .phy_read = ksz8_phy_read16, + .phy_write = ksz8_phy_write16, .phylink_get_caps = ksz8_phylink_get_caps, - .port_setup = ksz_port_setup, + .port_setup = ksz8_dsa_port_setup, .get_strings = ksz_get_strings, .get_ethtool_stats = ksz_get_ethtool_stats, .get_sset_count = ksz_sset_count, @@ -2397,12 +2540,12 @@ 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, + .phy_read = ksz8_phy_read16, + .phy_write = ksz8_phy_write16, .phylink_get_caps = ksz8_phylink_get_caps, - .port_setup = ksz_port_setup, + .port_setup = ksz8_dsa_port_setup, .get_strings = ksz_get_strings, .get_ethtool_stats = ksz_get_ethtool_stats, .get_sset_count = ksz_sset_count, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 65fd07ef73ad..c1395322e54b 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -575,6 +575,19 @@ static int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) return 0; } +static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val = 0xffff; + int ret; + + ret = ksz9477_r_phy(dev, addr, reg, &val); + if (ret) + return ret; + + return val; +} + static int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { u32 mask, val32; @@ -600,6 +613,18 @@ static int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) return ksz_prmw32(dev, addr, 0x100 + (reg << 1), mask, val32); } +static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) +{ + struct ksz_device *dev = ds->priv; + int ret; + + ret = ksz9477_w_phy(dev, addr, reg, val); + if (ret) + return ret; + + return 0; +} + void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member) { ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member); @@ -1309,6 +1334,23 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) ksz_pwrite8(dev, port, regs[REG_PORT_PME_CTRL], 0); } +static int ksz9477_dsa_port_setup(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + int ret; + + if (!dsa_is_user_port(ds, port)) + return 0; + + ksz9477_port_setup(dev, port, false); + + ret = ksz9477_set_default_prio_queue_mapping(dev, port); + if (ret) + return ret; + + return ksz_dcb_init_port(dev, port); +} + static void ksz9477_config_cpu_port(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -1477,9 +1519,54 @@ int ksz9477_enable_stp_addr(struct ksz_device *dev) static int ksz9477_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; - const u16 *regs = dev->info->regs; - int ret = 0; + u16 storm_mask, storm_rate; + struct dsa_port *dp; + struct ksz_port *p; + const u16 *regs; + int 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 = ksz9477_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; + + if (ksz_has_sgmii_port(dev)) { + ret = ksz9477_pcs_create(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; + regmap_update_bits(ksz_regmap_16(dev), regs[S_BROADCAST_CTRL], + storm_mask, storm_rate); + + ksz9477_config_cpu_port(ds); + + ksz9477_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; /* Required for port partitioning. */ @@ -1512,7 +1599,76 @@ static int ksz9477_setup(struct dsa_switch *ds) * be enabled by ksz_wol_pre_shutdown(). Otherwise, some PMICs * do not like PME events changes before shutdown. */ - return ksz_write8(dev, regs[REG_SW_PME_CTRL], 0); + ret = ksz_write8(dev, regs[REG_SW_PME_CTRL], 0); + if (ret < 0) + 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; } u32 ksz9477_get_port_addr(int port, int offset) @@ -1624,11 +1780,6 @@ static int ksz9477_switch_init(struct ksz_device *dev) return 0; } -static void ksz9477_switch_exit(struct ksz_device *dev) -{ - ksz9477_reset_switch(dev); -} - static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp) @@ -1784,12 +1935,8 @@ const struct phylink_mac_ops ksz9477_phylink_mac_ops = { }; const struct ksz_dev_ops ksz9477_dev_ops = { - .setup = ksz9477_setup, .get_port_addr = ksz9477_get_port_addr, .cfg_port_member = ksz9477_cfg_port_member, - .port_setup = ksz9477_port_setup, - .r_phy = ksz9477_r_phy, - .w_phy = ksz9477_w_phy, .r_mib_cnt = ksz9477_r_mib_cnt, .r_mib_pkt = ksz9477_r_mib_pkt, .r_mib_stat64 = ksz_r_mib_stats64, @@ -1798,25 +1945,20 @@ const struct ksz_dev_ops ksz9477_dev_ops = { .pme_write8 = ksz_write8, .pme_pread8 = ksz_pread8, .pme_pwrite8 = ksz_pwrite8, - .config_cpu_port = ksz9477_config_cpu_port, .tc_cbs_set_cinc = ksz9477_tc_cbs_set_cinc, - .enable_stp_addr = ksz9477_enable_stp_addr, - .reset = ksz9477_reset_switch, .init = ksz9477_switch_init, - .exit = ksz9477_switch_exit, - .pcs_create = ksz9477_pcs_create, }; const struct dsa_switch_ops ksz9477_switch_ops = { .get_tag_protocol = ksz9477_get_tag_protocol, .connect_tag_protocol = ksz9477_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, - .setup = ksz_setup, + .setup = ksz9477_setup, .teardown = ksz_teardown, - .phy_read = ksz_phy_read16, - .phy_write = ksz_phy_write16, + .phy_read = ksz9477_phy_read16, + .phy_write = ksz9477_phy_write16, .phylink_get_caps = ksz9477_phylink_get_caps, - .port_setup = ksz_port_setup, + .port_setup = ksz9477_dsa_port_setup, .set_ageing_time = ksz9477_set_ageing_time, .get_strings = ksz_get_strings, .get_ethtool_stats = ksz_get_ethtool_stats, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 4a7bcd1a9392..57c8abfe0147 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2260,22 +2260,18 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct ksz_device *dev = bus->priv; - u16 val; - int ret; + struct dsa_switch *ds = dev->ds; - ret = dev->dev_ops->r_phy(dev, addr, regnum, &val); - if (ret < 0) - return ret; - - return val; + return ds->ops->phy_read(ds, addr, regnum); } static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) { struct ksz_device *dev = bus->priv; + struct dsa_switch *ds = dev->ds; - return dev->dev_ops->w_phy(dev, addr, regnum, val); + return ds->ops->phy_write(ds, addr, regnum, val); } /** @@ -2488,7 +2484,7 @@ static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, * * Return: 0 on success, or a negative error code on failure. */ -static int ksz_mdio_register(struct ksz_device *dev) +int ksz_mdio_register(struct ksz_device *dev) { struct device_node *parent_bus_node; struct mii_bus *parent_bus = NULL; @@ -2644,7 +2640,7 @@ static const struct irq_domain_ops ksz_irq_domain_ops = { .xlate = irq_domain_xlate_twocell, }; -static void ksz_irq_free(struct ksz_irq *kirq) +void ksz_irq_free(struct ksz_irq *kirq) { int irq, virq; @@ -2713,7 +2709,7 @@ out: return ret; } -static int ksz_girq_setup(struct ksz_device *dev) +int ksz_girq_setup(struct ksz_device *dev) { struct ksz_irq *girq = &dev->girq; @@ -2728,7 +2724,7 @@ static int ksz_girq_setup(struct ksz_device *dev) return ksz_irq_common_setup(dev, girq); } -static int ksz_pirq_setup(struct ksz_device *dev, u8 p) +int ksz_pirq_setup(struct ksz_device *dev, u8 p) { struct ksz_irq *pirq = &dev->ports[p].pirq; @@ -2745,138 +2741,6 @@ static int ksz_pirq_setup(struct ksz_device *dev, u8 p) return ksz_irq_common_setup(dev, pirq); } -static int ksz_parse_drive_strength(struct ksz_device *dev); - -int ksz_setup(struct dsa_switch *ds) -{ - struct ksz_device *dev = ds->priv; - u16 storm_mask, storm_rate; - struct dsa_port *dp; - struct ksz_port *p; - const u16 *regs; - int 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 = dev->dev_ops->reset(dev); - if (ret) { - dev_err(ds->dev, "failed to reset switch\n"); - return ret; - } - - ret = ksz_parse_drive_strength(dev); - if (ret) - return ret; - - if (ksz_has_sgmii_port(dev) && dev->dev_ops->pcs_create) { - ret = dev->dev_ops->pcs_create(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); - - dev->dev_ops->config_cpu_port(ds); - - dev->dev_ops->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; - - if (dev->dev_ops->setup) { - ret = dev->dev_ops->setup(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; -} - void ksz_teardown(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -2895,9 +2759,6 @@ void ksz_teardown(struct dsa_switch *ds) ksz_irq_free(&dev->girq); } - - if (dev->dev_ops->teardown) - dev->dev_ops->teardown(ds); } static void port_r_cnt(struct ksz_device *dev, int port) @@ -2977,31 +2838,6 @@ void ksz_init_mib_timer(struct ksz_device *dev) } } -int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) -{ - struct ksz_device *dev = ds->priv; - u16 val = 0xffff; - int ret; - - ret = dev->dev_ops->r_phy(dev, addr, reg, &val); - if (ret) - return ret; - - return val; -} - -int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) -{ - struct ksz_device *dev = ds->priv; - int ret; - - ret = dev->dev_ops->w_phy(dev, addr, reg, val); - if (ret) - return ret; - - return 0; -} - u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) { struct ksz_device *dev = ds->priv; @@ -3082,8 +2918,7 @@ void ksz_port_bridge_leave(struct dsa_switch *ds, int port, */ } -static int ksz9477_set_default_prio_queue_mapping(struct ksz_device *dev, - int port) +int ksz9477_set_default_prio_queue_mapping(struct ksz_device *dev, int port) { u32 queue_map = 0; int ipm; @@ -3105,30 +2940,6 @@ static int ksz9477_set_default_prio_queue_mapping(struct ksz_device *dev, return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map); } -int ksz_port_setup(struct dsa_switch *ds, int port) -{ - struct ksz_device *dev = ds->priv; - int ret; - - if (!dsa_is_user_port(ds, port)) - return 0; - - /* setup user port */ - dev->dev_ops->port_setup(dev, port, false); - - if (!is_ksz8(dev)) { - ret = ksz9477_set_default_prio_queue_mapping(dev, port); - if (ret) - return ret; - } - - /* port_stp_state_set() will be called after to enable the port so - * there is no need to do anything. - */ - - return ksz_dcb_init_port(dev, port); -} - void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { struct ksz_device *dev = ds->priv; @@ -4162,24 +3973,19 @@ int ksz_set_wol(struct dsa_switch *ds, int port, * ksz_wol_pre_shutdown - Prepares the switch device for shutdown while * considering Wake-on-LAN (WoL) settings. * @dev: The switch device structure. - * @wol_enabled: Pointer to a boolean which will be set to true if WoL is - * enabled on any port. * * This function prepares the switch device for a safe shutdown while taking - * into account the Wake-on-LAN (WoL) settings on the user ports. It updates - * the wol_enabled flag accordingly to reflect whether WoL is active on any - * port. + * into account the Wake-on-LAN (WoL) settings on the user ports. */ -static void ksz_wol_pre_shutdown(struct ksz_device *dev, bool *wol_enabled) +static void ksz_wol_pre_shutdown(struct ksz_device *dev) { const struct ksz_dev_ops *ops = dev->dev_ops; const u16 *regs = dev->info->regs; u8 pme_pin_en = PME_ENABLE; + bool wol_enabled = false; struct dsa_port *dp; int ret; - *wol_enabled = false; - if (!is_ksz9477(dev) && !ksz_is_ksz87xx(dev)) return; @@ -4192,7 +3998,7 @@ static void ksz_wol_pre_shutdown(struct ksz_device *dev, bool *wol_enabled) ret = ops->pme_pread8(dev, dp->index, regs[REG_PORT_PME_CTRL], &pme_ctrl); if (!ret && pme_ctrl) - *wol_enabled = true; + wol_enabled = true; /* make sure there are no pending wake events which would * prevent the device from going to sleep/shutdown. @@ -4201,7 +4007,7 @@ static void ksz_wol_pre_shutdown(struct ksz_device *dev, bool *wol_enabled) } /* Now we are save to enable PME pin. */ - if (*wol_enabled) { + if (wol_enabled) { if (dev->pme_active_high) pme_pin_en |= PME_POLARITY; ops->pme_write8(dev, regs[REG_SW_PME_CTRL], pme_pin_en); @@ -4480,20 +4286,12 @@ EXPORT_SYMBOL(ksz_switch_alloc); * @dev: The switch device structure. * * This function is responsible for initiating a shutdown sequence for the - * switch device. It invokes the reset operation defined in the device - * operations, if available, to reset the switch. Subsequently, it calls the - * DSA framework's shutdown function to ensure a proper shutdown of the DSA - * switch. + * switch device. Subsequently, it calls the DSA framework's shutdown function + * to ensure a proper shutdown of the DSA switch. */ void ksz_switch_shutdown(struct ksz_device *dev) { - bool wol_enabled = false; - - ksz_wol_pre_shutdown(dev, &wol_enabled); - - if (dev->dev_ops->reset && !wol_enabled) - dev->dev_ops->reset(dev); - + ksz_wol_pre_shutdown(dev); dsa_switch_shutdown(dev->ds); } EXPORT_SYMBOL(ksz_switch_shutdown); @@ -4707,7 +4505,7 @@ static int ksz88x3_drive_strength_write(struct ksz_device *dev, * * Return: 0 on success, error code otherwise */ -static int ksz_parse_drive_strength(struct ksz_device *dev) +int ksz_parse_drive_strength(struct ksz_device *dev) { struct ksz_driver_strength_prop of_props[] = { [KSZ_DRIVER_STRENGTH_HI] = { @@ -4943,10 +4741,8 @@ int ksz_switch_register(struct ksz_device *dev) } ret = dsa_register_switch(dev->ds); - if (ret) { - dev->dev_ops->exit(dev); + if (ret) return ret; - } /* Read MIB counters every 30 seconds to avoid overflow. */ dev->mib_read_interval = msecs_to_jiffies(5000); @@ -4966,12 +4762,7 @@ void ksz_switch_remove(struct ksz_device *dev) cancel_delayed_work_sync(&dev->mib_read); } - dev->dev_ops->exit(dev); dsa_unregister_switch(dev->ds); - - if (dev->reset_gpio) - gpiod_set_value_cansleep(dev->reset_gpio, 1); - } EXPORT_SYMBOL(ksz_switch_remove); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index f6dad256a550..b67038cf1bd0 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -359,11 +359,8 @@ struct alu_struct { }; struct ksz_dev_ops { - int (*setup)(struct dsa_switch *ds); - void (*teardown)(struct dsa_switch *ds); u32 (*get_port_addr)(int port, int offset); void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member); - void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port); /** * @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus @@ -401,8 +398,6 @@ struct ksz_dev_ops { * - Negative error code on failure (e.g., invalid configuration). */ int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio); - int (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); - int (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, @@ -417,13 +412,7 @@ struct ksz_dev_ops { void (*port_init_cnt)(struct ksz_device *dev, int port); void (*setup_rgmii_delay)(struct ksz_device *dev, int port); int (*tc_cbs_set_cinc)(struct ksz_device *dev, int port, u32 val); - void (*config_cpu_port)(struct dsa_switch *ds); - int (*enable_stp_addr)(struct ksz_device *dev); - int (*reset)(struct ksz_device *dev); int (*init)(struct ksz_device *dev); - void (*exit)(struct ksz_device *dev); - - int (*pcs_create)(struct ksz_device *dev); }; struct ksz_device *ksz_switch_alloc(struct device *base, @@ -434,9 +423,7 @@ void ksz_switch_remove(struct ksz_device *dev); int ksz_switch_suspend(struct device *dev); int ksz_switch_resume(struct device *dev); -int ksz_setup(struct dsa_switch *ds); void ksz_teardown(struct dsa_switch *ds); -int ksz_port_setup(struct dsa_switch *ds, int port); void ksz_port_teardown(struct dsa_switch *ds, int port); void ksz_init_mib_timer(struct ksz_device *dev); @@ -453,8 +440,6 @@ void ksz_switch_macaddr_put(struct dsa_switch *ds); void ksz_switch_shutdown(struct ksz_device *dev); int ksz_handle_wake_reason(struct ksz_device *dev, int port); -int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg); -int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val); u32 ksz_get_phy_flags(struct dsa_switch *ds, int port); int ksz_sset_count(struct dsa_switch *ds, int port, int sset); @@ -519,6 +504,13 @@ int ksz_hsr_leave(struct dsa_switch *ds, int port, int ksz_suspend(struct dsa_switch *ds); int ksz_resume(struct dsa_switch *ds); +int ksz_mdio_register(struct ksz_device *dev); +int ksz_pirq_setup(struct ksz_device *dev, u8 p); +int ksz_girq_setup(struct ksz_device *dev); +void ksz_irq_free(struct ksz_irq *kirq); +int ksz_parse_drive_strength(struct ksz_device *dev); +int ksz9477_set_default_prio_queue_mapping(struct ksz_device *dev, int port); + /* Common register access functions */ static inline struct regmap *ksz_regmap_8(struct ksz_device *dev) { diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index f84548168b37..536153886f7b 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -334,14 +334,29 @@ static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); } -static int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) +static int lan937x_phy_read16(struct dsa_switch *ds, int addr, int reg) { - return lan937x_internal_phy_read(dev, addr, reg, data); + struct ksz_device *dev = ds->priv; + u16 val = 0xffff; + int ret; + + ret = lan937x_internal_phy_read(dev, addr, reg, &val); + if (ret) + return ret; + + return val; } -static int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) +static int lan937x_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) { - return lan937x_internal_phy_write(dev, addr, reg, val); + struct ksz_device *dev = ds->priv; + int ret; + + ret = lan937x_internal_phy_write(dev, addr, reg, val); + if (ret) + return ret; + + return 0; } static int lan937x_reset_switch(struct ksz_device *dev) @@ -411,6 +426,23 @@ static void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) dev->dev_ops->cfg_port_member(dev, port, member); } +static int lan937x_dsa_port_setup(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + int ret; + + if (!dsa_is_user_port(ds, port)) + return 0; + + lan937x_port_setup(dev, port, false); + + ret = ksz9477_set_default_prio_queue_mapping(dev, port); + if (ret) + return ret; + + return ksz_dcb_init_port(dev, port); +} + static void lan937x_config_cpu_port(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -626,8 +658,49 @@ static int lan937x_switch_init(struct ksz_device *dev) static int lan937x_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; + u16 storm_mask, storm_rate; + struct dsa_port *dp; + struct ksz_port *p; + const u16 *regs; int 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 = lan937x_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; + regmap_update_bits(ksz_regmap_16(dev), regs[S_BROADCAST_CTRL], + storm_mask, storm_rate); + + lan937x_config_cpu_port(ds); + + ksz9477_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; + /* The VLAN aware is a global setting. Mixed vlan * filterings are not supported. */ @@ -659,18 +732,71 @@ static int lan937x_setup(struct dsa_switch *ds) return ret; /* Disable global VPHY support. Related to CPU interface only? */ - return ksz_rmw32(dev, REG_SW_CFG_STRAP_OVR, SW_VPHY_DISABLE, - SW_VPHY_DISABLE); -} + ret = ksz_rmw32(dev, REG_SW_CFG_STRAP_OVR, SW_VPHY_DISABLE, + SW_VPHY_DISABLE); + if (ret < 0) + return ret; -static void lan937x_teardown(struct dsa_switch *ds) -{ + /* 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; -static void lan937x_switch_exit(struct ksz_device *dev) -{ - lan937x_reset_switch(dev); + dsa_switch_for_each_user_port(dp, dev->ds) { + ret = ksz_pirq_setup(dev, dp->index); + if (ret) + goto port_release; + + ret = ksz_ptp_irq_setup(ds, dp->index); + if (ret) + goto pirq_release; + } + } + + 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: + ksz_ptp_clock_unregister(ds); +port_release: + if (dev->irq > 0) { + dsa_switch_for_each_user_port_continue_reverse(dp, dev->ds) { + 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 enum dsa_tag_protocol lan937x_get_tag_protocol(struct dsa_switch *ds, @@ -703,39 +829,30 @@ const struct phylink_mac_ops lan937x_phylink_mac_ops = { }; const struct ksz_dev_ops lan937x_dev_ops = { - .setup = lan937x_setup, - .teardown = lan937x_teardown, .get_port_addr = ksz9477_get_port_addr, .cfg_port_member = ksz9477_cfg_port_member, - .port_setup = lan937x_port_setup, .mdio_bus_preinit = lan937x_mdio_bus_preinit, .create_phy_addr_map = lan937x_create_phy_addr_map, - .r_phy = lan937x_r_phy, - .w_phy = lan937x_w_phy, .r_mib_cnt = ksz9477_r_mib_cnt, .r_mib_pkt = ksz9477_r_mib_pkt, .r_mib_stat64 = ksz_r_mib_stats64, .freeze_mib = ksz9477_freeze_mib, .port_init_cnt = ksz9477_port_init_cnt, .setup_rgmii_delay = lan937x_setup_rgmii_delay, - .config_cpu_port = lan937x_config_cpu_port, .tc_cbs_set_cinc = lan937x_tc_cbs_set_cinc, - .enable_stp_addr = ksz9477_enable_stp_addr, - .reset = lan937x_reset_switch, .init = lan937x_switch_init, - .exit = lan937x_switch_exit, }; const struct dsa_switch_ops lan937x_switch_ops = { .get_tag_protocol = lan937x_get_tag_protocol, .connect_tag_protocol = lan937x_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, - .setup = ksz_setup, + .setup = lan937x_setup, .teardown = ksz_teardown, - .phy_read = ksz_phy_read16, - .phy_write = ksz_phy_write16, + .phy_read = lan937x_phy_read16, + .phy_write = lan937x_phy_write16, .phylink_get_caps = lan937x_phylink_get_caps, - .port_setup = ksz_port_setup, + .port_setup = lan937x_dsa_port_setup, .set_ageing_time = lan937x_set_ageing_time, .get_strings = ksz_get_strings, .get_ethtool_stats = ksz_get_ethtool_stats,