From 56d8bb71a811da7bd1655044b4740d2aacff2f74 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 5 Oct 2021 21:47:02 +0200 Subject: net: dsa: rtl8366rb: Support disabling learning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RTL8366RB hardware supports disabling learning per-port so let's make use of this feature. Rename some unfortunately named registers in the process. Suggested-by: Vladimir Oltean Cc: Alvin Šipraga Cc: Mauri Sandberg Cc: Florian Fainelli Cc: DENG Qingfang Reviewed-by: Vladimir Oltean Signed-off-by: Linus Walleij Signed-off-by: David S. Miller --- drivers/net/dsa/rtl8366rb.c | 50 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c index bb9d017c2f9f..b3056064b937 100644 --- a/drivers/net/dsa/rtl8366rb.c +++ b/drivers/net/dsa/rtl8366rb.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -42,9 +43,12 @@ /* Port Enable Control register */ #define RTL8366RB_PECR 0x0001 -/* Switch Security Control registers */ -#define RTL8366RB_SSCR0 0x0002 -#define RTL8366RB_SSCR1 0x0003 +/* Switch per-port learning disablement register */ +#define RTL8366RB_PORT_LEARNDIS_CTRL 0x0002 + +/* Security control, actually aging register */ +#define RTL8366RB_SECURITY_CTRL 0x0003 + #define RTL8366RB_SSCR2 0x0004 #define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) @@ -927,13 +931,14 @@ static int rtl8366rb_setup(struct dsa_switch *ds) /* layer 2 size, see rtl8366rb_change_mtu() */ rb->max_mtu[i] = 1532; - /* Enable learning for all ports */ - ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0); + /* Disable learning for all ports */ + ret = regmap_write(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, + RTL8366RB_PORT_ALL); if (ret) return ret; /* Enable auto ageing for all ports */ - ret = regmap_write(smi->map, RTL8366RB_SSCR1, 0); + ret = regmap_write(smi->map, RTL8366RB_SECURITY_CTRL, 0); if (ret) return ret; @@ -1272,6 +1277,37 @@ static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, return ret; } +static int +rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + /* We support enabling/disabling learning */ + if (flags.mask & ~(BR_LEARNING)) + return -EINVAL; + + return 0; +} + +static int +rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct realtek_smi *smi = ds->priv; + int ret; + + if (flags.mask & BR_LEARNING) { + ret = regmap_update_bits(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, + BIT(port), + (flags.val & BR_LEARNING) ? 0 : BIT(port)); + if (ret) + return ret; + } + + return 0; +} + static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) { struct realtek_smi *smi = ds->priv; @@ -1682,6 +1718,8 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops = { .port_vlan_del = rtl8366_vlan_del, .port_enable = rtl8366rb_port_enable, .port_disable = rtl8366rb_port_disable, + .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, + .port_bridge_flags = rtl8366rb_port_bridge_flags, .port_change_mtu = rtl8366rb_change_mtu, .port_max_mtu = rtl8366rb_max_mtu, }; -- cgit v1.2.3 From 1fbd19e10b735106fb91d4cb07095bc986a513aa Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 5 Oct 2021 21:47:03 +0200 Subject: net: dsa: rtl8366rb: Support fast aging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements fast aging per-port using the special "security" register, which will flush any learned L2 LUT entries on a port. The vendor API just enabled setting and clearing this bit, so we set it to age out any entries on the port and then we clear it again. Suggested-by: Vladimir Oltean Cc: Mauri Sandberg Cc: DENG Qingfang Cc: Florian Fainelli Reviewed-by: Alvin Šipraga Signed-off-by: Linus Walleij Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/rtl8366rb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c index b3056064b937..c78e4220ddd1 100644 --- a/drivers/net/dsa/rtl8366rb.c +++ b/drivers/net/dsa/rtl8366rb.c @@ -1308,6 +1308,19 @@ rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, return 0; } +static void +rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) +{ + struct realtek_smi *smi = ds->priv; + + /* This will age out any learned L2 entries */ + regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, + BIT(port), BIT(port)); + /* Restore the normal state of things */ + regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, + BIT(port), 0); +} + static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) { struct realtek_smi *smi = ds->priv; @@ -1720,6 +1733,7 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops = { .port_disable = rtl8366rb_port_disable, .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, .port_bridge_flags = rtl8366rb_port_bridge_flags, + .port_fast_age = rtl8366rb_port_fast_age, .port_change_mtu = rtl8366rb_change_mtu, .port_max_mtu = rtl8366rb_max_mtu, }; -- cgit v1.2.3 From e674cfd08537f2692a7d06dcbe4633b07819c92a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 5 Oct 2021 21:47:04 +0200 Subject: net: dsa: rtl8366rb: Support setting STP state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for setting the STP state to the RTL8366RB DSA switch. This rids the following message from the kernel on e.g. OpenWrt: DSA: failed to set STP state 3 (-95) Since the RTL8366RB has one STP state register per FID with two bit per port in each, we simply loop over all the FIDs and set the state on all of them. Cc: Vladimir Oltean Cc: Alvin Šipraga Cc: Mauri Sandberg Cc: DENG Qingfang Signed-off-by: Linus Walleij Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/rtl8366rb.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c index c78e4220ddd1..d2370cda4be0 100644 --- a/drivers/net/dsa/rtl8366rb.c +++ b/drivers/net/dsa/rtl8366rb.c @@ -110,6 +110,18 @@ #define RTL8366RB_POWER_SAVING_REG 0x0021 +/* Spanning tree status (STP) control, two bits per port per FID */ +#define RTL8366RB_STP_STATE_BASE 0x0050 /* 0x0050..0x0057 */ +#define RTL8366RB_STP_STATE_DISABLED 0x0 +#define RTL8366RB_STP_STATE_BLOCKING 0x1 +#define RTL8366RB_STP_STATE_LEARNING 0x2 +#define RTL8366RB_STP_STATE_FORWARDING 0x3 +#define RTL8366RB_STP_MASK GENMASK(1, 0) +#define RTL8366RB_STP_STATE(port, state) \ + ((state) << ((port) * 2)) +#define RTL8366RB_STP_STATE_MASK(port) \ + RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK) + /* CPU port control reg */ #define RTL8368RB_CPU_CTRL_REG 0x0061 #define RTL8368RB_CPU_PORTS_MSK 0x00FF @@ -234,6 +246,7 @@ #define RTL8366RB_NUM_LEDGROUPS 4 #define RTL8366RB_NUM_VIDS 4096 #define RTL8366RB_PRIORITYMAX 7 +#define RTL8366RB_NUM_FIDS 8 #define RTL8366RB_FIDMAX 7 #define RTL8366RB_PORT_1 BIT(0) /* In userspace port 0 */ @@ -1308,6 +1321,40 @@ rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, return 0; } +static void +rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct realtek_smi *smi = ds->priv; + u32 val; + int i; + + switch (state) { + case BR_STATE_DISABLED: + val = RTL8366RB_STP_STATE_DISABLED; + break; + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + val = RTL8366RB_STP_STATE_BLOCKING; + break; + case BR_STATE_LEARNING: + val = RTL8366RB_STP_STATE_LEARNING; + break; + case BR_STATE_FORWARDING: + val = RTL8366RB_STP_STATE_FORWARDING; + break; + default: + dev_err(smi->dev, "unknown bridge state requested\n"); + return; + }; + + /* Set the same status for the port on all the FIDs */ + for (i = 0; i < RTL8366RB_NUM_FIDS; i++) { + regmap_update_bits(smi->map, RTL8366RB_STP_STATE_BASE + i, + RTL8366RB_STP_STATE_MASK(port), + RTL8366RB_STP_STATE(port, val)); + } +} + static void rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) { @@ -1733,6 +1780,7 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops = { .port_disable = rtl8366rb_port_disable, .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, .port_bridge_flags = rtl8366rb_port_bridge_flags, + .port_stp_state_set = rtl8366rb_port_stp_state_set, .port_fast_age = rtl8366rb_port_fast_age, .port_change_mtu = rtl8366rb_change_mtu, .port_max_mtu = rtl8366rb_max_mtu, -- cgit v1.2.3