mlxsw: spectrum_switchdev: Attach mid id allocation to HW write
authorNogah Frankel <nogahf@mellanox.com>
Wed, 20 Sep 2017 14:15:06 +0000 (16:15 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 21 Sep 2017 01:03:12 +0000 (18:03 -0700)
Attach mid getting and releasing mid id to the HW write / remove, and add
a flag to indicate whether the mid is in the HW. It is done because mid id
is also HW index to this mid.
This change allows adding in the following patches the ability to have a
mid in the mdb cache but not in the HW. It will be useful for being able
to disable the multicast.
It means that the mdb is being written / delete to the HW in the mid
allocation / removing function, not after them.

Signed-off-by: Nogah Frankel <nogahf@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.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c

index 6fd0afe..e907ec4 100644 (file)
@@ -94,6 +94,7 @@ struct mlxsw_sp_mid {
        unsigned char addr[ETH_ALEN];
        u16 fid;
        u16 mid;
+       bool in_hw;
        unsigned long *ports_in_mid; /* bits array */
 };
 
index 09ead97..9dd05d8 100644 (file)
@@ -1260,6 +1260,42 @@ mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device,
        return NULL;
 }
 
+static bool
+mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
+                           struct mlxsw_sp_mid *mid)
+{
+       u16 mid_idx;
+       int err;
+
+       mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
+                                     MLXSW_SP_MID_MAX);
+       if (mid_idx == MLXSW_SP_MID_MAX)
+               return false;
+
+       mid->mid = mid_idx;
+       err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx);
+       if (err)
+               return false;
+
+       err = mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid_idx,
+                                  true);
+       if (err)
+               return false;
+
+       set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
+       mid->in_hw = true;
+       return true;
+}
+
+static int mlxsw_sp_mc_remove_mdb_entry(struct mlxsw_sp *mlxsw_sp,
+                                       struct mlxsw_sp_mid *mid)
+{
+       clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
+       mid->in_hw = false;
+       return mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid->mid,
+                                   false);
+}
+
 static struct
 mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
                                  struct mlxsw_sp_bridge_device *bridge_device,
@@ -1268,12 +1304,6 @@ mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
 {
        struct mlxsw_sp_mid *mid;
        size_t alloc_size;
-       u16 mid_idx;
-
-       mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
-                                     MLXSW_SP_MID_MAX);
-       if (mid_idx == MLXSW_SP_MID_MAX)
-               return NULL;
 
        mid = kzalloc(sizeof(*mid), GFP_KERNEL);
        if (!mid)
@@ -1281,36 +1311,43 @@ mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
 
        alloc_size = sizeof(unsigned long) *
                     BITS_TO_LONGS(mlxsw_core_max_ports(mlxsw_sp->core));
+
        mid->ports_in_mid = kzalloc(alloc_size, GFP_KERNEL);
-       if (!mid->ports_in_mid) {
-               kfree(mid);
-               return NULL;
-       }
+       if (!mid->ports_in_mid)
+               goto err_ports_in_mid_alloc;
 
-       set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
        ether_addr_copy(mid->addr, addr);
        mid->fid = fid;
-       mid->mid = mid_idx;
+       mid->in_hw = false;
+       if (!mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid))
+               goto err_write_mdb_entry;
+
        list_add_tail(&mid->list, &bridge_device->mids_list);
 
        return mid;
+
+err_write_mdb_entry:
+       kfree(mid->ports_in_mid);
+err_ports_in_mid_alloc:
+       kfree(mid);
+       return NULL;
 }
 
 static int mlxsw_sp_port_remove_from_mid(struct mlxsw_sp_port *mlxsw_sp_port,
                                         struct mlxsw_sp_mid *mid)
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       int err = 0;
 
        clear_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
        if (bitmap_empty(mid->ports_in_mid,
                         mlxsw_core_max_ports(mlxsw_sp->core))) {
+               err = mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
                list_del(&mid->list);
-               clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
                kfree(mid->ports_in_mid);
                kfree(mid);
-               return 1;
        }
-       return 0;
+       return err;
 }
 
 static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -1324,7 +1361,6 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
        struct mlxsw_sp_bridge_device *bridge_device;
        struct mlxsw_sp_bridge_port *bridge_port;
        struct mlxsw_sp_mid *mid;
-       bool is_new_mid = false;
        u16 fid_index;
        int err = 0;
 
@@ -1352,8 +1388,6 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
                        netdev_err(dev, "Unable to allocate MC group\n");
                        return -ENOMEM;
                }
-               is_new_mid = true;
-               mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid->mid);
        }
        set_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
 
@@ -1363,15 +1397,6 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
                goto err_out;
        }
 
-       if (is_new_mid) {
-               err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid_index,
-                                          mid->mid, true);
-               if (err) {
-                       netdev_err(dev, "Unable to set MC SFD\n");
-                       goto err_out;
-               }
-       }
-
        return 0;
 
 err_out:
@@ -1481,12 +1506,9 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
                netdev_err(dev, "Unable to remove port from SMID\n");
 
        mid_idx = mid->mid;
-       if (mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid)) {
-               err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid_index,
-                                          mid_idx, false);
-               if (err)
-                       netdev_err(dev, "Unable to remove MC SFD\n");
-       }
+       err = mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
+       if (err)
+               netdev_err(dev, "Unable to remove MC SFD\n");
 
        return err;
 }