mlxsw: spectrum: Configure learning for VLAN-aware bridge port
authorIdo Schimmel <idosch@mellanox.com>
Wed, 24 Aug 2016 10:00:26 +0000 (12:00 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 24 Aug 2016 16:41:12 +0000 (09:41 -0700)
We are going to prevent the device from generating learning
notifications for a port that was configured with learning disabled.

Since learning configuration is done per {Port, VID} we need to apply
the port's learning configuration for any VID that is added to the
bridge port's VLAN filter list.

When a VID is added to the VLAN filter list of a VLAN-aware bridge port,
configure the {Port, VID} learning status according to the port's
configuration. When the VID is removed, disable learning for the {Port,
VID}.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c

index 1f816890681109e367f8b7a8e5639e35474e2a44..3820317d9a4255ced9cc9619a8608b2c8bd6b619 100644 (file)
@@ -555,8 +555,9 @@ int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port,
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
 }
 
-static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
-                                         u16 vid, bool learn_enable)
+int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                    u16 vid_begin, u16 vid_end,
+                                    bool learn_enable)
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        char *spvmlr_pl;
@@ -565,13 +566,20 @@ static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
        spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL);
        if (!spvmlr_pl)
                return -ENOMEM;
-       mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid,
-                             learn_enable);
+       mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid_begin,
+                             vid_end, learn_enable);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl);
        kfree(spvmlr_pl);
        return err;
 }
 
+static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                         u16 vid, bool learn_enable)
+{
+       return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid,
+                                               learn_enable);
+}
+
 static int
 mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port)
 {
index ab3feb81bd432fe0dae79c41c82e2c2e5789ee1a..01537d3a1c481a552fedd2d33eb703674f0c2a6d 100644 (file)
@@ -558,6 +558,9 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
 int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
                                  enum mlxsw_reg_qeec_hr hr, u8 index,
                                  u8 next_index, u32 maxrate);
+int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                    u16 vid_begin, u16 vid_end,
+                                    bool learn_enable);
 
 #ifdef CONFIG_MLXSW_SPECTRUM_DCB
 
index e5cf8a5da5d05d0244812175b9f7a4a927a4e310..d1b2b11a39361dfb3c7953c4cce2d308d389d263 100644 (file)
@@ -635,6 +635,27 @@ static int __mlxsw_sp_port_vlans_set(struct mlxsw_sp_port *mlxsw_sp_port,
        return 0;
 }
 
+static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                         u16 vid_begin, u16 vid_end,
+                                         bool learn_enable)
+{
+       u16 vid, vid_e;
+       int err;
+
+       for (vid = vid_begin; vid <= vid_end;
+            vid += MLXSW_REG_SPVMLR_REC_MAX_COUNT) {
+               vid_e = min((u16) (vid + MLXSW_REG_SPVMLR_REC_MAX_COUNT - 1),
+                           vid_end);
+
+               err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid,
+                                                      vid_e, learn_enable);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
                                     u16 vid_begin, u16 vid_end,
                                     bool flag_untagged, bool flag_pvid)
@@ -675,6 +696,14 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
                }
        }
 
+       err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end,
+                                            mlxsw_sp_port->learning);
+       if (err) {
+               netdev_err(dev, "Failed to set learning for VIDs %d-%d\n",
+                          vid_begin, vid_end);
+               goto err_port_vid_learning_set;
+       }
+
        /* Changing activity bits only if HW operation succeded */
        for (vid = vid_begin; vid <= vid_end; vid++) {
                set_bit(vid, mlxsw_sp_port->active_vlans);
@@ -697,6 +726,9 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
 err_port_stp_state_set:
        for (vid = vid_begin; vid <= vid_end; vid++)
                clear_bit(vid, mlxsw_sp_port->active_vlans);
+       mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end,
+                                      false);
+err_port_vid_learning_set:
        if (old_pvid != mlxsw_sp_port->pvid)
                mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid);
 err_port_pvid_set:
@@ -1006,6 +1038,9 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
        if (!mlxsw_sp_port->bridged)
                return -EINVAL;
 
+       mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end,
+                                      false);
+
        pvid = mlxsw_sp_port->pvid;
        if (pvid >= vid_begin && pvid <= vid_end)
                mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);