Skip to content

Commit cfe908c

Browse files
committed
Merge branch 'sja1105-fast-ageing'
Vladimir Oltean says: ==================== Fast ageing support for SJA1105 DSA driver While adding support for flushing dynamically learned FDB entries in the sja1105 driver, I noticed a few things that could be improved in DSA. Most notably, drivers could omit a fast age when address learning is turned off, which might mean that ports leaving a bridge and becoming standalone could still have FDB entries pointing towards them. Secondly, when DSA fast ages a port after the 'learning' flag has been turned off, the software bridge still has the dynamically learned 'master' FDB entries installed, and those should be deleted too. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 64ec13e + 5126ec7 commit cfe908c

File tree

6 files changed

+108
-32
lines changed

6 files changed

+108
-32
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5797,7 +5797,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
57975797
struct netlink_ext_ack *extack)
57985798
{
57995799
struct mv88e6xxx_chip *chip = ds->priv;
5800-
bool do_fast_age = false;
58015800
int err = -EOPNOTSUPP;
58025801

58035802
mv88e6xxx_reg_lock(chip);
@@ -5809,9 +5808,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
58095808
err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
58105809
if (err)
58115810
goto out;
5812-
5813-
if (!learning)
5814-
do_fast_age = true;
58155811
}
58165812

58175813
if (flags.mask & BR_FLOOD) {
@@ -5843,9 +5839,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
58435839
out:
58445840
mv88e6xxx_reg_unlock(chip);
58455841

5846-
if (do_fast_age)
5847-
mv88e6xxx_port_fast_age(ds, port);
5848-
58495842
return err;
58505843
}
58515844

drivers/net/dsa/sja1105/sja1105.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ struct sja1105_private {
233233
phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
234234
bool fixed_link[SJA1105_MAX_NUM_PORTS];
235235
bool vlan_aware;
236-
unsigned long learn_ena;
237236
unsigned long ucast_egress_floods;
238237
unsigned long bcast_egress_floods;
239238
const struct sja1105_info *info;

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
176176
struct sja1105_mac_config_entry *mac;
177177
struct dsa_switch *ds = priv->ds;
178178
struct sja1105_table *table;
179-
int i;
179+
struct dsa_port *dp;
180180

181181
table = &priv->static_config.tables[BLK_IDX_MAC_CONFIG];
182182

@@ -195,8 +195,11 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
195195

196196
mac = table->entries;
197197

198-
for (i = 0; i < ds->num_ports; i++) {
199-
mac[i] = default_mac;
198+
list_for_each_entry(dp, &ds->dst->ports, list) {
199+
if (dp->ds != ds)
200+
continue;
201+
202+
mac[dp->index] = default_mac;
200203

201204
/* Let sja1105_bridge_stp_state_set() keep address learning
202205
* enabled for the DSA ports. CPU ports use software-assisted
@@ -205,8 +208,8 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
205208
* CPU ports in a cross-chip topology if multiple CPU ports
206209
* exist.
207210
*/
208-
if (dsa_is_dsa_port(ds, i))
209-
priv->learn_ena |= BIT(i);
211+
if (dsa_port_is_dsa(dp))
212+
dp->learning = true;
210213
}
211214

212215
return 0;
@@ -1791,6 +1794,46 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
17911794
return 0;
17921795
}
17931796

1797+
static void sja1105_fast_age(struct dsa_switch *ds, int port)
1798+
{
1799+
struct sja1105_private *priv = ds->priv;
1800+
int i;
1801+
1802+
for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
1803+
struct sja1105_l2_lookup_entry l2_lookup = {0};
1804+
u8 macaddr[ETH_ALEN];
1805+
int rc;
1806+
1807+
rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
1808+
i, &l2_lookup);
1809+
/* No fdb entry at i, not an issue */
1810+
if (rc == -ENOENT)
1811+
continue;
1812+
if (rc) {
1813+
dev_err(ds->dev, "Failed to read FDB: %pe\n",
1814+
ERR_PTR(rc));
1815+
return;
1816+
}
1817+
1818+
if (!(l2_lookup.destports & BIT(port)))
1819+
continue;
1820+
1821+
/* Don't delete static FDB entries */
1822+
if (l2_lookup.lockeds)
1823+
continue;
1824+
1825+
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
1826+
1827+
rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid);
1828+
if (rc) {
1829+
dev_err(ds->dev,
1830+
"Failed to delete FDB entry %pM vid %lld: %pe\n",
1831+
macaddr, l2_lookup.vlanid, ERR_PTR(rc));
1832+
return;
1833+
}
1834+
}
1835+
}
1836+
17941837
static int sja1105_mdb_add(struct dsa_switch *ds, int port,
17951838
const struct switchdev_obj_port_mdb *mdb)
17961839
{
@@ -1899,6 +1942,7 @@ static int sja1105_bridge_member(struct dsa_switch *ds, int port,
18991942
static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
19001943
u8 state)
19011944
{
1945+
struct dsa_port *dp = dsa_to_port(ds, port);
19021946
struct sja1105_private *priv = ds->priv;
19031947
struct sja1105_mac_config_entry *mac;
19041948

@@ -1924,12 +1968,12 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
19241968
case BR_STATE_LEARNING:
19251969
mac[port].ingress = true;
19261970
mac[port].egress = false;
1927-
mac[port].dyn_learn = !!(priv->learn_ena & BIT(port));
1971+
mac[port].dyn_learn = dp->learning;
19281972
break;
19291973
case BR_STATE_FORWARDING:
19301974
mac[port].ingress = true;
19311975
mac[port].egress = true;
1932-
mac[port].dyn_learn = !!(priv->learn_ena & BIT(port));
1976+
mac[port].dyn_learn = dp->learning;
19331977
break;
19341978
default:
19351979
dev_err(ds->dev, "invalid STP state: %d\n", state);
@@ -2891,23 +2935,13 @@ static int sja1105_port_set_learning(struct sja1105_private *priv, int port,
28912935
bool enabled)
28922936
{
28932937
struct sja1105_mac_config_entry *mac;
2894-
int rc;
28952938

28962939
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
28972940

28982941
mac[port].dyn_learn = enabled;
28992942

2900-
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
2901-
&mac[port], true);
2902-
if (rc)
2903-
return rc;
2904-
2905-
if (enabled)
2906-
priv->learn_ena |= BIT(port);
2907-
else
2908-
priv->learn_ena &= ~BIT(port);
2909-
2910-
return 0;
2943+
return sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
2944+
&mac[port], true);
29112945
}
29122946

29132947
static int sja1105_port_ucast_bcast_flood(struct sja1105_private *priv, int to,
@@ -3042,6 +3076,7 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
30423076
.port_fdb_dump = sja1105_fdb_dump,
30433077
.port_fdb_add = sja1105_fdb_add,
30443078
.port_fdb_del = sja1105_fdb_del,
3079+
.port_fast_age = sja1105_fast_age,
30453080
.port_bridge_join = sja1105_bridge_join,
30463081
.port_bridge_leave = sja1105_bridge_leave,
30473082
.port_pre_bridge_flags = sja1105_port_pre_bridge_flags,

include/net/dsa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ struct dsa_port {
254254
struct device_node *dn;
255255
unsigned int ageing_time;
256256
bool vlan_filtering;
257+
/* Managed by DSA on user ports and by drivers on CPU and DSA ports */
258+
bool learning;
257259
u8 stp_state;
258260
struct net_device *bridge_dev;
259261
int bridge_num;

net/dsa/dsa_priv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ int dsa_port_host_mdb_del(const struct dsa_port *dp,
241241
int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
242242
struct switchdev_brport_flags flags,
243243
struct netlink_ext_ack *extack);
244-
int dsa_port_bridge_flags(const struct dsa_port *dp,
244+
int dsa_port_bridge_flags(struct dsa_port *dp,
245245
struct switchdev_brport_flags flags,
246246
struct netlink_ext_ack *extack);
247247
int dsa_port_vlan_add(struct dsa_port *dp,

net/dsa/port.c

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,36 @@ static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v)
3030
return dsa_tree_notify(dp->ds->dst, e, v);
3131
}
3232

33+
static void dsa_port_notify_bridge_fdb_flush(const struct dsa_port *dp)
34+
{
35+
struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
36+
struct switchdev_notifier_fdb_info info = {
37+
/* flush all VLANs */
38+
.vid = 0,
39+
};
40+
41+
/* When the port becomes standalone it has already left the bridge.
42+
* Don't notify the bridge in that case.
43+
*/
44+
if (!brport_dev)
45+
return;
46+
47+
call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE,
48+
brport_dev, &info.info, NULL);
49+
}
50+
51+
static void dsa_port_fast_age(const struct dsa_port *dp)
52+
{
53+
struct dsa_switch *ds = dp->ds;
54+
55+
if (!ds->ops->port_fast_age)
56+
return;
57+
58+
ds->ops->port_fast_age(ds, dp->index);
59+
60+
dsa_port_notify_bridge_fdb_flush(dp);
61+
}
62+
3363
int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
3464
{
3565
struct dsa_switch *ds = dp->ds;
@@ -40,7 +70,7 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
4070

4171
ds->ops->port_stp_state_set(ds, port, state);
4272

43-
if (do_fast_age && ds->ops->port_fast_age) {
73+
if (do_fast_age && dp->learning) {
4474
/* Fast age FDB entries or flush appropriate forwarding database
4575
* for the given port, if we are moving it from Learning or
4676
* Forwarding state, to Disabled or Blocking or Listening state.
@@ -54,7 +84,7 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
5484
(state == BR_STATE_DISABLED ||
5585
state == BR_STATE_BLOCKING ||
5686
state == BR_STATE_LISTENING))
57-
ds->ops->port_fast_age(ds, port);
87+
dsa_port_fast_age(dp);
5888
}
5989

6090
dp->stp_state = state;
@@ -633,16 +663,33 @@ int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
633663
return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack);
634664
}
635665

636-
int dsa_port_bridge_flags(const struct dsa_port *dp,
666+
int dsa_port_bridge_flags(struct dsa_port *dp,
637667
struct switchdev_brport_flags flags,
638668
struct netlink_ext_ack *extack)
639669
{
640670
struct dsa_switch *ds = dp->ds;
671+
int err;
641672

642673
if (!ds->ops->port_bridge_flags)
643674
return -EOPNOTSUPP;
644675

645-
return ds->ops->port_bridge_flags(ds, dp->index, flags, extack);
676+
err = ds->ops->port_bridge_flags(ds, dp->index, flags, extack);
677+
if (err)
678+
return err;
679+
680+
if (flags.mask & BR_LEARNING) {
681+
bool learning = flags.val & BR_LEARNING;
682+
683+
if (learning == dp->learning)
684+
return 0;
685+
686+
if (dp->learning && !learning)
687+
dsa_port_fast_age(dp);
688+
689+
dp->learning = learning;
690+
}
691+
692+
return 0;
646693
}
647694

648695
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,

0 commit comments

Comments
 (0)