162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/dcbnl.h> 762306a36Sopenharmony_ci#include <linux/if_ether.h> 862306a36Sopenharmony_ci#include <linux/list.h> 962306a36Sopenharmony_ci#include <linux/netlink.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "spectrum.h" 1262306a36Sopenharmony_ci#include "core.h" 1362306a36Sopenharmony_ci#include "port.h" 1462306a36Sopenharmony_ci#include "reg.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct mlxsw_sp_sb_pr { 1762306a36Sopenharmony_ci enum mlxsw_reg_sbpr_mode mode; 1862306a36Sopenharmony_ci u32 size; 1962306a36Sopenharmony_ci u8 freeze_mode:1, 2062306a36Sopenharmony_ci freeze_size:1; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct mlxsw_cp_sb_occ { 2462306a36Sopenharmony_ci u32 cur; 2562306a36Sopenharmony_ci u32 max; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct mlxsw_sp_sb_cm { 2962306a36Sopenharmony_ci u32 min_buff; 3062306a36Sopenharmony_ci u32 max_buff; 3162306a36Sopenharmony_ci u16 pool_index; 3262306a36Sopenharmony_ci struct mlxsw_cp_sb_occ occ; 3362306a36Sopenharmony_ci u8 freeze_pool:1, 3462306a36Sopenharmony_ci freeze_thresh:1; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define MLXSW_SP_SB_INFI -1U 3862306a36Sopenharmony_ci#define MLXSW_SP_SB_REST -2U 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct mlxsw_sp_sb_pm { 4162306a36Sopenharmony_ci u32 min_buff; 4262306a36Sopenharmony_ci u32 max_buff; 4362306a36Sopenharmony_ci struct mlxsw_cp_sb_occ occ; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct mlxsw_sp_sb_mm { 4762306a36Sopenharmony_ci u32 min_buff; 4862306a36Sopenharmony_ci u32 max_buff; 4962306a36Sopenharmony_ci u16 pool_index; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct mlxsw_sp_sb_pool_des { 5362306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir; 5462306a36Sopenharmony_ci u8 pool; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define MLXSW_SP_SB_POOL_ING 0 5862306a36Sopenharmony_ci#define MLXSW_SP_SB_POOL_EGR 4 5962306a36Sopenharmony_ci#define MLXSW_SP_SB_POOL_EGR_MC 8 6062306a36Sopenharmony_ci#define MLXSW_SP_SB_POOL_ING_CPU 9 6162306a36Sopenharmony_ci#define MLXSW_SP_SB_POOL_EGR_CPU 10 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pool_des mlxsw_sp1_sb_pool_dess[] = { 6462306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 0}, 6562306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 1}, 6662306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 2}, 6762306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 3}, 6862306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 0}, 6962306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 1}, 7062306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 2}, 7162306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 3}, 7262306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 15}, 7362306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 4}, 7462306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 4}, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pool_des mlxsw_sp2_sb_pool_dess[] = { 7862306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 0}, 7962306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 1}, 8062306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 2}, 8162306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 3}, 8262306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 0}, 8362306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 1}, 8462306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 2}, 8562306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 3}, 8662306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 15}, 8762306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_INGRESS, 4}, 8862306a36Sopenharmony_ci {MLXSW_REG_SBXX_DIR_EGRESS, 4}, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define MLXSW_SP_SB_ING_TC_COUNT 8 9262306a36Sopenharmony_ci#define MLXSW_SP_SB_EG_TC_COUNT 16 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct mlxsw_sp_sb_port { 9562306a36Sopenharmony_ci struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT]; 9662306a36Sopenharmony_ci struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT]; 9762306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pms; 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct mlxsw_sp_sb { 10162306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *prs; 10262306a36Sopenharmony_ci struct mlxsw_sp_sb_port *ports; 10362306a36Sopenharmony_ci u32 cell_size; 10462306a36Sopenharmony_ci u32 max_headroom_cells; 10562306a36Sopenharmony_ci u64 sb_size; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct mlxsw_sp_sb_vals { 10962306a36Sopenharmony_ci unsigned int pool_count; 11062306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *pool_dess; 11162306a36Sopenharmony_ci const struct mlxsw_sp_sb_pm *pms; 11262306a36Sopenharmony_ci const struct mlxsw_sp_sb_pm *pms_cpu; 11362306a36Sopenharmony_ci const struct mlxsw_sp_sb_pr *prs; 11462306a36Sopenharmony_ci const struct mlxsw_sp_sb_mm *mms; 11562306a36Sopenharmony_ci const struct mlxsw_sp_sb_cm *cms_ingress; 11662306a36Sopenharmony_ci const struct mlxsw_sp_sb_cm *cms_egress; 11762306a36Sopenharmony_ci const struct mlxsw_sp_sb_cm *cms_cpu; 11862306a36Sopenharmony_ci unsigned int mms_count; 11962306a36Sopenharmony_ci unsigned int cms_ingress_count; 12062306a36Sopenharmony_ci unsigned int cms_egress_count; 12162306a36Sopenharmony_ci unsigned int cms_cpu_count; 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct mlxsw_sp_sb_ops { 12562306a36Sopenharmony_ci u32 (*int_buf_size_get)(int mtu, u32 speed); 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciu32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return mlxsw_sp->sb->cell_size * cells; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciu32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic u32 mlxsw_sp_port_headroom_8x_adjust(const struct mlxsw_sp_port *mlxsw_sp_port, 13962306a36Sopenharmony_ci u32 size_cells) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci /* Ports with eight lanes use two headroom buffers between which the 14262306a36Sopenharmony_ci * configured headroom size is split. Therefore, multiply the calculated 14362306a36Sopenharmony_ci * headroom size by two. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci return mlxsw_sp_port->mapping.width == 8 ? 2 * size_cells : size_cells; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, 14962306a36Sopenharmony_ci u16 pool_index) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return &mlxsw_sp->sb->prs[pool_index]; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic bool mlxsw_sp_sb_cm_exists(u8 pg_buff, enum mlxsw_reg_sbxx_dir dir) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci if (dir == MLXSW_REG_SBXX_DIR_INGRESS) 15762306a36Sopenharmony_ci return pg_buff < MLXSW_SP_SB_ING_TC_COUNT; 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci return pg_buff < MLXSW_SP_SB_EG_TC_COUNT; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, 16362306a36Sopenharmony_ci u16 local_port, u8 pg_buff, 16462306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct mlxsw_sp_sb_port *sb_port = &mlxsw_sp->sb->ports[local_port]; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci WARN_ON(!mlxsw_sp_sb_cm_exists(pg_buff, dir)); 16962306a36Sopenharmony_ci if (dir == MLXSW_REG_SBXX_DIR_INGRESS) 17062306a36Sopenharmony_ci return &sb_port->ing_cms[pg_buff]; 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci return &sb_port->eg_cms[pg_buff]; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, 17662306a36Sopenharmony_ci u16 local_port, u16 pool_index) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci return &mlxsw_sp->sb->ports[local_port].pms[pool_index]; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index, 18262306a36Sopenharmony_ci enum mlxsw_reg_sbpr_mode mode, 18362306a36Sopenharmony_ci u32 size, bool infi_size) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des = 18662306a36Sopenharmony_ci &mlxsw_sp->sb_vals->pool_dess[pool_index]; 18762306a36Sopenharmony_ci char sbpr_pl[MLXSW_REG_SBPR_LEN]; 18862306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *pr; 18962306a36Sopenharmony_ci int err; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode, 19262306a36Sopenharmony_ci size, infi_size); 19362306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl); 19462306a36Sopenharmony_ci if (err) 19562306a36Sopenharmony_ci return err; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (infi_size) 19862306a36Sopenharmony_ci size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp->sb->sb_size); 19962306a36Sopenharmony_ci pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); 20062306a36Sopenharmony_ci pr->mode = mode; 20162306a36Sopenharmony_ci pr->size = size; 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int mlxsw_sp_sb_pr_desc_write(struct mlxsw_sp *mlxsw_sp, 20662306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir, 20762306a36Sopenharmony_ci enum mlxsw_reg_sbpr_mode mode, 20862306a36Sopenharmony_ci u32 size, bool infi_size) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci char sbpr_pl[MLXSW_REG_SBPR_LEN]; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* The FW default descriptor buffer configuration uses only pool 14 for 21362306a36Sopenharmony_ci * descriptors. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci mlxsw_reg_sbpr_pack(sbpr_pl, 14, dir, mode, size, infi_size); 21662306a36Sopenharmony_ci mlxsw_reg_sbpr_desc_set(sbpr_pl, true); 21762306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u16 local_port, 22162306a36Sopenharmony_ci u8 pg_buff, u32 min_buff, u32 max_buff, 22262306a36Sopenharmony_ci bool infi_max, u16 pool_index) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des = 22562306a36Sopenharmony_ci &mlxsw_sp->sb_vals->pool_dess[pool_index]; 22662306a36Sopenharmony_ci char sbcm_pl[MLXSW_REG_SBCM_LEN]; 22762306a36Sopenharmony_ci struct mlxsw_sp_sb_cm *cm; 22862306a36Sopenharmony_ci int err; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, des->dir, 23162306a36Sopenharmony_ci min_buff, max_buff, infi_max, des->pool); 23262306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl); 23362306a36Sopenharmony_ci if (err) 23462306a36Sopenharmony_ci return err; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (mlxsw_sp_sb_cm_exists(pg_buff, des->dir)) { 23762306a36Sopenharmony_ci if (infi_max) 23862306a36Sopenharmony_ci max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, 23962306a36Sopenharmony_ci mlxsw_sp->sb->sb_size); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, 24262306a36Sopenharmony_ci des->dir); 24362306a36Sopenharmony_ci cm->min_buff = min_buff; 24462306a36Sopenharmony_ci cm->max_buff = max_buff; 24562306a36Sopenharmony_ci cm->pool_index = pool_index; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u16 local_port, 25162306a36Sopenharmony_ci u16 pool_index, u32 min_buff, u32 max_buff) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des = 25462306a36Sopenharmony_ci &mlxsw_sp->sb_vals->pool_dess[pool_index]; 25562306a36Sopenharmony_ci char sbpm_pl[MLXSW_REG_SBPM_LEN]; 25662306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pm; 25762306a36Sopenharmony_ci int err; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, false, 26062306a36Sopenharmony_ci min_buff, max_buff); 26162306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl); 26262306a36Sopenharmony_ci if (err) 26362306a36Sopenharmony_ci return err; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index); 26662306a36Sopenharmony_ci pm->min_buff = min_buff; 26762306a36Sopenharmony_ci pm->max_buff = max_buff; 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u16 local_port, 27262306a36Sopenharmony_ci u16 pool_index, struct list_head *bulk_list) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des = 27562306a36Sopenharmony_ci &mlxsw_sp->sb_vals->pool_dess[pool_index]; 27662306a36Sopenharmony_ci char sbpm_pl[MLXSW_REG_SBPM_LEN]; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (local_port == MLXSW_PORT_CPU_PORT && 27962306a36Sopenharmony_ci des->dir == MLXSW_REG_SBXX_DIR_INGRESS) 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, 28362306a36Sopenharmony_ci true, 0, 0); 28462306a36Sopenharmony_ci return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, 28562306a36Sopenharmony_ci bulk_list, NULL, 0); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core, 28962306a36Sopenharmony_ci char *sbpm_pl, size_t sbpm_pl_len, 29062306a36Sopenharmony_ci unsigned long cb_priv) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pm = (struct mlxsw_sp_sb_pm *) cb_priv; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci mlxsw_reg_sbpm_unpack(sbpm_pl, &pm->occ.cur, &pm->occ.max); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u16 local_port, 29862306a36Sopenharmony_ci u16 pool_index, struct list_head *bulk_list) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des = 30162306a36Sopenharmony_ci &mlxsw_sp->sb_vals->pool_dess[pool_index]; 30262306a36Sopenharmony_ci char sbpm_pl[MLXSW_REG_SBPM_LEN]; 30362306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pm; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (local_port == MLXSW_PORT_CPU_PORT && 30662306a36Sopenharmony_ci des->dir == MLXSW_REG_SBXX_DIR_INGRESS) 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index); 31062306a36Sopenharmony_ci mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, 31162306a36Sopenharmony_ci false, 0, 0); 31262306a36Sopenharmony_ci return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, 31362306a36Sopenharmony_ci bulk_list, 31462306a36Sopenharmony_ci mlxsw_sp_sb_pm_occ_query_cb, 31562306a36Sopenharmony_ci (unsigned long) pm); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_civoid mlxsw_sp_hdroom_prios_reset_buf_idx(struct mlxsw_sp_hdroom *hdroom) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci int prio; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) { 32362306a36Sopenharmony_ci switch (hdroom->mode) { 32462306a36Sopenharmony_ci case MLXSW_SP_HDROOM_MODE_DCB: 32562306a36Sopenharmony_ci hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].ets_buf_idx; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case MLXSW_SP_HDROOM_MODE_TC: 32862306a36Sopenharmony_ci hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].set_buf_idx; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_civoid mlxsw_sp_hdroom_bufs_reset_lossiness(struct mlxsw_sp_hdroom *hdroom) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int prio; 33762306a36Sopenharmony_ci int i; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_BUFFERS; i++) 34062306a36Sopenharmony_ci hdroom->bufs.buf[i].lossy = true; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++) { 34362306a36Sopenharmony_ci if (!hdroom->prios.prio[prio].lossy) 34462306a36Sopenharmony_ci hdroom->bufs.buf[hdroom->prios.prio[prio].buf_idx].lossy = false; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic u16 mlxsw_sp_hdroom_buf_threshold_get(const struct mlxsw_sp *mlxsw_sp, int mtu) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci return 2 * mlxsw_sp_bytes_cells(mlxsw_sp, mtu); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void mlxsw_sp_hdroom_buf_pack(char *pbmc_pl, int index, u16 size, u16 thres, bool lossy) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci if (lossy) 35662306a36Sopenharmony_ci mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, index, size); 35762306a36Sopenharmony_ci else 35862306a36Sopenharmony_ci mlxsw_reg_pbmc_lossless_buffer_pack(pbmc_pl, index, size, 35962306a36Sopenharmony_ci thres); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic u16 mlxsw_sp_hdroom_buf_delay_get(const struct mlxsw_sp *mlxsw_sp, 36362306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci u16 delay_cells; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci delay_cells = mlxsw_sp_bytes_cells(mlxsw_sp, hdroom->delay_bytes); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* In the worst case scenario the delay will be made up of packets that 37062306a36Sopenharmony_ci * are all of size CELL_SIZE + 1, which means each packet will require 37162306a36Sopenharmony_ci * almost twice its true size when buffered in the switch. We therefore 37262306a36Sopenharmony_ci * multiply this value by the "cell factor", which is close to 2. 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * Another MTU is added in case the transmitting host already started 37562306a36Sopenharmony_ci * transmitting a maximum length frame when the PFC packet was received. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ci return 2 * delay_cells + mlxsw_sp_bytes_cells(mlxsw_sp, hdroom->mtu); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic u32 mlxsw_sp_hdroom_int_buf_size_get(struct mlxsw_sp *mlxsw_sp, int mtu, u32 speed) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci u32 buffsize = mlxsw_sp->sb_ops->int_buf_size_get(mtu, speed); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return mlxsw_sp_bytes_cells(mlxsw_sp, buffsize) + 1; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic bool mlxsw_sp_hdroom_buf_is_used(const struct mlxsw_sp_hdroom *hdroom, int buf) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci int prio; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) { 39262306a36Sopenharmony_ci if (hdroom->prios.prio[prio].buf_idx == buf) 39362306a36Sopenharmony_ci return true; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci return false; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_civoid mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port, 39962306a36Sopenharmony_ci struct mlxsw_sp_hdroom *hdroom) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 40262306a36Sopenharmony_ci u16 reserve_cells; 40362306a36Sopenharmony_ci int i; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Internal buffer. */ 40662306a36Sopenharmony_ci reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_mtu, 40762306a36Sopenharmony_ci mlxsw_sp_port->max_speed); 40862306a36Sopenharmony_ci reserve_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, reserve_cells); 40962306a36Sopenharmony_ci hdroom->int_buf.reserve_cells = reserve_cells; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (hdroom->int_buf.enable) 41262306a36Sopenharmony_ci hdroom->int_buf.size_cells = reserve_cells; 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci hdroom->int_buf.size_cells = 0; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* PG buffers. */ 41762306a36Sopenharmony_ci for (i = 0; i < DCBX_MAX_BUFFERS; i++) { 41862306a36Sopenharmony_ci struct mlxsw_sp_hdroom_buf *buf = &hdroom->bufs.buf[i]; 41962306a36Sopenharmony_ci u16 thres_cells; 42062306a36Sopenharmony_ci u16 delay_cells; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (!mlxsw_sp_hdroom_buf_is_used(hdroom, i)) { 42362306a36Sopenharmony_ci thres_cells = 0; 42462306a36Sopenharmony_ci delay_cells = 0; 42562306a36Sopenharmony_ci } else if (buf->lossy) { 42662306a36Sopenharmony_ci thres_cells = mlxsw_sp_hdroom_buf_threshold_get(mlxsw_sp, hdroom->mtu); 42762306a36Sopenharmony_ci delay_cells = 0; 42862306a36Sopenharmony_ci } else { 42962306a36Sopenharmony_ci thres_cells = mlxsw_sp_hdroom_buf_threshold_get(mlxsw_sp, hdroom->mtu); 43062306a36Sopenharmony_ci delay_cells = mlxsw_sp_hdroom_buf_delay_get(mlxsw_sp, hdroom); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci thres_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, thres_cells); 43462306a36Sopenharmony_ci delay_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, delay_cells); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci buf->thres_cells = thres_cells; 43762306a36Sopenharmony_ci if (hdroom->mode == MLXSW_SP_HDROOM_MODE_DCB) { 43862306a36Sopenharmony_ci buf->size_cells = thres_cells + delay_cells; 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci /* Do not allow going below the minimum size, even if 44162306a36Sopenharmony_ci * the user requested it. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ci buf->size_cells = max(buf->set_size_cells, buf->thres_cells); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci#define MLXSW_SP_PB_UNUSED 8 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int mlxsw_sp_hdroom_configure_buffers(struct mlxsw_sp_port *mlxsw_sp_port, 45162306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom, bool force) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 45462306a36Sopenharmony_ci char pbmc_pl[MLXSW_REG_PBMC_LEN]; 45562306a36Sopenharmony_ci bool dirty; 45662306a36Sopenharmony_ci int err; 45762306a36Sopenharmony_ci int i; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci dirty = memcmp(&mlxsw_sp_port->hdroom->bufs, &hdroom->bufs, sizeof(hdroom->bufs)); 46062306a36Sopenharmony_ci if (!dirty && !force) 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, 0xffff, 0xffff / 2); 46462306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_PB_COUNT; i++) { 46562306a36Sopenharmony_ci const struct mlxsw_sp_hdroom_buf *buf = &hdroom->bufs.buf[i]; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (i == MLXSW_SP_PB_UNUSED) 46862306a36Sopenharmony_ci continue; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci mlxsw_sp_hdroom_buf_pack(pbmc_pl, i, buf->size_cells, buf->thres_cells, buf->lossy); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0); 47462306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl); 47562306a36Sopenharmony_ci if (err) 47662306a36Sopenharmony_ci return err; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mlxsw_sp_port->hdroom->bufs = hdroom->bufs; 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int mlxsw_sp_hdroom_configure_priomap(struct mlxsw_sp_port *mlxsw_sp_port, 48362306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom, bool force) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci char pptb_pl[MLXSW_REG_PPTB_LEN]; 48662306a36Sopenharmony_ci bool dirty; 48762306a36Sopenharmony_ci int prio; 48862306a36Sopenharmony_ci int err; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci dirty = memcmp(&mlxsw_sp_port->hdroom->prios, &hdroom->prios, sizeof(hdroom->prios)); 49162306a36Sopenharmony_ci if (!dirty && !force) 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port); 49562306a36Sopenharmony_ci for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) 49662306a36Sopenharmony_ci mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, prio, hdroom->prios.prio[prio].buf_idx); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl); 49962306a36Sopenharmony_ci if (err) 50062306a36Sopenharmony_ci return err; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci mlxsw_sp_port->hdroom->prios = hdroom->prios; 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic int mlxsw_sp_hdroom_configure_int_buf(struct mlxsw_sp_port *mlxsw_sp_port, 50762306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom, bool force) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci char sbib_pl[MLXSW_REG_SBIB_LEN]; 51062306a36Sopenharmony_ci bool dirty; 51162306a36Sopenharmony_ci int err; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci dirty = memcmp(&mlxsw_sp_port->hdroom->int_buf, &hdroom->int_buf, sizeof(hdroom->int_buf)); 51462306a36Sopenharmony_ci if (!dirty && !force) 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci mlxsw_reg_sbib_pack(sbib_pl, mlxsw_sp_port->local_port, hdroom->int_buf.size_cells); 51862306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); 51962306a36Sopenharmony_ci if (err) 52062306a36Sopenharmony_ci return err; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci mlxsw_sp_port->hdroom->int_buf = hdroom->int_buf; 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp, 52762306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci u32 taken_headroom_cells = 0; 53062306a36Sopenharmony_ci int i; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_PB_COUNT; i++) 53362306a36Sopenharmony_ci taken_headroom_cells += hdroom->bufs.buf[i].size_cells; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci taken_headroom_cells += hdroom->int_buf.reserve_cells; 53662306a36Sopenharmony_ci return taken_headroom_cells <= mlxsw_sp->sb->max_headroom_cells; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int __mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, 54062306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom, bool force) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct mlxsw_sp_hdroom orig_hdroom; 54362306a36Sopenharmony_ci struct mlxsw_sp_hdroom tmp_hdroom; 54462306a36Sopenharmony_ci int err; 54562306a36Sopenharmony_ci int i; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Port buffers need to be configured in three steps. First, all buffers 54862306a36Sopenharmony_ci * with non-zero size are configured. Then, prio-to-buffer map is 54962306a36Sopenharmony_ci * updated, allowing traffic to flow to the now non-zero buffers. 55062306a36Sopenharmony_ci * Finally, zero-sized buffers are configured, because now no traffic 55162306a36Sopenharmony_ci * should be directed to them anymore. This way, in a non-congested 55262306a36Sopenharmony_ci * system, no packet drops are introduced by the reconfiguration. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci orig_hdroom = *mlxsw_sp_port->hdroom; 55662306a36Sopenharmony_ci tmp_hdroom = orig_hdroom; 55762306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_PB_COUNT; i++) { 55862306a36Sopenharmony_ci if (hdroom->bufs.buf[i].size_cells) 55962306a36Sopenharmony_ci tmp_hdroom.bufs.buf[i] = hdroom->bufs.buf[i]; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (!mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, &tmp_hdroom) || 56362306a36Sopenharmony_ci !mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, hdroom)) 56462306a36Sopenharmony_ci return -ENOBUFS; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &tmp_hdroom, force); 56762306a36Sopenharmony_ci if (err) 56862306a36Sopenharmony_ci return err; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci err = mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, hdroom, force); 57162306a36Sopenharmony_ci if (err) 57262306a36Sopenharmony_ci goto err_configure_priomap; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, hdroom, false); 57562306a36Sopenharmony_ci if (err) 57662306a36Sopenharmony_ci goto err_configure_buffers; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci err = mlxsw_sp_hdroom_configure_int_buf(mlxsw_sp_port, hdroom, false); 57962306a36Sopenharmony_ci if (err) 58062306a36Sopenharmony_ci goto err_configure_int_buf; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci *mlxsw_sp_port->hdroom = *hdroom; 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cierr_configure_int_buf: 58662306a36Sopenharmony_ci mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &tmp_hdroom, false); 58762306a36Sopenharmony_cierr_configure_buffers: 58862306a36Sopenharmony_ci mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, &tmp_hdroom, false); 58962306a36Sopenharmony_cierr_configure_priomap: 59062306a36Sopenharmony_ci mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &orig_hdroom, false); 59162306a36Sopenharmony_ci return err; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ciint mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, 59562306a36Sopenharmony_ci const struct mlxsw_sp_hdroom *hdroom) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci return __mlxsw_sp_hdroom_configure(mlxsw_sp_port, hdroom, false); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 60362306a36Sopenharmony_ci struct mlxsw_sp_hdroom hdroom = {}; 60462306a36Sopenharmony_ci u32 size9; 60562306a36Sopenharmony_ci int prio; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci hdroom.mtu = mlxsw_sp_port->dev->mtu; 60862306a36Sopenharmony_ci hdroom.mode = MLXSW_SP_HDROOM_MODE_DCB; 60962306a36Sopenharmony_ci for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) 61062306a36Sopenharmony_ci hdroom.prios.prio[prio].lossy = true; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom); 61362306a36Sopenharmony_ci mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* Buffer 9 is used for control traffic. */ 61662306a36Sopenharmony_ci size9 = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, mlxsw_sp_port->max_mtu); 61762306a36Sopenharmony_ci hdroom.bufs.buf[9].size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size9); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return __mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom, true); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int mlxsw_sp_sb_port_init(struct mlxsw_sp *mlxsw_sp, 62362306a36Sopenharmony_ci struct mlxsw_sp_sb_port *sb_port) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pms; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci pms = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*pms), 62862306a36Sopenharmony_ci GFP_KERNEL); 62962306a36Sopenharmony_ci if (!pms) 63062306a36Sopenharmony_ci return -ENOMEM; 63162306a36Sopenharmony_ci sb_port->pms = pms; 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void mlxsw_sp_sb_port_fini(struct mlxsw_sp_sb_port *sb_port) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci kfree(sb_port->pms); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 64362306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *prs; 64462306a36Sopenharmony_ci int i; 64562306a36Sopenharmony_ci int err; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mlxsw_sp->sb->ports = kcalloc(max_ports, 64862306a36Sopenharmony_ci sizeof(struct mlxsw_sp_sb_port), 64962306a36Sopenharmony_ci GFP_KERNEL); 65062306a36Sopenharmony_ci if (!mlxsw_sp->sb->ports) 65162306a36Sopenharmony_ci return -ENOMEM; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci prs = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*prs), 65462306a36Sopenharmony_ci GFP_KERNEL); 65562306a36Sopenharmony_ci if (!prs) { 65662306a36Sopenharmony_ci err = -ENOMEM; 65762306a36Sopenharmony_ci goto err_alloc_prs; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci mlxsw_sp->sb->prs = prs; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci for (i = 0; i < max_ports; i++) { 66262306a36Sopenharmony_ci err = mlxsw_sp_sb_port_init(mlxsw_sp, &mlxsw_sp->sb->ports[i]); 66362306a36Sopenharmony_ci if (err) 66462306a36Sopenharmony_ci goto err_sb_port_init; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cierr_sb_port_init: 67062306a36Sopenharmony_ci for (i--; i >= 0; i--) 67162306a36Sopenharmony_ci mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]); 67262306a36Sopenharmony_ci kfree(mlxsw_sp->sb->prs); 67362306a36Sopenharmony_cierr_alloc_prs: 67462306a36Sopenharmony_ci kfree(mlxsw_sp->sb->ports); 67562306a36Sopenharmony_ci return err; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 68162306a36Sopenharmony_ci int i; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci for (i = max_ports - 1; i >= 0; i--) 68462306a36Sopenharmony_ci mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]); 68562306a36Sopenharmony_ci kfree(mlxsw_sp->sb->prs); 68662306a36Sopenharmony_ci kfree(mlxsw_sp->sb->ports); 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci#define MLXSW_SP_SB_PR(_mode, _size) \ 69062306a36Sopenharmony_ci { \ 69162306a36Sopenharmony_ci .mode = _mode, \ 69262306a36Sopenharmony_ci .size = _size, \ 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci#define MLXSW_SP_SB_PR_EXT(_mode, _size, _freeze_mode, _freeze_size) \ 69662306a36Sopenharmony_ci { \ 69762306a36Sopenharmony_ci .mode = _mode, \ 69862306a36Sopenharmony_ci .size = _size, \ 69962306a36Sopenharmony_ci .freeze_mode = _freeze_mode, \ 70062306a36Sopenharmony_ci .freeze_size = _freeze_size, \ 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci#define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000) 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* Order according to mlxsw_sp1_sb_pool_dess */ 70662306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { 70762306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), 70862306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 70962306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 71062306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 71162306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, 71262306a36Sopenharmony_ci true, false), 71362306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 71462306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 71562306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 71662306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI, 71762306a36Sopenharmony_ci true, true), 71862306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, 71962306a36Sopenharmony_ci MLXSW_SP1_SB_PR_CPU_SIZE, true, false), 72062306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, 72162306a36Sopenharmony_ci MLXSW_SP1_SB_PR_CPU_SIZE, true, false), 72262306a36Sopenharmony_ci}; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci#define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci/* Order according to mlxsw_sp2_sb_pool_dess */ 72762306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { 72862306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), 72962306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), 73062306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), 73162306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), 73262306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, 73362306a36Sopenharmony_ci true, false), 73462306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), 73562306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), 73662306a36Sopenharmony_ci MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), 73762306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI, 73862306a36Sopenharmony_ci true, true), 73962306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, 74062306a36Sopenharmony_ci MLXSW_SP2_SB_PR_CPU_SIZE, true, false), 74162306a36Sopenharmony_ci MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, 74262306a36Sopenharmony_ci MLXSW_SP2_SB_PR_CPU_SIZE, true, false), 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, 74662306a36Sopenharmony_ci const struct mlxsw_sp_sb_pr *prs, 74762306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *pool_dess, 74862306a36Sopenharmony_ci size_t prs_len) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci /* Round down, unlike mlxsw_sp_bytes_cells(). */ 75162306a36Sopenharmony_ci u32 sb_cells = div_u64(mlxsw_sp->sb->sb_size, mlxsw_sp->sb->cell_size); 75262306a36Sopenharmony_ci u32 rest_cells[2] = {sb_cells, sb_cells}; 75362306a36Sopenharmony_ci int i; 75462306a36Sopenharmony_ci int err; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* Calculate how much space to give to the "REST" pools in either 75762306a36Sopenharmony_ci * direction. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci for (i = 0; i < prs_len; i++) { 76062306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir = pool_dess[i].dir; 76162306a36Sopenharmony_ci u32 size = prs[i].size; 76262306a36Sopenharmony_ci u32 size_cells; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (size == MLXSW_SP_SB_INFI || size == MLXSW_SP_SB_REST) 76562306a36Sopenharmony_ci continue; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); 76862306a36Sopenharmony_ci if (WARN_ON_ONCE(size_cells > rest_cells[dir])) 76962306a36Sopenharmony_ci continue; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci rest_cells[dir] -= size_cells; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci for (i = 0; i < prs_len; i++) { 77562306a36Sopenharmony_ci u32 size = prs[i].size; 77662306a36Sopenharmony_ci u32 size_cells; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (size == MLXSW_SP_SB_INFI) { 77962306a36Sopenharmony_ci err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, 78062306a36Sopenharmony_ci 0, true); 78162306a36Sopenharmony_ci } else if (size == MLXSW_SP_SB_REST) { 78262306a36Sopenharmony_ci size_cells = rest_cells[pool_dess[i].dir]; 78362306a36Sopenharmony_ci err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, 78462306a36Sopenharmony_ci size_cells, false); 78562306a36Sopenharmony_ci } else { 78662306a36Sopenharmony_ci size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); 78762306a36Sopenharmony_ci err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, 78862306a36Sopenharmony_ci size_cells, false); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci if (err) 79162306a36Sopenharmony_ci return err; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci err = mlxsw_sp_sb_pr_desc_write(mlxsw_sp, MLXSW_REG_SBXX_DIR_INGRESS, 79562306a36Sopenharmony_ci MLXSW_REG_SBPR_MODE_DYNAMIC, 0, true); 79662306a36Sopenharmony_ci if (err) 79762306a36Sopenharmony_ci return err; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci err = mlxsw_sp_sb_pr_desc_write(mlxsw_sp, MLXSW_REG_SBXX_DIR_EGRESS, 80062306a36Sopenharmony_ci MLXSW_REG_SBPR_MODE_DYNAMIC, 0, true); 80162306a36Sopenharmony_ci if (err) 80262306a36Sopenharmony_ci return err; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci#define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \ 80862306a36Sopenharmony_ci { \ 80962306a36Sopenharmony_ci .min_buff = _min_buff, \ 81062306a36Sopenharmony_ci .max_buff = _max_buff, \ 81162306a36Sopenharmony_ci .pool_index = _pool, \ 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci#define MLXSW_SP_SB_CM_ING(_min_buff, _max_buff) \ 81562306a36Sopenharmony_ci { \ 81662306a36Sopenharmony_ci .min_buff = _min_buff, \ 81762306a36Sopenharmony_ci .max_buff = _max_buff, \ 81862306a36Sopenharmony_ci .pool_index = MLXSW_SP_SB_POOL_ING, \ 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci#define MLXSW_SP_SB_CM_EGR(_min_buff, _max_buff) \ 82262306a36Sopenharmony_ci { \ 82362306a36Sopenharmony_ci .min_buff = _min_buff, \ 82462306a36Sopenharmony_ci .max_buff = _max_buff, \ 82562306a36Sopenharmony_ci .pool_index = MLXSW_SP_SB_POOL_EGR, \ 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci#define MLXSW_SP_SB_CM_EGR_MC(_min_buff, _max_buff) \ 82962306a36Sopenharmony_ci { \ 83062306a36Sopenharmony_ci .min_buff = _min_buff, \ 83162306a36Sopenharmony_ci .max_buff = _max_buff, \ 83262306a36Sopenharmony_ci .pool_index = MLXSW_SP_SB_POOL_EGR_MC, \ 83362306a36Sopenharmony_ci .freeze_pool = true, \ 83462306a36Sopenharmony_ci .freeze_thresh = true, \ 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_ingress[] = { 83862306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(10000, 8), 83962306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84062306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84162306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84262306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84362306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84462306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84562306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 84662306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, 0), /* dummy, this PG does not exist */ 84762306a36Sopenharmony_ci MLXSW_SP_SB_CM(10000, 8, MLXSW_SP_SB_POOL_ING_CPU), 84862306a36Sopenharmony_ci}; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_ingress[] = { 85162306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, 7), 85262306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85362306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85462306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85562306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85662306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85762306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85862306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 85962306a36Sopenharmony_ci MLXSW_SP_SB_CM_ING(0, 0), /* dummy, this PG does not exist */ 86062306a36Sopenharmony_ci MLXSW_SP_SB_CM(10000, 8, MLXSW_SP_SB_POOL_ING_CPU), 86162306a36Sopenharmony_ci}; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_egress[] = { 86462306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 86562306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 86662306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 86762306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 86862306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 86962306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 87062306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 87162306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1500, 9), 87262306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87362306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87462306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87562306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87662306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87762306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87862306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 87962306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 88062306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1, 0xff), 88162306a36Sopenharmony_ci}; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_egress[] = { 88462306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 88562306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 88662306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 88762306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 88862306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 88962306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 89062306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 89162306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(0, 7), 89262306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89362306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89462306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89562306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89662306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89762306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89862306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 89962306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), 90062306a36Sopenharmony_ci MLXSW_SP_SB_CM_EGR(1, 0xff), 90162306a36Sopenharmony_ci}; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, MLXSW_SP_SB_POOL_EGR_CPU) 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = { 90662306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 90762306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 90862306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 90962306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 91062306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 91162306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 91262306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 91362306a36Sopenharmony_ci MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), 91462306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 91562306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 91662306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 91762306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 91862306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 91962306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92062306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92162306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92262306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92362306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92462306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92562306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92662306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92762306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92862306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 92962306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93062306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93162306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93262306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93362306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93462306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93562306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93662306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93762306a36Sopenharmony_ci MLXSW_SP_CPU_PORT_SB_CM, 93862306a36Sopenharmony_ci}; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic bool 94162306a36Sopenharmony_cimlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return pr->mode == MLXSW_REG_SBPR_MODE_STATIC; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u16 local_port, 94962306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir, 95062306a36Sopenharmony_ci const struct mlxsw_sp_sb_cm *cms, 95162306a36Sopenharmony_ci size_t cms_len) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci const struct mlxsw_sp_sb_vals *sb_vals = mlxsw_sp->sb_vals; 95462306a36Sopenharmony_ci int i; 95562306a36Sopenharmony_ci int err; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci for (i = 0; i < cms_len; i++) { 95862306a36Sopenharmony_ci const struct mlxsw_sp_sb_cm *cm; 95962306a36Sopenharmony_ci u32 min_buff; 96062306a36Sopenharmony_ci u32 max_buff; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS) 96362306a36Sopenharmony_ci continue; /* PG number 8 does not exist, skip it */ 96462306a36Sopenharmony_ci cm = &cms[i]; 96562306a36Sopenharmony_ci if (WARN_ON(sb_vals->pool_dess[cm->pool_index].dir != dir)) 96662306a36Sopenharmony_ci continue; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff); 96962306a36Sopenharmony_ci max_buff = cm->max_buff; 97062306a36Sopenharmony_ci if (max_buff == MLXSW_SP_SB_INFI) { 97162306a36Sopenharmony_ci err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, 97262306a36Sopenharmony_ci min_buff, 0, 97362306a36Sopenharmony_ci true, cm->pool_index); 97462306a36Sopenharmony_ci } else { 97562306a36Sopenharmony_ci if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, 97662306a36Sopenharmony_ci cm->pool_index)) 97762306a36Sopenharmony_ci max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, 97862306a36Sopenharmony_ci max_buff); 97962306a36Sopenharmony_ci err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, 98062306a36Sopenharmony_ci min_buff, max_buff, 98162306a36Sopenharmony_ci false, cm->pool_index); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci if (err) 98462306a36Sopenharmony_ci return err; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci return 0; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 99262306a36Sopenharmony_ci int err; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci err = __mlxsw_sp_sb_cms_init(mlxsw_sp, 99562306a36Sopenharmony_ci mlxsw_sp_port->local_port, 99662306a36Sopenharmony_ci MLXSW_REG_SBXX_DIR_INGRESS, 99762306a36Sopenharmony_ci mlxsw_sp->sb_vals->cms_ingress, 99862306a36Sopenharmony_ci mlxsw_sp->sb_vals->cms_ingress_count); 99962306a36Sopenharmony_ci if (err) 100062306a36Sopenharmony_ci return err; 100162306a36Sopenharmony_ci return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp, 100262306a36Sopenharmony_ci mlxsw_sp_port->local_port, 100362306a36Sopenharmony_ci MLXSW_REG_SBXX_DIR_EGRESS, 100462306a36Sopenharmony_ci mlxsw_sp->sb_vals->cms_egress, 100562306a36Sopenharmony_ci mlxsw_sp->sb_vals->cms_egress_count); 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS, 101162306a36Sopenharmony_ci mlxsw_sp->sb_vals->cms_cpu, 101262306a36Sopenharmony_ci mlxsw_sp->sb_vals->cms_cpu_count); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci#define MLXSW_SP_SB_PM(_min_buff, _max_buff) \ 101662306a36Sopenharmony_ci { \ 101762306a36Sopenharmony_ci .min_buff = _min_buff, \ 101862306a36Sopenharmony_ci .max_buff = _max_buff, \ 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/* Order according to mlxsw_sp1_sb_pool_dess */ 102262306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pm mlxsw_sp1_sb_pms[] = { 102362306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), 102462306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 102562306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 102662306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 102762306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 7), 102862306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 102962306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 103062306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 103162306a36Sopenharmony_ci MLXSW_SP_SB_PM(10000, 90000), 103262306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 8), /* 50% occupancy */ 103362306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 103462306a36Sopenharmony_ci}; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci/* Order according to mlxsw_sp2_sb_pool_dess */ 103762306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pm mlxsw_sp2_sb_pms[] = { 103862306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 7), 103962306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 104062306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 104162306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 104262306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 7), 104362306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 104462306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 104562306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 104662306a36Sopenharmony_ci MLXSW_SP_SB_PM(10000, 90000), 104762306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 8), /* 50% occupancy */ 104862306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 104962306a36Sopenharmony_ci}; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci/* Order according to mlxsw_sp*_sb_pool_dess */ 105262306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_pm mlxsw_sp_cpu_port_sb_pms[] = { 105362306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 105462306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 105562306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 105662306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 105762306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 105862306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 105962306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 106062306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 106162306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 90000), 106262306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, 0), 106362306a36Sopenharmony_ci MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), 106462306a36Sopenharmony_ci}; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic int mlxsw_sp_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u16 local_port, 106762306a36Sopenharmony_ci const struct mlxsw_sp_sb_pm *pms, 106862306a36Sopenharmony_ci bool skip_ingress) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci int i, err; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) { 107362306a36Sopenharmony_ci const struct mlxsw_sp_sb_pm *pm = &pms[i]; 107462306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des; 107562306a36Sopenharmony_ci u32 max_buff; 107662306a36Sopenharmony_ci u32 min_buff; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci des = &mlxsw_sp->sb_vals->pool_dess[i]; 107962306a36Sopenharmony_ci if (skip_ingress && des->dir == MLXSW_REG_SBXX_DIR_INGRESS) 108062306a36Sopenharmony_ci continue; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, pm->min_buff); 108362306a36Sopenharmony_ci max_buff = pm->max_buff; 108462306a36Sopenharmony_ci if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, i)) 108562306a36Sopenharmony_ci max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, max_buff); 108662306a36Sopenharmony_ci err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, min_buff, 108762306a36Sopenharmony_ci max_buff); 108862306a36Sopenharmony_ci if (err) 108962306a36Sopenharmony_ci return err; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci return 0; 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci return mlxsw_sp_sb_pms_init(mlxsw_sp, mlxsw_sp_port->local_port, 109962306a36Sopenharmony_ci mlxsw_sp->sb_vals->pms, false); 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic int mlxsw_sp_cpu_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci return mlxsw_sp_sb_pms_init(mlxsw_sp, 0, mlxsw_sp->sb_vals->pms_cpu, 110562306a36Sopenharmony_ci true); 110662306a36Sopenharmony_ci} 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci#define MLXSW_SP_SB_MM(_min_buff, _max_buff) \ 110962306a36Sopenharmony_ci { \ 111062306a36Sopenharmony_ci .min_buff = _min_buff, \ 111162306a36Sopenharmony_ci .max_buff = _max_buff, \ 111262306a36Sopenharmony_ci .pool_index = MLXSW_SP_SB_POOL_EGR, \ 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = { 111662306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 111762306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 111862306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 111962306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112062306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112162306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112262306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112362306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112462306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112562306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112662306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112762306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112862306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 112962306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 113062306a36Sopenharmony_ci MLXSW_SP_SB_MM(0, 6), 113162306a36Sopenharmony_ci}; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci char sbmm_pl[MLXSW_REG_SBMM_LEN]; 113662306a36Sopenharmony_ci int i; 113762306a36Sopenharmony_ci int err; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci for (i = 0; i < mlxsw_sp->sb_vals->mms_count; i++) { 114062306a36Sopenharmony_ci const struct mlxsw_sp_sb_pool_des *des; 114162306a36Sopenharmony_ci const struct mlxsw_sp_sb_mm *mc; 114262306a36Sopenharmony_ci u32 min_buff; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci mc = &mlxsw_sp->sb_vals->mms[i]; 114562306a36Sopenharmony_ci des = &mlxsw_sp->sb_vals->pool_dess[mc->pool_index]; 114662306a36Sopenharmony_ci /* All pools used by sb_mm's are initialized using dynamic 114762306a36Sopenharmony_ci * thresholds, therefore 'max_buff' isn't specified in cells. 114862306a36Sopenharmony_ci */ 114962306a36Sopenharmony_ci min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff); 115062306a36Sopenharmony_ci mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff, 115162306a36Sopenharmony_ci des->pool); 115262306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl); 115362306a36Sopenharmony_ci if (err) 115462306a36Sopenharmony_ci return err; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci return 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic void mlxsw_sp_pool_count(struct mlxsw_sp *mlxsw_sp, 116062306a36Sopenharmony_ci u16 *p_ingress_len, u16 *p_egress_len) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci int i; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci for (i = 0; i < mlxsw_sp->sb_vals->pool_count; ++i) { 116562306a36Sopenharmony_ci if (mlxsw_sp->sb_vals->pool_dess[i].dir == 116662306a36Sopenharmony_ci MLXSW_REG_SBXX_DIR_INGRESS) 116762306a36Sopenharmony_ci (*p_ingress_len)++; 116862306a36Sopenharmony_ci else 116962306a36Sopenharmony_ci (*p_egress_len)++; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci WARN(*p_egress_len == 0, "No egress pools\n"); 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ciconst struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals = { 117662306a36Sopenharmony_ci .pool_count = ARRAY_SIZE(mlxsw_sp1_sb_pool_dess), 117762306a36Sopenharmony_ci .pool_dess = mlxsw_sp1_sb_pool_dess, 117862306a36Sopenharmony_ci .pms = mlxsw_sp1_sb_pms, 117962306a36Sopenharmony_ci .pms_cpu = mlxsw_sp_cpu_port_sb_pms, 118062306a36Sopenharmony_ci .prs = mlxsw_sp1_sb_prs, 118162306a36Sopenharmony_ci .mms = mlxsw_sp_sb_mms, 118262306a36Sopenharmony_ci .cms_ingress = mlxsw_sp1_sb_cms_ingress, 118362306a36Sopenharmony_ci .cms_egress = mlxsw_sp1_sb_cms_egress, 118462306a36Sopenharmony_ci .cms_cpu = mlxsw_sp_cpu_port_sb_cms, 118562306a36Sopenharmony_ci .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms), 118662306a36Sopenharmony_ci .cms_ingress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_ingress), 118762306a36Sopenharmony_ci .cms_egress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_egress), 118862306a36Sopenharmony_ci .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms), 118962306a36Sopenharmony_ci}; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ciconst struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals = { 119262306a36Sopenharmony_ci .pool_count = ARRAY_SIZE(mlxsw_sp2_sb_pool_dess), 119362306a36Sopenharmony_ci .pool_dess = mlxsw_sp2_sb_pool_dess, 119462306a36Sopenharmony_ci .pms = mlxsw_sp2_sb_pms, 119562306a36Sopenharmony_ci .pms_cpu = mlxsw_sp_cpu_port_sb_pms, 119662306a36Sopenharmony_ci .prs = mlxsw_sp2_sb_prs, 119762306a36Sopenharmony_ci .mms = mlxsw_sp_sb_mms, 119862306a36Sopenharmony_ci .cms_ingress = mlxsw_sp2_sb_cms_ingress, 119962306a36Sopenharmony_ci .cms_egress = mlxsw_sp2_sb_cms_egress, 120062306a36Sopenharmony_ci .cms_cpu = mlxsw_sp_cpu_port_sb_cms, 120162306a36Sopenharmony_ci .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms), 120262306a36Sopenharmony_ci .cms_ingress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_ingress), 120362306a36Sopenharmony_ci .cms_egress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_egress), 120462306a36Sopenharmony_ci .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms), 120562306a36Sopenharmony_ci}; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic u32 mlxsw_sp1_pb_int_buf_size_get(int mtu, u32 speed) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci return mtu * 5 / 2; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic u32 __mlxsw_sp_pb_int_buf_size_get(int mtu, u32 speed, u32 buffer_factor) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci return 3 * mtu + buffer_factor * speed / 1000; 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci#define MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR 38 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic u32 mlxsw_sp2_pb_int_buf_size_get(int mtu, u32 speed) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci int factor = MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci return __mlxsw_sp_pb_int_buf_size_get(mtu, speed, factor); 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci#define MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR 50 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic u32 mlxsw_sp3_pb_int_buf_size_get(int mtu, u32 speed) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci int factor = MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci return __mlxsw_sp_pb_int_buf_size_get(mtu, speed, factor); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ciconst struct mlxsw_sp_sb_ops mlxsw_sp1_sb_ops = { 123662306a36Sopenharmony_ci .int_buf_size_get = mlxsw_sp1_pb_int_buf_size_get, 123762306a36Sopenharmony_ci}; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ciconst struct mlxsw_sp_sb_ops mlxsw_sp2_sb_ops = { 124062306a36Sopenharmony_ci .int_buf_size_get = mlxsw_sp2_pb_int_buf_size_get, 124162306a36Sopenharmony_ci}; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ciconst struct mlxsw_sp_sb_ops mlxsw_sp3_sb_ops = { 124462306a36Sopenharmony_ci .int_buf_size_get = mlxsw_sp3_pb_int_buf_size_get, 124562306a36Sopenharmony_ci}; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ciint mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci u32 max_headroom_size; 125062306a36Sopenharmony_ci u16 ing_pool_count = 0; 125162306a36Sopenharmony_ci u16 eg_pool_count = 0; 125262306a36Sopenharmony_ci int err; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) 125562306a36Sopenharmony_ci return -EIO; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, GUARANTEED_SHARED_BUFFER)) 125862306a36Sopenharmony_ci return -EIO; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE)) 126162306a36Sopenharmony_ci return -EIO; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL); 126462306a36Sopenharmony_ci if (!mlxsw_sp->sb) 126562306a36Sopenharmony_ci return -ENOMEM; 126662306a36Sopenharmony_ci mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); 126762306a36Sopenharmony_ci mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, 126862306a36Sopenharmony_ci GUARANTEED_SHARED_BUFFER); 126962306a36Sopenharmony_ci max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, 127062306a36Sopenharmony_ci MAX_HEADROOM_SIZE); 127162306a36Sopenharmony_ci /* Round down, because this limit must not be overstepped. */ 127262306a36Sopenharmony_ci mlxsw_sp->sb->max_headroom_cells = max_headroom_size / 127362306a36Sopenharmony_ci mlxsw_sp->sb->cell_size; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci err = mlxsw_sp_sb_ports_init(mlxsw_sp); 127662306a36Sopenharmony_ci if (err) 127762306a36Sopenharmony_ci goto err_sb_ports_init; 127862306a36Sopenharmony_ci err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs, 127962306a36Sopenharmony_ci mlxsw_sp->sb_vals->pool_dess, 128062306a36Sopenharmony_ci mlxsw_sp->sb_vals->pool_count); 128162306a36Sopenharmony_ci if (err) 128262306a36Sopenharmony_ci goto err_sb_prs_init; 128362306a36Sopenharmony_ci err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp); 128462306a36Sopenharmony_ci if (err) 128562306a36Sopenharmony_ci goto err_sb_cpu_port_sb_cms_init; 128662306a36Sopenharmony_ci err = mlxsw_sp_cpu_port_sb_pms_init(mlxsw_sp); 128762306a36Sopenharmony_ci if (err) 128862306a36Sopenharmony_ci goto err_sb_cpu_port_pms_init; 128962306a36Sopenharmony_ci err = mlxsw_sp_sb_mms_init(mlxsw_sp); 129062306a36Sopenharmony_ci if (err) 129162306a36Sopenharmony_ci goto err_sb_mms_init; 129262306a36Sopenharmony_ci mlxsw_sp_pool_count(mlxsw_sp, &ing_pool_count, &eg_pool_count); 129362306a36Sopenharmony_ci err = devl_sb_register(priv_to_devlink(mlxsw_sp->core), 0, 129462306a36Sopenharmony_ci mlxsw_sp->sb->sb_size, 129562306a36Sopenharmony_ci ing_pool_count, 129662306a36Sopenharmony_ci eg_pool_count, 129762306a36Sopenharmony_ci MLXSW_SP_SB_ING_TC_COUNT, 129862306a36Sopenharmony_ci MLXSW_SP_SB_EG_TC_COUNT); 129962306a36Sopenharmony_ci if (err) 130062306a36Sopenharmony_ci goto err_devlink_sb_register; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cierr_devlink_sb_register: 130562306a36Sopenharmony_cierr_sb_mms_init: 130662306a36Sopenharmony_cierr_sb_cpu_port_pms_init: 130762306a36Sopenharmony_cierr_sb_cpu_port_sb_cms_init: 130862306a36Sopenharmony_cierr_sb_prs_init: 130962306a36Sopenharmony_ci mlxsw_sp_sb_ports_fini(mlxsw_sp); 131062306a36Sopenharmony_cierr_sb_ports_init: 131162306a36Sopenharmony_ci kfree(mlxsw_sp->sb); 131262306a36Sopenharmony_ci return err; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_civoid mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci devl_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0); 131862306a36Sopenharmony_ci mlxsw_sp_sb_ports_fini(mlxsw_sp); 131962306a36Sopenharmony_ci kfree(mlxsw_sp->sb); 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ciint mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci int err; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci mlxsw_sp_port->hdroom = kzalloc(sizeof(*mlxsw_sp_port->hdroom), GFP_KERNEL); 132762306a36Sopenharmony_ci if (!mlxsw_sp_port->hdroom) 132862306a36Sopenharmony_ci return -ENOMEM; 132962306a36Sopenharmony_ci mlxsw_sp_port->hdroom->mtu = mlxsw_sp_port->dev->mtu; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci err = mlxsw_sp_port_headroom_init(mlxsw_sp_port); 133262306a36Sopenharmony_ci if (err) 133362306a36Sopenharmony_ci goto err_headroom_init; 133462306a36Sopenharmony_ci err = mlxsw_sp_port_sb_cms_init(mlxsw_sp_port); 133562306a36Sopenharmony_ci if (err) 133662306a36Sopenharmony_ci goto err_port_sb_cms_init; 133762306a36Sopenharmony_ci err = mlxsw_sp_port_sb_pms_init(mlxsw_sp_port); 133862306a36Sopenharmony_ci if (err) 133962306a36Sopenharmony_ci goto err_port_sb_pms_init; 134062306a36Sopenharmony_ci return 0; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cierr_port_sb_pms_init: 134362306a36Sopenharmony_cierr_port_sb_cms_init: 134462306a36Sopenharmony_cierr_headroom_init: 134562306a36Sopenharmony_ci kfree(mlxsw_sp_port->hdroom); 134662306a36Sopenharmony_ci return err; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_civoid mlxsw_sp_port_buffers_fini(struct mlxsw_sp_port *mlxsw_sp_port) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci kfree(mlxsw_sp_port->hdroom); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ciint mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core, 135562306a36Sopenharmony_ci unsigned int sb_index, u16 pool_index, 135662306a36Sopenharmony_ci struct devlink_sb_pool_info *pool_info) 135762306a36Sopenharmony_ci{ 135862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 135962306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir; 136062306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *pr; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci dir = mlxsw_sp->sb_vals->pool_dess[pool_index].dir; 136362306a36Sopenharmony_ci pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); 136462306a36Sopenharmony_ci pool_info->pool_type = (enum devlink_sb_pool_type) dir; 136562306a36Sopenharmony_ci pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size); 136662306a36Sopenharmony_ci pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode; 136762306a36Sopenharmony_ci pool_info->cell_size = mlxsw_sp->sb->cell_size; 136862306a36Sopenharmony_ci return 0; 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ciint mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, 137262306a36Sopenharmony_ci unsigned int sb_index, u16 pool_index, u32 size, 137362306a36Sopenharmony_ci enum devlink_sb_threshold_type threshold_type, 137462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 137762306a36Sopenharmony_ci u32 pool_size = mlxsw_sp_bytes_cells(mlxsw_sp, size); 137862306a36Sopenharmony_ci const struct mlxsw_sp_sb_pr *pr; 137962306a36Sopenharmony_ci enum mlxsw_reg_sbpr_mode mode; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci mode = (enum mlxsw_reg_sbpr_mode) threshold_type; 138262306a36Sopenharmony_ci pr = &mlxsw_sp->sb_vals->prs[pool_index]; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, 138562306a36Sopenharmony_ci GUARANTEED_SHARED_BUFFER)) { 138662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Exceeded shared buffer size"); 138762306a36Sopenharmony_ci return -EINVAL; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (pr->freeze_mode && pr->mode != mode) { 139162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Changing this pool's threshold type is forbidden"); 139262306a36Sopenharmony_ci return -EINVAL; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (pr->freeze_size && pr->size != size) { 139662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Changing this pool's size is forbidden"); 139762306a36Sopenharmony_ci return -EINVAL; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, 140162306a36Sopenharmony_ci pool_size, false); 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci#define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */ 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistatic u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u16 pool_index, 140762306a36Sopenharmony_ci u32 max_buff) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) 141262306a36Sopenharmony_ci return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; 141362306a36Sopenharmony_ci return mlxsw_sp_cells_bytes(mlxsw_sp, max_buff); 141462306a36Sopenharmony_ci} 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_cistatic int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u16 pool_index, 141762306a36Sopenharmony_ci u32 threshold, u32 *p_max_buff, 141862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) { 142362306a36Sopenharmony_ci int val; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci val = threshold + MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; 142662306a36Sopenharmony_ci if (val < MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN || 142762306a36Sopenharmony_ci val > MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX) { 142862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Invalid dynamic threshold value"); 142962306a36Sopenharmony_ci return -EINVAL; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci *p_max_buff = val; 143262306a36Sopenharmony_ci } else { 143362306a36Sopenharmony_ci *p_max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, threshold); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci return 0; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ciint mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, 143962306a36Sopenharmony_ci unsigned int sb_index, u16 pool_index, 144062306a36Sopenharmony_ci u32 *p_threshold) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 144362306a36Sopenharmony_ci mlxsw_core_port_driver_priv(mlxsw_core_port); 144462306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 144562306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 144662306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, 144762306a36Sopenharmony_ci pool_index); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool_index, 145062306a36Sopenharmony_ci pm->max_buff); 145162306a36Sopenharmony_ci return 0; 145262306a36Sopenharmony_ci} 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ciint mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port, 145562306a36Sopenharmony_ci unsigned int sb_index, u16 pool_index, 145662306a36Sopenharmony_ci u32 threshold, struct netlink_ext_ack *extack) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 145962306a36Sopenharmony_ci mlxsw_core_port_driver_priv(mlxsw_core_port); 146062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 146162306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 146262306a36Sopenharmony_ci u32 max_buff; 146362306a36Sopenharmony_ci int err; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (local_port == MLXSW_PORT_CPU_PORT) { 146662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's threshold is forbidden"); 146762306a36Sopenharmony_ci return -EINVAL; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index, 147162306a36Sopenharmony_ci threshold, &max_buff, extack); 147262306a36Sopenharmony_ci if (err) 147362306a36Sopenharmony_ci return err; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool_index, 147662306a36Sopenharmony_ci 0, max_buff); 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ciint mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port, 148062306a36Sopenharmony_ci unsigned int sb_index, u16 tc_index, 148162306a36Sopenharmony_ci enum devlink_sb_pool_type pool_type, 148262306a36Sopenharmony_ci u16 *p_pool_index, u32 *p_threshold) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 148562306a36Sopenharmony_ci mlxsw_core_port_driver_priv(mlxsw_core_port); 148662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 148762306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 148862306a36Sopenharmony_ci u8 pg_buff = tc_index; 148962306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; 149062306a36Sopenharmony_ci struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, 149162306a36Sopenharmony_ci pg_buff, dir); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool_index, 149462306a36Sopenharmony_ci cm->max_buff); 149562306a36Sopenharmony_ci *p_pool_index = cm->pool_index; 149662306a36Sopenharmony_ci return 0; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ciint mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, 150062306a36Sopenharmony_ci unsigned int sb_index, u16 tc_index, 150162306a36Sopenharmony_ci enum devlink_sb_pool_type pool_type, 150262306a36Sopenharmony_ci u16 pool_index, u32 threshold, 150362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 150462306a36Sopenharmony_ci{ 150562306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 150662306a36Sopenharmony_ci mlxsw_core_port_driver_priv(mlxsw_core_port); 150762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 150862306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 150962306a36Sopenharmony_ci const struct mlxsw_sp_sb_cm *cm; 151062306a36Sopenharmony_ci u8 pg_buff = tc_index; 151162306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; 151262306a36Sopenharmony_ci u32 max_buff; 151362306a36Sopenharmony_ci int err; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci if (local_port == MLXSW_PORT_CPU_PORT) { 151662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's binding is forbidden"); 151762306a36Sopenharmony_ci return -EINVAL; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir) { 152162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Binding egress TC to ingress pool and vice versa is forbidden"); 152262306a36Sopenharmony_ci return -EINVAL; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (dir == MLXSW_REG_SBXX_DIR_INGRESS) 152662306a36Sopenharmony_ci cm = &mlxsw_sp->sb_vals->cms_ingress[tc_index]; 152762306a36Sopenharmony_ci else 152862306a36Sopenharmony_ci cm = &mlxsw_sp->sb_vals->cms_egress[tc_index]; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (cm->freeze_pool && cm->pool_index != pool_index) { 153162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Binding this TC to a different pool is forbidden"); 153262306a36Sopenharmony_ci return -EINVAL; 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (cm->freeze_thresh && cm->max_buff != threshold) { 153662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Changing this TC's threshold is forbidden"); 153762306a36Sopenharmony_ci return -EINVAL; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index, 154162306a36Sopenharmony_ci threshold, &max_buff, extack); 154262306a36Sopenharmony_ci if (err) 154362306a36Sopenharmony_ci return err; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, 154662306a36Sopenharmony_ci 0, max_buff, false, pool_index); 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci#define MASKED_COUNT_MAX \ 155062306a36Sopenharmony_ci (MLXSW_REG_SBSR_REC_MAX_COUNT / \ 155162306a36Sopenharmony_ci (MLXSW_SP_SB_ING_TC_COUNT + MLXSW_SP_SB_EG_TC_COUNT)) 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistruct mlxsw_sp_sb_sr_occ_query_cb_ctx { 155462306a36Sopenharmony_ci u8 masked_count; 155562306a36Sopenharmony_ci u16 local_port_1; 155662306a36Sopenharmony_ci}; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_cistatic void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core, 155962306a36Sopenharmony_ci char *sbsr_pl, size_t sbsr_pl_len, 156062306a36Sopenharmony_ci unsigned long cb_priv) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 156362306a36Sopenharmony_ci struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx; 156462306a36Sopenharmony_ci u8 masked_count; 156562306a36Sopenharmony_ci u16 local_port; 156662306a36Sopenharmony_ci int rec_index = 0; 156762306a36Sopenharmony_ci struct mlxsw_sp_sb_cm *cm; 156862306a36Sopenharmony_ci int i; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci memcpy(&cb_ctx, &cb_priv, sizeof(cb_ctx)); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci masked_count = 0; 157362306a36Sopenharmony_ci for (local_port = cb_ctx.local_port_1; 157462306a36Sopenharmony_ci local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 157562306a36Sopenharmony_ci if (!mlxsw_sp->ports[local_port]) 157662306a36Sopenharmony_ci continue; 157762306a36Sopenharmony_ci if (local_port == MLXSW_PORT_CPU_PORT) { 157862306a36Sopenharmony_ci /* Ingress quotas are not supported for the CPU port */ 157962306a36Sopenharmony_ci masked_count++; 158062306a36Sopenharmony_ci continue; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) { 158362306a36Sopenharmony_ci cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, 158462306a36Sopenharmony_ci MLXSW_REG_SBXX_DIR_INGRESS); 158562306a36Sopenharmony_ci mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, 158662306a36Sopenharmony_ci &cm->occ.cur, &cm->occ.max); 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci if (++masked_count == cb_ctx.masked_count) 158962306a36Sopenharmony_ci break; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci masked_count = 0; 159262306a36Sopenharmony_ci for (local_port = cb_ctx.local_port_1; 159362306a36Sopenharmony_ci local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 159462306a36Sopenharmony_ci if (!mlxsw_sp->ports[local_port]) 159562306a36Sopenharmony_ci continue; 159662306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) { 159762306a36Sopenharmony_ci cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, 159862306a36Sopenharmony_ci MLXSW_REG_SBXX_DIR_EGRESS); 159962306a36Sopenharmony_ci mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, 160062306a36Sopenharmony_ci &cm->occ.cur, &cm->occ.max); 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci if (++masked_count == cb_ctx.masked_count) 160362306a36Sopenharmony_ci break; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci} 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ciint mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core, 160862306a36Sopenharmony_ci unsigned int sb_index) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 161162306a36Sopenharmony_ci u16 local_port, local_port_1, last_local_port; 161262306a36Sopenharmony_ci struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx; 161362306a36Sopenharmony_ci u8 masked_count, current_page = 0; 161462306a36Sopenharmony_ci unsigned long cb_priv = 0; 161562306a36Sopenharmony_ci LIST_HEAD(bulk_list); 161662306a36Sopenharmony_ci char *sbsr_pl; 161762306a36Sopenharmony_ci int i; 161862306a36Sopenharmony_ci int err; 161962306a36Sopenharmony_ci int err2; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL); 162262306a36Sopenharmony_ci if (!sbsr_pl) 162362306a36Sopenharmony_ci return -ENOMEM; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci local_port = MLXSW_PORT_CPU_PORT; 162662306a36Sopenharmony_cinext_batch: 162762306a36Sopenharmony_ci local_port_1 = local_port; 162862306a36Sopenharmony_ci masked_count = 0; 162962306a36Sopenharmony_ci mlxsw_reg_sbsr_pack(sbsr_pl, false); 163062306a36Sopenharmony_ci mlxsw_reg_sbsr_port_page_set(sbsr_pl, current_page); 163162306a36Sopenharmony_ci last_local_port = current_page * MLXSW_REG_SBSR_NUM_PORTS_IN_PAGE + 163262306a36Sopenharmony_ci MLXSW_REG_SBSR_NUM_PORTS_IN_PAGE - 1; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) 163562306a36Sopenharmony_ci mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); 163662306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) 163762306a36Sopenharmony_ci mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); 163862306a36Sopenharmony_ci for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 163962306a36Sopenharmony_ci if (!mlxsw_sp->ports[local_port]) 164062306a36Sopenharmony_ci continue; 164162306a36Sopenharmony_ci if (local_port > last_local_port) { 164262306a36Sopenharmony_ci current_page++; 164362306a36Sopenharmony_ci goto do_query; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci if (local_port != MLXSW_PORT_CPU_PORT) { 164662306a36Sopenharmony_ci /* Ingress quotas are not supported for the CPU port */ 164762306a36Sopenharmony_ci mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, 164862306a36Sopenharmony_ci local_port, 1); 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); 165162306a36Sopenharmony_ci for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) { 165262306a36Sopenharmony_ci err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i, 165362306a36Sopenharmony_ci &bulk_list); 165462306a36Sopenharmony_ci if (err) 165562306a36Sopenharmony_ci goto out; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci if (++masked_count == MASKED_COUNT_MAX) 165862306a36Sopenharmony_ci goto do_query; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cido_query: 166262306a36Sopenharmony_ci cb_ctx.masked_count = masked_count; 166362306a36Sopenharmony_ci cb_ctx.local_port_1 = local_port_1; 166462306a36Sopenharmony_ci memcpy(&cb_priv, &cb_ctx, sizeof(cb_ctx)); 166562306a36Sopenharmony_ci err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl, 166662306a36Sopenharmony_ci &bulk_list, mlxsw_sp_sb_sr_occ_query_cb, 166762306a36Sopenharmony_ci cb_priv); 166862306a36Sopenharmony_ci if (err) 166962306a36Sopenharmony_ci goto out; 167062306a36Sopenharmony_ci if (local_port < mlxsw_core_max_ports(mlxsw_core)) { 167162306a36Sopenharmony_ci local_port++; 167262306a36Sopenharmony_ci goto next_batch; 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ciout: 167662306a36Sopenharmony_ci err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); 167762306a36Sopenharmony_ci if (!err) 167862306a36Sopenharmony_ci err = err2; 167962306a36Sopenharmony_ci kfree(sbsr_pl); 168062306a36Sopenharmony_ci return err; 168162306a36Sopenharmony_ci} 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ciint mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core, 168462306a36Sopenharmony_ci unsigned int sb_index) 168562306a36Sopenharmony_ci{ 168662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 168762306a36Sopenharmony_ci u16 local_port, last_local_port; 168862306a36Sopenharmony_ci LIST_HEAD(bulk_list); 168962306a36Sopenharmony_ci unsigned int masked_count; 169062306a36Sopenharmony_ci u8 current_page = 0; 169162306a36Sopenharmony_ci char *sbsr_pl; 169262306a36Sopenharmony_ci int i; 169362306a36Sopenharmony_ci int err; 169462306a36Sopenharmony_ci int err2; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL); 169762306a36Sopenharmony_ci if (!sbsr_pl) 169862306a36Sopenharmony_ci return -ENOMEM; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci local_port = MLXSW_PORT_CPU_PORT; 170162306a36Sopenharmony_cinext_batch: 170262306a36Sopenharmony_ci masked_count = 0; 170362306a36Sopenharmony_ci mlxsw_reg_sbsr_pack(sbsr_pl, true); 170462306a36Sopenharmony_ci mlxsw_reg_sbsr_port_page_set(sbsr_pl, current_page); 170562306a36Sopenharmony_ci last_local_port = current_page * MLXSW_REG_SBSR_NUM_PORTS_IN_PAGE + 170662306a36Sopenharmony_ci MLXSW_REG_SBSR_NUM_PORTS_IN_PAGE - 1; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) 170962306a36Sopenharmony_ci mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); 171062306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) 171162306a36Sopenharmony_ci mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); 171262306a36Sopenharmony_ci for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 171362306a36Sopenharmony_ci if (!mlxsw_sp->ports[local_port]) 171462306a36Sopenharmony_ci continue; 171562306a36Sopenharmony_ci if (local_port > last_local_port) { 171662306a36Sopenharmony_ci current_page++; 171762306a36Sopenharmony_ci goto do_query; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci if (local_port != MLXSW_PORT_CPU_PORT) { 172062306a36Sopenharmony_ci /* Ingress quotas are not supported for the CPU port */ 172162306a36Sopenharmony_ci mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, 172262306a36Sopenharmony_ci local_port, 1); 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); 172562306a36Sopenharmony_ci for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) { 172662306a36Sopenharmony_ci err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i, 172762306a36Sopenharmony_ci &bulk_list); 172862306a36Sopenharmony_ci if (err) 172962306a36Sopenharmony_ci goto out; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci if (++masked_count == MASKED_COUNT_MAX) 173262306a36Sopenharmony_ci goto do_query; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_cido_query: 173662306a36Sopenharmony_ci err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl, 173762306a36Sopenharmony_ci &bulk_list, NULL, 0); 173862306a36Sopenharmony_ci if (err) 173962306a36Sopenharmony_ci goto out; 174062306a36Sopenharmony_ci if (local_port < mlxsw_core_max_ports(mlxsw_core)) { 174162306a36Sopenharmony_ci local_port++; 174262306a36Sopenharmony_ci goto next_batch; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ciout: 174662306a36Sopenharmony_ci err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); 174762306a36Sopenharmony_ci if (!err) 174862306a36Sopenharmony_ci err = err2; 174962306a36Sopenharmony_ci kfree(sbsr_pl); 175062306a36Sopenharmony_ci return err; 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ciint mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, 175462306a36Sopenharmony_ci unsigned int sb_index, u16 pool_index, 175562306a36Sopenharmony_ci u32 *p_cur, u32 *p_max) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 175862306a36Sopenharmony_ci mlxsw_core_port_driver_priv(mlxsw_core_port); 175962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 176062306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 176162306a36Sopenharmony_ci struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, 176262306a36Sopenharmony_ci pool_index); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.cur); 176562306a36Sopenharmony_ci *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.max); 176662306a36Sopenharmony_ci return 0; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ciint mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, 177062306a36Sopenharmony_ci unsigned int sb_index, u16 tc_index, 177162306a36Sopenharmony_ci enum devlink_sb_pool_type pool_type, 177262306a36Sopenharmony_ci u32 *p_cur, u32 *p_max) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 177562306a36Sopenharmony_ci mlxsw_core_port_driver_priv(mlxsw_core_port); 177662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 177762306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 177862306a36Sopenharmony_ci u8 pg_buff = tc_index; 177962306a36Sopenharmony_ci enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; 178062306a36Sopenharmony_ci struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, 178162306a36Sopenharmony_ci pg_buff, dir); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.cur); 178462306a36Sopenharmony_ci *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.max); 178562306a36Sopenharmony_ci return 0; 178662306a36Sopenharmony_ci} 1787