Skip to content

Commit 421741e

Browse files
vladimirolteandavem330
authored andcommitted
net: mscc: ocelot: offload bridge port flags to device
We should not be unconditionally enabling address learning, since doing that is actively detrimential when a port is standalone and not offloading a bridge. Namely, if a port in the switch is standalone and others are offloading the bridge, then we could enter a situation where we learn an address towards the standalone port, but the bridged ports could not forward the packet there, because the CPU is the only path between the standalone and the bridged ports. The solution of course is to not enable address learning unless the bridge asks for it. We need to set up the initial port flags for no learning and flooding everything, and also when the port joins and leaves the bridge. The flood configuration was already configured ok for standalone mode in ocelot_init, we just need to disable learning in ocelot_init_port. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Alexandre Belloni <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b360d94 commit 421741e

File tree

4 files changed

+158
-5
lines changed

4 files changed

+158
-5
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,26 @@ static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port,
556556
return ocelot_bridge_stp_state_set(ocelot, port, state);
557557
}
558558

559+
static int felix_pre_bridge_flags(struct dsa_switch *ds, int port,
560+
struct switchdev_brport_flags val,
561+
struct netlink_ext_ack *extack)
562+
{
563+
struct ocelot *ocelot = ds->priv;
564+
565+
return ocelot_port_pre_bridge_flags(ocelot, port, val);
566+
}
567+
568+
static int felix_bridge_flags(struct dsa_switch *ds, int port,
569+
struct switchdev_brport_flags val,
570+
struct netlink_ext_ack *extack)
571+
{
572+
struct ocelot *ocelot = ds->priv;
573+
574+
ocelot_port_bridge_flags(ocelot, port, val);
575+
576+
return 0;
577+
}
578+
559579
static int felix_bridge_join(struct dsa_switch *ds, int port,
560580
struct net_device *br)
561581
{
@@ -1376,6 +1396,8 @@ const struct dsa_switch_ops felix_switch_ops = {
13761396
.port_fdb_del = felix_fdb_del,
13771397
.port_mdb_add = felix_mdb_add,
13781398
.port_mdb_del = felix_mdb_del,
1399+
.port_pre_bridge_flags = felix_pre_bridge_flags,
1400+
.port_bridge_flags = felix_bridge_flags,
13791401
.port_bridge_join = felix_bridge_join,
13801402
.port_bridge_leave = felix_bridge_leave,
13811403
.port_lag_join = felix_lag_join,

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,7 @@ EXPORT_SYMBOL(ocelot_apply_bridge_fwd_mask);
10381038

10391039
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
10401040
{
1041+
struct ocelot_port *ocelot_port = ocelot->ports[port];
10411042
u32 port_cfg;
10421043

10431044
if (!(BIT(port) & ocelot->bridge_mask))
@@ -1050,7 +1051,8 @@ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
10501051
ocelot->bridge_fwd_mask |= BIT(port);
10511052
fallthrough;
10521053
case BR_STATE_LEARNING:
1053-
port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
1054+
if (ocelot_port->learn_ena)
1055+
port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
10541056
break;
10551057

10561058
default:
@@ -1534,6 +1536,86 @@ int ocelot_get_max_mtu(struct ocelot *ocelot, int port)
15341536
}
15351537
EXPORT_SYMBOL(ocelot_get_max_mtu);
15361538

1539+
static void ocelot_port_set_learning(struct ocelot *ocelot, int port,
1540+
bool enabled)
1541+
{
1542+
struct ocelot_port *ocelot_port = ocelot->ports[port];
1543+
u32 val = 0;
1544+
1545+
if (enabled)
1546+
val = ANA_PORT_PORT_CFG_LEARN_ENA;
1547+
1548+
ocelot_rmw_gix(ocelot, val, ANA_PORT_PORT_CFG_LEARN_ENA,
1549+
ANA_PORT_PORT_CFG, port);
1550+
1551+
ocelot_port->learn_ena = enabled;
1552+
}
1553+
1554+
static void ocelot_port_set_ucast_flood(struct ocelot *ocelot, int port,
1555+
bool enabled)
1556+
{
1557+
u32 val = 0;
1558+
1559+
if (enabled)
1560+
val = BIT(port);
1561+
1562+
ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_UC);
1563+
}
1564+
1565+
static void ocelot_port_set_mcast_flood(struct ocelot *ocelot, int port,
1566+
bool enabled)
1567+
{
1568+
u32 val = 0;
1569+
1570+
if (enabled)
1571+
val = BIT(port);
1572+
1573+
ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_MC);
1574+
}
1575+
1576+
static void ocelot_port_set_bcast_flood(struct ocelot *ocelot, int port,
1577+
bool enabled)
1578+
{
1579+
u32 val = 0;
1580+
1581+
if (enabled)
1582+
val = BIT(port);
1583+
1584+
ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_BC);
1585+
}
1586+
1587+
int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port,
1588+
struct switchdev_brport_flags flags)
1589+
{
1590+
if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
1591+
BR_BCAST_FLOOD))
1592+
return -EINVAL;
1593+
1594+
return 0;
1595+
}
1596+
EXPORT_SYMBOL(ocelot_port_pre_bridge_flags);
1597+
1598+
void ocelot_port_bridge_flags(struct ocelot *ocelot, int port,
1599+
struct switchdev_brport_flags flags)
1600+
{
1601+
if (flags.mask & BR_LEARNING)
1602+
ocelot_port_set_learning(ocelot, port,
1603+
!!(flags.val & BR_LEARNING));
1604+
1605+
if (flags.mask & BR_FLOOD)
1606+
ocelot_port_set_ucast_flood(ocelot, port,
1607+
!!(flags.val & BR_FLOOD));
1608+
1609+
if (flags.mask & BR_MCAST_FLOOD)
1610+
ocelot_port_set_mcast_flood(ocelot, port,
1611+
!!(flags.val & BR_MCAST_FLOOD));
1612+
1613+
if (flags.mask & BR_BCAST_FLOOD)
1614+
ocelot_port_set_bcast_flood(ocelot, port,
1615+
!!(flags.val & BR_BCAST_FLOOD));
1616+
}
1617+
EXPORT_SYMBOL(ocelot_port_bridge_flags);
1618+
15371619
void ocelot_init_port(struct ocelot *ocelot, int port)
15381620
{
15391621
struct ocelot_port *ocelot_port = ocelot->ports[port];
@@ -1583,6 +1665,9 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
15831665
REW_PORT_VLAN_CFG_PORT_TPID_M,
15841666
REW_PORT_VLAN_CFG, port);
15851667

1668+
/* Disable source address learning for standalone mode */
1669+
ocelot_port_set_learning(ocelot, port, false);
1670+
15861671
/* Enable vcap lookups */
15871672
ocelot_vcap_enable(ocelot, port);
15881673
}

drivers/net/ethernet/mscc/ocelot_net.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,13 @@ static int ocelot_port_attr_set(struct net_device *dev,
10261026
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
10271027
ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
10281028
break;
1029+
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
1030+
err = ocelot_port_pre_bridge_flags(ocelot, port,
1031+
attr->u.brport_flags);
1032+
break;
1033+
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
1034+
ocelot_port_bridge_flags(ocelot, port, attr->u.brport_flags);
1035+
break;
10291036
default:
10301037
err = -EOPNOTSUPP;
10311038
break;
@@ -1111,6 +1118,40 @@ static int ocelot_port_obj_del(struct net_device *dev,
11111118
return ret;
11121119
}
11131120

1121+
static int ocelot_netdevice_bridge_join(struct ocelot *ocelot, int port,
1122+
struct net_device *bridge)
1123+
{
1124+
struct switchdev_brport_flags flags;
1125+
int err;
1126+
1127+
flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
1128+
flags.val = flags.mask;
1129+
1130+
err = ocelot_port_bridge_join(ocelot, port, bridge);
1131+
if (err)
1132+
return err;
1133+
1134+
ocelot_port_bridge_flags(ocelot, port, flags);
1135+
1136+
return 0;
1137+
}
1138+
1139+
static int ocelot_netdevice_bridge_leave(struct ocelot *ocelot, int port,
1140+
struct net_device *bridge)
1141+
{
1142+
struct switchdev_brport_flags flags;
1143+
int err;
1144+
1145+
flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
1146+
flags.val = flags.mask & ~BR_LEARNING;
1147+
1148+
err = ocelot_port_bridge_leave(ocelot, port, bridge);
1149+
1150+
ocelot_port_bridge_flags(ocelot, port, flags);
1151+
1152+
return err;
1153+
}
1154+
11141155
static int ocelot_netdevice_changeupper(struct net_device *dev,
11151156
struct netdev_notifier_changeupper_info *info)
11161157
{
@@ -1122,11 +1163,11 @@ static int ocelot_netdevice_changeupper(struct net_device *dev,
11221163

11231164
if (netif_is_bridge_master(info->upper_dev)) {
11241165
if (info->linking) {
1125-
err = ocelot_port_bridge_join(ocelot, port,
1126-
info->upper_dev);
1166+
err = ocelot_netdevice_bridge_join(ocelot, port,
1167+
info->upper_dev);
11271168
} else {
1128-
err = ocelot_port_bridge_leave(ocelot, port,
1129-
info->upper_dev);
1169+
err = ocelot_netdevice_bridge_leave(ocelot, port,
1170+
info->upper_dev);
11301171
}
11311172
}
11321173
if (netif_is_lag_master(info->upper_dev)) {

include/soc/mscc/ocelot.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ struct ocelot_port {
612612

613613
u8 *xmit_template;
614614
bool is_dsa_8021q_cpu;
615+
bool learn_ena;
615616

616617
struct net_device *bond;
617618
bool lag_tx_active;
@@ -766,6 +767,10 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port,
766767
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled);
767768
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
768769
void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot);
770+
int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port,
771+
struct switchdev_brport_flags val);
772+
void ocelot_port_bridge_flags(struct ocelot *ocelot, int port,
773+
struct switchdev_brport_flags val);
769774
int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
770775
struct net_device *bridge);
771776
int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,

0 commit comments

Comments
 (0)