Merge branch 'mlxsw-Support-for-shared-buffers-in-Spectrum-2'

Ido Schimmel says:

====================
mlxsw: Support for shared buffers in Spectrum-2

Petr says:

Spectrum-2 will be configured with a different set of pools than
Spectrum-1, their sizes will be larger, and the individual quotas will
be different as well. It is therefore necessary to make the shared
buffer module aware of this dependence on chip type, and adjust the
individual tables.

In patch #1, introduce a structure for keeping per-chip immutable and
default values.

In patch #2, structures for keeping current values of SBPM and SBPR
(pool configuration and port-pool quota) are allocated dynamically to
support varying pool counts.

In patches #3 to #7, uses of individual shared buffer configuration
tables are migrated from global definitions to fields in struct
mlxsw_sp_sb_vals, which was introduced above.

Up until this point, the actual configuration is still the one suitable
for Spectrum-1. In patch #8 Spectrum-2 configuration is added.

In patch #9, port headroom configuration is changed to take into account
current recommended value for a 100-Gbps port, and the split factor.

In patch #10, requests for overlarge headroom are rejected. This avoids
potential chip freeze should such overlarge requests be made.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-02-21 15:57:46 -08:00
Родитель fdb89a3113 bb6c346cef
Коммит 2fb44dd0e8
4 изменённых файлов: 267 добавлений и 68 удалений

Просмотреть файл

@ -26,6 +26,7 @@ enum mlxsw_res_id {
MLXSW_RES_ID_MAX_LAG_MEMBERS,
MLXSW_RES_ID_MAX_BUFFER_SIZE,
MLXSW_RES_ID_CELL_SIZE,
MLXSW_RES_ID_MAX_HEADROOM_SIZE,
MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS,
MLXSW_RES_ID_ACL_MAX_TCAM_RULES,
MLXSW_RES_ID_ACL_MAX_REGIONS,
@ -79,6 +80,7 @@ static u16 mlxsw_res_ids[] = {
[MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521,
[MLXSW_RES_ID_MAX_BUFFER_SIZE] = 0x2802, /* Bytes */
[MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */
[MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */
[MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS] = 0x2901,
[MLXSW_RES_ID_ACL_MAX_TCAM_RULES] = 0x2902,
[MLXSW_RES_ID_ACL_MAX_REGIONS] = 0x2903,

Просмотреть файл

@ -852,8 +852,12 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
u8 pfc_en = !!my_pfc ? my_pfc->pfc_en : 0;
u16 delay = !!my_pfc ? my_pfc->delay : 0;
char pbmc_pl[MLXSW_REG_PBMC_LEN];
u32 taken_headroom_cells = 0;
u32 max_headroom_cells;
int i, j, err;
max_headroom_cells = mlxsw_sp_sb_max_headroom_cells(mlxsw_sp);
mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, 0, 0);
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl);
if (err)
@ -864,6 +868,7 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
bool pfc = false;
u16 thres_cells;
u16 delay_cells;
u16 total_cells;
bool lossy;
for (j = 0; j < IEEE_8021QAZ_MAX_TCS; j++) {
@ -881,7 +886,13 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
thres_cells = mlxsw_sp_pg_buf_threshold_get(mlxsw_sp, mtu);
delay_cells = mlxsw_sp_pg_buf_delay_get(mlxsw_sp, mtu, delay,
pfc, pause_en);
mlxsw_sp_pg_buf_pack(pbmc_pl, i, thres_cells + delay_cells,
total_cells = thres_cells + delay_cells;
taken_headroom_cells += total_cells;
if (taken_headroom_cells > max_headroom_cells)
return -ENOBUFS;
mlxsw_sp_pg_buf_pack(pbmc_pl, i, total_cells,
thres_cells, lossy);
}
@ -4092,6 +4103,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr;
mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask;
mlxsw_sp->rif_ops_arr = mlxsw_sp1_rif_ops_arr;
mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
}
@ -4109,6 +4121,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
}

Просмотреть файл

@ -133,6 +133,7 @@ struct mlxsw_sp_kvdl_ops;
struct mlxsw_sp_mr_tcam_ops;
struct mlxsw_sp_acl_tcam_ops;
struct mlxsw_sp_nve_ops;
struct mlxsw_sp_sb_vals;
struct mlxsw_sp {
struct mlxsw_sp_port **ports;
@ -167,6 +168,7 @@ struct mlxsw_sp {
const struct mlxsw_sp_acl_tcam_ops *acl_tcam_ops;
const struct mlxsw_sp_nve_ops **nve_ops_arr;
const struct mlxsw_sp_rif_ops **rif_ops_arr;
const struct mlxsw_sp_sb_vals *sb_vals;
};
static inline struct mlxsw_sp_upper *
@ -371,6 +373,10 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
u32 *p_cur, u32 *p_max);
u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells);
u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes);
u32 mlxsw_sp_sb_max_headroom_cells(const struct mlxsw_sp *mlxsw_sp);
extern const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals;
extern const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals;
/* spectrum_switchdev.c */
int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp);

Просмотреть файл

@ -37,13 +37,19 @@ struct mlxsw_sp_sb_pm {
struct mlxsw_cp_sb_occ occ;
};
struct mlxsw_sp_sb_mm {
u32 min_buff;
u32 max_buff;
u16 pool_index;
};
struct mlxsw_sp_sb_pool_des {
enum mlxsw_reg_sbxx_dir dir;
u8 pool;
};
/* Order ingress pools before egress pools. */
static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
static const struct mlxsw_sp_sb_pool_des mlxsw_sp1_sb_pool_dess[] = {
{MLXSW_REG_SBXX_DIR_INGRESS, 0},
{MLXSW_REG_SBXX_DIR_INGRESS, 1},
{MLXSW_REG_SBXX_DIR_INGRESS, 2},
@ -55,7 +61,16 @@ static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
{MLXSW_REG_SBXX_DIR_EGRESS, 15},
};
#define MLXSW_SP_SB_POOL_DESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pool_dess)
static const struct mlxsw_sp_sb_pool_des mlxsw_sp2_sb_pool_dess[] = {
{MLXSW_REG_SBXX_DIR_INGRESS, 0},
{MLXSW_REG_SBXX_DIR_INGRESS, 1},
{MLXSW_REG_SBXX_DIR_INGRESS, 2},
{MLXSW_REG_SBXX_DIR_INGRESS, 3},
{MLXSW_REG_SBXX_DIR_EGRESS, 0},
{MLXSW_REG_SBXX_DIR_EGRESS, 1},
{MLXSW_REG_SBXX_DIR_EGRESS, 2},
{MLXSW_REG_SBXX_DIR_EGRESS, 3},
};
#define MLXSW_SP_SB_ING_TC_COUNT 8
#define MLXSW_SP_SB_EG_TC_COUNT 16
@ -63,16 +78,32 @@ static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
struct mlxsw_sp_sb_port {
struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT];
struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT];
struct mlxsw_sp_sb_pm pms[MLXSW_SP_SB_POOL_DESS_LEN];
struct mlxsw_sp_sb_pm *pms;
};
struct mlxsw_sp_sb {
struct mlxsw_sp_sb_pr prs[MLXSW_SP_SB_POOL_DESS_LEN];
struct mlxsw_sp_sb_pr *prs;
struct mlxsw_sp_sb_port *ports;
u32 cell_size;
u32 max_headroom_cells;
u64 sb_size;
};
struct mlxsw_sp_sb_vals {
unsigned int pool_count;
const struct mlxsw_sp_sb_pool_des *pool_dess;
const struct mlxsw_sp_sb_pm *pms;
const struct mlxsw_sp_sb_pr *prs;
const struct mlxsw_sp_sb_mm *mms;
const struct mlxsw_sp_sb_cm *cms_ingress;
const struct mlxsw_sp_sb_cm *cms_egress;
const struct mlxsw_sp_sb_cm *cms_cpu;
unsigned int mms_count;
unsigned int cms_ingress_count;
unsigned int cms_egress_count;
unsigned int cms_cpu_count;
};
u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells)
{
return mlxsw_sp->sb->cell_size * cells;
@ -83,6 +114,11 @@ u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes)
return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size);
}
u32 mlxsw_sp_sb_max_headroom_cells(const struct mlxsw_sp *mlxsw_sp)
{
return mlxsw_sp->sb->max_headroom_cells;
}
static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp,
u16 pool_index)
{
@ -121,7 +157,7 @@ static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
u32 size, bool infi_size)
{
const struct mlxsw_sp_sb_pool_des *des =
&mlxsw_sp_sb_pool_dess[pool_index];
&mlxsw_sp->sb_vals->pool_dess[pool_index];
char sbpr_pl[MLXSW_REG_SBPR_LEN];
struct mlxsw_sp_sb_pr *pr;
int err;
@ -145,7 +181,7 @@ static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
bool infi_max, u16 pool_index)
{
const struct mlxsw_sp_sb_pool_des *des =
&mlxsw_sp_sb_pool_dess[pool_index];
&mlxsw_sp->sb_vals->pool_dess[pool_index];
char sbcm_pl[MLXSW_REG_SBCM_LEN];
struct mlxsw_sp_sb_cm *cm;
int err;
@ -174,7 +210,7 @@ static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
u16 pool_index, u32 min_buff, u32 max_buff)
{
const struct mlxsw_sp_sb_pool_des *des =
&mlxsw_sp_sb_pool_dess[pool_index];
&mlxsw_sp->sb_vals->pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
struct mlxsw_sp_sb_pm *pm;
int err;
@ -195,7 +231,7 @@ static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
u16 pool_index, struct list_head *bulk_list)
{
const struct mlxsw_sp_sb_pool_des *des =
&mlxsw_sp_sb_pool_dess[pool_index];
&mlxsw_sp->sb_vals->pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
@ -217,7 +253,7 @@ static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
u16 pool_index, struct list_head *bulk_list)
{
const struct mlxsw_sp_sb_pool_des *des =
&mlxsw_sp_sb_pool_dess[pool_index];
&mlxsw_sp->sb_vals->pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
struct mlxsw_sp_sb_pm *pm;
@ -230,24 +266,24 @@ static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
(unsigned long) pm);
}
static const u16 mlxsw_sp_pbs[] = {
[0] = 2 * ETH_FRAME_LEN,
[9] = 2 * MLXSW_PORT_MAX_MTU,
};
#define MLXSW_SP_PBS_LEN ARRAY_SIZE(mlxsw_sp_pbs)
/* 1/4 of a headroom necessary for 100Gbps port and 100m cable. */
#define MLXSW_SP_PB_HEADROOM 25632
#define MLXSW_SP_PB_UNUSED 8
static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
const u32 pbs[] = {
[0] = MLXSW_SP_PB_HEADROOM * mlxsw_sp_port->mapping.width,
[9] = 2 * MLXSW_PORT_MAX_MTU,
};
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pbmc_pl[MLXSW_REG_PBMC_LEN];
int i;
mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port,
0xffff, 0xffff / 2);
for (i = 0; i < MLXSW_SP_PBS_LEN; i++) {
u16 size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp_pbs[i]);
for (i = 0; i < ARRAY_SIZE(pbs); i++) {
u16 size = mlxsw_sp_bytes_cells(mlxsw_sp, pbs[i]);
if (i == MLXSW_SP_PB_UNUSED)
continue;
@ -280,50 +316,119 @@ static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port);
}
static int mlxsw_sp_sb_port_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_sb_port *sb_port)
{
struct mlxsw_sp_sb_pm *pms;
pms = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*pms),
GFP_KERNEL);
if (!pms)
return -ENOMEM;
sb_port->pms = pms;
return 0;
}
static void mlxsw_sp_sb_port_fini(struct mlxsw_sp_sb_port *sb_port)
{
kfree(sb_port->pms);
}
static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp)
{
unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
struct mlxsw_sp_sb_pr *prs;
int i;
int err;
mlxsw_sp->sb->ports = kcalloc(max_ports,
sizeof(struct mlxsw_sp_sb_port),
GFP_KERNEL);
if (!mlxsw_sp->sb->ports)
return -ENOMEM;
prs = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*prs),
GFP_KERNEL);
if (!prs) {
err = -ENOMEM;
goto err_alloc_prs;
}
mlxsw_sp->sb->prs = prs;
for (i = 0; i < max_ports; i++) {
err = mlxsw_sp_sb_port_init(mlxsw_sp, &mlxsw_sp->sb->ports[i]);
if (err)
goto err_sb_port_init;
}
return 0;
err_sb_port_init:
for (i--; i >= 0; i--)
mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]);
kfree(mlxsw_sp->sb->prs);
err_alloc_prs:
kfree(mlxsw_sp->sb->ports);
return err;
}
static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp)
{
int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
int i;
for (i = max_ports - 1; i >= 0; i--)
mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]);
kfree(mlxsw_sp->sb->prs);
kfree(mlxsw_sp->sb->ports);
}
#define MLXSW_SP_SB_PR_INGRESS_SIZE 12440000
#define MLXSW_SP_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
#define MLXSW_SP_SB_PR_EGRESS_SIZE 13232000
#define MLXSW_SP_SB_PR(_mode, _size) \
{ \
.mode = _mode, \
.size = _size, \
}
static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs[] = {
#define MLXSW_SP1_SB_PR_INGRESS_SIZE 12440000
#define MLXSW_SP1_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
#define MLXSW_SP1_SB_PR_EGRESS_SIZE 13232000
static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = {
/* Ingress pools. */
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP_SB_PR_INGRESS_SIZE),
MLXSW_SP1_SB_PR_INGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP_SB_PR_INGRESS_MNG_SIZE),
MLXSW_SP1_SB_PR_INGRESS_MNG_SIZE),
/* Egress pools. */
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_EGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP1_SB_PR_EGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI),
};
#define MLXSW_SP_SB_PRS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs)
#define MLXSW_SP2_SB_PR_INGRESS_SIZE 40960000
#define MLXSW_SP2_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
#define MLXSW_SP2_SB_PR_EGRESS_SIZE 40960000
static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = {
/* Ingress pools. */
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP2_SB_PR_INGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP2_SB_PR_INGRESS_MNG_SIZE),
/* Egress pools. */
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP2_SB_PR_EGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
};
static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_sb_pr *prs,
@ -357,7 +462,7 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
.pool_index = _pool, \
}
static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_ingress[] = {
MLXSW_SP_SB_CM(10000, 8, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
@ -370,9 +475,20 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
MLXSW_SP_SB_CM(20000, 1, 3),
};
#define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress)
static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_ingress[] = {
MLXSW_SP_SB_CM(0, 7, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
MLXSW_SP_SB_CM(0, 0, 0), /* dummy, this PG does not exist */
MLXSW_SP_SB_CM(20000, 1, 3),
};
static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_egress[] = {
MLXSW_SP_SB_CM(1500, 9, 4),
MLXSW_SP_SB_CM(1500, 9, 4),
MLXSW_SP_SB_CM(1500, 9, 4),
@ -392,7 +508,25 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
MLXSW_SP_SB_CM(1, 0xff, 4),
};
#define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress)
static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_egress[] = {
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(0, 7, 4),
MLXSW_SP_SB_CM(1, 0xff, 4),
};
#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 4)
@ -431,9 +565,6 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
MLXSW_SP_CPU_PORT_SB_CM,
};
#define MLXSW_SP_CPU_PORT_SB_MCS_LEN \
ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms)
static bool
mlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index)
{
@ -447,6 +578,7 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const struct mlxsw_sp_sb_cm *cms,
size_t cms_len)
{
const struct mlxsw_sp_sb_vals *sb_vals = mlxsw_sp->sb_vals;
int i;
int err;
@ -458,7 +590,7 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS)
continue; /* PG number 8 does not exist, skip it */
cm = &cms[i];
if (WARN_ON(mlxsw_sp_sb_pool_dess[cm->pool_index].dir != dir))
if (WARN_ON(sb_vals->pool_dess[cm->pool_index].dir != dir))
continue;
min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff);
@ -484,27 +616,28 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
int err;
err = __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
err = __mlxsw_sp_sb_cms_init(mlxsw_sp,
mlxsw_sp_port->local_port,
MLXSW_REG_SBXX_DIR_INGRESS,
mlxsw_sp_sb_cms_ingress,
MLXSW_SP_SB_CMS_INGRESS_LEN);
mlxsw_sp->sb_vals->cms_ingress,
mlxsw_sp->sb_vals->cms_ingress_count);
if (err)
return err;
return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
mlxsw_sp_port->local_port,
MLXSW_REG_SBXX_DIR_EGRESS,
mlxsw_sp_sb_cms_egress,
MLXSW_SP_SB_CMS_EGRESS_LEN);
mlxsw_sp->sb_vals->cms_egress,
mlxsw_sp->sb_vals->cms_egress_count);
}
static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
{
return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS,
mlxsw_sp_cpu_port_sb_cms,
MLXSW_SP_CPU_PORT_SB_MCS_LEN);
mlxsw_sp->sb_vals->cms_cpu,
mlxsw_sp->sb_vals->cms_cpu_count);
}
#define MLXSW_SP_SB_PM(_min_buff, _max_buff) \
@ -513,7 +646,7 @@ static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
.max_buff = _max_buff, \
}
static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = {
static const struct mlxsw_sp_sb_pm mlxsw_sp1_sb_pms[] = {
/* Ingress pools. */
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
@ -527,7 +660,18 @@ static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = {
MLXSW_SP_SB_PM(10000, 90000),
};
#define MLXSW_SP_SB_PMS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms)
static const struct mlxsw_sp_sb_pm mlxsw_sp2_sb_pms[] = {
/* Ingress pools. */
MLXSW_SP_SB_PM(0, 7),
MLXSW_SP_SB_PM(0, 0),
MLXSW_SP_SB_PM(0, 0),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
/* Egress pools. */
MLXSW_SP_SB_PM(0, 7),
MLXSW_SP_SB_PM(0, 0),
MLXSW_SP_SB_PM(0, 0),
MLXSW_SP_SB_PM(0, 0),
};
static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
@ -535,8 +679,8 @@ static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
int i;
int err;
for (i = 0; i < MLXSW_SP_SB_PMS_LEN; i++) {
const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp_sb_pms[i];
for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp->sb_vals->pms[i];
u32 max_buff;
u32 min_buff;
@ -552,12 +696,6 @@ static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
return 0;
}
struct mlxsw_sp_sb_mm {
u32 min_buff;
u32 max_buff;
u16 pool_index;
};
#define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool) \
{ \
.min_buff = _min_buff, \
@ -583,21 +721,19 @@ static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = {
MLXSW_SP_SB_MM(0, 6, 4),
};
#define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms)
static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
{
char sbmm_pl[MLXSW_REG_SBMM_LEN];
int i;
int err;
for (i = 0; i < MLXSW_SP_SB_MMS_LEN; i++) {
for (i = 0; i < mlxsw_sp->sb_vals->mms_count; i++) {
const struct mlxsw_sp_sb_pool_des *des;
const struct mlxsw_sp_sb_mm *mc;
u32 min_buff;
mc = &mlxsw_sp_sb_mms[i];
des = &mlxsw_sp_sb_pool_dess[mc->pool_index];
mc = &mlxsw_sp->sb_vals->mms[i];
des = &mlxsw_sp->sb_vals->pool_dess[mc->pool_index];
/* All pools used by sb_mm's are initialized using dynamic
* thresholds, therefore 'max_buff' isn't specified in cells.
*/
@ -611,22 +747,55 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
return 0;
}
static void mlxsw_sp_pool_count(u16 *p_ingress_len, u16 *p_egress_len)
static void mlxsw_sp_pool_count(struct mlxsw_sp *mlxsw_sp,
u16 *p_ingress_len, u16 *p_egress_len)
{
int i;
for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; ++i)
if (mlxsw_sp_sb_pool_dess[i].dir == MLXSW_REG_SBXX_DIR_EGRESS)
for (i = 0; i < mlxsw_sp->sb_vals->pool_count; ++i)
if (mlxsw_sp->sb_vals->pool_dess[i].dir ==
MLXSW_REG_SBXX_DIR_EGRESS)
goto out;
WARN(1, "No egress pools\n");
out:
*p_ingress_len = i;
*p_egress_len = MLXSW_SP_SB_POOL_DESS_LEN - i;
*p_egress_len = mlxsw_sp->sb_vals->pool_count - i;
}
const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals = {
.pool_count = ARRAY_SIZE(mlxsw_sp1_sb_pool_dess),
.pool_dess = mlxsw_sp1_sb_pool_dess,
.pms = mlxsw_sp1_sb_pms,
.prs = mlxsw_sp1_sb_prs,
.mms = mlxsw_sp_sb_mms,
.cms_ingress = mlxsw_sp1_sb_cms_ingress,
.cms_egress = mlxsw_sp1_sb_cms_egress,
.cms_cpu = mlxsw_sp_cpu_port_sb_cms,
.mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms),
.cms_ingress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_ingress),
.cms_egress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_egress),
.cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms),
};
const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals = {
.pool_count = ARRAY_SIZE(mlxsw_sp2_sb_pool_dess),
.pool_dess = mlxsw_sp2_sb_pool_dess,
.pms = mlxsw_sp2_sb_pms,
.prs = mlxsw_sp2_sb_prs,
.mms = mlxsw_sp_sb_mms,
.cms_ingress = mlxsw_sp2_sb_cms_ingress,
.cms_egress = mlxsw_sp2_sb_cms_egress,
.cms_cpu = mlxsw_sp_cpu_port_sb_cms,
.mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms),
.cms_ingress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_ingress),
.cms_egress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_egress),
.cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms),
};
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
{
u32 max_headroom_size;
u16 ing_pool_count;
u16 eg_pool_count;
int err;
@ -637,18 +806,26 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE))
return -EIO;
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE))
return -EIO;
mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL);
if (!mlxsw_sp->sb)
return -ENOMEM;
mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE);
mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
MAX_BUFFER_SIZE);
max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
MAX_HEADROOM_SIZE);
/* Round down, because this limit must not be overstepped. */
mlxsw_sp->sb->max_headroom_cells = max_headroom_size /
mlxsw_sp->sb->cell_size;
err = mlxsw_sp_sb_ports_init(mlxsw_sp);
if (err)
goto err_sb_ports_init;
err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp_sb_prs,
MLXSW_SP_SB_PRS_LEN);
err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs,
mlxsw_sp->sb_vals->pool_count);
if (err)
goto err_sb_prs_init;
err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp);
@ -657,7 +834,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
err = mlxsw_sp_sb_mms_init(mlxsw_sp);
if (err)
goto err_sb_mms_init;
mlxsw_sp_pool_count(&ing_pool_count, &eg_pool_count);
mlxsw_sp_pool_count(mlxsw_sp, &ing_pool_count, &eg_pool_count);
err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0,
mlxsw_sp->sb->sb_size,
ing_pool_count,
@ -705,10 +882,11 @@ int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core,
unsigned int sb_index, u16 pool_index,
struct devlink_sb_pool_info *pool_info)
{
enum mlxsw_reg_sbxx_dir dir = mlxsw_sp_sb_pool_dess[pool_index].dir;
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
enum mlxsw_reg_sbxx_dir dir;
struct mlxsw_sp_sb_pr *pr;
dir = mlxsw_sp->sb_vals->pool_dess[pool_index].dir;
pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
pool_info->pool_type = (enum devlink_sb_pool_type) dir;
pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size);
@ -834,7 +1012,7 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
u32 max_buff;
int err;
if (dir != mlxsw_sp_sb_pool_dess[pool_index].dir)
if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir)
return -EINVAL;
err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
@ -932,7 +1110,7 @@ next_batch:
continue;
mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) {
for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
&bulk_list);
if (err)
@ -991,7 +1169,7 @@ next_batch:
continue;
mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) {
for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
&bulk_list);
if (err)