2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
3 * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <linux/kernel.h>
36 #include <linux/types.h>
37 #include <linux/dcbnl.h>
38 #include <linux/if_ether.h>
39 #include <linux/list.h>
46 static struct mlxsw_sp_sb_pr
*mlxsw_sp_sb_pr_get(struct mlxsw_sp
*mlxsw_sp
,
48 enum mlxsw_reg_sbxx_dir dir
)
50 return &mlxsw_sp
->sb
.prs
[dir
][pool
];
53 static struct mlxsw_sp_sb_cm
*mlxsw_sp_sb_cm_get(struct mlxsw_sp
*mlxsw_sp
,
54 u8 local_port
, u8 pg_buff
,
55 enum mlxsw_reg_sbxx_dir dir
)
57 return &mlxsw_sp
->sb
.ports
[local_port
].cms
[dir
][pg_buff
];
60 static struct mlxsw_sp_sb_pm
*mlxsw_sp_sb_pm_get(struct mlxsw_sp
*mlxsw_sp
,
61 u8 local_port
, u8 pool
,
62 enum mlxsw_reg_sbxx_dir dir
)
64 return &mlxsw_sp
->sb
.ports
[local_port
].pms
[dir
][pool
];
67 static int mlxsw_sp_sb_pr_write(struct mlxsw_sp
*mlxsw_sp
, u8 pool
,
68 enum mlxsw_reg_sbxx_dir dir
,
69 enum mlxsw_reg_sbpr_mode mode
, u32 size
)
71 char sbpr_pl
[MLXSW_REG_SBPR_LEN
];
72 struct mlxsw_sp_sb_pr
*pr
;
75 mlxsw_reg_sbpr_pack(sbpr_pl
, pool
, dir
, mode
, size
);
76 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbpr
), sbpr_pl
);
80 pr
= mlxsw_sp_sb_pr_get(mlxsw_sp
, pool
, dir
);
86 static int mlxsw_sp_sb_cm_write(struct mlxsw_sp
*mlxsw_sp
, u8 local_port
,
87 u8 pg_buff
, enum mlxsw_reg_sbxx_dir dir
,
88 u32 min_buff
, u32 max_buff
, u8 pool
)
90 char sbcm_pl
[MLXSW_REG_SBCM_LEN
];
93 mlxsw_reg_sbcm_pack(sbcm_pl
, local_port
, pg_buff
, dir
,
94 min_buff
, max_buff
, pool
);
95 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbcm
), sbcm_pl
);
98 if (pg_buff
< MLXSW_SP_SB_TC_COUNT
) {
99 struct mlxsw_sp_sb_cm
*cm
;
101 cm
= mlxsw_sp_sb_cm_get(mlxsw_sp
, local_port
, pg_buff
, dir
);
102 cm
->min_buff
= min_buff
;
103 cm
->max_buff
= max_buff
;
109 static int mlxsw_sp_sb_pm_write(struct mlxsw_sp
*mlxsw_sp
, u8 local_port
,
110 u8 pool
, enum mlxsw_reg_sbxx_dir dir
,
111 u32 min_buff
, u32 max_buff
)
113 char sbpm_pl
[MLXSW_REG_SBPM_LEN
];
114 struct mlxsw_sp_sb_pm
*pm
;
117 mlxsw_reg_sbpm_pack(sbpm_pl
, local_port
, pool
, dir
, false,
119 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbpm
), sbpm_pl
);
123 pm
= mlxsw_sp_sb_pm_get(mlxsw_sp
, local_port
, pool
, dir
);
124 pm
->min_buff
= min_buff
;
125 pm
->max_buff
= max_buff
;
129 static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp
*mlxsw_sp
, u8 local_port
,
130 u8 pool
, enum mlxsw_reg_sbxx_dir dir
,
131 struct list_head
*bulk_list
)
133 char sbpm_pl
[MLXSW_REG_SBPM_LEN
];
135 mlxsw_reg_sbpm_pack(sbpm_pl
, local_port
, pool
, dir
, true, 0, 0);
136 return mlxsw_reg_trans_query(mlxsw_sp
->core
, MLXSW_REG(sbpm
), sbpm_pl
,
140 static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core
*mlxsw_core
,
141 char *sbpm_pl
, size_t sbpm_pl_len
,
142 unsigned long cb_priv
)
144 struct mlxsw_sp_sb_pm
*pm
= (struct mlxsw_sp_sb_pm
*) cb_priv
;
146 mlxsw_reg_sbpm_unpack(sbpm_pl
, &pm
->occ
.cur
, &pm
->occ
.max
);
149 static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp
*mlxsw_sp
, u8 local_port
,
150 u8 pool
, enum mlxsw_reg_sbxx_dir dir
,
151 struct list_head
*bulk_list
)
153 char sbpm_pl
[MLXSW_REG_SBPM_LEN
];
154 struct mlxsw_sp_sb_pm
*pm
;
156 pm
= mlxsw_sp_sb_pm_get(mlxsw_sp
, local_port
, pool
, dir
);
157 mlxsw_reg_sbpm_pack(sbpm_pl
, local_port
, pool
, dir
, false, 0, 0);
158 return mlxsw_reg_trans_query(mlxsw_sp
->core
, MLXSW_REG(sbpm
), sbpm_pl
,
160 mlxsw_sp_sb_pm_occ_query_cb
,
164 static const u16 mlxsw_sp_pbs
[] = {
165 [0] = 2 * MLXSW_SP_BYTES_TO_CELLS(ETH_FRAME_LEN
),
166 [9] = 2 * MLXSW_SP_BYTES_TO_CELLS(MLXSW_PORT_MAX_MTU
),
169 #define MLXSW_SP_PBS_LEN ARRAY_SIZE(mlxsw_sp_pbs)
170 #define MLXSW_SP_PB_UNUSED 8
172 static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
174 char pbmc_pl
[MLXSW_REG_PBMC_LEN
];
177 mlxsw_reg_pbmc_pack(pbmc_pl
, mlxsw_sp_port
->local_port
,
179 for (i
= 0; i
< MLXSW_SP_PBS_LEN
; i
++) {
180 if (i
== MLXSW_SP_PB_UNUSED
)
182 mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl
, i
, mlxsw_sp_pbs
[i
]);
184 mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl
,
185 MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX
, 0);
186 return mlxsw_reg_write(mlxsw_sp_port
->mlxsw_sp
->core
,
187 MLXSW_REG(pbmc
), pbmc_pl
);
190 static int mlxsw_sp_port_pb_prio_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
192 char pptb_pl
[MLXSW_REG_PPTB_LEN
];
195 mlxsw_reg_pptb_pack(pptb_pl
, mlxsw_sp_port
->local_port
);
196 for (i
= 0; i
< IEEE_8021QAZ_MAX_TCS
; i
++)
197 mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl
, i
, 0);
198 return mlxsw_reg_write(mlxsw_sp_port
->mlxsw_sp
->core
, MLXSW_REG(pptb
),
202 static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
206 err
= mlxsw_sp_port_pb_init(mlxsw_sp_port
);
209 return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port
);
212 #define MLXSW_SP_SB_PR_INGRESS_SIZE \
213 (15000000 - (2 * 20000 * MLXSW_PORT_MAX_PORTS))
214 #define MLXSW_SP_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
215 #define MLXSW_SP_SB_PR_EGRESS_SIZE \
216 (14000000 - (8 * 1500 * MLXSW_PORT_MAX_PORTS))
218 #define MLXSW_SP_SB_PR(_mode, _size) \
224 static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_ingress
[] = {
225 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
,
226 MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_PR_INGRESS_SIZE
)),
227 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
, 0),
228 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
, 0),
229 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
,
230 MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_PR_INGRESS_MNG_SIZE
)),
233 #define MLXSW_SP_SB_PRS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_ingress)
235 static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_egress
[] = {
236 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
,
237 MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_PR_EGRESS_SIZE
)),
238 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
, 0),
239 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
, 0),
240 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC
, 0),
243 #define MLXSW_SP_SB_PRS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_egress)
245 static int __mlxsw_sp_sb_prs_init(struct mlxsw_sp
*mlxsw_sp
,
246 enum mlxsw_reg_sbxx_dir dir
,
247 const struct mlxsw_sp_sb_pr
*prs
,
253 for (i
= 0; i
< prs_len
; i
++) {
254 const struct mlxsw_sp_sb_pr
*pr
;
257 err
= mlxsw_sp_sb_pr_write(mlxsw_sp
, i
, dir
,
265 static int mlxsw_sp_sb_prs_init(struct mlxsw_sp
*mlxsw_sp
)
269 err
= __mlxsw_sp_sb_prs_init(mlxsw_sp
, MLXSW_REG_SBXX_DIR_INGRESS
,
270 mlxsw_sp_sb_prs_ingress
,
271 MLXSW_SP_SB_PRS_INGRESS_LEN
);
274 return __mlxsw_sp_sb_prs_init(mlxsw_sp
, MLXSW_REG_SBXX_DIR_EGRESS
,
275 mlxsw_sp_sb_prs_egress
,
276 MLXSW_SP_SB_PRS_EGRESS_LEN
);
279 #define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \
281 .min_buff = _min_buff, \
282 .max_buff = _max_buff, \
286 static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress
[] = {
287 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(10000), 8, 0),
288 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
289 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
290 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
291 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
292 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
293 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
294 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
, 0),
295 MLXSW_SP_SB_CM(0, 0, 0), /* dummy, this PG does not exist */
296 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(20000), 1, 3),
299 #define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress)
301 static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress
[] = {
302 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
303 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
304 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
305 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
306 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
307 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
308 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
309 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
310 MLXSW_SP_SB_CM(0, 0, 0),
311 MLXSW_SP_SB_CM(0, 0, 0),
312 MLXSW_SP_SB_CM(0, 0, 0),
313 MLXSW_SP_SB_CM(0, 0, 0),
314 MLXSW_SP_SB_CM(0, 0, 0),
315 MLXSW_SP_SB_CM(0, 0, 0),
316 MLXSW_SP_SB_CM(0, 0, 0),
317 MLXSW_SP_SB_CM(0, 0, 0),
318 MLXSW_SP_SB_CM(1, 0xff, 0),
321 #define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress)
323 #define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 0)
325 static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms
[] = {
326 MLXSW_SP_CPU_PORT_SB_CM
,
327 MLXSW_SP_CPU_PORT_SB_CM
,
328 MLXSW_SP_CPU_PORT_SB_CM
,
329 MLXSW_SP_CPU_PORT_SB_CM
,
330 MLXSW_SP_CPU_PORT_SB_CM
,
331 MLXSW_SP_CPU_PORT_SB_CM
,
332 MLXSW_SP_CPU_PORT_SB_CM
,
333 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(10000), 0, 0),
334 MLXSW_SP_CPU_PORT_SB_CM
,
335 MLXSW_SP_CPU_PORT_SB_CM
,
336 MLXSW_SP_CPU_PORT_SB_CM
,
337 MLXSW_SP_CPU_PORT_SB_CM
,
338 MLXSW_SP_CPU_PORT_SB_CM
,
339 MLXSW_SP_CPU_PORT_SB_CM
,
340 MLXSW_SP_CPU_PORT_SB_CM
,
341 MLXSW_SP_CPU_PORT_SB_CM
,
342 MLXSW_SP_CPU_PORT_SB_CM
,
343 MLXSW_SP_CPU_PORT_SB_CM
,
344 MLXSW_SP_CPU_PORT_SB_CM
,
345 MLXSW_SP_CPU_PORT_SB_CM
,
346 MLXSW_SP_CPU_PORT_SB_CM
,
347 MLXSW_SP_CPU_PORT_SB_CM
,
348 MLXSW_SP_CPU_PORT_SB_CM
,
349 MLXSW_SP_CPU_PORT_SB_CM
,
350 MLXSW_SP_CPU_PORT_SB_CM
,
351 MLXSW_SP_CPU_PORT_SB_CM
,
352 MLXSW_SP_CPU_PORT_SB_CM
,
353 MLXSW_SP_CPU_PORT_SB_CM
,
354 MLXSW_SP_CPU_PORT_SB_CM
,
355 MLXSW_SP_CPU_PORT_SB_CM
,
356 MLXSW_SP_CPU_PORT_SB_CM
,
357 MLXSW_SP_CPU_PORT_SB_CM
,
360 #define MLXSW_SP_CPU_PORT_SB_MCS_LEN \
361 ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms)
363 static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp
*mlxsw_sp
, u8 local_port
,
364 enum mlxsw_reg_sbxx_dir dir
,
365 const struct mlxsw_sp_sb_cm
*cms
,
371 for (i
= 0; i
< cms_len
; i
++) {
372 const struct mlxsw_sp_sb_cm
*cm
;
374 if (i
== 8 && dir
== MLXSW_REG_SBXX_DIR_INGRESS
)
375 continue; /* PG number 8 does not exist, skip it */
377 err
= mlxsw_sp_sb_cm_write(mlxsw_sp
, local_port
, i
, dir
,
378 cm
->min_buff
, cm
->max_buff
,
386 static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
390 err
= __mlxsw_sp_sb_cms_init(mlxsw_sp_port
->mlxsw_sp
,
391 mlxsw_sp_port
->local_port
,
392 MLXSW_REG_SBXX_DIR_INGRESS
,
393 mlxsw_sp_sb_cms_ingress
,
394 MLXSW_SP_SB_CMS_INGRESS_LEN
);
397 return __mlxsw_sp_sb_cms_init(mlxsw_sp_port
->mlxsw_sp
,
398 mlxsw_sp_port
->local_port
,
399 MLXSW_REG_SBXX_DIR_EGRESS
,
400 mlxsw_sp_sb_cms_egress
,
401 MLXSW_SP_SB_CMS_EGRESS_LEN
);
404 static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp
*mlxsw_sp
)
406 return __mlxsw_sp_sb_cms_init(mlxsw_sp
, 0, MLXSW_REG_SBXX_DIR_EGRESS
,
407 mlxsw_sp_cpu_port_sb_cms
,
408 MLXSW_SP_CPU_PORT_SB_MCS_LEN
);
411 #define MLXSW_SP_SB_PM(_min_buff, _max_buff) \
413 .min_buff = _min_buff, \
414 .max_buff = _max_buff, \
417 static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_ingress
[] = {
418 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX
),
419 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
),
420 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
),
421 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX
),
424 #define MLXSW_SP_SB_PMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_ingress)
426 static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_egress
[] = {
427 MLXSW_SP_SB_PM(0, 7),
428 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
),
429 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
),
430 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
),
433 #define MLXSW_SP_SB_PMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_egress)
435 static int __mlxsw_sp_port_sb_pms_init(struct mlxsw_sp
*mlxsw_sp
, u8 local_port
,
436 enum mlxsw_reg_sbxx_dir dir
,
437 const struct mlxsw_sp_sb_pm
*pms
,
443 for (i
= 0; i
< pms_len
; i
++) {
444 const struct mlxsw_sp_sb_pm
*pm
;
447 err
= mlxsw_sp_sb_pm_write(mlxsw_sp
, local_port
, i
, dir
,
448 pm
->min_buff
, pm
->max_buff
);
455 static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
459 err
= __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port
->mlxsw_sp
,
460 mlxsw_sp_port
->local_port
,
461 MLXSW_REG_SBXX_DIR_INGRESS
,
462 mlxsw_sp_sb_pms_ingress
,
463 MLXSW_SP_SB_PMS_INGRESS_LEN
);
466 return __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port
->mlxsw_sp
,
467 mlxsw_sp_port
->local_port
,
468 MLXSW_REG_SBXX_DIR_EGRESS
,
469 mlxsw_sp_sb_pms_egress
,
470 MLXSW_SP_SB_PMS_EGRESS_LEN
);
473 struct mlxsw_sp_sb_mm
{
479 #define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool) \
481 .min_buff = _min_buff, \
482 .max_buff = _max_buff, \
486 static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms
[] = {
487 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
488 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
489 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
490 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
491 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
492 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
493 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
494 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
495 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
496 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
497 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
498 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
499 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
500 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
501 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
504 #define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms)
506 static int mlxsw_sp_sb_mms_init(struct mlxsw_sp
*mlxsw_sp
)
508 char sbmm_pl
[MLXSW_REG_SBMM_LEN
];
512 for (i
= 0; i
< MLXSW_SP_SB_MMS_LEN
; i
++) {
513 const struct mlxsw_sp_sb_mm
*mc
;
515 mc
= &mlxsw_sp_sb_mms
[i
];
516 mlxsw_reg_sbmm_pack(sbmm_pl
, i
, mc
->min_buff
,
517 mc
->max_buff
, mc
->pool
);
518 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sbmm
), sbmm_pl
);
525 #define MLXSW_SP_SB_SIZE (16 * 1024 * 1024)
527 int mlxsw_sp_buffers_init(struct mlxsw_sp
*mlxsw_sp
)
531 err
= mlxsw_sp_sb_prs_init(mlxsw_sp
);
534 err
= mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp
);
537 err
= mlxsw_sp_sb_mms_init(mlxsw_sp
);
540 return devlink_sb_register(priv_to_devlink(mlxsw_sp
->core
), 0,
542 MLXSW_SP_SB_POOL_COUNT
,
543 MLXSW_SP_SB_POOL_COUNT
,
544 MLXSW_SP_SB_TC_COUNT
,
545 MLXSW_SP_SB_TC_COUNT
);
548 void mlxsw_sp_buffers_fini(struct mlxsw_sp
*mlxsw_sp
)
550 devlink_sb_unregister(priv_to_devlink(mlxsw_sp
->core
), 0);
553 int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
557 err
= mlxsw_sp_port_headroom_init(mlxsw_sp_port
);
560 err
= mlxsw_sp_port_sb_cms_init(mlxsw_sp_port
);
563 err
= mlxsw_sp_port_sb_pms_init(mlxsw_sp_port
);
568 static u8
pool_get(u16 pool_index
)
570 return pool_index
% MLXSW_SP_SB_POOL_COUNT
;
573 static u16
pool_index_get(u8 pool
, enum mlxsw_reg_sbxx_dir dir
)
578 if (dir
== MLXSW_REG_SBXX_DIR_EGRESS
)
579 pool_index
+= MLXSW_SP_SB_POOL_COUNT
;
583 static enum mlxsw_reg_sbxx_dir
dir_get(u16 pool_index
)
585 return pool_index
< MLXSW_SP_SB_POOL_COUNT
?
586 MLXSW_REG_SBXX_DIR_INGRESS
: MLXSW_REG_SBXX_DIR_EGRESS
;
589 int mlxsw_sp_sb_pool_get(struct mlxsw_core
*mlxsw_core
,
590 unsigned int sb_index
, u16 pool_index
,
591 struct devlink_sb_pool_info
*pool_info
)
593 struct mlxsw_sp
*mlxsw_sp
= mlxsw_core_driver_priv(mlxsw_core
);
594 u8 pool
= pool_get(pool_index
);
595 enum mlxsw_reg_sbxx_dir dir
= dir_get(pool_index
);
596 struct mlxsw_sp_sb_pr
*pr
= mlxsw_sp_sb_pr_get(mlxsw_sp
, pool
, dir
);
598 pool_info
->pool_type
= (enum devlink_sb_pool_type
) dir
;
599 pool_info
->size
= MLXSW_SP_CELLS_TO_BYTES(pr
->size
);
600 pool_info
->threshold_type
= (enum devlink_sb_threshold_type
) pr
->mode
;
604 int mlxsw_sp_sb_pool_set(struct mlxsw_core
*mlxsw_core
,
605 unsigned int sb_index
, u16 pool_index
, u32 size
,
606 enum devlink_sb_threshold_type threshold_type
)
608 struct mlxsw_sp
*mlxsw_sp
= mlxsw_core_driver_priv(mlxsw_core
);
609 u8 pool
= pool_get(pool_index
);
610 enum mlxsw_reg_sbxx_dir dir
= dir_get(pool_index
);
611 u32 pool_size
= MLXSW_SP_BYTES_TO_CELLS(size
);
612 enum mlxsw_reg_sbpr_mode mode
;
614 if (size
> MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_BUFFER_SIZE
))
617 mode
= (enum mlxsw_reg_sbpr_mode
) threshold_type
;
618 return mlxsw_sp_sb_pr_write(mlxsw_sp
, pool
, dir
, mode
, pool_size
);
621 #define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */
623 static u32
mlxsw_sp_sb_threshold_out(struct mlxsw_sp
*mlxsw_sp
, u8 pool
,
624 enum mlxsw_reg_sbxx_dir dir
, u32 max_buff
)
626 struct mlxsw_sp_sb_pr
*pr
= mlxsw_sp_sb_pr_get(mlxsw_sp
, pool
, dir
);
628 if (pr
->mode
== MLXSW_REG_SBPR_MODE_DYNAMIC
)
629 return max_buff
- MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET
;
630 return MLXSW_SP_CELLS_TO_BYTES(max_buff
);
633 static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp
*mlxsw_sp
, u8 pool
,
634 enum mlxsw_reg_sbxx_dir dir
, u32 threshold
,
637 struct mlxsw_sp_sb_pr
*pr
= mlxsw_sp_sb_pr_get(mlxsw_sp
, pool
, dir
);
639 if (pr
->mode
== MLXSW_REG_SBPR_MODE_DYNAMIC
) {
642 val
= threshold
+ MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET
;
643 if (val
< MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN
||
644 val
> MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX
)
648 *p_max_buff
= MLXSW_SP_BYTES_TO_CELLS(threshold
);
653 int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port
*mlxsw_core_port
,
654 unsigned int sb_index
, u16 pool_index
,
657 struct mlxsw_sp_port
*mlxsw_sp_port
=
658 mlxsw_core_port_driver_priv(mlxsw_core_port
);
659 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
660 u8 local_port
= mlxsw_sp_port
->local_port
;
661 u8 pool
= pool_get(pool_index
);
662 enum mlxsw_reg_sbxx_dir dir
= dir_get(pool_index
);
663 struct mlxsw_sp_sb_pm
*pm
= mlxsw_sp_sb_pm_get(mlxsw_sp
, local_port
,
666 *p_threshold
= mlxsw_sp_sb_threshold_out(mlxsw_sp
, pool
, dir
,
671 int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port
*mlxsw_core_port
,
672 unsigned int sb_index
, u16 pool_index
,
675 struct mlxsw_sp_port
*mlxsw_sp_port
=
676 mlxsw_core_port_driver_priv(mlxsw_core_port
);
677 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
678 u8 local_port
= mlxsw_sp_port
->local_port
;
679 u8 pool
= pool_get(pool_index
);
680 enum mlxsw_reg_sbxx_dir dir
= dir_get(pool_index
);
684 err
= mlxsw_sp_sb_threshold_in(mlxsw_sp
, pool
, dir
,
685 threshold
, &max_buff
);
689 return mlxsw_sp_sb_pm_write(mlxsw_sp
, local_port
, pool
, dir
,
693 int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port
*mlxsw_core_port
,
694 unsigned int sb_index
, u16 tc_index
,
695 enum devlink_sb_pool_type pool_type
,
696 u16
*p_pool_index
, u32
*p_threshold
)
698 struct mlxsw_sp_port
*mlxsw_sp_port
=
699 mlxsw_core_port_driver_priv(mlxsw_core_port
);
700 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
701 u8 local_port
= mlxsw_sp_port
->local_port
;
702 u8 pg_buff
= tc_index
;
703 enum mlxsw_reg_sbxx_dir dir
= (enum mlxsw_reg_sbxx_dir
) pool_type
;
704 struct mlxsw_sp_sb_cm
*cm
= mlxsw_sp_sb_cm_get(mlxsw_sp
, local_port
,
707 *p_threshold
= mlxsw_sp_sb_threshold_out(mlxsw_sp
, cm
->pool
, dir
,
709 *p_pool_index
= pool_index_get(cm
->pool
, dir
);
713 int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port
*mlxsw_core_port
,
714 unsigned int sb_index
, u16 tc_index
,
715 enum devlink_sb_pool_type pool_type
,
716 u16 pool_index
, u32 threshold
)
718 struct mlxsw_sp_port
*mlxsw_sp_port
=
719 mlxsw_core_port_driver_priv(mlxsw_core_port
);
720 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
721 u8 local_port
= mlxsw_sp_port
->local_port
;
722 u8 pg_buff
= tc_index
;
723 enum mlxsw_reg_sbxx_dir dir
= (enum mlxsw_reg_sbxx_dir
) pool_type
;
724 u8 pool
= pool_get(pool_index
);
728 if (dir
!= dir_get(pool_index
))
731 err
= mlxsw_sp_sb_threshold_in(mlxsw_sp
, pool
, dir
,
732 threshold
, &max_buff
);
736 return mlxsw_sp_sb_cm_write(mlxsw_sp
, local_port
, pg_buff
, dir
,
740 #define MASKED_COUNT_MAX \
741 (MLXSW_REG_SBSR_REC_MAX_COUNT / (MLXSW_SP_SB_TC_COUNT * 2))
743 struct mlxsw_sp_sb_sr_occ_query_cb_ctx
{
748 static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core
*mlxsw_core
,
749 char *sbsr_pl
, size_t sbsr_pl_len
,
750 unsigned long cb_priv
)
752 struct mlxsw_sp
*mlxsw_sp
= mlxsw_core_driver_priv(mlxsw_core
);
753 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx
;
757 struct mlxsw_sp_sb_cm
*cm
;
760 memcpy(&cb_ctx
, &cb_priv
, sizeof(cb_ctx
));
763 for (local_port
= cb_ctx
.local_port_1
;
764 local_port
< MLXSW_PORT_MAX_PORTS
; local_port
++) {
765 if (!mlxsw_sp
->ports
[local_port
])
767 for (i
= 0; i
< MLXSW_SP_SB_TC_COUNT
; i
++) {
768 cm
= mlxsw_sp_sb_cm_get(mlxsw_sp
, local_port
, i
,
769 MLXSW_REG_SBXX_DIR_INGRESS
);
770 mlxsw_reg_sbsr_rec_unpack(sbsr_pl
, rec_index
++,
771 &cm
->occ
.cur
, &cm
->occ
.max
);
773 if (++masked_count
== cb_ctx
.masked_count
)
777 for (local_port
= cb_ctx
.local_port_1
;
778 local_port
< MLXSW_PORT_MAX_PORTS
; local_port
++) {
779 if (!mlxsw_sp
->ports
[local_port
])
781 for (i
= 0; i
< MLXSW_SP_SB_TC_COUNT
; i
++) {
782 cm
= mlxsw_sp_sb_cm_get(mlxsw_sp
, local_port
, i
,
783 MLXSW_REG_SBXX_DIR_EGRESS
);
784 mlxsw_reg_sbsr_rec_unpack(sbsr_pl
, rec_index
++,
785 &cm
->occ
.cur
, &cm
->occ
.max
);
787 if (++masked_count
== cb_ctx
.masked_count
)
792 int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core
*mlxsw_core
,
793 unsigned int sb_index
)
795 struct mlxsw_sp
*mlxsw_sp
= mlxsw_core_driver_priv(mlxsw_core
);
796 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx
;
797 unsigned long cb_priv
;
798 LIST_HEAD(bulk_list
);
807 sbsr_pl
= kmalloc(MLXSW_REG_SBSR_LEN
, GFP_KERNEL
);
813 local_port_1
= local_port
;
815 mlxsw_reg_sbsr_pack(sbsr_pl
, false);
816 for (i
= 0; i
< MLXSW_SP_SB_TC_COUNT
; i
++) {
817 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl
, i
, 1);
818 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl
, i
, 1);
820 for (; local_port
< MLXSW_PORT_MAX_PORTS
; local_port
++) {
821 if (!mlxsw_sp
->ports
[local_port
])
823 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl
, local_port
, 1);
824 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl
, local_port
, 1);
825 for (i
= 0; i
< MLXSW_SP_SB_POOL_COUNT
; i
++) {
826 err
= mlxsw_sp_sb_pm_occ_query(mlxsw_sp
, local_port
, i
,
827 MLXSW_REG_SBXX_DIR_INGRESS
,
831 err
= mlxsw_sp_sb_pm_occ_query(mlxsw_sp
, local_port
, i
,
832 MLXSW_REG_SBXX_DIR_EGRESS
,
837 if (++masked_count
== MASKED_COUNT_MAX
)
842 cb_ctx
.masked_count
= masked_count
;
843 cb_ctx
.local_port_1
= local_port_1
;
844 memcpy(&cb_priv
, &cb_ctx
, sizeof(cb_ctx
));
845 err
= mlxsw_reg_trans_query(mlxsw_core
, MLXSW_REG(sbsr
), sbsr_pl
,
846 &bulk_list
, mlxsw_sp_sb_sr_occ_query_cb
,
850 if (local_port
< MLXSW_PORT_MAX_PORTS
)
854 err2
= mlxsw_reg_trans_bulk_wait(&bulk_list
);
861 int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core
*mlxsw_core
,
862 unsigned int sb_index
)
864 struct mlxsw_sp
*mlxsw_sp
= mlxsw_core_driver_priv(mlxsw_core
);
865 LIST_HEAD(bulk_list
);
867 unsigned int masked_count
;
873 sbsr_pl
= kmalloc(MLXSW_REG_SBSR_LEN
, GFP_KERNEL
);
880 mlxsw_reg_sbsr_pack(sbsr_pl
, true);
881 for (i
= 0; i
< MLXSW_SP_SB_TC_COUNT
; i
++) {
882 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl
, i
, 1);
883 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl
, i
, 1);
885 for (; local_port
< MLXSW_PORT_MAX_PORTS
; local_port
++) {
886 if (!mlxsw_sp
->ports
[local_port
])
888 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl
, local_port
, 1);
889 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl
, local_port
, 1);
890 for (i
= 0; i
< MLXSW_SP_SB_POOL_COUNT
; i
++) {
891 err
= mlxsw_sp_sb_pm_occ_clear(mlxsw_sp
, local_port
, i
,
892 MLXSW_REG_SBXX_DIR_INGRESS
,
896 err
= mlxsw_sp_sb_pm_occ_clear(mlxsw_sp
, local_port
, i
,
897 MLXSW_REG_SBXX_DIR_EGRESS
,
902 if (++masked_count
== MASKED_COUNT_MAX
)
907 err
= mlxsw_reg_trans_query(mlxsw_core
, MLXSW_REG(sbsr
), sbsr_pl
,
908 &bulk_list
, NULL
, 0);
911 if (local_port
< MLXSW_PORT_MAX_PORTS
)
915 err2
= mlxsw_reg_trans_bulk_wait(&bulk_list
);
922 int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port
*mlxsw_core_port
,
923 unsigned int sb_index
, u16 pool_index
,
924 u32
*p_cur
, u32
*p_max
)
926 struct mlxsw_sp_port
*mlxsw_sp_port
=
927 mlxsw_core_port_driver_priv(mlxsw_core_port
);
928 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
929 u8 local_port
= mlxsw_sp_port
->local_port
;
930 u8 pool
= pool_get(pool_index
);
931 enum mlxsw_reg_sbxx_dir dir
= dir_get(pool_index
);
932 struct mlxsw_sp_sb_pm
*pm
= mlxsw_sp_sb_pm_get(mlxsw_sp
, local_port
,
935 *p_cur
= MLXSW_SP_CELLS_TO_BYTES(pm
->occ
.cur
);
936 *p_max
= MLXSW_SP_CELLS_TO_BYTES(pm
->occ
.max
);
940 int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port
*mlxsw_core_port
,
941 unsigned int sb_index
, u16 tc_index
,
942 enum devlink_sb_pool_type pool_type
,
943 u32
*p_cur
, u32
*p_max
)
945 struct mlxsw_sp_port
*mlxsw_sp_port
=
946 mlxsw_core_port_driver_priv(mlxsw_core_port
);
947 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
948 u8 local_port
= mlxsw_sp_port
->local_port
;
949 u8 pg_buff
= tc_index
;
950 enum mlxsw_reg_sbxx_dir dir
= (enum mlxsw_reg_sbxx_dir
) pool_type
;
951 struct mlxsw_sp_sb_cm
*cm
= mlxsw_sp_sb_cm_get(mlxsw_sp
, local_port
,
954 *p_cur
= MLXSW_SP_CELLS_TO_BYTES(cm
->occ
.cur
);
955 *p_max
= MLXSW_SP_CELLS_TO_BYTES(cm
->occ
.max
);