Skip to content

Commit f1d5ca4

Browse files
committed
Merge branch 'mv88e6xxx-switchdev-fdb'
Vivien Didelot says: ==================== net: dsa: mv88e6xxx: support switchdev FDB objects This patchset refactors the DSA and mv88e6xxx code to use the switchdev FDB objects. The first two patches add minor but necessary changes to switchdev, the third one implements the switchdev glue in DSA for FDB routines, and the remaining ones refactor the FDB access functions in the mv88e6xxx code. Below is an usage example (ports 0-2 belongs to br0, ports 3-4 belongs to br1): # bridge fdb add 3c:97:0e:11:30:6e dev swp2 # bridge fdb add 3c:97:0e:11:40:78 dev swp3 # bridge fdb add 3c:97:0e:11:50:86 dev swp4 # bridge fdb del 3c:97:0e:11:40:78 dev swp3 # bridge fdb 01:00:5e:00:00:01 dev eth0 self permanent 01:00:5e:00:00:01 dev eth1 self permanent 00:50:d2:10:78:15 dev swp0 master br0 permanent 3c:97:0e:11:30:6e dev swp2 self static 00:50:d2:10:78:15 dev swp3 master br1 permanent 3c:97:0e:11:50:86 dev swp4 self static # cat /sys/kernel/debug/dsa0/atu # DB T/P Vec State Addr # 001 Port 004 e 3c:97:0e:11:30:6e # 004 Port 010 e 3c:97:0e:11:50:86 For the 88E6xxx switches, FIDs 1 to num_ports will be reserved for non-bridged ports and bridge groups, and the remaining will be later used by VLANs. This change is necessary to welcome the support for hardware VLANs (which will follow soon). Changes in v2: - remove ndo_bridge_{get,set,del}link from switchdev/DSA glue code - use ether_addr_copy instead of memcpy for MAC addresses - constify MAC address in port_fdb_{add,del} - split the mv88e6xxx code refactoring into several patches ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4933d85 + 8782051 commit f1d5ca4

File tree

10 files changed

+317
-197
lines changed

10 files changed

+317
-197
lines changed

drivers/net/dsa/mv88e6171.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
116116
.port_join_bridge = mv88e6xxx_join_bridge,
117117
.port_leave_bridge = mv88e6xxx_leave_bridge,
118118
.port_stp_update = mv88e6xxx_port_stp_update,
119-
.fdb_add = mv88e6xxx_port_fdb_add,
120-
.fdb_del = mv88e6xxx_port_fdb_del,
121-
.fdb_getnext = mv88e6xxx_port_fdb_getnext,
119+
.port_fdb_add = mv88e6xxx_port_fdb_add,
120+
.port_fdb_del = mv88e6xxx_port_fdb_del,
121+
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
122122
};
123123

124124
MODULE_ALIAS("platform:mv88e6171");

drivers/net/dsa/mv88e6352.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,9 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
341341
.port_join_bridge = mv88e6xxx_join_bridge,
342342
.port_leave_bridge = mv88e6xxx_leave_bridge,
343343
.port_stp_update = mv88e6xxx_port_stp_update,
344-
.fdb_add = mv88e6xxx_port_fdb_add,
345-
.fdb_del = mv88e6xxx_port_fdb_del,
346-
.fdb_getnext = mv88e6xxx_port_fdb_getnext,
344+
.port_fdb_add = mv88e6xxx_port_fdb_add,
345+
.port_fdb_del = mv88e6xxx_port_fdb_del,
346+
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
347347
};
348348

349349
MODULE_ALIAS("platform:mv88e6172");

drivers/net/dsa/mv88e6xxx.c

Lines changed: 155 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd)
964964
{
965965
int ret;
966966

967-
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x01, fid);
967+
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
968968
if (ret < 0)
969969
return ret;
970970

@@ -1091,7 +1091,7 @@ int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
10911091
ps->bridge_mask[fid] = br_port_mask;
10921092

10931093
if (fid != ps->fid[port]) {
1094-
ps->fid_mask |= 1 << ps->fid[port];
1094+
clear_bit(ps->fid[port], ps->fid_bitmap);
10951095
ps->fid[port] = fid;
10961096
ret = _mv88e6xxx_update_bridge_config(ds, fid);
10971097
}
@@ -1125,16 +1125,24 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
11251125

11261126
mutex_lock(&ps->smi_mutex);
11271127

1128-
newfid = __ffs(ps->fid_mask);
1128+
newfid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID, 1);
1129+
if (unlikely(newfid > ps->num_ports)) {
1130+
netdev_err(ds->ports[port], "all first %d FIDs are used\n",
1131+
ps->num_ports);
1132+
ret = -ENOSPC;
1133+
goto unlock;
1134+
}
1135+
11291136
ps->fid[port] = newfid;
1130-
ps->fid_mask &= ~(1 << newfid);
1137+
set_bit(newfid, ps->fid_bitmap);
11311138
ps->bridge_mask[fid] &= ~(1 << port);
11321139
ps->bridge_mask[newfid] = 1 << port;
11331140

11341141
ret = _mv88e6xxx_update_bridge_config(ds, fid);
11351142
if (!ret)
11361143
ret = _mv88e6xxx_update_bridge_config(ds, newfid);
11371144

1145+
unlock:
11381146
mutex_unlock(&ps->smi_mutex);
11391147

11401148
return ret;
@@ -1174,8 +1182,8 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
11741182
return 0;
11751183
}
11761184

1177-
static int __mv88e6xxx_write_addr(struct dsa_switch *ds,
1178-
const unsigned char *addr)
1185+
static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds,
1186+
const u8 addr[ETH_ALEN])
11791187
{
11801188
int i, ret;
11811189

@@ -1190,7 +1198,7 @@ static int __mv88e6xxx_write_addr(struct dsa_switch *ds,
11901198
return 0;
11911199
}
11921200

1193-
static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr)
1201+
static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, u8 addr[ETH_ALEN])
11941202
{
11951203
int i, ret;
11961204

@@ -1206,109 +1214,190 @@ static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr)
12061214
return 0;
12071215
}
12081216

1209-
static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port,
1210-
const unsigned char *addr, int state)
1217+
static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
1218+
struct mv88e6xxx_atu_entry *entry)
12111219
{
1212-
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1213-
u8 fid = ps->fid[port];
1220+
u16 reg = 0;
12141221
int ret;
12151222

12161223
ret = _mv88e6xxx_atu_wait(ds);
12171224
if (ret < 0)
12181225
return ret;
12191226

1220-
ret = __mv88e6xxx_write_addr(ds, addr);
1227+
ret = _mv88e6xxx_atu_mac_write(ds, entry->mac);
12211228
if (ret < 0)
12221229
return ret;
12231230

1224-
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA,
1225-
(0x10 << port) | state);
1226-
if (ret)
1231+
if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1232+
unsigned int mask, shift;
1233+
1234+
if (entry->trunk) {
1235+
reg |= GLOBAL_ATU_DATA_TRUNK;
1236+
mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
1237+
shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
1238+
} else {
1239+
mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
1240+
shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
1241+
}
1242+
1243+
reg |= (entry->portv_trunkid << shift) & mask;
1244+
}
1245+
1246+
reg |= entry->state & GLOBAL_ATU_DATA_STATE_MASK;
1247+
1248+
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, reg);
1249+
if (ret < 0)
12271250
return ret;
12281251

1229-
ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB);
1252+
return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
1253+
}
12301254

1231-
return ret;
1255+
static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
1256+
const u8 addr[ETH_ALEN],
1257+
struct mv88e6xxx_atu_entry *entry)
1258+
{
1259+
struct mv88e6xxx_atu_entry next = { 0 };
1260+
int ret;
1261+
1262+
next.fid = fid;
1263+
1264+
ret = _mv88e6xxx_atu_wait(ds);
1265+
if (ret < 0)
1266+
return ret;
1267+
1268+
ret = _mv88e6xxx_atu_mac_write(ds, addr);
1269+
if (ret < 0)
1270+
return ret;
1271+
1272+
ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
1273+
if (ret < 0)
1274+
return ret;
1275+
1276+
ret = _mv88e6xxx_atu_mac_read(ds, next.mac);
1277+
if (ret < 0)
1278+
return ret;
1279+
1280+
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
1281+
if (ret < 0)
1282+
return ret;
1283+
1284+
next.state = ret & GLOBAL_ATU_DATA_STATE_MASK;
1285+
if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1286+
unsigned int mask, shift;
1287+
1288+
if (ret & GLOBAL_ATU_DATA_TRUNK) {
1289+
next.trunk = true;
1290+
mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
1291+
shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
1292+
} else {
1293+
next.trunk = false;
1294+
mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
1295+
shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
1296+
}
1297+
1298+
next.portv_trunkid = (ret & mask) >> shift;
1299+
}
1300+
1301+
*entry = next;
1302+
return 0;
12321303
}
12331304

1234-
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
1235-
const unsigned char *addr, u16 vid)
1305+
static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid)
12361306
{
1237-
int state = is_multicast_ether_addr(addr) ?
1307+
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1308+
1309+
if (vid == 0)
1310+
return ps->fid[port];
1311+
1312+
return -ENOENT;
1313+
}
1314+
1315+
static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port, u16 vid,
1316+
const u8 addr[ETH_ALEN], u8 state)
1317+
{
1318+
struct mv88e6xxx_atu_entry entry = { 0 };
1319+
int ret;
1320+
1321+
ret = _mv88e6xxx_port_vid_to_fid(ds, port, vid);
1322+
if (ret < 0)
1323+
return ret;
1324+
1325+
entry.fid = ret;
1326+
entry.state = state;
1327+
ether_addr_copy(entry.mac, addr);
1328+
if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
1329+
entry.trunk = false;
1330+
entry.portv_trunkid = BIT(port);
1331+
}
1332+
1333+
return _mv88e6xxx_atu_load(ds, &entry);
1334+
}
1335+
1336+
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, u16 vid,
1337+
const u8 addr[ETH_ALEN])
1338+
{
1339+
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1340+
u8 state = is_multicast_ether_addr(addr) ?
12381341
GLOBAL_ATU_DATA_STATE_MC_STATIC :
12391342
GLOBAL_ATU_DATA_STATE_UC_STATIC;
1240-
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
12411343
int ret;
12421344

12431345
mutex_lock(&ps->smi_mutex);
1244-
ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state);
1346+
ret = _mv88e6xxx_port_fdb_load(ds, port, vid, addr, state);
12451347
mutex_unlock(&ps->smi_mutex);
12461348

12471349
return ret;
12481350
}
12491351

1250-
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
1251-
const unsigned char *addr, u16 vid)
1352+
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, u16 vid,
1353+
const u8 addr[ETH_ALEN])
12521354
{
12531355
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1356+
u8 state = GLOBAL_ATU_DATA_STATE_UNUSED;
12541357
int ret;
12551358

12561359
mutex_lock(&ps->smi_mutex);
1257-
ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr,
1258-
GLOBAL_ATU_DATA_STATE_UNUSED);
1360+
ret = _mv88e6xxx_port_fdb_load(ds, port, vid, addr, state);
12591361
mutex_unlock(&ps->smi_mutex);
12601362

12611363
return ret;
12621364
}
12631365

1264-
static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port,
1265-
unsigned char *addr, bool *is_static)
1366+
int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, u16 *vid,
1367+
u8 addr[ETH_ALEN], bool *is_static)
12661368
{
12671369
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1268-
u8 fid = ps->fid[port];
1269-
int ret, state;
1370+
struct mv88e6xxx_atu_entry next;
1371+
u16 fid;
1372+
int ret;
12701373

1271-
ret = _mv88e6xxx_atu_wait(ds);
1272-
if (ret < 0)
1273-
return ret;
1374+
mutex_lock(&ps->smi_mutex);
12741375

1275-
ret = __mv88e6xxx_write_addr(ds, addr);
1376+
ret = _mv88e6xxx_port_vid_to_fid(ds, port, *vid);
12761377
if (ret < 0)
1277-
return ret;
1378+
goto unlock;
1379+
fid = ret;
12781380

12791381
do {
1280-
ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
1281-
if (ret < 0)
1282-
return ret;
1382+
if (is_broadcast_ether_addr(addr)) {
1383+
ret = -ENOENT;
1384+
goto unlock;
1385+
}
12831386

1284-
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
1387+
ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next);
12851388
if (ret < 0)
1286-
return ret;
1287-
state = ret & GLOBAL_ATU_DATA_STATE_MASK;
1288-
if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
1289-
return -ENOENT;
1290-
} while (!(((ret >> 4) & 0xff) & (1 << port)));
1389+
goto unlock;
12911390

1292-
ret = __mv88e6xxx_read_addr(ds, addr);
1293-
if (ret < 0)
1294-
return ret;
1391+
ether_addr_copy(addr, next.mac);
12951392

1296-
*is_static = state == (is_multicast_ether_addr(addr) ?
1297-
GLOBAL_ATU_DATA_STATE_MC_STATIC :
1298-
GLOBAL_ATU_DATA_STATE_UC_STATIC);
1299-
1300-
return 0;
1301-
}
1302-
1303-
/* get next entry for port */
1304-
int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
1305-
unsigned char *addr, bool *is_static)
1306-
{
1307-
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1308-
int ret;
1393+
if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
1394+
continue;
1395+
} while (next.trunk || (next.portv_trunkid & BIT(port)) == 0);
13091396

1310-
mutex_lock(&ps->smi_mutex);
1311-
ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static);
1397+
*is_static = next.state == (is_multicast_ether_addr(addr) ?
1398+
GLOBAL_ATU_DATA_STATE_MC_STATIC :
1399+
GLOBAL_ATU_DATA_STATE_UC_STATIC);
1400+
unlock:
13121401
mutex_unlock(&ps->smi_mutex);
13131402

13141403
return ret;
@@ -1552,9 +1641,9 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
15521641
* ports, and allow each of the 'real' ports to only talk to
15531642
* the upstream port.
15541643
*/
1555-
fid = __ffs(ps->fid_mask);
1644+
fid = port + 1;
15561645
ps->fid[port] = fid;
1557-
ps->fid_mask &= ~(1 << fid);
1646+
set_bit(fid, ps->fid_bitmap);
15581647

15591648
if (!dsa_is_cpu_port(ds, port))
15601649
ps->bridge_mask[fid] = 1 << port;
@@ -1651,7 +1740,7 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
16511740
unsigned char addr[6];
16521741
int ret, data, state;
16531742

1654-
ret = __mv88e6xxx_write_addr(ds, bcast);
1743+
ret = _mv88e6xxx_atu_mac_write(ds, bcast);
16551744
if (ret < 0)
16561745
return ret;
16571746

@@ -1666,7 +1755,7 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
16661755
state = data & GLOBAL_ATU_DATA_STATE_MASK;
16671756
if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
16681757
break;
1669-
ret = __mv88e6xxx_read_addr(ds, addr);
1758+
ret = _mv88e6xxx_atu_mac_read(ds, addr);
16701759
if (ret < 0)
16711760
return ret;
16721761
mv88e6xxx_atu_show_entry(s, dbnum, addr, data);
@@ -1853,8 +1942,6 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds)
18531942

18541943
ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;
18551944

1856-
ps->fid_mask = (1 << DSA_MAX_PORTS) - 1;
1857-
18581945
INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work);
18591946

18601947
name = kasprintf(GFP_KERNEL, "dsa%d", ds->index);

0 commit comments

Comments
 (0)