Commit 923ba95e authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlxsw-spectrum-prepare-for-xm-implementation-lpm-trees'

Ido Schimmel says:

====================
mlxsw: spectrum: Prepare for XM implementation - LPM trees

Jiri says:

This is a preparation patchset for follow-up support of boards with
extended mezzanine (XM), which are going to allow extended (scale-wise)
router offload.

XM requires a separate set of PRM registers to be used to configure LPM
trees. Therefore, this patchset introduces operations that allow
different implementations of tree configuration for legacy router
offload and the XM router offload.
====================

Link: https://lore.kernel.org/r/20201101134215.713708-1-idosch@idosch.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 8e6a0485 803be108
......@@ -8245,6 +8245,86 @@ mlxsw_reg_rmft2_ipv6_pack(char *payload, bool v, u16 offset, u16 virtual_router,
mlxsw_reg_rmft2_sip6_mask_memcpy_to(payload, (void *)&sip6_mask);
}
/* Note that XRALXX register position violates the rule of ordering register
* definition by the ID. However, XRALXX pack helpers are using RALXX pack
* helpers, RALXX registers have higher IDs.
*/
/* XRALTA - XM Router Algorithmic LPM Tree Allocation Register
* -----------------------------------------------------------
* The XRALTA is used to allocate the XLT LPM trees.
*
* This register embeds original RALTA register.
*/
#define MLXSW_REG_XRALTA_ID 0x7811
#define MLXSW_REG_XRALTA_LEN 0x08
#define MLXSW_REG_XRALTA_RALTA_OFFSET 0x04
MLXSW_REG_DEFINE(xralta, MLXSW_REG_XRALTA_ID, MLXSW_REG_XRALTA_LEN);
static inline void mlxsw_reg_xralta_pack(char *payload, bool alloc,
enum mlxsw_reg_ralxx_protocol protocol,
u8 tree_id)
{
char *ralta_payload = payload + MLXSW_REG_XRALTA_RALTA_OFFSET;
MLXSW_REG_ZERO(xralta, payload);
mlxsw_reg_ralta_pack(ralta_payload, alloc, protocol, tree_id);
}
/* XRALST - XM Router Algorithmic LPM Structure Tree Register
* ----------------------------------------------------------
* The XRALST is used to set and query the structure of an XLT LPM tree.
*
* This register embeds original RALST register.
*/
#define MLXSW_REG_XRALST_ID 0x7812
#define MLXSW_REG_XRALST_LEN 0x108
#define MLXSW_REG_XRALST_RALST_OFFSET 0x04
MLXSW_REG_DEFINE(xralst, MLXSW_REG_XRALST_ID, MLXSW_REG_XRALST_LEN);
static inline void mlxsw_reg_xralst_pack(char *payload, u8 root_bin, u8 tree_id)
{
char *ralst_payload = payload + MLXSW_REG_XRALST_RALST_OFFSET;
MLXSW_REG_ZERO(xralst, payload);
mlxsw_reg_ralst_pack(ralst_payload, root_bin, tree_id);
}
static inline void mlxsw_reg_xralst_bin_pack(char *payload, u8 bin_number,
u8 left_child_bin,
u8 right_child_bin)
{
char *ralst_payload = payload + MLXSW_REG_XRALST_RALST_OFFSET;
mlxsw_reg_ralst_bin_pack(ralst_payload, bin_number, left_child_bin,
right_child_bin);
}
/* XRALTB - XM Router Algorithmic LPM Tree Binding Register
* --------------------------------------------------------
* The XRALTB register is used to bind virtual router and protocol
* to an allocated LPM tree.
*
* This register embeds original RALTB register.
*/
#define MLXSW_REG_XRALTB_ID 0x7813
#define MLXSW_REG_XRALTB_LEN 0x08
#define MLXSW_REG_XRALTB_RALTB_OFFSET 0x04
MLXSW_REG_DEFINE(xraltb, MLXSW_REG_XRALTB_ID, MLXSW_REG_XRALTB_LEN);
static inline void mlxsw_reg_xraltb_pack(char *payload, u16 virtual_router,
enum mlxsw_reg_ralxx_protocol protocol,
u8 tree_id)
{
char *raltb_payload = payload + MLXSW_REG_XRALTB_RALTB_OFFSET;
MLXSW_REG_ZERO(xraltb, payload);
mlxsw_reg_raltb_pack(raltb_payload, virtual_router, protocol, tree_id);
}
/* MFCR - Management Fan Control Register
* --------------------------------------
* This register controls the settings of the Fan Speed PWM mechanism.
......@@ -11195,6 +11275,9 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(rigr2),
MLXSW_REG(recr2),
MLXSW_REG(rmft2),
MLXSW_REG(xralta),
MLXSW_REG(xralst),
MLXSW_REG(xraltb),
MLXSW_REG(mfcr),
MLXSW_REG(mfsc),
MLXSW_REG(mfsm),
......
......@@ -409,6 +409,7 @@ struct mlxsw_sp_fib {
struct mlxsw_sp_vr *vr;
struct mlxsw_sp_lpm_tree *lpm_tree;
enum mlxsw_sp_l3proto proto;
const struct mlxsw_sp_router_ll_ops *ll_ops;
};
struct mlxsw_sp_vr {
......@@ -422,12 +423,31 @@ struct mlxsw_sp_vr {
refcount_t ul_rif_refcnt;
};
static int mlxsw_sp_router_ll_basic_ralta_write(struct mlxsw_sp *mlxsw_sp, char *xralta_pl)
{
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta),
xralta_pl + MLXSW_REG_XRALTA_RALTA_OFFSET);
}
static int mlxsw_sp_router_ll_basic_ralst_write(struct mlxsw_sp *mlxsw_sp, char *xralst_pl)
{
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst),
xralst_pl + MLXSW_REG_XRALST_RALST_OFFSET);
}
static int mlxsw_sp_router_ll_basic_raltb_write(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl)
{
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb),
xraltb_pl + MLXSW_REG_XRALTB_RALTB_OFFSET);
}
static const struct rhashtable_params mlxsw_sp_fib_ht_params;
static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_vr *vr,
enum mlxsw_sp_l3proto proto)
{
const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
struct mlxsw_sp_lpm_tree *lpm_tree;
struct mlxsw_sp_fib *fib;
int err;
......@@ -443,6 +463,7 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
fib->proto = proto;
fib->vr = vr;
fib->lpm_tree = lpm_tree;
fib->ll_ops = ll_ops;
mlxsw_sp_lpm_tree_hold(lpm_tree);
err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
if (err)
......@@ -481,33 +502,36 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
}
static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_router_ll_ops *ll_ops,
struct mlxsw_sp_lpm_tree *lpm_tree)
{
char ralta_pl[MLXSW_REG_RALTA_LEN];
char xralta_pl[MLXSW_REG_XRALTA_LEN];
mlxsw_reg_ralta_pack(ralta_pl, true,
(enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
lpm_tree->id);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
mlxsw_reg_xralta_pack(xralta_pl, true,
(enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
lpm_tree->id);
return ll_ops->ralta_write(mlxsw_sp, xralta_pl);
}
static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_router_ll_ops *ll_ops,
struct mlxsw_sp_lpm_tree *lpm_tree)
{
char ralta_pl[MLXSW_REG_RALTA_LEN];
char xralta_pl[MLXSW_REG_XRALTA_LEN];
mlxsw_reg_ralta_pack(ralta_pl, false,
(enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
lpm_tree->id);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
mlxsw_reg_xralta_pack(xralta_pl, false,
(enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
lpm_tree->id);
ll_ops->ralta_write(mlxsw_sp, xralta_pl);
}
static int
mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_router_ll_ops *ll_ops,
struct mlxsw_sp_prefix_usage *prefix_usage,
struct mlxsw_sp_lpm_tree *lpm_tree)
{
char ralst_pl[MLXSW_REG_RALST_LEN];
char xralst_pl[MLXSW_REG_XRALST_LEN];
u8 root_bin = 0;
u8 prefix;
u8 last_prefix = MLXSW_REG_RALST_BIN_NO_CHILD;
......@@ -515,19 +539,20 @@ mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage)
root_bin = prefix;
mlxsw_reg_ralst_pack(ralst_pl, root_bin, lpm_tree->id);
mlxsw_reg_xralst_pack(xralst_pl, root_bin, lpm_tree->id);
mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) {
if (prefix == 0)
continue;
mlxsw_reg_ralst_bin_pack(ralst_pl, prefix, last_prefix,
MLXSW_REG_RALST_BIN_NO_CHILD);
mlxsw_reg_xralst_bin_pack(xralst_pl, prefix, last_prefix,
MLXSW_REG_RALST_BIN_NO_CHILD);
last_prefix = prefix;
}
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
return ll_ops->ralst_write(mlxsw_sp, xralst_pl);
}
static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_router_ll_ops *ll_ops,
struct mlxsw_sp_prefix_usage *prefix_usage,
enum mlxsw_sp_l3proto proto)
{
......@@ -538,12 +563,11 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
if (!lpm_tree)
return ERR_PTR(-EBUSY);
lpm_tree->proto = proto;
err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, lpm_tree);
err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, ll_ops, lpm_tree);
if (err)
return ERR_PTR(err);
err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, prefix_usage,
lpm_tree);
err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, ll_ops, prefix_usage, lpm_tree);
if (err)
goto err_left_struct_set;
memcpy(&lpm_tree->prefix_usage, prefix_usage,
......@@ -554,14 +578,15 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
return lpm_tree;
err_left_struct_set:
mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
mlxsw_sp_lpm_tree_free(mlxsw_sp, ll_ops, lpm_tree);
return ERR_PTR(err);
}
static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_router_ll_ops *ll_ops,
struct mlxsw_sp_lpm_tree *lpm_tree)
{
mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
mlxsw_sp_lpm_tree_free(mlxsw_sp, ll_ops, lpm_tree);
}
static struct mlxsw_sp_lpm_tree *
......@@ -569,6 +594,7 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_prefix_usage *prefix_usage,
enum mlxsw_sp_l3proto proto)
{
const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
struct mlxsw_sp_lpm_tree *lpm_tree;
int i;
......@@ -582,7 +608,7 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
return lpm_tree;
}
}
return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
return mlxsw_sp_lpm_tree_create(mlxsw_sp, ll_ops, prefix_usage, proto);
}
static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
......@@ -593,8 +619,11 @@ static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_lpm_tree *lpm_tree)
{
const struct mlxsw_sp_router_ll_ops *ll_ops =
mlxsw_sp->router->proto_ll_ops[lpm_tree->proto];
if (--lpm_tree->ref_count == 0)
mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree);
mlxsw_sp_lpm_tree_destroy(mlxsw_sp, ll_ops, lpm_tree);
}
#define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
......@@ -684,23 +713,23 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_fib *fib, u8 tree_id)
{
char raltb_pl[MLXSW_REG_RALTB_LEN];
char xraltb_pl[MLXSW_REG_XRALTB_LEN];
mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
(enum mlxsw_reg_ralxx_protocol) fib->proto,
tree_id);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
mlxsw_reg_xraltb_pack(xraltb_pl, fib->vr->id,
(enum mlxsw_reg_ralxx_protocol) fib->proto,
tree_id);
return fib->ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
}
static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_fib *fib)
{
char raltb_pl[MLXSW_REG_RALTB_LEN];
char xraltb_pl[MLXSW_REG_XRALTB_LEN];
/* Bind to tree 0 which is default */
mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
(enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
mlxsw_reg_xraltb_pack(xraltb_pl, fib->vr->id,
(enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
return fib->ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
}
static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
......@@ -5659,28 +5688,28 @@ static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_reg_ralxx_protocol proto,
u8 tree_id)
{
char ralta_pl[MLXSW_REG_RALTA_LEN];
char ralst_pl[MLXSW_REG_RALST_LEN];
const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
char xralta_pl[MLXSW_REG_XRALTA_LEN];
char xralst_pl[MLXSW_REG_XRALST_LEN];
int i, err;
mlxsw_reg_ralta_pack(ralta_pl, true, proto, tree_id);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
mlxsw_reg_xralta_pack(xralta_pl, true, proto, tree_id);
err = ll_ops->ralta_write(mlxsw_sp, xralta_pl);
if (err)
return err;
mlxsw_reg_ralst_pack(ralst_pl, 0xff, tree_id);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
mlxsw_reg_xralst_pack(xralst_pl, 0xff, tree_id);
err = ll_ops->ralst_write(mlxsw_sp, xralst_pl);
if (err)
return err;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
char raltb_pl[MLXSW_REG_RALTB_LEN];
char xraltb_pl[MLXSW_REG_XRALTB_LEN];
char ralue_pl[MLXSW_REG_RALUE_LEN];
mlxsw_reg_raltb_pack(raltb_pl, vr->id, proto, tree_id);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb),
raltb_pl);
mlxsw_reg_xraltb_pack(xraltb_pl, vr->id, proto, tree_id);
err = ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
if (err)
return err;
......@@ -8057,6 +8086,12 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
}
static const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_basic_ops = {
.ralta_write = mlxsw_sp_router_ll_basic_ralta_write,
.ralst_write = mlxsw_sp_router_ll_basic_ralst_write,
.raltb_write = mlxsw_sp_router_ll_basic_raltb_write,
};
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
struct netlink_ext_ack *extack)
{
......@@ -8070,6 +8105,9 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp->router = router;
router->mlxsw_sp = mlxsw_sp;
router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_router_ll_basic_ops;
router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_router_ll_basic_ops;
INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
err = __mlxsw_sp_router_init(mlxsw_sp);
if (err)
......
......@@ -48,6 +48,17 @@ struct mlxsw_sp_router {
bool adj_discard_index_valid;
struct mlxsw_sp_router_nve_decap nve_decap_config;
struct mutex lock; /* Protects shared router resources */
/* One set of ops for each protocol: IPv4 and IPv6 */
const struct mlxsw_sp_router_ll_ops *proto_ll_ops[MLXSW_SP_L3_PROTO_MAX];
};
/* Low-level router ops. Basically this is to handle the different
* register sets to work with ordinary and XM trees and FIB entries.
*/
struct mlxsw_sp_router_ll_ops {
int (*ralta_write)(struct mlxsw_sp *mlxsw_sp, char *xralta_pl);
int (*ralst_write)(struct mlxsw_sp *mlxsw_sp, char *xralst_pl);
int (*raltb_write)(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl);
};
struct mlxsw_sp_rif_ipip_lb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment