]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: dsa: lantiq_gswip: support enable/disable learning
authorDaniel Golle <daniel@makrotopia.org>
Mon, 3 Nov 2025 12:18:49 +0000 (12:18 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 6 Nov 2025 22:16:16 +0000 (14:16 -0800)
Switch API 2.2 or later supports enabling or disabling learning on each
port. Implement support for BR_LEARNING bridge flag and announce support
for BR_LEARNING on GSWIP 2.2 or later.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/0aa4621e01c998378ad5812464bc17d23aa3bf62.1762170107.git.daniel@makrotopia.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/lantiq/lantiq_gswip.h
drivers/net/dsa/lantiq/lantiq_gswip_common.c

index d86290db19b41b575f03df999ce8da1530431464..fb7d2c02bde90e3ec539b63c5cfff1a748c67573 100644 (file)
 #define  GSWIP_PCE_PCTRL_0_PSTATE_LEARNING     0x3
 #define  GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING   0x7
 #define  GSWIP_PCE_PCTRL_0_PSTATE_MASK GENMASK(2, 0)
+/* Ethernet Switch PCE Port Control Register 3 */
+#define GSWIP_PCE_PCTRL_3p(p)          (0x483 + ((p) * 0xA))
+#define  GSWIP_PCE_PCTRL_3_LNDIS       BIT(15)  /* Learning Disable */
 #define GSWIP_PCE_VCTRL(p)             (0x485 + ((p) * 0xA))
 #define  GSWIP_PCE_VCTRL_UVR           BIT(0)  /* Unknown VLAN Rule */
 #define  GSWIP_PCE_VCTRL_VINR          GENMASK(2, 1) /* VLAN Ingress Tag Rule */
index a0e361622acb0814a586b208123b3d998f9d149b..f130bf6642a7b313a26dd74bac5c8ad7324c0493 100644 (file)
@@ -403,6 +403,47 @@ static int gswip_add_single_port_br(struct gswip_priv *priv, int port, bool add)
        return 0;
 }
 
+static int gswip_port_set_learning(struct gswip_priv *priv, int port,
+                                  bool enable)
+{
+       if (!GSWIP_VERSION_GE(priv, GSWIP_VERSION_2_2))
+               return -EOPNOTSUPP;
+
+       /* learning disable bit */
+       return regmap_update_bits(priv->gswip, GSWIP_PCE_PCTRL_3p(port),
+                                 GSWIP_PCE_PCTRL_3_LNDIS,
+                                 enable ? 0 : GSWIP_PCE_PCTRL_3_LNDIS);
+}
+
+static int gswip_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+                                      struct switchdev_brport_flags flags,
+                                      struct netlink_ext_ack *extack)
+{
+       struct gswip_priv *priv = ds->priv;
+       unsigned long supported = 0;
+
+       if (GSWIP_VERSION_GE(priv, GSWIP_VERSION_2_2))
+               supported |= BR_LEARNING;
+
+       if (flags.mask & ~supported)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int gswip_port_bridge_flags(struct dsa_switch *ds, int port,
+                                  struct switchdev_brport_flags flags,
+                                  struct netlink_ext_ack *extack)
+{
+       struct gswip_priv *priv = ds->priv;
+
+       if (flags.mask & BR_LEARNING)
+               return gswip_port_set_learning(priv, port,
+                                              !!(flags.val & BR_LEARNING));
+
+       return 0;
+}
+
 static int gswip_port_setup(struct dsa_switch *ds, int port)
 {
        struct gswip_priv *priv = ds->priv;
@@ -1521,6 +1562,8 @@ static const struct dsa_switch_ops gswip_switch_ops = {
        .port_setup             = gswip_port_setup,
        .port_enable            = gswip_port_enable,
        .port_disable           = gswip_port_disable,
+       .port_pre_bridge_flags  = gswip_port_pre_bridge_flags,
+       .port_bridge_flags      = gswip_port_bridge_flags,
        .port_bridge_join       = gswip_port_bridge_join,
        .port_bridge_leave      = gswip_port_bridge_leave,
        .port_fast_age          = gswip_port_fast_age,