* [patch net-next 12/18] mlxsw: spectrum_router: Extend the RIF struct
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
Currently, when a Subport RIF is configured, the LAG status and VLAN of
the underlying port are read from the port itself. This is problematic,
as we would like to have common code to configure all types of RIFs,
which aren't necessarily bound to a port.
Instead, embed the RIF in a struct specific to the Subport type, which
contains all the necessary information.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 31 +++++++++++++++++++---
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index e81d45c..28ba5d3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -97,6 +97,16 @@ struct mlxsw_sp_rif {
bool counter_egress_valid;
};
+struct mlxsw_sp_rif_subport {
+ struct mlxsw_sp_rif common;
+ union {
+ u16 system_port;
+ u16 lag_id;
+ };
+ u16 vid;
+ bool lag;
+};
+
static unsigned int *
mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
enum mlxsw_sp_rif_counter_dir dir)
@@ -2965,11 +2975,13 @@ mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev)
static struct mlxsw_sp_rif *
mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
- struct mlxsw_sp_fid *f)
+ struct mlxsw_sp_fid *f, bool is_subport)
{
+ size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) :
+ sizeof(struct mlxsw_sp_rif);
struct mlxsw_sp_rif *rif;
- rif = kzalloc(sizeof(*rif), GFP_KERNEL);
+ rif = kzalloc(size, GFP_KERNEL);
if (!rif)
return NULL;
@@ -3007,6 +3019,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_rif_subport *rif_subport;
u32 tb_id = l3mdev_fib_table(l3_dev);
struct mlxsw_sp_vr *vr;
struct mlxsw_sp_fid *f;
@@ -3029,12 +3042,22 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
goto err_vr_get;
}
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
+ rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true);
if (!rif) {
err = -ENOMEM;
goto err_rif_alloc;
}
+ rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common);
+ rif_subport->vid = mlxsw_sp_port_vlan->vid;
+ if (mlxsw_sp_port->lagged) {
+ rif_subport->lag = true;
+ rif_subport->lag_id = mlxsw_sp_port->lag_id;
+ } else {
+ rif_subport->lag = false;
+ rif_subport->system_port = mlxsw_sp_port->local_port;
+ }
+
err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, true);
if (err)
@@ -3341,7 +3364,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_port_flood_set;
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
+ rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false);
if (!rif) {
err = -ENOMEM;
goto err_rif_alloc;
--
2.9.3
^ permalink raw reply related
* [patch net-next 08/18] mlxsw: spectrum: Don't create FIDs upon creation of VLAN uppers
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
Up until now we used to create FIDs upon the creation of VLAN uppers on
top of the VLAN-aware bridge. This was done so that in case a router
interface (RIF) was configured on top of the bridge, the FID would
already be there.
Instead, simplify the code and only create the FID upon RIF creation.
This is an intermediary step towards the introduction of the common FID
core, in which this code would be completely removed.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 95 +---------------------
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 16 +++-
2 files changed, 13 insertions(+), 98 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 29d9439..f4c31f6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3982,17 +3982,6 @@ int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid)
return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid);
}
-static void mlxsw_sp_master_bridge_gone_sync(struct mlxsw_sp *mlxsw_sp)
-{
- struct mlxsw_sp_fid *f, *tmp;
-
- list_for_each_entry_safe(f, tmp, &mlxsw_sp->fids, list)
- if (--f->ref_count == 0)
- mlxsw_sp_fid_destroy(mlxsw_sp, f);
- else
- WARN_ON_ONCE(1);
-}
-
static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev)
{
@@ -4014,15 +4003,8 @@ static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp)
{
struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp);
- if (--master_bridge->ref_count == 0) {
+ if (--master_bridge->ref_count == 0)
master_bridge->dev = NULL;
- /* It's possible upper VLAN devices are still holding
- * references to underlying FIDs. Drop the reference
- * and release the resources if it was the last one.
- * If it wasn't, then something bad happened.
- */
- mlxsw_sp_master_bridge_gone_sync(mlxsw_sp);
- }
}
static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -4584,79 +4566,6 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,
return 0;
}
-static int mlxsw_sp_master_bridge_vlan_link(struct mlxsw_sp *mlxsw_sp,
- struct net_device *vlan_dev)
-{
- u16 fid = vlan_dev_vlan_id(vlan_dev);
- struct mlxsw_sp_fid *f;
-
- f = mlxsw_sp_fid_find(mlxsw_sp, fid);
- if (!f) {
- f = mlxsw_sp_fid_create(mlxsw_sp, fid);
- if (IS_ERR(f))
- return PTR_ERR(f);
- }
-
- f->ref_count++;
-
- return 0;
-}
-
-static void mlxsw_sp_master_bridge_vlan_unlink(struct mlxsw_sp *mlxsw_sp,
- struct net_device *vlan_dev)
-{
- u16 fid = vlan_dev_vlan_id(vlan_dev);
- struct mlxsw_sp_fid *f;
-
- f = mlxsw_sp_fid_find(mlxsw_sp, fid);
- if (f && f->rif)
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
- if (f && --f->ref_count == 0)
- mlxsw_sp_fid_destroy(mlxsw_sp, f);
-}
-
-static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
- unsigned long event, void *ptr)
-{
- struct netdev_notifier_changeupper_info *info;
- struct net_device *upper_dev;
- struct mlxsw_sp *mlxsw_sp;
- int err = 0;
-
- mlxsw_sp = mlxsw_sp_lower_get(br_dev);
- if (!mlxsw_sp)
- return 0;
-
- info = ptr;
-
- switch (event) {
- case NETDEV_PRECHANGEUPPER:
- upper_dev = info->upper_dev;
- if (!is_vlan_dev(upper_dev))
- return -EINVAL;
- if (is_vlan_dev(upper_dev) &&
- br_dev != mlxsw_sp_master_bridge(mlxsw_sp)->dev)
- return -EINVAL;
- break;
- case NETDEV_CHANGEUPPER:
- upper_dev = info->upper_dev;
- if (is_vlan_dev(upper_dev)) {
- if (info->linking)
- err = mlxsw_sp_master_bridge_vlan_link(mlxsw_sp,
- upper_dev);
- else
- mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp,
- upper_dev);
- } else {
- err = -EINVAL;
- WARN_ON(1);
- }
- break;
- }
-
- return err;
-}
-
static u16 mlxsw_sp_avail_vfid_get(const struct mlxsw_sp *mlxsw_sp)
{
return find_first_zero_bit(mlxsw_sp->vfids.mapped,
@@ -5012,8 +4921,6 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr);
else if (netif_is_lag_master(dev))
err = mlxsw_sp_netdevice_lag_event(dev, event, ptr);
- else if (netif_is_bridge_master(dev))
- err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr);
else if (is_vlan_dev(dev))
err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index ef8e8a1..c582180 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3239,16 +3239,24 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
struct net_device *l3_dev)
{
- u16 fid;
+ struct mlxsw_sp_fid *fid;
+ u16 fid_index;
if (is_vlan_dev(l3_dev))
- fid = vlan_dev_vlan_id(l3_dev);
+ fid_index = vlan_dev_vlan_id(l3_dev);
else if (mlxsw_sp_master_bridge(mlxsw_sp)->dev == l3_dev)
- fid = 1;
+ fid_index = 1;
else
return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev);
- return mlxsw_sp_fid_find(mlxsw_sp, fid);
+ fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index);
+ if (fid)
+ return fid;
+
+ fid = mlxsw_sp_fid_create(mlxsw_sp, fid_index);
+ if (IS_ERR(fid))
+ return NULL;
+ return fid;
}
static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
--
2.9.3
^ permalink raw reply related
* [patch net-next 13/18] mlxsw: spectrum_router: Configure RIFs based on RIF struct
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
All the information necessary for the configuration of RIFs can now be
found in the RIF struct itself, so reduce the arguments list.
This gets us one step closer to the common RIF core.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 56 +++++++++-------------
1 file changed, 23 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 28ba5d3..73cc519 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -2928,22 +2928,20 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
}
static int
-mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
- u16 vr_id, struct net_device *l3_dev,
- u16 rif_index, bool create)
+mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_rif *rif, bool create)
{
- struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- bool lagged = mlxsw_sp_port->lagged;
+ struct mlxsw_sp_rif_subport *rif_subport;
char ritr_pl[MLXSW_REG_RITR_LEN];
- u16 system_port;
- system_port = lagged ? mlxsw_sp_port->lag_id :
- mlxsw_sp_port->local_port;
- mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif_index,
- vr_id, l3_dev->mtu, l3_dev->dev_addr);
- mlxsw_reg_ritr_sp_if_pack(ritr_pl, lagged, system_port,
- mlxsw_sp_port_vlan->vid);
+ rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common);
+ mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF,
+ rif->rif_index, rif->vr_id, rif->dev->mtu,
+ rif->dev->dev_addr);
+ mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
+ rif_subport->lag ? rif_subport->lag_id :
+ rif_subport->system_port,
+ rif_subport->vid);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}
@@ -3058,8 +3056,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
rif_subport->system_port = mlxsw_sp_port->local_port;
}
- err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
- rif_index, true);
+ err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, true);
if (err)
goto err_port_vlan_rif_sp_op;
@@ -3083,8 +3080,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
return rif;
err_rif_fdb_op:
- mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
- rif_index, false);
+ mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false);
err_port_vlan_rif_sp_op:
kfree(rif);
err_rif_alloc:
@@ -3117,8 +3113,7 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
- mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
- rif_index, false);
+ mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false);
kfree(rif);
mlxsw_sp_vr_put(vr);
kfree(f);
@@ -3326,18 +3321,16 @@ static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid)
return MLXSW_REG_RITR_VLAN_IF;
}
-static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, u16 vr_id,
- struct net_device *l3_dev,
- u16 fid, u16 rif,
- bool create)
+static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_rif *rif, bool create)
{
enum mlxsw_reg_ritr_if_type rif_type;
char ritr_pl[MLXSW_REG_RITR_LEN];
- rif_type = mlxsw_sp_rif_type_get(fid);
- mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, vr_id, l3_dev->mtu,
- l3_dev->dev_addr);
- mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, fid);
+ rif_type = mlxsw_sp_rif_type_get(rif->f->fid);
+ mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index,
+ rif->vr_id, rif->dev->mtu, rif->dev->dev_addr);
+ mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, rif->f->fid);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}
@@ -3370,8 +3363,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
goto err_rif_alloc;
}
- err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid,
- rif_index, true);
+ err = mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, true);
if (err)
goto err_rif_bridge_op;
@@ -3388,8 +3380,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
return 0;
err_rif_fdb_op:
- mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index,
- false);
+ mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
err_rif_bridge_op:
kfree(rif);
err_rif_alloc:
@@ -3415,8 +3406,7 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
- mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index,
- false);
+ mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
kfree(rif);
--
2.9.3
^ permalink raw reply related
* [patch net-next 14/18] mlxsw: spectrum_router: Destroy RIF only based on its struct
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
Now that all the information to create a RIF is contained within the RIF
struct itself, we can also simplify the destruction logic.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 73cc519..41c85dc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3091,11 +3091,9 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
}
static void
-mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
+mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif)
{
- struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
struct net_device *l3_dev = rif->dev;
struct mlxsw_sp_fid *f = rif->f;
@@ -3124,11 +3122,12 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
struct net_device *l3_dev)
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u16 vid = mlxsw_sp_port_vlan->vid;
struct mlxsw_sp_rif *rif;
int err;
- rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp_port->mlxsw_sp, l3_dev);
+ rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
if (!rif) {
rif = mlxsw_sp_port_vlan_rif_sp_create(mlxsw_sp_port_vlan,
l3_dev);
@@ -3163,7 +3162,7 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
err_port_vid_learning_set:
if (rif->f->ref_count == 0)
- mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp_port_vlan, rif);
+ mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif);
return err;
}
@@ -3171,6 +3170,7 @@ static void
mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
u16 vid = mlxsw_sp_port_vlan->vid;
@@ -3184,7 +3184,7 @@ mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
if (fid->ref_count == 0)
- mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp_port_vlan, fid->rif);
+ mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, fid->rif);
}
static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
--
2.9.3
^ permalink raw reply related
* [patch net-next 10/18] mlxsw: spectrum_router: Allocate FID prior to RIF configuration
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
The following patches are going to re-arrange the FID and RIF code, so
that when the RIF is configured to the device based on the information
present in the RIF struct (which points to a FID).
For this reason, move the FID allocation to just before the RIF
configuration.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 25 +++++++++++-----------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 7f1054f..c8d136c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3018,26 +3018,26 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
if (rif_index == MLXSW_SP_INVALID_INDEX_RIF)
return ERR_PTR(-ERANGE);
+ fid = mlxsw_sp_rif_sp_to_fid(rif_index);
+ f = mlxsw_sp_rfid_alloc(fid, l3_dev);
+ if (!f)
+ return ERR_PTR(-ENOMEM);
+
vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
- if (IS_ERR(vr))
- return ERR_CAST(vr);
+ if (IS_ERR(vr)) {
+ err = PTR_ERR(vr);
+ goto err_vr_get;
+ }
err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, true);
if (err)
goto err_port_vlan_rif_sp_op;
- fid = mlxsw_sp_rif_sp_to_fid(rif_index);
err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true);
if (err)
goto err_rif_fdb_op;
- f = mlxsw_sp_rfid_alloc(fid, l3_dev);
- if (!f) {
- err = -ENOMEM;
- goto err_rfid_alloc;
- }
-
rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
if (!rif) {
err = -ENOMEM;
@@ -3060,14 +3060,14 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
return rif;
err_rif_alloc:
- kfree(f);
-err_rfid_alloc:
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
err_rif_fdb_op:
mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, false);
err_port_vlan_rif_sp_op:
mlxsw_sp_vr_put(vr);
+err_vr_get:
+ kfree(f);
return ERR_PTR(err);
}
@@ -3094,14 +3094,13 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
kfree(rif);
- kfree(f);
-
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, false);
mlxsw_sp_vr_put(vr);
+ kfree(f);
}
static int
--
2.9.3
^ permalink raw reply related
* [patch net-next 11/18] mlxsw: spectrum_router: Allocate RIF prior to its configuration
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
In the following patches the RIF's configuration function is going to
expect a RIF struct with all the necessary information.
Therefore, allocate the RIF just before it's configured to the device.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 40 ++++++++++------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index c8d136c..e81d45c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3029,6 +3029,12 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
goto err_vr_get;
}
+ rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
+ if (!rif) {
+ err = -ENOMEM;
+ goto err_rif_alloc;
+ }
+
err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, true);
if (err)
@@ -3038,12 +3044,6 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
if (err)
goto err_rif_fdb_op;
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
- if (!rif) {
- err = -ENOMEM;
- goto err_rif_alloc;
- }
-
if (devlink_dpipe_table_counter_enabled(priv_to_devlink(mlxsw_sp->core),
MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) {
err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
@@ -3059,12 +3059,12 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
return rif;
-err_rif_alloc:
- mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
err_rif_fdb_op:
mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, false);
err_port_vlan_rif_sp_op:
+ kfree(rif);
+err_rif_alloc:
mlxsw_sp_vr_put(vr);
err_vr_get:
kfree(f);
@@ -3092,13 +3092,11 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
mlxsw_sp->router->rifs[rif_index] = NULL;
f->rif = NULL;
- kfree(rif);
-
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev,
rif_index, false);
-
+ kfree(rif);
mlxsw_sp_vr_put(vr);
kfree(f);
}
@@ -3343,6 +3341,12 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_port_flood_set;
+ rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
+ if (!rif) {
+ err = -ENOMEM;
+ goto err_rif_alloc;
+ }
+
err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid,
rif_index, true);
if (err)
@@ -3352,12 +3356,6 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_rif_fdb_op;
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
- if (!rif) {
- err = -ENOMEM;
- goto err_rif_alloc;
- }
-
f->rif = rif;
mlxsw_sp->router->rifs[rif_index] = rif;
vr->rif_count++;
@@ -3366,12 +3364,12 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
return 0;
-err_rif_alloc:
- mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
err_rif_fdb_op:
mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index,
false);
err_rif_bridge_op:
+ kfree(rif);
+err_rif_alloc:
mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
err_port_flood_set:
mlxsw_sp_vr_put(vr);
@@ -3392,13 +3390,13 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp->router->rifs[rif_index] = NULL;
f->rif = NULL;
- kfree(rif);
-
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index,
false);
+ kfree(rif);
+
mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
mlxsw_sp_vr_put(vr);
--
2.9.3
^ permalink raw reply related
* [patch net-next 15/18] mlxsw: spectrum_router: Flood packets to router after RIF creation
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
If a packet ingress the router but can't be assigned an ingress RIF,
it's dropped.
Therefore, in the case of RIF configured on top of a bridge, it makes
sense to start flooding broadcast packets to the router only after the
RIF was created.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 41c85dc..32bf658 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3353,10 +3353,6 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
if (IS_ERR(vr))
return PTR_ERR(vr);
- err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true);
- if (err)
- goto err_port_flood_set;
-
rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false);
if (!rif) {
err = -ENOMEM;
@@ -3367,6 +3363,10 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_rif_bridge_op;
+ err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true);
+ if (err)
+ goto err_port_flood_set;
+
err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true);
if (err)
goto err_rif_fdb_op;
@@ -3380,12 +3380,12 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
return 0;
err_rif_fdb_op:
+ mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
+err_port_flood_set:
mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
err_rif_bridge_op:
kfree(rif);
err_rif_alloc:
- mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
-err_port_flood_set:
mlxsw_sp_vr_put(vr);
return err;
}
@@ -3406,12 +3406,12 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
+ mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
+
mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
kfree(rif);
- mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
-
mlxsw_sp_vr_put(vr);
netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index);
--
2.9.3
^ permalink raw reply related
* [patch net-next 16/18] mlxsw: spectrum_router: Determine VR first when creating RIF
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
All RIF types are associated with a virtual router (VR), so determine VR
first when creating a RIF.
That way, we can more easily integrate the common RIF core in the
following patches.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 38 +++++++++++++---------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 32bf658..0c0ec2a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3025,19 +3025,21 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
u16 fid, rif_index;
int err;
+ vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
+ if (IS_ERR(vr))
+ return ERR_CAST(vr);
+
rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp);
- if (rif_index == MLXSW_SP_INVALID_INDEX_RIF)
- return ERR_PTR(-ERANGE);
+ if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) {
+ err = -ERANGE;
+ goto err_avail_rif_get;
+ }
fid = mlxsw_sp_rif_sp_to_fid(rif_index);
f = mlxsw_sp_rfid_alloc(fid, l3_dev);
- if (!f)
- return ERR_PTR(-ENOMEM);
-
- vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
- if (IS_ERR(vr)) {
- err = PTR_ERR(vr);
- goto err_vr_get;
+ if (!f) {
+ err = -ENOMEM;
+ goto err_rfid_alloc;
}
rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true);
@@ -3084,9 +3086,10 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
err_port_vlan_rif_sp_op:
kfree(rif);
err_rif_alloc:
- mlxsw_sp_vr_put(vr);
-err_vr_get:
kfree(f);
+err_rfid_alloc:
+err_avail_rif_get:
+ mlxsw_sp_vr_put(vr);
return ERR_PTR(err);
}
@@ -3113,8 +3116,8 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false);
kfree(rif);
- mlxsw_sp_vr_put(vr);
kfree(f);
+ mlxsw_sp_vr_put(vr);
}
static int
@@ -3345,14 +3348,16 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
u16 rif_index;
int err;
- rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp);
- if (rif_index == MLXSW_SP_INVALID_INDEX_RIF)
- return -ERANGE;
-
vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
if (IS_ERR(vr))
return PTR_ERR(vr);
+ rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp);
+ if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) {
+ err = -ERANGE;
+ goto err_avail_rif_get;
+ }
+
rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false);
if (!rif) {
err = -ENOMEM;
@@ -3386,6 +3391,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
err_rif_bridge_op:
kfree(rif);
err_rif_alloc:
+err_avail_rif_get:
mlxsw_sp_vr_put(vr);
return err;
}
--
2.9.3
^ permalink raw reply related
* [patch net-next 17/18] mlxsw: spectrum: Implement common FID core
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
The device supports three types of FIDs. 802.1Q and 802.1D FIDs for
VLAN-aware and VLAN-unaware bridges (respectively) and rFIDs to
transport packets to the router block.
The different users (e.g., bridge, router, ACLs) of the FIDs
infrastructure need not know about the internal FIDs implementation and
can therefore interact with it using a restricted set of exported
functions.
By encapsulating the entire FID logic and hiding it from the rest of the
driver we get a code base that it much simpler and easier to work with
and extend.
For example, in the current Spectrum ASIC only 802.1D FIDs can be
assigned a VNI, but future ASICs will also support 802.1Q FIDs. With
this patch in place, support for future ASICs can be easily added by
implementing a new FID operations according to their capabilities.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 192 +---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 123 ++-
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 17 +
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 978 +++++++++++++++++++++
.../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 6 +-
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 301 +++----
.../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 419 ++-------
8 files changed, 1278 insertions(+), 761 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index 2fb8c65..62fc42f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -16,7 +16,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_switchdev.o spectrum_router.o \
spectrum_kvdl.o spectrum_acl_tcam.o \
spectrum_acl.o spectrum_flower.o \
- spectrum_cnt.o spectrum_dpipe.o
+ spectrum_cnt.o spectrum_dpipe.o \
+ spectrum_fid.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o
mlxsw_minimal-objs := minimal.o
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 3b6056a..666bcf4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -870,8 +870,7 @@ static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid)
swid);
}
-static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,
- bool enable)
+int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char svpe_pl[MLXSW_REG_SVPE_LEN];
@@ -880,18 +879,6 @@ static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl);
}
-int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port,
- enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid,
- u16 vid)
-{
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- char svfa_pl[MLXSW_REG_SVFA_LEN];
-
- mlxsw_reg_svfa_pack(svfa_pl, mlxsw_sp_port->local_port, mt, valid,
- fid, vid);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
-}
-
int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
bool learn_enable)
{
@@ -1398,75 +1385,6 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
return 0;
}
-int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
- struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
- struct mlxsw_sp_fid *fid;
- u16 vid;
- int err;
-
- list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
- list) {
- fid = mlxsw_sp_port_vlan->fid;
-
- if (!fid || fid->fid >= MLXSW_SP_VFID_BASE)
- continue;
-
- vid = mlxsw_sp_port_vlan->vid;
- err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true,
- fid->fid, vid);
- if (err)
- goto err_port_vid_to_fid_set;
- }
-
- err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
- if (err)
- goto err_port_vp_mode_set;
-
- return 0;
-
-err_port_vp_mode_set:
-err_port_vid_to_fid_set:
- list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
- &mlxsw_sp_port->vlans_list, list) {
- fid = mlxsw_sp_port_vlan->fid;
-
- if (!fid || fid->fid >= MLXSW_SP_VFID_BASE)
- continue;
-
- vid = mlxsw_sp_port_vlan->vid;
- mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid,
- vid);
- }
- return err;
-}
-
-int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
- struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
- int err;
-
- err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
- if (err)
- return err;
-
- list_for_each_entry_reverse(mlxsw_sp_port_vlan,
- &mlxsw_sp_port->vlans_list, list) {
- struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
- u16 vid = mlxsw_sp_port_vlan->vid;
-
- if (!fid || fid->fid >= MLXSW_SP_VFID_BASE)
- continue;
-
- mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid,
- vid);
- }
-
- return 0;
-}
-
static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp;
@@ -1529,10 +1447,12 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
{
+ struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
+
if (mlxsw_sp_port_vlan->bridge_port)
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
- else if (mlxsw_sp_port_vlan->fid)
- mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan);
+ else if (fid)
+ mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
}
@@ -2831,11 +2751,11 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
goto err_port_dcb_init;
}
- err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
+ err = mlxsw_sp_port_fids_init(mlxsw_sp_port);
if (err) {
- dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set non-virtual mode\n",
+ dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n",
mlxsw_sp_port->local_port);
- goto err_port_vp_mode_set;
+ goto err_port_fids_init;
}
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
@@ -2865,7 +2785,8 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
err_port_vlan_get:
-err_port_vp_mode_set:
+ mlxsw_sp_port_fids_fini(mlxsw_sp_port);
+err_port_fids_init:
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
err_port_dcb_init:
err_port_ets_init:
@@ -2919,6 +2840,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_sp->ports[local_port] = NULL;
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
mlxsw_sp_port_vlan_flush(mlxsw_sp_port);
+ mlxsw_sp_port_fids_fini(mlxsw_sp_port);
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
@@ -3478,57 +3400,6 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
}
}
-static int __mlxsw_sp_flood_init(struct mlxsw_core *mlxsw_core,
- enum mlxsw_reg_sfgc_type type,
- enum mlxsw_reg_sfgc_bridge_type bridge_type)
-{
- enum mlxsw_flood_table_type table_type;
- enum mlxsw_sp_flood_table flood_table;
- char sfgc_pl[MLXSW_REG_SFGC_LEN];
-
- if (bridge_type == MLXSW_REG_SFGC_BRIDGE_TYPE_VFID)
- table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID;
- else
- table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
-
- switch (type) {
- case MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST:
- flood_table = MLXSW_SP_FLOOD_TABLE_UC;
- break;
- case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4:
- flood_table = MLXSW_SP_FLOOD_TABLE_MC;
- break;
- default:
- flood_table = MLXSW_SP_FLOOD_TABLE_BC;
- }
-
- mlxsw_reg_sfgc_pack(sfgc_pl, type, bridge_type, table_type,
- flood_table);
- return mlxsw_reg_write(mlxsw_core, MLXSW_REG(sfgc), sfgc_pl);
-}
-
-static int mlxsw_sp_flood_init(struct mlxsw_sp *mlxsw_sp)
-{
- int type, err;
-
- for (type = 0; type < MLXSW_REG_SFGC_TYPE_MAX; type++) {
- if (type == MLXSW_REG_SFGC_TYPE_RESERVED)
- continue;
-
- err = __mlxsw_sp_flood_init(mlxsw_sp->core, type,
- MLXSW_REG_SFGC_BRIDGE_TYPE_VFID);
- if (err)
- return err;
-
- err = __mlxsw_sp_flood_init(mlxsw_sp->core, type,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID);
- if (err)
- return err;
- }
-
- return 0;
-}
-
static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
{
char slcr_pl[MLXSW_REG_SLCR_LEN];
@@ -3576,16 +3447,6 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
}
-static int mlxsw_sp_dummy_fid_init(struct mlxsw_sp *mlxsw_sp)
-{
- return mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, true);
-}
-
-static void mlxsw_sp_dummy_fid_fini(struct mlxsw_sp *mlxsw_sp)
-{
- mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, false);
-}
-
static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info)
{
@@ -3594,8 +3455,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->core = mlxsw_core;
mlxsw_sp->bus_info = mlxsw_bus_info;
- INIT_LIST_HEAD(&mlxsw_sp->fids);
- INIT_LIST_HEAD(&mlxsw_sp->vfids.list);
err = mlxsw_sp_fw_rev_validate(mlxsw_sp);
if (err) {
@@ -3609,16 +3468,16 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
return err;
}
- err = mlxsw_sp_traps_init(mlxsw_sp);
+ err = mlxsw_sp_fids_init(mlxsw_sp);
if (err) {
- dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n");
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");
return err;
}
- err = mlxsw_sp_flood_init(mlxsw_sp);
+ err = mlxsw_sp_traps_init(mlxsw_sp);
if (err) {
- dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize flood tables\n");
- goto err_flood_init;
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n");
+ goto err_traps_init;
}
err = mlxsw_sp_buffers_init(mlxsw_sp);
@@ -3669,12 +3528,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_dpipe_init;
}
- err = mlxsw_sp_dummy_fid_init(mlxsw_sp);
- if (err) {
- dev_err(mlxsw_sp->bus_info->dev, "Failed to init dummy FID\n");
- goto err_dummy_fid_init;
- }
-
err = mlxsw_sp_ports_create(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");
@@ -3684,8 +3537,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
return 0;
err_ports_create:
- mlxsw_sp_dummy_fid_fini(mlxsw_sp);
-err_dummy_fid_init:
mlxsw_sp_dpipe_fini(mlxsw_sp);
err_dpipe_init:
mlxsw_sp_counter_pool_fini(mlxsw_sp);
@@ -3702,8 +3553,9 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
err_lag_init:
mlxsw_sp_buffers_fini(mlxsw_sp);
err_buffers_init:
-err_flood_init:
mlxsw_sp_traps_fini(mlxsw_sp);
+err_traps_init:
+ mlxsw_sp_fids_fini(mlxsw_sp);
return err;
}
@@ -3712,7 +3564,6 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
mlxsw_sp_ports_remove(mlxsw_sp);
- mlxsw_sp_dummy_fid_fini(mlxsw_sp);
mlxsw_sp_dpipe_fini(mlxsw_sp);
mlxsw_sp_counter_pool_fini(mlxsw_sp);
mlxsw_sp_acl_fini(mlxsw_sp);
@@ -3722,8 +3573,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
mlxsw_sp_lag_fini(mlxsw_sp);
mlxsw_sp_buffers_fini(mlxsw_sp);
mlxsw_sp_traps_fini(mlxsw_sp);
- WARN_ON(!list_empty(&mlxsw_sp->vfids.list));
- WARN_ON(!list_empty(&mlxsw_sp->fids));
+ mlxsw_sp_fids_fini(mlxsw_sp);
}
static struct mlxsw_config_profile mlxsw_sp_config_profile = {
@@ -3739,7 +3589,7 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = {
.max_fid_offset_flood_tables = 3,
.fid_offset_flood_table_size = VLAN_N_VID - 1,
.max_fid_flood_tables = 3,
- .fid_flood_table_size = MLXSW_SP_VFID_MAX,
+ .fid_flood_table_size = MLXSW_SP_FID_8021D_MAX,
.used_max_ib_mc = 1,
.max_ib_mc = 0,
.used_max_pkey = 1,
@@ -4009,7 +3859,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
/* Port is no longer usable as a router interface */
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1);
if (mlxsw_sp_port_vlan->fid)
- mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan);
+ mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 8c511ff..c542b33 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -54,12 +54,7 @@
#include "core_acl_flex_keys.h"
#include "core_acl_flex_actions.h"
-#define MLXSW_SP_VFID_BASE VLAN_N_VID
-#define MLXSW_SP_VFID_MAX 1024 /* Bridged VLAN interfaces */
-
-#define MLXSW_SP_DUMMY_FID 15359
-
-#define MLXSW_SP_RFID_BASE 15360
+#define MLXSW_SP_FID_8021D_MAX 1024
#define MLXSW_SP_MID_MAX 7000
@@ -70,7 +65,6 @@
#define MLXSW_SP_KVD_LINEAR_SIZE 65536 /* entries */
#define MLXSW_SP_KVD_GRANULARITY 128
-struct mlxsw_sp_port_vlan;
struct mlxsw_sp_port;
struct mlxsw_sp_rif;
@@ -79,13 +73,19 @@ struct mlxsw_sp_upper {
unsigned int ref_count;
};
-struct mlxsw_sp_fid {
- void (*leave)(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
- struct list_head list;
- unsigned int ref_count;
- struct net_device *dev;
- struct mlxsw_sp_rif *rif;
- u16 fid;
+enum mlxsw_sp_rif_type {
+ MLXSW_SP_RIF_TYPE_SUBPORT,
+ MLXSW_SP_RIF_TYPE_VLAN,
+ MLXSW_SP_RIF_TYPE_FID,
+ MLXSW_SP_RIF_TYPE_MAX,
+};
+
+enum mlxsw_sp_fid_type {
+ MLXSW_SP_FID_TYPE_8021Q,
+ MLXSW_SP_FID_TYPE_8021D,
+ MLXSW_SP_FID_TYPE_RFID,
+ MLXSW_SP_FID_TYPE_DUMMY,
+ MLXSW_SP_FID_TYPE_MAX,
};
struct mlxsw_sp_mid {
@@ -96,21 +96,6 @@ struct mlxsw_sp_mid {
unsigned int ref_count;
};
-static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid)
-{
- return MLXSW_SP_VFID_BASE + vfid;
-}
-
-static inline u16 mlxsw_sp_fid_to_vfid(u16 fid)
-{
- return fid - MLXSW_SP_VFID_BASE;
-}
-
-static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
-{
- return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID;
-}
-
enum mlxsw_sp_span_type {
MLXSW_SP_SPAN_EGRESS,
MLXSW_SP_SPAN_INGRESS
@@ -154,13 +139,9 @@ struct mlxsw_sp_bridge;
struct mlxsw_sp_router;
struct mlxsw_sp_acl;
struct mlxsw_sp_counter_pool;
+struct mlxsw_sp_fid_core;
struct mlxsw_sp {
- struct {
- struct list_head list;
- DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX);
- } vfids;
- struct list_head fids; /* VLAN-aware bridge FIDs */
struct mlxsw_sp_port **ports;
struct mlxsw_core *core;
const struct mlxsw_bus_info *bus_info;
@@ -171,6 +152,7 @@ struct mlxsw_sp {
struct mlxsw_sp_bridge *bridge;
struct mlxsw_sp_router *router;
struct mlxsw_sp_acl *acl;
+ struct mlxsw_sp_fid_core *fid_core;
struct {
DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE);
} kvdl;
@@ -205,6 +187,7 @@ struct mlxsw_sp_port_sample {
};
struct mlxsw_sp_bridge_port;
+struct mlxsw_sp_fid;
struct mlxsw_sp_port_vlan {
struct list_head list;
@@ -247,7 +230,6 @@ struct mlxsw_sp_port {
struct delayed_work update_dw;
} hw_stats;
struct mlxsw_sp_port_sample *sample;
- unsigned int nr_port_vid_map; /* {Port, VID} => FID mappings */
struct list_head vlans_list;
};
@@ -290,35 +272,10 @@ mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port,
return NULL;
}
-static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
- u16 fid)
-{
- struct mlxsw_sp_fid *f;
-
- list_for_each_entry(f, &mlxsw_sp->fids, list)
- if (f->fid == fid)
- return f;
-
- return NULL;
-}
-
-static inline struct mlxsw_sp_fid *
-mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp,
- const struct net_device *br_dev)
-{
- struct mlxsw_sp_fid *f;
-
- list_for_each_entry(f, &mlxsw_sp->vfids.list, list)
- if (f->dev == br_dev)
- return f;
-
- return NULL;
-}
-
-enum mlxsw_sp_flood_table {
- MLXSW_SP_FLOOD_TABLE_UC,
- MLXSW_SP_FLOOD_TABLE_BC,
- MLXSW_SP_FLOOD_TABLE_MC,
+enum mlxsw_sp_flood_type {
+ MLXSW_SP_FLOOD_TYPE_UC,
+ MLXSW_SP_FLOOD_TYPE_BC,
+ MLXSW_SP_FLOOD_TYPE_MC,
};
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp);
@@ -362,15 +319,10 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port);
void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port);
-int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port,
- enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid,
- u16 vid);
int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
u16 vid_end, bool is_member, bool untagged);
int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
bool adding);
-struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid);
-int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid);
void
mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -393,11 +345,10 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
u8 next_index, u32 maxrate);
int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
u8 state);
+int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable);
int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
bool learn_enable);
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
-int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port);
-int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port);
struct mlxsw_sp_port_vlan *
mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
@@ -426,10 +377,11 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
int mlxsw_sp_netdevice_router_port_event(struct net_device *dev);
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
unsigned long event, void *ptr);
-void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_rif *rif);
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
struct netdev_notifier_changeupper_info *info);
+void
+mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
+void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif);
int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count,
u32 *p_entry_index);
@@ -535,6 +487,8 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule *rule,
u64 *packets, u64 *bytes, u64 *last_use);
+struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp);
+
int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp);
@@ -554,4 +508,27 @@ int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
unsigned int counter_index);
+int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_flood_type packet_type, u8 local_port,
+ bool member);
+int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
+void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
+enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid);
+u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid);
+enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid);
+void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
+struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid);
+struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
+ int br_ifindex);
+struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
+ u16 rif_index);
+struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid);
+int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port);
+void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port);
+int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp);
+
#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index 317f7b1..1da889a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -53,6 +53,7 @@ struct mlxsw_sp_acl {
struct mlxsw_sp *mlxsw_sp;
struct mlxsw_afk *afk;
struct mlxsw_afa *afa;
+ struct mlxsw_sp_fid *dummy_fid;
const struct mlxsw_sp_acl_ops *ops;
struct rhashtable ruleset_ht;
struct list_head rules;
@@ -112,6 +113,11 @@ static const struct rhashtable_params mlxsw_sp_acl_rule_ht_params = {
.automatic_shrinking = true,
};
+struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp)
+{
+ return mlxsw_sp->acl->dummy_fid;
+}
+
static struct mlxsw_sp_acl_ruleset *
mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_acl_profile_ops *ops)
@@ -676,6 +682,7 @@ static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = {
int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
{
const struct mlxsw_sp_acl_ops *acl_ops = &mlxsw_sp_acl_tcam_ops;
+ struct mlxsw_sp_fid *fid;
struct mlxsw_sp_acl *acl;
int err;
@@ -706,6 +713,13 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
if (err)
goto err_rhashtable_init;
+ fid = mlxsw_sp_fid_dummy_get(mlxsw_sp);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ goto err_fid_get;
+ }
+ acl->dummy_fid = fid;
+
INIT_LIST_HEAD(&acl->rules);
err = acl_ops->init(mlxsw_sp, acl->priv);
if (err)
@@ -721,6 +735,8 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
return 0;
err_acl_ops_init:
+ mlxsw_sp_fid_put(fid);
+err_fid_get:
rhashtable_destroy(&acl->ruleset_ht);
err_rhashtable_init:
mlxsw_afa_destroy(acl->afa);
@@ -739,6 +755,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp)
cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw);
acl_ops->fini(mlxsw_sp, acl->priv);
WARN_ON(!list_empty(&acl->rules));
+ mlxsw_sp_fid_put(acl->dummy_fid);
rhashtable_destroy(&acl->ruleset_ht);
mlxsw_afa_destroy(acl->afa);
mlxsw_afk_destroy(acl->afk);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
new file mode 100644
index 0000000..379bbe0
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
@@ -0,0 +1,978 @@
+/*
+ * drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Ido Schimmel <idosch@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+
+#include "spectrum.h"
+#include "reg.h"
+
+struct mlxsw_sp_fid_family;
+
+struct mlxsw_sp_fid_core {
+ struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
+ unsigned int *port_fid_mappings;
+};
+
+struct mlxsw_sp_fid {
+ struct list_head list;
+ struct mlxsw_sp_rif *rif;
+ unsigned int ref_count;
+ u16 fid_index;
+ struct mlxsw_sp_fid_family *fid_family;
+};
+
+struct mlxsw_sp_fid_8021q {
+ struct mlxsw_sp_fid common;
+ u16 vid;
+};
+
+struct mlxsw_sp_fid_8021d {
+ struct mlxsw_sp_fid common;
+ int br_ifindex;
+};
+
+struct mlxsw_sp_flood_table {
+ enum mlxsw_sp_flood_type packet_type;
+ enum mlxsw_reg_sfgc_bridge_type bridge_type;
+ enum mlxsw_flood_table_type table_type;
+ int table_index;
+};
+
+struct mlxsw_sp_fid_ops {
+ void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
+ int (*configure)(struct mlxsw_sp_fid *fid);
+ void (*deconfigure)(struct mlxsw_sp_fid *fid);
+ int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
+ u16 *p_fid_index);
+ bool (*compare)(const struct mlxsw_sp_fid *fid,
+ const void *arg);
+ u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
+ int (*port_vid_map)(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *port, u16 vid);
+ void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *port, u16 vid);
+};
+
+struct mlxsw_sp_fid_family {
+ enum mlxsw_sp_fid_type type;
+ size_t fid_size;
+ u16 start_index;
+ u16 end_index;
+ struct list_head fids_list;
+ unsigned long *fids_bitmap;
+ const struct mlxsw_sp_flood_table *flood_tables;
+ int nr_flood_tables;
+ enum mlxsw_sp_rif_type rif_type;
+ const struct mlxsw_sp_fid_ops *ops;
+ struct mlxsw_sp *mlxsw_sp;
+};
+
+static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
+ [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
+};
+
+static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
+ [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
+ [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
+ [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
+};
+
+static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
+};
+
+static const int *mlxsw_sp_packet_type_sfgc_types[] = {
+ [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
+ [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
+ [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
+};
+
+static const struct mlxsw_sp_flood_table *
+mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_flood_type packet_type)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ int i;
+
+ for (i = 0; i < fid_family->nr_flood_tables; i++) {
+ if (fid_family->flood_tables[i].packet_type != packet_type)
+ continue;
+ return &fid_family->flood_tables[i];
+ }
+
+ return NULL;
+}
+
+int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_flood_type packet_type, u8 local_port,
+ bool member)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+ const struct mlxsw_sp_flood_table *flood_table;
+ char *sftr_pl;
+ int err;
+
+ if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
+ return -EINVAL;
+
+ flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
+ if (!flood_table)
+ return -ESRCH;
+
+ sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
+ if (!sftr_pl)
+ return -ENOMEM;
+
+ mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index,
+ ops->flood_index(fid), flood_table->table_type, 1,
+ local_port, member);
+ err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr),
+ sftr_pl);
+ kfree(sftr_pl);
+ return err;
+}
+
+int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+ if (WARN_ON(!fid->fid_family->ops->port_vid_map))
+ return -EINVAL;
+ return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
+}
+
+void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+ fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
+}
+
+enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid)
+{
+ return fid->fid_family->rif_type;
+}
+
+u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
+{
+ return fid->fid_index;
+}
+
+enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
+{
+ return fid->fid_family->type;
+}
+
+void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
+{
+ fid->rif = rif;
+}
+
+static struct mlxsw_sp_fid_8021q *
+mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
+{
+ return container_of(fid, struct mlxsw_sp_fid_8021q, common);
+}
+
+static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
+{
+ u16 vid = *(u16 *) arg;
+
+ mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
+}
+
+static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
+{
+ return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
+ MLXSW_REG_SFMR_OP_DESTROY_FID;
+}
+
+static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
+ u16 fid_offset, bool valid)
+{
+ char sfmr_pl[MLXSW_REG_SFMR_LEN];
+
+ mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
+ fid_offset);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
+}
+
+static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
+ u16 vid, bool valid)
+{
+ enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
+ char svfa_pl[MLXSW_REG_SVFA_LEN];
+
+ mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
+}
+
+static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
+ u8 local_port, u16 vid, bool valid)
+{
+ enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
+ char svfa_pl[MLXSW_REG_SVFA_LEN];
+
+ mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
+}
+
+static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+ struct mlxsw_sp_fid_8021q *fid_8021q;
+ int err;
+
+ err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true);
+ if (err)
+ return err;
+
+ fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
+ err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid,
+ true);
+ if (err)
+ goto err_fid_map;
+
+ return 0;
+
+err_fid_map:
+ mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
+ return err;
+}
+
+static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+ struct mlxsw_sp_fid_8021q *fid_8021q;
+
+ fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
+ mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false);
+ mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
+}
+
+static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid,
+ const void *arg, u16 *p_fid_index)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ u16 vid = *(u16 *) arg;
+
+ /* Use 1:1 mapping for simplicity although not a must */
+ if (vid < fid_family->start_index || vid > fid_family->end_index)
+ return -EINVAL;
+ *p_fid_index = vid;
+
+ return 0;
+}
+
+static bool
+mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
+{
+ u16 vid = *(u16 *) arg;
+
+ return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
+}
+
+static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
+{
+ return fid->fid_index;
+}
+
+static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 local_port = mlxsw_sp_port->local_port;
+
+ /* In case there are no {Port, VID} => FID mappings on the port,
+ * we can use the global VID => FID mapping we created when the
+ * FID was configured.
+ */
+ if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
+ return 0;
+ return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port,
+ vid, true);
+}
+
+static void
+mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 local_port = mlxsw_sp_port->local_port;
+
+ if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
+ return;
+ __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid,
+ false);
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
+ .setup = mlxsw_sp_fid_8021q_setup,
+ .configure = mlxsw_sp_fid_8021q_configure,
+ .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
+ .index_alloc = mlxsw_sp_fid_8021q_index_alloc,
+ .compare = mlxsw_sp_fid_8021q_compare,
+ .flood_index = mlxsw_sp_fid_8021q_flood_index,
+ .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
+ .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
+};
+
+static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = {
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
+ .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
+ .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST,
+ .table_index = 0,
+ },
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
+ .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
+ .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST,
+ .table_index = 1,
+ },
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
+ .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
+ .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST,
+ .table_index = 2,
+ },
+};
+
+/* Range and flood configuration must match mlxsw_config_profile */
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = {
+ .type = MLXSW_SP_FID_TYPE_8021Q,
+ .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
+ .start_index = 1,
+ .end_index = VLAN_VID_MASK,
+ .flood_tables = mlxsw_sp_fid_8021q_flood_tables,
+ .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables),
+ .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
+ .ops = &mlxsw_sp_fid_8021q_ops,
+};
+
+static struct mlxsw_sp_fid_8021d *
+mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
+{
+ return container_of(fid, struct mlxsw_sp_fid_8021d, common);
+}
+
+static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
+{
+ int br_ifindex = *(int *) arg;
+
+ mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
+}
+
+static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+ return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
+}
+
+static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
+{
+ mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
+}
+
+static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
+ const void *arg, u16 *p_fid_index)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ u16 nr_fids, fid_index;
+
+ nr_fids = fid_family->end_index - fid_family->start_index + 1;
+ fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
+ if (fid_index == nr_fids)
+ return -ENOBUFS;
+ *p_fid_index = fid_family->start_index + fid_index;
+
+ return 0;
+}
+
+static bool
+mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
+{
+ int br_ifindex = *(int *) arg;
+
+ return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
+}
+
+static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
+{
+ return fid->fid_index - fid->fid_family->start_index;
+}
+
+static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
+ int err;
+
+ list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
+ list) {
+ struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
+ u16 vid = mlxsw_sp_port_vlan->vid;
+
+ if (!fid)
+ continue;
+
+ err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+ mlxsw_sp_port->local_port,
+ vid, true);
+ if (err)
+ goto err_fid_port_vid_map;
+ }
+
+ err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
+ if (err)
+ goto err_port_vp_mode_set;
+
+ return 0;
+
+err_port_vp_mode_set:
+err_fid_port_vid_map:
+ list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
+ &mlxsw_sp_port->vlans_list, list) {
+ struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
+ u16 vid = mlxsw_sp_port_vlan->vid;
+
+ if (!fid)
+ continue;
+
+ __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+ mlxsw_sp_port->local_port, vid,
+ false);
+ }
+ return err;
+}
+
+static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
+
+ mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
+
+ list_for_each_entry_reverse(mlxsw_sp_port_vlan,
+ &mlxsw_sp_port->vlans_list, list) {
+ struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
+ u16 vid = mlxsw_sp_port_vlan->vid;
+
+ if (!fid)
+ continue;
+
+ __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+ mlxsw_sp_port->local_port, vid,
+ false);
+ }
+}
+
+static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 local_port = mlxsw_sp_port->local_port;
+ int err;
+
+ err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+ mlxsw_sp_port->local_port, vid, true);
+ if (err)
+ return err;
+
+ if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
+ err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
+ if (err)
+ goto err_port_vp_mode_trans;
+ }
+
+ return 0;
+
+err_port_vp_mode_trans:
+ mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
+ __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+ mlxsw_sp_port->local_port, vid, false);
+ return err;
+}
+
+static void
+mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 local_port = mlxsw_sp_port->local_port;
+
+ if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
+ mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
+ mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
+ __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+ mlxsw_sp_port->local_port, vid, false);
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
+ .setup = mlxsw_sp_fid_8021d_setup,
+ .configure = mlxsw_sp_fid_8021d_configure,
+ .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
+ .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
+ .compare = mlxsw_sp_fid_8021d_compare,
+ .flood_index = mlxsw_sp_fid_8021d_flood_index,
+ .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
+ .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
+};
+
+static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
+ .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
+ .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
+ .table_index = 0,
+ },
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
+ .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
+ .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
+ .table_index = 1,
+ },
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
+ .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
+ .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
+ .table_index = 2,
+ },
+};
+
+/* Range and flood configuration must match mlxsw_config_profile */
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
+ .type = MLXSW_SP_FID_TYPE_8021D,
+ .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
+ .start_index = VLAN_N_VID,
+ .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
+ .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
+ .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
+ .rif_type = MLXSW_SP_RIF_TYPE_FID,
+ .ops = &mlxsw_sp_fid_8021d_ops,
+};
+
+static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
+{
+ /* rFIDs are allocated by the device during init */
+ return 0;
+}
+
+static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
+{
+}
+
+static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
+ const void *arg, u16 *p_fid_index)
+{
+ u16 rif_index = *(u16 *) arg;
+
+ *p_fid_index = fid->fid_family->start_index + rif_index;
+
+ return 0;
+}
+
+static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
+ const void *arg)
+{
+ u16 rif_index = *(u16 *) arg;
+
+ return fid->fid_index == rif_index + fid->fid_family->start_index;
+}
+
+static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 local_port = mlxsw_sp_port->local_port;
+ int err;
+
+ /* We only need to transition the port to virtual mode since
+ * {Port, VID} => FID is done by the firmware upon RIF creation.
+ */
+ if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
+ err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
+ if (err)
+ goto err_port_vp_mode_trans;
+ }
+
+ return 0;
+
+err_port_vp_mode_trans:
+ mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
+ return err;
+}
+
+static void
+mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 local_port = mlxsw_sp_port->local_port;
+
+ if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
+ mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
+ mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
+ .configure = mlxsw_sp_fid_rfid_configure,
+ .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
+ .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
+ .compare = mlxsw_sp_fid_rfid_compare,
+ .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
+ .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
+};
+
+#define MLXSW_SP_RFID_BASE (15 * 1024)
+#define MLXSW_SP_RFID_MAX 1024
+
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
+ .type = MLXSW_SP_FID_TYPE_RFID,
+ .fid_size = sizeof(struct mlxsw_sp_fid),
+ .start_index = MLXSW_SP_RFID_BASE,
+ .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
+ .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
+ .ops = &mlxsw_sp_fid_rfid_ops,
+};
+
+static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+
+ return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
+}
+
+static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
+{
+ mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
+}
+
+static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
+ const void *arg, u16 *p_fid_index)
+{
+ *p_fid_index = fid->fid_family->start_index;
+
+ return 0;
+}
+
+static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
+ const void *arg)
+{
+ return true;
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
+ .configure = mlxsw_sp_fid_dummy_configure,
+ .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
+ .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
+ .compare = mlxsw_sp_fid_dummy_compare,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
+ .type = MLXSW_SP_FID_TYPE_DUMMY,
+ .fid_size = sizeof(struct mlxsw_sp_fid),
+ .start_index = MLXSW_SP_RFID_BASE - 1,
+ .end_index = MLXSW_SP_RFID_BASE - 1,
+ .ops = &mlxsw_sp_fid_dummy_ops,
+};
+
+static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
+ [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family,
+ [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family,
+ [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
+ [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
+};
+
+static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_sp_fid_type type,
+ const void *arg)
+{
+ struct mlxsw_sp_fid_family *fid_family;
+ struct mlxsw_sp_fid *fid;
+ u16 fid_index;
+ int err;
+
+ fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
+ list_for_each_entry(fid, &fid_family->fids_list, list) {
+ if (!fid->fid_family->ops->compare(fid, arg))
+ continue;
+ fid->ref_count++;
+ return fid;
+ }
+
+ fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
+ if (!fid)
+ return ERR_PTR(-ENOMEM);
+ fid->fid_family = fid_family;
+
+ err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
+ if (err)
+ goto err_index_alloc;
+ fid->fid_index = fid_index;
+ __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
+
+ if (fid->fid_family->ops->setup)
+ fid->fid_family->ops->setup(fid, arg);
+
+ err = fid->fid_family->ops->configure(fid);
+ if (err)
+ goto err_configure;
+
+ list_add(&fid->list, &fid_family->fids_list);
+ fid->ref_count++;
+ return fid;
+
+err_configure:
+ __clear_bit(fid_index - fid_family->start_index,
+ fid_family->fids_bitmap);
+err_index_alloc:
+ kfree(fid);
+ return ERR_PTR(err);
+}
+
+void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+ if (--fid->ref_count == 1 && fid->rif) {
+ /* Destroy the associated RIF and let it drop the last
+ * reference on the FID.
+ */
+ return mlxsw_sp_rif_destroy(fid_family->mlxsw_sp, fid->rif);
+ } else if (fid->ref_count == 0) {
+ list_del(&fid->list);
+ fid->fid_family->ops->deconfigure(fid);
+ __clear_bit(fid->fid_index - fid_family->start_index,
+ fid_family->fids_bitmap);
+ kfree(fid);
+ }
+}
+
+struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
+{
+ return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
+}
+
+struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
+ int br_ifindex)
+{
+ return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
+}
+
+struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
+ u16 rif_index)
+{
+ return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
+}
+
+struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
+{
+ return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
+}
+
+static int
+mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_flood_table *flood_table)
+{
+ enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
+ const int *sfgc_packet_types;
+ int i;
+
+ sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
+ for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
+ struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+ char sfgc_pl[MLXSW_REG_SFGC_LEN];
+ int err;
+
+ if (!sfgc_packet_types[i])
+ continue;
+ mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
+ flood_table->table_type,
+ flood_table->table_index);
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
+{
+ int i;
+
+ for (i = 0; i < fid_family->nr_flood_tables; i++) {
+ const struct mlxsw_sp_flood_table *flood_table;
+ int err;
+
+ flood_table = &fid_family->flood_tables[i];
+ err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_fid_family *tmpl)
+{
+ u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
+ struct mlxsw_sp_fid_family *fid_family;
+ int err;
+
+ fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
+ if (!fid_family)
+ return -ENOMEM;
+
+ fid_family->mlxsw_sp = mlxsw_sp;
+ INIT_LIST_HEAD(&fid_family->fids_list);
+ fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!fid_family->fids_bitmap) {
+ err = -ENOMEM;
+ goto err_alloc_fids_bitmap;
+ }
+
+ if (fid_family->flood_tables) {
+ err = mlxsw_sp_fid_flood_tables_init(fid_family);
+ if (err)
+ goto err_fid_flood_tables_init;
+ }
+
+ mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
+
+ return 0;
+
+err_fid_flood_tables_init:
+ kfree(fid_family->fids_bitmap);
+err_alloc_fids_bitmap:
+ kfree(fid_family);
+ return err;
+}
+
+static void
+mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid_family *fid_family)
+{
+ mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
+ kfree(fid_family->fids_bitmap);
+ WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
+ kfree(fid_family);
+}
+
+int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+
+ /* Track number of FIDs configured on the port with mapping type
+ * PORT_VID_TO_FID, so that we know when to transition the port
+ * back to non-virtual (VLAN) mode.
+ */
+ mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
+
+ return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
+}
+
+void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+
+ mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
+}
+
+int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
+{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
+ struct mlxsw_sp_fid_core *fid_core;
+ int err, i;
+
+ fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
+ if (!fid_core)
+ return -ENOMEM;
+ mlxsw_sp->fid_core = fid_core;
+
+ fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!fid_core->port_fid_mappings) {
+ err = -ENOMEM;
+ goto err_alloc_port_fid_mappings;
+ }
+
+ for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
+ err = mlxsw_sp_fid_family_register(mlxsw_sp,
+ mlxsw_sp_fid_family_arr[i]);
+
+ if (err)
+ goto err_fid_ops_register;
+ }
+
+ return 0;
+
+err_fid_ops_register:
+ for (i--; i >= 0; i--) {
+ struct mlxsw_sp_fid_family *fid_family;
+
+ fid_family = fid_core->fid_family_arr[i];
+ mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
+ }
+ kfree(fid_core->port_fid_mappings);
+err_alloc_port_fid_mappings:
+ kfree(fid_core);
+ return err;
+}
+
+void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
+ int i;
+
+ for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
+ mlxsw_sp_fid_family_unregister(mlxsw_sp,
+ fid_core->fid_family_arr[i]);
+ kfree(fid_core->port_fid_mappings);
+ kfree(fid_core);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index 739dc1e..ed75c6a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -70,9 +70,13 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
} else if (is_tcf_mirred_egress_redirect(a)) {
int ifindex = tcf_mirred_ifindex(a);
struct net_device *out_dev;
+ struct mlxsw_sp_fid *fid;
+ u16 fid_index;
+ fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp);
+ fid_index = mlxsw_sp_fid_index(fid);
err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei,
- MLXSW_SP_DUMMY_FID);
+ fid_index);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 0c0ec2a..3c2e47d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -86,7 +86,7 @@ struct mlxsw_sp_rif {
struct list_head nexthop_list;
struct list_head neigh_list;
struct net_device *dev;
- struct mlxsw_sp_fid *f;
+ struct mlxsw_sp_fid *fid;
unsigned char addr[ETH_ALEN];
int mtu;
u16 rif_index;
@@ -2946,34 +2946,9 @@ mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp,
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}
-static void
-mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
-
-static u16 mlxsw_sp_rif_sp_to_fid(u16 rif_index)
-{
- return MLXSW_SP_RFID_BASE + rif_index;
-}
-
-static struct mlxsw_sp_fid *
-mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev)
-{
- struct mlxsw_sp_fid *f;
-
- f = kzalloc(sizeof(*f), GFP_KERNEL);
- if (!f)
- return NULL;
-
- f->leave = mlxsw_sp_port_vlan_rif_sp_leave;
- f->ref_count = 0;
- f->dev = l3_dev;
- f->fid = fid;
-
- return f;
-}
-
static struct mlxsw_sp_rif *
mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
- struct mlxsw_sp_fid *f, bool is_subport)
+ struct mlxsw_sp_fid *fid, bool is_subport)
{
size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) :
sizeof(struct mlxsw_sp_rif);
@@ -2990,7 +2965,7 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
rif->vr_id = vr_id;
rif->dev = l3_dev;
rif->rif_index = rif_index;
- rif->f = f;
+ rif->fid = fid;
return rif;
}
@@ -3019,10 +2994,10 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_rif_subport *rif_subport;
u32 tb_id = l3mdev_fib_table(l3_dev);
- struct mlxsw_sp_vr *vr;
- struct mlxsw_sp_fid *f;
struct mlxsw_sp_rif *rif;
- u16 fid, rif_index;
+ struct mlxsw_sp_fid *fid;
+ struct mlxsw_sp_vr *vr;
+ u16 rif_index;
int err;
vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
@@ -3035,14 +3010,13 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
goto err_avail_rif_get;
}
- fid = mlxsw_sp_rif_sp_to_fid(rif_index);
- f = mlxsw_sp_rfid_alloc(fid, l3_dev);
- if (!f) {
- err = -ENOMEM;
- goto err_rfid_alloc;
+ fid = mlxsw_sp_fid_rfid_get(mlxsw_sp, rif_index);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ goto err_fid_get;
}
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true);
+ rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, true);
if (!rif) {
err = -ENOMEM;
goto err_rif_alloc;
@@ -3062,7 +3036,8 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
if (err)
goto err_port_vlan_rif_sp_op;
- err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true);
+ err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr,
+ mlxsw_sp_fid_index(fid), true);
if (err)
goto err_rif_fdb_op;
@@ -3075,7 +3050,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
"Counter alloc Failed err=%d\n", err);
}
- f->rif = rif;
+ mlxsw_sp_fid_rif_set(fid, rif);
mlxsw_sp->router->rifs[rif_index] = rif;
vr->rif_count++;
@@ -3086,8 +3061,8 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
err_port_vlan_rif_sp_op:
kfree(rif);
err_rif_alloc:
- kfree(f);
-err_rfid_alloc:
+ mlxsw_sp_fid_put(fid);
+err_fid_get:
err_avail_rif_get:
mlxsw_sp_vr_put(vr);
return ERR_PTR(err);
@@ -3099,9 +3074,8 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp,
{
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
struct net_device *l3_dev = rif->dev;
- struct mlxsw_sp_fid *f = rif->f;
+ struct mlxsw_sp_fid *fid = rif->fid;
u16 rif_index = rif->rif_index;
- u16 fid = f->fid;
mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
@@ -3110,24 +3084,25 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp,
vr->rif_count--;
mlxsw_sp->router->rifs[rif_index] = NULL;
- f->rif = NULL;
-
- mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
+ mlxsw_sp_fid_rif_set(fid, NULL);
+ mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid),
+ false);
mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false);
kfree(rif);
- kfree(f);
+ mlxsw_sp_fid_put(fid);
mlxsw_sp_vr_put(vr);
}
static int
-mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
+mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
struct net_device *l3_dev)
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u16 vid = mlxsw_sp_port_vlan->vid;
struct mlxsw_sp_rif *rif;
+ struct mlxsw_sp_fid *fid;
int err;
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
@@ -3138,6 +3113,12 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
return PTR_ERR(rif);
}
+ /* FID was already created, just take a reference */
+ fid = mlxsw_sp_fid_rfid_get(mlxsw_sp_port->mlxsw_sp, rif->rif_index);
+ err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
+ if (err)
+ goto err_fid_port_vid_map;
+
err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
if (err)
goto err_port_vid_learning_set;
@@ -3147,47 +3128,37 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
if (err)
goto err_port_vid_stp_set;
- if (mlxsw_sp_port->nr_port_vid_map++ == 0) {
- err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
- if (err)
- goto err_port_vp_mode_trans;
- }
-
- mlxsw_sp_port_vlan->fid = rif->f;
- rif->f->ref_count++;
+ mlxsw_sp_port_vlan->fid = fid;
return 0;
-err_port_vp_mode_trans:
- mlxsw_sp_port->nr_port_vid_map--;
- mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
err_port_vid_stp_set:
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
err_port_vid_learning_set:
- if (rif->f->ref_count == 0)
- mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif);
+ mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
+err_fid_port_vid_map:
+ mlxsw_sp_fid_put(fid);
return err;
}
-static void
-mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
+void
+mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
u16 vid = mlxsw_sp_port_vlan->vid;
- fid->ref_count--;
- mlxsw_sp_port_vlan->fid = NULL;
+ if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
+ return;
- if (mlxsw_sp_port->nr_port_vid_map == 1)
- mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
- mlxsw_sp_port->nr_port_vid_map--;
+ mlxsw_sp_port_vlan->fid = NULL;
mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
-
- if (fid->ref_count == 0)
- mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, fid->rif);
+ mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
+ /* If router port holds the last reference on the rFID, then the
+ * associated Sub-port RIF will be destroyed.
+ */
+ mlxsw_sp_fid_put(fid);
}
static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
@@ -3203,10 +3174,10 @@ static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
switch (event) {
case NETDEV_UP:
- return mlxsw_sp_port_vlan_rif_sp_join(mlxsw_sp_port_vlan,
+ return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan,
l3_dev);
case NETDEV_DOWN:
- mlxsw_sp_port_vlan_rif_sp_leave(mlxsw_sp_port_vlan);
+ mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
break;
}
@@ -3254,96 +3225,65 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1);
}
-static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev)
-{
- struct mlxsw_sp_fid *fid;
- u16 fid_index;
-
- if (is_vlan_dev(l3_dev))
- fid_index = vlan_dev_vlan_id(l3_dev);
- else if (br_vlan_enabled(l3_dev))
- fid_index = 1;
- else
- return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev);
-
- fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index);
- if (fid)
- return fid;
-
- fid = mlxsw_sp_fid_create(mlxsw_sp, fid_index);
- if (IS_ERR(fid))
- return NULL;
- return fid;
-}
-
static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
{
return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
}
-static enum mlxsw_flood_table_type mlxsw_sp_flood_table_type_get(u16 fid)
-{
- return mlxsw_sp_fid_is_vfid(fid) ? MLXSW_REG_SFGC_TABLE_TYPE_FID :
- MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
-}
-
-static u16 mlxsw_sp_flood_table_index_get(u16 fid)
-{
- return mlxsw_sp_fid_is_vfid(fid) ? mlxsw_sp_fid_to_vfid(fid) : fid;
-}
-
-static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid,
- bool set)
-{
- u8 router_port = mlxsw_sp_router_port(mlxsw_sp);
- enum mlxsw_flood_table_type table_type;
- char *sftr_pl;
- u16 index;
- int err;
-
- sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
- if (!sftr_pl)
- return -ENOMEM;
-
- table_type = mlxsw_sp_flood_table_type_get(fid);
- index = mlxsw_sp_flood_table_index_get(fid);
- mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type,
- 1, router_port, set);
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
-
- kfree(sftr_pl);
- return err;
-}
-
-static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid)
+static enum mlxsw_reg_ritr_if_type
+mlxsw_sp_rif_type_ritr_if_type(enum mlxsw_sp_rif_type rif_type)
{
- if (mlxsw_sp_fid_is_vfid(fid))
- return MLXSW_REG_RITR_FID_IF;
- else
+ switch (rif_type) {
+ case MLXSW_SP_RIF_TYPE_SUBPORT:
+ return MLXSW_REG_RITR_SP_IF;
+ case MLXSW_SP_RIF_TYPE_VLAN:
return MLXSW_REG_RITR_VLAN_IF;
+ case MLXSW_SP_RIF_TYPE_FID:
+ return MLXSW_REG_RITR_FID_IF;
+ default:
+ WARN_ON(1);
+ return 0;
+ }
}
static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_rif *rif, bool create)
{
- enum mlxsw_reg_ritr_if_type rif_type;
+ enum mlxsw_reg_ritr_if_type ritr_if_type;
+ enum mlxsw_sp_rif_type rif_type;
char ritr_pl[MLXSW_REG_RITR_LEN];
- rif_type = mlxsw_sp_rif_type_get(rif->f->fid);
+ rif_type = mlxsw_sp_fid_rif_type(rif->fid);
+ ritr_if_type = mlxsw_sp_rif_type_ritr_if_type(rif_type);
mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index,
rif->vr_id, rif->dev->mtu, rif->dev->dev_addr);
- mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, rif->f->fid);
+ mlxsw_reg_ritr_fid_set(ritr_pl, ritr_if_type,
+ mlxsw_sp_fid_index(rif->fid));
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}
+static struct mlxsw_sp_fid *
+mlxsw_sp_rif_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *dev)
+{
+ if (netif_is_bridge_master(dev) && !br_vlan_enabled(dev))
+ return mlxsw_sp_fid_8021d_get(mlxsw_sp, dev->ifindex);
+ else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
+ return mlxsw_sp_fid_8021q_get(mlxsw_sp, 1);
+ else if (is_vlan_dev(dev) &&
+ netif_is_bridge_master(vlan_dev_real_dev(dev)))
+ return mlxsw_sp_fid_8021q_get(mlxsw_sp, vlan_dev_vlan_id(dev));
+ else
+ return ERR_PTR(-EINVAL);
+}
+
static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev,
- struct mlxsw_sp_fid *f)
+ struct net_device *l3_dev)
{
u32 tb_id = l3mdev_fib_table(l3_dev);
struct mlxsw_sp_rif *rif;
+ struct mlxsw_sp_fid *fid;
struct mlxsw_sp_vr *vr;
u16 rif_index;
int err;
@@ -3358,7 +3298,13 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
goto err_avail_rif_get;
}
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false);
+ fid = mlxsw_sp_rif_bridge_fid_get(mlxsw_sp, l3_dev);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ goto err_fid_get;
+ }
+
+ rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, false);
if (!rif) {
err = -ENOMEM;
goto err_rif_alloc;
@@ -3368,15 +3314,17 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_rif_bridge_op;
- err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true);
+ err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), true);
if (err)
- goto err_port_flood_set;
+ goto err_fid_bc_flood_set;
- err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true);
+ err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr,
+ mlxsw_sp_fid_index(fid), true);
if (err)
goto err_rif_fdb_op;
- f->rif = rif;
+ mlxsw_sp_fid_rif_set(fid, rif);
mlxsw_sp->router->rifs[rif_index] = rif;
vr->rif_count++;
@@ -3385,64 +3333,58 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
return 0;
err_rif_fdb_op:
- mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
-err_port_flood_set:
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), false);
+err_fid_bc_flood_set:
mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
err_rif_bridge_op:
kfree(rif);
err_rif_alloc:
+ mlxsw_sp_fid_put(fid);
+err_fid_get:
err_avail_rif_get:
mlxsw_sp_vr_put(vr);
return err;
}
-void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_rif *rif)
+static void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *rif)
{
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
struct net_device *l3_dev = rif->dev;
- struct mlxsw_sp_fid *f = rif->f;
+ struct mlxsw_sp_fid *fid = rif->fid;
u16 rif_index = rif->rif_index;
mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
vr->rif_count--;
mlxsw_sp->router->rifs[rif_index] = NULL;
- f->rif = NULL;
-
- mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
-
- mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
+ mlxsw_sp_fid_rif_set(fid, NULL);
+ mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid),
+ false);
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), false);
mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
-
kfree(rif);
-
+ mlxsw_sp_fid_put(fid);
mlxsw_sp_vr_put(vr);
netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index);
}
static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
- struct net_device *br_dev,
unsigned long event)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
- struct mlxsw_sp_fid *f;
-
- /* FID can either be an actual FID if the L3 device is the
- * VLAN-aware bridge or a VLAN device on top. Otherwise, the
- * L3 device is a VLAN-unaware bridge and we get a vFID.
- */
- f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
- if (WARN_ON(!f))
- return -EINVAL;
+ struct mlxsw_sp_rif *rif;
switch (event) {
case NETDEV_UP:
- return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
+ return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev);
case NETDEV_DOWN:
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
+ rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
+ mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif);
break;
}
@@ -3462,8 +3404,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
vid);
else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
- return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev,
- event);
+ return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event);
return 0;
}
@@ -3476,7 +3417,7 @@ static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
else if (netif_is_lag_master(dev))
return mlxsw_sp_inetaddr_lag_event(dev, event);
else if (netif_is_bridge_master(dev))
- return mlxsw_sp_inetaddr_bridge_event(dev, dev, event);
+ return mlxsw_sp_inetaddr_bridge_event(dev, event);
else if (is_vlan_dev(dev))
return mlxsw_sp_inetaddr_vlan_event(dev, event);
else
@@ -3526,6 +3467,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
{
struct mlxsw_sp *mlxsw_sp;
struct mlxsw_sp_rif *rif;
+ u16 fid_index;
int err;
mlxsw_sp = mlxsw_sp_lower_get(dev);
@@ -3535,8 +3477,9 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
if (!rif)
return 0;
+ fid_index = mlxsw_sp_fid_index(rif->fid);
- err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, false);
+ err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
if (err)
return err;
@@ -3545,7 +3488,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
if (err)
goto err_rif_edit;
- err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, rif->f->fid, true);
+ err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true);
if (err)
goto err_rif_fdb_op;
@@ -3559,7 +3502,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
err_rif_fdb_op:
mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu);
err_rif_edit:
- mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, true);
+ mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
return err;
}
@@ -3612,6 +3555,14 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
return err;
}
+void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif)
+{
+ if (mlxsw_sp_fid_rif_type(rif->fid) == MLXSW_SP_RIF_TYPE_SUBPORT)
+ mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif);
+ else
+ mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif);
+}
+
static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
{
u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index b17b224..edcc273 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -113,6 +113,9 @@ struct mlxsw_sp_bridge_ops {
void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device,
struct mlxsw_sp_bridge_port *bridge_port,
struct mlxsw_sp_port *mlxsw_sp_port);
+ struct mlxsw_sp_fid *
+ (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device,
+ u16 vid);
};
static int
@@ -361,7 +364,7 @@ mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port,
list) {
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
- if (fid && fid->fid == fid_index)
+ if (fid && mlxsw_sp_fid_index(fid) == fid_index)
return mlxsw_sp_port_vlan;
}
@@ -517,40 +520,10 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}
-static int mlxsw_sp_port_fid_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
- struct mlxsw_sp_fid *fid,
- enum mlxsw_sp_flood_table table,
- bool member)
-{
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- enum mlxsw_flood_table_type table_type;
- u16 flood_index = fid->fid;
- char *sftr_pl;
- int err;
-
- table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
- if (mlxsw_sp_fid_is_vfid(fid->fid)) {
- table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID;
- flood_index = mlxsw_sp_fid_to_vfid(fid->fid);
- }
-
- sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
- if (!sftr_pl)
- return -ENOMEM;
-
- mlxsw_reg_sftr_pack(sftr_pl, table, flood_index, table_type, 1,
- local_port, member);
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
-
- kfree(sftr_pl);
- return err;
-}
-
static int
mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_bridge_vlan *bridge_vlan,
- enum mlxsw_sp_flood_table table,
+ enum mlxsw_sp_flood_type packet_type,
bool member)
{
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
@@ -559,9 +532,10 @@ mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
bridge_vlan_node) {
if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
continue;
- return mlxsw_sp_port_fid_flood_set(mlxsw_sp_port,
- mlxsw_sp_port_vlan->fid,
- table, member);
+ return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid,
+ packet_type,
+ mlxsw_sp_port->local_port,
+ member);
}
return 0;
@@ -570,7 +544,7 @@ mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
static int
mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_bridge_port *bridge_port,
- enum mlxsw_sp_flood_table table,
+ enum mlxsw_sp_flood_type packet_type,
bool member)
{
struct mlxsw_sp_bridge_vlan *bridge_vlan;
@@ -578,7 +552,8 @@ mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port,
- bridge_vlan, table,
+ bridge_vlan,
+ packet_type,
member);
if (err)
goto err_port_bridge_vlan_flood_set;
@@ -590,7 +565,7 @@ mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
list_for_each_entry_continue_reverse(bridge_vlan,
&bridge_port->vlans_list, list)
mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan,
- table, !member);
+ packet_type, !member);
return err;
}
@@ -654,7 +629,7 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
return -EINVAL;
err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
- MLXSW_SP_FLOOD_TABLE_UC,
+ MLXSW_SP_FLOOD_TYPE_UC,
brport_flags & BR_FLOOD);
if (err)
return err;
@@ -742,7 +717,7 @@ static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port,
return 0;
return mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
- MLXSW_SP_FLOOD_TABLE_MC,
+ MLXSW_SP_FLOOD_TYPE_MC,
is_port_mc_router);
}
@@ -767,12 +742,12 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
return 0;
list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
- enum mlxsw_sp_flood_table table = MLXSW_SP_FLOOD_TABLE_MC;
+ enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC;
bool member = mc_disabled ? true : bridge_port->mrouter;
err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
- bridge_port, table,
- member);
+ bridge_port,
+ packet_type, member);
if (err)
return err;
}
@@ -827,189 +802,6 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
return err;
}
-static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
-{
- return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
- MLXSW_REG_SFMR_OP_DESTROY_FID;
-}
-
-int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid)
-{
- u16 fid_offset = fid_index < MLXSW_SP_VFID_BASE ? fid_index : 0;
- char sfmr_pl[MLXSW_REG_SFMR_LEN];
-
- mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
- fid_offset);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
-}
-
-static int mlxsw_sp_fid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
- bool valid)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
- char svfa_pl[MLXSW_REG_SVFA_LEN];
-
- mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, fid_index);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
-}
-
-struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp,
- u16 fid_index)
-{
- struct mlxsw_sp_fid *fid;
- int err;
-
- err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true);
- if (err)
- return ERR_PTR(err);
-
- err = mlxsw_sp_fid_map(mlxsw_sp, fid_index, true);
- if (err)
- goto err_fid_map;
-
- fid = kzalloc(sizeof(*fid), GFP_KERNEL);
- if (!fid) {
- err = -ENOMEM;
- goto err_allocate_fid;
- }
-
- fid->fid = fid_index;
- fid->ref_count = 1;
- list_add(&fid->list, &mlxsw_sp->fids);
-
- return fid;
-
-err_allocate_fid:
- mlxsw_sp_fid_map(mlxsw_sp, fid_index, false);
-err_fid_map:
- mlxsw_sp_fid_op(mlxsw_sp, fid_index, false);
- return ERR_PTR(err);
-}
-
-static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fid *fid)
-{
- u16 fid_index = fid->fid;
-
- list_del(&fid->list);
- if (fid->rif)
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif);
- kfree(fid);
- mlxsw_sp_fid_map(mlxsw_sp, fid_index, false);
- mlxsw_sp_fid_op(mlxsw_sp, fid_index, false);
-}
-
-static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp,
- struct net_device *dev)
-{
- u16 vfid_index, fid_index;
- struct mlxsw_sp_fid *fid;
- int err;
-
- vfid_index = find_first_zero_bit(mlxsw_sp->vfids.mapped,
- MLXSW_SP_VFID_MAX);
- if (vfid_index == MLXSW_SP_VFID_MAX)
- return ERR_PTR(-ENOBUFS);
-
- fid_index = mlxsw_sp_vfid_to_fid(vfid_index);
- err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true);
- if (err)
- return ERR_PTR(err);
-
- fid = kzalloc(sizeof(*fid), GFP_KERNEL);
- if (!fid) {
- err = -ENOMEM;
- goto err_allocate_fid;
- }
-
- fid->fid = fid_index;
- fid->ref_count = 1;
- fid->dev = dev;
- list_add(&fid->list, &mlxsw_sp->vfids.list);
- __set_bit(vfid_index, mlxsw_sp->vfids.mapped);
-
- return fid;
-
-err_allocate_fid:
- mlxsw_sp_fid_op(mlxsw_sp, fid_index, false);
- return ERR_PTR(err);
-}
-
-static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fid *fid)
-{
- u16 vfid_index = mlxsw_sp_fid_to_vfid(fid->fid);
- u16 fid_index = fid->fid;
-
- __clear_bit(vfid_index, mlxsw_sp->vfids.mapped);
- list_del(&fid->list);
- if (fid->rif)
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif);
- kfree(fid);
- mlxsw_sp_fid_op(mlxsw_sp, fid_index, false);
-}
-
-static struct mlxsw_sp_fid *__mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
- u16 fid_index)
-{
- struct mlxsw_sp_fid *fid;
-
- fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index);
- if (fid) {
- fid->ref_count++;
- return fid;
- }
-
- return mlxsw_sp_fid_create(mlxsw_sp, fid_index);
-}
-
-static struct mlxsw_sp_fid *mlxsw_sp_vfid_get(struct mlxsw_sp *mlxsw_sp,
- struct net_device *dev)
-{
- struct mlxsw_sp_fid *fid;
-
- fid = mlxsw_sp_vfid_find(mlxsw_sp, dev);
- if (fid) {
- fid->ref_count++;
- return fid;
- }
-
- return mlxsw_sp_vfid_create(mlxsw_sp, dev);
-}
-
-static struct mlxsw_sp_fid *
-mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, u16 vid,
- struct mlxsw_sp_bridge_device *bridge_device)
-{
- if (bridge_device->vlan_enabled)
- return __mlxsw_sp_fid_get(mlxsw_sp, vid);
- else
- return mlxsw_sp_vfid_get(mlxsw_sp, bridge_device->dev);
-}
-
-static void __mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fid *fid)
-{
- if (--fid->ref_count == 0)
- mlxsw_sp_fid_destroy(mlxsw_sp, fid);
-}
-
-static void mlxsw_sp_vfid_put(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fid *fid)
-{
- if (--fid->ref_count == 0)
- mlxsw_sp_vfid_destroy(mlxsw_sp, fid);
-}
-
-static void mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fid *fid)
-{
- if (!mlxsw_sp_fid_is_vfid(fid->fid))
- __mlxsw_sp_fid_put(mlxsw_sp, fid);
- else
- mlxsw_sp_vfid_put(mlxsw_sp, fid);
-}
-
static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)
{
const struct mlxsw_sp_bridge_device *bridge_device;
@@ -1018,126 +810,53 @@ static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)
return !bridge_device->multicast_enabled ? true : bridge_port->mrouter;
}
-static int __mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid, u16 fid_index)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
- int err;
-
- err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index,
- vid);
- if (err)
- return err;
-
- if (mlxsw_sp_port->nr_port_vid_map++ == 0) {
- err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
- if (err)
- goto err_port_vp_mode_trans;
- }
-
- return 0;
-
-err_port_vp_mode_trans:
- mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid);
- return err;
-}
-
-static int __mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid, u16 fid_index)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
-
- if (mlxsw_sp_port->nr_port_vid_map == 1)
- mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
- mlxsw_sp_port->nr_port_vid_map--;
-
- mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid);
-
- return 0;
-}
-
-static int mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid, u16 fid_index)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
-
- if (mlxsw_sp_fid_is_vfid(fid_index))
- return __mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid,
- fid_index);
-
- if (mlxsw_sp_port->nr_port_vid_map == 0)
- return 0;
-
- return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index,
- fid_index);
-}
-
-static int mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid, u16 fid_index)
-{
- enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
-
- if (mlxsw_sp_fid_is_vfid(fid_index))
- return __mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid,
- fid_index);
-
- if (mlxsw_sp_port->nr_port_vid_map == 0)
- return 0;
-
- return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index,
- fid_index);
-}
-
static int
mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
struct mlxsw_sp_bridge_port *bridge_port)
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_bridge_device *bridge_device;
+ u8 local_port = mlxsw_sp_port->local_port;
u16 vid = mlxsw_sp_port_vlan->vid;
struct mlxsw_sp_fid *fid;
int err;
- fid = mlxsw_sp_fid_get(mlxsw_sp, vid, bridge_port->bridge_device);
+ bridge_device = bridge_port->bridge_device;
+ fid = bridge_device->ops->fid_get(bridge_device, vid);
if (IS_ERR(fid))
return PTR_ERR(fid);
- err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid,
- MLXSW_SP_FLOOD_TABLE_UC,
- bridge_port->flags & BR_FLOOD);
+ err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port,
+ bridge_port->flags & BR_FLOOD);
if (err)
- goto err_port_fid_uc_flood_set;
+ goto err_fid_uc_flood_set;
- err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid,
- MLXSW_SP_FLOOD_TABLE_MC,
- mlxsw_sp_mc_flood(bridge_port));
+ err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port,
+ mlxsw_sp_mc_flood(bridge_port));
if (err)
- goto err_port_fid_mc_flood_set;
+ goto err_fid_mc_flood_set;
- err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid,
- MLXSW_SP_FLOOD_TABLE_BC, true);
+ err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port,
+ true);
if (err)
- goto err_port_fid_bc_flood_set;
+ goto err_fid_bc_flood_set;
- err = mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, fid->fid);
+ err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
if (err)
- goto err_port_vid_fid_map;
+ goto err_fid_port_vid_map;
mlxsw_sp_port_vlan->fid = fid;
return 0;
-err_port_vid_fid_map:
- mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC,
- false);
-err_port_fid_bc_flood_set:
- mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC,
- false);
-err_port_fid_mc_flood_set:
- mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC,
- false);
-err_port_fid_uc_flood_set:
- mlxsw_sp_fid_put(mlxsw_sp, fid);
+err_fid_port_vid_map:
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
+err_fid_bc_flood_set:
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
+err_fid_mc_flood_set:
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
+err_fid_uc_flood_set:
+ mlxsw_sp_fid_put(fid);
return err;
}
@@ -1145,19 +864,16 @@ static void
mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
+ u8 local_port = mlxsw_sp_port->local_port;
u16 vid = mlxsw_sp_port_vlan->vid;
mlxsw_sp_port_vlan->fid = NULL;
- mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, fid->fid);
- mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC,
- false);
- mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC,
- false);
- mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC,
- false);
- mlxsw_sp_fid_put(mlxsw_sp, fid);
+ mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
+ mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
+ mlxsw_sp_fid_put(fid);
}
static u16
@@ -1233,6 +949,10 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
u16 vid = mlxsw_sp_port_vlan->vid;
bool last;
+ if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q &&
+ mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D))
+ return;
+
bridge_port = mlxsw_sp_port_vlan->bridge_port;
bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
last = list_is_singular(&bridge_vlan->port_vlan_list);
@@ -1243,7 +963,8 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
if (last)
mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp,
- bridge_port, fid->fid);
+ bridge_port,
+ mlxsw_sp_fid_index(fid));
mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port);
@@ -1446,7 +1167,7 @@ mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port,
if (!mlxsw_sp_port_vlan)
return 0;
- fid_index = mlxsw_sp_port_vlan->fid->fid;
+ fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
vid = mlxsw_sp_port_vlan->vid;
if (!mlxsw_sp_port->lagged)
@@ -1580,7 +1301,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
if (WARN_ON(!mlxsw_sp_port_vlan))
return -EINVAL;
- fid_index = mlxsw_sp_port_vlan->fid->fid;
+ fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index);
if (!mid) {
@@ -1706,7 +1427,7 @@ mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port,
if (!mlxsw_sp_port_vlan)
return 0;
- fid_index = mlxsw_sp_port_vlan->fid->fid;
+ fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
vid = mlxsw_sp_port_vlan->vid;
if (!mlxsw_sp_port->lagged)
@@ -1746,7 +1467,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
if (WARN_ON(!mlxsw_sp_port_vlan))
return -EINVAL;
- fid_index = mlxsw_sp_port_vlan->fid->fid;
+ fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index);
if (!mid) {
@@ -2000,9 +1721,19 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
}
+static struct mlxsw_sp_fid *
+mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
+ u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
+
+ return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid);
+}
+
static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = {
.port_join = mlxsw_sp_bridge_8021q_port_join,
.port_leave = mlxsw_sp_bridge_8021q_port_leave,
+ .fid_get = mlxsw_sp_bridge_8021q_fid_get,
};
static bool
@@ -2028,7 +1759,6 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
- struct mlxsw_sp_fid *fid;
u16 vid;
if (!is_vlan_dev(bridge_port->dev))
@@ -2038,7 +1768,6 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
if (WARN_ON(!mlxsw_sp_port_vlan))
return -EINVAL;
- fid = mlxsw_sp_port_vlan->fid;
if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) {
netdev_err(mlxsw_sp_port->dev, "Can't bridge VLAN uppers of the same port\n");
@@ -2046,8 +1775,8 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
}
/* Port is no longer usable as a router interface */
- if (fid)
- fid->leave(mlxsw_sp_port_vlan);
+ if (mlxsw_sp_port_vlan->fid)
+ mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port);
}
@@ -2067,9 +1796,19 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
}
+static struct mlxsw_sp_fid *
+mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
+ u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
+
+ return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
+}
+
static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = {
.port_join = mlxsw_sp_bridge_8021d_port_join,
.port_leave = mlxsw_sp_bridge_8021d_port_leave,
+ .fid_get = mlxsw_sp_bridge_8021d_fid_get,
};
int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
--
2.9.3
^ permalink raw reply related
* [patch net-next 18/18] mlxsw: spectrum_router: Implement common RIF core
From: Jiri Pirko @ 2017-05-26 6:37 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, stephen, nikolay
In-Reply-To: <20170526063740.8909-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
The mlxsw driver currently implements three types of RIFs. VLAN and FID
RIFs for L3 interfaces on top of VLAN-aware and VLAN-unaware bridges
(respectively) and Subport RIFs for all other L3 interfaces.
All the RIF types follow a common configuration procedure, which only
differs in the type-specific bits. The patch exploits this fact and
consolidates the common code paths, thereby simplifying the code and
making it more extensible.
This work also prepares the driver for use with future ASICs, where the
range of the Subport RIFs will be extended and their configuration
modified accordingly. By merely implementing a new RIF operations and
selecting it during initialization, the same driver could be re-used.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 6 +-
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 16 +-
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 552 ++++++++++++---------
3 files changed, 337 insertions(+), 237 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index c542b33..1a83410 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -381,7 +381,7 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
struct netdev_notifier_changeupper_info *info);
void
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
-void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif);
+void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count,
u32 *p_entry_index);
@@ -519,6 +519,10 @@ enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid);
u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid);
enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid);
void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
+enum mlxsw_sp_rif_type
+mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_sp_fid_type type);
+u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
int br_ifindex);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
index 379bbe0..c7590ae 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
@@ -205,12 +205,26 @@ void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
fid->rif = rif;
}
+enum mlxsw_sp_rif_type
+mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_sp_fid_type type)
+{
+ struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
+
+ return fid_core->fid_family_arr[type]->rif_type;
+}
+
static struct mlxsw_sp_fid_8021q *
mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
{
return container_of(fid, struct mlxsw_sp_fid_8021q, common);
}
+u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
+{
+ return mlxsw_sp_fid_8021q_fid(fid)->vid;
+}
+
static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
{
u16 vid = *(u16 *) arg;
@@ -780,7 +794,7 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
/* Destroy the associated RIF and let it drop the last
* reference on the FID.
*/
- return mlxsw_sp_rif_destroy(fid_family->mlxsw_sp, fid->rif);
+ return mlxsw_sp_rif_destroy(fid->rif);
} else if (fid->ref_count == 0) {
list_del(&fid->list);
fid->fid_family->ops->deconfigure(fid);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 3c2e47d..a4272c3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -59,6 +59,7 @@
struct mlxsw_sp_vr;
struct mlxsw_sp_lpm_tree;
+struct mlxsw_sp_rif_ops;
struct mlxsw_sp_router {
struct mlxsw_sp *mlxsw_sp;
@@ -80,6 +81,7 @@ struct mlxsw_sp_router {
struct list_head nexthop_neighs_list;
bool aborted;
struct notifier_block fib_nb;
+ const struct mlxsw_sp_rif_ops **rif_ops_arr;
};
struct mlxsw_sp_rif {
@@ -91,12 +93,25 @@ struct mlxsw_sp_rif {
int mtu;
u16 rif_index;
u16 vr_id;
+ const struct mlxsw_sp_rif_ops *ops;
+ struct mlxsw_sp *mlxsw_sp;
+
unsigned int counter_ingress;
bool counter_ingress_valid;
unsigned int counter_egress;
bool counter_egress_valid;
};
+struct mlxsw_sp_rif_params {
+ struct net_device *dev;
+ union {
+ u16 system_port;
+ u16 lag_id;
+ };
+ u16 vid;
+ bool lag;
+};
+
struct mlxsw_sp_rif_subport {
struct mlxsw_sp_rif common;
union {
@@ -107,6 +122,17 @@ struct mlxsw_sp_rif_subport {
bool lag;
};
+struct mlxsw_sp_rif_ops {
+ enum mlxsw_sp_rif_type type;
+ size_t rif_size;
+
+ void (*setup)(struct mlxsw_sp_rif *rif,
+ const struct mlxsw_sp_rif_params *params);
+ int (*configure)(struct mlxsw_sp_rif *rif);
+ void (*deconfigure)(struct mlxsw_sp_rif *rif);
+ struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif);
+};
+
static unsigned int *
mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
enum mlxsw_sp_rif_counter_dir dir)
@@ -255,6 +281,25 @@ void mlxsw_sp_rif_counter_free(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_rif_counter_valid_set(rif, dir, false);
}
+static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ struct devlink *devlink;
+
+ devlink = priv_to_devlink(mlxsw_sp->core);
+ if (!devlink_dpipe_table_counter_enabled(devlink,
+ MLXSW_SP_DPIPE_TABLE_NAME_ERIF))
+ return;
+ mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
+}
+
+static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+
+ mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
+}
+
static struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev);
@@ -2915,6 +2960,25 @@ static bool mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif,
return false;
}
+static enum mlxsw_sp_rif_type
+mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *dev)
+{
+ enum mlxsw_sp_fid_type type;
+
+ /* RIF type is derived from the type of the underlying FID */
+ if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev)))
+ type = MLXSW_SP_FID_TYPE_8021Q;
+ else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
+ type = MLXSW_SP_FID_TYPE_8021Q;
+ else if (netif_is_bridge_master(dev))
+ type = MLXSW_SP_FID_TYPE_8021D;
+ else
+ type = MLXSW_SP_FID_TYPE_RFID;
+
+ return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type);
+}
+
#define MLXSW_SP_INVALID_INDEX_RIF 0xffff
static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
{
@@ -2927,34 +2991,13 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
return MLXSW_SP_INVALID_INDEX_RIF;
}
-static int
-mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_rif *rif, bool create)
-{
- struct mlxsw_sp_rif_subport *rif_subport;
- char ritr_pl[MLXSW_REG_RITR_LEN];
-
- rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common);
- mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF,
- rif->rif_index, rif->vr_id, rif->dev->mtu,
- rif->dev->dev_addr);
- mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
- rif_subport->lag ? rif_subport->lag_id :
- rif_subport->system_port,
- rif_subport->vid);
-
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
-}
-
-static struct mlxsw_sp_rif *
-mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
- struct mlxsw_sp_fid *fid, bool is_subport)
+static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index,
+ u16 vr_id,
+ struct net_device *l3_dev)
{
- size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) :
- sizeof(struct mlxsw_sp_rif);
struct mlxsw_sp_rif *rif;
- rif = kzalloc(size, GFP_KERNEL);
+ rif = kzalloc(rif_size, GFP_KERNEL);
if (!rif)
return NULL;
@@ -2965,7 +3008,6 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
rif->vr_id = vr_id;
rif->dev = l3_dev;
rif->rif_index = rif_index;
- rif->fid = fid;
return rif;
}
@@ -2987,19 +3029,21 @@ int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif)
}
static struct mlxsw_sp_rif *
-mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
- struct net_device *l3_dev)
+mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_rif_params *params)
{
- struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- struct mlxsw_sp_rif_subport *rif_subport;
- u32 tb_id = l3mdev_fib_table(l3_dev);
+ u32 tb_id = l3mdev_fib_table(params->dev);
+ const struct mlxsw_sp_rif_ops *ops;
+ enum mlxsw_sp_rif_type type;
struct mlxsw_sp_rif *rif;
struct mlxsw_sp_fid *fid;
struct mlxsw_sp_vr *vr;
u16 rif_index;
int err;
+ type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev);
+ ops = mlxsw_sp->router->rif_ops_arr[type];
+
vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
if (IS_ERR(vr))
return ERR_CAST(vr);
@@ -3010,46 +3054,34 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
goto err_avail_rif_get;
}
- fid = mlxsw_sp_fid_rfid_get(mlxsw_sp, rif_index);
- if (IS_ERR(fid)) {
- err = PTR_ERR(fid);
- goto err_fid_get;
- }
-
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, true);
+ rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev);
if (!rif) {
err = -ENOMEM;
goto err_rif_alloc;
}
+ rif->mlxsw_sp = mlxsw_sp;
+ rif->ops = ops;
- rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common);
- rif_subport->vid = mlxsw_sp_port_vlan->vid;
- if (mlxsw_sp_port->lagged) {
- rif_subport->lag = true;
- rif_subport->lag_id = mlxsw_sp_port->lag_id;
- } else {
- rif_subport->lag = false;
- rif_subport->system_port = mlxsw_sp_port->local_port;
+ fid = ops->fid_get(rif);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ goto err_fid_get;
}
+ rif->fid = fid;
- err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, true);
+ if (ops->setup)
+ ops->setup(rif, params);
+
+ err = ops->configure(rif);
if (err)
- goto err_port_vlan_rif_sp_op;
+ goto err_configure;
- err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr,
+ err = mlxsw_sp_rif_fdb_op(mlxsw_sp, params->dev->dev_addr,
mlxsw_sp_fid_index(fid), true);
if (err)
goto err_rif_fdb_op;
- if (devlink_dpipe_table_counter_enabled(priv_to_devlink(mlxsw_sp->core),
- MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) {
- err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
- MLXSW_SP_RIF_COUNTER_EGRESS);
- if (err)
- netdev_dbg(mlxsw_sp_port->dev,
- "Counter alloc Failed err=%d\n", err);
- }
-
+ mlxsw_sp_rif_counters_alloc(rif);
mlxsw_sp_fid_rif_set(fid, rif);
mlxsw_sp->router->rifs[rif_index] = rif;
vr->rif_count++;
@@ -3057,43 +3089,53 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
return rif;
err_rif_fdb_op:
- mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false);
-err_port_vlan_rif_sp_op:
- kfree(rif);
-err_rif_alloc:
+ ops->deconfigure(rif);
+err_configure:
mlxsw_sp_fid_put(fid);
err_fid_get:
+ kfree(rif);
+err_rif_alloc:
err_avail_rif_get:
mlxsw_sp_vr_put(vr);
return ERR_PTR(err);
}
-static void
-mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_rif *rif)
+void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
{
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
- struct net_device *l3_dev = rif->dev;
+ const struct mlxsw_sp_rif_ops *ops = rif->ops;
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
struct mlxsw_sp_fid *fid = rif->fid;
- u16 rif_index = rif->rif_index;
+ struct mlxsw_sp_vr *vr;
mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
-
- mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
- mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_INGRESS);
+ vr = &mlxsw_sp->router->vrs[rif->vr_id];
vr->rif_count--;
- mlxsw_sp->router->rifs[rif_index] = NULL;
+ mlxsw_sp->router->rifs[rif->rif_index] = NULL;
mlxsw_sp_fid_rif_set(fid, NULL);
-
- mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid),
- false);
- mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false);
- kfree(rif);
+ mlxsw_sp_rif_counters_free(rif);
+ mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->dev->dev_addr,
+ mlxsw_sp_fid_index(fid), false);
+ ops->deconfigure(rif);
mlxsw_sp_fid_put(fid);
+ kfree(rif);
mlxsw_sp_vr_put(vr);
}
+static void
+mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
+ struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
+
+ params->vid = mlxsw_sp_port_vlan->vid;
+ params->lag = mlxsw_sp_port->lagged;
+ if (params->lag)
+ params->lag_id = mlxsw_sp_port->lag_id;
+ else
+ params->system_port = mlxsw_sp_port->local_port;
+}
+
static int
mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
struct net_device *l3_dev)
@@ -3107,14 +3149,18 @@ mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
if (!rif) {
- rif = mlxsw_sp_port_vlan_rif_sp_create(mlxsw_sp_port_vlan,
- l3_dev);
+ struct mlxsw_sp_rif_params params = {
+ .dev = l3_dev,
+ };
+
+ mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan);
+ rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms);
if (IS_ERR(rif))
return PTR_ERR(rif);
}
/* FID was already created, just take a reference */
- fid = mlxsw_sp_fid_rfid_get(mlxsw_sp_port->mlxsw_sp, rif->rif_index);
+ fid = rif->ops->fid_get(rif);
err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
if (err)
goto err_fid_port_vid_map;
@@ -3225,166 +3271,24 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1);
}
-static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
-{
- return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
-}
-
-static enum mlxsw_reg_ritr_if_type
-mlxsw_sp_rif_type_ritr_if_type(enum mlxsw_sp_rif_type rif_type)
-{
- switch (rif_type) {
- case MLXSW_SP_RIF_TYPE_SUBPORT:
- return MLXSW_REG_RITR_SP_IF;
- case MLXSW_SP_RIF_TYPE_VLAN:
- return MLXSW_REG_RITR_VLAN_IF;
- case MLXSW_SP_RIF_TYPE_FID:
- return MLXSW_REG_RITR_FID_IF;
- default:
- WARN_ON(1);
- return 0;
- }
-}
-
-static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_rif *rif, bool create)
-{
- enum mlxsw_reg_ritr_if_type ritr_if_type;
- enum mlxsw_sp_rif_type rif_type;
- char ritr_pl[MLXSW_REG_RITR_LEN];
-
- rif_type = mlxsw_sp_fid_rif_type(rif->fid);
- ritr_if_type = mlxsw_sp_rif_type_ritr_if_type(rif_type);
- mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index,
- rif->vr_id, rif->dev->mtu, rif->dev->dev_addr);
- mlxsw_reg_ritr_fid_set(ritr_pl, ritr_if_type,
- mlxsw_sp_fid_index(rif->fid));
-
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
-}
-
-static struct mlxsw_sp_fid *
-mlxsw_sp_rif_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
- const struct net_device *dev)
-{
- if (netif_is_bridge_master(dev) && !br_vlan_enabled(dev))
- return mlxsw_sp_fid_8021d_get(mlxsw_sp, dev->ifindex);
- else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
- return mlxsw_sp_fid_8021q_get(mlxsw_sp, 1);
- else if (is_vlan_dev(dev) &&
- netif_is_bridge_master(vlan_dev_real_dev(dev)))
- return mlxsw_sp_fid_8021q_get(mlxsw_sp, vlan_dev_vlan_id(dev));
- else
- return ERR_PTR(-EINVAL);
-}
-
-static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev)
-{
- u32 tb_id = l3mdev_fib_table(l3_dev);
- struct mlxsw_sp_rif *rif;
- struct mlxsw_sp_fid *fid;
- struct mlxsw_sp_vr *vr;
- u16 rif_index;
- int err;
-
- vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
- if (IS_ERR(vr))
- return PTR_ERR(vr);
-
- rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp);
- if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) {
- err = -ERANGE;
- goto err_avail_rif_get;
- }
-
- fid = mlxsw_sp_rif_bridge_fid_get(mlxsw_sp, l3_dev);
- if (IS_ERR(fid)) {
- err = PTR_ERR(fid);
- goto err_fid_get;
- }
-
- rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, false);
- if (!rif) {
- err = -ENOMEM;
- goto err_rif_alloc;
- }
-
- err = mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, true);
- if (err)
- goto err_rif_bridge_op;
-
- err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC,
- mlxsw_sp_router_port(mlxsw_sp), true);
- if (err)
- goto err_fid_bc_flood_set;
-
- err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr,
- mlxsw_sp_fid_index(fid), true);
- if (err)
- goto err_rif_fdb_op;
-
- mlxsw_sp_fid_rif_set(fid, rif);
- mlxsw_sp->router->rifs[rif_index] = rif;
- vr->rif_count++;
-
- netdev_dbg(l3_dev, "RIF=%d created\n", rif_index);
-
- return 0;
-
-err_rif_fdb_op:
- mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC,
- mlxsw_sp_router_port(mlxsw_sp), false);
-err_fid_bc_flood_set:
- mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
-err_rif_bridge_op:
- kfree(rif);
-err_rif_alloc:
- mlxsw_sp_fid_put(fid);
-err_fid_get:
-err_avail_rif_get:
- mlxsw_sp_vr_put(vr);
- return err;
-}
-
-static void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_rif *rif)
-{
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
- struct net_device *l3_dev = rif->dev;
- struct mlxsw_sp_fid *fid = rif->fid;
- u16 rif_index = rif->rif_index;
-
- mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
-
- vr->rif_count--;
- mlxsw_sp->router->rifs[rif_index] = NULL;
- mlxsw_sp_fid_rif_set(fid, NULL);
-
- mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid),
- false);
- mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC,
- mlxsw_sp_router_port(mlxsw_sp), false);
- mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false);
- kfree(rif);
- mlxsw_sp_fid_put(fid);
- mlxsw_sp_vr_put(vr);
-
- netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index);
-}
-
static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
unsigned long event)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
+ struct mlxsw_sp_rif_params params = {
+ .dev = l3_dev,
+ };
struct mlxsw_sp_rif *rif;
switch (event) {
case NETDEV_UP:
- return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev);
+ rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms);
+ if (IS_ERR(rif))
+ return PTR_ERR(rif);
+ break;
case NETDEV_DOWN:
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif);
+ mlxsw_sp_rif_destroy(rif);
break;
}
@@ -3555,14 +3459,189 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
return err;
}
-void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif)
+static struct mlxsw_sp_rif_subport *
+mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
{
- if (mlxsw_sp_fid_rif_type(rif->fid) == MLXSW_SP_RIF_TYPE_SUBPORT)
- mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif);
+ return container_of(rif, struct mlxsw_sp_rif_subport, common);
+}
+
+static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
+ const struct mlxsw_sp_rif_params *params)
+{
+ struct mlxsw_sp_rif_subport *rif_subport;
+
+ rif_subport = mlxsw_sp_rif_subport_rif(rif);
+ rif_subport->vid = params->vid;
+ rif_subport->lag = params->lag;
+ if (params->lag)
+ rif_subport->lag_id = params->lag_id;
else
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif);
+ rif_subport->system_port = params->system_port;
+}
+
+static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ struct mlxsw_sp_rif_subport *rif_subport;
+ char ritr_pl[MLXSW_REG_RITR_LEN];
+
+ rif_subport = mlxsw_sp_rif_subport_rif(rif);
+ mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
+ rif->rif_index, rif->vr_id, rif->dev->mtu,
+ rif->dev->dev_addr);
+ mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
+ rif_subport->lag ? rif_subport->lag_id :
+ rif_subport->system_port,
+ rif_subport->vid);
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+}
+
+static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif)
+{
+ return mlxsw_sp_rif_subport_op(rif, true);
}
+static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
+{
+ mlxsw_sp_rif_subport_op(rif, false);
+}
+
+static struct mlxsw_sp_fid *
+mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif)
+{
+ return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
+}
+
+static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = {
+ .type = MLXSW_SP_RIF_TYPE_SUBPORT,
+ .rif_size = sizeof(struct mlxsw_sp_rif_subport),
+ .setup = mlxsw_sp_rif_subport_setup,
+ .configure = mlxsw_sp_rif_subport_configure,
+ .deconfigure = mlxsw_sp_rif_subport_deconfigure,
+ .fid_get = mlxsw_sp_rif_subport_fid_get,
+};
+
+static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
+ enum mlxsw_reg_ritr_if_type type,
+ u16 vid_fid, bool enable)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ char ritr_pl[MLXSW_REG_RITR_LEN];
+
+ mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
+ rif->dev->mtu, rif->dev->dev_addr);
+ mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+}
+
+static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
+{
+ return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
+}
+
+static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
+ int err;
+
+ err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), true);
+ if (err)
+ goto err_fid_bc_flood_set;
+
+ return 0;
+
+err_fid_bc_flood_set:
+ mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
+ return err;
+}
+
+static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
+
+ mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), false);
+ mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
+}
+
+static struct mlxsw_sp_fid *
+mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif)
+{
+ u16 vid = is_vlan_dev(rif->dev) ? vlan_dev_vlan_id(rif->dev) : 1;
+
+ return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
+}
+
+static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = {
+ .type = MLXSW_SP_RIF_TYPE_VLAN,
+ .rif_size = sizeof(struct mlxsw_sp_rif),
+ .configure = mlxsw_sp_rif_vlan_configure,
+ .deconfigure = mlxsw_sp_rif_vlan_deconfigure,
+ .fid_get = mlxsw_sp_rif_vlan_fid_get,
+};
+
+static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ u16 fid_index = mlxsw_sp_fid_index(rif->fid);
+ int err;
+
+ err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
+ true);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), true);
+ if (err)
+ goto err_fid_bc_flood_set;
+
+ return 0;
+
+err_fid_bc_flood_set:
+ mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
+ return err;
+}
+
+static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+ u16 fid_index = mlxsw_sp_fid_index(rif->fid);
+
+ mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+ mlxsw_sp_router_port(mlxsw_sp), false);
+ mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
+}
+
+static struct mlxsw_sp_fid *
+mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif)
+{
+ return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex);
+}
+
+static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
+ .type = MLXSW_SP_RIF_TYPE_FID,
+ .rif_size = sizeof(struct mlxsw_sp_rif),
+ .configure = mlxsw_sp_rif_fid_configure,
+ .deconfigure = mlxsw_sp_rif_fid_deconfigure,
+ .fid_get = mlxsw_sp_rif_fid_fid_get,
+};
+
+static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = {
+ [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
+ [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_ops,
+ [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
+};
+
static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
{
u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
@@ -3572,6 +3651,9 @@ static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
GFP_KERNEL);
if (!mlxsw_sp->router->rifs)
return -ENOMEM;
+
+ mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr;
+
return 0;
}
--
2.9.3
^ permalink raw reply related
* Re: [RFC] skbuff: introduce skb_put_zero()
From: Johannes Berg @ 2017-05-26 6:58 UTC (permalink / raw)
To: David Miller; +Cc: linux-wireless, netdev
In-Reply-To: <20170525.130117.551364108206528221.davem@davemloft.net>
On Thu, 2017-05-25 at 13:01 -0400, David Miller wrote:
> From: Johannes Berg <johannes@sipsolutions.net>
> Date: Wed, 24 May 2017 09:07:47 +0200
>
> > From: Johannes Berg <johannes.berg@intel.com>
> >
> > This pattern was introduced a number of times in mac80211 just now,
> > and since it's present in a number of other places it makes sense
> > to add a little helper for it.
> >
> > The transformations of all code were done with the following
> spatch:
[...]
> > NB: the patch won't apply to net-next because a few of the mac80211
> > users don't exist there yet
>
> Acked-by: David S. Miller <davem@davemloft.net>
>
> No objections, feel free to push this in via your mac80211 tree.
Do you think I should include the conversions in other drivers, or
would you prefer to get those as a separate patch later?
johannes
^ permalink raw reply
* Re: [PATCH net v2] sctp: fix ICMP processing if skb is non-linear
From: Xin Long @ 2017-05-26 7:02 UTC (permalink / raw)
To: Davide Caratti
Cc: network dev, linux-sctp, Marcelo Ricardo Leitner,
David S . Miller
In-Reply-To: <d0cd7c2e4b9329ec23e48aed94bf2fbf94554f44.1495730857.git.dcaratti@redhat.com>
On Fri, May 26, 2017 at 1:14 AM, Davide Caratti <dcaratti@redhat.com> wrote:
> sometimes ICMP replies to INIT chunks are ignored by the client, even if
> the encapsulated SCTP headers match an open socket. This happens when the
> ICMP packet is carried by a paged skb: use skb_header_pointer() to read
> packet contents beyond the SCTP header, so that chunk header and initiate
> tag are validated correctly.
>
> v2:
> - don't use skb_header_pointer() to read the transport header, since
> icmp_socket_deliver() already puts these 8 bytes in the linear area.
> - change commit message to make specific reference to INIT chunks.
>
> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Thanks.
Reviewed-by: Xin Long <lucien.xin@gmail.com>
> ---
> net/sctp/input.c | 16 +++++++++-------
> 1 file changed, 9 insertions(+), 7 deletions(-)
>
> diff --git a/net/sctp/input.c b/net/sctp/input.c
> index 0e06a27..ba9ad32 100644
> --- a/net/sctp/input.c
> +++ b/net/sctp/input.c
> @@ -473,15 +473,14 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
> struct sctp_association **app,
> struct sctp_transport **tpp)
> {
> + struct sctp_init_chunk *chunkhdr, _chunkhdr;
> union sctp_addr saddr;
> union sctp_addr daddr;
> struct sctp_af *af;
> struct sock *sk = NULL;
> struct sctp_association *asoc;
> struct sctp_transport *transport = NULL;
> - struct sctp_init_chunk *chunkhdr;
> __u32 vtag = ntohl(sctphdr->vtag);
> - int len = skb->len - ((void *)sctphdr - (void *)skb->data);
>
> *app = NULL; *tpp = NULL;
>
> @@ -516,13 +515,16 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
> * discard the packet.
> */
> if (vtag == 0) {
> - chunkhdr = (void *)sctphdr + sizeof(struct sctphdr);
> - if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t)
> - + sizeof(__be32) ||
> + /* chunk header + first 4 octects of init header */
> + chunkhdr = skb_header_pointer(skb, skb_transport_offset(skb) +
> + sizeof(struct sctphdr),
> + sizeof(struct sctp_chunkhdr) +
> + sizeof(__be32), &_chunkhdr);
> + if (!chunkhdr ||
> chunkhdr->chunk_hdr.type != SCTP_CID_INIT ||
> - ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) {
> + ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag)
> goto out;
> - }
> +
> } else if (vtag != asoc->c.peer_vtag) {
> goto out;
> }
> --
> 2.9.4
>
^ permalink raw reply
* [patch net-next] net/sched: let chain_get to figure out the return value
From: Jiri Pirko @ 2017-05-26 7:21 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, xiyou.wangcong, mlxsw
From: Jiri Pirko <jiri@mellanox.com>
Alhough I believe that this create/nocreate dance is completelly
pointless, at least make it a bit nicer and easier to read.
Push the decision on what error value is returned to chain_get function
and use ERR macros.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
net/sched/act_api.c | 4 ++--
net/sched/cls_api.c | 15 ++++++---------
2 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index aed6cf2..42bb75a 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -35,8 +35,8 @@ static int tcf_action_goto_chain_init(struct tc_action *a, struct tcf_proto *tp)
if (!tp)
return -EINVAL;
a->goto_chain = tcf_chain_get(tp->chain->block, chain_index, true);
- if (!a->goto_chain)
- return -ENOMEM;
+ if (IS_ERR(a->goto_chain))
+ return PTR_ERR(a->goto_chain);
return 0;
}
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 39da0c5..deec814 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -193,7 +193,7 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (!chain)
- return NULL;
+ return ERR_PTR(-ENOMEM);
list_add_tail(&chain->list, &block->chain_list);
chain->block = block;
chain->index = chain_index;
@@ -231,10 +231,7 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
return chain;
}
}
- if (create)
- return tcf_chain_create(block, chain_index);
- else
- return NULL;
+ return create ? tcf_chain_create(block, chain_index) : ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL(tcf_chain_get);
@@ -267,8 +264,8 @@ int tcf_block_get(struct tcf_block **p_block,
INIT_LIST_HEAD(&block->chain_list);
/* Create chain 0 by default, it has to be always present. */
chain = tcf_chain_create(block, 0);
- if (!chain) {
- err = -ENOMEM;
+ if (IS_ERR(chain)) {
+ err = PTR_ERR(chain);
goto err_chain_create;
}
tcf_chain_filter_chain_ptr_set(chain, p_filter_chain);
@@ -517,8 +514,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}
chain = tcf_chain_get(block, chain_index,
n->nlmsg_type == RTM_NEWTFILTER);
- if (!chain) {
- err = n->nlmsg_type == RTM_NEWTFILTER ? -ENOMEM : -EINVAL;
+ if (IS_ERR(chain)) {
+ err = PTR_ERR(chain);
goto errout;
}
--
2.9.3
^ permalink raw reply related
* [PATCH v3 0/2] net: phy: Support managed Cortina phys
From: Bogdan Purcareata @ 2017-05-26 7:58 UTC (permalink / raw)
To: andrew-g2DYL2Zd6BY, f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
So far, the Cortina family phys (CS4340 in this particular case) are only
supported in fixed link mode (via fixed_phy_register). The generic 10G
phy driver does not work well with the phylib state machine, when the phy
is registered via of_phy_connect. This prohibits the user from describing the
phy nodes in the device tree.
In order to support this scenario, and to properly describe the board
device tree, add a minimal Cortina driver that reads the status from the
right register. With the generic 10G C45 driver, the kernel will print
messages like:
[ 0.226521] mdio_bus 8b96000: Error while reading PHY16 reg at 1.6
[ 0.232780] mdio_bus 8b96000: Error while reading PHY16 reg at 1.5
v2 -> v3:
- Add documentation entry.
v1 -> v2:
- Change approach for getting the phy_id from hacking get_phy_c45_ids to
describing the device in the device tree via ethernet-phy-id.
More patch version changes per individual patches.
Bogdan Purcareata (2):
net: phy: Add Cortina CS4340 driver
dt-bindings: net: Add Cortina device tree bindings
Documentation/devicetree/bindings/net/cortina.txt | 19 ++++
drivers/net/phy/Kconfig | 5 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/cortina.c | 115 ++++++++++++++++++++++
4 files changed, 140 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/cortina.txt
create mode 100644 drivers/net/phy/cortina.c
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v3 1/2] net: phy: Add Cortina CS4340 driver
From: Bogdan Purcareata @ 2017-05-26 7:58 UTC (permalink / raw)
To: andrew, f.fainelli, netdev, devicetree, linux-kernel
In-Reply-To: <1495785519-1468-1-git-send-email-bogdan.purcareata@nxp.com>
Add basic support for Cortina PHY drivers. Support only CS4340 for now.
The phys are not compatible with IEEE 802.3 clause 22/45 registers.
Implement proper read_status support. The generic 10G phy driver causes
bus register access errors.
The driver should be described using the "ethernet-phy-id" device tree
compatible.
Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
---
v2 -> v3:
- Add probe function to check the device we're talking with is the same
as the one described in the device tree.
- Change the link status (GPIO interrupt status) register and validate
that the read is done from the right place (cable plug-in / plug-out).
- Some functions + Kconfig entry renaming.
v1 -> v2:
- Rename "mdio-cortina.c" to "cortina.c" since it's a phy driver.
- Test probing based on the "ethernet-phy-id" compatible. In the previous
version, getting the phy_id via get_phy_c45_ids() involved an additional
hack. Drop that approach and document probing in the commit message.
drivers/net/phy/Kconfig | 5 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/cortina.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 121 insertions(+)
create mode 100644 drivers/net/phy/cortina.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 22dea7f..8cd7a0e 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -240,6 +240,11 @@ config CICADA_PHY
---help---
Currently supports the cis8204
+config CORTINA_PHY
+ tristate "Cortina EDC CDR 10G Ethernet PHY"
+ ---help---
+ Currently supports the CS4340 phy.
+
config DAVICOM_PHY
tristate "Davicom PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 79365be..0de3e20 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o
obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o
+obj-$(CONFIG_CORTINA_PHY) += cortina.o
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_DP83848_PHY) += dp83848.o
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
new file mode 100644
index 0000000..209c022
--- /dev/null
+++ b/drivers/net/phy/cortina.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define PHY_ID_CS4340 0x13e51002
+
+#define VILLA_GLOBAL_CHIP_ID_LSB 0x0
+#define VILLA_GLOBAL_CHIP_ID_MSB 0x1
+
+#define VILLA_GLOBAL_GPIO_1_INTS 0x017
+
+static int cortina_read_reg(struct phy_device *phydev, u16 regnum)
+{
+ return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
+ MII_ADDR_C45 | regnum);
+}
+
+static int cortina_config_aneg(struct phy_device *phydev)
+{
+ phydev->supported = SUPPORTED_10000baseT_Full;
+ phydev->advertising = SUPPORTED_10000baseT_Full;
+
+ return 0;
+}
+
+static int cortina_read_status(struct phy_device *phydev)
+{
+ int gpio_int_status, ret = 0;
+
+ gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS);
+ if (gpio_int_status < 0) {
+ ret = gpio_int_status;
+ goto err;
+ }
+
+ if (gpio_int_status & 0x8) {
+ /* up when edc_convergedS set */
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+ phydev->link = 1;
+ } else {
+ phydev->link = 0;
+ }
+
+err:
+ return ret;
+}
+
+static int cortina_soft_reset(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static int cortina_probe(struct phy_device *phydev)
+{
+ u32 phy_id = 0, id_lsb, id_msb;
+
+ /* Read device id from phy registers. */
+ id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB);
+ if (id_lsb < 0)
+ return -ENXIO;
+
+ phy_id = id_lsb << 16;
+
+ id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB);
+ if (id_msb < 0)
+ return -ENXIO;
+
+ phy_id |= id_msb;
+
+ /* Make sure the device tree binding matched the driver with the
+ * right device.
+ */
+ if (phy_id != phydev->drv->phy_id) {
+ phydev_err(phydev, "Error matching phy with %s driver\n",
+ phydev->drv->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static struct phy_driver cortina_driver[] = {
+{
+ .phy_id = PHY_ID_CS4340,
+ .phy_id_mask = 0xffffffff,
+ .name = "Cortina CS4340",
+ .config_aneg = cortina_config_aneg,
+ .read_status = cortina_read_status,
+ .soft_reset = cortina_soft_reset,
+ .probe = cortina_probe,
+},
+};
+
+module_phy_driver(cortina_driver);
+
+static struct mdio_device_id __maybe_unused cortina_tbl[] = {
+ { PHY_ID_CS4340, 0xffffffff},
+ {},
+};
+
+MODULE_DEVICE_TABLE(mdio, cortina_tbl);
--
1.9.1
^ permalink raw reply related
* [PATCH v3 2/2] dt-bindings: net: Add Cortina device tree bindings
From: Bogdan Purcareata @ 2017-05-26 7:58 UTC (permalink / raw)
To: andrew, f.fainelli, netdev, devicetree, linux-kernel
In-Reply-To: <1495785519-1468-1-git-send-email-bogdan.purcareata@nxp.com>
Add device tree description info for Cortina 10G phy devices.
Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
---
Patch introduced in v3 of the patchset.
Documentation/devicetree/bindings/net/cortina.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/cortina.txt
diff --git a/Documentation/devicetree/bindings/net/cortina.txt b/Documentation/devicetree/bindings/net/cortina.txt
new file mode 100644
index 0000000..006a1ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/cortina.txt
@@ -0,0 +1,19 @@
+Cortina Phy Driver Device Tree Bindings
+---------------------------------------
+
+The driver supports the Cortina Electronic Dispersion Compensation (EDC)
+devices, equipped with clock and data recovery (CDR) circuits. These
+devices make use of registers that are not compatible with Clause 45 or
+Clause 22, therefore they need to be described using the
+"ethernet-phy-id" compatible.
+
+Since the driver only implements polling mode support, interrupts info
+can be skipped.
+
+Example (CS4340 phy):
+ mdio {
+ cs4340_phy@1 {
+ compatible = "ethernet-phy-id13e5.1002";
+ reg = <0x10>;
+ };
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v2 0/6] nfp: devlink port implementation
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Jakub Kicinski
Hi!
This series adds basic devlink support. The operations we can perform
are port show and port split/unsplit.
v2:
Register devlink first, and then register all the ports. Port {,un}split
searches the port list, which is protected by a mutex. If port split
is requested before ports are registered we will simply not find the port
and return -EINVAL.
Jakub Kicinski (5):
nfp: move mutex init out of net code
nfp: add helper for cleaning up vNICs
nfp: register ports as devlink ports
nfp: calculate total port lanes for split
nfp: support port splitting via devlink
Simon Horman (1):
nfp: add devlink support
drivers/net/ethernet/netronome/nfp/Makefile | 1 +
drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 181 +++++++++++++++++++++
drivers/net/ethernet/netronome/nfp/nfp_main.c | 28 +++-
drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 +
drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 61 ++++---
drivers/net/ethernet/netronome/nfp/nfp_port.c | 19 +++
drivers/net/ethernet/netronome/nfp/nfp_port.h | 12 ++
.../net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 3 +
.../ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c | 11 +-
9 files changed, 289 insertions(+), 30 deletions(-)
create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_devlink.c
--
2.11.0
^ permalink raw reply
* [PATCH net-next v2 1/6] nfp: move mutex init out of net code
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Jakub Kicinski
In-Reply-To: <20170526080336.32689-1-jakub.kicinski@netronome.com>
Move mutex init to main file close to structure allocation.
This will allow mutex to be taken before net code runs (e.g.
from devlink callbacks). While at it remember to destroy
the mutex.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/nfp_main.c | 4 ++++
drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 1 -
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c
index bb586ce1ea06..3a131559153a 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c
@@ -41,6 +41,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/vermagic.h>
@@ -342,6 +343,7 @@ static int nfp_pci_probe(struct pci_dev *pdev,
}
INIT_LIST_HEAD(&pf->vnics);
INIT_LIST_HEAD(&pf->ports);
+ mutex_init(&pf->lock);
pci_set_drvdata(pdev, pf);
pf->pdev = pdev;
@@ -380,6 +382,7 @@ static int nfp_pci_probe(struct pci_dev *pdev,
nfp_cpp_free(pf->cpp);
err_disable_msix:
pci_set_drvdata(pdev, NULL);
+ mutex_destroy(&pf->lock);
kfree(pf);
err_rel_regions:
pci_release_regions(pdev);
@@ -404,6 +407,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
nfp_cpp_free(pf->cpp);
kfree(pf->eth_tbl);
+ mutex_destroy(&pf->lock);
kfree(pf);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index dd1118c7e1a4..5139c13b6e53 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -641,7 +641,6 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
int err;
INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics);
- mutex_init(&pf->lock);
/* Verify that the board has completed initialization */
if (!nfp_is_ready(pf->cpp)) {
--
2.11.0
^ permalink raw reply related
* [PATCH net-next v2 3/6] nfp: add helper for cleaning up vNICs
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Jakub Kicinski
In-Reply-To: <20170526080336.32689-1-jakub.kicinski@netronome.com>
We will soon have to invoke more clean up for vNICs.
Move the cleanup callbacks into a helper.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index 8f5a240c8d2f..b0a6ec4fe097 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -418,6 +418,12 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
return err;
}
+static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn)
+{
+ nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
+ nfp_net_clean(nn);
+}
+
static int
nfp_net_pf_spawn_vnics(struct nfp_pf *pf,
void __iomem *ctrl_bar, void __iomem *tx_bar,
@@ -480,10 +486,8 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf,
return 0;
err_prev_deinit:
- list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) {
- nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
- nfp_net_clean(nn);
- }
+ list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list)
+ nfp_net_pf_clean_vnic(pf, nn);
nfp_net_irqs_disable(pf->pdev);
err_vec_free:
kfree(pf->irq_entries);
@@ -585,9 +589,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
if (!nn->port || nn->port->type != NFP_PORT_INVALID)
continue;
- nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
- nfp_net_clean(nn);
-
+ nfp_net_pf_clean_vnic(pf, nn);
nfp_net_pf_free_vnic(pf, nn);
}
@@ -760,11 +762,8 @@ void nfp_net_pci_remove(struct nfp_pf *pf)
if (list_empty(&pf->vnics))
goto out;
- list_for_each_entry(nn, &pf->vnics, vnic_list) {
- nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
-
- nfp_net_clean(nn);
- }
+ list_for_each_entry(nn, &pf->vnics, vnic_list)
+ nfp_net_pf_clean_vnic(pf, nn);
nfp_net_pf_free_vnics(pf);
--
2.11.0
^ permalink raw reply related
* [PATCH net-next v2 2/6] nfp: add devlink support
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Simon Horman, Jakub Kicinski
In-Reply-To: <20170526080336.32689-1-jakub.kicinski@netronome.com>
From: Simon Horman <simon.horman@netronome.com>
Add initial devlink support. This patch simply switches allocation
of per-adapter structure to devlink's priv and register devlink
with empty ops table. See following patches for implementation
of particular ops.
We should now clear the app pointer on exit, this is how devlink
callbacks will know app is not initialized.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/Makefile | 1 +
drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 39 +++++++++++++++++++++++
drivers/net/ethernet/netronome/nfp/nfp_main.c | 24 +++++++++++---
drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 ++
drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 1 +
5 files changed, 63 insertions(+), 5 deletions(-)
create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_devlink.c
diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile
index e8333283ada6..95f6b97b5d71 100644
--- a/drivers/net/ethernet/netronome/nfp/Makefile
+++ b/drivers/net/ethernet/netronome/nfp/Makefile
@@ -15,6 +15,7 @@ nfp-objs := \
nfpcore/nfp_rtsym.o \
nfpcore/nfp_target.o \
nfp_app.o \
+ nfp_devlink.o \
nfp_main.o \
nfp_net_common.o \
nfp_net_ethtool.o \
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
new file mode 100644
index 000000000000..a8a52b3ff42b
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Netronome Systems, Inc.
+ *
+ * This software is dual licensed under the GNU General License Version 2,
+ * June 1991 as shown in the file COPYING in the top-level directory of this
+ * source tree or the BSD 2-Clause License provided below. You have the
+ * option to license this software under the complete terms of either license.
+ *
+ * The BSD 2-Clause License:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <net/devlink.h>
+
+#include "nfp_main.h"
+
+const struct devlink_ops nfp_devlink_ops = {
+};
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c
index 3a131559153a..f22f56c9218f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c
@@ -45,6 +45,7 @@
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/vermagic.h>
+#include <net/devlink.h>
#include "nfpcore/nfp.h"
#include "nfpcore/nfp_cpp.h"
@@ -316,6 +317,7 @@ static void nfp_fw_unload(struct nfp_pf *pf)
static int nfp_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
+ struct devlink *devlink;
struct nfp_pf *pf;
int err;
@@ -336,11 +338,12 @@ static int nfp_pci_probe(struct pci_dev *pdev,
goto err_pci_disable;
}
- pf = kzalloc(sizeof(*pf), GFP_KERNEL);
- if (!pf) {
+ devlink = devlink_alloc(&nfp_devlink_ops, sizeof(*pf));
+ if (!devlink) {
err = -ENOMEM;
goto err_rel_regions;
}
+ pf = devlink_priv(devlink);
INIT_LIST_HEAD(&pf->vnics);
INIT_LIST_HEAD(&pf->ports);
mutex_init(&pf->lock);
@@ -362,10 +365,14 @@ static int nfp_pci_probe(struct pci_dev *pdev,
nfp_hwinfo_lookup(pf->cpp, "assembly.revision"),
nfp_hwinfo_lookup(pf->cpp, "cpld.version"));
- err = nfp_nsp_init(pdev, pf);
+ err = devlink_register(devlink, &pdev->dev);
if (err)
goto err_cpp_free;
+ err = nfp_nsp_init(pdev, pf);
+ if (err)
+ goto err_devlink_unreg;
+
nfp_pcie_sriov_read_nfd_limit(pf);
err = nfp_net_pci_probe(pf);
@@ -378,12 +385,14 @@ static int nfp_pci_probe(struct pci_dev *pdev,
if (pf->fw_loaded)
nfp_fw_unload(pf);
kfree(pf->eth_tbl);
+err_devlink_unreg:
+ devlink_unregister(devlink);
err_cpp_free:
nfp_cpp_free(pf->cpp);
err_disable_msix:
pci_set_drvdata(pdev, NULL);
mutex_destroy(&pf->lock);
- kfree(pf);
+ devlink_free(devlink);
err_rel_regions:
pci_release_regions(pdev);
err_pci_disable:
@@ -395,11 +404,16 @@ static int nfp_pci_probe(struct pci_dev *pdev,
static void nfp_pci_remove(struct pci_dev *pdev)
{
struct nfp_pf *pf = pci_get_drvdata(pdev);
+ struct devlink *devlink;
+
+ devlink = priv_to_devlink(pf);
nfp_net_pci_remove(pf);
nfp_pcie_sriov_disable(pdev);
+ devlink_unregister(devlink);
+
if (pf->fw_loaded)
nfp_fw_unload(pf);
@@ -408,7 +422,7 @@ static void nfp_pci_remove(struct pci_dev *pdev)
kfree(pf->eth_tbl);
mutex_destroy(&pf->lock);
- kfree(pf);
+ devlink_free(devlink);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h
index 991c4cba0bbf..526db8029dea 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h
@@ -47,6 +47,7 @@
#include <linux/workqueue.h>
struct dentry;
+struct devlink_ops;
struct pci_dev;
struct nfp_cpp;
@@ -107,6 +108,8 @@ struct nfp_pf {
extern struct pci_driver nfp_netvf_pci_driver;
+extern const struct devlink_ops nfp_devlink_ops;
+
int nfp_net_pci_probe(struct nfp_pf *pf);
void nfp_net_pci_remove(struct nfp_pf *pf);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index 5139c13b6e53..8f5a240c8d2f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -502,6 +502,7 @@ static int nfp_net_pf_app_init(struct nfp_pf *pf)
static void nfp_net_pf_app_clean(struct nfp_pf *pf)
{
nfp_app_free(pf->app);
+ pf->app = NULL;
}
static void nfp_net_pci_remove_finish(struct nfp_pf *pf)
--
2.11.0
^ permalink raw reply related
* [PATCH net-next v2 4/6] nfp: register ports as devlink ports
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Jakub Kicinski
In-Reply-To: <20170526080336.32689-1-jakub.kicinski@netronome.com>
Extend nfp_port to contain devlink_port structures. Register the
ports to allow users inspecting device ports.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 45 +++++++++++++++++++++++
drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 13 +++++++
drivers/net/ethernet/netronome/nfp/nfp_port.h | 8 ++++
3 files changed, 66 insertions(+)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index a8a52b3ff42b..2cfcb66b04bb 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -31,9 +31,54 @@
* SOFTWARE.
*/
+#include <linux/rtnetlink.h>
#include <net/devlink.h>
+#include "nfpcore/nfp_nsp.h"
+#include "nfp_app.h"
#include "nfp_main.h"
+#include "nfp_port.h"
+
+static int
+nfp_devlink_fill_eth_port(struct nfp_port *port,
+ struct nfp_eth_table_port *copy)
+{
+ struct nfp_eth_table_port *eth_port;
+
+ eth_port = __nfp_port_get_eth_port(port);
+ if (!eth_port)
+ return -EINVAL;
+
+ memcpy(copy, eth_port, sizeof(*eth_port));
+
+ return 0;
+}
const struct devlink_ops nfp_devlink_ops = {
};
+
+int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
+{
+ struct nfp_eth_table_port eth_port;
+ struct devlink *devlink;
+ int ret;
+
+ rtnl_lock();
+ ret = nfp_devlink_fill_eth_port(port, ð_port);
+ rtnl_unlock();
+ if (ret)
+ return ret;
+
+ devlink_port_type_eth_set(&port->dl_port, port->netdev);
+ if (eth_port.is_split)
+ devlink_port_split_set(&port->dl_port, eth_port.label_port);
+
+ devlink = priv_to_devlink(app->pf);
+
+ return devlink_port_register(devlink, &port->dl_port, port->eth_id);
+}
+
+void nfp_devlink_port_unregister(struct nfp_port *port)
+{
+ devlink_port_unregister(&port->dl_port);
+}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index b0a6ec4fe097..b733c97677fb 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -354,9 +354,20 @@ nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id)
nfp_net_debugfs_vnic_add(nn, pf->ddir, id);
+ if (nn->port) {
+ err = nfp_devlink_port_register(pf->app, nn->port);
+ if (err)
+ goto err_dfs_clean;
+ }
+
nfp_net_info(nn);
return 0;
+
+err_dfs_clean:
+ nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
+ nfp_net_clean(nn);
+ return err;
}
static int
@@ -420,6 +431,8 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn)
{
+ if (nn->port)
+ nfp_devlink_port_unregister(nn->port);
nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
nfp_net_clean(nn);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h
index 641617de41cc..36a540b514be 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_port.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h
@@ -34,6 +34,8 @@
#ifndef _NFP_PORT_H_
#define _NFP_PORT_H_
+#include <net/devlink.h>
+
struct net_device;
struct nfp_app;
struct nfp_port;
@@ -66,6 +68,7 @@ enum nfp_port_flags {
* @type: what port type does the entity represent
* @flags: port flags
* @app: backpointer to the app structure
+ * @dl_port: devlink port structure
* @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme
* @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry
* @port_list: entry on pf's list of ports
@@ -78,6 +81,8 @@ struct nfp_port {
struct nfp_app *app;
+ struct devlink_port dl_port;
+
unsigned int eth_id;
struct nfp_eth_table_port *eth_port;
@@ -99,4 +104,7 @@ void nfp_port_free(struct nfp_port *port);
int nfp_net_refresh_eth_port(struct nfp_port *port);
void nfp_net_refresh_port_table(struct nfp_port *port);
+int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port);
+void nfp_devlink_port_unregister(struct nfp_port *port);
+
#endif
--
2.11.0
^ permalink raw reply related
* [PATCH net-next v2 5/6] nfp: calculate total port lanes for split
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Jakub Kicinski
In-Reply-To: <20170526080336.32689-1-jakub.kicinski@netronome.com>
For port splitting we will need to know the total number of lanes
in a port. Calculate that based on eth_table information.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
---
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 3 +++
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c | 11 ++++++-----
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
index 36b21e4dc56d..84a1d20adae1 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
@@ -96,6 +96,7 @@ enum nfp_eth_aneg {
* @override_changed: is media reconfig pending?
*
* @port_type: one of %PORT_* defines for ethtool
+ * @port_lanes: total number of lanes on the port (sum of lanes of all subports)
* @is_split: is interface part of a split port
*/
struct nfp_eth_table {
@@ -127,6 +128,8 @@ struct nfp_eth_table {
/* Computed fields */
u8 port_type;
+ unsigned int port_lanes;
+
bool is_split;
} ports[0];
};
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
index 639438d8313a..b0f8785c064f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
@@ -186,17 +186,19 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
}
static void
-nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table)
+nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table)
{
unsigned int i, j;
for (i = 0; i < table->count; i++)
for (j = 0; j < table->count; j++) {
- if (i == j)
- continue;
if (table->ports[i].label_port !=
table->ports[j].label_port)
continue;
+ table->ports[i].port_lanes += table->ports[j].lanes;
+
+ if (i == j)
+ continue;
if (table->ports[i].label_subport ==
table->ports[j].label_subport)
nfp_warn(cpp,
@@ -205,7 +207,6 @@ nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table)
table->ports[i].label_subport);
table->ports[i].is_split = true;
- break;
}
}
@@ -289,7 +290,7 @@ __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp)
nfp_eth_port_translate(nsp, &entries[i], i,
&table->ports[j++]);
- nfp_eth_mark_split_ports(cpp, table);
+ nfp_eth_calc_port_geometry(cpp, table);
for (i = 0; i < table->count; i++)
nfp_eth_calc_port_type(cpp, &table->ports[i]);
--
2.11.0
^ permalink raw reply related
* [PATCH net-next v2 6/6] nfp: support port splitting via devlink
From: Jakub Kicinski @ 2017-05-26 8:03 UTC (permalink / raw)
To: netdev; +Cc: jiri, oss-drivers, Jakub Kicinski
In-Reply-To: <20170526080336.32689-1-jakub.kicinski@netronome.com>
Add support for configuring port split with devlink. Add devlink
callbacks to validate requested config and call NSP helpers.
Getting the right nfp_port structure can be done with simple iteration.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
---
drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 97 +++++++++++++++++++++++
drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 23 ++++--
drivers/net/ethernet/netronome/nfp/nfp_port.c | 19 +++++
drivers/net/ethernet/netronome/nfp/nfp_port.h | 4 +
4 files changed, 136 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index 2cfcb66b04bb..2609a0f28e81 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -54,7 +54,104 @@ nfp_devlink_fill_eth_port(struct nfp_port *port,
return 0;
}
+static int
+nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index,
+ struct nfp_eth_table_port *copy)
+{
+ struct nfp_port *port;
+
+ port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index);
+
+ return nfp_devlink_fill_eth_port(port, copy);
+}
+
+static int
+nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
+{
+ struct nfp_nsp *nsp;
+ int ret;
+
+ nsp = nfp_eth_config_start(pf->cpp, idx);
+ if (IS_ERR(nsp))
+ return PTR_ERR(nsp);
+
+ ret = __nfp_eth_set_split(nsp, lanes);
+ if (ret) {
+ nfp_eth_config_cleanup_end(nsp);
+ return ret;
+ }
+
+ ret = nfp_eth_config_commit_end(nsp);
+ if (ret < 0)
+ return ret;
+ if (ret) /* no change */
+ return 0;
+
+ return nfp_net_refresh_port_table_sync(pf);
+}
+
+static int
+nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
+ unsigned int count)
+{
+ struct nfp_pf *pf = devlink_priv(devlink);
+ struct nfp_eth_table_port eth_port;
+ int ret;
+
+ if (count < 2)
+ return -EINVAL;
+
+ mutex_lock(&pf->lock);
+
+ rtnl_lock();
+ ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port);
+ rtnl_unlock();
+ if (ret)
+ goto out;
+
+ if (eth_port.is_split || eth_port.port_lanes % count) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = nfp_devlink_set_lanes(pf, eth_port.index,
+ eth_port.port_lanes / count);
+out:
+ mutex_unlock(&pf->lock);
+
+ return ret;
+}
+
+static int
+nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index)
+{
+ struct nfp_pf *pf = devlink_priv(devlink);
+ struct nfp_eth_table_port eth_port;
+ int ret;
+
+ mutex_lock(&pf->lock);
+
+ rtnl_lock();
+ ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port);
+ rtnl_unlock();
+ if (ret)
+ goto out;
+
+ if (!eth_port.is_split) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes);
+out:
+ mutex_unlock(&pf->lock);
+
+ return ret;
+}
+
const struct devlink_ops nfp_devlink_ops = {
+ .port_split = nfp_devlink_port_split,
+ .port_unsplit = nfp_devlink_port_unsplit,
};
int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index b733c97677fb..388759e047d8 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -43,6 +43,7 @@
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/lockdep.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/msi.h>
@@ -561,19 +562,17 @@ nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port,
return 0;
}
-static void nfp_net_refresh_vnics(struct work_struct *work)
+int nfp_net_refresh_port_table_sync(struct nfp_pf *pf)
{
- struct nfp_pf *pf = container_of(work, struct nfp_pf,
- port_refresh_work);
struct nfp_eth_table *eth_table;
struct nfp_net *nn, *next;
struct nfp_port *port;
- mutex_lock(&pf->lock);
+ lockdep_assert_held(&pf->lock);
/* Check for nfp_net_pci_remove() racing against us */
if (list_empty(&pf->vnics))
- goto out;
+ return 0;
/* Update state of all ports */
rtnl_lock();
@@ -587,7 +586,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
set_bit(NFP_PORT_CHANGED, &port->flags);
rtnl_unlock();
nfp_err(pf->cpp, "Error refreshing port config!\n");
- goto out;
+ return -EIO;
}
list_for_each_entry(port, &pf->ports, port_list)
@@ -608,7 +607,17 @@ static void nfp_net_refresh_vnics(struct work_struct *work)
if (list_empty(&pf->vnics))
nfp_net_pci_remove_finish(pf);
-out:
+
+ return 0;
+}
+
+static void nfp_net_refresh_vnics(struct work_struct *work)
+{
+ struct nfp_pf *pf = container_of(work, struct nfp_pf,
+ port_refresh_work);
+
+ mutex_lock(&pf->lock);
+ nfp_net_refresh_port_table_sync(pf);
mutex_unlock(&pf->lock);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c
index 3beed4167e2f..a17410ac01ab 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_port.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c
@@ -31,6 +31,8 @@
* SOFTWARE.
*/
+#include <linux/lockdep.h>
+
#include "nfpcore/nfp_nsp.h"
#include "nfp_app.h"
#include "nfp_main.h"
@@ -48,6 +50,23 @@ struct nfp_port *nfp_port_from_netdev(struct net_device *netdev)
return nn->port;
}
+struct nfp_port *
+nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id)
+{
+ struct nfp_port *port;
+
+ lockdep_assert_held(&pf->lock);
+
+ if (type != NFP_PORT_PHYS_PORT)
+ return NULL;
+
+ list_for_each_entry(port, &pf->ports, port_list)
+ if (port->eth_id == id)
+ return port;
+
+ return NULL;
+}
+
struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port)
{
if (!port)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h
index 36a540b514be..4d1a9b3fed41 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_port.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h
@@ -38,6 +38,7 @@
struct net_device;
struct nfp_app;
+struct nfp_pf;
struct nfp_port;
/**
@@ -90,6 +91,8 @@ struct nfp_port {
};
struct nfp_port *nfp_port_from_netdev(struct net_device *netdev);
+struct nfp_port *
+nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id);
struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port);
struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port);
@@ -103,6 +106,7 @@ void nfp_port_free(struct nfp_port *port);
int nfp_net_refresh_eth_port(struct nfp_port *port);
void nfp_net_refresh_port_table(struct nfp_port *port);
+int nfp_net_refresh_port_table_sync(struct nfp_pf *pf);
int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port);
void nfp_devlink_port_unregister(struct nfp_port *port);
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 1/5] MIPS: Optimize uasm insn lookup.
From: Matt Redfearn @ 2017-05-26 8:07 UTC (permalink / raw)
To: David Daney, Alexei Starovoitov, Daniel Borkmann, netdev,
linux-kernel, linux-mips, ralf
In-Reply-To: <20170526003826.10834-2-david.daney@cavium.com>
Hi David,
On 26/05/17 01:38, David Daney wrote:
> Instead of doing a linear search through the insn_table for each
> instruction, use the opcode as direct index into the table. This will
> give constant time lookup performance as the number of supported
> opcodes increases. Make the tables const as they are only ever read.
> For uasm-mips.c sort the table alphabetically, and remove duplicate
> entries, uasm-micromips.c was already sorted and duplicate free.
> There is a small savings in object size as struct insn loses a field:
>
> $ size arch/mips/mm/uasm-mips.o arch/mips/mm/uasm-mips.o.save
> text data bss dec hex filename
> 10040 0 0 10040 2738 arch/mips/mm/uasm-mips.o
> 9240 1120 0 10360 2878 arch/mips/mm/uasm-mips.o.save
>
> Signed-off-by: David Daney <david.daney@cavium.com>
> ---
> arch/mips/mm/uasm-micromips.c | 188 ++++++++++++++++++------------------
> arch/mips/mm/uasm-mips.c | 217 +++++++++++++++++++++---------------------
> arch/mips/mm/uasm.c | 3 +-
> 3 files changed, 199 insertions(+), 209 deletions(-)
>
> diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c
> index 277cf52..da6de62 100644
> --- a/arch/mips/mm/uasm-micromips.c
> +++ b/arch/mips/mm/uasm-micromips.c
> @@ -40,93 +40,92 @@
>
> #include "uasm.c"
>
> -static struct insn insn_table_MM[] = {
> - { insn_addu, M(mm_pool32a_op, 0, 0, 0, 0, mm_addu32_op), RT | RS | RD },
> - { insn_addiu, M(mm_addiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
> - { insn_and, M(mm_pool32a_op, 0, 0, 0, 0, mm_and_op), RT | RS | RD },
> - { insn_andi, M(mm_andi32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
> - { insn_beq, M(mm_beq32_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
> - { insn_beql, 0, 0 },
> - { insn_bgez, M(mm_pool32i_op, mm_bgez_op, 0, 0, 0, 0), RS | BIMM },
> - { insn_bgezl, 0, 0 },
> - { insn_bltz, M(mm_pool32i_op, mm_bltz_op, 0, 0, 0, 0), RS | BIMM },
> - { insn_bltzl, 0, 0 },
> - { insn_bne, M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM },
> - { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM },
> - { insn_cfc1, M(mm_pool32f_op, 0, 0, 0, mm_cfc1_op, mm_32f_73_op), RT | RS },
> - { insn_cfcmsa, M(mm_pool32s_op, 0, msa_cfc_op, 0, 0, mm_32s_elm_op), RD | RE },
> - { insn_ctc1, M(mm_pool32f_op, 0, 0, 0, mm_ctc1_op, mm_32f_73_op), RT | RS },
> - { insn_ctcmsa, M(mm_pool32s_op, 0, msa_ctc_op, 0, 0, mm_32s_elm_op), RD | RE },
> - { insn_daddu, 0, 0 },
> - { insn_daddiu, 0, 0 },
> - { insn_di, M(mm_pool32a_op, 0, 0, 0, mm_di_op, mm_pool32axf_op), RS },
> - { insn_divu, M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS },
> - { insn_dmfc0, 0, 0 },
> - { insn_dmtc0, 0, 0 },
> - { insn_dsll, 0, 0 },
> - { insn_dsll32, 0, 0 },
> - { insn_dsra, 0, 0 },
> - { insn_dsrl, 0, 0 },
> - { insn_dsrl32, 0, 0 },
> - { insn_drotr, 0, 0 },
> - { insn_drotr32, 0, 0 },
> - { insn_dsubu, 0, 0 },
> - { insn_eret, M(mm_pool32a_op, 0, 0, 0, mm_eret_op, mm_pool32axf_op), 0 },
> - { insn_ins, M(mm_pool32a_op, 0, 0, 0, 0, mm_ins_op), RT | RS | RD | RE },
> - { insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE },
> - { insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM },
> - { insn_jal, M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM },
> - { insn_jalr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RT | RS },
> - { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS },
> - { insn_lb, M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
> - { insn_ld, 0, 0 },
> - { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM },
> - { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM },
> - { insn_lld, 0, 0 },
> - { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM },
> - { insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
> - { insn_mfc0, M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD },
> - { insn_mfhi, M(mm_pool32a_op, 0, 0, 0, mm_mfhi32_op, mm_pool32axf_op), RS },
> - { insn_mflo, M(mm_pool32a_op, 0, 0, 0, mm_mflo32_op, mm_pool32axf_op), RS },
> - { insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD },
> - { insn_mthi, M(mm_pool32a_op, 0, 0, 0, mm_mthi32_op, mm_pool32axf_op), RS },
> - { insn_mtlo, M(mm_pool32a_op, 0, 0, 0, mm_mtlo32_op, mm_pool32axf_op), RS },
> - { insn_mul, M(mm_pool32a_op, 0, 0, 0, 0, mm_mul_op), RT | RS | RD },
> - { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD },
> - { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
> - { insn_pref, M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM },
> - { insn_rfe, 0, 0 },
> - { insn_sc, M(mm_pool32c_op, 0, 0, (mm_sc_func << 1), 0, 0), RT | RS | SIMM },
> - { insn_scd, 0, 0 },
> - { insn_sd, 0, 0 },
> - { insn_sll, M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD },
> - { insn_sllv, M(mm_pool32a_op, 0, 0, 0, 0, mm_sllv32_op), RT | RS | RD },
> - { insn_slt, M(mm_pool32a_op, 0, 0, 0, 0, mm_slt_op), RT | RS | RD },
> - { insn_sltiu, M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
> - { insn_sltu, M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD },
> - { insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD },
> - { insn_srl, M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD },
> - { insn_srlv, M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD },
> - { insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD },
> - { insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD },
> - { insn_sw, M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
> - { insn_sync, M(mm_pool32a_op, 0, 0, 0, mm_sync_op, mm_pool32axf_op), RS },
> - { insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 },
> - { insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 },
> - { insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 },
> - { insn_tlbwr, M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0 },
> - { insn_wait, M(mm_pool32a_op, 0, 0, 0, mm_wait_op, mm_pool32axf_op), SCIMM },
> - { insn_wsbh, M(mm_pool32a_op, 0, 0, 0, mm_wsbh_op, mm_pool32axf_op), RT | RS },
> - { insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD },
> - { insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
> - { insn_dins, 0, 0 },
> - { insn_dinsm, 0, 0 },
> - { insn_syscall, M(mm_pool32a_op, 0, 0, 0, mm_syscall_op, mm_pool32axf_op), SCIMM},
> - { insn_bbit0, 0, 0 },
> - { insn_bbit1, 0, 0 },
> - { insn_lwx, 0, 0 },
> - { insn_ldx, 0, 0 },
> - { insn_invalid, 0, 0 }
> +static struct insn insn_table_MM[insn_invalid] = {
^ You could make this const too, like you have the one in uasm-mips.c.
Thanks,
Matt
> + [insn_addu] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_addu32_op), RT | RS | RD},
> + [insn_addiu] = {M(mm_addiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
> + [insn_and] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_and_op), RT | RS | RD},
> + [insn_andi] = {M(mm_andi32_op, 0, 0, 0, 0, 0), RT | RS | UIMM},
> + [insn_beq] = {M(mm_beq32_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
> + [insn_beql] = {0, 0},
> + [insn_bgez] = {M(mm_pool32i_op, mm_bgez_op, 0, 0, 0, 0), RS | BIMM},
> + [insn_bgezl] = {0, 0},
> + [insn_bltz] = {M(mm_pool32i_op, mm_bltz_op, 0, 0, 0, 0), RS | BIMM},
> + [insn_bltzl] = {0, 0},
> + [insn_bne] = {M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM},
> + [insn_cache] = {M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM},
> + [insn_cfc1] = {M(mm_pool32f_op, 0, 0, 0, mm_cfc1_op, mm_32f_73_op), RT | RS},
> + [insn_cfcmsa] = {M(mm_pool32s_op, 0, msa_cfc_op, 0, 0, mm_32s_elm_op), RD | RE},
> + [insn_ctc1] = {M(mm_pool32f_op, 0, 0, 0, mm_ctc1_op, mm_32f_73_op), RT | RS},
> + [insn_ctcmsa] = {M(mm_pool32s_op, 0, msa_ctc_op, 0, 0, mm_32s_elm_op), RD | RE},
> + [insn_daddu] = {0, 0},
> + [insn_daddiu] = {0, 0},
> + [insn_di] = {M(mm_pool32a_op, 0, 0, 0, mm_di_op, mm_pool32axf_op), RS},
> + [insn_divu] = {M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS},
> + [insn_dmfc0] = {0, 0},
> + [insn_dmtc0] = {0, 0},
> + [insn_dsll] = {0, 0},
> + [insn_dsll32] = {0, 0},
> + [insn_dsra] = {0, 0},
> + [insn_dsrl] = {0, 0},
> + [insn_dsrl32] = {0, 0},
> + [insn_drotr] = {0, 0},
> + [insn_drotr32] = {0, 0},
> + [insn_dsubu] = {0, 0},
> + [insn_eret] = {M(mm_pool32a_op, 0, 0, 0, mm_eret_op, mm_pool32axf_op), 0},
> + [insn_ins] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_ins_op), RT | RS | RD | RE},
> + [insn_ext] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE},
> + [insn_j] = {M(mm_j32_op, 0, 0, 0, 0, 0), JIMM},
> + [insn_jal] = {M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM},
> + [insn_jalr] = {M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RT | RS},
> + [insn_jr] = {M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS},
> + [insn_lb] = {M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
> + [insn_ld] = {0, 0},
> + [insn_lh] = {M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM},
> + [insn_ll] = {M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM},
> + [insn_lld] = {0, 0},
> + [insn_lui] = {M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM},
> + [insn_lw] = {M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
> + [insn_mfc0] = {M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD},
> + [insn_mfhi] = {M(mm_pool32a_op, 0, 0, 0, mm_mfhi32_op, mm_pool32axf_op), RS},
> + [insn_mflo] = {M(mm_pool32a_op, 0, 0, 0, mm_mflo32_op, mm_pool32axf_op), RS},
> + [insn_mtc0] = {M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD},
> + [insn_mthi] = {M(mm_pool32a_op, 0, 0, 0, mm_mthi32_op, mm_pool32axf_op), RS},
> + [insn_mtlo] = {M(mm_pool32a_op, 0, 0, 0, mm_mtlo32_op, mm_pool32axf_op), RS},
> + [insn_mul] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_mul_op), RT | RS | RD},
> + [insn_or] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD},
> + [insn_ori] = {M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM},
> + [insn_pref] = {M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM},
> + [insn_rfe] = {0, 0},
> + [insn_sc] = {M(mm_pool32c_op, 0, 0, (mm_sc_func << 1), 0, 0), RT | RS | SIMM},
> + [insn_scd] = {0, 0},
> + [insn_sd] = {0, 0},
> + [insn_sll] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD},
> + [insn_sllv] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sllv32_op), RT | RS | RD},
> + [insn_slt] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_slt_op), RT | RS | RD},
> + [insn_sltiu] = {M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
> + [insn_sltu] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD},
> + [insn_sra] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD},
> + [insn_srl] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD},
> + [insn_srlv] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD},
> + [insn_rotr] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD},
> + [insn_subu] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD},
> + [insn_sw] = {M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
> + [insn_sync] = {M(mm_pool32a_op, 0, 0, 0, mm_sync_op, mm_pool32axf_op), RS},
> + [insn_tlbp] = {M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0},
> + [insn_tlbr] = {M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0},
> + [insn_tlbwi] = {M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0},
> + [insn_tlbwr] = {M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0},
> + [insn_wait] = {M(mm_pool32a_op, 0, 0, 0, mm_wait_op, mm_pool32axf_op), SCIMM},
> + [insn_wsbh] = {M(mm_pool32a_op, 0, 0, 0, mm_wsbh_op, mm_pool32axf_op), RT | RS},
> + [insn_xor] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD},
> + [insn_xori] = {M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM},
> + [insn_dins] = {0, 0},
> + [insn_dinsm] = {0, 0},
> + [insn_syscall] = {M(mm_pool32a_op, 0, 0, 0, mm_syscall_op, mm_pool32axf_op), SCIMM},
> + [insn_bbit0] = {0, 0},
> + [insn_bbit1] = {0, 0},
> + [insn_lwx] = {0, 0},
> + [insn_ldx] = {0, 0},
> };
>
> #undef M
> @@ -156,20 +155,17 @@ static inline u32 build_jimm(u32 arg)
> */
> static void build_insn(u32 **buf, enum opcode opc, ...)
> {
> - struct insn *ip = NULL;
> - unsigned int i;
> + const struct insn *ip;
> va_list ap;
> u32 op;
>
> - for (i = 0; insn_table_MM[i].opcode != insn_invalid; i++)
> - if (insn_table_MM[i].opcode == opc) {
> - ip = &insn_table_MM[i];
> - break;
> - }
> -
> - if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
> + if (opc < 0 || opc >= insn_invalid ||
> + (opc == insn_daddiu && r4k_daddiu_bug()) ||
> + (insn_table_MM[opc].match == 0 && insn_table_MM[opc].fields == 0))
> panic("Unsupported Micro-assembler instruction %d", opc);
>
> + ip = &insn_table_MM[opc];
> +
> op = ip->match;
> va_start(ap, opc);
> if (ip->fields & RS) {
> diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c
> index 2277499..f3937e3 100644
> --- a/arch/mips/mm/uasm-mips.c
> +++ b/arch/mips/mm/uasm-mips.c
> @@ -48,126 +48,124 @@
>
> #include "uasm.c"
>
> -static struct insn insn_table[] = {
> - { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
> - { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
> - { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
> - { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
> - { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
> - { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
> - { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
> - { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
> - { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
> - { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
> - { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
> - { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
> +static const struct insn const insn_table[insn_invalid] = {
> + [insn_addiu] = {M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_addu] = {M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD},
> + [insn_and] = {M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD},
> + [insn_andi] = {M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM},
> + [insn_bbit0] = {M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
> + [insn_bbit1] = {M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
> + [insn_beq] = {M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
> + [insn_beql] = {M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
> + [insn_bgez] = {M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM},
> + [insn_bgezl] = {M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM},
> + [insn_bltz] = {M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM},
> + [insn_bltzl] = {M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM},
> + [insn_bne] = {M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM},
> #ifndef CONFIG_CPU_MIPSR6
> - { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> + [insn_cache] = {M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> #else
> - { insn_cache, M6(spec3_op, 0, 0, 0, cache6_op), RS | RT | SIMM9 },
> + [insn_cache] = {M6(spec3_op, 0, 0, 0, cache6_op), RS | RT | SIMM9},
> #endif
> - { insn_cfc1, M(cop1_op, cfc_op, 0, 0, 0, 0), RT | RD },
> - { insn_cfcmsa, M(msa_op, 0, msa_cfc_op, 0, 0, msa_elm_op), RD | RE },
> - { insn_ctc1, M(cop1_op, ctc_op, 0, 0, 0, 0), RT | RD },
> - { insn_ctcmsa, M(msa_op, 0, msa_ctc_op, 0, 0, msa_elm_op), RD | RE },
> - { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
> - { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
> - { insn_di, M(cop0_op, mfmc0_op, 0, 12, 0, 0), RT },
> - { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
> - { insn_divu, M(spec_op, 0, 0, 0, 0, divu_op), RS | RT },
> - { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
> - { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
> - { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
> - { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
> - { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
> - { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
> - { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
> - { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
> - { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
> - { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
> - { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
> - { insn_ext, M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE },
> - { insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE },
> - { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
> - { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
> - { insn_jalr, M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD },
> - { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
> + [insn_cfc1] = {M(cop1_op, cfc_op, 0, 0, 0, 0), RT | RD},
> + [insn_cfcmsa] = {M(msa_op, 0, msa_cfc_op, 0, 0, msa_elm_op), RD | RE},
> + [insn_ctc1] = {M(cop1_op, ctc_op, 0, 0, 0, 0), RT | RD},
> + [insn_ctcmsa] = {M(msa_op, 0, msa_ctc_op, 0, 0, msa_elm_op), RD | RE},
> + [insn_daddiu] = {M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_daddu] = {M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD},
> + [insn_di] = {M(cop0_op, mfmc0_op, 0, 12, 0, 0), RT},
> + [insn_dins] = {M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE},
> + [insn_dinsm] = {M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE},
> + [insn_divu] = {M(spec_op, 0, 0, 0, 0, divu_op), RS | RT},
> + [insn_dmfc0] = {M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
> + [insn_dmtc0] = {M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
> + [insn_drotr] = {M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE},
> + [insn_drotr32] = {M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE},
> + [insn_dsll] = {M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE},
> + [insn_dsll32] = {M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE},
> + [insn_dsra] = {M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE},
> + [insn_dsrl] = {M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE},
> + [insn_dsrl32] = {M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE},
> + [insn_dsubu] = {M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD},
> + [insn_eret] = {M(cop0_op, cop_op, 0, 0, 0, eret_op), 0},
> + [insn_ext] = {M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE},
> + [insn_ins] = {M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE},
> + [insn_j] = {M(j_op, 0, 0, 0, 0, 0), JIMM},
> + [insn_jal] = {M(jal_op, 0, 0, 0, 0, 0), JIMM},
> + [insn_jalr] = {M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD},
> #ifndef CONFIG_CPU_MIPSR6
> - { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
> + [insn_jr] = {M(spec_op, 0, 0, 0, 0, jr_op), RS},
> #else
> - { insn_jr, M(spec_op, 0, 0, 0, 0, jalr_op), RS },
> + [insn_jr] = {M(spec_op, 0, 0, 0, 0, jalr_op), RS},
> #endif
> - { insn_lb, M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
> - { insn_lh, M(lh_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_lhu, M(lhu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> + [insn_lb] = {M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_ld] = {M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_lddir] = {M(lwc2_op, 0, 0, 0, lddir_op, mult_op), RS | RT | RD},
> + [insn_ldpte] = {M(lwc2_op, 0, 0, 0, ldpte_op, mult_op), RS | RD},
> + [insn_ldx] = {M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD},
> + [insn_lh] = {M(lh_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_lhu] = {M(lhu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> #ifndef CONFIG_CPU_MIPSR6
> - { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> + [insn_ll] = {M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_lld] = {M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> #else
> - { insn_lld, M6(spec3_op, 0, 0, 0, lld6_op), RS | RT | SIMM9 },
> - { insn_ll, M6(spec3_op, 0, 0, 0, ll6_op), RS | RT | SIMM9 },
> + [insn_ll] = {M6(spec3_op, 0, 0, 0, ll6_op), RS | RT | SIMM9},
> + [insn_lld] = {M6(spec3_op, 0, 0, 0, lld6_op), RS | RT | SIMM9},
> #endif
> - { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
> - { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
> - { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
> - { insn_mfhc0, M(cop0_op, mfhc0_op, 0, 0, 0, 0), RT | RD | SET},
> - { insn_mfhi, M(spec_op, 0, 0, 0, 0, mfhi_op), RD },
> - { insn_mflo, M(spec_op, 0, 0, 0, 0, mflo_op), RD },
> - { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
> - { insn_mthc0, M(cop0_op, mthc0_op, 0, 0, 0, 0), RT | RD | SET},
> - { insn_mthi, M(spec_op, 0, 0, 0, 0, mthi_op), RS },
> - { insn_mtlo, M(spec_op, 0, 0, 0, 0, mtlo_op), RS },
> + [insn_lui] = {M(lui_op, 0, 0, 0, 0, 0), RT | SIMM},
> + [insn_lw] = {M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_lwx] = {M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD},
> + [insn_mfc0] = {M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
> + [insn_mfhc0] = {M(cop0_op, mfhc0_op, 0, 0, 0, 0), RT | RD | SET},
> + [insn_mfhi] = {M(spec_op, 0, 0, 0, 0, mfhi_op), RD},
> + [insn_mflo] = {M(spec_op, 0, 0, 0, 0, mflo_op), RD},
> + [insn_mtc0] = {M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
> + [insn_mthc0] = {M(cop0_op, mthc0_op, 0, 0, 0, 0), RT | RD | SET},
> + [insn_mthi] = {M(spec_op, 0, 0, 0, 0, mthi_op), RS},
> + [insn_mtlo] = {M(spec_op, 0, 0, 0, 0, mtlo_op), RS},
> #ifndef CONFIG_CPU_MIPSR6
> - { insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
> + [insn_mul] = {M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
> #else
> - { insn_mul, M(spec_op, 0, 0, 0, mult_mul_op, mult_op), RS | RT | RD},
> + [insn_mul] = {M(spec_op, 0, 0, 0, mult_mul_op, mult_op), RS | RT | RD},
> #endif
> - { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
> - { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD },
> + [insn_or] = {M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD},
> + [insn_ori] = {M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM},
> #ifndef CONFIG_CPU_MIPSR6
> - { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> + [insn_pref] = {M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> #else
> - { insn_pref, M6(spec3_op, 0, 0, 0, pref6_op), RS | RT | SIMM9 },
> + [insn_pref] = {M6(spec3_op, 0, 0, 0, pref6_op), RS | RT | SIMM9},
> #endif
> - { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
> - { insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE },
> + [insn_rfe] = {M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0},
> + [insn_rotr] = {M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE},
> #ifndef CONFIG_CPU_MIPSR6
> - { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> + [insn_sc] = {M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_scd] = {M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> #else
> - { insn_scd, M6(spec3_op, 0, 0, 0, scd6_op), RS | RT | SIMM9 },
> - { insn_sc, M6(spec3_op, 0, 0, 0, sc6_op), RS | RT | SIMM9 },
> + [insn_sc] = {M6(spec3_op, 0, 0, 0, sc6_op), RS | RT | SIMM9},
> + [insn_scd] = {M6(spec3_op, 0, 0, 0, scd6_op), RS | RT | SIMM9},
> #endif
> - { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
> - { insn_sllv, M(spec_op, 0, 0, 0, 0, sllv_op), RS | RT | RD },
> - { insn_slt, M(spec_op, 0, 0, 0, 0, slt_op), RS | RT | RD },
> - { insn_sltiu, M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_sltu, M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD },
> - { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE },
> - { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE },
> - { insn_srlv, M(spec_op, 0, 0, 0, 0, srlv_op), RS | RT | RD },
> - { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD },
> - { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
> - { insn_sync, M(spec_op, 0, 0, 0, 0, sync_op), RE },
> - { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
> - { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 },
> - { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 },
> - { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 },
> - { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 },
> - { insn_wait, M(cop0_op, cop_op, 0, 0, 0, wait_op), SCIMM },
> - { insn_wsbh, M(spec3_op, 0, 0, 0, wsbh_op, bshfl_op), RT | RD },
> - { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
> - { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
> - { insn_yield, M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD },
> - { insn_ldpte, M(lwc2_op, 0, 0, 0, ldpte_op, mult_op), RS | RD },
> - { insn_lddir, M(lwc2_op, 0, 0, 0, lddir_op, mult_op), RS | RT | RD },
> - { insn_invalid, 0, 0 }
> + [insn_sd] = {M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_sll] = {M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE},
> + [insn_sllv] = {M(spec_op, 0, 0, 0, 0, sllv_op), RS | RT | RD},
> + [insn_slt] = {M(spec_op, 0, 0, 0, 0, slt_op), RS | RT | RD},
> + [insn_sltiu] = {M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_sltu] = {M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD},
> + [insn_sra] = {M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE},
> + [insn_srl] = {M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE},
> + [insn_srlv] = {M(spec_op, 0, 0, 0, 0, srlv_op), RS | RT | RD},
> + [insn_subu] = {M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD},
> + [insn_sw] = {M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
> + [insn_sync] = {M(spec_op, 0, 0, 0, 0, sync_op), RE},
> + [insn_syscall] = {M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
> + [insn_tlbp] = {M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0},
> + [insn_tlbr] = {M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0},
> + [insn_tlbwi] = {M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0},
> + [insn_tlbwr] = {M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0},
> + [insn_wait] = {M(cop0_op, cop_op, 0, 0, 0, wait_op), SCIMM},
> + [insn_wsbh] = {M(spec3_op, 0, 0, 0, wsbh_op, bshfl_op), RT | RD},
> + [insn_xor] = {M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD},
> + [insn_xori] = {M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM},
> + [insn_yield] = {M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD},
> };
>
> #undef M
> @@ -196,20 +194,17 @@ static inline u32 build_jimm(u32 arg)
> */
> static void build_insn(u32 **buf, enum opcode opc, ...)
> {
> - struct insn *ip = NULL;
> - unsigned int i;
> + const struct insn *ip;
> va_list ap;
> u32 op;
>
> - for (i = 0; insn_table[i].opcode != insn_invalid; i++)
> - if (insn_table[i].opcode == opc) {
> - ip = &insn_table[i];
> - break;
> - }
> -
> - if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
> + if (opc < 0 || opc >= insn_invalid ||
> + (opc == insn_daddiu && r4k_daddiu_bug()) ||
> + (insn_table[opc].match == 0 && insn_table[opc].fields == 0))
> panic("Unsupported Micro-assembler instruction %d", opc);
>
> + ip = &insn_table[opc];
> +
> op = ip->match;
> va_start(ap, opc);
> if (ip->fields & RS)
> diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
> index 730363b..f23ed85 100644
> --- a/arch/mips/mm/uasm.c
> +++ b/arch/mips/mm/uasm.c
> @@ -46,7 +46,6 @@ enum fields {
> #define SIMM9_MASK 0x1ff
>
> enum opcode {
> - insn_invalid,
> insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
> insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
> insn_bne, insn_cache, insn_cfc1, insn_cfcmsa, insn_ctc1, insn_ctcmsa,
> @@ -62,10 +61,10 @@ enum opcode {
> insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, insn_tlbp,
> insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, insn_xor,
> insn_xori, insn_yield, insn_lddir, insn_ldpte, insn_lhu,
> + insn_invalid /* insn_invalid must be last */
> };
>
> struct insn {
> - enum opcode opcode;
> u32 match;
> enum fields fields;
> };
^ permalink raw reply
* Re: Deleting a dynamic mac entry..
From: Toshiaki Makita @ 2017-05-26 8:15 UTC (permalink / raw)
To: Manohar Kumar; +Cc: netdev, bridge
In-Reply-To: <CA+N+6-wErt=9XX6u8tPnLbb2DrLqADOnCBn3mDe=qvxCoLCFyg@mail.gmail.com>
On 2017/05/26 14:08, Manohar Kumar wrote:
> On Wed, May 24, 2017 at 6:11 PM, Toshiaki Makita
> <makita.toshiaki@lab.ntt.co.jp> wrote:
>> On 2017/05/25 3:05, Manohar Kumar wrote:
>>> Thanks, Toshiaki.
>>>
>>> What is the right way to set the default_pvid using the bridge command
>>> ? I tried this, which fails..
>>>
>>> root@net-3:~# ip link set dev vxlan0 name untagged type vlan id 0
>>> RTNETLINK answers: Operation not supported
>>> root@net-3:~#
>>>
>>> All the interfaces in the bridge are untagged.
>>
>> # ip link set br0 down
>> # echo 0 > /sys/class/net/br0/bridge/default_pvid
>>
>
> I have the bridge inside a network namespace. There is no
> /sys/class/net entry for the bridge interface inside the namespace.
>
> I see online references to this concept of 'tagged' sysfs directories
> to support namespaces. But its not clear how to access the sysfs
> entries for a particular namespace.
Did you remount /sys after entering netns?
If not, remount /sys or use "ip netns" which automatically do it.
> Is there any other way to set the default_pvid for the bridge
> interface inside namespace ?
No, as of 3.19.
Toshiaki Makita
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox