Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ocelot: replay switchdev events when joining bridge

The premise of this change is that the switchdev port attributes and
objects offloaded by ocelot might have been missed when we are joining
an already existing bridge port, such as a bonding interface.

The patch pulls these switchdev attributes and objects from the bridge,
on behalf of the 'bridge port' net device which might be either the
ocelot switch interface, or the bonding upper interface.

The ocelot_net.c belongs strictly to the switchdev ocelot driver, while
ocelot.c is part of a library shared with the DSA felix driver.
The ocelot_port_bridge_leave function (part of the common library) used
to call ocelot_port_vlan_filtering(false), something which is not
necessary for DSA, since the framework deals with that already there.
So we move this function to ocelot_switchdev_unsync, which is specific
to the switchdev driver.

The code movement described above makes ocelot_port_bridge_leave no
longer return an error code, so we change its type from int to void.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vladimir Oltean and committed by
David S. Miller
e4bd44e8 81ef35e7

+113 -35
+3 -1
drivers/net/dsa/ocelot/felix.c
··· 719 719 { 720 720 struct ocelot *ocelot = ds->priv; 721 721 722 - return ocelot_port_bridge_join(ocelot, port, br); 722 + ocelot_port_bridge_join(ocelot, port, br); 723 + 724 + return 0; 723 725 } 724 726 725 727 static void felix_bridge_leave(struct dsa_switch *ds, int port,
+2 -1
drivers/net/ethernet/mscc/Kconfig
··· 11 11 12 12 if NET_VENDOR_MICROSEMI 13 13 14 - # Users should depend on NET_SWITCHDEV, HAS_IOMEM 14 + # Users should depend on NET_SWITCHDEV, HAS_IOMEM, BRIDGE 15 15 config MSCC_OCELOT_SWITCH_LIB 16 16 select NET_DEVLINK 17 17 select REGMAP_MMIO ··· 24 24 25 25 config MSCC_OCELOT_SWITCH 26 26 tristate "Ocelot switch driver" 27 + depends on BRIDGE || BRIDGE=n 27 28 depends on NET_SWITCHDEV 28 29 depends on HAS_IOMEM 29 30 depends on OF_NET
+6 -12
drivers/net/ethernet/mscc/ocelot.c
··· 1514 1514 } 1515 1515 EXPORT_SYMBOL(ocelot_port_mdb_del); 1516 1516 1517 - int ocelot_port_bridge_join(struct ocelot *ocelot, int port, 1518 - struct net_device *bridge) 1517 + void ocelot_port_bridge_join(struct ocelot *ocelot, int port, 1518 + struct net_device *bridge) 1519 1519 { 1520 1520 struct ocelot_port *ocelot_port = ocelot->ports[port]; 1521 1521 1522 1522 ocelot_port->bridge = bridge; 1523 1523 1524 - return 0; 1524 + ocelot_apply_bridge_fwd_mask(ocelot); 1525 1525 } 1526 1526 EXPORT_SYMBOL(ocelot_port_bridge_join); 1527 1527 1528 - int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, 1529 - struct net_device *bridge) 1528 + void ocelot_port_bridge_leave(struct ocelot *ocelot, int port, 1529 + struct net_device *bridge) 1530 1530 { 1531 1531 struct ocelot_port *ocelot_port = ocelot->ports[port]; 1532 1532 struct ocelot_vlan pvid = {0}, native_vlan = {0}; 1533 - int ret; 1534 1533 1535 1534 ocelot_port->bridge = NULL; 1536 1535 1537 - ret = ocelot_port_vlan_filtering(ocelot, port, false); 1538 - if (ret) 1539 - return ret; 1540 - 1541 1536 ocelot_port_set_pvid(ocelot, port, pvid); 1542 1537 ocelot_port_set_native_vlan(ocelot, port, native_vlan); 1543 - 1544 - return 0; 1538 + ocelot_apply_bridge_fwd_mask(ocelot); 1545 1539 } 1546 1540 EXPORT_SYMBOL(ocelot_port_bridge_leave); 1547 1541
+99 -18
drivers/net/ethernet/mscc/ocelot_net.c
··· 1117 1117 return ret; 1118 1118 } 1119 1119 1120 + static void ocelot_inherit_brport_flags(struct ocelot *ocelot, int port, 1121 + struct net_device *brport_dev) 1122 + { 1123 + struct switchdev_brport_flags flags = {0}; 1124 + int flag; 1125 + 1126 + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 1127 + 1128 + for_each_set_bit(flag, &flags.mask, 32) 1129 + if (br_port_flag_is_set(brport_dev, BIT(flag))) 1130 + flags.val |= BIT(flag); 1131 + 1132 + ocelot_port_bridge_flags(ocelot, port, flags); 1133 + } 1134 + 1135 + static void ocelot_clear_brport_flags(struct ocelot *ocelot, int port) 1136 + { 1137 + struct switchdev_brport_flags flags; 1138 + 1139 + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 1140 + flags.val = flags.mask & ~BR_LEARNING; 1141 + 1142 + ocelot_port_bridge_flags(ocelot, port, flags); 1143 + } 1144 + 1145 + static int ocelot_switchdev_sync(struct ocelot *ocelot, int port, 1146 + struct net_device *brport_dev, 1147 + struct net_device *bridge_dev, 1148 + struct netlink_ext_ack *extack) 1149 + { 1150 + clock_t ageing_time; 1151 + u8 stp_state; 1152 + int err; 1153 + 1154 + ocelot_inherit_brport_flags(ocelot, port, brport_dev); 1155 + 1156 + stp_state = br_port_get_stp_state(brport_dev); 1157 + ocelot_bridge_stp_state_set(ocelot, port, stp_state); 1158 + 1159 + err = ocelot_port_vlan_filtering(ocelot, port, 1160 + br_vlan_enabled(bridge_dev)); 1161 + if (err) 1162 + return err; 1163 + 1164 + ageing_time = br_get_ageing_time(bridge_dev); 1165 + ocelot_port_attr_ageing_set(ocelot, port, ageing_time); 1166 + 1167 + err = br_mdb_replay(bridge_dev, brport_dev, 1168 + &ocelot_switchdev_blocking_nb, extack); 1169 + if (err && err != -EOPNOTSUPP) 1170 + return err; 1171 + 1172 + err = br_fdb_replay(bridge_dev, brport_dev, &ocelot_switchdev_nb); 1173 + if (err) 1174 + return err; 1175 + 1176 + err = br_vlan_replay(bridge_dev, brport_dev, 1177 + &ocelot_switchdev_blocking_nb, extack); 1178 + if (err && err != -EOPNOTSUPP) 1179 + return err; 1180 + 1181 + return 0; 1182 + } 1183 + 1184 + static int ocelot_switchdev_unsync(struct ocelot *ocelot, int port) 1185 + { 1186 + int err; 1187 + 1188 + err = ocelot_port_vlan_filtering(ocelot, port, false); 1189 + if (err) 1190 + return err; 1191 + 1192 + ocelot_clear_brport_flags(ocelot, port); 1193 + 1194 + ocelot_bridge_stp_state_set(ocelot, port, BR_STATE_FORWARDING); 1195 + 1196 + return 0; 1197 + } 1198 + 1120 1199 static int ocelot_netdevice_bridge_join(struct net_device *dev, 1200 + struct net_device *brport_dev, 1121 1201 struct net_device *bridge, 1122 1202 struct netlink_ext_ack *extack) 1123 1203 { 1124 1204 struct ocelot_port_private *priv = netdev_priv(dev); 1125 1205 struct ocelot_port *ocelot_port = &priv->port; 1126 1206 struct ocelot *ocelot = ocelot_port->ocelot; 1127 - struct switchdev_brport_flags flags; 1128 1207 int port = priv->chip_port; 1129 1208 int err; 1130 1209 1131 - flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 1132 - flags.val = flags.mask; 1210 + ocelot_port_bridge_join(ocelot, port, bridge); 1133 1211 1134 - err = ocelot_port_bridge_join(ocelot, port, bridge); 1212 + err = ocelot_switchdev_sync(ocelot, port, brport_dev, bridge, extack); 1135 1213 if (err) 1136 - return err; 1137 - 1138 - ocelot_port_bridge_flags(ocelot, port, flags); 1214 + goto err_switchdev_sync; 1139 1215 1140 1216 return 0; 1217 + 1218 + err_switchdev_sync: 1219 + ocelot_port_bridge_leave(ocelot, port, bridge); 1220 + return err; 1141 1221 } 1142 1222 1143 1223 static int ocelot_netdevice_bridge_leave(struct net_device *dev, 1224 + struct net_device *brport_dev, 1144 1225 struct net_device *bridge) 1145 1226 { 1146 1227 struct ocelot_port_private *priv = netdev_priv(dev); 1147 1228 struct ocelot_port *ocelot_port = &priv->port; 1148 1229 struct ocelot *ocelot = ocelot_port->ocelot; 1149 - struct switchdev_brport_flags flags; 1150 1230 int port = priv->chip_port; 1151 1231 int err; 1152 1232 1153 - flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 1154 - flags.val = flags.mask & ~BR_LEARNING; 1233 + err = ocelot_switchdev_unsync(ocelot, port); 1234 + if (err) 1235 + return err; 1155 1236 1156 - err = ocelot_port_bridge_leave(ocelot, port, bridge); 1237 + ocelot_port_bridge_leave(ocelot, port, bridge); 1157 1238 1158 - ocelot_port_bridge_flags(ocelot, port, flags); 1159 - 1160 - return err; 1239 + return 0; 1161 1240 } 1162 1241 1163 1242 static int ocelot_netdevice_lag_join(struct net_device *dev, ··· 1261 1182 if (!bridge_dev || !netif_is_bridge_master(bridge_dev)) 1262 1183 return 0; 1263 1184 1264 - err = ocelot_netdevice_bridge_join(dev, bridge_dev, extack); 1185 + err = ocelot_netdevice_bridge_join(dev, bond, bridge_dev, extack); 1265 1186 if (err) 1266 1187 goto err_bridge_join; 1267 1188 ··· 1287 1208 if (!bridge_dev || !netif_is_bridge_master(bridge_dev)) 1288 1209 return 0; 1289 1210 1290 - return ocelot_netdevice_bridge_leave(dev, bridge_dev); 1211 + return ocelot_netdevice_bridge_leave(dev, bond, bridge_dev); 1291 1212 } 1292 1213 1293 1214 static int ocelot_netdevice_changeupper(struct net_device *dev, ··· 1300 1221 1301 1222 if (netif_is_bridge_master(info->upper_dev)) { 1302 1223 if (info->linking) 1303 - err = ocelot_netdevice_bridge_join(dev, info->upper_dev, 1224 + err = ocelot_netdevice_bridge_join(dev, dev, 1225 + info->upper_dev, 1304 1226 extack); 1305 1227 else 1306 - err = ocelot_netdevice_bridge_leave(dev, info->upper_dev); 1228 + err = ocelot_netdevice_bridge_leave(dev, dev, 1229 + info->upper_dev); 1307 1230 } 1308 1231 if (netif_is_lag_master(info->upper_dev)) { 1309 1232 if (info->linking)
+3 -3
include/soc/mscc/ocelot.h
··· 803 803 struct switchdev_brport_flags val); 804 804 void ocelot_port_bridge_flags(struct ocelot *ocelot, int port, 805 805 struct switchdev_brport_flags val); 806 - int ocelot_port_bridge_join(struct ocelot *ocelot, int port, 807 - struct net_device *bridge); 808 - int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, 806 + void ocelot_port_bridge_join(struct ocelot *ocelot, int port, 809 807 struct net_device *bridge); 808 + void ocelot_port_bridge_leave(struct ocelot *ocelot, int port, 809 + struct net_device *bridge); 810 810 int ocelot_fdb_dump(struct ocelot *ocelot, int port, 811 811 dsa_fdb_dump_cb_t *cb, void *data); 812 812 int ocelot_fdb_add(struct ocelot *ocelot, int port,