Skip to content

Commit ff39c2d

Browse files
ffainellidavem330
authored andcommitted
net: dsa: b53: Add bridge support
Add support for HW bridging by tying the ports together in the same port VLAN mask when they belong to the same bridge, and isolating them to be alone with the CPU port when they are not. Propagate STP states from the bridge layer to the switch's HW mapping when requested. Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1da6df8 commit ff39c2d

File tree

3 files changed

+174
-3
lines changed

3 files changed

+174
-3
lines changed

drivers/net/dsa/b53/b53_common.c

Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/platform_data/b53.h>
2828
#include <linux/phy.h>
2929
#include <linux/etherdevice.h>
30+
#include <linux/if_bridge.h>
3031
#include <net/dsa.h>
3132
#include <net/switchdev.h>
3233

@@ -339,12 +340,12 @@ static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100)
339340
return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size);
340341
}
341342

342-
static int b53_flush_arl(struct b53_device *dev)
343+
static int b53_flush_arl(struct b53_device *dev, u8 mask)
343344
{
344345
unsigned int i;
345346

346347
b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
347-
FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC);
348+
FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask);
348349

349350
for (i = 0; i < 10; i++) {
350351
u8 fast_age_ctrl;
@@ -365,14 +366,52 @@ static int b53_flush_arl(struct b53_device *dev)
365366
return 0;
366367
}
367368

369+
static int b53_fast_age_port(struct b53_device *dev, int port)
370+
{
371+
b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_PORT_CTRL, port);
372+
373+
return b53_flush_arl(dev, FAST_AGE_PORT);
374+
}
375+
376+
static void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port)
377+
{
378+
struct b53_device *dev = ds_to_priv(ds);
379+
unsigned int i;
380+
u16 pvlan;
381+
382+
/* Enable the IMP port to be in the same VLAN as the other ports
383+
* on a per-port basis such that we only have Port i and IMP in
384+
* the same VLAN.
385+
*/
386+
b53_for_each_port(dev, i) {
387+
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), &pvlan);
388+
pvlan |= BIT(cpu_port);
389+
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), pvlan);
390+
}
391+
}
392+
368393
static int b53_enable_port(struct dsa_switch *ds, int port,
369394
struct phy_device *phy)
370395
{
371396
struct b53_device *dev = ds_to_priv(ds);
397+
unsigned int cpu_port = dev->cpu_port;
398+
u16 pvlan;
372399

373400
/* Clear the Rx and Tx disable bits and set to no spanning tree */
374401
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0);
375402

403+
/* Set this port, and only this one to be in the default VLAN,
404+
* if member of a bridge, restore its membership prior to
405+
* bringing down this port.
406+
*/
407+
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
408+
pvlan &= ~0x1ff;
409+
pvlan |= BIT(port);
410+
pvlan |= dev->ports[port].vlan_ctl_mask;
411+
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
412+
413+
b53_imp_vlan_setup(ds, cpu_port);
414+
376415
return 0;
377416
}
378417

@@ -482,7 +521,7 @@ static int b53_switch_reset(struct b53_device *dev)
482521

483522
b53_enable_mib(dev);
484523

485-
return b53_flush_arl(dev);
524+
return b53_flush_arl(dev, FAST_AGE_STATIC);
486525
}
487526

488527
static int b53_phy_read16(struct dsa_switch *ds, int addr, int reg)
@@ -1019,6 +1058,120 @@ static int b53_fdb_dump(struct dsa_switch *ds, int port,
10191058
return 0;
10201059
}
10211060

1061+
static int b53_br_join(struct dsa_switch *ds, int port,
1062+
struct net_device *bridge)
1063+
{
1064+
struct b53_device *dev = ds_to_priv(ds);
1065+
u16 pvlan, reg;
1066+
unsigned int i;
1067+
1068+
dev->ports[port].bridge_dev = bridge;
1069+
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
1070+
1071+
b53_for_each_port(dev, i) {
1072+
if (dev->ports[i].bridge_dev != bridge)
1073+
continue;
1074+
1075+
/* Add this local port to the remote port VLAN control
1076+
* membership and update the remote port bitmask
1077+
*/
1078+
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), &reg);
1079+
reg |= BIT(port);
1080+
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), reg);
1081+
dev->ports[i].vlan_ctl_mask = reg;
1082+
1083+
pvlan |= BIT(i);
1084+
}
1085+
1086+
/* Configure the local port VLAN control membership to include
1087+
* remote ports and update the local port bitmask
1088+
*/
1089+
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
1090+
dev->ports[port].vlan_ctl_mask = pvlan;
1091+
1092+
return 0;
1093+
}
1094+
1095+
static void b53_br_leave(struct dsa_switch *ds, int port)
1096+
{
1097+
struct b53_device *dev = ds_to_priv(ds);
1098+
struct net_device *bridge = dev->ports[port].bridge_dev;
1099+
unsigned int i;
1100+
u16 pvlan, reg;
1101+
1102+
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
1103+
1104+
b53_for_each_port(dev, i) {
1105+
/* Don't touch the remaining ports */
1106+
if (dev->ports[i].bridge_dev != bridge)
1107+
continue;
1108+
1109+
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), &reg);
1110+
reg &= ~BIT(port);
1111+
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), reg);
1112+
dev->ports[port].vlan_ctl_mask = reg;
1113+
1114+
/* Prevent self removal to preserve isolation */
1115+
if (port != i)
1116+
pvlan &= ~BIT(i);
1117+
}
1118+
1119+
b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
1120+
dev->ports[port].vlan_ctl_mask = pvlan;
1121+
dev->ports[port].bridge_dev = NULL;
1122+
}
1123+
1124+
static void b53_br_set_stp_state(struct dsa_switch *ds, int port,
1125+
u8 state)
1126+
{
1127+
struct b53_device *dev = ds_to_priv(ds);
1128+
u8 hw_state, cur_hw_state;
1129+
u8 reg;
1130+
1131+
b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg);
1132+
cur_hw_state = reg & PORT_CTRL_STP_STATE_MASK;
1133+
1134+
switch (state) {
1135+
case BR_STATE_DISABLED:
1136+
hw_state = PORT_CTRL_DIS_STATE;
1137+
break;
1138+
case BR_STATE_LISTENING:
1139+
hw_state = PORT_CTRL_LISTEN_STATE;
1140+
break;
1141+
case BR_STATE_LEARNING:
1142+
hw_state = PORT_CTRL_LEARN_STATE;
1143+
break;
1144+
case BR_STATE_FORWARDING:
1145+
hw_state = PORT_CTRL_FWD_STATE;
1146+
break;
1147+
case BR_STATE_BLOCKING:
1148+
hw_state = PORT_CTRL_BLOCK_STATE;
1149+
break;
1150+
default:
1151+
dev_err(ds->dev, "invalid STP state: %d\n", state);
1152+
return;
1153+
}
1154+
1155+
/* Fast-age ARL entries if we are moving a port from Learning or
1156+
* Forwarding (cur_hw_state) state to Disabled, Blocking or Listening
1157+
* state (hw_state)
1158+
*/
1159+
if (cur_hw_state != hw_state) {
1160+
if (cur_hw_state >= PORT_CTRL_LEARN_STATE &&
1161+
hw_state <= PORT_CTRL_LISTEN_STATE) {
1162+
if (b53_fast_age_port(dev, port)) {
1163+
dev_err(ds->dev, "fast ageing failed\n");
1164+
return;
1165+
}
1166+
}
1167+
}
1168+
1169+
b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg);
1170+
reg &= ~PORT_CTRL_STP_STATE_MASK;
1171+
reg |= hw_state;
1172+
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg);
1173+
}
1174+
10221175
static struct dsa_switch_driver b53_switch_ops = {
10231176
.tag_protocol = DSA_TAG_PROTO_NONE,
10241177
.setup = b53_setup,
@@ -1031,6 +1184,9 @@ static struct dsa_switch_driver b53_switch_ops = {
10311184
.adjust_link = b53_adjust_link,
10321185
.port_enable = b53_enable_port,
10331186
.port_disable = b53_disable_port,
1187+
.port_bridge_join = b53_br_join,
1188+
.port_bridge_leave = b53_br_leave,
1189+
.port_stp_state_set = b53_br_set_stp_state,
10341190
.port_fdb_prepare = b53_fdb_prepare,
10351191
.port_fdb_dump = b53_fdb_dump,
10361192
.port_fdb_add = b53_fdb_add,

drivers/net/dsa/b53/b53_priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "b53_regs.h"
2828

2929
struct b53_device;
30+
struct net_device;
3031

3132
struct b53_io_ops {
3233
int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
@@ -64,6 +65,8 @@ enum {
6465
#define B53_N_PORTS_25 6
6566

6667
struct b53_port {
68+
u16 vlan_ctl_mask;
69+
struct net_device *bridge_dev;
6770
};
6871

6972
struct b53_device {

drivers/net/dsa/b53/b53_regs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */
6666
#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */
6767
#define PORT_CTRL_STP_STATE_S 5
68+
#define PORT_CTRL_NO_STP (0 << PORT_CTRL_STP_STATE_S)
69+
#define PORT_CTRL_DIS_STATE (1 << PORT_CTRL_STP_STATE_S)
70+
#define PORT_CTRL_BLOCK_STATE (2 << PORT_CTRL_STP_STATE_S)
71+
#define PORT_CTRL_LISTEN_STATE (3 << PORT_CTRL_STP_STATE_S)
72+
#define PORT_CTRL_LEARN_STATE (4 << PORT_CTRL_STP_STATE_S)
73+
#define PORT_CTRL_FWD_STATE (5 << PORT_CTRL_STP_STATE_S)
6874
#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S)
6975

7076
/* SMP Control Register (8 bit) */
@@ -145,6 +151,12 @@
145151
#define FAST_AGE_MC BIT(5)
146152
#define FAST_AGE_DONE BIT(7)
147153

154+
/* Fast Aging Port Control register (8 bit) */
155+
#define B53_FAST_AGE_PORT_CTRL 0x89
156+
157+
/* Fast Aging VID Control register (16 bit) */
158+
#define B53_FAST_AGE_VID_CTRL 0x8a
159+
148160
/*************************************************************************
149161
* Status Page registers
150162
*************************************************************************/

0 commit comments

Comments
 (0)