diff options
Diffstat (limited to 'drivers/net/ethernet/mscc')
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot.c | 271 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_fdma.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_flower.c | 25 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_net.c | 79 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_police.c | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_police.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_vcap.c | 51 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_vsc7514.c | 2 |
9 files changed, 302 insertions, 159 deletions
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index e443bd8b2d09a..8da7e25a47c96 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -551,7 +551,7 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, struct ocelot_vcap_block *block = &ocelot->block[VCAP_IS1]; struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_vcap_filter *filter; - int err; + int err = 0; u32 val; list_for_each_entry(filter, &block->rules, list) { @@ -570,7 +570,7 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, if (vlan_aware) err = ocelot_del_vlan_unaware_pvid(ocelot, port, ocelot_port->bridge); - else + else if (ocelot_port->bridge) err = ocelot_add_vlan_unaware_pvid(ocelot, port, ocelot_port->bridge); if (err) @@ -629,6 +629,13 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, { int err; + /* Ignore VID 0 added to our RX filter by the 8021q module, since + * that collides with OCELOT_STANDALONE_PVID and changes it from + * egress-untagged to egress-tagged. + */ + if (!vid) + return 0; + err = ocelot_vlan_member_add(ocelot, port, vid, untagged); if (err) return err; @@ -651,6 +658,9 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) bool del_pvid = false; int err; + if (!vid) + return 0; + if (ocelot_port->pvid_vlan && ocelot_port->pvid_vlan->vid == vid) del_pvid = true; @@ -1339,15 +1349,10 @@ EXPORT_SYMBOL(ocelot_drain_cpu_queue); int ocelot_fdb_add(struct ocelot *ocelot, int port, const unsigned char *addr, u16 vid, const struct net_device *bridge) { - int pgid = port; - - if (port == ocelot->npi) - pgid = PGID_CPU; - if (!vid) vid = ocelot_vlan_unaware_pvid(ocelot, bridge); - return ocelot_mact_learn(ocelot, pgid, addr, vid, ENTRYTYPE_LOCKED); + return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED); } EXPORT_SYMBOL(ocelot_fdb_add); @@ -1612,7 +1617,7 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, trap->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; trap->action.port_mask = 0; trap->take_ts = take_ts; - list_add_tail(&trap->trap_list, &ocelot->traps); + trap->is_trap = true; new = true; } @@ -1624,10 +1629,8 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, err = ocelot_vcap_filter_replace(ocelot, trap); if (err) { trap->ingress_port_mask &= ~BIT(port); - if (!trap->ingress_port_mask) { - list_del(&trap->trap_list); + if (!trap->ingress_port_mask) kfree(trap); - } return err; } @@ -1647,11 +1650,8 @@ int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie) return 0; trap->ingress_port_mask &= ~BIT(port); - if (!trap->ingress_port_mask) { - list_del(&trap->trap_list); - + if (!trap->ingress_port_mask) return ocelot_vcap_filter_del(ocelot, trap); - } return ocelot_vcap_filter_replace(ocelot, trap); } @@ -2046,57 +2046,68 @@ static int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond) return __ffs(bond_mask); } -u32 ocelot_get_bridge_fwd_mask(struct ocelot *ocelot, int src_port) +static u32 ocelot_dsa_8021q_cpu_assigned_ports(struct ocelot *ocelot, + struct ocelot_port *cpu) { - struct ocelot_port *ocelot_port = ocelot->ports[src_port]; - const struct net_device *bridge; u32 mask = 0; int port; - if (!ocelot_port || ocelot_port->stp_state != BR_STATE_FORWARDING) - return 0; - - bridge = ocelot_port->bridge; - if (!bridge) - return 0; - for (port = 0; port < ocelot->num_phys_ports; port++) { - ocelot_port = ocelot->ports[port]; + struct ocelot_port *ocelot_port = ocelot->ports[port]; if (!ocelot_port) continue; - if (ocelot_port->stp_state == BR_STATE_FORWARDING && - ocelot_port->bridge == bridge) + if (ocelot_port->dsa_8021q_cpu == cpu) mask |= BIT(port); } return mask; } -EXPORT_SYMBOL_GPL(ocelot_get_bridge_fwd_mask); -u32 ocelot_get_dsa_8021q_cpu_mask(struct ocelot *ocelot) +u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + struct ocelot_port *cpu_port = ocelot_port->dsa_8021q_cpu; + + if (!cpu_port) + return 0; + + return BIT(cpu_port->index); +} +EXPORT_SYMBOL_GPL(ocelot_port_assigned_dsa_8021q_cpu_mask); + +u32 ocelot_get_bridge_fwd_mask(struct ocelot *ocelot, int src_port) { + struct ocelot_port *ocelot_port = ocelot->ports[src_port]; + const struct net_device *bridge; u32 mask = 0; int port; + if (!ocelot_port || ocelot_port->stp_state != BR_STATE_FORWARDING) + return 0; + + bridge = ocelot_port->bridge; + if (!bridge) + return 0; + for (port = 0; port < ocelot->num_phys_ports; port++) { - struct ocelot_port *ocelot_port = ocelot->ports[port]; + ocelot_port = ocelot->ports[port]; if (!ocelot_port) continue; - if (ocelot_port->is_dsa_8021q_cpu) + if (ocelot_port->stp_state == BR_STATE_FORWARDING && + ocelot_port->bridge == bridge) mask |= BIT(port); } return mask; } -EXPORT_SYMBOL_GPL(ocelot_get_dsa_8021q_cpu_mask); +EXPORT_SYMBOL_GPL(ocelot_get_bridge_fwd_mask); -void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) +static void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) { - unsigned long cpu_fwd_mask; int port; lockdep_assert_held(&ocelot->fwd_domain_lock); @@ -2108,15 +2119,6 @@ void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) if (joining && ocelot->ops->cut_through_fwd) ocelot->ops->cut_through_fwd(ocelot); - /* If a DSA tag_8021q CPU exists, it needs to be included in the - * regular forwarding path of the front ports regardless of whether - * those are bridged or standalone. - * If DSA tag_8021q is not used, this returns 0, which is fine because - * the hardware-based CPU port module can be a destination for packets - * even if it isn't part of PGID_SRC. - */ - cpu_fwd_mask = ocelot_get_dsa_8021q_cpu_mask(ocelot); - /* Apply FWD mask. The loop is needed to add/remove the current port as * a source for the other ports. */ @@ -2129,17 +2131,19 @@ void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) mask = 0; } else if (ocelot_port->is_dsa_8021q_cpu) { /* The DSA tag_8021q CPU ports need to be able to - * forward packets to all other ports except for - * themselves + * forward packets to all ports assigned to them. */ - mask = GENMASK(ocelot->num_phys_ports - 1, 0); - mask &= ~cpu_fwd_mask; + mask = ocelot_dsa_8021q_cpu_assigned_ports(ocelot, + ocelot_port); } else if (ocelot_port->bridge) { struct net_device *bond = ocelot_port->bond; mask = ocelot_get_bridge_fwd_mask(ocelot, port); - mask |= cpu_fwd_mask; mask &= ~BIT(port); + + mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, + port); + if (bond) mask &= ~ocelot_get_bond_mask(ocelot, bond); } else { @@ -2147,7 +2151,8 @@ void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) * ports (if those exist), or to the hardware CPU port * module otherwise. */ - mask = cpu_fwd_mask; + mask = ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot, + port); } ocelot_write_rix(ocelot, mask, ANA_PGID_PGID, PGID_SRC + port); @@ -2163,29 +2168,94 @@ void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot, bool joining) if (!joining && ocelot->ops->cut_through_fwd) ocelot->ops->cut_through_fwd(ocelot); } -EXPORT_SYMBOL(ocelot_apply_bridge_fwd_mask); -void ocelot_port_set_dsa_8021q_cpu(struct ocelot *ocelot, int port) +/* Update PGID_CPU which is the destination port mask used for whitelisting + * unicast addresses filtered towards the host. In the normal and NPI modes, + * this points to the analyzer entry for the CPU port module, while in DSA + * tag_8021q mode, it is a bit mask of all active CPU ports. + * PGID_SRC will take care of forwarding a packet from one user port to + * no more than a single CPU port. + */ +static void ocelot_update_pgid_cpu(struct ocelot *ocelot) +{ + int pgid_cpu = 0; + int port; + + for (port = 0; port < ocelot->num_phys_ports; port++) { + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + if (!ocelot_port || !ocelot_port->is_dsa_8021q_cpu) + continue; + + pgid_cpu |= BIT(port); + } + + if (!pgid_cpu) + pgid_cpu = BIT(ocelot->num_phys_ports); + + ocelot_write_rix(ocelot, pgid_cpu, ANA_PGID_PGID, PGID_CPU); +} + +void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, + int cpu) { + struct ocelot_port *cpu_port = ocelot->ports[cpu]; u16 vid; - ocelot->ports[port]->is_dsa_8021q_cpu = true; + mutex_lock(&ocelot->fwd_domain_lock); + + ocelot->ports[port]->dsa_8021q_cpu = cpu_port; - for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) - ocelot_vlan_member_add(ocelot, port, vid, true); + if (!cpu_port->is_dsa_8021q_cpu) { + cpu_port->is_dsa_8021q_cpu = true; + + for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) + ocelot_vlan_member_add(ocelot, cpu, vid, true); + + ocelot_update_pgid_cpu(ocelot); + } + + ocelot_apply_bridge_fwd_mask(ocelot, true); + + mutex_unlock(&ocelot->fwd_domain_lock); } -EXPORT_SYMBOL_GPL(ocelot_port_set_dsa_8021q_cpu); +EXPORT_SYMBOL_GPL(ocelot_port_assign_dsa_8021q_cpu); -void ocelot_port_unset_dsa_8021q_cpu(struct ocelot *ocelot, int port) +void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port) { + struct ocelot_port *cpu_port = ocelot->ports[port]->dsa_8021q_cpu; + bool keep = false; u16 vid; + int p; + + mutex_lock(&ocelot->fwd_domain_lock); + + ocelot->ports[port]->dsa_8021q_cpu = NULL; + + for (p = 0; p < ocelot->num_phys_ports; p++) { + if (!ocelot->ports[p]) + continue; + + if (ocelot->ports[p]->dsa_8021q_cpu == cpu_port) { + keep = true; + break; + } + } + + if (!keep) { + cpu_port->is_dsa_8021q_cpu = false; + + for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) + ocelot_vlan_member_del(ocelot, cpu_port->index, vid); - ocelot->ports[port]->is_dsa_8021q_cpu = false; + ocelot_update_pgid_cpu(ocelot); + } + + ocelot_apply_bridge_fwd_mask(ocelot, true); - for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) - ocelot_vlan_member_del(ocelot, port, vid); + mutex_unlock(&ocelot->fwd_domain_lock); } -EXPORT_SYMBOL_GPL(ocelot_port_unset_dsa_8021q_cpu); +EXPORT_SYMBOL_GPL(ocelot_port_unassign_dsa_8021q_cpu); void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) { @@ -2339,9 +2409,6 @@ int ocelot_port_mdb_add(struct ocelot *ocelot, int port, struct ocelot_pgid *pgid; u16 vid = mdb->vid; - if (port == ocelot->npi) - port = ocelot->num_phys_ports; - if (!vid) vid = ocelot_vlan_unaware_pvid(ocelot, bridge); @@ -2399,9 +2466,6 @@ int ocelot_port_mdb_del(struct ocelot *ocelot, int port, struct ocelot_pgid *pgid; u16 vid = mdb->vid; - if (port == ocelot->npi) - port = ocelot->num_phys_ports; - if (!vid) vid = ocelot_vlan_unaware_pvid(ocelot, bridge); @@ -2600,6 +2664,67 @@ static void ocelot_setup_logical_port_ids(struct ocelot *ocelot) } } +static int ocelot_migrate_mc(struct ocelot *ocelot, struct ocelot_multicast *mc, + unsigned long from_mask, unsigned long to_mask) +{ + unsigned char addr[ETH_ALEN]; + struct ocelot_pgid *pgid; + u16 vid = mc->vid; + + dev_dbg(ocelot->dev, + "Migrating multicast %pM vid %d from port mask 0x%lx to 0x%lx\n", + mc->addr, mc->vid, from_mask, to_mask); + + /* First clean up the current port mask from hardware, because + * we'll be modifying it. + */ + ocelot_pgid_free(ocelot, mc->pgid); + ocelot_encode_ports_to_mdb(addr, mc); + ocelot_mact_forget(ocelot, addr, vid); + + mc->ports &= ~from_mask; + mc->ports |= to_mask; + + pgid = ocelot_mdb_get_pgid(ocelot, mc); + if (IS_ERR(pgid)) { + dev_err(ocelot->dev, + "Cannot allocate PGID for mdb %pM vid %d\n", + mc->addr, mc->vid); + devm_kfree(ocelot->dev, mc); + return PTR_ERR(pgid); + } + mc->pgid = pgid; + + ocelot_encode_ports_to_mdb(addr, mc); + + if (mc->entry_type != ENTRYTYPE_MACv4 && + mc->entry_type != ENTRYTYPE_MACv6) + ocelot_write_rix(ocelot, pgid->ports, ANA_PGID_PGID, + pgid->index); + + return ocelot_mact_learn(ocelot, pgid->index, addr, vid, + mc->entry_type); +} + +int ocelot_migrate_mdbs(struct ocelot *ocelot, unsigned long from_mask, + unsigned long to_mask) +{ + struct ocelot_multicast *mc; + int err; + + list_for_each_entry(mc, &ocelot->multicast, list) { + if (!(mc->ports & from_mask)) + continue; + + err = ocelot_migrate_mc(ocelot, mc, from_mask, to_mask); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ocelot_migrate_mdbs); + /* Documentation for PORTID_VAL says: * Logical port number for front port. If port is not a member of a LLAG, * then PORTID must be set to the physical port number. @@ -2859,6 +2984,8 @@ static void ocelot_port_set_mcast_flood(struct ocelot *ocelot, int port, val = BIT(port); ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_MC); + ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_MCIPV4); + ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_MCIPV6); } static void ocelot_port_set_bcast_flood(struct ocelot *ocelot, int port, @@ -2886,9 +3013,6 @@ EXPORT_SYMBOL(ocelot_port_pre_bridge_flags); void ocelot_port_bridge_flags(struct ocelot *ocelot, int port, struct switchdev_brport_flags flags) { - if (port == ocelot->npi) - port = ocelot->num_phys_ports; - if (flags.mask & BR_LEARNING) ocelot_port_set_learning(ocelot, port, !!(flags.val & BR_LEARNING)); @@ -3216,6 +3340,7 @@ static void ocelot_detect_features(struct ocelot *ocelot) int ocelot_init(struct ocelot *ocelot) { + const struct ocelot_stat_layout *stat; char queue_name[32]; int i, ret; u32 port; @@ -3228,6 +3353,10 @@ int ocelot_init(struct ocelot *ocelot) } } + ocelot->num_stats = 0; + for_each_stat(ocelot, stat) + ocelot->num_stats++; + ocelot->stats = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports * ocelot->num_stats, sizeof(u64), GFP_KERNEL); diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index d0fa8ab6cc81e..6d65cc87d757a 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -48,7 +48,6 @@ struct ocelot_port_private { struct net_device *dev; struct phylink *phylink; struct phylink_config phylink_config; - u8 chip_port; struct ocelot_port_tc tc; }; diff --git a/drivers/net/ethernet/mscc/ocelot_fdma.c b/drivers/net/ethernet/mscc/ocelot_fdma.c index dffa597bffe6b..083fddd263ec6 100644 --- a/drivers/net/ethernet/mscc/ocelot_fdma.c +++ b/drivers/net/ethernet/mscc/ocelot_fdma.c @@ -799,8 +799,8 @@ void ocelot_fdma_netdev_init(struct ocelot *ocelot, struct net_device *dev) return; fdma->ndev = dev; - netif_napi_add(dev, &fdma->napi, ocelot_fdma_napi_poll, - OCELOT_FDMA_WEIGHT); + netif_napi_add_weight(dev, &fdma->napi, ocelot_fdma_napi_poll, + OCELOT_FDMA_WEIGHT); } void ocelot_fdma_netdev_deinit(struct ocelot *ocelot, struct net_device *dev) diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index 03b5e59d033e4..7c0897e779dc6 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -279,10 +279,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, filter->action.pol_ix = OCELOT_POLICER_DISCARD; filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; + case FLOW_ACTION_ACCEPT: + if (filter->block_id != VCAP_ES0 && + filter->block_id != VCAP_IS1 && + filter->block_id != VCAP_IS2) { + NL_SET_ERR_MSG_MOD(extack, + "Accept action can only be offloaded to VCAP chains"); + return -EOPNOTSUPP; + } + if (filter->block_id != VCAP_ES0 && + filter->goto_target != -1) { + NL_SET_ERR_MSG_MOD(extack, + "Last action must be GOTO"); + return -EOPNOTSUPP; + } + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; + break; case FLOW_ACTION_TRAP: - if (filter->block_id != VCAP_IS2) { + if (filter->block_id != VCAP_IS2 || + filter->lookup != 0) { NL_SET_ERR_MSG_MOD(extack, - "Trap action can only be offloaded to VCAP IS2"); + "Trap action can only be offloaded to VCAP IS2 lookup 0"); return -EOPNOTSUPP; } if (filter->goto_target != -1) { @@ -295,7 +312,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, filter->action.cpu_copy_ena = true; filter->action.cpu_qu_num = 0; filter->type = OCELOT_VCAP_FILTER_OFFLOAD; - list_add_tail(&filter->trap_list, &ocelot->traps); + filter->is_trap = true; break; case FLOW_ACTION_POLICE: if (filter->block_id == PSFP_BLOCK_ID) { @@ -878,8 +895,6 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, ret = ocelot_flower_parse(ocelot, port, ingress, f, filter); if (ret) { - if (!list_empty(&filter->trap_list)) - list_del(&filter->trap_list); kfree(filter); return ret; } diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index 247bc105bdd2c..5e6136e80282b 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -191,7 +191,7 @@ static struct devlink_port *ocelot_get_devlink_port(struct net_device *dev) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; return &ocelot->devlink_ports[port]; } @@ -201,7 +201,7 @@ int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv, bool ingress) { struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; if (!ingress) return -EOPNOTSUPP; @@ -226,7 +226,7 @@ static int ocelot_setup_tc_cls_matchall_police(struct ocelot_port_private *priv, struct flow_action_entry *action = &f->rule->action.entries[0]; struct ocelot *ocelot = priv->port.ocelot; struct ocelot_policer pol = { 0 }; - int port = priv->chip_port; + int port = priv->port.index; int err; if (!ingress) { @@ -288,8 +288,8 @@ static int ocelot_setup_tc_cls_matchall_mirred(struct ocelot_port_private *priv, other_priv = netdev_priv(a->dev); - err = ocelot_port_mirror_add(ocelot, priv->chip_port, - other_priv->chip_port, ingress, extack); + err = ocelot_port_mirror_add(ocelot, priv->port.index, + other_priv->port.index, ingress, extack); if (err) return err; @@ -306,7 +306,7 @@ static int ocelot_del_tc_cls_matchall_police(struct ocelot_port_private *priv, struct netlink_ext_ack *extack) { struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; int err; err = ocelot_port_policer_del(ocelot, port); @@ -327,7 +327,7 @@ static int ocelot_del_tc_cls_matchall_mirred(struct ocelot_port_private *priv, struct netlink_ext_ack *extack) { struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; ocelot_port_mirror_del(ocelot, port, ingress); @@ -497,7 +497,7 @@ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; int ret; ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged); @@ -515,7 +515,7 @@ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; int ret; /* 8021q removes VID 0 on module unload for all interfaces @@ -558,7 +558,7 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; u32 rew_op = 0; if (!static_branch_unlikely(&ocelot_fdma_enabled) && @@ -724,7 +724,7 @@ static void ocelot_get_stats64(struct net_device *dev, { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; /* Configure the port to read the stats from */ ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), @@ -767,19 +767,20 @@ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_fdb_add(ocelot, port, addr, vid, ocelot_port->bridge); } static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, + struct netlink_ext_ack *extack) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_fdb_del(ocelot, port, addr, vid, ocelot_port->bridge); } @@ -797,7 +798,7 @@ static int ocelot_port_fdb_dump(struct sk_buff *skb, .cb = cb, .idx = *idx, }; - int port = priv->chip_port; + int port = priv->port.index; int ret; ret = ocelot_fdb_dump(ocelot, port, ocelot_port_fdb_do_dump, &dump); @@ -839,7 +840,7 @@ static int ocelot_set_features(struct net_device *dev, netdev_features_t changed = dev->features ^ features; struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && priv->tc.offload_cnt) { @@ -858,7 +859,7 @@ static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; /* If the attached PHY device isn't capable of timestamping operations, * use our own (when possible). @@ -881,7 +882,7 @@ static int ocelot_change_mtu(struct net_device *dev, int new_mtu) struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - ocelot_port_set_maxlen(ocelot, priv->chip_port, new_mtu); + ocelot_port_set_maxlen(ocelot, priv->port.index, new_mtu); WRITE_ONCE(dev->mtu, new_mtu); return 0; @@ -934,7 +935,7 @@ int ocelot_netdev_to_port(struct net_device *dev) priv = netdev_priv(dev); - return priv->chip_port; + return priv->port.index; } static void ocelot_port_get_strings(struct net_device *netdev, u32 sset, @@ -942,7 +943,7 @@ static void ocelot_port_get_strings(struct net_device *netdev, u32 sset, { struct ocelot_port_private *priv = netdev_priv(netdev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; ocelot_get_strings(ocelot, port, sset, data); } @@ -953,7 +954,7 @@ static void ocelot_port_get_ethtool_stats(struct net_device *dev, { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; ocelot_get_ethtool_stats(ocelot, port, data); } @@ -962,7 +963,7 @@ static int ocelot_port_get_sset_count(struct net_device *dev, int sset) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_get_sset_count(ocelot, port, sset); } @@ -972,7 +973,7 @@ static int ocelot_port_get_ts_info(struct net_device *dev, { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; if (!ocelot->ptp) return ethtool_op_get_ts_info(dev, info); @@ -1024,7 +1025,7 @@ static int ocelot_port_attr_set(struct net_device *dev, const void *ctx, { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; int err = 0; if (ctx && ctx != priv) @@ -1065,7 +1066,7 @@ static int ocelot_vlan_vid_prepare(struct net_device *dev, u16 vid, bool pvid, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_vlan_prepare(ocelot, port, vid, pvid, untagged, extack); } @@ -1091,7 +1092,7 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_port_mdb_add(ocelot, port, mdb, ocelot_port->bridge); } @@ -1102,7 +1103,7 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_port_mdb_del(ocelot, port, mdb, ocelot_port->bridge); } @@ -1113,7 +1114,7 @@ static int ocelot_port_obj_mrp_add(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_mrp_add(ocelot, port, mrp); } @@ -1124,7 +1125,7 @@ static int ocelot_port_obj_mrp_del(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_mrp_del(ocelot, port, mrp); } @@ -1136,7 +1137,7 @@ ocelot_port_obj_mrp_add_ring_role(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_mrp_add_ring_role(ocelot, port, mrp); } @@ -1148,7 +1149,7 @@ ocelot_port_obj_mrp_del_ring_role(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; return ocelot_mrp_del_ring_role(ocelot, port, mrp); } @@ -1313,7 +1314,7 @@ static int ocelot_netdevice_bridge_join(struct net_device *dev, struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; int bridge_num, err; bridge_num = ocelot_bridge_num_get(ocelot, bridge); @@ -1365,7 +1366,7 @@ static int ocelot_netdevice_bridge_leave(struct net_device *dev, struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; int bridge_num = ocelot_port->bridge_num; - int port = priv->chip_port; + int port = priv->port.index; int err; err = ocelot_switchdev_unsync(ocelot, port); @@ -1387,7 +1388,7 @@ static int ocelot_netdevice_lag_join(struct net_device *dev, struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; struct net_device *bridge_dev; - int port = priv->chip_port; + int port = priv->port.index; int err; err = ocelot_port_lag_join(ocelot, port, bond, info); @@ -1430,7 +1431,7 @@ static int ocelot_netdevice_lag_leave(struct net_device *dev, struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; struct net_device *bridge_dev; - int port = priv->chip_port; + int port = priv->port.index; ocelot_port_lag_leave(ocelot, port, bond); @@ -1544,7 +1545,7 @@ ocelot_netdevice_changelowerstate(struct net_device *dev, bool is_active = info->link_up && info->tx_enabled; struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = priv->chip_port; + int port = priv->port.index; if (!ocelot_port->bond) return NOTIFY_DONE; @@ -1692,7 +1693,7 @@ static void vsc7514_phylink_mac_link_down(struct phylink_config *config, struct net_device *ndev = to_net_dev(config->dev); struct ocelot_port_private *priv = netdev_priv(ndev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface, OCELOT_MAC_QUIRKS); @@ -1708,7 +1709,7 @@ static void vsc7514_phylink_mac_link_up(struct phylink_config *config, struct net_device *ndev = to_net_dev(config->dev); struct ocelot_port_private *priv = netdev_priv(ndev); struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; + int port = priv->port.index; ocelot_phylink_mac_link_up(ocelot, port, phydev, link_an_mode, interface, speed, duplex, @@ -1822,9 +1823,9 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target, SET_NETDEV_DEV(dev, ocelot->dev); priv = netdev_priv(dev); priv->dev = dev; - priv->chip_port = port; ocelot_port = &priv->port; ocelot_port->ocelot = ocelot; + ocelot_port->index = port; ocelot_port->target = target; ocelot->ports[port] = ocelot_port; diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c index a65606bb84a0c..7e1f67be38f5b 100644 --- a/drivers/net/ethernet/mscc/ocelot_police.c +++ b/drivers/net/ethernet/mscc/ocelot_police.c @@ -20,7 +20,7 @@ /* Default policer order */ #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */ -int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, +int qos_policer_conf_set(struct ocelot *ocelot, u32 pol_ix, struct qos_policer_conf *conf) { u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE; @@ -102,26 +102,30 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, /* Check limits */ if (pir > GENMASK(15, 0)) { - dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n", - port, pir, GENMASK(15, 0)); + dev_err(ocelot->dev, + "Invalid pir for policer %u: %u (max %lu)\n", + pol_ix, pir, GENMASK(15, 0)); return -EINVAL; } if (cir > GENMASK(15, 0)) { - dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n", - port, cir, GENMASK(15, 0)); + dev_err(ocelot->dev, + "Invalid cir for policer %u: %u (max %lu)\n", + pol_ix, cir, GENMASK(15, 0)); return -EINVAL; } if (pbs > pbs_max) { - dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n", - port, pbs, pbs_max); + dev_err(ocelot->dev, + "Invalid pbs for policer %u: %u (max %u)\n", + pol_ix, pbs, pbs_max); return -EINVAL; } if (cbs > cbs_max) { - dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n", - port, cbs, cbs_max); + dev_err(ocelot->dev, + "Invalid cbs for policer %u: %u (max %u)\n", + pol_ix, cbs, cbs_max); return -EINVAL; } @@ -211,7 +215,7 @@ int ocelot_port_policer_add(struct ocelot *ocelot, int port, dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n", __func__, port, pp.pir, pp.pbs); - err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); + err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp); if (err) return err; @@ -235,7 +239,7 @@ int ocelot_port_policer_del(struct ocelot *ocelot, int port) pp.mode = MSCC_QOS_RATE_MODE_DISABLED; - err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); + err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp); if (err) return err; diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h index 7552995f8b177..0749f23684f24 100644 --- a/drivers/net/ethernet/mscc/ocelot_police.h +++ b/drivers/net/ethernet/mscc/ocelot_police.h @@ -31,7 +31,7 @@ struct qos_policer_conf { u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */ }; -int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, +int qos_policer_conf_set(struct ocelot *ocelot, u32 pol_ix, struct qos_policer_conf *conf); int ocelot_policer_validate(const struct flow_action *action, diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c index c8701ac955a8f..73cdec5ca6a34 100644 --- a/drivers/net/ethernet/mscc/ocelot_vcap.c +++ b/drivers/net/ethernet/mscc/ocelot_vcap.c @@ -374,7 +374,6 @@ static void is2_entry_set(struct ocelot *ocelot, int ix, OCELOT_VCAP_BIT_0); vcap_key_set(vcap, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0, ~filter->ingress_port_mask); - vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_ANY); vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_HOST_MATCH, OCELOT_VCAP_BIT_ANY); vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_MC, filter->dmac_mc); @@ -672,12 +671,10 @@ static void is1_entry_set(struct ocelot *ocelot, int ix, { const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1]; struct ocelot_vcap_key_vlan *tag = &filter->vlan; - struct ocelot_vcap_u64 payload; struct vcap_data data; int row = ix / 2; u32 type; - memset(&payload, 0, sizeof(payload)); memset(&data, 0, sizeof(data)); /* Read row */ @@ -813,11 +810,9 @@ static void es0_entry_set(struct ocelot *ocelot, int ix, { const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; struct ocelot_vcap_key_vlan *tag = &filter->vlan; - struct ocelot_vcap_u64 payload; struct vcap_data data; int row = ix; - memset(&payload, 0, sizeof(payload)); memset(&data, 0, sizeof(data)); /* Read row */ @@ -918,7 +913,7 @@ int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix, if (!tmp) return -ENOMEM; - ret = qos_policer_conf_set(ocelot, 0, pol_ix, &pp); + ret = qos_policer_conf_set(ocelot, pol_ix, &pp); if (ret) { kfree(tmp); return ret; @@ -949,7 +944,7 @@ int ocelot_vcap_policer_del(struct ocelot *ocelot, u32 pol_ix) if (z) { pp.mode = MSCC_QOS_RATE_MODE_DISABLED; - return qos_policer_conf_set(ocelot, 0, pol_ix, &pp); + return qos_policer_conf_set(ocelot, pol_ix, &pp); } return 0; @@ -997,8 +992,8 @@ static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, struct ocelot_vcap_filter *filter, struct netlink_ext_ack *extack) { + struct list_head *pos = &block->rules; struct ocelot_vcap_filter *tmp; - struct list_head *pos, *n; int ret; ret = ocelot_vcap_filter_add_aux_resources(ocelot, filter, extack); @@ -1007,17 +1002,13 @@ static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, block->count++; - if (list_empty(&block->rules)) { - list_add(&filter->list, &block->rules); - return 0; - } - - list_for_each_safe(pos, n, &block->rules) { - tmp = list_entry(pos, struct ocelot_vcap_filter, list); - if (filter->prio < tmp->prio) + list_for_each_entry(tmp, &block->rules, list) { + if (filter->prio < tmp->prio) { + pos = &tmp->list; break; + } } - list_add(&filter->list, pos->prev); + list_add_tail(&filter->list, pos); return 0; } @@ -1217,6 +1208,8 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot, struct ocelot_vcap_filter *tmp; tmp = ocelot_vcap_block_find_filter_by_index(block, i); + /* Read back the filter's counters before moving it */ + vcap_entry_get(ocelot, i - 1, tmp); vcap_entry_set(ocelot, i, tmp); } @@ -1250,7 +1243,11 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot, struct ocelot_vcap_filter del_filter; int i, index; + /* Need to inherit the block_id so that vcap_entry_set() + * does not get confused and knows where to install it. + */ memset(&del_filter, 0, sizeof(del_filter)); + del_filter.block_id = filter->block_id; /* Gets index of the filter */ index = ocelot_vcap_block_get_filter_index(block, filter); @@ -1265,6 +1262,8 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot, struct ocelot_vcap_filter *tmp; tmp = ocelot_vcap_block_find_filter_by_index(block, i); + /* Read back the filter's counters before moving it */ + vcap_entry_get(ocelot, i + 1, tmp); vcap_entry_set(ocelot, i, tmp); } @@ -1402,22 +1401,18 @@ static void ocelot_vcap_detect_constants(struct ocelot *ocelot, int ocelot_vcap_init(struct ocelot *ocelot) { - int i; + struct qos_policer_conf cpu_drop = { + .mode = MSCC_QOS_RATE_MODE_DATA, + }; + int ret, i; /* Create a policer that will drop the frames for the cpu. * This policer will be used as action in the acl rules to drop * frames. */ - ocelot_write_gix(ocelot, 0x299, ANA_POL_MODE_CFG, - OCELOT_POLICER_DISCARD); - ocelot_write_gix(ocelot, 0x1, ANA_POL_PIR_CFG, - OCELOT_POLICER_DISCARD); - ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_PIR_STATE, - OCELOT_POLICER_DISCARD); - ocelot_write_gix(ocelot, 0x0, ANA_POL_CIR_CFG, - OCELOT_POLICER_DISCARD); - ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE, - OCELOT_POLICER_DISCARD); + ret = qos_policer_conf_set(ocelot, OCELOT_POLICER_DISCARD, &cpu_drop); + if (ret) + return ret; for (i = 0; i < OCELOT_NUM_VCAP_BLOCKS; i++) { struct ocelot_vcap_block *block = &ocelot->block[i]; diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c index 4f4a495a60ad5..961f803aca192 100644 --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c @@ -190,6 +190,7 @@ static const struct ocelot_stat_layout ocelot_stats_layout[] = { { .name = "drop_green_prio_5", .offset = 0x8F, }, { .name = "drop_green_prio_6", .offset = 0x90, }, { .name = "drop_green_prio_7", .offset = 0x91, }, + OCELOT_STAT_END }; static void ocelot_pll5_init(struct ocelot *ocelot) @@ -227,7 +228,6 @@ static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops) ocelot->map = ocelot_regmap; ocelot->stats_layout = ocelot_stats_layout; - ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout); ocelot->num_mact_rows = 1024; ocelot->ops = ops; |