diff options
author | Horatiu Vultur <horatiu.vultur@microchip.com> | 2021-12-22 14:07:59 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-12-23 14:19:06 +0300 |
commit | 2e49761e4fd156d0be61810ad6958b5a57f7cc9e (patch) | |
tree | 71536673bbfacd9a2f78b8d7beb44fe4354875bb /drivers/net/ethernet/microchip | |
parent | 963178a06352a059c688eb36f1f8c2f03212b60b (diff) | |
download | linux-2e49761e4fd156d0be61810ad6958b5a57f7cc9e.tar.xz |
net: lan966x: Add support for multiple bridge flags
This patch series extends the current supported bridge flags with the
following flags: BR_FLOOD, BR_BCAST_FLOOD and BR_LEARNING.
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/microchip')
4 files changed, 82 insertions, 2 deletions
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index 5b9f004ad902..16f4d8737d7b 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -715,8 +715,10 @@ static void lan966x_init(struct lan966x *lan966x) /* There are 8 priorities */ for (i = 0; i < 8; ++i) lan_rmw(ANA_FLOODING_FLD_MULTICAST_SET(PGID_MC) | + ANA_FLOODING_FLD_UNICAST_SET(PGID_UC) | ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC), ANA_FLOODING_FLD_MULTICAST | + ANA_FLOODING_FLD_UNICAST | ANA_FLOODING_FLD_BROADCAST, lan966x, ANA_FLOODING(i)); @@ -768,6 +770,11 @@ static void lan966x_init(struct lan966x *lan966x) ANA_PGID_PGID, lan966x, ANA_PGID(PGID_MCIPV4)); + /* Unicast to all other ports */ + lan_rmw(GENMASK(lan966x->num_phys_ports - 1, 0), + ANA_PGID_PGID, + lan966x, ANA_PGID(PGID_UC)); + /* Broadcast to the CPU port and to other ports */ lan_rmw(ANA_PGID_PGID_SET(BIT(CPU_PORT) | GENMASK(lan966x->num_phys_ports - 1, 0)), ANA_PGID_PGID, diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index 051182890237..c399b1256edc 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -126,6 +126,8 @@ struct lan966x_port { u16 vid; bool vlan_aware; + bool learn_ena; + struct phylink_config phylink_config; struct phylink_pcs phylink_pcs; struct lan966x_port_config config; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h index 2f2b26b9f8c6..a13c469e139a 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h @@ -91,6 +91,12 @@ enum lan966x_target { /* ANA:ANA:FLOODING */ #define ANA_FLOODING(r) __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 68, r, 8, 4) +#define ANA_FLOODING_FLD_UNICAST GENMASK(17, 12) +#define ANA_FLOODING_FLD_UNICAST_SET(x)\ + FIELD_PREP(ANA_FLOODING_FLD_UNICAST, x) +#define ANA_FLOODING_FLD_UNICAST_GET(x)\ + FIELD_GET(ANA_FLOODING_FLD_UNICAST, x) + #define ANA_FLOODING_FLD_BROADCAST GENMASK(11, 6) #define ANA_FLOODING_FLD_BROADCAST_SET(x)\ FIELD_PREP(ANA_FLOODING_FLD_BROADCAST, x) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c b/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c index 42c3170030d0..deb3dd5be67a 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c @@ -25,18 +25,72 @@ static void lan966x_port_set_mcast_flood(struct lan966x_port *port, port->lan966x, ANA_PGID(PGID_MC)); } +static void lan966x_port_set_ucast_flood(struct lan966x_port *port, + bool enabled) +{ + u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_UC)); + + val = ANA_PGID_PGID_GET(val); + if (enabled) + val |= BIT(port->chip_port); + else + val &= ~BIT(port->chip_port); + + lan_rmw(ANA_PGID_PGID_SET(val), + ANA_PGID_PGID, + port->lan966x, ANA_PGID(PGID_UC)); +} + +static void lan966x_port_set_bcast_flood(struct lan966x_port *port, + bool enabled) +{ + u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_BC)); + + val = ANA_PGID_PGID_GET(val); + if (enabled) + val |= BIT(port->chip_port); + else + val &= ~BIT(port->chip_port); + + lan_rmw(ANA_PGID_PGID_SET(val), + ANA_PGID_PGID, + port->lan966x, ANA_PGID(PGID_BC)); +} + +static void lan966x_port_set_learning(struct lan966x_port *port, bool enabled) +{ + lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled), + ANA_PORT_CFG_LEARN_ENA, + port->lan966x, ANA_PORT_CFG(port->chip_port)); + + port->learn_ena = enabled; +} + static void lan966x_port_bridge_flags(struct lan966x_port *port, struct switchdev_brport_flags flags) { if (flags.mask & BR_MCAST_FLOOD) lan966x_port_set_mcast_flood(port, !!(flags.val & BR_MCAST_FLOOD)); + + if (flags.mask & BR_FLOOD) + lan966x_port_set_ucast_flood(port, + !!(flags.val & BR_FLOOD)); + + if (flags.mask & BR_BCAST_FLOOD) + lan966x_port_set_bcast_flood(port, + !!(flags.val & BR_BCAST_FLOOD)); + + if (flags.mask & BR_LEARNING) + lan966x_port_set_learning(port, + !!(flags.val & BR_LEARNING)); } static int lan966x_port_pre_bridge_flags(struct lan966x_port *port, struct switchdev_brport_flags flags) { - if (flags.mask & ~BR_MCAST_FLOOD) + if (flags.mask & ~(BR_MCAST_FLOOD | BR_FLOOD | BR_BCAST_FLOOD | + BR_LEARNING)) return -EINVAL; return 0; @@ -65,7 +119,8 @@ static void lan966x_port_stp_state_set(struct lan966x_port *port, u8 state) struct lan966x *lan966x = port->lan966x; bool learn_ena = false; - if (state == BR_STATE_FORWARDING || state == BR_STATE_LEARNING) + if ((state == BR_STATE_FORWARDING || state == BR_STATE_LEARNING) && + port->learn_ena) learn_ena = true; if (state == BR_STATE_FORWARDING) @@ -128,6 +183,7 @@ static int lan966x_port_bridge_join(struct lan966x_port *port, struct net_device *bridge, struct netlink_ext_ack *extack) { + struct switchdev_brport_flags flags = {0}; struct lan966x *lan966x = port->lan966x; struct net_device *dev = port->dev; int err; @@ -150,14 +206,23 @@ static int lan966x_port_bridge_join(struct lan966x_port *port, lan966x->bridge_mask |= BIT(port->chip_port); + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + flags.val = flags.mask; + lan966x_port_bridge_flags(port, flags); + return 0; } static void lan966x_port_bridge_leave(struct lan966x_port *port, struct net_device *bridge) { + struct switchdev_brport_flags flags = {0}; struct lan966x *lan966x = port->lan966x; + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + flags.val = flags.mask & ~BR_LEARNING; + lan966x_port_bridge_flags(port, flags); + lan966x->bridge_mask &= ~BIT(port->chip_port); if (!lan966x->bridge_mask) |