xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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