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