diff options
| -rw-r--r-- | drivers/net/dsa/microchip/ksz8.c | 126 |
1 files changed, 114 insertions, 12 deletions
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index c4c769028a20..5ed63f425013 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -181,6 +181,14 @@ static int ksz8_pme_pwrite8(struct ksz_device *dev, int port, int offset, u8 dat return ksz8_ind_write8(dev, table, (u8)(offset), data); } +static int ksz8463_reset_switch(struct ksz_device *dev) +{ + ksz_cfg(dev, KSZ8463_REG_SW_RESET, KSZ8463_GLOBAL_SOFTWARE_RESET, true); + ksz_cfg(dev, KSZ8463_REG_SW_RESET, KSZ8463_GLOBAL_SOFTWARE_RESET, + false); + return 0; +} + static int ksz8_reset_switch(struct ksz_device *dev) { if (ksz_is_ksz88x3(dev)) { @@ -189,11 +197,6 @@ static int ksz8_reset_switch(struct ksz_device *dev) KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true); ksz_cfg(dev, KSZ8863_REG_SW_RESET, KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false); - } else if (ksz_is_ksz8463(dev)) { - ksz_cfg(dev, KSZ8463_REG_SW_RESET, - KSZ8463_GLOBAL_SOFTWARE_RESET, true); - ksz_cfg(dev, KSZ8463_REG_SW_RESET, - KSZ8463_GLOBAL_SOFTWARE_RESET, false); } else { /* reset switch */ ksz_write8(dev, REG_POWER_MANAGEMENT_1, @@ -2300,6 +2303,110 @@ static void ksz88xx_r_mib_stats64(struct ksz_device *dev, int port) spin_unlock(&mib->stats64_lock); } +static int ksz8463_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + u16 storm_mask, storm_rate; + 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 = ksz8463_reset_switch(dev); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + /* set broadcast storm protection 10% rate */ + storm_mask = BROADCAST_STORM_RATE; + storm_rate = (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100; + 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 + * can support both tagged and untagged VLANs + */ + ds->untag_bridge_pvid = true; + + /* VLAN filtering is partly controlled by the global VLAN + * Enable flag + */ + ds->vlan_filtering_is_global = true; + + /* Enable automatic fast aging when link changed detected. */ + ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true); + + /* Enable aggressive back off algorithm in half duplex mode. */ + ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_AGGR_BACKOFF, SW_AGGR_BACKOFF); + if (ret) + return ret; + + /* + * Make sure unicast VLAN boundary is set as default and + * enable no excessive collision drop. + */ + ret = ksz_rmw8(dev, REG_SW_CTRL_2, + UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP, + UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP); + if (ret) + return ret; + + ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false); + + ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); + + for (i = 0; i < (dev->info->num_vlans / 4); i++) + ksz8_r_vlan_entries(dev, i); + + /* 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; + + ret = ksz_mdio_register(dev); + if (ret < 0) { + dev_err(dev->dev, "failed to register the mdio"); + return ret; + } + + ret = ksz_dcb_init(dev); + if (ret) + return ret; + + /* start switch */ + regmap_update_bits(ksz_regmap_8(dev), regs[S_START_CTRL], + SW_START, SW_START); + + return 0; +} + /** * ksz88x3_drive_strength_write() - Set the drive strength configuration for * KSZ8863 compatible chip variants. @@ -2445,10 +2552,6 @@ static int ksz8_setup(struct dsa_switch *ds) /* 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); @@ -2499,7 +2602,7 @@ static int ksz8_setup(struct dsa_switch *ds) ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); - if (!ksz_is_ksz88x3(dev) && !ksz_is_ksz8463(dev)) + if (!ksz_is_ksz88x3(dev)) ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true); for (i = 0; i < (dev->info->num_vlans / 4); i++) @@ -2889,8 +2992,7 @@ const struct ksz_dev_ops ksz88xx_dev_ops = { const struct dsa_switch_ops ksz8463_switch_ops = { .get_tag_protocol = ksz8463_get_tag_protocol, .connect_tag_protocol = ksz8463_connect_tag_protocol, - .setup = ksz8_setup, - .teardown = ksz_teardown, + .setup = ksz8463_setup, .phy_read = ksz8463_phy_read16, .phy_write = ksz8463_phy_write16, .phylink_get_caps = ksz8_phylink_get_caps, |
