1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/types.h>
6*4882a593Smuzhiyun #include <linux/dcbnl.h>
7*4882a593Smuzhiyun #include <linux/if_ether.h>
8*4882a593Smuzhiyun #include <linux/list.h>
9*4882a593Smuzhiyun #include <linux/netlink.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include "spectrum.h"
12*4882a593Smuzhiyun #include "core.h"
13*4882a593Smuzhiyun #include "port.h"
14*4882a593Smuzhiyun #include "reg.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun struct mlxsw_sp_sb_pr {
17*4882a593Smuzhiyun enum mlxsw_reg_sbpr_mode mode;
18*4882a593Smuzhiyun u32 size;
19*4882a593Smuzhiyun u8 freeze_mode:1,
20*4882a593Smuzhiyun freeze_size:1;
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct mlxsw_cp_sb_occ {
24*4882a593Smuzhiyun u32 cur;
25*4882a593Smuzhiyun u32 max;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct mlxsw_sp_sb_cm {
29*4882a593Smuzhiyun u32 min_buff;
30*4882a593Smuzhiyun u32 max_buff;
31*4882a593Smuzhiyun u16 pool_index;
32*4882a593Smuzhiyun struct mlxsw_cp_sb_occ occ;
33*4882a593Smuzhiyun u8 freeze_pool:1,
34*4882a593Smuzhiyun freeze_thresh:1;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define MLXSW_SP_SB_INFI -1U
38*4882a593Smuzhiyun #define MLXSW_SP_SB_REST -2U
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun struct mlxsw_sp_sb_pm {
41*4882a593Smuzhiyun u32 min_buff;
42*4882a593Smuzhiyun u32 max_buff;
43*4882a593Smuzhiyun struct mlxsw_cp_sb_occ occ;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct mlxsw_sp_sb_mm {
47*4882a593Smuzhiyun u32 min_buff;
48*4882a593Smuzhiyun u32 max_buff;
49*4882a593Smuzhiyun u16 pool_index;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun struct mlxsw_sp_sb_pool_des {
53*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir;
54*4882a593Smuzhiyun u8 pool;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define MLXSW_SP_SB_POOL_ING 0
58*4882a593Smuzhiyun #define MLXSW_SP_SB_POOL_EGR 4
59*4882a593Smuzhiyun #define MLXSW_SP_SB_POOL_EGR_MC 8
60*4882a593Smuzhiyun #define MLXSW_SP_SB_POOL_ING_CPU 9
61*4882a593Smuzhiyun #define MLXSW_SP_SB_POOL_EGR_CPU 10
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pool_des mlxsw_sp1_sb_pool_dess[] = {
64*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 0},
65*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 1},
66*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 2},
67*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 3},
68*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 0},
69*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 1},
70*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 2},
71*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 3},
72*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 15},
73*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 4},
74*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 4},
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pool_des mlxsw_sp2_sb_pool_dess[] = {
78*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 0},
79*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 1},
80*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 2},
81*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 3},
82*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 0},
83*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 1},
84*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 2},
85*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 3},
86*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 15},
87*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_INGRESS, 4},
88*4882a593Smuzhiyun {MLXSW_REG_SBXX_DIR_EGRESS, 4},
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #define MLXSW_SP_SB_ING_TC_COUNT 8
92*4882a593Smuzhiyun #define MLXSW_SP_SB_EG_TC_COUNT 16
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun struct mlxsw_sp_sb_port {
95*4882a593Smuzhiyun struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT];
96*4882a593Smuzhiyun struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT];
97*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pms;
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun struct mlxsw_sp_sb {
101*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *prs;
102*4882a593Smuzhiyun struct mlxsw_sp_sb_port *ports;
103*4882a593Smuzhiyun u32 cell_size;
104*4882a593Smuzhiyun u32 max_headroom_cells;
105*4882a593Smuzhiyun u64 sb_size;
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun struct mlxsw_sp_sb_vals {
109*4882a593Smuzhiyun unsigned int pool_count;
110*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *pool_dess;
111*4882a593Smuzhiyun const struct mlxsw_sp_sb_pm *pms;
112*4882a593Smuzhiyun const struct mlxsw_sp_sb_pm *pms_cpu;
113*4882a593Smuzhiyun const struct mlxsw_sp_sb_pr *prs;
114*4882a593Smuzhiyun const struct mlxsw_sp_sb_mm *mms;
115*4882a593Smuzhiyun const struct mlxsw_sp_sb_cm *cms_ingress;
116*4882a593Smuzhiyun const struct mlxsw_sp_sb_cm *cms_egress;
117*4882a593Smuzhiyun const struct mlxsw_sp_sb_cm *cms_cpu;
118*4882a593Smuzhiyun unsigned int mms_count;
119*4882a593Smuzhiyun unsigned int cms_ingress_count;
120*4882a593Smuzhiyun unsigned int cms_egress_count;
121*4882a593Smuzhiyun unsigned int cms_cpu_count;
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun struct mlxsw_sp_sb_ops {
125*4882a593Smuzhiyun u32 (*int_buf_size_get)(int mtu, u32 speed);
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
mlxsw_sp_cells_bytes(const struct mlxsw_sp * mlxsw_sp,u32 cells)128*4882a593Smuzhiyun u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun return mlxsw_sp->sb->cell_size * cells;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
mlxsw_sp_bytes_cells(const struct mlxsw_sp * mlxsw_sp,u32 bytes)133*4882a593Smuzhiyun u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
mlxsw_sp_port_headroom_8x_adjust(const struct mlxsw_sp_port * mlxsw_sp_port,u32 size_cells)138*4882a593Smuzhiyun static u32 mlxsw_sp_port_headroom_8x_adjust(const struct mlxsw_sp_port *mlxsw_sp_port,
139*4882a593Smuzhiyun u32 size_cells)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun /* Ports with eight lanes use two headroom buffers between which the
142*4882a593Smuzhiyun * configured headroom size is split. Therefore, multiply the calculated
143*4882a593Smuzhiyun * headroom size by two.
144*4882a593Smuzhiyun */
145*4882a593Smuzhiyun return mlxsw_sp_port->mapping.width == 8 ? 2 * size_cells : size_cells;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
mlxsw_sp_sb_pr_get(struct mlxsw_sp * mlxsw_sp,u16 pool_index)148*4882a593Smuzhiyun static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp,
149*4882a593Smuzhiyun u16 pool_index)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun return &mlxsw_sp->sb->prs[pool_index];
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
mlxsw_sp_sb_cm_exists(u8 pg_buff,enum mlxsw_reg_sbxx_dir dir)154*4882a593Smuzhiyun static bool mlxsw_sp_sb_cm_exists(u8 pg_buff, enum mlxsw_reg_sbxx_dir dir)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun if (dir == MLXSW_REG_SBXX_DIR_INGRESS)
157*4882a593Smuzhiyun return pg_buff < MLXSW_SP_SB_ING_TC_COUNT;
158*4882a593Smuzhiyun else
159*4882a593Smuzhiyun return pg_buff < MLXSW_SP_SB_EG_TC_COUNT;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
mlxsw_sp_sb_cm_get(struct mlxsw_sp * mlxsw_sp,u8 local_port,u8 pg_buff,enum mlxsw_reg_sbxx_dir dir)162*4882a593Smuzhiyun static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp,
163*4882a593Smuzhiyun u8 local_port, u8 pg_buff,
164*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun struct mlxsw_sp_sb_port *sb_port = &mlxsw_sp->sb->ports[local_port];
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun WARN_ON(!mlxsw_sp_sb_cm_exists(pg_buff, dir));
169*4882a593Smuzhiyun if (dir == MLXSW_REG_SBXX_DIR_INGRESS)
170*4882a593Smuzhiyun return &sb_port->ing_cms[pg_buff];
171*4882a593Smuzhiyun else
172*4882a593Smuzhiyun return &sb_port->eg_cms[pg_buff];
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
mlxsw_sp_sb_pm_get(struct mlxsw_sp * mlxsw_sp,u8 local_port,u16 pool_index)175*4882a593Smuzhiyun static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp,
176*4882a593Smuzhiyun u8 local_port, u16 pool_index)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun return &mlxsw_sp->sb->ports[local_port].pms[pool_index];
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
mlxsw_sp_sb_pr_write(struct mlxsw_sp * mlxsw_sp,u16 pool_index,enum mlxsw_reg_sbpr_mode mode,u32 size,bool infi_size)181*4882a593Smuzhiyun static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
182*4882a593Smuzhiyun enum mlxsw_reg_sbpr_mode mode,
183*4882a593Smuzhiyun u32 size, bool infi_size)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des =
186*4882a593Smuzhiyun &mlxsw_sp->sb_vals->pool_dess[pool_index];
187*4882a593Smuzhiyun char sbpr_pl[MLXSW_REG_SBPR_LEN];
188*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *pr;
189*4882a593Smuzhiyun int err;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode,
192*4882a593Smuzhiyun size, infi_size);
193*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl);
194*4882a593Smuzhiyun if (err)
195*4882a593Smuzhiyun return err;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if (infi_size)
198*4882a593Smuzhiyun size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp->sb->sb_size);
199*4882a593Smuzhiyun pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
200*4882a593Smuzhiyun pr->mode = mode;
201*4882a593Smuzhiyun pr->size = size;
202*4882a593Smuzhiyun return 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
mlxsw_sp_sb_cm_write(struct mlxsw_sp * mlxsw_sp,u8 local_port,u8 pg_buff,u32 min_buff,u32 max_buff,bool infi_max,u16 pool_index)205*4882a593Smuzhiyun static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
206*4882a593Smuzhiyun u8 pg_buff, u32 min_buff, u32 max_buff,
207*4882a593Smuzhiyun bool infi_max, u16 pool_index)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des =
210*4882a593Smuzhiyun &mlxsw_sp->sb_vals->pool_dess[pool_index];
211*4882a593Smuzhiyun char sbcm_pl[MLXSW_REG_SBCM_LEN];
212*4882a593Smuzhiyun struct mlxsw_sp_sb_cm *cm;
213*4882a593Smuzhiyun int err;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, des->dir,
216*4882a593Smuzhiyun min_buff, max_buff, infi_max, des->pool);
217*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl);
218*4882a593Smuzhiyun if (err)
219*4882a593Smuzhiyun return err;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (mlxsw_sp_sb_cm_exists(pg_buff, des->dir)) {
222*4882a593Smuzhiyun if (infi_max)
223*4882a593Smuzhiyun max_buff = mlxsw_sp_bytes_cells(mlxsw_sp,
224*4882a593Smuzhiyun mlxsw_sp->sb->sb_size);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff,
227*4882a593Smuzhiyun des->dir);
228*4882a593Smuzhiyun cm->min_buff = min_buff;
229*4882a593Smuzhiyun cm->max_buff = max_buff;
230*4882a593Smuzhiyun cm->pool_index = pool_index;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
mlxsw_sp_sb_pm_write(struct mlxsw_sp * mlxsw_sp,u8 local_port,u16 pool_index,u32 min_buff,u32 max_buff)235*4882a593Smuzhiyun static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
236*4882a593Smuzhiyun u16 pool_index, u32 min_buff, u32 max_buff)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des =
239*4882a593Smuzhiyun &mlxsw_sp->sb_vals->pool_dess[pool_index];
240*4882a593Smuzhiyun char sbpm_pl[MLXSW_REG_SBPM_LEN];
241*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pm;
242*4882a593Smuzhiyun int err;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, false,
245*4882a593Smuzhiyun min_buff, max_buff);
246*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl);
247*4882a593Smuzhiyun if (err)
248*4882a593Smuzhiyun return err;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index);
251*4882a593Smuzhiyun pm->min_buff = min_buff;
252*4882a593Smuzhiyun pm->max_buff = max_buff;
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp * mlxsw_sp,u8 local_port,u16 pool_index,struct list_head * bulk_list)256*4882a593Smuzhiyun static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
257*4882a593Smuzhiyun u16 pool_index, struct list_head *bulk_list)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des =
260*4882a593Smuzhiyun &mlxsw_sp->sb_vals->pool_dess[pool_index];
261*4882a593Smuzhiyun char sbpm_pl[MLXSW_REG_SBPM_LEN];
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (local_port == MLXSW_PORT_CPU_PORT &&
264*4882a593Smuzhiyun des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
265*4882a593Smuzhiyun return 0;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
268*4882a593Smuzhiyun true, 0, 0);
269*4882a593Smuzhiyun return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
270*4882a593Smuzhiyun bulk_list, NULL, 0);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core * mlxsw_core,char * sbpm_pl,size_t sbpm_pl_len,unsigned long cb_priv)273*4882a593Smuzhiyun static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core,
274*4882a593Smuzhiyun char *sbpm_pl, size_t sbpm_pl_len,
275*4882a593Smuzhiyun unsigned long cb_priv)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pm = (struct mlxsw_sp_sb_pm *) cb_priv;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun mlxsw_reg_sbpm_unpack(sbpm_pl, &pm->occ.cur, &pm->occ.max);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp * mlxsw_sp,u8 local_port,u16 pool_index,struct list_head * bulk_list)282*4882a593Smuzhiyun static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
283*4882a593Smuzhiyun u16 pool_index, struct list_head *bulk_list)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des =
286*4882a593Smuzhiyun &mlxsw_sp->sb_vals->pool_dess[pool_index];
287*4882a593Smuzhiyun char sbpm_pl[MLXSW_REG_SBPM_LEN];
288*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pm;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (local_port == MLXSW_PORT_CPU_PORT &&
291*4882a593Smuzhiyun des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
292*4882a593Smuzhiyun return 0;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index);
295*4882a593Smuzhiyun mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
296*4882a593Smuzhiyun false, 0, 0);
297*4882a593Smuzhiyun return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
298*4882a593Smuzhiyun bulk_list,
299*4882a593Smuzhiyun mlxsw_sp_sb_pm_occ_query_cb,
300*4882a593Smuzhiyun (unsigned long) pm);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
mlxsw_sp_hdroom_prios_reset_buf_idx(struct mlxsw_sp_hdroom * hdroom)303*4882a593Smuzhiyun void mlxsw_sp_hdroom_prios_reset_buf_idx(struct mlxsw_sp_hdroom *hdroom)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun int prio;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
308*4882a593Smuzhiyun switch (hdroom->mode) {
309*4882a593Smuzhiyun case MLXSW_SP_HDROOM_MODE_DCB:
310*4882a593Smuzhiyun hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].ets_buf_idx;
311*4882a593Smuzhiyun break;
312*4882a593Smuzhiyun case MLXSW_SP_HDROOM_MODE_TC:
313*4882a593Smuzhiyun hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].set_buf_idx;
314*4882a593Smuzhiyun break;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
mlxsw_sp_hdroom_bufs_reset_lossiness(struct mlxsw_sp_hdroom * hdroom)319*4882a593Smuzhiyun void mlxsw_sp_hdroom_bufs_reset_lossiness(struct mlxsw_sp_hdroom *hdroom)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun int prio;
322*4882a593Smuzhiyun int i;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun for (i = 0; i < DCBX_MAX_BUFFERS; i++)
325*4882a593Smuzhiyun hdroom->bufs.buf[i].lossy = true;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++) {
328*4882a593Smuzhiyun if (!hdroom->prios.prio[prio].lossy)
329*4882a593Smuzhiyun hdroom->bufs.buf[hdroom->prios.prio[prio].buf_idx].lossy = false;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
mlxsw_sp_hdroom_buf_threshold_get(const struct mlxsw_sp * mlxsw_sp,int mtu)333*4882a593Smuzhiyun static u16 mlxsw_sp_hdroom_buf_threshold_get(const struct mlxsw_sp *mlxsw_sp, int mtu)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun return 2 * mlxsw_sp_bytes_cells(mlxsw_sp, mtu);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
mlxsw_sp_hdroom_buf_pack(char * pbmc_pl,int index,u16 size,u16 thres,bool lossy)338*4882a593Smuzhiyun static void mlxsw_sp_hdroom_buf_pack(char *pbmc_pl, int index, u16 size, u16 thres, bool lossy)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun if (lossy)
341*4882a593Smuzhiyun mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, index, size);
342*4882a593Smuzhiyun else
343*4882a593Smuzhiyun mlxsw_reg_pbmc_lossless_buffer_pack(pbmc_pl, index, size,
344*4882a593Smuzhiyun thres);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
mlxsw_sp_hdroom_buf_delay_get(const struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_hdroom * hdroom)347*4882a593Smuzhiyun static u16 mlxsw_sp_hdroom_buf_delay_get(const struct mlxsw_sp *mlxsw_sp,
348*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun u16 delay_cells;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun delay_cells = mlxsw_sp_bytes_cells(mlxsw_sp, hdroom->delay_bytes);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /* In the worst case scenario the delay will be made up of packets that
355*4882a593Smuzhiyun * are all of size CELL_SIZE + 1, which means each packet will require
356*4882a593Smuzhiyun * almost twice its true size when buffered in the switch. We therefore
357*4882a593Smuzhiyun * multiply this value by the "cell factor", which is close to 2.
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun * Another MTU is added in case the transmitting host already started
360*4882a593Smuzhiyun * transmitting a maximum length frame when the PFC packet was received.
361*4882a593Smuzhiyun */
362*4882a593Smuzhiyun return 2 * delay_cells + mlxsw_sp_bytes_cells(mlxsw_sp, hdroom->mtu);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
mlxsw_sp_hdroom_int_buf_size_get(struct mlxsw_sp * mlxsw_sp,int mtu,u32 speed)365*4882a593Smuzhiyun static u32 mlxsw_sp_hdroom_int_buf_size_get(struct mlxsw_sp *mlxsw_sp, int mtu, u32 speed)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun u32 buffsize = mlxsw_sp->sb_ops->int_buf_size_get(speed, mtu);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun return mlxsw_sp_bytes_cells(mlxsw_sp, buffsize) + 1;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
mlxsw_sp_hdroom_buf_is_used(const struct mlxsw_sp_hdroom * hdroom,int buf)372*4882a593Smuzhiyun static bool mlxsw_sp_hdroom_buf_is_used(const struct mlxsw_sp_hdroom *hdroom, int buf)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun int prio;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
377*4882a593Smuzhiyun if (hdroom->prios.prio[prio].buf_idx == buf)
378*4882a593Smuzhiyun return true;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun return false;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_hdroom * hdroom)383*4882a593Smuzhiyun void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port,
384*4882a593Smuzhiyun struct mlxsw_sp_hdroom *hdroom)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
387*4882a593Smuzhiyun u16 reserve_cells;
388*4882a593Smuzhiyun int i;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* Internal buffer. */
391*4882a593Smuzhiyun reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_speed,
392*4882a593Smuzhiyun mlxsw_sp_port->max_mtu);
393*4882a593Smuzhiyun reserve_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, reserve_cells);
394*4882a593Smuzhiyun hdroom->int_buf.reserve_cells = reserve_cells;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun if (hdroom->int_buf.enable)
397*4882a593Smuzhiyun hdroom->int_buf.size_cells = reserve_cells;
398*4882a593Smuzhiyun else
399*4882a593Smuzhiyun hdroom->int_buf.size_cells = 0;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun /* PG buffers. */
402*4882a593Smuzhiyun for (i = 0; i < DCBX_MAX_BUFFERS; i++) {
403*4882a593Smuzhiyun struct mlxsw_sp_hdroom_buf *buf = &hdroom->bufs.buf[i];
404*4882a593Smuzhiyun u16 thres_cells;
405*4882a593Smuzhiyun u16 delay_cells;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun if (!mlxsw_sp_hdroom_buf_is_used(hdroom, i)) {
408*4882a593Smuzhiyun thres_cells = 0;
409*4882a593Smuzhiyun delay_cells = 0;
410*4882a593Smuzhiyun } else if (buf->lossy) {
411*4882a593Smuzhiyun thres_cells = mlxsw_sp_hdroom_buf_threshold_get(mlxsw_sp, hdroom->mtu);
412*4882a593Smuzhiyun delay_cells = 0;
413*4882a593Smuzhiyun } else {
414*4882a593Smuzhiyun thres_cells = mlxsw_sp_hdroom_buf_threshold_get(mlxsw_sp, hdroom->mtu);
415*4882a593Smuzhiyun delay_cells = mlxsw_sp_hdroom_buf_delay_get(mlxsw_sp, hdroom);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun thres_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, thres_cells);
419*4882a593Smuzhiyun delay_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, delay_cells);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun buf->thres_cells = thres_cells;
422*4882a593Smuzhiyun if (hdroom->mode == MLXSW_SP_HDROOM_MODE_DCB) {
423*4882a593Smuzhiyun buf->size_cells = thres_cells + delay_cells;
424*4882a593Smuzhiyun } else {
425*4882a593Smuzhiyun /* Do not allow going below the minimum size, even if
426*4882a593Smuzhiyun * the user requested it.
427*4882a593Smuzhiyun */
428*4882a593Smuzhiyun buf->size_cells = max(buf->set_size_cells, buf->thres_cells);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun #define MLXSW_SP_PB_UNUSED 8
434*4882a593Smuzhiyun
mlxsw_sp_hdroom_configure_buffers(struct mlxsw_sp_port * mlxsw_sp_port,const struct mlxsw_sp_hdroom * hdroom,bool force)435*4882a593Smuzhiyun static int mlxsw_sp_hdroom_configure_buffers(struct mlxsw_sp_port *mlxsw_sp_port,
436*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom, bool force)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
439*4882a593Smuzhiyun char pbmc_pl[MLXSW_REG_PBMC_LEN];
440*4882a593Smuzhiyun bool dirty;
441*4882a593Smuzhiyun int err;
442*4882a593Smuzhiyun int i;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun dirty = memcmp(&mlxsw_sp_port->hdroom->bufs, &hdroom->bufs, sizeof(hdroom->bufs));
445*4882a593Smuzhiyun if (!dirty && !force)
446*4882a593Smuzhiyun return 0;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, 0xffff, 0xffff / 2);
449*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
450*4882a593Smuzhiyun const struct mlxsw_sp_hdroom_buf *buf = &hdroom->bufs.buf[i];
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (i == MLXSW_SP_PB_UNUSED)
453*4882a593Smuzhiyun continue;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun mlxsw_sp_hdroom_buf_pack(pbmc_pl, i, buf->size_cells, buf->thres_cells, buf->lossy);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0);
459*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl);
460*4882a593Smuzhiyun if (err)
461*4882a593Smuzhiyun return err;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun mlxsw_sp_port->hdroom->bufs = hdroom->bufs;
464*4882a593Smuzhiyun return 0;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
mlxsw_sp_hdroom_configure_priomap(struct mlxsw_sp_port * mlxsw_sp_port,const struct mlxsw_sp_hdroom * hdroom,bool force)467*4882a593Smuzhiyun static int mlxsw_sp_hdroom_configure_priomap(struct mlxsw_sp_port *mlxsw_sp_port,
468*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom, bool force)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun char pptb_pl[MLXSW_REG_PPTB_LEN];
471*4882a593Smuzhiyun bool dirty;
472*4882a593Smuzhiyun int prio;
473*4882a593Smuzhiyun int err;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun dirty = memcmp(&mlxsw_sp_port->hdroom->prios, &hdroom->prios, sizeof(hdroom->prios));
476*4882a593Smuzhiyun if (!dirty && !force)
477*4882a593Smuzhiyun return 0;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port);
480*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
481*4882a593Smuzhiyun mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, prio, hdroom->prios.prio[prio].buf_idx);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl);
484*4882a593Smuzhiyun if (err)
485*4882a593Smuzhiyun return err;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun mlxsw_sp_port->hdroom->prios = hdroom->prios;
488*4882a593Smuzhiyun return 0;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
mlxsw_sp_hdroom_configure_int_buf(struct mlxsw_sp_port * mlxsw_sp_port,const struct mlxsw_sp_hdroom * hdroom,bool force)491*4882a593Smuzhiyun static int mlxsw_sp_hdroom_configure_int_buf(struct mlxsw_sp_port *mlxsw_sp_port,
492*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom, bool force)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun char sbib_pl[MLXSW_REG_SBIB_LEN];
495*4882a593Smuzhiyun bool dirty;
496*4882a593Smuzhiyun int err;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun dirty = memcmp(&mlxsw_sp_port->hdroom->int_buf, &hdroom->int_buf, sizeof(hdroom->int_buf));
499*4882a593Smuzhiyun if (!dirty && !force)
500*4882a593Smuzhiyun return 0;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun mlxsw_reg_sbib_pack(sbib_pl, mlxsw_sp_port->local_port, hdroom->int_buf.size_cells);
503*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
504*4882a593Smuzhiyun if (err)
505*4882a593Smuzhiyun return err;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun mlxsw_sp_port->hdroom->int_buf = hdroom->int_buf;
508*4882a593Smuzhiyun return 0;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_hdroom * hdroom)511*4882a593Smuzhiyun static bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp,
512*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun u32 taken_headroom_cells = 0;
515*4882a593Smuzhiyun int i;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_PB_COUNT; i++)
518*4882a593Smuzhiyun taken_headroom_cells += hdroom->bufs.buf[i].size_cells;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun taken_headroom_cells += hdroom->int_buf.reserve_cells;
521*4882a593Smuzhiyun return taken_headroom_cells <= mlxsw_sp->sb->max_headroom_cells;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
__mlxsw_sp_hdroom_configure(struct mlxsw_sp_port * mlxsw_sp_port,const struct mlxsw_sp_hdroom * hdroom,bool force)524*4882a593Smuzhiyun static int __mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port,
525*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom, bool force)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun struct mlxsw_sp_hdroom orig_hdroom;
528*4882a593Smuzhiyun struct mlxsw_sp_hdroom tmp_hdroom;
529*4882a593Smuzhiyun int err;
530*4882a593Smuzhiyun int i;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun /* Port buffers need to be configured in three steps. First, all buffers
533*4882a593Smuzhiyun * with non-zero size are configured. Then, prio-to-buffer map is
534*4882a593Smuzhiyun * updated, allowing traffic to flow to the now non-zero buffers.
535*4882a593Smuzhiyun * Finally, zero-sized buffers are configured, because now no traffic
536*4882a593Smuzhiyun * should be directed to them anymore. This way, in a non-congested
537*4882a593Smuzhiyun * system, no packet drops are introduced by the reconfiguration.
538*4882a593Smuzhiyun */
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun orig_hdroom = *mlxsw_sp_port->hdroom;
541*4882a593Smuzhiyun tmp_hdroom = orig_hdroom;
542*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
543*4882a593Smuzhiyun if (hdroom->bufs.buf[i].size_cells)
544*4882a593Smuzhiyun tmp_hdroom.bufs.buf[i] = hdroom->bufs.buf[i];
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun if (!mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, &tmp_hdroom) ||
548*4882a593Smuzhiyun !mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, hdroom))
549*4882a593Smuzhiyun return -ENOBUFS;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &tmp_hdroom, force);
552*4882a593Smuzhiyun if (err)
553*4882a593Smuzhiyun return err;
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun err = mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, hdroom, force);
556*4882a593Smuzhiyun if (err)
557*4882a593Smuzhiyun goto err_configure_priomap;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, hdroom, false);
560*4882a593Smuzhiyun if (err)
561*4882a593Smuzhiyun goto err_configure_buffers;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun err = mlxsw_sp_hdroom_configure_int_buf(mlxsw_sp_port, hdroom, false);
564*4882a593Smuzhiyun if (err)
565*4882a593Smuzhiyun goto err_configure_int_buf;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun *mlxsw_sp_port->hdroom = *hdroom;
568*4882a593Smuzhiyun return 0;
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun err_configure_int_buf:
571*4882a593Smuzhiyun mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &tmp_hdroom, false);
572*4882a593Smuzhiyun err_configure_buffers:
573*4882a593Smuzhiyun mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, &tmp_hdroom, false);
574*4882a593Smuzhiyun err_configure_priomap:
575*4882a593Smuzhiyun mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &orig_hdroom, false);
576*4882a593Smuzhiyun return err;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
mlxsw_sp_hdroom_configure(struct mlxsw_sp_port * mlxsw_sp_port,const struct mlxsw_sp_hdroom * hdroom)579*4882a593Smuzhiyun int mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port,
580*4882a593Smuzhiyun const struct mlxsw_sp_hdroom *hdroom)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun return __mlxsw_sp_hdroom_configure(mlxsw_sp_port, hdroom, false);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
mlxsw_sp_port_headroom_init(struct mlxsw_sp_port * mlxsw_sp_port)585*4882a593Smuzhiyun static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
588*4882a593Smuzhiyun struct mlxsw_sp_hdroom hdroom = {};
589*4882a593Smuzhiyun u32 size9;
590*4882a593Smuzhiyun int prio;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun hdroom.mtu = mlxsw_sp_port->dev->mtu;
593*4882a593Smuzhiyun hdroom.mode = MLXSW_SP_HDROOM_MODE_DCB;
594*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
595*4882a593Smuzhiyun hdroom.prios.prio[prio].lossy = true;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
598*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun /* Buffer 9 is used for control traffic. */
601*4882a593Smuzhiyun size9 = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, mlxsw_sp_port->max_mtu);
602*4882a593Smuzhiyun hdroom.bufs.buf[9].size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size9);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun return __mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom, true);
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
mlxsw_sp_sb_port_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_sb_port * sb_port)607*4882a593Smuzhiyun static int mlxsw_sp_sb_port_init(struct mlxsw_sp *mlxsw_sp,
608*4882a593Smuzhiyun struct mlxsw_sp_sb_port *sb_port)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pms;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun pms = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*pms),
613*4882a593Smuzhiyun GFP_KERNEL);
614*4882a593Smuzhiyun if (!pms)
615*4882a593Smuzhiyun return -ENOMEM;
616*4882a593Smuzhiyun sb_port->pms = pms;
617*4882a593Smuzhiyun return 0;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
mlxsw_sp_sb_port_fini(struct mlxsw_sp_sb_port * sb_port)620*4882a593Smuzhiyun static void mlxsw_sp_sb_port_fini(struct mlxsw_sp_sb_port *sb_port)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun kfree(sb_port->pms);
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
mlxsw_sp_sb_ports_init(struct mlxsw_sp * mlxsw_sp)625*4882a593Smuzhiyun static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
628*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *prs;
629*4882a593Smuzhiyun int i;
630*4882a593Smuzhiyun int err;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun mlxsw_sp->sb->ports = kcalloc(max_ports,
633*4882a593Smuzhiyun sizeof(struct mlxsw_sp_sb_port),
634*4882a593Smuzhiyun GFP_KERNEL);
635*4882a593Smuzhiyun if (!mlxsw_sp->sb->ports)
636*4882a593Smuzhiyun return -ENOMEM;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun prs = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*prs),
639*4882a593Smuzhiyun GFP_KERNEL);
640*4882a593Smuzhiyun if (!prs) {
641*4882a593Smuzhiyun err = -ENOMEM;
642*4882a593Smuzhiyun goto err_alloc_prs;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun mlxsw_sp->sb->prs = prs;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun for (i = 0; i < max_ports; i++) {
647*4882a593Smuzhiyun err = mlxsw_sp_sb_port_init(mlxsw_sp, &mlxsw_sp->sb->ports[i]);
648*4882a593Smuzhiyun if (err)
649*4882a593Smuzhiyun goto err_sb_port_init;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun return 0;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun err_sb_port_init:
655*4882a593Smuzhiyun for (i--; i >= 0; i--)
656*4882a593Smuzhiyun mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]);
657*4882a593Smuzhiyun kfree(mlxsw_sp->sb->prs);
658*4882a593Smuzhiyun err_alloc_prs:
659*4882a593Smuzhiyun kfree(mlxsw_sp->sb->ports);
660*4882a593Smuzhiyun return err;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun
mlxsw_sp_sb_ports_fini(struct mlxsw_sp * mlxsw_sp)663*4882a593Smuzhiyun static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
666*4882a593Smuzhiyun int i;
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun for (i = max_ports - 1; i >= 0; i--)
669*4882a593Smuzhiyun mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]);
670*4882a593Smuzhiyun kfree(mlxsw_sp->sb->prs);
671*4882a593Smuzhiyun kfree(mlxsw_sp->sb->ports);
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun #define MLXSW_SP_SB_PR(_mode, _size) \
675*4882a593Smuzhiyun { \
676*4882a593Smuzhiyun .mode = _mode, \
677*4882a593Smuzhiyun .size = _size, \
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun #define MLXSW_SP_SB_PR_EXT(_mode, _size, _freeze_mode, _freeze_size) \
681*4882a593Smuzhiyun { \
682*4882a593Smuzhiyun .mode = _mode, \
683*4882a593Smuzhiyun .size = _size, \
684*4882a593Smuzhiyun .freeze_mode = _freeze_mode, \
685*4882a593Smuzhiyun .freeze_size = _freeze_size, \
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun #define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000)
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun /* Order according to mlxsw_sp1_sb_pool_dess */
691*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = {
692*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST),
693*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
694*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
695*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
696*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST,
697*4882a593Smuzhiyun true, false),
698*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
699*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
700*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
701*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI,
702*4882a593Smuzhiyun true, true),
703*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC,
704*4882a593Smuzhiyun MLXSW_SP1_SB_PR_CPU_SIZE, true, false),
705*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC,
706*4882a593Smuzhiyun MLXSW_SP1_SB_PR_CPU_SIZE, true, false),
707*4882a593Smuzhiyun };
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000)
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun /* Order according to mlxsw_sp2_sb_pool_dess */
712*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = {
713*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST),
714*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
715*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
716*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
717*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST,
718*4882a593Smuzhiyun true, false),
719*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
720*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
721*4882a593Smuzhiyun MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0),
722*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI,
723*4882a593Smuzhiyun true, true),
724*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC,
725*4882a593Smuzhiyun MLXSW_SP2_SB_PR_CPU_SIZE, true, false),
726*4882a593Smuzhiyun MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC,
727*4882a593Smuzhiyun MLXSW_SP2_SB_PR_CPU_SIZE, true, false),
728*4882a593Smuzhiyun };
729*4882a593Smuzhiyun
mlxsw_sp_sb_prs_init(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_sb_pr * prs,const struct mlxsw_sp_sb_pool_des * pool_dess,size_t prs_len)730*4882a593Smuzhiyun static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
731*4882a593Smuzhiyun const struct mlxsw_sp_sb_pr *prs,
732*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *pool_dess,
733*4882a593Smuzhiyun size_t prs_len)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun /* Round down, unlike mlxsw_sp_bytes_cells(). */
736*4882a593Smuzhiyun u32 sb_cells = div_u64(mlxsw_sp->sb->sb_size, mlxsw_sp->sb->cell_size);
737*4882a593Smuzhiyun u32 rest_cells[2] = {sb_cells, sb_cells};
738*4882a593Smuzhiyun int i;
739*4882a593Smuzhiyun int err;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /* Calculate how much space to give to the "REST" pools in either
742*4882a593Smuzhiyun * direction.
743*4882a593Smuzhiyun */
744*4882a593Smuzhiyun for (i = 0; i < prs_len; i++) {
745*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir = pool_dess[i].dir;
746*4882a593Smuzhiyun u32 size = prs[i].size;
747*4882a593Smuzhiyun u32 size_cells;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun if (size == MLXSW_SP_SB_INFI || size == MLXSW_SP_SB_REST)
750*4882a593Smuzhiyun continue;
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size);
753*4882a593Smuzhiyun if (WARN_ON_ONCE(size_cells > rest_cells[dir]))
754*4882a593Smuzhiyun continue;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun rest_cells[dir] -= size_cells;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun for (i = 0; i < prs_len; i++) {
760*4882a593Smuzhiyun u32 size = prs[i].size;
761*4882a593Smuzhiyun u32 size_cells;
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun if (size == MLXSW_SP_SB_INFI) {
764*4882a593Smuzhiyun err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode,
765*4882a593Smuzhiyun 0, true);
766*4882a593Smuzhiyun } else if (size == MLXSW_SP_SB_REST) {
767*4882a593Smuzhiyun size_cells = rest_cells[pool_dess[i].dir];
768*4882a593Smuzhiyun err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode,
769*4882a593Smuzhiyun size_cells, false);
770*4882a593Smuzhiyun } else {
771*4882a593Smuzhiyun size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size);
772*4882a593Smuzhiyun err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode,
773*4882a593Smuzhiyun size_cells, false);
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun if (err)
776*4882a593Smuzhiyun return err;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun return 0;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun #define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \
782*4882a593Smuzhiyun { \
783*4882a593Smuzhiyun .min_buff = _min_buff, \
784*4882a593Smuzhiyun .max_buff = _max_buff, \
785*4882a593Smuzhiyun .pool_index = _pool, \
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun #define MLXSW_SP_SB_CM_ING(_min_buff, _max_buff) \
789*4882a593Smuzhiyun { \
790*4882a593Smuzhiyun .min_buff = _min_buff, \
791*4882a593Smuzhiyun .max_buff = _max_buff, \
792*4882a593Smuzhiyun .pool_index = MLXSW_SP_SB_POOL_ING, \
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun #define MLXSW_SP_SB_CM_EGR(_min_buff, _max_buff) \
796*4882a593Smuzhiyun { \
797*4882a593Smuzhiyun .min_buff = _min_buff, \
798*4882a593Smuzhiyun .max_buff = _max_buff, \
799*4882a593Smuzhiyun .pool_index = MLXSW_SP_SB_POOL_EGR, \
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun #define MLXSW_SP_SB_CM_EGR_MC(_min_buff, _max_buff) \
803*4882a593Smuzhiyun { \
804*4882a593Smuzhiyun .min_buff = _min_buff, \
805*4882a593Smuzhiyun .max_buff = _max_buff, \
806*4882a593Smuzhiyun .pool_index = MLXSW_SP_SB_POOL_EGR_MC, \
807*4882a593Smuzhiyun .freeze_pool = true, \
808*4882a593Smuzhiyun .freeze_thresh = true, \
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_ingress[] = {
812*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(10000, 8),
813*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
814*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
815*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
816*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
817*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
818*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
819*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
820*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, 0), /* dummy, this PG does not exist */
821*4882a593Smuzhiyun MLXSW_SP_SB_CM(10000, 8, MLXSW_SP_SB_POOL_ING_CPU),
822*4882a593Smuzhiyun };
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_ingress[] = {
825*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, 7),
826*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
827*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
828*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
829*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
830*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
831*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
832*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
833*4882a593Smuzhiyun MLXSW_SP_SB_CM_ING(0, 0), /* dummy, this PG does not exist */
834*4882a593Smuzhiyun MLXSW_SP_SB_CM(10000, 8, MLXSW_SP_SB_POOL_ING_CPU),
835*4882a593Smuzhiyun };
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_egress[] = {
838*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
839*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
840*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
841*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
842*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
843*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
844*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
845*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1500, 9),
846*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
847*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
848*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
849*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
850*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
851*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
852*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
853*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
854*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1, 0xff),
855*4882a593Smuzhiyun };
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_egress[] = {
858*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
859*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
860*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
861*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
862*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
863*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
864*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
865*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(0, 7),
866*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
867*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
868*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
869*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
870*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
871*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
872*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
873*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI),
874*4882a593Smuzhiyun MLXSW_SP_SB_CM_EGR(1, 0xff),
875*4882a593Smuzhiyun };
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun #define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, MLXSW_SP_SB_POOL_EGR_CPU)
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
880*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
881*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
882*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
883*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
884*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
885*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
886*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
887*4882a593Smuzhiyun MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU),
888*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
889*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
890*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
891*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
892*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
893*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
894*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
895*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
896*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
897*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
898*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
899*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
900*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
901*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
902*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
903*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
904*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
905*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
906*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
907*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
908*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
909*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
910*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
911*4882a593Smuzhiyun MLXSW_SP_CPU_PORT_SB_CM,
912*4882a593Smuzhiyun };
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun static bool
mlxsw_sp_sb_pool_is_static(struct mlxsw_sp * mlxsw_sp,u16 pool_index)915*4882a593Smuzhiyun mlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index)
916*4882a593Smuzhiyun {
917*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun return pr->mode == MLXSW_REG_SBPR_MODE_STATIC;
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun
__mlxsw_sp_sb_cms_init(struct mlxsw_sp * mlxsw_sp,u8 local_port,enum mlxsw_reg_sbxx_dir dir,const struct mlxsw_sp_sb_cm * cms,size_t cms_len)922*4882a593Smuzhiyun static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
923*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir,
924*4882a593Smuzhiyun const struct mlxsw_sp_sb_cm *cms,
925*4882a593Smuzhiyun size_t cms_len)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun const struct mlxsw_sp_sb_vals *sb_vals = mlxsw_sp->sb_vals;
928*4882a593Smuzhiyun int i;
929*4882a593Smuzhiyun int err;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun for (i = 0; i < cms_len; i++) {
932*4882a593Smuzhiyun const struct mlxsw_sp_sb_cm *cm;
933*4882a593Smuzhiyun u32 min_buff;
934*4882a593Smuzhiyun u32 max_buff;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS)
937*4882a593Smuzhiyun continue; /* PG number 8 does not exist, skip it */
938*4882a593Smuzhiyun cm = &cms[i];
939*4882a593Smuzhiyun if (WARN_ON(sb_vals->pool_dess[cm->pool_index].dir != dir))
940*4882a593Smuzhiyun continue;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff);
943*4882a593Smuzhiyun max_buff = cm->max_buff;
944*4882a593Smuzhiyun if (max_buff == MLXSW_SP_SB_INFI) {
945*4882a593Smuzhiyun err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i,
946*4882a593Smuzhiyun min_buff, 0,
947*4882a593Smuzhiyun true, cm->pool_index);
948*4882a593Smuzhiyun } else {
949*4882a593Smuzhiyun if (mlxsw_sp_sb_pool_is_static(mlxsw_sp,
950*4882a593Smuzhiyun cm->pool_index))
951*4882a593Smuzhiyun max_buff = mlxsw_sp_bytes_cells(mlxsw_sp,
952*4882a593Smuzhiyun max_buff);
953*4882a593Smuzhiyun err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i,
954*4882a593Smuzhiyun min_buff, max_buff,
955*4882a593Smuzhiyun false, cm->pool_index);
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun if (err)
958*4882a593Smuzhiyun return err;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun return 0;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun
mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port * mlxsw_sp_port)963*4882a593Smuzhiyun static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port)
964*4882a593Smuzhiyun {
965*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
966*4882a593Smuzhiyun int err;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun err = __mlxsw_sp_sb_cms_init(mlxsw_sp,
969*4882a593Smuzhiyun mlxsw_sp_port->local_port,
970*4882a593Smuzhiyun MLXSW_REG_SBXX_DIR_INGRESS,
971*4882a593Smuzhiyun mlxsw_sp->sb_vals->cms_ingress,
972*4882a593Smuzhiyun mlxsw_sp->sb_vals->cms_ingress_count);
973*4882a593Smuzhiyun if (err)
974*4882a593Smuzhiyun return err;
975*4882a593Smuzhiyun return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
976*4882a593Smuzhiyun mlxsw_sp_port->local_port,
977*4882a593Smuzhiyun MLXSW_REG_SBXX_DIR_EGRESS,
978*4882a593Smuzhiyun mlxsw_sp->sb_vals->cms_egress,
979*4882a593Smuzhiyun mlxsw_sp->sb_vals->cms_egress_count);
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun
mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp * mlxsw_sp)982*4882a593Smuzhiyun static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
983*4882a593Smuzhiyun {
984*4882a593Smuzhiyun return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS,
985*4882a593Smuzhiyun mlxsw_sp->sb_vals->cms_cpu,
986*4882a593Smuzhiyun mlxsw_sp->sb_vals->cms_cpu_count);
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun #define MLXSW_SP_SB_PM(_min_buff, _max_buff) \
990*4882a593Smuzhiyun { \
991*4882a593Smuzhiyun .min_buff = _min_buff, \
992*4882a593Smuzhiyun .max_buff = _max_buff, \
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun /* Order according to mlxsw_sp1_sb_pool_dess */
996*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pm mlxsw_sp1_sb_pms[] = {
997*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
998*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
999*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1000*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1001*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 7),
1002*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1003*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1004*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1005*4882a593Smuzhiyun MLXSW_SP_SB_PM(10000, 90000),
1006*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 8), /* 50% occupancy */
1007*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1008*4882a593Smuzhiyun };
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun /* Order according to mlxsw_sp2_sb_pool_dess */
1011*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pm mlxsw_sp2_sb_pms[] = {
1012*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 7),
1013*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1014*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1015*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1016*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 7),
1017*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1018*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1019*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1020*4882a593Smuzhiyun MLXSW_SP_SB_PM(10000, 90000),
1021*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 8), /* 50% occupancy */
1022*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
1023*4882a593Smuzhiyun };
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun /* Order according to mlxsw_sp*_sb_pool_dess */
1026*4882a593Smuzhiyun static const struct mlxsw_sp_sb_pm mlxsw_sp_cpu_port_sb_pms[] = {
1027*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1028*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1029*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1030*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1031*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1032*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1033*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1034*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1035*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 90000),
1036*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, 0),
1037*4882a593Smuzhiyun MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
1038*4882a593Smuzhiyun };
1039*4882a593Smuzhiyun
mlxsw_sp_sb_pms_init(struct mlxsw_sp * mlxsw_sp,u8 local_port,const struct mlxsw_sp_sb_pm * pms,bool skip_ingress)1040*4882a593Smuzhiyun static int mlxsw_sp_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1041*4882a593Smuzhiyun const struct mlxsw_sp_sb_pm *pms,
1042*4882a593Smuzhiyun bool skip_ingress)
1043*4882a593Smuzhiyun {
1044*4882a593Smuzhiyun int i, err;
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
1047*4882a593Smuzhiyun const struct mlxsw_sp_sb_pm *pm = &pms[i];
1048*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des;
1049*4882a593Smuzhiyun u32 max_buff;
1050*4882a593Smuzhiyun u32 min_buff;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun des = &mlxsw_sp->sb_vals->pool_dess[i];
1053*4882a593Smuzhiyun if (skip_ingress && des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
1054*4882a593Smuzhiyun continue;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, pm->min_buff);
1057*4882a593Smuzhiyun max_buff = pm->max_buff;
1058*4882a593Smuzhiyun if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, i))
1059*4882a593Smuzhiyun max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, max_buff);
1060*4882a593Smuzhiyun err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, min_buff,
1061*4882a593Smuzhiyun max_buff);
1062*4882a593Smuzhiyun if (err)
1063*4882a593Smuzhiyun return err;
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun return 0;
1066*4882a593Smuzhiyun }
1067*4882a593Smuzhiyun
mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port * mlxsw_sp_port)1068*4882a593Smuzhiyun static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun return mlxsw_sp_sb_pms_init(mlxsw_sp, mlxsw_sp_port->local_port,
1073*4882a593Smuzhiyun mlxsw_sp->sb_vals->pms, false);
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun
mlxsw_sp_cpu_port_sb_pms_init(struct mlxsw_sp * mlxsw_sp)1076*4882a593Smuzhiyun static int mlxsw_sp_cpu_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun return mlxsw_sp_sb_pms_init(mlxsw_sp, 0, mlxsw_sp->sb_vals->pms_cpu,
1079*4882a593Smuzhiyun true);
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun #define MLXSW_SP_SB_MM(_min_buff, _max_buff) \
1083*4882a593Smuzhiyun { \
1084*4882a593Smuzhiyun .min_buff = _min_buff, \
1085*4882a593Smuzhiyun .max_buff = _max_buff, \
1086*4882a593Smuzhiyun .pool_index = MLXSW_SP_SB_POOL_EGR, \
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = {
1090*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1091*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1092*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1093*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1094*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1095*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1096*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1097*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1098*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1099*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1100*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1101*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1102*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1103*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1104*4882a593Smuzhiyun MLXSW_SP_SB_MM(0, 6),
1105*4882a593Smuzhiyun };
1106*4882a593Smuzhiyun
mlxsw_sp_sb_mms_init(struct mlxsw_sp * mlxsw_sp)1107*4882a593Smuzhiyun static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
1108*4882a593Smuzhiyun {
1109*4882a593Smuzhiyun char sbmm_pl[MLXSW_REG_SBMM_LEN];
1110*4882a593Smuzhiyun int i;
1111*4882a593Smuzhiyun int err;
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun for (i = 0; i < mlxsw_sp->sb_vals->mms_count; i++) {
1114*4882a593Smuzhiyun const struct mlxsw_sp_sb_pool_des *des;
1115*4882a593Smuzhiyun const struct mlxsw_sp_sb_mm *mc;
1116*4882a593Smuzhiyun u32 min_buff;
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun mc = &mlxsw_sp->sb_vals->mms[i];
1119*4882a593Smuzhiyun des = &mlxsw_sp->sb_vals->pool_dess[mc->pool_index];
1120*4882a593Smuzhiyun /* All pools used by sb_mm's are initialized using dynamic
1121*4882a593Smuzhiyun * thresholds, therefore 'max_buff' isn't specified in cells.
1122*4882a593Smuzhiyun */
1123*4882a593Smuzhiyun min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff);
1124*4882a593Smuzhiyun mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff,
1125*4882a593Smuzhiyun des->pool);
1126*4882a593Smuzhiyun err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl);
1127*4882a593Smuzhiyun if (err)
1128*4882a593Smuzhiyun return err;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun return 0;
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun
mlxsw_sp_pool_count(struct mlxsw_sp * mlxsw_sp,u16 * p_ingress_len,u16 * p_egress_len)1133*4882a593Smuzhiyun static void mlxsw_sp_pool_count(struct mlxsw_sp *mlxsw_sp,
1134*4882a593Smuzhiyun u16 *p_ingress_len, u16 *p_egress_len)
1135*4882a593Smuzhiyun {
1136*4882a593Smuzhiyun int i;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun for (i = 0; i < mlxsw_sp->sb_vals->pool_count; ++i) {
1139*4882a593Smuzhiyun if (mlxsw_sp->sb_vals->pool_dess[i].dir ==
1140*4882a593Smuzhiyun MLXSW_REG_SBXX_DIR_INGRESS)
1141*4882a593Smuzhiyun (*p_ingress_len)++;
1142*4882a593Smuzhiyun else
1143*4882a593Smuzhiyun (*p_egress_len)++;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun WARN(*p_egress_len == 0, "No egress pools\n");
1147*4882a593Smuzhiyun }
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals = {
1150*4882a593Smuzhiyun .pool_count = ARRAY_SIZE(mlxsw_sp1_sb_pool_dess),
1151*4882a593Smuzhiyun .pool_dess = mlxsw_sp1_sb_pool_dess,
1152*4882a593Smuzhiyun .pms = mlxsw_sp1_sb_pms,
1153*4882a593Smuzhiyun .pms_cpu = mlxsw_sp_cpu_port_sb_pms,
1154*4882a593Smuzhiyun .prs = mlxsw_sp1_sb_prs,
1155*4882a593Smuzhiyun .mms = mlxsw_sp_sb_mms,
1156*4882a593Smuzhiyun .cms_ingress = mlxsw_sp1_sb_cms_ingress,
1157*4882a593Smuzhiyun .cms_egress = mlxsw_sp1_sb_cms_egress,
1158*4882a593Smuzhiyun .cms_cpu = mlxsw_sp_cpu_port_sb_cms,
1159*4882a593Smuzhiyun .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms),
1160*4882a593Smuzhiyun .cms_ingress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_ingress),
1161*4882a593Smuzhiyun .cms_egress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_egress),
1162*4882a593Smuzhiyun .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms),
1163*4882a593Smuzhiyun };
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals = {
1166*4882a593Smuzhiyun .pool_count = ARRAY_SIZE(mlxsw_sp2_sb_pool_dess),
1167*4882a593Smuzhiyun .pool_dess = mlxsw_sp2_sb_pool_dess,
1168*4882a593Smuzhiyun .pms = mlxsw_sp2_sb_pms,
1169*4882a593Smuzhiyun .pms_cpu = mlxsw_sp_cpu_port_sb_pms,
1170*4882a593Smuzhiyun .prs = mlxsw_sp2_sb_prs,
1171*4882a593Smuzhiyun .mms = mlxsw_sp_sb_mms,
1172*4882a593Smuzhiyun .cms_ingress = mlxsw_sp2_sb_cms_ingress,
1173*4882a593Smuzhiyun .cms_egress = mlxsw_sp2_sb_cms_egress,
1174*4882a593Smuzhiyun .cms_cpu = mlxsw_sp_cpu_port_sb_cms,
1175*4882a593Smuzhiyun .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms),
1176*4882a593Smuzhiyun .cms_ingress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_ingress),
1177*4882a593Smuzhiyun .cms_egress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_egress),
1178*4882a593Smuzhiyun .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms),
1179*4882a593Smuzhiyun };
1180*4882a593Smuzhiyun
mlxsw_sp1_pb_int_buf_size_get(int mtu,u32 speed)1181*4882a593Smuzhiyun static u32 mlxsw_sp1_pb_int_buf_size_get(int mtu, u32 speed)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun return mtu * 5 / 2;
1184*4882a593Smuzhiyun }
1185*4882a593Smuzhiyun
__mlxsw_sp_pb_int_buf_size_get(int mtu,u32 speed,u32 buffer_factor)1186*4882a593Smuzhiyun static u32 __mlxsw_sp_pb_int_buf_size_get(int mtu, u32 speed, u32 buffer_factor)
1187*4882a593Smuzhiyun {
1188*4882a593Smuzhiyun return 3 * mtu + buffer_factor * speed / 1000;
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun #define MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR 38
1192*4882a593Smuzhiyun
mlxsw_sp2_pb_int_buf_size_get(int mtu,u32 speed)1193*4882a593Smuzhiyun static u32 mlxsw_sp2_pb_int_buf_size_get(int mtu, u32 speed)
1194*4882a593Smuzhiyun {
1195*4882a593Smuzhiyun int factor = MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun return __mlxsw_sp_pb_int_buf_size_get(mtu, speed, factor);
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun #define MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR 50
1201*4882a593Smuzhiyun
mlxsw_sp3_pb_int_buf_size_get(int mtu,u32 speed)1202*4882a593Smuzhiyun static u32 mlxsw_sp3_pb_int_buf_size_get(int mtu, u32 speed)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun int factor = MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR;
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun return __mlxsw_sp_pb_int_buf_size_get(mtu, speed, factor);
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun const struct mlxsw_sp_sb_ops mlxsw_sp1_sb_ops = {
1210*4882a593Smuzhiyun .int_buf_size_get = mlxsw_sp1_pb_int_buf_size_get,
1211*4882a593Smuzhiyun };
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun const struct mlxsw_sp_sb_ops mlxsw_sp2_sb_ops = {
1214*4882a593Smuzhiyun .int_buf_size_get = mlxsw_sp2_pb_int_buf_size_get,
1215*4882a593Smuzhiyun };
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun const struct mlxsw_sp_sb_ops mlxsw_sp3_sb_ops = {
1218*4882a593Smuzhiyun .int_buf_size_get = mlxsw_sp3_pb_int_buf_size_get,
1219*4882a593Smuzhiyun };
1220*4882a593Smuzhiyun
mlxsw_sp_buffers_init(struct mlxsw_sp * mlxsw_sp)1221*4882a593Smuzhiyun int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun u32 max_headroom_size;
1224*4882a593Smuzhiyun u16 ing_pool_count = 0;
1225*4882a593Smuzhiyun u16 eg_pool_count = 0;
1226*4882a593Smuzhiyun int err;
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE))
1229*4882a593Smuzhiyun return -EIO;
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, GUARANTEED_SHARED_BUFFER))
1232*4882a593Smuzhiyun return -EIO;
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE))
1235*4882a593Smuzhiyun return -EIO;
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL);
1238*4882a593Smuzhiyun if (!mlxsw_sp->sb)
1239*4882a593Smuzhiyun return -ENOMEM;
1240*4882a593Smuzhiyun mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE);
1241*4882a593Smuzhiyun mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1242*4882a593Smuzhiyun GUARANTEED_SHARED_BUFFER);
1243*4882a593Smuzhiyun max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1244*4882a593Smuzhiyun MAX_HEADROOM_SIZE);
1245*4882a593Smuzhiyun /* Round down, because this limit must not be overstepped. */
1246*4882a593Smuzhiyun mlxsw_sp->sb->max_headroom_cells = max_headroom_size /
1247*4882a593Smuzhiyun mlxsw_sp->sb->cell_size;
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun err = mlxsw_sp_sb_ports_init(mlxsw_sp);
1250*4882a593Smuzhiyun if (err)
1251*4882a593Smuzhiyun goto err_sb_ports_init;
1252*4882a593Smuzhiyun err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs,
1253*4882a593Smuzhiyun mlxsw_sp->sb_vals->pool_dess,
1254*4882a593Smuzhiyun mlxsw_sp->sb_vals->pool_count);
1255*4882a593Smuzhiyun if (err)
1256*4882a593Smuzhiyun goto err_sb_prs_init;
1257*4882a593Smuzhiyun err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp);
1258*4882a593Smuzhiyun if (err)
1259*4882a593Smuzhiyun goto err_sb_cpu_port_sb_cms_init;
1260*4882a593Smuzhiyun err = mlxsw_sp_cpu_port_sb_pms_init(mlxsw_sp);
1261*4882a593Smuzhiyun if (err)
1262*4882a593Smuzhiyun goto err_sb_cpu_port_pms_init;
1263*4882a593Smuzhiyun err = mlxsw_sp_sb_mms_init(mlxsw_sp);
1264*4882a593Smuzhiyun if (err)
1265*4882a593Smuzhiyun goto err_sb_mms_init;
1266*4882a593Smuzhiyun mlxsw_sp_pool_count(mlxsw_sp, &ing_pool_count, &eg_pool_count);
1267*4882a593Smuzhiyun err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0,
1268*4882a593Smuzhiyun mlxsw_sp->sb->sb_size,
1269*4882a593Smuzhiyun ing_pool_count,
1270*4882a593Smuzhiyun eg_pool_count,
1271*4882a593Smuzhiyun MLXSW_SP_SB_ING_TC_COUNT,
1272*4882a593Smuzhiyun MLXSW_SP_SB_EG_TC_COUNT);
1273*4882a593Smuzhiyun if (err)
1274*4882a593Smuzhiyun goto err_devlink_sb_register;
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun return 0;
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun err_devlink_sb_register:
1279*4882a593Smuzhiyun err_sb_mms_init:
1280*4882a593Smuzhiyun err_sb_cpu_port_pms_init:
1281*4882a593Smuzhiyun err_sb_cpu_port_sb_cms_init:
1282*4882a593Smuzhiyun err_sb_prs_init:
1283*4882a593Smuzhiyun mlxsw_sp_sb_ports_fini(mlxsw_sp);
1284*4882a593Smuzhiyun err_sb_ports_init:
1285*4882a593Smuzhiyun kfree(mlxsw_sp->sb);
1286*4882a593Smuzhiyun return err;
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun
mlxsw_sp_buffers_fini(struct mlxsw_sp * mlxsw_sp)1289*4882a593Smuzhiyun void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp)
1290*4882a593Smuzhiyun {
1291*4882a593Smuzhiyun devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0);
1292*4882a593Smuzhiyun mlxsw_sp_sb_ports_fini(mlxsw_sp);
1293*4882a593Smuzhiyun kfree(mlxsw_sp->sb);
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
mlxsw_sp_port_buffers_init(struct mlxsw_sp_port * mlxsw_sp_port)1296*4882a593Smuzhiyun int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port)
1297*4882a593Smuzhiyun {
1298*4882a593Smuzhiyun int err;
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun mlxsw_sp_port->hdroom = kzalloc(sizeof(*mlxsw_sp_port->hdroom), GFP_KERNEL);
1301*4882a593Smuzhiyun if (!mlxsw_sp_port->hdroom)
1302*4882a593Smuzhiyun return -ENOMEM;
1303*4882a593Smuzhiyun mlxsw_sp_port->hdroom->mtu = mlxsw_sp_port->dev->mtu;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun err = mlxsw_sp_port_headroom_init(mlxsw_sp_port);
1306*4882a593Smuzhiyun if (err)
1307*4882a593Smuzhiyun goto err_headroom_init;
1308*4882a593Smuzhiyun err = mlxsw_sp_port_sb_cms_init(mlxsw_sp_port);
1309*4882a593Smuzhiyun if (err)
1310*4882a593Smuzhiyun goto err_port_sb_cms_init;
1311*4882a593Smuzhiyun err = mlxsw_sp_port_sb_pms_init(mlxsw_sp_port);
1312*4882a593Smuzhiyun if (err)
1313*4882a593Smuzhiyun goto err_port_sb_pms_init;
1314*4882a593Smuzhiyun return 0;
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun err_port_sb_pms_init:
1317*4882a593Smuzhiyun err_port_sb_cms_init:
1318*4882a593Smuzhiyun err_headroom_init:
1319*4882a593Smuzhiyun kfree(mlxsw_sp_port->hdroom);
1320*4882a593Smuzhiyun return err;
1321*4882a593Smuzhiyun }
1322*4882a593Smuzhiyun
mlxsw_sp_port_buffers_fini(struct mlxsw_sp_port * mlxsw_sp_port)1323*4882a593Smuzhiyun void mlxsw_sp_port_buffers_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1324*4882a593Smuzhiyun {
1325*4882a593Smuzhiyun kfree(mlxsw_sp_port->hdroom);
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun
mlxsw_sp_sb_pool_get(struct mlxsw_core * mlxsw_core,unsigned int sb_index,u16 pool_index,struct devlink_sb_pool_info * pool_info)1328*4882a593Smuzhiyun int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core,
1329*4882a593Smuzhiyun unsigned int sb_index, u16 pool_index,
1330*4882a593Smuzhiyun struct devlink_sb_pool_info *pool_info)
1331*4882a593Smuzhiyun {
1332*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1333*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir;
1334*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *pr;
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun dir = mlxsw_sp->sb_vals->pool_dess[pool_index].dir;
1337*4882a593Smuzhiyun pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
1338*4882a593Smuzhiyun pool_info->pool_type = (enum devlink_sb_pool_type) dir;
1339*4882a593Smuzhiyun pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size);
1340*4882a593Smuzhiyun pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode;
1341*4882a593Smuzhiyun pool_info->cell_size = mlxsw_sp->sb->cell_size;
1342*4882a593Smuzhiyun return 0;
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun
mlxsw_sp_sb_pool_set(struct mlxsw_core * mlxsw_core,unsigned int sb_index,u16 pool_index,u32 size,enum devlink_sb_threshold_type threshold_type,struct netlink_ext_ack * extack)1345*4882a593Smuzhiyun int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core,
1346*4882a593Smuzhiyun unsigned int sb_index, u16 pool_index, u32 size,
1347*4882a593Smuzhiyun enum devlink_sb_threshold_type threshold_type,
1348*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1349*4882a593Smuzhiyun {
1350*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1351*4882a593Smuzhiyun u32 pool_size = mlxsw_sp_bytes_cells(mlxsw_sp, size);
1352*4882a593Smuzhiyun const struct mlxsw_sp_sb_pr *pr;
1353*4882a593Smuzhiyun enum mlxsw_reg_sbpr_mode mode;
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun mode = (enum mlxsw_reg_sbpr_mode) threshold_type;
1356*4882a593Smuzhiyun pr = &mlxsw_sp->sb_vals->prs[pool_index];
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core,
1359*4882a593Smuzhiyun GUARANTEED_SHARED_BUFFER)) {
1360*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Exceeded shared buffer size");
1361*4882a593Smuzhiyun return -EINVAL;
1362*4882a593Smuzhiyun }
1363*4882a593Smuzhiyun
1364*4882a593Smuzhiyun if (pr->freeze_mode && pr->mode != mode) {
1365*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Changing this pool's threshold type is forbidden");
1366*4882a593Smuzhiyun return -EINVAL;
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun
1369*4882a593Smuzhiyun if (pr->freeze_size && pr->size != size) {
1370*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Changing this pool's size is forbidden");
1371*4882a593Smuzhiyun return -EINVAL;
1372*4882a593Smuzhiyun }
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode,
1375*4882a593Smuzhiyun pool_size, false);
1376*4882a593Smuzhiyun }
1377*4882a593Smuzhiyun
1378*4882a593Smuzhiyun #define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */
1379*4882a593Smuzhiyun
mlxsw_sp_sb_threshold_out(struct mlxsw_sp * mlxsw_sp,u16 pool_index,u32 max_buff)1380*4882a593Smuzhiyun static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
1381*4882a593Smuzhiyun u32 max_buff)
1382*4882a593Smuzhiyun {
1383*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC)
1386*4882a593Smuzhiyun return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET;
1387*4882a593Smuzhiyun return mlxsw_sp_cells_bytes(mlxsw_sp, max_buff);
1388*4882a593Smuzhiyun }
1389*4882a593Smuzhiyun
mlxsw_sp_sb_threshold_in(struct mlxsw_sp * mlxsw_sp,u16 pool_index,u32 threshold,u32 * p_max_buff,struct netlink_ext_ack * extack)1390*4882a593Smuzhiyun static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
1391*4882a593Smuzhiyun u32 threshold, u32 *p_max_buff,
1392*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1393*4882a593Smuzhiyun {
1394*4882a593Smuzhiyun struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) {
1397*4882a593Smuzhiyun int val;
1398*4882a593Smuzhiyun
1399*4882a593Smuzhiyun val = threshold + MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET;
1400*4882a593Smuzhiyun if (val < MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN ||
1401*4882a593Smuzhiyun val > MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX) {
1402*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Invalid dynamic threshold value");
1403*4882a593Smuzhiyun return -EINVAL;
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun *p_max_buff = val;
1406*4882a593Smuzhiyun } else {
1407*4882a593Smuzhiyun *p_max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, threshold);
1408*4882a593Smuzhiyun }
1409*4882a593Smuzhiyun return 0;
1410*4882a593Smuzhiyun }
1411*4882a593Smuzhiyun
mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port * mlxsw_core_port,unsigned int sb_index,u16 pool_index,u32 * p_threshold)1412*4882a593Smuzhiyun int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
1413*4882a593Smuzhiyun unsigned int sb_index, u16 pool_index,
1414*4882a593Smuzhiyun u32 *p_threshold)
1415*4882a593Smuzhiyun {
1416*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port =
1417*4882a593Smuzhiyun mlxsw_core_port_driver_priv(mlxsw_core_port);
1418*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1419*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1420*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
1421*4882a593Smuzhiyun pool_index);
1422*4882a593Smuzhiyun
1423*4882a593Smuzhiyun *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool_index,
1424*4882a593Smuzhiyun pm->max_buff);
1425*4882a593Smuzhiyun return 0;
1426*4882a593Smuzhiyun }
1427*4882a593Smuzhiyun
mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port * mlxsw_core_port,unsigned int sb_index,u16 pool_index,u32 threshold,struct netlink_ext_ack * extack)1428*4882a593Smuzhiyun int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port,
1429*4882a593Smuzhiyun unsigned int sb_index, u16 pool_index,
1430*4882a593Smuzhiyun u32 threshold, struct netlink_ext_ack *extack)
1431*4882a593Smuzhiyun {
1432*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port =
1433*4882a593Smuzhiyun mlxsw_core_port_driver_priv(mlxsw_core_port);
1434*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1435*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1436*4882a593Smuzhiyun u32 max_buff;
1437*4882a593Smuzhiyun int err;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun if (local_port == MLXSW_PORT_CPU_PORT) {
1440*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's threshold is forbidden");
1441*4882a593Smuzhiyun return -EINVAL;
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
1445*4882a593Smuzhiyun threshold, &max_buff, extack);
1446*4882a593Smuzhiyun if (err)
1447*4882a593Smuzhiyun return err;
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool_index,
1450*4882a593Smuzhiyun 0, max_buff);
1451*4882a593Smuzhiyun }
1452*4882a593Smuzhiyun
mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port * mlxsw_core_port,unsigned int sb_index,u16 tc_index,enum devlink_sb_pool_type pool_type,u16 * p_pool_index,u32 * p_threshold)1453*4882a593Smuzhiyun int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port,
1454*4882a593Smuzhiyun unsigned int sb_index, u16 tc_index,
1455*4882a593Smuzhiyun enum devlink_sb_pool_type pool_type,
1456*4882a593Smuzhiyun u16 *p_pool_index, u32 *p_threshold)
1457*4882a593Smuzhiyun {
1458*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port =
1459*4882a593Smuzhiyun mlxsw_core_port_driver_priv(mlxsw_core_port);
1460*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1461*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1462*4882a593Smuzhiyun u8 pg_buff = tc_index;
1463*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
1464*4882a593Smuzhiyun struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port,
1465*4882a593Smuzhiyun pg_buff, dir);
1466*4882a593Smuzhiyun
1467*4882a593Smuzhiyun *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool_index,
1468*4882a593Smuzhiyun cm->max_buff);
1469*4882a593Smuzhiyun *p_pool_index = cm->pool_index;
1470*4882a593Smuzhiyun return 0;
1471*4882a593Smuzhiyun }
1472*4882a593Smuzhiyun
mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port * mlxsw_core_port,unsigned int sb_index,u16 tc_index,enum devlink_sb_pool_type pool_type,u16 pool_index,u32 threshold,struct netlink_ext_ack * extack)1473*4882a593Smuzhiyun int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
1474*4882a593Smuzhiyun unsigned int sb_index, u16 tc_index,
1475*4882a593Smuzhiyun enum devlink_sb_pool_type pool_type,
1476*4882a593Smuzhiyun u16 pool_index, u32 threshold,
1477*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1478*4882a593Smuzhiyun {
1479*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port =
1480*4882a593Smuzhiyun mlxsw_core_port_driver_priv(mlxsw_core_port);
1481*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1482*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1483*4882a593Smuzhiyun const struct mlxsw_sp_sb_cm *cm;
1484*4882a593Smuzhiyun u8 pg_buff = tc_index;
1485*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
1486*4882a593Smuzhiyun u32 max_buff;
1487*4882a593Smuzhiyun int err;
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun if (local_port == MLXSW_PORT_CPU_PORT) {
1490*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's binding is forbidden");
1491*4882a593Smuzhiyun return -EINVAL;
1492*4882a593Smuzhiyun }
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir) {
1495*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Binding egress TC to ingress pool and vice versa is forbidden");
1496*4882a593Smuzhiyun return -EINVAL;
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun
1499*4882a593Smuzhiyun if (dir == MLXSW_REG_SBXX_DIR_INGRESS)
1500*4882a593Smuzhiyun cm = &mlxsw_sp->sb_vals->cms_ingress[tc_index];
1501*4882a593Smuzhiyun else
1502*4882a593Smuzhiyun cm = &mlxsw_sp->sb_vals->cms_egress[tc_index];
1503*4882a593Smuzhiyun
1504*4882a593Smuzhiyun if (cm->freeze_pool && cm->pool_index != pool_index) {
1505*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Binding this TC to a different pool is forbidden");
1506*4882a593Smuzhiyun return -EINVAL;
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun if (cm->freeze_thresh && cm->max_buff != threshold) {
1510*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Changing this TC's threshold is forbidden");
1511*4882a593Smuzhiyun return -EINVAL;
1512*4882a593Smuzhiyun }
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
1515*4882a593Smuzhiyun threshold, &max_buff, extack);
1516*4882a593Smuzhiyun if (err)
1517*4882a593Smuzhiyun return err;
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff,
1520*4882a593Smuzhiyun 0, max_buff, false, pool_index);
1521*4882a593Smuzhiyun }
1522*4882a593Smuzhiyun
1523*4882a593Smuzhiyun #define MASKED_COUNT_MAX \
1524*4882a593Smuzhiyun (MLXSW_REG_SBSR_REC_MAX_COUNT / \
1525*4882a593Smuzhiyun (MLXSW_SP_SB_ING_TC_COUNT + MLXSW_SP_SB_EG_TC_COUNT))
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun struct mlxsw_sp_sb_sr_occ_query_cb_ctx {
1528*4882a593Smuzhiyun u8 masked_count;
1529*4882a593Smuzhiyun u8 local_port_1;
1530*4882a593Smuzhiyun };
1531*4882a593Smuzhiyun
mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core * mlxsw_core,char * sbsr_pl,size_t sbsr_pl_len,unsigned long cb_priv)1532*4882a593Smuzhiyun static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
1533*4882a593Smuzhiyun char *sbsr_pl, size_t sbsr_pl_len,
1534*4882a593Smuzhiyun unsigned long cb_priv)
1535*4882a593Smuzhiyun {
1536*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1537*4882a593Smuzhiyun struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx;
1538*4882a593Smuzhiyun u8 masked_count;
1539*4882a593Smuzhiyun u8 local_port;
1540*4882a593Smuzhiyun int rec_index = 0;
1541*4882a593Smuzhiyun struct mlxsw_sp_sb_cm *cm;
1542*4882a593Smuzhiyun int i;
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun memcpy(&cb_ctx, &cb_priv, sizeof(cb_ctx));
1545*4882a593Smuzhiyun
1546*4882a593Smuzhiyun masked_count = 0;
1547*4882a593Smuzhiyun for (local_port = cb_ctx.local_port_1;
1548*4882a593Smuzhiyun local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
1549*4882a593Smuzhiyun if (!mlxsw_sp->ports[local_port])
1550*4882a593Smuzhiyun continue;
1551*4882a593Smuzhiyun if (local_port == MLXSW_PORT_CPU_PORT) {
1552*4882a593Smuzhiyun /* Ingress quotas are not supported for the CPU port */
1553*4882a593Smuzhiyun masked_count++;
1554*4882a593Smuzhiyun continue;
1555*4882a593Smuzhiyun }
1556*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) {
1557*4882a593Smuzhiyun cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
1558*4882a593Smuzhiyun MLXSW_REG_SBXX_DIR_INGRESS);
1559*4882a593Smuzhiyun mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
1560*4882a593Smuzhiyun &cm->occ.cur, &cm->occ.max);
1561*4882a593Smuzhiyun }
1562*4882a593Smuzhiyun if (++masked_count == cb_ctx.masked_count)
1563*4882a593Smuzhiyun break;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun masked_count = 0;
1566*4882a593Smuzhiyun for (local_port = cb_ctx.local_port_1;
1567*4882a593Smuzhiyun local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
1568*4882a593Smuzhiyun if (!mlxsw_sp->ports[local_port])
1569*4882a593Smuzhiyun continue;
1570*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) {
1571*4882a593Smuzhiyun cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
1572*4882a593Smuzhiyun MLXSW_REG_SBXX_DIR_EGRESS);
1573*4882a593Smuzhiyun mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
1574*4882a593Smuzhiyun &cm->occ.cur, &cm->occ.max);
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun if (++masked_count == cb_ctx.masked_count)
1577*4882a593Smuzhiyun break;
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun }
1580*4882a593Smuzhiyun
mlxsw_sp_sb_occ_snapshot(struct mlxsw_core * mlxsw_core,unsigned int sb_index)1581*4882a593Smuzhiyun int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
1582*4882a593Smuzhiyun unsigned int sb_index)
1583*4882a593Smuzhiyun {
1584*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1585*4882a593Smuzhiyun struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx;
1586*4882a593Smuzhiyun unsigned long cb_priv;
1587*4882a593Smuzhiyun LIST_HEAD(bulk_list);
1588*4882a593Smuzhiyun char *sbsr_pl;
1589*4882a593Smuzhiyun u8 masked_count;
1590*4882a593Smuzhiyun u8 local_port_1;
1591*4882a593Smuzhiyun u8 local_port;
1592*4882a593Smuzhiyun int i;
1593*4882a593Smuzhiyun int err;
1594*4882a593Smuzhiyun int err2;
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL);
1597*4882a593Smuzhiyun if (!sbsr_pl)
1598*4882a593Smuzhiyun return -ENOMEM;
1599*4882a593Smuzhiyun
1600*4882a593Smuzhiyun local_port = MLXSW_PORT_CPU_PORT;
1601*4882a593Smuzhiyun next_batch:
1602*4882a593Smuzhiyun local_port_1 = local_port;
1603*4882a593Smuzhiyun masked_count = 0;
1604*4882a593Smuzhiyun mlxsw_reg_sbsr_pack(sbsr_pl, false);
1605*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++)
1606*4882a593Smuzhiyun mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
1607*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++)
1608*4882a593Smuzhiyun mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
1609*4882a593Smuzhiyun for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
1610*4882a593Smuzhiyun if (!mlxsw_sp->ports[local_port])
1611*4882a593Smuzhiyun continue;
1612*4882a593Smuzhiyun if (local_port != MLXSW_PORT_CPU_PORT) {
1613*4882a593Smuzhiyun /* Ingress quotas are not supported for the CPU port */
1614*4882a593Smuzhiyun mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl,
1615*4882a593Smuzhiyun local_port, 1);
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
1618*4882a593Smuzhiyun for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
1619*4882a593Smuzhiyun err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
1620*4882a593Smuzhiyun &bulk_list);
1621*4882a593Smuzhiyun if (err)
1622*4882a593Smuzhiyun goto out;
1623*4882a593Smuzhiyun }
1624*4882a593Smuzhiyun if (++masked_count == MASKED_COUNT_MAX)
1625*4882a593Smuzhiyun goto do_query;
1626*4882a593Smuzhiyun }
1627*4882a593Smuzhiyun
1628*4882a593Smuzhiyun do_query:
1629*4882a593Smuzhiyun cb_ctx.masked_count = masked_count;
1630*4882a593Smuzhiyun cb_ctx.local_port_1 = local_port_1;
1631*4882a593Smuzhiyun memcpy(&cb_priv, &cb_ctx, sizeof(cb_ctx));
1632*4882a593Smuzhiyun err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl,
1633*4882a593Smuzhiyun &bulk_list, mlxsw_sp_sb_sr_occ_query_cb,
1634*4882a593Smuzhiyun cb_priv);
1635*4882a593Smuzhiyun if (err)
1636*4882a593Smuzhiyun goto out;
1637*4882a593Smuzhiyun if (local_port < mlxsw_core_max_ports(mlxsw_core)) {
1638*4882a593Smuzhiyun local_port++;
1639*4882a593Smuzhiyun goto next_batch;
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun out:
1643*4882a593Smuzhiyun err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
1644*4882a593Smuzhiyun if (!err)
1645*4882a593Smuzhiyun err = err2;
1646*4882a593Smuzhiyun kfree(sbsr_pl);
1647*4882a593Smuzhiyun return err;
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun
mlxsw_sp_sb_occ_max_clear(struct mlxsw_core * mlxsw_core,unsigned int sb_index)1650*4882a593Smuzhiyun int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
1651*4882a593Smuzhiyun unsigned int sb_index)
1652*4882a593Smuzhiyun {
1653*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1654*4882a593Smuzhiyun LIST_HEAD(bulk_list);
1655*4882a593Smuzhiyun char *sbsr_pl;
1656*4882a593Smuzhiyun unsigned int masked_count;
1657*4882a593Smuzhiyun u8 local_port;
1658*4882a593Smuzhiyun int i;
1659*4882a593Smuzhiyun int err;
1660*4882a593Smuzhiyun int err2;
1661*4882a593Smuzhiyun
1662*4882a593Smuzhiyun sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL);
1663*4882a593Smuzhiyun if (!sbsr_pl)
1664*4882a593Smuzhiyun return -ENOMEM;
1665*4882a593Smuzhiyun
1666*4882a593Smuzhiyun local_port = MLXSW_PORT_CPU_PORT;
1667*4882a593Smuzhiyun next_batch:
1668*4882a593Smuzhiyun masked_count = 0;
1669*4882a593Smuzhiyun mlxsw_reg_sbsr_pack(sbsr_pl, true);
1670*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++)
1671*4882a593Smuzhiyun mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
1672*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++)
1673*4882a593Smuzhiyun mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
1674*4882a593Smuzhiyun for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
1675*4882a593Smuzhiyun if (!mlxsw_sp->ports[local_port])
1676*4882a593Smuzhiyun continue;
1677*4882a593Smuzhiyun if (local_port != MLXSW_PORT_CPU_PORT) {
1678*4882a593Smuzhiyun /* Ingress quotas are not supported for the CPU port */
1679*4882a593Smuzhiyun mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl,
1680*4882a593Smuzhiyun local_port, 1);
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
1683*4882a593Smuzhiyun for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
1684*4882a593Smuzhiyun err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
1685*4882a593Smuzhiyun &bulk_list);
1686*4882a593Smuzhiyun if (err)
1687*4882a593Smuzhiyun goto out;
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun if (++masked_count == MASKED_COUNT_MAX)
1690*4882a593Smuzhiyun goto do_query;
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun
1693*4882a593Smuzhiyun do_query:
1694*4882a593Smuzhiyun err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl,
1695*4882a593Smuzhiyun &bulk_list, NULL, 0);
1696*4882a593Smuzhiyun if (err)
1697*4882a593Smuzhiyun goto out;
1698*4882a593Smuzhiyun if (local_port < mlxsw_core_max_ports(mlxsw_core)) {
1699*4882a593Smuzhiyun local_port++;
1700*4882a593Smuzhiyun goto next_batch;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun
1703*4882a593Smuzhiyun out:
1704*4882a593Smuzhiyun err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
1705*4882a593Smuzhiyun if (!err)
1706*4882a593Smuzhiyun err = err2;
1707*4882a593Smuzhiyun kfree(sbsr_pl);
1708*4882a593Smuzhiyun return err;
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port * mlxsw_core_port,unsigned int sb_index,u16 pool_index,u32 * p_cur,u32 * p_max)1711*4882a593Smuzhiyun int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
1712*4882a593Smuzhiyun unsigned int sb_index, u16 pool_index,
1713*4882a593Smuzhiyun u32 *p_cur, u32 *p_max)
1714*4882a593Smuzhiyun {
1715*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port =
1716*4882a593Smuzhiyun mlxsw_core_port_driver_priv(mlxsw_core_port);
1717*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1718*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1719*4882a593Smuzhiyun struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
1720*4882a593Smuzhiyun pool_index);
1721*4882a593Smuzhiyun
1722*4882a593Smuzhiyun *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.cur);
1723*4882a593Smuzhiyun *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.max);
1724*4882a593Smuzhiyun return 0;
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun
mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port * mlxsw_core_port,unsigned int sb_index,u16 tc_index,enum devlink_sb_pool_type pool_type,u32 * p_cur,u32 * p_max)1727*4882a593Smuzhiyun int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
1728*4882a593Smuzhiyun unsigned int sb_index, u16 tc_index,
1729*4882a593Smuzhiyun enum devlink_sb_pool_type pool_type,
1730*4882a593Smuzhiyun u32 *p_cur, u32 *p_max)
1731*4882a593Smuzhiyun {
1732*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port =
1733*4882a593Smuzhiyun mlxsw_core_port_driver_priv(mlxsw_core_port);
1734*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1735*4882a593Smuzhiyun u8 local_port = mlxsw_sp_port->local_port;
1736*4882a593Smuzhiyun u8 pg_buff = tc_index;
1737*4882a593Smuzhiyun enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
1738*4882a593Smuzhiyun struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port,
1739*4882a593Smuzhiyun pg_buff, dir);
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.cur);
1742*4882a593Smuzhiyun *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.max);
1743*4882a593Smuzhiyun return 0;
1744*4882a593Smuzhiyun }
1745