Skip to content

Commit dd5a300

Browse files
committed
Merge branch 'dsa-port-fast-ageing'
Vivien Didelot says: ==================== net: dsa: add port fast ageing Today the DSA drivers are in charge of flushing the MAC addresses associated to a port when its STP state changes from Learning or Forwarding, to Disabled or Blocking or Listening. This makes the drivers more complex and hides this generic switch logic. This patchset introduces a new optional port_fast_age operation to dsa_switch_ops, to move this logic to the DSA layer and keep drivers simple. b53 and mv88e6xxx are updated accordingly. ==================== Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
2 parents e397867 + 749efcb commit dd5a300

File tree

4 files changed

+64
-49
lines changed

4 files changed

+64
-49
lines changed

drivers/net/dsa/b53/b53_common.c

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,16 +1402,12 @@ static void b53_br_leave(struct dsa_switch *ds, int port)
14021402
}
14031403
}
14041404

1405-
static void b53_br_set_stp_state(struct dsa_switch *ds, int port,
1406-
u8 state)
1405+
static void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state)
14071406
{
14081407
struct b53_device *dev = ds->priv;
1409-
u8 hw_state, cur_hw_state;
1408+
u8 hw_state;
14101409
u8 reg;
14111410

1412-
b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg);
1413-
cur_hw_state = reg & PORT_CTRL_STP_STATE_MASK;
1414-
14151411
switch (state) {
14161412
case BR_STATE_DISABLED:
14171413
hw_state = PORT_CTRL_DIS_STATE;
@@ -1433,26 +1429,20 @@ static void b53_br_set_stp_state(struct dsa_switch *ds, int port,
14331429
return;
14341430
}
14351431

1436-
/* Fast-age ARL entries if we are moving a port from Learning or
1437-
* Forwarding (cur_hw_state) state to Disabled, Blocking or Listening
1438-
* state (hw_state)
1439-
*/
1440-
if (cur_hw_state != hw_state) {
1441-
if (cur_hw_state >= PORT_CTRL_LEARN_STATE &&
1442-
hw_state <= PORT_CTRL_LISTEN_STATE) {
1443-
if (b53_fast_age_port(dev, port)) {
1444-
dev_err(ds->dev, "fast ageing failed\n");
1445-
return;
1446-
}
1447-
}
1448-
}
1449-
14501432
b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg);
14511433
reg &= ~PORT_CTRL_STP_STATE_MASK;
14521434
reg |= hw_state;
14531435
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg);
14541436
}
14551437

1438+
static void b53_br_fast_age(struct dsa_switch *ds, int port)
1439+
{
1440+
struct b53_device *dev = ds->priv;
1441+
1442+
if (b53_fast_age_port(dev, port))
1443+
dev_err(ds->dev, "fast ageing failed\n");
1444+
}
1445+
14561446
static enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds)
14571447
{
14581448
return DSA_TAG_PROTO_NONE;
@@ -1472,6 +1462,7 @@ static struct dsa_switch_ops b53_switch_ops = {
14721462
.port_bridge_join = b53_br_join,
14731463
.port_bridge_leave = b53_br_leave,
14741464
.port_stp_state_set = b53_br_set_stp_state,
1465+
.port_fast_age = b53_br_fast_age,
14751466
.port_vlan_filtering = b53_vlan_filtering,
14761467
.port_vlan_prepare = b53_vlan_prepare,
14771468
.port_vlan_add = b53_vlan_add,

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,31 +1133,18 @@ static int _mv88e6xxx_port_state(struct mv88e6xxx_chip *chip, int port,
11331133

11341134
oldstate = reg & PORT_CONTROL_STATE_MASK;
11351135

1136-
if (oldstate != state) {
1137-
/* Flush forwarding database if we're moving a port
1138-
* from Learning or Forwarding state to Disabled or
1139-
* Blocking or Listening state.
1140-
*/
1141-
if ((oldstate == PORT_CONTROL_STATE_LEARNING ||
1142-
oldstate == PORT_CONTROL_STATE_FORWARDING) &&
1143-
(state == PORT_CONTROL_STATE_DISABLED ||
1144-
state == PORT_CONTROL_STATE_BLOCKING)) {
1145-
err = _mv88e6xxx_atu_remove(chip, 0, port, false);
1146-
if (err)
1147-
return err;
1148-
}
1136+
reg &= ~PORT_CONTROL_STATE_MASK;
1137+
reg |= state;
11491138

1150-
reg = (reg & ~PORT_CONTROL_STATE_MASK) | state;
1151-
err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
1152-
if (err)
1153-
return err;
1139+
err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
1140+
if (err)
1141+
return err;
11541142

1155-
netdev_dbg(ds->ports[port].netdev, "PortState %s (was %s)\n",
1156-
mv88e6xxx_port_state_names[state],
1157-
mv88e6xxx_port_state_names[oldstate]);
1158-
}
1143+
netdev_dbg(ds->ports[port].netdev, "PortState %s (was %s)\n",
1144+
mv88e6xxx_port_state_names[state],
1145+
mv88e6xxx_port_state_names[oldstate]);
11591146

1160-
return err;
1147+
return 0;
11611148
}
11621149

11631150
static int _mv88e6xxx_port_based_vlan_map(struct mv88e6xxx_chip *chip, int port)
@@ -1232,6 +1219,19 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
12321219
mv88e6xxx_port_state_names[stp_state]);
12331220
}
12341221

1222+
static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
1223+
{
1224+
struct mv88e6xxx_chip *chip = ds->priv;
1225+
int err;
1226+
1227+
mutex_lock(&chip->reg_lock);
1228+
err = _mv88e6xxx_atu_remove(chip, 0, port, false);
1229+
mutex_unlock(&chip->reg_lock);
1230+
1231+
if (err)
1232+
netdev_err(ds->ports[port].netdev, "failed to flush ATU\n");
1233+
}
1234+
12351235
static int _mv88e6xxx_port_pvid(struct mv88e6xxx_chip *chip, int port,
12361236
u16 *new, u16 *old)
12371237
{
@@ -3684,6 +3684,7 @@ static struct dsa_switch_ops mv88e6xxx_switch_ops = {
36843684
.port_bridge_join = mv88e6xxx_port_bridge_join,
36853685
.port_bridge_leave = mv88e6xxx_port_bridge_leave,
36863686
.port_stp_state_set = mv88e6xxx_port_stp_state_set,
3687+
.port_fast_age = mv88e6xxx_port_fast_age,
36873688
.port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
36883689
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
36893690
.port_vlan_add = mv88e6xxx_port_vlan_add,

include/net/dsa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ struct dsa_port {
143143
struct net_device *netdev;
144144
struct device_node *dn;
145145
unsigned int ageing_time;
146+
u8 stp_state;
146147
};
147148

148149
struct dsa_switch {
@@ -339,6 +340,7 @@ struct dsa_switch_ops {
339340
void (*port_bridge_leave)(struct dsa_switch *ds, int port);
340341
void (*port_stp_state_set)(struct dsa_switch *ds, int port,
341342
u8 state);
343+
void (*port_fast_age)(struct dsa_switch *ds, int port);
342344

343345
/*
344346
* VLAN support

net/dsa/slave.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,30 @@ static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)
6969
return !!p->bridge_dev;
7070
}
7171

72+
static void dsa_port_set_stp_state(struct dsa_switch *ds, int port, u8 state)
73+
{
74+
struct dsa_port *dp = &ds->ports[port];
75+
76+
if (ds->ops->port_stp_state_set)
77+
ds->ops->port_stp_state_set(ds, port, state);
78+
79+
if (ds->ops->port_fast_age) {
80+
/* Fast age FDB entries or flush appropriate forwarding database
81+
* for the given port, if we are moving it from Learning or
82+
* Forwarding state, to Disabled or Blocking or Listening state.
83+
*/
84+
85+
if ((dp->stp_state == BR_STATE_LEARNING ||
86+
dp->stp_state == BR_STATE_FORWARDING) &&
87+
(state == BR_STATE_DISABLED ||
88+
state == BR_STATE_BLOCKING ||
89+
state == BR_STATE_LISTENING))
90+
ds->ops->port_fast_age(ds, port);
91+
}
92+
93+
dp->stp_state = state;
94+
}
95+
7296
static int dsa_slave_open(struct net_device *dev)
7397
{
7498
struct dsa_slave_priv *p = netdev_priv(dev);
@@ -104,8 +128,7 @@ static int dsa_slave_open(struct net_device *dev)
104128
goto clear_promisc;
105129
}
106130

107-
if (ds->ops->port_stp_state_set)
108-
ds->ops->port_stp_state_set(ds, p->port, stp_state);
131+
dsa_port_set_stp_state(ds, p->port, stp_state);
109132

110133
if (p->phy)
111134
phy_start(p->phy);
@@ -147,8 +170,7 @@ static int dsa_slave_close(struct net_device *dev)
147170
if (ds->ops->port_disable)
148171
ds->ops->port_disable(ds, p->port, p->phy);
149172

150-
if (ds->ops->port_stp_state_set)
151-
ds->ops->port_stp_state_set(ds, p->port, BR_STATE_DISABLED);
173+
dsa_port_set_stp_state(ds, p->port, BR_STATE_DISABLED);
152174

153175
return 0;
154176
}
@@ -354,7 +376,7 @@ static int dsa_slave_stp_state_set(struct net_device *dev,
354376
if (switchdev_trans_ph_prepare(trans))
355377
return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
356378

357-
ds->ops->port_stp_state_set(ds, p->port, attr->u.stp_state);
379+
dsa_port_set_stp_state(ds, p->port, attr->u.stp_state);
358380

359381
return 0;
360382
}
@@ -556,8 +578,7 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)
556578
/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
557579
* so allow it to be in BR_STATE_FORWARDING to be kept functional
558580
*/
559-
if (ds->ops->port_stp_state_set)
560-
ds->ops->port_stp_state_set(ds, p->port, BR_STATE_FORWARDING);
581+
dsa_port_set_stp_state(ds, p->port, BR_STATE_FORWARDING);
561582
}
562583

563584
static int dsa_slave_port_attr_get(struct net_device *dev,

0 commit comments

Comments
 (0)