Skip to content

Commit b3612cc

Browse files
oleremkuba-moo
authored andcommitted
net: dsa: microchip: implement multi-bridge support
Current driver version is able to handle only one bridge at time. Configuring two bridges on two different ports would end up shorting this bridges by HW. To reproduce it: ip l a name br0 type bridge ip l a name br1 type bridge ip l s dev br0 up ip l s dev br1 up ip l s lan1 master br0 ip l s dev lan1 up ip l s lan2 master br1 ip l s dev lan2 up Ping on lan1 and get response on lan2, which should not happen. This happened, because current driver version is storing one global "Port VLAN Membership" and applying it to all ports which are members of any bridge. To solve this issue, we need to handle each port separately. This patch is dropping the global port member storage and calculating membership dynamically depending on STP state and bridge participation. Note: STP support was broken before this patch and should be fixed separately. Fixes: c2e8669 ("net: dsa: microchip: break KSZ9477 DSA driver into two files") Signed-off-by: Oleksij Rempel <[email protected]> Reviewed-by: Vladimir Oltean <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 32c5449 commit b3612cc

File tree

4 files changed

+43
-133
lines changed

4 files changed

+43
-133
lines changed

drivers/net/dsa/microchip/ksz8795.c

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,80 +1002,44 @@ static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
10021002
data &= ~PORT_VLAN_MEMBERSHIP;
10031003
data |= (member & dev->port_mask);
10041004
ksz_pwrite8(dev, port, P_MIRROR_CTRL, data);
1005-
dev->ports[port].member = member;
10061005
}
10071006

10081007
static void ksz8_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
10091008
{
10101009
struct ksz_device *dev = ds->priv;
1011-
int forward = dev->member;
10121010
struct ksz_port *p;
1013-
int member = -1;
10141011
u8 data;
10151012

1016-
p = &dev->ports[port];
1017-
10181013
ksz_pread8(dev, port, P_STP_CTRL, &data);
10191014
data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
10201015

10211016
switch (state) {
10221017
case BR_STATE_DISABLED:
10231018
data |= PORT_LEARN_DISABLE;
1024-
if (port < dev->phy_port_cnt)
1025-
member = 0;
10261019
break;
10271020
case BR_STATE_LISTENING:
10281021
data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
1029-
if (port < dev->phy_port_cnt &&
1030-
p->stp_state == BR_STATE_DISABLED)
1031-
member = dev->host_mask | p->vid_member;
10321022
break;
10331023
case BR_STATE_LEARNING:
10341024
data |= PORT_RX_ENABLE;
10351025
break;
10361026
case BR_STATE_FORWARDING:
10371027
data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
1038-
1039-
/* This function is also used internally. */
1040-
if (port == dev->cpu_port)
1041-
break;
1042-
1043-
/* Port is a member of a bridge. */
1044-
if (dev->br_member & BIT(port)) {
1045-
dev->member |= BIT(port);
1046-
member = dev->member;
1047-
} else {
1048-
member = dev->host_mask | p->vid_member;
1049-
}
10501028
break;
10511029
case BR_STATE_BLOCKING:
10521030
data |= PORT_LEARN_DISABLE;
1053-
if (port < dev->phy_port_cnt &&
1054-
p->stp_state == BR_STATE_DISABLED)
1055-
member = dev->host_mask | p->vid_member;
10561031
break;
10571032
default:
10581033
dev_err(ds->dev, "invalid STP state: %d\n", state);
10591034
return;
10601035
}
10611036

10621037
ksz_pwrite8(dev, port, P_STP_CTRL, data);
1038+
1039+
p = &dev->ports[port];
10631040
p->stp_state = state;
1064-
/* Port membership may share register with STP state. */
1065-
if (member >= 0 && member != p->member)
1066-
ksz8_cfg_port_member(dev, port, (u8)member);
1067-
1068-
/* Check if forwarding needs to be updated. */
1069-
if (state != BR_STATE_FORWARDING) {
1070-
if (dev->br_member & BIT(port))
1071-
dev->member &= ~BIT(port);
1072-
}
10731041

1074-
/* When topology has changed the function ksz_update_port_member
1075-
* should be called to modify port forwarding behavior.
1076-
*/
1077-
if (forward != dev->member)
1078-
ksz_update_port_member(dev, port);
1042+
ksz_update_port_member(dev, port);
10791043
}
10801044

10811045
static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
@@ -1341,7 +1305,7 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
13411305

13421306
static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
13431307
{
1344-
struct ksz_port *p = &dev->ports[port];
1308+
struct dsa_switch *ds = dev->ds;
13451309
struct ksz8 *ksz8 = dev->priv;
13461310
const u32 *masks;
13471311
u8 member;
@@ -1368,10 +1332,11 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
13681332
if (!ksz_is_ksz88x3(dev))
13691333
ksz8795_cpu_interface_select(dev, port);
13701334

1371-
member = dev->port_mask;
1335+
member = dsa_user_ports(ds);
13721336
} else {
1373-
member = dev->host_mask | p->vid_member;
1337+
member = BIT(dsa_upstream_port(ds, port));
13741338
}
1339+
13751340
ksz8_cfg_port_member(dev, port, member);
13761341
}
13771342

@@ -1392,20 +1357,13 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)
13921357
ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
13931358

13941359
p = &dev->ports[dev->cpu_port];
1395-
p->vid_member = dev->port_mask;
13961360
p->on = 1;
13971361

13981362
ksz8_port_setup(dev, dev->cpu_port, true);
1399-
dev->member = dev->host_mask;
14001363

14011364
for (i = 0; i < dev->phy_port_cnt; i++) {
14021365
p = &dev->ports[i];
14031366

1404-
/* Initialize to non-zero so that ksz_cfg_port_member() will
1405-
* be called.
1406-
*/
1407-
p->vid_member = BIT(i);
1408-
p->member = dev->port_mask;
14091367
ksz8_port_stp_state_set(ds, i, BR_STATE_DISABLED);
14101368

14111369
/* Last port may be disabled. */

drivers/net/dsa/microchip/ksz9477.c

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ static void ksz9477_cfg_port_member(struct ksz_device *dev, int port,
391391
u8 member)
392392
{
393393
ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member);
394-
dev->ports[port].member = member;
395394
}
396395

397396
static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port,
@@ -400,49 +399,25 @@ static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port,
400399
struct ksz_device *dev = ds->priv;
401400
struct ksz_port *p = &dev->ports[port];
402401
u8 data;
403-
int member = -1;
404-
int forward = dev->member;
405402

406403
ksz_pread8(dev, port, P_STP_CTRL, &data);
407404
data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
408405

409406
switch (state) {
410407
case BR_STATE_DISABLED:
411408
data |= PORT_LEARN_DISABLE;
412-
if (port != dev->cpu_port)
413-
member = 0;
414409
break;
415410
case BR_STATE_LISTENING:
416411
data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
417-
if (port != dev->cpu_port &&
418-
p->stp_state == BR_STATE_DISABLED)
419-
member = dev->host_mask | p->vid_member;
420412
break;
421413
case BR_STATE_LEARNING:
422414
data |= PORT_RX_ENABLE;
423415
break;
424416
case BR_STATE_FORWARDING:
425417
data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
426-
427-
/* This function is also used internally. */
428-
if (port == dev->cpu_port)
429-
break;
430-
431-
member = dev->host_mask | p->vid_member;
432-
mutex_lock(&dev->dev_mutex);
433-
434-
/* Port is a member of a bridge. */
435-
if (dev->br_member & (1 << port)) {
436-
dev->member |= (1 << port);
437-
member = dev->member;
438-
}
439-
mutex_unlock(&dev->dev_mutex);
440418
break;
441419
case BR_STATE_BLOCKING:
442420
data |= PORT_LEARN_DISABLE;
443-
if (port != dev->cpu_port &&
444-
p->stp_state == BR_STATE_DISABLED)
445-
member = dev->host_mask | p->vid_member;
446421
break;
447422
default:
448423
dev_err(ds->dev, "invalid STP state: %d\n", state);
@@ -451,23 +426,8 @@ static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port,
451426

452427
ksz_pwrite8(dev, port, P_STP_CTRL, data);
453428
p->stp_state = state;
454-
mutex_lock(&dev->dev_mutex);
455-
/* Port membership may share register with STP state. */
456-
if (member >= 0 && member != p->member)
457-
ksz9477_cfg_port_member(dev, port, (u8)member);
458-
459-
/* Check if forwarding needs to be updated. */
460-
if (state != BR_STATE_FORWARDING) {
461-
if (dev->br_member & (1 << port))
462-
dev->member &= ~(1 << port);
463-
}
464429

465-
/* When topology has changed the function ksz_update_port_member
466-
* should be called to modify port forwarding behavior.
467-
*/
468-
if (forward != dev->member)
469-
ksz_update_port_member(dev, port);
470-
mutex_unlock(&dev->dev_mutex);
430+
ksz_update_port_member(dev, port);
471431
}
472432

473433
static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
@@ -1168,10 +1128,10 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
11681128

11691129
static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
11701130
{
1171-
u8 data8;
1172-
u8 member;
1173-
u16 data16;
11741131
struct ksz_port *p = &dev->ports[port];
1132+
struct dsa_switch *ds = dev->ds;
1133+
u8 data8, member;
1134+
u16 data16;
11751135

11761136
/* enable tag tail for host port */
11771137
if (cpu_port)
@@ -1250,12 +1210,12 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
12501210
ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8);
12511211
p->phydev.duplex = 1;
12521212
}
1253-
mutex_lock(&dev->dev_mutex);
1213+
12541214
if (cpu_port)
1255-
member = dev->port_mask;
1215+
member = dsa_user_ports(ds);
12561216
else
1257-
member = dev->host_mask | p->vid_member;
1258-
mutex_unlock(&dev->dev_mutex);
1217+
member = BIT(dsa_upstream_port(ds, port));
1218+
12591219
ksz9477_cfg_port_member(dev, port, member);
12601220

12611221
/* clear pending interrupts */
@@ -1276,8 +1236,6 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
12761236
const char *prev_mode;
12771237

12781238
dev->cpu_port = i;
1279-
dev->host_mask = (1 << dev->cpu_port);
1280-
dev->port_mask |= dev->host_mask;
12811239
p = &dev->ports[i];
12821240

12831241
/* Read from XMII register to determine host port
@@ -1312,23 +1270,15 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
13121270

13131271
/* enable cpu port */
13141272
ksz9477_port_setup(dev, i, true);
1315-
p->vid_member = dev->port_mask;
13161273
p->on = 1;
13171274
}
13181275
}
13191276

1320-
dev->member = dev->host_mask;
1321-
13221277
for (i = 0; i < dev->port_cnt; i++) {
13231278
if (i == dev->cpu_port)
13241279
continue;
13251280
p = &dev->ports[i];
13261281

1327-
/* Initialize to non-zero so that ksz_cfg_port_member() will
1328-
* be called.
1329-
*/
1330-
p->vid_member = (1 << i);
1331-
p->member = dev->port_mask;
13321282
ksz9477_port_stp_state_set(ds, i, BR_STATE_DISABLED);
13331283
p->on = 1;
13341284
if (i < dev->phy_port_cnt)

drivers/net/dsa/microchip/ksz_common.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,40 @@
2222

2323
void ksz_update_port_member(struct ksz_device *dev, int port)
2424
{
25-
struct ksz_port *p;
25+
struct ksz_port *p = &dev->ports[port];
26+
struct dsa_switch *ds = dev->ds;
27+
u8 port_member = 0, cpu_port;
28+
const struct dsa_port *dp;
2629
int i;
2730

28-
for (i = 0; i < dev->port_cnt; i++) {
29-
if (i == port || i == dev->cpu_port)
31+
if (!dsa_is_user_port(ds, port))
32+
return;
33+
34+
dp = dsa_to_port(ds, port);
35+
cpu_port = BIT(dsa_upstream_port(ds, port));
36+
37+
for (i = 0; i < ds->num_ports; i++) {
38+
const struct dsa_port *other_dp = dsa_to_port(ds, i);
39+
struct ksz_port *other_p = &dev->ports[i];
40+
u8 val = 0;
41+
42+
if (!dsa_is_user_port(ds, i))
3043
continue;
31-
p = &dev->ports[i];
32-
if (!(dev->member & (1 << i)))
44+
if (port == i)
45+
continue;
46+
if (!dp->bridge_dev || dp->bridge_dev != other_dp->bridge_dev)
3347
continue;
3448

35-
/* Port is a member of the bridge and is forwarding. */
36-
if (p->stp_state == BR_STATE_FORWARDING &&
37-
p->member != dev->member)
38-
dev->dev_ops->cfg_port_member(dev, i, dev->member);
49+
if (other_p->stp_state == BR_STATE_FORWARDING &&
50+
p->stp_state == BR_STATE_FORWARDING) {
51+
val |= BIT(port);
52+
port_member |= BIT(i);
53+
}
54+
55+
dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
3956
}
57+
58+
dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
4059
}
4160
EXPORT_SYMBOL_GPL(ksz_update_port_member);
4261

@@ -175,12 +194,6 @@ EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
175194
int ksz_port_bridge_join(struct dsa_switch *ds, int port,
176195
struct net_device *br)
177196
{
178-
struct ksz_device *dev = ds->priv;
179-
180-
mutex_lock(&dev->dev_mutex);
181-
dev->br_member |= (1 << port);
182-
mutex_unlock(&dev->dev_mutex);
183-
184197
/* port_stp_state_set() will be called after to put the port in
185198
* appropriate state so there is no need to do anything.
186199
*/
@@ -192,13 +205,6 @@ EXPORT_SYMBOL_GPL(ksz_port_bridge_join);
192205
void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
193206
struct net_device *br)
194207
{
195-
struct ksz_device *dev = ds->priv;
196-
197-
mutex_lock(&dev->dev_mutex);
198-
dev->br_member &= ~(1 << port);
199-
dev->member &= ~(1 << port);
200-
mutex_unlock(&dev->dev_mutex);
201-
202208
/* port_stp_state_set() will be called after to put the port in
203209
* forwarding state so there is no need to do anything.
204210
*/

drivers/net/dsa/microchip/ksz_common.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ struct ksz_port_mib {
2525
};
2626

2727
struct ksz_port {
28-
u16 member;
29-
u16 vid_member;
3028
bool remove_tag; /* Remove Tag flag set, for ksz8795 only */
3129
int stp_state;
3230
struct phy_device phydev;
@@ -83,8 +81,6 @@ struct ksz_device {
8381
struct ksz_port *ports;
8482
struct delayed_work mib_read;
8583
unsigned long mib_read_interval;
86-
u16 br_member;
87-
u16 member;
8884
u16 mirror_rx;
8985
u16 mirror_tx;
9086
u32 features; /* chip specific features */

0 commit comments

Comments
 (0)