Skip to content

Commit c311db9

Browse files
committed
Merge branch 'mv88e6xxx-broadcast-flooding-in-hardware'
Andrew Lunn says: ==================== mv88e6xxx broadcast flooding in hardware This patchset makes the mv88e6xxx driver perform flooding in hardware, rather than let the software bridge perform the flooding. This is a prerequisite for IGMP snooping on the bridge interface. In order to make hardware broadcasting work, a few other issues need fixing or improving. SWITCHDEV_ATTR_ID_PORT_PARENT_ID is broken, which is apparent when testing on the ZII devel board with multiple switches. Some of these patches are taken from a previous RFC patchset of IGMP support. Rebased onto net-next, with fixup for Vivien's refactoring. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 8c5f9a8 + 87fa886 commit c311db9

File tree

4 files changed

+86
-50
lines changed

4 files changed

+86
-50
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 79 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
11371137
if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
11381138
continue;
11391139

1140-
if (!ds->ports[port].slave)
1140+
if (!ds->ports[i].slave)
11411141
continue;
11421142

11431143
if (vlan.member[i] ==
@@ -1151,8 +1151,8 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
11511151
if (!dsa_to_port(ds, i)->bridge_dev)
11521152
continue;
11531153

1154-
dev_err(ds->dev, "p%d: hw VLAN %d already used by %s\n",
1155-
port, vlan.vid,
1154+
dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
1155+
port, vlan.vid, i,
11561156
netdev_name(dsa_to_port(ds, i)->bridge_dev));
11571157
err = -EOPNOTSUPP;
11581158
goto unlock;
@@ -1208,6 +1208,73 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
12081208
return 0;
12091209
}
12101210

1211+
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1212+
const unsigned char *addr, u16 vid,
1213+
u8 state)
1214+
{
1215+
struct mv88e6xxx_vtu_entry vlan;
1216+
struct mv88e6xxx_atu_entry entry;
1217+
int err;
1218+
1219+
/* Null VLAN ID corresponds to the port private database */
1220+
if (vid == 0)
1221+
err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
1222+
else
1223+
err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1224+
if (err)
1225+
return err;
1226+
1227+
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1228+
ether_addr_copy(entry.mac, addr);
1229+
eth_addr_dec(entry.mac);
1230+
1231+
err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
1232+
if (err)
1233+
return err;
1234+
1235+
/* Initialize a fresh ATU entry if it isn't found */
1236+
if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
1237+
!ether_addr_equal(entry.mac, addr)) {
1238+
memset(&entry, 0, sizeof(entry));
1239+
ether_addr_copy(entry.mac, addr);
1240+
}
1241+
1242+
/* Purge the ATU entry only if no port is using it anymore */
1243+
if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
1244+
entry.portvec &= ~BIT(port);
1245+
if (!entry.portvec)
1246+
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1247+
} else {
1248+
entry.portvec |= BIT(port);
1249+
entry.state = state;
1250+
}
1251+
1252+
return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
1253+
}
1254+
1255+
static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
1256+
u16 vid)
1257+
{
1258+
const char broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1259+
u8 state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
1260+
1261+
return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
1262+
}
1263+
1264+
static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
1265+
{
1266+
int port;
1267+
int err;
1268+
1269+
for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
1270+
err = mv88e6xxx_port_add_broadcast(chip, port, vid);
1271+
if (err)
1272+
return err;
1273+
}
1274+
1275+
return 0;
1276+
}
1277+
12111278
static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
12121279
u16 vid, u8 member)
12131280
{
@@ -1220,7 +1287,11 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
12201287

12211288
vlan.member[port] = member;
12221289

1223-
return mv88e6xxx_vtu_loadpurge(chip, &vlan);
1290+
err = mv88e6xxx_vtu_loadpurge(chip, &vlan);
1291+
if (err)
1292+
return err;
1293+
1294+
return mv88e6xxx_broadcast_setup(chip, vid);
12241295
}
12251296

12261297
static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
@@ -1324,50 +1395,6 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
13241395
return err;
13251396
}
13261397

1327-
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
1328-
const unsigned char *addr, u16 vid,
1329-
u8 state)
1330-
{
1331-
struct mv88e6xxx_vtu_entry vlan;
1332-
struct mv88e6xxx_atu_entry entry;
1333-
int err;
1334-
1335-
/* Null VLAN ID corresponds to the port private database */
1336-
if (vid == 0)
1337-
err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
1338-
else
1339-
err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
1340-
if (err)
1341-
return err;
1342-
1343-
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1344-
ether_addr_copy(entry.mac, addr);
1345-
eth_addr_dec(entry.mac);
1346-
1347-
err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
1348-
if (err)
1349-
return err;
1350-
1351-
/* Initialize a fresh ATU entry if it isn't found */
1352-
if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
1353-
!ether_addr_equal(entry.mac, addr)) {
1354-
memset(&entry, 0, sizeof(entry));
1355-
ether_addr_copy(entry.mac, addr);
1356-
}
1357-
1358-
/* Purge the ATU entry only if no port is using it anymore */
1359-
if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
1360-
entry.portvec &= ~BIT(port);
1361-
if (!entry.portvec)
1362-
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
1363-
} else {
1364-
entry.portvec |= BIT(port);
1365-
entry.state = state;
1366-
}
1367-
1368-
return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
1369-
}
1370-
13711398
static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
13721399
const unsigned char *addr, u16 vid)
13731400
{
@@ -2049,6 +2076,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
20492076
if (err)
20502077
goto unlock;
20512078

2079+
err = mv88e6xxx_broadcast_setup(chip, 0);
2080+
if (err)
2081+
goto unlock;
2082+
20522083
err = mv88e6xxx_pot_setup(chip);
20532084
if (err)
20542085
goto unlock;

net/dsa/slave.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,12 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
355355
{
356356
struct dsa_port *dp = dsa_slave_to_port(dev);
357357
struct dsa_switch *ds = dp->ds;
358+
struct dsa_switch_tree *dst = ds->dst;
358359

359360
switch (attr->id) {
360361
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
361-
attr->u.ppid.id_len = sizeof(ds->index);
362-
memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len);
362+
attr->u.ppid.id_len = sizeof(dst->index);
363+
memcpy(&attr->u.ppid.id, &dst->index, attr->u.ppid.id_len);
363364
break;
364365
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:
365366
attr->u.brport_flags_support = 0;

net/dsa/tag_dsa.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
141141
2 * ETH_ALEN);
142142
}
143143

144+
skb->offload_fwd_mark = 1;
145+
144146
return skb;
145147
}
146148

net/dsa/tag_edsa.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
160160
2 * ETH_ALEN);
161161
}
162162

163+
skb->offload_fwd_mark = 1;
164+
163165
return skb;
164166
}
165167

0 commit comments

Comments
 (0)