Commit 6c601aac authored by David S. Miller's avatar David S. Miller

Merge branch 'RTL8366RB-enhancements'

Linus Walleij says:

====================
RTL8366RB enhancements

This patch set is a set of reasonably mature improvements
for the RTL8366RB switch, implemented after Vladimir
challenged me to dig deeper into the switch functions.

ChangeLog v4->v5:
- Drop dubious flood control patch: these registers probably
  only deal with rate limiting, we will deal with this
  another time if we can figure it out.

ChangeLog -> v4:
- Rebase earlier circulated patches on the now merged
  VLAN set-up cleanups.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bcb2293d e674cfd0
......@@ -14,6 +14,7 @@
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
......@@ -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)
......@@ -106,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
......@@ -230,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 */
......@@ -927,13 +944,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 +1290,84 @@ 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 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)
{
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;
......@@ -1682,6 +1778,10 @@ 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_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,
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment