Commit fddf42c3 authored by Amit Cohen's avatar Amit Cohen Committed by David S. Miller

mlxsw: spectrum_fid: Maintain {port, VID}->FID mappings

In the unified bridge model, FID classification mappings (e.g., {Port,
VID}->FID) and layer 3 egress VID classification mappings (i.e., {eRIF,
ePort}->VID) will need to be updated when a RIF is configured on top of
a FID. This requires the driver to be aware of all the {Port, VID} pairs
mapped to a FID.

To that end, extend the FID structure with a linked list of {Port, VID}
pairs. Add an entry to the list when a {Port, VID} is mapped to a FID
and remove it upon unmap.

Keep the list sorted by local port as it will be useful for {eRIF,
ePort}->VID mappings via REIV register in the future.
Signed-off-by: default avatarAmit Cohen <amcohen@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 23f94f1b
...@@ -22,6 +22,12 @@ struct mlxsw_sp_fid_core { ...@@ -22,6 +22,12 @@ struct mlxsw_sp_fid_core {
unsigned int *port_fid_mappings; unsigned int *port_fid_mappings;
}; };
struct mlxsw_sp_fid_port_vid {
struct list_head list;
u16 local_port;
u16 vid;
};
struct mlxsw_sp_fid { struct mlxsw_sp_fid {
struct list_head list; struct list_head list;
struct mlxsw_sp_rif *rif; struct mlxsw_sp_rif *rif;
...@@ -38,6 +44,7 @@ struct mlxsw_sp_fid { ...@@ -38,6 +44,7 @@ struct mlxsw_sp_fid {
int nve_ifindex; int nve_ifindex;
u8 vni_valid:1, u8 vni_valid:1,
nve_flood_index_valid:1; nve_flood_index_valid:1;
struct list_head port_vid_list; /* Ordered by local port. */
}; };
struct mlxsw_sp_fid_8021q { struct mlxsw_sp_fid_8021q {
...@@ -567,6 +574,44 @@ static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) ...@@ -567,6 +574,44 @@ static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
} }
} }
static int
mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
u16 vid)
{
struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
if (!port_vid)
return -ENOMEM;
port_vid->local_port = local_port;
port_vid->vid = vid;
list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
if (tmp_port_vid->local_port > local_port)
break;
}
list_add_tail(&port_vid->list, &tmp_port_vid->list);
return 0;
}
static void
mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
u16 vid)
{
struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
if (port_vid->local_port != local_port || port_vid->vid != vid)
continue;
list_del(&port_vid->list);
kfree(port_vid);
return;
}
}
static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid) u16 vid)
...@@ -580,6 +625,11 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, ...@@ -580,6 +625,11 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
if (err) if (err)
return err; return err;
err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
vid);
if (err)
goto err_port_vid_list_add;
if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
if (err) if (err)
...@@ -590,6 +640,8 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, ...@@ -590,6 +640,8 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
err_port_vp_mode_trans: err_port_vp_mode_trans:
mlxsw_sp->fid_core->port_fid_mappings[local_port]--; mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
err_port_vid_list_add:
__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
mlxsw_sp_port->local_port, vid, false); mlxsw_sp_port->local_port, vid, false);
return err; return err;
...@@ -605,6 +657,7 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, ...@@ -605,6 +657,7 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
mlxsw_sp->fid_core->port_fid_mappings[local_port]--; mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
mlxsw_sp_port->local_port, vid, false); mlxsw_sp_port->local_port, vid, false);
} }
...@@ -792,6 +845,11 @@ static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, ...@@ -792,6 +845,11 @@ static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
u16 local_port = mlxsw_sp_port->local_port; u16 local_port = mlxsw_sp_port->local_port;
int err; int err;
err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
vid);
if (err)
return err;
/* We only need to transition the port to virtual mode since /* We only need to transition the port to virtual mode since
* {Port, VID} => FID is done by the firmware upon RIF creation. * {Port, VID} => FID is done by the firmware upon RIF creation.
*/ */
...@@ -805,6 +863,7 @@ static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, ...@@ -805,6 +863,7 @@ static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
err_port_vp_mode_trans: err_port_vp_mode_trans:
mlxsw_sp->fid_core->port_fid_mappings[local_port]--; mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
return err; return err;
} }
...@@ -818,6 +877,7 @@ mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, ...@@ -818,6 +877,7 @@ mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
mlxsw_sp->fid_core->port_fid_mappings[local_port]--; mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
} }
static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni) static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
...@@ -982,6 +1042,8 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, ...@@ -982,6 +1042,8 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
fid = kzalloc(fid_family->fid_size, GFP_KERNEL); fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
if (!fid) if (!fid)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&fid->port_vid_list);
fid->fid_family = fid_family; fid->fid_family = fid_family;
err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
...@@ -1029,6 +1091,7 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) ...@@ -1029,6 +1091,7 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
fid->fid_family->ops->deconfigure(fid); fid->fid_family->ops->deconfigure(fid);
__clear_bit(fid->fid_index - fid_family->start_index, __clear_bit(fid->fid_index - fid_family->start_index,
fid_family->fids_bitmap); fid_family->fids_bitmap);
WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
kfree(fid); kfree(fid);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment