summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/microchip
diff options
context:
space:
mode:
authorHoratiu Vultur <horatiu.vultur@microchip.com>2021-12-22 14:07:59 +0300
committerDavid S. Miller <davem@davemloft.net>2021-12-23 14:19:06 +0300
commit2e49761e4fd156d0be61810ad6958b5a57f7cc9e (patch)
tree71536673bbfacd9a2f78b8d7beb44fe4354875bb /drivers/net/ethernet/microchip
parent963178a06352a059c688eb36f1f8c2f03212b60b (diff)
downloadlinux-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')
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.c7
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.h2
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_regs.h6
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c69
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)