Skip to content

Commit 904de98

Browse files
committed
Merge branch 'sha1105-regressions'
Vladimir Oltean says: ==================== Fixes for SJA1105 DSA FDB regressions A report by Yanan Yang has prompted an investigation into the sja1105 driver's behavior w.r.t. multicast. The report states that when adding multicast L2 addresses with "bridge mdb add", only the most recently added address works - the others seem to be overwritten. This is solved by patch 3/5 (with patch 2/5 as a dependency for it). Patches 4/5 and 5/5 fix a series of race conditions introduced during the same patch set as the bug above, namely this one: https://patchwork.kernel.org/project/netdevbpf/cover/[email protected]/ Finally, patch 1/5 fixes an issue found ever since the introduction of multicast forwarding offload in sja1105, which is that the multicast addresses are visible (with the "self" flag) in "bridge fdb show". ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 32530db + 86899e9 commit 904de98

File tree

3 files changed

+97
-67
lines changed

3 files changed

+97
-67
lines changed

drivers/net/dsa/sja1105/sja1105.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ struct sja1105_private {
266266
* the switch doesn't confuse them with one another.
267267
*/
268268
struct mutex mgmt_lock;
269+
/* Serializes accesses to the FDB */
270+
struct mutex fdb_lock;
269271
/* PTP two-step TX timestamp ID, and its serialization lock */
270272
spinlock_t ts_id_lock;
271273
u8 ts_id;

drivers/net/dsa/sja1105/sja1105_dynamic_config.c

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,18 +1175,15 @@ const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = {
11751175

11761176
static int
11771177
sja1105_dynamic_config_poll_valid(struct sja1105_private *priv,
1178-
struct sja1105_dyn_cmd *cmd,
1179-
const struct sja1105_dynamic_table_ops *ops)
1178+
const struct sja1105_dynamic_table_ops *ops,
1179+
void *entry, bool check_valident,
1180+
bool check_errors)
11801181
{
11811182
u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {};
1183+
struct sja1105_dyn_cmd cmd = {};
11821184
int rc;
11831185

1184-
/* We don't _need_ to read the full entry, just the command area which
1185-
* is a fixed SJA1105_SIZE_DYN_CMD. But our cmd_packing() API expects a
1186-
* buffer that contains the full entry too. Additionally, our API
1187-
* doesn't really know how many bytes into the buffer does the command
1188-
* area really begin. So just read back the whole entry.
1189-
*/
1186+
/* Read back the whole entry + command structure. */
11901187
rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf,
11911188
ops->packed_size);
11921189
if (rc)
@@ -1195,11 +1192,25 @@ sja1105_dynamic_config_poll_valid(struct sja1105_private *priv,
11951192
/* Unpack the command structure, and return it to the caller in case it
11961193
* needs to perform further checks on it (VALIDENT).
11971194
*/
1198-
memset(cmd, 0, sizeof(*cmd));
1199-
ops->cmd_packing(packed_buf, cmd, UNPACK);
1195+
ops->cmd_packing(packed_buf, &cmd, UNPACK);
12001196

12011197
/* Hardware hasn't cleared VALID => still working on it */
1202-
return cmd->valid ? -EAGAIN : 0;
1198+
if (cmd.valid)
1199+
return -EAGAIN;
1200+
1201+
if (check_valident && !cmd.valident && !(ops->access & OP_VALID_ANYWAY))
1202+
return -ENOENT;
1203+
1204+
if (check_errors && cmd.errors)
1205+
return -EINVAL;
1206+
1207+
/* Don't dereference possibly NULL pointer - maybe caller
1208+
* only wanted to see whether the entry existed or not.
1209+
*/
1210+
if (entry)
1211+
ops->entry_packing(packed_buf, entry, UNPACK);
1212+
1213+
return 0;
12031214
}
12041215

12051216
/* Poll the dynamic config entry's control area until the hardware has
@@ -1208,16 +1219,19 @@ sja1105_dynamic_config_poll_valid(struct sja1105_private *priv,
12081219
*/
12091220
static int
12101221
sja1105_dynamic_config_wait_complete(struct sja1105_private *priv,
1211-
struct sja1105_dyn_cmd *cmd,
1212-
const struct sja1105_dynamic_table_ops *ops)
1222+
const struct sja1105_dynamic_table_ops *ops,
1223+
void *entry, bool check_valident,
1224+
bool check_errors)
12131225
{
1214-
int rc;
1215-
1216-
return read_poll_timeout(sja1105_dynamic_config_poll_valid,
1217-
rc, rc != -EAGAIN,
1218-
SJA1105_DYNAMIC_CONFIG_SLEEP_US,
1219-
SJA1105_DYNAMIC_CONFIG_TIMEOUT_US,
1220-
false, priv, cmd, ops);
1226+
int err, rc;
1227+
1228+
err = read_poll_timeout(sja1105_dynamic_config_poll_valid,
1229+
rc, rc != -EAGAIN,
1230+
SJA1105_DYNAMIC_CONFIG_SLEEP_US,
1231+
SJA1105_DYNAMIC_CONFIG_TIMEOUT_US,
1232+
false, priv, ops, entry, check_valident,
1233+
check_errors);
1234+
return err < 0 ? err : rc;
12211235
}
12221236

12231237
/* Provides read access to the settings through the dynamic interface
@@ -1286,25 +1300,14 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,
12861300
mutex_lock(&priv->dynamic_config_lock);
12871301
rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
12881302
ops->packed_size);
1289-
if (rc < 0) {
1290-
mutex_unlock(&priv->dynamic_config_lock);
1291-
return rc;
1292-
}
1293-
1294-
rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops);
1295-
mutex_unlock(&priv->dynamic_config_lock);
12961303
if (rc < 0)
1297-
return rc;
1304+
goto out;
12981305

1299-
if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
1300-
return -ENOENT;
1306+
rc = sja1105_dynamic_config_wait_complete(priv, ops, entry, true, false);
1307+
out:
1308+
mutex_unlock(&priv->dynamic_config_lock);
13011309

1302-
/* Don't dereference possibly NULL pointer - maybe caller
1303-
* only wanted to see whether the entry existed or not.
1304-
*/
1305-
if (entry)
1306-
ops->entry_packing(packed_buf, entry, UNPACK);
1307-
return 0;
1310+
return rc;
13081311
}
13091312

13101313
int sja1105_dynamic_config_write(struct sja1105_private *priv,
@@ -1356,22 +1359,14 @@ int sja1105_dynamic_config_write(struct sja1105_private *priv,
13561359
mutex_lock(&priv->dynamic_config_lock);
13571360
rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf,
13581361
ops->packed_size);
1359-
if (rc < 0) {
1360-
mutex_unlock(&priv->dynamic_config_lock);
1361-
return rc;
1362-
}
1363-
1364-
rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops);
1365-
mutex_unlock(&priv->dynamic_config_lock);
13661362
if (rc < 0)
1367-
return rc;
1363+
goto out;
13681364

1369-
cmd = (struct sja1105_dyn_cmd) {0};
1370-
ops->cmd_packing(packed_buf, &cmd, UNPACK);
1371-
if (cmd.errors)
1372-
return -EINVAL;
1365+
rc = sja1105_dynamic_config_wait_complete(priv, ops, NULL, false, true);
1366+
out:
1367+
mutex_unlock(&priv->dynamic_config_lock);
13731368

1374-
return 0;
1369+
return rc;
13751370
}
13761371

13771372
static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,7 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
17981798
struct dsa_db db)
17991799
{
18001800
struct sja1105_private *priv = ds->priv;
1801+
int rc;
18011802

18021803
if (!vid) {
18031804
switch (db.type) {
@@ -1812,12 +1813,16 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
18121813
}
18131814
}
18141815

1815-
return priv->info->fdb_add_cmd(ds, port, addr, vid);
1816+
mutex_lock(&priv->fdb_lock);
1817+
rc = priv->info->fdb_add_cmd(ds, port, addr, vid);
1818+
mutex_unlock(&priv->fdb_lock);
1819+
1820+
return rc;
18161821
}
18171822

1818-
static int sja1105_fdb_del(struct dsa_switch *ds, int port,
1819-
const unsigned char *addr, u16 vid,
1820-
struct dsa_db db)
1823+
static int __sja1105_fdb_del(struct dsa_switch *ds, int port,
1824+
const unsigned char *addr, u16 vid,
1825+
struct dsa_db db)
18211826
{
18221827
struct sja1105_private *priv = ds->priv;
18231828

@@ -1837,6 +1842,20 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port,
18371842
return priv->info->fdb_del_cmd(ds, port, addr, vid);
18381843
}
18391844

1845+
static int sja1105_fdb_del(struct dsa_switch *ds, int port,
1846+
const unsigned char *addr, u16 vid,
1847+
struct dsa_db db)
1848+
{
1849+
struct sja1105_private *priv = ds->priv;
1850+
int rc;
1851+
1852+
mutex_lock(&priv->fdb_lock);
1853+
rc = __sja1105_fdb_del(ds, port, addr, vid, db);
1854+
mutex_unlock(&priv->fdb_lock);
1855+
1856+
return rc;
1857+
}
1858+
18401859
static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
18411860
dsa_fdb_dump_cb_t *cb, void *data)
18421861
{
@@ -1868,13 +1887,14 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
18681887
if (!(l2_lookup.destports & BIT(port)))
18691888
continue;
18701889

1871-
/* We need to hide the FDB entry for unknown multicast */
1872-
if (l2_lookup.macaddr == SJA1105_UNKNOWN_MULTICAST &&
1873-
l2_lookup.mask_macaddr == SJA1105_UNKNOWN_MULTICAST)
1874-
continue;
1875-
18761890
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
18771891

1892+
/* Hardware FDB is shared for fdb and mdb, "bridge fdb show"
1893+
* only wants to see unicast
1894+
*/
1895+
if (is_multicast_ether_addr(macaddr))
1896+
continue;
1897+
18781898
/* We need to hide the dsa_8021q VLANs from the user. */
18791899
if (vid_is_dsa_8021q(l2_lookup.vlanid))
18801900
l2_lookup.vlanid = 0;
@@ -1898,6 +1918,8 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
18981918
};
18991919
int i;
19001920

1921+
mutex_lock(&priv->fdb_lock);
1922+
19011923
for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
19021924
struct sja1105_l2_lookup_entry l2_lookup = {0};
19031925
u8 macaddr[ETH_ALEN];
@@ -1911,7 +1933,7 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
19111933
if (rc) {
19121934
dev_err(ds->dev, "Failed to read FDB: %pe\n",
19131935
ERR_PTR(rc));
1914-
return;
1936+
break;
19151937
}
19161938

19171939
if (!(l2_lookup.destports & BIT(port)))
@@ -1923,14 +1945,16 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
19231945

19241946
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
19251947

1926-
rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db);
1948+
rc = __sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db);
19271949
if (rc) {
19281950
dev_err(ds->dev,
19291951
"Failed to delete FDB entry %pM vid %lld: %pe\n",
19301952
macaddr, l2_lookup.vlanid, ERR_PTR(rc));
1931-
return;
1953+
break;
19321954
}
19331955
}
1956+
1957+
mutex_unlock(&priv->fdb_lock);
19341958
}
19351959

19361960
static int sja1105_mdb_add(struct dsa_switch *ds, int port,
@@ -2273,6 +2297,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
22732297
int rc, i;
22742298
s64 now;
22752299

2300+
mutex_lock(&priv->fdb_lock);
22762301
mutex_lock(&priv->mgmt_lock);
22772302

22782303
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
@@ -2385,6 +2410,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
23852410
goto out;
23862411
out:
23872412
mutex_unlock(&priv->mgmt_lock);
2413+
mutex_unlock(&priv->fdb_lock);
23882414

23892415
return rc;
23902416
}
@@ -2954,7 +2980,9 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to,
29542980
{
29552981
struct sja1105_l2_lookup_entry *l2_lookup;
29562982
struct sja1105_table *table;
2957-
int match;
2983+
int match, rc;
2984+
2985+
mutex_lock(&priv->fdb_lock);
29582986

29592987
table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP];
29602988
l2_lookup = table->entries;
@@ -2967,18 +2995,22 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to,
29672995
if (match == table->entry_count) {
29682996
NL_SET_ERR_MSG_MOD(extack,
29692997
"Could not find FDB entry for unknown multicast");
2970-
return -ENOSPC;
2998+
rc = -ENOSPC;
2999+
goto out;
29713000
}
29723001

29733002
if (flags.val & BR_MCAST_FLOOD)
29743003
l2_lookup[match].destports |= BIT(to);
29753004
else
29763005
l2_lookup[match].destports &= ~BIT(to);
29773006

2978-
return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
2979-
l2_lookup[match].index,
2980-
&l2_lookup[match],
2981-
true);
3007+
rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
3008+
l2_lookup[match].index,
3009+
&l2_lookup[match], true);
3010+
out:
3011+
mutex_unlock(&priv->fdb_lock);
3012+
3013+
return rc;
29823014
}
29833015

29843016
static int sja1105_port_pre_bridge_flags(struct dsa_switch *ds, int port,
@@ -3348,6 +3380,7 @@ static int sja1105_probe(struct spi_device *spi)
33483380
mutex_init(&priv->ptp_data.lock);
33493381
mutex_init(&priv->dynamic_config_lock);
33503382
mutex_init(&priv->mgmt_lock);
3383+
mutex_init(&priv->fdb_lock);
33513384
spin_lock_init(&priv->ts_id_lock);
33523385

33533386
rc = sja1105_parse_dt(priv);

0 commit comments

Comments
 (0)