Skip to content

Commit 843eb67

Browse files
committed
Merge branch 'dsa-rzn1-a5psw-stp'
Alexis Lothoré says: ==================== net: dsa: rzn1-a5psw: fix STP states handling This small series fixes STP support and while adding a new function to enable/disable learning, use that to disable learning on standalone ports at switch setup as reported by Vladimir Oltean. This series was initially submitted on net-next by Clement Leger, but some career evolutions has made him hand me over those topics. Also, this new revision is submitted on net instead of net-next for V1 based on Vladimir Oltean's suggestion Changes since v2: - fix commit split by moving A5PSW_MGMT_CFG_ENABLE in relevant commit - fix reverse christmas tree ordering in a5psw_port_stp_state_set Changes since v1: - fix typos in commit messages and doc - re-split STP states handling commit - add Fixes: tag and new Signed-off-by - submit series as fix on net instead of net-next - split learning and blocking setting functions - remove unused define A5PSW_PORT_ENA_TX_SHIFT - add boolean for tx/rx enabled for clarity ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents d80fc10 + ec52b69 commit 843eb67

File tree

2 files changed

+67
-19
lines changed

2 files changed

+67
-19
lines changed

drivers/net/dsa/rzn1_a5psw.c

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,22 @@ static void a5psw_port_mgmtfwd_set(struct a5psw *a5psw, int port, bool enable)
120120
a5psw_port_pattern_set(a5psw, port, A5PSW_PATTERN_MGMTFWD, enable);
121121
}
122122

123+
static void a5psw_port_tx_enable(struct a5psw *a5psw, int port, bool enable)
124+
{
125+
u32 mask = A5PSW_PORT_ENA_TX(port);
126+
u32 reg = enable ? mask : 0;
127+
128+
/* Even though the port TX is disabled through TXENA bit in the
129+
* PORT_ENA register, it can still send BPDUs. This depends on the tag
130+
* configuration added when sending packets from the CPU port to the
131+
* switch port. Indeed, when using forced forwarding without filtering,
132+
* even disabled ports will be able to send packets that are tagged.
133+
* This allows to implement STP support when ports are in a state where
134+
* forwarding traffic should be stopped but BPDUs should still be sent.
135+
*/
136+
a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, mask, reg);
137+
}
138+
123139
static void a5psw_port_enable_set(struct a5psw *a5psw, int port, bool enable)
124140
{
125141
u32 port_ena = 0;
@@ -292,6 +308,22 @@ static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
292308
return 0;
293309
}
294310

311+
static void a5psw_port_learning_set(struct a5psw *a5psw, int port, bool learn)
312+
{
313+
u32 mask = A5PSW_INPUT_LEARN_DIS(port);
314+
u32 reg = !learn ? mask : 0;
315+
316+
a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
317+
}
318+
319+
static void a5psw_port_rx_block_set(struct a5psw *a5psw, int port, bool block)
320+
{
321+
u32 mask = A5PSW_INPUT_LEARN_BLOCK(port);
322+
u32 reg = block ? mask : 0;
323+
324+
a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
325+
}
326+
295327
static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
296328
bool set)
297329
{
@@ -308,6 +340,14 @@ static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
308340
a5psw_reg_writel(a5psw, offsets[i], a5psw->bridged_ports);
309341
}
310342

343+
static void a5psw_port_set_standalone(struct a5psw *a5psw, int port,
344+
bool standalone)
345+
{
346+
a5psw_port_learning_set(a5psw, port, !standalone);
347+
a5psw_flooding_set_resolution(a5psw, port, !standalone);
348+
a5psw_port_mgmtfwd_set(a5psw, port, standalone);
349+
}
350+
311351
static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
312352
struct dsa_bridge bridge,
313353
bool *tx_fwd_offload,
@@ -323,8 +363,7 @@ static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
323363
}
324364

325365
a5psw->br_dev = bridge.dev;
326-
a5psw_flooding_set_resolution(a5psw, port, true);
327-
a5psw_port_mgmtfwd_set(a5psw, port, false);
366+
a5psw_port_set_standalone(a5psw, port, false);
328367

329368
return 0;
330369
}
@@ -334,8 +373,7 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
334373
{
335374
struct a5psw *a5psw = ds->priv;
336375

337-
a5psw_flooding_set_resolution(a5psw, port, false);
338-
a5psw_port_mgmtfwd_set(a5psw, port, true);
376+
a5psw_port_set_standalone(a5psw, port, true);
339377

340378
/* No more ports bridged */
341379
if (a5psw->bridged_ports == BIT(A5PSW_CPU_PORT))
@@ -344,28 +382,35 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
344382

345383
static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
346384
{
347-
u32 mask = A5PSW_INPUT_LEARN_DIS(port) | A5PSW_INPUT_LEARN_BLOCK(port);
385+
bool learning_enabled, rx_enabled, tx_enabled;
348386
struct a5psw *a5psw = ds->priv;
349-
u32 reg = 0;
350387

351388
switch (state) {
352389
case BR_STATE_DISABLED:
353390
case BR_STATE_BLOCKING:
354-
reg |= A5PSW_INPUT_LEARN_DIS(port);
355-
reg |= A5PSW_INPUT_LEARN_BLOCK(port);
356-
break;
357391
case BR_STATE_LISTENING:
358-
reg |= A5PSW_INPUT_LEARN_DIS(port);
392+
rx_enabled = false;
393+
tx_enabled = false;
394+
learning_enabled = false;
359395
break;
360396
case BR_STATE_LEARNING:
361-
reg |= A5PSW_INPUT_LEARN_BLOCK(port);
397+
rx_enabled = false;
398+
tx_enabled = false;
399+
learning_enabled = true;
362400
break;
363401
case BR_STATE_FORWARDING:
364-
default:
402+
rx_enabled = true;
403+
tx_enabled = true;
404+
learning_enabled = true;
365405
break;
406+
default:
407+
dev_err(ds->dev, "invalid STP state: %d\n", state);
408+
return;
366409
}
367410

368-
a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
411+
a5psw_port_learning_set(a5psw, port, learning_enabled);
412+
a5psw_port_rx_block_set(a5psw, port, !rx_enabled);
413+
a5psw_port_tx_enable(a5psw, port, tx_enabled);
369414
}
370415

371416
static void a5psw_port_fast_age(struct dsa_switch *ds, int port)
@@ -673,7 +718,7 @@ static int a5psw_setup(struct dsa_switch *ds)
673718
}
674719

675720
/* Configure management port */
676-
reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_DISCARD;
721+
reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_ENABLE;
677722
a5psw_reg_writel(a5psw, A5PSW_MGMT_CFG, reg);
678723

679724
/* Set pattern 0 to forward all frame to mgmt port */
@@ -722,13 +767,15 @@ static int a5psw_setup(struct dsa_switch *ds)
722767
if (dsa_port_is_unused(dp))
723768
continue;
724769

725-
/* Enable egress flooding for CPU port */
726-
if (dsa_port_is_cpu(dp))
770+
/* Enable egress flooding and learning for CPU port */
771+
if (dsa_port_is_cpu(dp)) {
727772
a5psw_flooding_set_resolution(a5psw, port, true);
773+
a5psw_port_learning_set(a5psw, port, true);
774+
}
728775

729-
/* Enable management forward only for user ports */
776+
/* Enable standalone mode for user ports */
730777
if (dsa_port_is_user(dp))
731-
a5psw_port_mgmtfwd_set(a5psw, port, true);
778+
a5psw_port_set_standalone(a5psw, port, true);
732779
}
733780

734781
return 0;

drivers/net/dsa/rzn1_a5psw.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define A5PSW_PORT_OFFSET(port) (0x400 * (port))
2020

2121
#define A5PSW_PORT_ENA 0x8
22+
#define A5PSW_PORT_ENA_TX(port) BIT(port)
2223
#define A5PSW_PORT_ENA_RX_SHIFT 16
2324
#define A5PSW_PORT_ENA_TX_RX(port) (BIT((port) + A5PSW_PORT_ENA_RX_SHIFT) | \
2425
BIT(port))
@@ -36,7 +37,7 @@
3637
#define A5PSW_INPUT_LEARN_BLOCK(p) BIT(p)
3738

3839
#define A5PSW_MGMT_CFG 0x20
39-
#define A5PSW_MGMT_CFG_DISCARD BIT(7)
40+
#define A5PSW_MGMT_CFG_ENABLE BIT(6)
4041

4142
#define A5PSW_MODE_CFG 0x24
4243
#define A5PSW_MODE_STATS_RESET BIT(31)

0 commit comments

Comments
 (0)