Merge branch 'for-v5.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/ebieder...
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_switchdev.c
index 23b7e8d..eeccd58 100644 (file)
@@ -98,6 +98,10 @@ struct mlxsw_sp_bridge_ops {
                       const struct mlxsw_sp_fid *fid);
 };
 
+struct mlxsw_sp_switchdev_ops {
+       void (*init)(struct mlxsw_sp *mlxsw_sp);
+};
+
 static int
 mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
                               struct mlxsw_sp_bridge_port *bridge_port,
@@ -2296,7 +2300,7 @@ mlxsw_sp_bridge_8021ad_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
                                                     vid, ETH_P_8021AD, extack);
 }
 
-static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021ad_ops = {
+static const struct mlxsw_sp_bridge_ops mlxsw_sp1_bridge_8021ad_ops = {
        .port_join      = mlxsw_sp_bridge_8021ad_port_join,
        .port_leave     = mlxsw_sp_bridge_8021ad_port_leave,
        .vxlan_join     = mlxsw_sp_bridge_8021ad_vxlan_join,
@@ -2305,6 +2309,53 @@ static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021ad_ops = {
        .fid_vid        = mlxsw_sp_bridge_8021q_fid_vid,
 };
 
+static int
+mlxsw_sp2_bridge_8021ad_port_join(struct mlxsw_sp_bridge_device *bridge_device,
+                                 struct mlxsw_sp_bridge_port *bridge_port,
+                                 struct mlxsw_sp_port *mlxsw_sp_port,
+                                 struct netlink_ext_ack *extack)
+{
+       int err;
+
+       /* The EtherType of decapsulated packets is determined at the egress
+        * port to allow 802.1d and 802.1ad bridges with VXLAN devices to
+        * co-exist.
+        */
+       err = mlxsw_sp_port_egress_ethtype_set(mlxsw_sp_port, ETH_P_8021AD);
+       if (err)
+               return err;
+
+       err = mlxsw_sp_bridge_8021ad_port_join(bridge_device, bridge_port,
+                                              mlxsw_sp_port, extack);
+       if (err)
+               goto err_bridge_8021ad_port_join;
+
+       return 0;
+
+err_bridge_8021ad_port_join:
+       mlxsw_sp_port_egress_ethtype_set(mlxsw_sp_port, ETH_P_8021Q);
+       return err;
+}
+
+static void
+mlxsw_sp2_bridge_8021ad_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
+                                  struct mlxsw_sp_bridge_port *bridge_port,
+                                  struct mlxsw_sp_port *mlxsw_sp_port)
+{
+       mlxsw_sp_bridge_8021ad_port_leave(bridge_device, bridge_port,
+                                         mlxsw_sp_port);
+       mlxsw_sp_port_egress_ethtype_set(mlxsw_sp_port, ETH_P_8021Q);
+}
+
+static const struct mlxsw_sp_bridge_ops mlxsw_sp2_bridge_8021ad_ops = {
+       .port_join      = mlxsw_sp2_bridge_8021ad_port_join,
+       .port_leave     = mlxsw_sp2_bridge_8021ad_port_leave,
+       .vxlan_join     = mlxsw_sp_bridge_8021ad_vxlan_join,
+       .fid_get        = mlxsw_sp_bridge_8021q_fid_get,
+       .fid_lookup     = mlxsw_sp_bridge_8021q_fid_lookup,
+       .fid_vid        = mlxsw_sp_bridge_8021q_fid_vid,
+};
+
 int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
                              struct net_device *brport_dev,
                              struct net_device *br_dev,
@@ -2865,7 +2916,8 @@ mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work *
                return;
 
        if (switchdev_work->event == SWITCHDEV_FDB_ADD_TO_DEVICE &&
-           !switchdev_work->fdb_info.added_by_user)
+           (!switchdev_work->fdb_info.added_by_user ||
+            switchdev_work->fdb_info.is_local))
                return;
 
        if (!netif_running(dev))
@@ -2920,7 +2972,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
        switch (switchdev_work->event) {
        case SWITCHDEV_FDB_ADD_TO_DEVICE:
                fdb_info = &switchdev_work->fdb_info;
-               if (!fdb_info->added_by_user)
+               if (!fdb_info->added_by_user || fdb_info->is_local)
                        break;
                err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);
                if (err)
@@ -3535,6 +3587,24 @@ static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)
        unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
 }
 
+static void mlxsw_sp1_switchdev_init(struct mlxsw_sp *mlxsw_sp)
+{
+       mlxsw_sp->bridge->bridge_8021ad_ops = &mlxsw_sp1_bridge_8021ad_ops;
+}
+
+const struct mlxsw_sp_switchdev_ops mlxsw_sp1_switchdev_ops = {
+       .init   = mlxsw_sp1_switchdev_init,
+};
+
+static void mlxsw_sp2_switchdev_init(struct mlxsw_sp *mlxsw_sp)
+{
+       mlxsw_sp->bridge->bridge_8021ad_ops = &mlxsw_sp2_bridge_8021ad_ops;
+}
+
+const struct mlxsw_sp_switchdev_ops mlxsw_sp2_switchdev_ops = {
+       .init   = mlxsw_sp2_switchdev_init,
+};
+
 int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
 {
        struct mlxsw_sp_bridge *bridge;
@@ -3549,7 +3619,8 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
 
        bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops;
        bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops;
-       bridge->bridge_8021ad_ops = &mlxsw_sp_bridge_8021ad_ops;
+
+       mlxsw_sp->switchdev_ops->init(mlxsw_sp);
 
        return mlxsw_sp_fdb_init(mlxsw_sp);
 }