diff options
Diffstat (limited to 'drivers/net/dsa/b53/b53_common.c')
-rw-r--r-- | drivers/net/dsa/b53/b53_common.c | 178 |
1 files changed, 134 insertions, 44 deletions
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 947adda3397d..8cf4801994e8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -712,7 +712,7 @@ static unsigned int b53_get_mib_size(struct b53_device *dev) return B53_MIBS_SIZE; } -static void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) { struct b53_device *dev = ds->priv; const struct b53_mib_desc *mibs = b53_get_mib(dev); @@ -723,9 +723,9 @@ static void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) memcpy(data + i * ETH_GSTRING_LEN, mibs[i].name, ETH_GSTRING_LEN); } +EXPORT_SYMBOL(b53_get_strings); -static void b53_get_ethtool_stats(struct dsa_switch *ds, int port, - uint64_t *data) +void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) { struct b53_device *dev = ds->priv; const struct b53_mib_desc *mibs = b53_get_mib(dev); @@ -756,13 +756,15 @@ static void b53_get_ethtool_stats(struct dsa_switch *ds, int port, mutex_unlock(&dev->stats_mutex); } +EXPORT_SYMBOL(b53_get_ethtool_stats); -static int b53_get_sset_count(struct dsa_switch *ds) +int b53_get_sset_count(struct dsa_switch *ds) { struct b53_device *dev = ds->priv; return b53_get_mib_size(dev); } +EXPORT_SYMBOL(b53_get_sset_count); static int b53_setup(struct dsa_switch *ds) { @@ -921,15 +923,15 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, } } -static int b53_vlan_filtering(struct dsa_switch *ds, int port, - bool vlan_filtering) +int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) { return 0; } +EXPORT_SYMBOL(b53_vlan_filtering); -static int b53_vlan_prepare(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) +int b53_vlan_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) { struct b53_device *dev = ds->priv; @@ -943,10 +945,11 @@ static int b53_vlan_prepare(struct dsa_switch *ds, int port, return 0; } +EXPORT_SYMBOL(b53_vlan_prepare); -static void b53_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) +void b53_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) { struct b53_device *dev = ds->priv; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; @@ -977,9 +980,10 @@ static void b53_vlan_add(struct dsa_switch *ds, int port, b53_fast_age_vlan(dev, vid); } } +EXPORT_SYMBOL(b53_vlan_add); -static int b53_vlan_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) +int b53_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) { struct b53_device *dev = ds->priv; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; @@ -1015,10 +1019,11 @@ static int b53_vlan_del(struct dsa_switch *ds, int port, return 0; } +EXPORT_SYMBOL(b53_vlan_del); -static int b53_vlan_dump(struct dsa_switch *ds, int port, - struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) +int b53_vlan_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + int (*cb)(struct switchdev_obj *obj)) { struct b53_device *dev = ds->priv; u16 vid, vid_start = 0, pvid; @@ -1057,6 +1062,7 @@ static int b53_vlan_dump(struct dsa_switch *ds, int port, return err; } +EXPORT_SYMBOL(b53_vlan_dump); /* Address Resolution Logic routines */ static int b53_arl_op_wait(struct b53_device *dev) @@ -1137,7 +1143,7 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, int ret; /* Convert the array into a 64-bit MAC */ - mac = b53_mac_to_u64(addr); + mac = ether_addr_to_u64(addr); /* Perform a read for the given MAC and VID */ b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac); @@ -1175,9 +1181,9 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, return b53_arl_rw_op(dev, 0); } -static int b53_fdb_prepare(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) +int b53_fdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) { struct b53_device *priv = ds->priv; @@ -1189,24 +1195,27 @@ static int b53_fdb_prepare(struct dsa_switch *ds, int port, return 0; } +EXPORT_SYMBOL(b53_fdb_prepare); -static void b53_fdb_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) +void b53_fdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) { struct b53_device *priv = ds->priv; if (b53_arl_op(priv, 0, port, fdb->addr, fdb->vid, true)) pr_err("%s: failed to add MAC address\n", __func__); } +EXPORT_SYMBOL(b53_fdb_add); -static int b53_fdb_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_fdb *fdb) +int b53_fdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb) { struct b53_device *priv = ds->priv; return b53_arl_op(priv, 0, port, fdb->addr, fdb->vid, false); } +EXPORT_SYMBOL(b53_fdb_del); static int b53_arl_search_wait(struct b53_device *dev) { @@ -1258,9 +1267,9 @@ static int b53_fdb_copy(struct net_device *dev, int port, return cb(&fdb->obj); } -static int b53_fdb_dump(struct dsa_switch *ds, int port, - struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) +int b53_fdb_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_fdb *fdb, + int (*cb)(struct switchdev_obj *obj)) { struct b53_device *priv = ds->priv; struct net_device *dev = ds->ports[port].netdev; @@ -1297,9 +1306,9 @@ static int b53_fdb_dump(struct dsa_switch *ds, int port, return 0; } +EXPORT_SYMBOL(b53_fdb_dump); -static int b53_br_join(struct dsa_switch *ds, int port, - struct net_device *bridge) +int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; s8 cpu_port = ds->dst->cpu_port; @@ -1317,11 +1326,10 @@ static int b53_br_join(struct dsa_switch *ds, int port, b53_write16(dev, B53_VLAN_PAGE, B53_JOIN_ALL_VLAN_EN, reg); } - dev->ports[port].bridge_dev = bridge; b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan); b53_for_each_port(dev, i) { - if (dev->ports[i].bridge_dev != bridge) + if (ds->ports[i].bridge_dev != br) continue; /* Add this local port to the remote port VLAN control @@ -1343,11 +1351,11 @@ static int b53_br_join(struct dsa_switch *ds, int port, return 0; } +EXPORT_SYMBOL(b53_br_join); -static void b53_br_leave(struct dsa_switch *ds, int port) +void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; - struct net_device *bridge = dev->ports[port].bridge_dev; struct b53_vlan *vl = &dev->vlans[0]; s8 cpu_port = ds->dst->cpu_port; unsigned int i; @@ -1357,7 +1365,7 @@ static void b53_br_leave(struct dsa_switch *ds, int port) b53_for_each_port(dev, i) { /* Don't touch the remaining ports */ - if (dev->ports[i].bridge_dev != bridge) + if (ds->ports[i].bridge_dev != br) continue; b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), ®); @@ -1372,7 +1380,6 @@ static void b53_br_leave(struct dsa_switch *ds, int port) b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); dev->ports[port].vlan_ctl_mask = pvlan; - dev->ports[port].bridge_dev = NULL; if (is5325(dev) || is5365(dev)) pvid = 1; @@ -1393,8 +1400,9 @@ static void b53_br_leave(struct dsa_switch *ds, int port) b53_set_vlan_entry(dev, pvid, vl); } } +EXPORT_SYMBOL(b53_br_leave); -static void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state) +void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state) { struct b53_device *dev = ds->priv; u8 hw_state; @@ -1426,21 +1434,88 @@ static void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state) reg |= hw_state; b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg); } +EXPORT_SYMBOL(b53_br_set_stp_state); -static void b53_br_fast_age(struct dsa_switch *ds, int port) +void b53_br_fast_age(struct dsa_switch *ds, int port) { struct b53_device *dev = ds->priv; if (b53_fast_age_port(dev, port)) dev_err(ds->dev, "fast ageing failed\n"); } +EXPORT_SYMBOL(b53_br_fast_age); static enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds) { return DSA_TAG_PROTO_NONE; } -static struct dsa_switch_ops b53_switch_ops = { +int b53_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, bool ingress) +{ + struct b53_device *dev = ds->priv; + u16 reg, loc; + + if (ingress) + loc = B53_IG_MIR_CTL; + else + loc = B53_EG_MIR_CTL; + + b53_read16(dev, B53_MGMT_PAGE, loc, ®); + reg &= ~MIRROR_MASK; + reg |= BIT(port); + b53_write16(dev, B53_MGMT_PAGE, loc, reg); + + b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, ®); + reg &= ~CAP_PORT_MASK; + reg |= mirror->to_local_port; + reg |= MIRROR_EN; + b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg); + + return 0; +} +EXPORT_SYMBOL(b53_mirror_add); + +void b53_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct b53_device *dev = ds->priv; + bool loc_disable = false, other_loc_disable = false; + u16 reg, loc; + + if (mirror->ingress) + loc = B53_IG_MIR_CTL; + else + loc = B53_EG_MIR_CTL; + + /* Update the desired ingress/egress register */ + b53_read16(dev, B53_MGMT_PAGE, loc, ®); + reg &= ~BIT(port); + if (!(reg & MIRROR_MASK)) + loc_disable = true; + b53_write16(dev, B53_MGMT_PAGE, loc, reg); + + /* Now look at the other one to know if we can disable mirroring + * entirely + */ + if (mirror->ingress) + b53_read16(dev, B53_MGMT_PAGE, B53_EG_MIR_CTL, ®); + else + b53_read16(dev, B53_MGMT_PAGE, B53_IG_MIR_CTL, ®); + if (!(reg & MIRROR_MASK)) + other_loc_disable = true; + + b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, ®); + /* Both no longer have ports, let's disable mirroring */ + if (loc_disable && other_loc_disable) { + reg &= ~MIRROR_EN; + reg &= ~mirror->to_local_port; + } + b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg); +} +EXPORT_SYMBOL(b53_mirror_del); + +static const struct dsa_switch_ops b53_switch_ops = { .get_tag_protocol = b53_get_tag_protocol, .setup = b53_setup, .get_strings = b53_get_strings, @@ -1464,6 +1539,8 @@ static struct dsa_switch_ops b53_switch_ops = { .port_fdb_dump = b53_fdb_dump, .port_fdb_add = b53_fdb_add, .port_fdb_del = b53_fdb_del, + .port_mirror_add = b53_mirror_add, + .port_mirror_del = b53_mirror_del, }; struct b53_chip_data { @@ -1672,6 +1749,18 @@ static const struct b53_chip_data b53_switch_chips[] = { .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, }, + { + .chip_id = BCM7278_DEVICE_ID, + .dev_name = "BCM7278", + .vlans = 4096, + .enabled_ports = 0x1ff, + .arl_entries= 4, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, }; static int b53_switch_init(struct b53_device *dev) @@ -1765,14 +1854,15 @@ struct b53_device *b53_switch_alloc(struct device *base, struct dsa_switch *ds; struct b53_device *dev; - ds = devm_kzalloc(base, sizeof(*ds) + sizeof(*dev), GFP_KERNEL); + ds = dsa_switch_alloc(base, DSA_MAX_PORTS); if (!ds) return NULL; - dev = (struct b53_device *)(ds + 1); + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; ds->priv = dev; - ds->dev = base; dev->dev = base; dev->ds = ds; @@ -1869,7 +1959,7 @@ int b53_switch_register(struct b53_device *dev) pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); - return dsa_register_switch(dev->ds, dev->ds->dev->of_node); + return dsa_register_switch(dev->ds, dev->ds->dev); } EXPORT_SYMBOL(b53_switch_register); |