struct mlxsw_sp_vr;
struct mlxsw_sp_lpm_tree;
+struct mlxsw_sp_rif_ops;
struct mlxsw_sp_router {
struct mlxsw_sp *mlxsw_sp;
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 {
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 {
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)
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);
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)
{
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;
rif->vr_id = vr_id;
rif->dev = l3_dev;
rif->rif_index = rif_index;
- rif->fid = fid;
return 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);
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++;
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)
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;
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;
}
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);
GFP_KERNEL);
if (!mlxsw_sp->router->rifs)
return -ENOMEM;
+
+ mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr;
+
return 0;
}