net: dsa: remove bitmap operations

The bitmap operations were introduced to simplify the switch drivers
in the future, since most of them could implement the common VLAN and
MDB operations (add, del, dump) with simple functions taking all target
ports at once, and thus limiting the number of hardware accesses.

Programming an MDB or VLAN this way in a single operation would clearly
simplify the drivers a lot but would require a new get-set interface
in DSA. The usage of such bitmap from the stack also raised concerned
in the past, leading to the dynamic allocation of a new ds->_bitmap
member in the dsa_switch structure. So let's get rid of them for now.

This commit nicely wraps the ds->ops->port_{mdb,vlan}_{prepare,add}
switch operations into new dsa_switch_{mdb,vlan}_{prepare,add}
variants not using any bitmap argument anymore.

New dsa_switch_{mdb,vlan}_match helpers have been introduced to make
clear which local port of a switch must be programmed with the target
object. While the targeted user port is an obvious candidate, the
DSA links must also be programmed, as well as the CPU port for VLANs.

While at it, also remove local variables that are only used once.

Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vivien Didelot 2019-08-25 13:25:15 -04:00 committed by David S. Miller
parent 68aaf44595
commit e65d45cc35
3 changed files with 61 additions and 92 deletions

View File

@ -275,9 +275,6 @@ struct dsa_switch {
*/
bool vlan_filtering;
unsigned long *bitmap;
unsigned long _bitmap;
/* Dynamically allocated ports, keep last */
size_t num_ports;
struct dsa_port ports[];

View File

@ -834,20 +834,6 @@ struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
if (!ds)
return NULL;
/* We avoid allocating memory outside dsa_switch
* if it is not needed.
*/
if (n <= sizeof(ds->_bitmap) * 8) {
ds->bitmap = &ds->_bitmap;
} else {
ds->bitmap = devm_kcalloc(dev,
BITS_TO_LONGS(n),
sizeof(unsigned long),
GFP_KERNEL);
if (unlikely(!ds->bitmap))
return NULL;
}
ds->dev = dev;
ds->num_ports = n;

View File

@ -128,57 +128,51 @@ static int dsa_switch_fdb_del(struct dsa_switch *ds,
return ds->ops->port_fdb_del(ds, port, info->addr, info->vid);
}
static int
dsa_switch_mdb_prepare_bitmap(struct dsa_switch *ds,
const struct switchdev_obj_port_mdb *mdb,
const unsigned long *bitmap)
static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port,
struct dsa_notifier_mdb_info *info)
{
if (ds->index == info->sw_index && port == info->port)
return true;
if (dsa_is_dsa_port(ds, port))
return true;
return false;
}
static int dsa_switch_mdb_prepare(struct dsa_switch *ds,
struct dsa_notifier_mdb_info *info)
{
int port, err;
if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
return -EOPNOTSUPP;
for_each_set_bit(port, bitmap, ds->num_ports) {
err = ds->ops->port_mdb_prepare(ds, port, mdb);
if (err)
return err;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_mdb_match(ds, port, info)) {
err = ds->ops->port_mdb_prepare(ds, port, info->mdb);
if (err)
return err;
}
}
return 0;
}
static void dsa_switch_mdb_add_bitmap(struct dsa_switch *ds,
const struct switchdev_obj_port_mdb *mdb,
const unsigned long *bitmap)
{
int port;
if (!ds->ops->port_mdb_add)
return;
for_each_set_bit(port, bitmap, ds->num_ports)
ds->ops->port_mdb_add(ds, port, mdb);
}
static int dsa_switch_mdb_add(struct dsa_switch *ds,
struct dsa_notifier_mdb_info *info)
{
const struct switchdev_obj_port_mdb *mdb = info->mdb;
struct switchdev_trans *trans = info->trans;
int port;
/* Build a mask of Multicast group members */
bitmap_zero(ds->bitmap, ds->num_ports);
if (ds->index == info->sw_index)
set_bit(info->port, ds->bitmap);
if (switchdev_trans_ph_prepare(info->trans))
return dsa_switch_mdb_prepare(ds, info);
if (!ds->ops->port_mdb_add)
return 0;
for (port = 0; port < ds->num_ports; port++)
if (dsa_is_dsa_port(ds, port))
set_bit(port, ds->bitmap);
if (switchdev_trans_ph_prepare(trans))
return dsa_switch_mdb_prepare_bitmap(ds, mdb, ds->bitmap);
dsa_switch_mdb_add_bitmap(ds, mdb, ds->bitmap);
if (dsa_switch_mdb_match(ds, port, info))
ds->ops->port_mdb_add(ds, port, info->mdb);
return 0;
}
@ -186,13 +180,11 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds,
static int dsa_switch_mdb_del(struct dsa_switch *ds,
struct dsa_notifier_mdb_info *info)
{
const struct switchdev_obj_port_mdb *mdb = info->mdb;
if (!ds->ops->port_mdb_del)
return -EOPNOTSUPP;
if (ds->index == info->sw_index)
return ds->ops->port_mdb_del(ds, info->port, mdb);
return ds->ops->port_mdb_del(ds, info->port, info->mdb);
return 0;
}
@ -234,59 +226,55 @@ static int dsa_port_vlan_check(struct dsa_switch *ds, int port,
(void *)vlan);
}
static int
dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds,
const struct switchdev_obj_port_vlan *vlan,
const unsigned long *bitmap)
static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
struct dsa_notifier_vlan_info *info)
{
if (ds->index == info->sw_index && port == info->port)
return true;
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
return true;
return false;
}
static int dsa_switch_vlan_prepare(struct dsa_switch *ds,
struct dsa_notifier_vlan_info *info)
{
int port, err;
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
return -EOPNOTSUPP;
for_each_set_bit(port, bitmap, ds->num_ports) {
err = dsa_port_vlan_check(ds, port, vlan);
if (err)
return err;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_vlan_match(ds, port, info)) {
err = dsa_port_vlan_check(ds, port, info->vlan);
if (err)
return err;
err = ds->ops->port_vlan_prepare(ds, port, vlan);
if (err)
return err;
err = ds->ops->port_vlan_prepare(ds, port, info->vlan);
if (err)
return err;
}
}
return 0;
}
static void
dsa_switch_vlan_add_bitmap(struct dsa_switch *ds,
const struct switchdev_obj_port_vlan *vlan,
const unsigned long *bitmap)
{
int port;
for_each_set_bit(port, bitmap, ds->num_ports)
ds->ops->port_vlan_add(ds, port, vlan);
}
static int dsa_switch_vlan_add(struct dsa_switch *ds,
struct dsa_notifier_vlan_info *info)
{
const struct switchdev_obj_port_vlan *vlan = info->vlan;
struct switchdev_trans *trans = info->trans;
int port;
/* Build a mask of VLAN members */
bitmap_zero(ds->bitmap, ds->num_ports);
if (ds->index == info->sw_index)
set_bit(info->port, ds->bitmap);
if (switchdev_trans_ph_prepare(info->trans))
return dsa_switch_vlan_prepare(ds, info);
if (!ds->ops->port_vlan_add)
return 0;
for (port = 0; port < ds->num_ports; port++)
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
set_bit(port, ds->bitmap);
if (switchdev_trans_ph_prepare(trans))
return dsa_switch_vlan_prepare_bitmap(ds, vlan, ds->bitmap);
dsa_switch_vlan_add_bitmap(ds, vlan, ds->bitmap);
if (dsa_switch_vlan_match(ds, port, info))
ds->ops->port_vlan_add(ds, port, info->vlan);
return 0;
}
@ -294,13 +282,11 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
static int dsa_switch_vlan_del(struct dsa_switch *ds,
struct dsa_notifier_vlan_info *info)
{
const struct switchdev_obj_port_vlan *vlan = info->vlan;
if (!ds->ops->port_vlan_del)
return -EOPNOTSUPP;
if (ds->index == info->sw_index)
return ds->ops->port_vlan_del(ds, info->port, vlan);
return ds->ops->port_vlan_del(ds, info->port, info->vlan);
return 0;
}