1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/types.h> 6 #include <linux/dcbnl.h> 7 #include <linux/if_ether.h> 8 #include <linux/list.h> 9 10 #include "spectrum.h" 11 #include "core.h" 12 #include "port.h" 13 #include "reg.h" 14 15 struct mlxsw_sp_sb_pr { 16 enum mlxsw_reg_sbpr_mode mode; 17 u32 size; 18 }; 19 20 struct mlxsw_cp_sb_occ { 21 u32 cur; 22 u32 max; 23 }; 24 25 struct mlxsw_sp_sb_cm { 26 u32 min_buff; 27 u32 max_buff; 28 u8 pool; 29 struct mlxsw_cp_sb_occ occ; 30 }; 31 32 struct mlxsw_sp_sb_pm { 33 u32 min_buff; 34 u32 max_buff; 35 struct mlxsw_cp_sb_occ occ; 36 }; 37 38 #define MLXSW_SP_SB_POOL_COUNT 4 39 #define MLXSW_SP_SB_TC_COUNT 8 40 41 struct mlxsw_sp_sb_port { 42 struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; 43 struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; 44 }; 45 46 struct mlxsw_sp_sb { 47 struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; 48 struct mlxsw_sp_sb_port *ports; 49 u32 cell_size; 50 }; 51 52 u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells) 53 { 54 return mlxsw_sp->sb->cell_size * cells; 55 } 56 57 u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes) 58 { 59 return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size); 60 } 61 62 static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, 63 u8 pool, 64 enum mlxsw_reg_sbxx_dir dir) 65 { 66 return &mlxsw_sp->sb->prs[dir][pool]; 67 } 68 69 static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, 70 u8 local_port, u8 pg_buff, 71 enum mlxsw_reg_sbxx_dir dir) 72 { 73 return &mlxsw_sp->sb->ports[local_port].cms[dir][pg_buff]; 74 } 75 76 static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, 77 u8 local_port, u8 pool, 78 enum mlxsw_reg_sbxx_dir dir) 79 { 80 return &mlxsw_sp->sb->ports[local_port].pms[dir][pool]; 81 } 82 83 static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool, 84 enum mlxsw_reg_sbxx_dir dir, 85 enum mlxsw_reg_sbpr_mode mode, u32 size) 86 { 87 char sbpr_pl[MLXSW_REG_SBPR_LEN]; 88 struct mlxsw_sp_sb_pr *pr; 89 int err; 90 91 mlxsw_reg_sbpr_pack(sbpr_pl, pool, dir, mode, size); 92 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl); 93 if (err) 94 return err; 95 96 pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); 97 pr->mode = mode; 98 pr->size = size; 99 return 0; 100 } 101 102 static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, 103 u8 pg_buff, enum mlxsw_reg_sbxx_dir dir, 104 u32 min_buff, u32 max_buff, u8 pool) 105 { 106 char sbcm_pl[MLXSW_REG_SBCM_LEN]; 107 int err; 108 109 mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, dir, 110 min_buff, max_buff, pool); 111 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl); 112 if (err) 113 return err; 114 if (pg_buff < MLXSW_SP_SB_TC_COUNT) { 115 struct mlxsw_sp_sb_cm *cm; 116 117 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, dir); 118 cm->min_buff = min_buff; 119 cm->max_buff = max_buff; 120 cm->pool = pool; 121 } 122 return 0; 123 } 124 125 static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, 126 u8 pool, enum mlxsw_reg_sbxx_dir dir, 127 u32 min_buff, u32 max_buff) 128 { 129 char sbpm_pl[MLXSW_REG_SBPM_LEN]; 130 struct mlxsw_sp_sb_pm *pm; 131 int err; 132 133 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, 134 min_buff, max_buff); 135 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl); 136 if (err) 137 return err; 138 139 pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir); 140 pm->min_buff = min_buff; 141 pm->max_buff = max_buff; 142 return 0; 143 } 144 145 static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port, 146 u8 pool, enum mlxsw_reg_sbxx_dir dir, 147 struct list_head *bulk_list) 148 { 149 char sbpm_pl[MLXSW_REG_SBPM_LEN]; 150 151 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, true, 0, 0); 152 return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, 153 bulk_list, NULL, 0); 154 } 155 156 static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core, 157 char *sbpm_pl, size_t sbpm_pl_len, 158 unsigned long cb_priv) 159 { 160 struct mlxsw_sp_sb_pm *pm = (struct mlxsw_sp_sb_pm *) cb_priv; 161 162 mlxsw_reg_sbpm_unpack(sbpm_pl, &pm->occ.cur, &pm->occ.max); 163 } 164 165 static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port, 166 u8 pool, enum mlxsw_reg_sbxx_dir dir, 167 struct list_head *bulk_list) 168 { 169 char sbpm_pl[MLXSW_REG_SBPM_LEN]; 170 struct mlxsw_sp_sb_pm *pm; 171 172 pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir); 173 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, 0, 0); 174 return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, 175 bulk_list, 176 mlxsw_sp_sb_pm_occ_query_cb, 177 (unsigned long) pm); 178 } 179 180 static const u16 mlxsw_sp_pbs[] = { 181 [0] = 2 * ETH_FRAME_LEN, 182 [9] = 2 * MLXSW_PORT_MAX_MTU, 183 }; 184 185 #define MLXSW_SP_PBS_LEN ARRAY_SIZE(mlxsw_sp_pbs) 186 #define MLXSW_SP_PB_UNUSED 8 187 188 static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port *mlxsw_sp_port) 189 { 190 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 191 char pbmc_pl[MLXSW_REG_PBMC_LEN]; 192 int i; 193 194 mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, 195 0xffff, 0xffff / 2); 196 for (i = 0; i < MLXSW_SP_PBS_LEN; i++) { 197 u16 size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp_pbs[i]); 198 199 if (i == MLXSW_SP_PB_UNUSED) 200 continue; 201 mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, i, size); 202 } 203 mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, 204 MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0); 205 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl); 206 } 207 208 static int mlxsw_sp_port_pb_prio_init(struct mlxsw_sp_port *mlxsw_sp_port) 209 { 210 char pptb_pl[MLXSW_REG_PPTB_LEN]; 211 int i; 212 213 mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port); 214 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 215 mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, i, 0); 216 return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), 217 pptb_pl); 218 } 219 220 static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port) 221 { 222 int err; 223 224 err = mlxsw_sp_port_pb_init(mlxsw_sp_port); 225 if (err) 226 return err; 227 return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port); 228 } 229 230 static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp) 231 { 232 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 233 234 mlxsw_sp->sb->ports = kcalloc(max_ports, 235 sizeof(struct mlxsw_sp_sb_port), 236 GFP_KERNEL); 237 if (!mlxsw_sp->sb->ports) 238 return -ENOMEM; 239 return 0; 240 } 241 242 static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) 243 { 244 kfree(mlxsw_sp->sb->ports); 245 } 246 247 #define MLXSW_SP_SB_PR_INGRESS_SIZE 12440000 248 #define MLXSW_SP_SB_PR_INGRESS_MNG_SIZE (200 * 1000) 249 #define MLXSW_SP_SB_PR_EGRESS_SIZE 13232000 250 251 #define MLXSW_SP_SB_PR(_mode, _size) \ 252 { \ 253 .mode = _mode, \ 254 .size = _size, \ 255 } 256 257 static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_ingress[] = { 258 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 259 MLXSW_SP_SB_PR_INGRESS_SIZE), 260 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 261 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 262 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 263 MLXSW_SP_SB_PR_INGRESS_MNG_SIZE), 264 }; 265 266 #define MLXSW_SP_SB_PRS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_ingress) 267 268 static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_egress[] = { 269 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_EGRESS_SIZE), 270 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 271 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 272 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), 273 }; 274 275 #define MLXSW_SP_SB_PRS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_egress) 276 277 static int __mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, 278 enum mlxsw_reg_sbxx_dir dir, 279 const struct mlxsw_sp_sb_pr *prs, 280 size_t prs_len) 281 { 282 int i; 283 int err; 284 285 for (i = 0; i < prs_len; i++) { 286 u32 size = mlxsw_sp_bytes_cells(mlxsw_sp, prs[i].size); 287 288 err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, dir, prs[i].mode, size); 289 if (err) 290 return err; 291 } 292 return 0; 293 } 294 295 static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp) 296 { 297 int err; 298 299 err = __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_INGRESS, 300 mlxsw_sp_sb_prs_ingress, 301 MLXSW_SP_SB_PRS_INGRESS_LEN); 302 if (err) 303 return err; 304 return __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_EGRESS, 305 mlxsw_sp_sb_prs_egress, 306 MLXSW_SP_SB_PRS_EGRESS_LEN); 307 } 308 309 #define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \ 310 { \ 311 .min_buff = _min_buff, \ 312 .max_buff = _max_buff, \ 313 .pool = _pool, \ 314 } 315 316 static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = { 317 MLXSW_SP_SB_CM(10000, 8, 0), 318 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 319 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 320 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 321 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 322 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 323 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 324 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0), 325 MLXSW_SP_SB_CM(0, 0, 0), /* dummy, this PG does not exist */ 326 MLXSW_SP_SB_CM(20000, 1, 3), 327 }; 328 329 #define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress) 330 331 static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = { 332 MLXSW_SP_SB_CM(1500, 9, 0), 333 MLXSW_SP_SB_CM(1500, 9, 0), 334 MLXSW_SP_SB_CM(1500, 9, 0), 335 MLXSW_SP_SB_CM(1500, 9, 0), 336 MLXSW_SP_SB_CM(1500, 9, 0), 337 MLXSW_SP_SB_CM(1500, 9, 0), 338 MLXSW_SP_SB_CM(1500, 9, 0), 339 MLXSW_SP_SB_CM(1500, 9, 0), 340 MLXSW_SP_SB_CM(0, 0, 0), 341 MLXSW_SP_SB_CM(0, 0, 0), 342 MLXSW_SP_SB_CM(0, 0, 0), 343 MLXSW_SP_SB_CM(0, 0, 0), 344 MLXSW_SP_SB_CM(0, 0, 0), 345 MLXSW_SP_SB_CM(0, 0, 0), 346 MLXSW_SP_SB_CM(0, 0, 0), 347 MLXSW_SP_SB_CM(0, 0, 0), 348 MLXSW_SP_SB_CM(1, 0xff, 0), 349 }; 350 351 #define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress) 352 353 #define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 0) 354 355 static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = { 356 MLXSW_SP_CPU_PORT_SB_CM, 357 MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), 358 MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), 359 MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), 360 MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), 361 MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), 362 MLXSW_SP_CPU_PORT_SB_CM, 363 MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), 364 MLXSW_SP_CPU_PORT_SB_CM, 365 MLXSW_SP_CPU_PORT_SB_CM, 366 MLXSW_SP_CPU_PORT_SB_CM, 367 MLXSW_SP_CPU_PORT_SB_CM, 368 MLXSW_SP_CPU_PORT_SB_CM, 369 MLXSW_SP_CPU_PORT_SB_CM, 370 MLXSW_SP_CPU_PORT_SB_CM, 371 MLXSW_SP_CPU_PORT_SB_CM, 372 MLXSW_SP_CPU_PORT_SB_CM, 373 MLXSW_SP_CPU_PORT_SB_CM, 374 MLXSW_SP_CPU_PORT_SB_CM, 375 MLXSW_SP_CPU_PORT_SB_CM, 376 MLXSW_SP_CPU_PORT_SB_CM, 377 MLXSW_SP_CPU_PORT_SB_CM, 378 MLXSW_SP_CPU_PORT_SB_CM, 379 MLXSW_SP_CPU_PORT_SB_CM, 380 MLXSW_SP_CPU_PORT_SB_CM, 381 MLXSW_SP_CPU_PORT_SB_CM, 382 MLXSW_SP_CPU_PORT_SB_CM, 383 MLXSW_SP_CPU_PORT_SB_CM, 384 MLXSW_SP_CPU_PORT_SB_CM, 385 MLXSW_SP_CPU_PORT_SB_CM, 386 MLXSW_SP_CPU_PORT_SB_CM, 387 MLXSW_SP_CPU_PORT_SB_CM, 388 }; 389 390 #define MLXSW_SP_CPU_PORT_SB_MCS_LEN \ 391 ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms) 392 393 static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, 394 enum mlxsw_reg_sbxx_dir dir, 395 const struct mlxsw_sp_sb_cm *cms, 396 size_t cms_len) 397 { 398 int i; 399 int err; 400 401 for (i = 0; i < cms_len; i++) { 402 const struct mlxsw_sp_sb_cm *cm; 403 u32 min_buff; 404 405 if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS) 406 continue; /* PG number 8 does not exist, skip it */ 407 cm = &cms[i]; 408 /* All pools are initialized using dynamic thresholds, 409 * therefore 'max_buff' isn't specified in cells. 410 */ 411 min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff); 412 err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, dir, 413 min_buff, cm->max_buff, cm->pool); 414 if (err) 415 return err; 416 } 417 return 0; 418 } 419 420 static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port) 421 { 422 int err; 423 424 err = __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp, 425 mlxsw_sp_port->local_port, 426 MLXSW_REG_SBXX_DIR_INGRESS, 427 mlxsw_sp_sb_cms_ingress, 428 MLXSW_SP_SB_CMS_INGRESS_LEN); 429 if (err) 430 return err; 431 return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp, 432 mlxsw_sp_port->local_port, 433 MLXSW_REG_SBXX_DIR_EGRESS, 434 mlxsw_sp_sb_cms_egress, 435 MLXSW_SP_SB_CMS_EGRESS_LEN); 436 } 437 438 static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp) 439 { 440 return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS, 441 mlxsw_sp_cpu_port_sb_cms, 442 MLXSW_SP_CPU_PORT_SB_MCS_LEN); 443 } 444 445 #define MLXSW_SP_SB_PM(_min_buff, _max_buff) \ 446 { \ 447 .min_buff = _min_buff, \ 448 .max_buff = _max_buff, \ 449 } 450 451 static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_ingress[] = { 452 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), 453 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 454 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 455 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), 456 }; 457 458 #define MLXSW_SP_SB_PMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_ingress) 459 460 static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_egress[] = { 461 MLXSW_SP_SB_PM(0, 7), 462 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 463 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 464 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), 465 }; 466 467 #define MLXSW_SP_SB_PMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_egress) 468 469 static int __mlxsw_sp_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, 470 enum mlxsw_reg_sbxx_dir dir, 471 const struct mlxsw_sp_sb_pm *pms, 472 size_t pms_len) 473 { 474 int i; 475 int err; 476 477 for (i = 0; i < pms_len; i++) { 478 const struct mlxsw_sp_sb_pm *pm; 479 480 pm = &pms[i]; 481 err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, dir, 482 pm->min_buff, pm->max_buff); 483 if (err) 484 return err; 485 } 486 return 0; 487 } 488 489 static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) 490 { 491 int err; 492 493 err = __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp, 494 mlxsw_sp_port->local_port, 495 MLXSW_REG_SBXX_DIR_INGRESS, 496 mlxsw_sp_sb_pms_ingress, 497 MLXSW_SP_SB_PMS_INGRESS_LEN); 498 if (err) 499 return err; 500 return __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp, 501 mlxsw_sp_port->local_port, 502 MLXSW_REG_SBXX_DIR_EGRESS, 503 mlxsw_sp_sb_pms_egress, 504 MLXSW_SP_SB_PMS_EGRESS_LEN); 505 } 506 507 struct mlxsw_sp_sb_mm { 508 u32 min_buff; 509 u32 max_buff; 510 u8 pool; 511 }; 512 513 #define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool) \ 514 { \ 515 .min_buff = _min_buff, \ 516 .max_buff = _max_buff, \ 517 .pool = _pool, \ 518 } 519 520 static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = { 521 MLXSW_SP_SB_MM(20000, 0xff, 0), 522 MLXSW_SP_SB_MM(20000, 0xff, 0), 523 MLXSW_SP_SB_MM(20000, 0xff, 0), 524 MLXSW_SP_SB_MM(20000, 0xff, 0), 525 MLXSW_SP_SB_MM(20000, 0xff, 0), 526 MLXSW_SP_SB_MM(20000, 0xff, 0), 527 MLXSW_SP_SB_MM(20000, 0xff, 0), 528 MLXSW_SP_SB_MM(20000, 0xff, 0), 529 MLXSW_SP_SB_MM(20000, 0xff, 0), 530 MLXSW_SP_SB_MM(20000, 0xff, 0), 531 MLXSW_SP_SB_MM(20000, 0xff, 0), 532 MLXSW_SP_SB_MM(20000, 0xff, 0), 533 MLXSW_SP_SB_MM(20000, 0xff, 0), 534 MLXSW_SP_SB_MM(20000, 0xff, 0), 535 MLXSW_SP_SB_MM(20000, 0xff, 0), 536 }; 537 538 #define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms) 539 540 static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp) 541 { 542 char sbmm_pl[MLXSW_REG_SBMM_LEN]; 543 int i; 544 int err; 545 546 for (i = 0; i < MLXSW_SP_SB_MMS_LEN; i++) { 547 const struct mlxsw_sp_sb_mm *mc; 548 u32 min_buff; 549 550 mc = &mlxsw_sp_sb_mms[i]; 551 /* All pools are initialized using dynamic thresholds, 552 * therefore 'max_buff' isn't specified in cells. 553 */ 554 min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff); 555 mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff, 556 mc->pool); 557 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl); 558 if (err) 559 return err; 560 } 561 return 0; 562 } 563 564 int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) 565 { 566 u64 sb_size; 567 int err; 568 569 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) 570 return -EIO; 571 572 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) 573 return -EIO; 574 sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE); 575 576 mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL); 577 if (!mlxsw_sp->sb) 578 return -ENOMEM; 579 mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); 580 581 err = mlxsw_sp_sb_ports_init(mlxsw_sp); 582 if (err) 583 goto err_sb_ports_init; 584 err = mlxsw_sp_sb_prs_init(mlxsw_sp); 585 if (err) 586 goto err_sb_prs_init; 587 err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp); 588 if (err) 589 goto err_sb_cpu_port_sb_cms_init; 590 err = mlxsw_sp_sb_mms_init(mlxsw_sp); 591 if (err) 592 goto err_sb_mms_init; 593 err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, sb_size, 594 MLXSW_SP_SB_POOL_COUNT, 595 MLXSW_SP_SB_POOL_COUNT, 596 MLXSW_SP_SB_TC_COUNT, 597 MLXSW_SP_SB_TC_COUNT); 598 if (err) 599 goto err_devlink_sb_register; 600 601 return 0; 602 603 err_devlink_sb_register: 604 err_sb_mms_init: 605 err_sb_cpu_port_sb_cms_init: 606 err_sb_prs_init: 607 mlxsw_sp_sb_ports_fini(mlxsw_sp); 608 err_sb_ports_init: 609 kfree(mlxsw_sp->sb); 610 return err; 611 } 612 613 void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp) 614 { 615 devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0); 616 mlxsw_sp_sb_ports_fini(mlxsw_sp); 617 kfree(mlxsw_sp->sb); 618 } 619 620 int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port) 621 { 622 int err; 623 624 err = mlxsw_sp_port_headroom_init(mlxsw_sp_port); 625 if (err) 626 return err; 627 err = mlxsw_sp_port_sb_cms_init(mlxsw_sp_port); 628 if (err) 629 return err; 630 err = mlxsw_sp_port_sb_pms_init(mlxsw_sp_port); 631 632 return err; 633 } 634 635 static u8 pool_get(u16 pool_index) 636 { 637 return pool_index % MLXSW_SP_SB_POOL_COUNT; 638 } 639 640 static u16 pool_index_get(u8 pool, enum mlxsw_reg_sbxx_dir dir) 641 { 642 u16 pool_index; 643 644 pool_index = pool; 645 if (dir == MLXSW_REG_SBXX_DIR_EGRESS) 646 pool_index += MLXSW_SP_SB_POOL_COUNT; 647 return pool_index; 648 } 649 650 static enum mlxsw_reg_sbxx_dir dir_get(u16 pool_index) 651 { 652 return pool_index < MLXSW_SP_SB_POOL_COUNT ? 653 MLXSW_REG_SBXX_DIR_INGRESS : MLXSW_REG_SBXX_DIR_EGRESS; 654 } 655 656 int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core, 657 unsigned int sb_index, u16 pool_index, 658 struct devlink_sb_pool_info *pool_info) 659 { 660 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 661 u8 pool = pool_get(pool_index); 662 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); 663 struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); 664 665 pool_info->pool_type = (enum devlink_sb_pool_type) dir; 666 pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size); 667 pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode; 668 return 0; 669 } 670 671 int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, 672 unsigned int sb_index, u16 pool_index, u32 size, 673 enum devlink_sb_threshold_type threshold_type) 674 { 675 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 676 u32 pool_size = mlxsw_sp_bytes_cells(mlxsw_sp, size); 677 u8 pool = pool_get(pool_index); 678 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); 679 enum mlxsw_reg_sbpr_mode mode; 680 681 if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) 682 return -EINVAL; 683 684 mode = (enum mlxsw_reg_sbpr_mode) threshold_type; 685 return mlxsw_sp_sb_pr_write(mlxsw_sp, pool, dir, mode, pool_size); 686 } 687 688 #define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */ 689 690 static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u8 pool, 691 enum mlxsw_reg_sbxx_dir dir, u32 max_buff) 692 { 693 struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); 694 695 if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) 696 return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; 697 return mlxsw_sp_cells_bytes(mlxsw_sp, max_buff); 698 } 699 700 static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u8 pool, 701 enum mlxsw_reg_sbxx_dir dir, u32 threshold, 702 u32 *p_max_buff) 703 { 704 struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); 705 706 if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) { 707 int val; 708 709 val = threshold + MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; 710 if (val < MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN || 711 val > MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX) 712 return -EINVAL; 713 *p_max_buff = val; 714 } else { 715 *p_max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, threshold); 716 } 717 return 0; 718 } 719 720 int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, 721 unsigned int sb_index, u16 pool_index, 722 u32 *p_threshold) 723 { 724 struct mlxsw_sp_port *mlxsw_sp_port = 725 mlxsw_core_port_driver_priv(mlxsw_core_port); 726 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 727 u8 local_port = mlxsw_sp_port->local_port; 728 u8 pool = pool_get(pool_index); 729 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); 730 struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, 731 pool, dir); 732 733 *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool, dir, 734 pm->max_buff); 735 return 0; 736 } 737 738 int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port, 739 unsigned int sb_index, u16 pool_index, 740 u32 threshold) 741 { 742 struct mlxsw_sp_port *mlxsw_sp_port = 743 mlxsw_core_port_driver_priv(mlxsw_core_port); 744 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 745 u8 local_port = mlxsw_sp_port->local_port; 746 u8 pool = pool_get(pool_index); 747 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); 748 u32 max_buff; 749 int err; 750 751 err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir, 752 threshold, &max_buff); 753 if (err) 754 return err; 755 756 return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool, dir, 757 0, max_buff); 758 } 759 760 int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port, 761 unsigned int sb_index, u16 tc_index, 762 enum devlink_sb_pool_type pool_type, 763 u16 *p_pool_index, u32 *p_threshold) 764 { 765 struct mlxsw_sp_port *mlxsw_sp_port = 766 mlxsw_core_port_driver_priv(mlxsw_core_port); 767 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 768 u8 local_port = mlxsw_sp_port->local_port; 769 u8 pg_buff = tc_index; 770 enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; 771 struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, 772 pg_buff, dir); 773 774 *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool, dir, 775 cm->max_buff); 776 *p_pool_index = pool_index_get(cm->pool, dir); 777 return 0; 778 } 779 780 int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, 781 unsigned int sb_index, u16 tc_index, 782 enum devlink_sb_pool_type pool_type, 783 u16 pool_index, u32 threshold) 784 { 785 struct mlxsw_sp_port *mlxsw_sp_port = 786 mlxsw_core_port_driver_priv(mlxsw_core_port); 787 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 788 u8 local_port = mlxsw_sp_port->local_port; 789 u8 pg_buff = tc_index; 790 enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; 791 u8 pool = pool_get(pool_index); 792 u32 max_buff; 793 int err; 794 795 if (dir != dir_get(pool_index)) 796 return -EINVAL; 797 798 err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir, 799 threshold, &max_buff); 800 if (err) 801 return err; 802 803 return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, dir, 804 0, max_buff, pool); 805 } 806 807 #define MASKED_COUNT_MAX \ 808 (MLXSW_REG_SBSR_REC_MAX_COUNT / (MLXSW_SP_SB_TC_COUNT * 2)) 809 810 struct mlxsw_sp_sb_sr_occ_query_cb_ctx { 811 u8 masked_count; 812 u8 local_port_1; 813 }; 814 815 static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core, 816 char *sbsr_pl, size_t sbsr_pl_len, 817 unsigned long cb_priv) 818 { 819 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 820 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx; 821 u8 masked_count; 822 u8 local_port; 823 int rec_index = 0; 824 struct mlxsw_sp_sb_cm *cm; 825 int i; 826 827 memcpy(&cb_ctx, &cb_priv, sizeof(cb_ctx)); 828 829 masked_count = 0; 830 for (local_port = cb_ctx.local_port_1; 831 local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 832 if (!mlxsw_sp->ports[local_port]) 833 continue; 834 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { 835 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, 836 MLXSW_REG_SBXX_DIR_INGRESS); 837 mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, 838 &cm->occ.cur, &cm->occ.max); 839 } 840 if (++masked_count == cb_ctx.masked_count) 841 break; 842 } 843 masked_count = 0; 844 for (local_port = cb_ctx.local_port_1; 845 local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 846 if (!mlxsw_sp->ports[local_port]) 847 continue; 848 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { 849 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, 850 MLXSW_REG_SBXX_DIR_EGRESS); 851 mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, 852 &cm->occ.cur, &cm->occ.max); 853 } 854 if (++masked_count == cb_ctx.masked_count) 855 break; 856 } 857 } 858 859 int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core, 860 unsigned int sb_index) 861 { 862 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 863 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx; 864 unsigned long cb_priv; 865 LIST_HEAD(bulk_list); 866 char *sbsr_pl; 867 u8 masked_count; 868 u8 local_port_1; 869 u8 local_port = 0; 870 int i; 871 int err; 872 int err2; 873 874 sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL); 875 if (!sbsr_pl) 876 return -ENOMEM; 877 878 next_batch: 879 local_port++; 880 local_port_1 = local_port; 881 masked_count = 0; 882 mlxsw_reg_sbsr_pack(sbsr_pl, false); 883 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { 884 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); 885 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); 886 } 887 for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 888 if (!mlxsw_sp->ports[local_port]) 889 continue; 890 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1); 891 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); 892 for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) { 893 err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i, 894 MLXSW_REG_SBXX_DIR_INGRESS, 895 &bulk_list); 896 if (err) 897 goto out; 898 err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i, 899 MLXSW_REG_SBXX_DIR_EGRESS, 900 &bulk_list); 901 if (err) 902 goto out; 903 } 904 if (++masked_count == MASKED_COUNT_MAX) 905 goto do_query; 906 } 907 908 do_query: 909 cb_ctx.masked_count = masked_count; 910 cb_ctx.local_port_1 = local_port_1; 911 memcpy(&cb_priv, &cb_ctx, sizeof(cb_ctx)); 912 err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl, 913 &bulk_list, mlxsw_sp_sb_sr_occ_query_cb, 914 cb_priv); 915 if (err) 916 goto out; 917 if (local_port < mlxsw_core_max_ports(mlxsw_core)) 918 goto next_batch; 919 920 out: 921 err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); 922 if (!err) 923 err = err2; 924 kfree(sbsr_pl); 925 return err; 926 } 927 928 int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core, 929 unsigned int sb_index) 930 { 931 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 932 LIST_HEAD(bulk_list); 933 char *sbsr_pl; 934 unsigned int masked_count; 935 u8 local_port = 0; 936 int i; 937 int err; 938 int err2; 939 940 sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL); 941 if (!sbsr_pl) 942 return -ENOMEM; 943 944 next_batch: 945 local_port++; 946 masked_count = 0; 947 mlxsw_reg_sbsr_pack(sbsr_pl, true); 948 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { 949 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); 950 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); 951 } 952 for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { 953 if (!mlxsw_sp->ports[local_port]) 954 continue; 955 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1); 956 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); 957 for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) { 958 err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i, 959 MLXSW_REG_SBXX_DIR_INGRESS, 960 &bulk_list); 961 if (err) 962 goto out; 963 err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i, 964 MLXSW_REG_SBXX_DIR_EGRESS, 965 &bulk_list); 966 if (err) 967 goto out; 968 } 969 if (++masked_count == MASKED_COUNT_MAX) 970 goto do_query; 971 } 972 973 do_query: 974 err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl, 975 &bulk_list, NULL, 0); 976 if (err) 977 goto out; 978 if (local_port < mlxsw_core_max_ports(mlxsw_core)) 979 goto next_batch; 980 981 out: 982 err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); 983 if (!err) 984 err = err2; 985 kfree(sbsr_pl); 986 return err; 987 } 988 989 int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, 990 unsigned int sb_index, u16 pool_index, 991 u32 *p_cur, u32 *p_max) 992 { 993 struct mlxsw_sp_port *mlxsw_sp_port = 994 mlxsw_core_port_driver_priv(mlxsw_core_port); 995 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 996 u8 local_port = mlxsw_sp_port->local_port; 997 u8 pool = pool_get(pool_index); 998 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); 999 struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, 1000 pool, dir); 1001 1002 *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.cur); 1003 *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.max); 1004 return 0; 1005 } 1006 1007 int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, 1008 unsigned int sb_index, u16 tc_index, 1009 enum devlink_sb_pool_type pool_type, 1010 u32 *p_cur, u32 *p_max) 1011 { 1012 struct mlxsw_sp_port *mlxsw_sp_port = 1013 mlxsw_core_port_driver_priv(mlxsw_core_port); 1014 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1015 u8 local_port = mlxsw_sp_port->local_port; 1016 u8 pg_buff = tc_index; 1017 enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; 1018 struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, 1019 pg_buff, dir); 1020 1021 *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.cur); 1022 *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.max); 1023 return 0; 1024 } 1025