917 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/* Copyright 2020-2021 NXP3 */4#include <net/devlink.h>5#include "ocelot.h"6 7/* The queue system tracks four resource consumptions:8 * Resource 0: Memory tracked per source port9 * Resource 1: Frame references tracked per source port10 * Resource 2: Memory tracked per destination port11 * Resource 3: Frame references tracked per destination port12 */13#define OCELOT_RESOURCE_SZ 25614#define OCELOT_NUM_RESOURCES 415 16#define BUF_xxxx_I (0 * OCELOT_RESOURCE_SZ)17#define REF_xxxx_I (1 * OCELOT_RESOURCE_SZ)18#define BUF_xxxx_E (2 * OCELOT_RESOURCE_SZ)19#define REF_xxxx_E (3 * OCELOT_RESOURCE_SZ)20 21/* For each resource type there are 4 types of watermarks:22 * Q_RSRV: reservation per QoS class per port23 * PRIO_SHR: sharing watermark per QoS class across all ports24 * P_RSRV: reservation per port25 * COL_SHR: sharing watermark per color (drop precedence) across all ports26 */27#define xxx_Q_RSRV_x 028#define xxx_PRIO_SHR_x 21629#define xxx_P_RSRV_x 22430#define xxx_COL_SHR_x 25431 32/* Reservation Watermarks33 * ----------------------34 *35 * For setting up the reserved areas, egress watermarks exist per port and per36 * QoS class for both ingress and egress.37 */38 39/* Amount of packet buffer40 * | per QoS class41 * | | reserved42 * | | | per egress port43 * | | | |44 * V V v v45 * BUF_Q_RSRV_E46 */47#define BUF_Q_RSRV_E(port, prio) \48 (BUF_xxxx_E + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))49 50/* Amount of packet buffer51 * | for all port's traffic classes52 * | | reserved53 * | | | per egress port54 * | | | |55 * V V v v56 * BUF_P_RSRV_E57 */58#define BUF_P_RSRV_E(port) \59 (BUF_xxxx_E + xxx_P_RSRV_x + (port))60 61/* Amount of packet buffer62 * | per QoS class63 * | | reserved64 * | | | per ingress port65 * | | | |66 * V V v v67 * BUF_Q_RSRV_I68 */69#define BUF_Q_RSRV_I(port, prio) \70 (BUF_xxxx_I + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))71 72/* Amount of packet buffer73 * | for all port's traffic classes74 * | | reserved75 * | | | per ingress port76 * | | | |77 * V V v v78 * BUF_P_RSRV_I79 */80#define BUF_P_RSRV_I(port) \81 (BUF_xxxx_I + xxx_P_RSRV_x + (port))82 83/* Amount of frame references84 * | per QoS class85 * | | reserved86 * | | | per egress port87 * | | | |88 * V V v v89 * REF_Q_RSRV_E90 */91#define REF_Q_RSRV_E(port, prio) \92 (REF_xxxx_E + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))93 94/* Amount of frame references95 * | for all port's traffic classes96 * | | reserved97 * | | | per egress port98 * | | | |99 * V V v v100 * REF_P_RSRV_E101 */102#define REF_P_RSRV_E(port) \103 (REF_xxxx_E + xxx_P_RSRV_x + (port))104 105/* Amount of frame references106 * | per QoS class107 * | | reserved108 * | | | per ingress port109 * | | | |110 * V V v v111 * REF_Q_RSRV_I112 */113#define REF_Q_RSRV_I(port, prio) \114 (REF_xxxx_I + xxx_Q_RSRV_x + OCELOT_NUM_TC * (port) + (prio))115 116/* Amount of frame references117 * | for all port's traffic classes118 * | | reserved119 * | | | per ingress port120 * | | | |121 * V V v v122 * REF_P_RSRV_I123 */124#define REF_P_RSRV_I(port) \125 (REF_xxxx_I + xxx_P_RSRV_x + (port))126 127/* Sharing Watermarks128 * ------------------129 *130 * The shared memory area is shared between all ports.131 */132 133/* Amount of buffer134 * | per QoS class135 * | | from the shared memory area136 * | | | for egress traffic137 * | | | |138 * V V v v139 * BUF_PRIO_SHR_E140 */141#define BUF_PRIO_SHR_E(prio) \142 (BUF_xxxx_E + xxx_PRIO_SHR_x + (prio))143 144/* Amount of buffer145 * | per color (drop precedence level)146 * | | from the shared memory area147 * | | | for egress traffic148 * | | | |149 * V V v v150 * BUF_COL_SHR_E151 */152#define BUF_COL_SHR_E(dp) \153 (BUF_xxxx_E + xxx_COL_SHR_x + (1 - (dp)))154 155/* Amount of buffer156 * | per QoS class157 * | | from the shared memory area158 * | | | for ingress traffic159 * | | | |160 * V V v v161 * BUF_PRIO_SHR_I162 */163#define BUF_PRIO_SHR_I(prio) \164 (BUF_xxxx_I + xxx_PRIO_SHR_x + (prio))165 166/* Amount of buffer167 * | per color (drop precedence level)168 * | | from the shared memory area169 * | | | for ingress traffic170 * | | | |171 * V V v v172 * BUF_COL_SHR_I173 */174#define BUF_COL_SHR_I(dp) \175 (BUF_xxxx_I + xxx_COL_SHR_x + (1 - (dp)))176 177/* Amount of frame references178 * | per QoS class179 * | | from the shared area180 * | | | for egress traffic181 * | | | |182 * V V v v183 * REF_PRIO_SHR_E184 */185#define REF_PRIO_SHR_E(prio) \186 (REF_xxxx_E + xxx_PRIO_SHR_x + (prio))187 188/* Amount of frame references189 * | per color (drop precedence level)190 * | | from the shared area191 * | | | for egress traffic192 * | | | |193 * V V v v194 * REF_COL_SHR_E195 */196#define REF_COL_SHR_E(dp) \197 (REF_xxxx_E + xxx_COL_SHR_x + (1 - (dp)))198 199/* Amount of frame references200 * | per QoS class201 * | | from the shared area202 * | | | for ingress traffic203 * | | | |204 * V V v v205 * REF_PRIO_SHR_I206 */207#define REF_PRIO_SHR_I(prio) \208 (REF_xxxx_I + xxx_PRIO_SHR_x + (prio))209 210/* Amount of frame references211 * | per color (drop precedence level)212 * | | from the shared area213 * | | | for ingress traffic214 * | | | |215 * V V v v216 * REF_COL_SHR_I217 */218#define REF_COL_SHR_I(dp) \219 (REF_xxxx_I + xxx_COL_SHR_x + (1 - (dp)))220 221static u32 ocelot_wm_read(struct ocelot *ocelot, int index)222{223 int wm = ocelot_read_gix(ocelot, QSYS_RES_CFG, index);224 225 return ocelot->ops->wm_dec(wm);226}227 228static void ocelot_wm_write(struct ocelot *ocelot, int index, u32 val)229{230 u32 wm = ocelot->ops->wm_enc(val);231 232 ocelot_write_gix(ocelot, wm, QSYS_RES_CFG, index);233}234 235static void ocelot_wm_status(struct ocelot *ocelot, int index, u32 *inuse,236 u32 *maxuse)237{238 int res_stat = ocelot_read_gix(ocelot, QSYS_RES_STAT, index);239 240 return ocelot->ops->wm_stat(res_stat, inuse, maxuse);241}242 243/* The hardware comes out of reset with strange defaults: the sum of all244 * reservations for frame memory is larger than the total buffer size.245 * One has to wonder how can the reservation watermarks still guarantee246 * anything under congestion.247 * Bring some sense into the hardware by changing the defaults to disable all248 * reservations and rely only on the sharing watermark for frames with drop249 * precedence 0. The user can still explicitly request reservations per port250 * and per port-tc through devlink-sb.251 */252static void ocelot_disable_reservation_watermarks(struct ocelot *ocelot,253 int port)254{255 int prio;256 257 for (prio = 0; prio < OCELOT_NUM_TC; prio++) {258 ocelot_wm_write(ocelot, BUF_Q_RSRV_I(port, prio), 0);259 ocelot_wm_write(ocelot, BUF_Q_RSRV_E(port, prio), 0);260 ocelot_wm_write(ocelot, REF_Q_RSRV_I(port, prio), 0);261 ocelot_wm_write(ocelot, REF_Q_RSRV_E(port, prio), 0);262 }263 264 ocelot_wm_write(ocelot, BUF_P_RSRV_I(port), 0);265 ocelot_wm_write(ocelot, BUF_P_RSRV_E(port), 0);266 ocelot_wm_write(ocelot, REF_P_RSRV_I(port), 0);267 ocelot_wm_write(ocelot, REF_P_RSRV_E(port), 0);268}269 270/* We want the sharing watermarks to consume all nonreserved resources, for271 * efficient resource utilization (a single traffic flow should be able to use272 * up the entire buffer space and frame resources as long as there's no273 * interference).274 * The switch has 10 sharing watermarks per lookup: 8 per traffic class and 2275 * per color (drop precedence).276 * The trouble with configuring these sharing watermarks is that:277 * (1) There's a risk that we overcommit the resources if we configure278 * (a) all 8 per-TC sharing watermarks to the max279 * (b) all 2 per-color sharing watermarks to the max280 * (2) There's a risk that we undercommit the resources if we configure281 * (a) all 8 per-TC sharing watermarks to "max / 8"282 * (b) all 2 per-color sharing watermarks to "max / 2"283 * So for Linux, let's just disable the sharing watermarks per traffic class284 * (setting them to 0 will make them always exceeded), and rely only on the285 * sharing watermark for drop priority 0. So frames with drop priority set to 1286 * by QoS classification or policing will still be allowed, but only as long as287 * the port and port-TC reservations are not exceeded.288 */289static void ocelot_disable_tc_sharing_watermarks(struct ocelot *ocelot)290{291 int prio;292 293 for (prio = 0; prio < OCELOT_NUM_TC; prio++) {294 ocelot_wm_write(ocelot, BUF_PRIO_SHR_I(prio), 0);295 ocelot_wm_write(ocelot, BUF_PRIO_SHR_E(prio), 0);296 ocelot_wm_write(ocelot, REF_PRIO_SHR_I(prio), 0);297 ocelot_wm_write(ocelot, REF_PRIO_SHR_E(prio), 0);298 }299}300 301static void ocelot_get_buf_rsrv(struct ocelot *ocelot, u32 *buf_rsrv_i,302 u32 *buf_rsrv_e)303{304 int port, prio;305 306 *buf_rsrv_i = 0;307 *buf_rsrv_e = 0;308 309 for (port = 0; port <= ocelot->num_phys_ports; port++) {310 for (prio = 0; prio < OCELOT_NUM_TC; prio++) {311 *buf_rsrv_i += ocelot_wm_read(ocelot,312 BUF_Q_RSRV_I(port, prio));313 *buf_rsrv_e += ocelot_wm_read(ocelot,314 BUF_Q_RSRV_E(port, prio));315 }316 317 *buf_rsrv_i += ocelot_wm_read(ocelot, BUF_P_RSRV_I(port));318 *buf_rsrv_e += ocelot_wm_read(ocelot, BUF_P_RSRV_E(port));319 }320 321 *buf_rsrv_i *= OCELOT_BUFFER_CELL_SZ;322 *buf_rsrv_e *= OCELOT_BUFFER_CELL_SZ;323}324 325static void ocelot_get_ref_rsrv(struct ocelot *ocelot, u32 *ref_rsrv_i,326 u32 *ref_rsrv_e)327{328 int port, prio;329 330 *ref_rsrv_i = 0;331 *ref_rsrv_e = 0;332 333 for (port = 0; port <= ocelot->num_phys_ports; port++) {334 for (prio = 0; prio < OCELOT_NUM_TC; prio++) {335 *ref_rsrv_i += ocelot_wm_read(ocelot,336 REF_Q_RSRV_I(port, prio));337 *ref_rsrv_e += ocelot_wm_read(ocelot,338 REF_Q_RSRV_E(port, prio));339 }340 341 *ref_rsrv_i += ocelot_wm_read(ocelot, REF_P_RSRV_I(port));342 *ref_rsrv_e += ocelot_wm_read(ocelot, REF_P_RSRV_E(port));343 }344}345 346/* Calculate all reservations, then set up the sharing watermark for DP=0 to347 * consume the remaining resources up to the pool's configured size.348 */349static void ocelot_setup_sharing_watermarks(struct ocelot *ocelot)350{351 u32 buf_rsrv_i, buf_rsrv_e;352 u32 ref_rsrv_i, ref_rsrv_e;353 u32 buf_shr_i, buf_shr_e;354 u32 ref_shr_i, ref_shr_e;355 356 ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);357 ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);358 359 buf_shr_i = ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING] -360 buf_rsrv_i;361 buf_shr_e = ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR] -362 buf_rsrv_e;363 ref_shr_i = ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING] -364 ref_rsrv_i;365 ref_shr_e = ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR] -366 ref_rsrv_e;367 368 buf_shr_i /= OCELOT_BUFFER_CELL_SZ;369 buf_shr_e /= OCELOT_BUFFER_CELL_SZ;370 371 ocelot_wm_write(ocelot, BUF_COL_SHR_I(0), buf_shr_i);372 ocelot_wm_write(ocelot, BUF_COL_SHR_E(0), buf_shr_e);373 ocelot_wm_write(ocelot, REF_COL_SHR_E(0), ref_shr_e);374 ocelot_wm_write(ocelot, REF_COL_SHR_I(0), ref_shr_i);375 ocelot_wm_write(ocelot, BUF_COL_SHR_I(1), 0);376 ocelot_wm_write(ocelot, BUF_COL_SHR_E(1), 0);377 ocelot_wm_write(ocelot, REF_COL_SHR_E(1), 0);378 ocelot_wm_write(ocelot, REF_COL_SHR_I(1), 0);379}380 381/* Ensure that all reservations can be enforced */382static int ocelot_watermark_validate(struct ocelot *ocelot,383 struct netlink_ext_ack *extack)384{385 u32 buf_rsrv_i, buf_rsrv_e;386 u32 ref_rsrv_i, ref_rsrv_e;387 388 ocelot_get_buf_rsrv(ocelot, &buf_rsrv_i, &buf_rsrv_e);389 ocelot_get_ref_rsrv(ocelot, &ref_rsrv_i, &ref_rsrv_e);390 391 if (buf_rsrv_i > ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING]) {392 NL_SET_ERR_MSG_MOD(extack,393 "Ingress frame reservations exceed pool size");394 return -ERANGE;395 }396 if (buf_rsrv_e > ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR]) {397 NL_SET_ERR_MSG_MOD(extack,398 "Egress frame reservations exceed pool size");399 return -ERANGE;400 }401 if (ref_rsrv_i > ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING]) {402 NL_SET_ERR_MSG_MOD(extack,403 "Ingress reference reservations exceed pool size");404 return -ERANGE;405 }406 if (ref_rsrv_e > ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR]) {407 NL_SET_ERR_MSG_MOD(extack,408 "Egress reference reservations exceed pool size");409 return -ERANGE;410 }411 412 return 0;413}414 415/* The hardware works like this:416 *417 * Frame forwarding decision taken418 * |419 * v420 * +--------------------+--------------------+--------------------+421 * | | | |422 * v v v v423 * Ingress memory Egress memory Ingress frame Egress frame424 * check check reference check reference check425 * | | | |426 * v v v v427 * BUF_Q_RSRV_I ok BUF_Q_RSRV_E ok REF_Q_RSRV_I ok REF_Q_RSRV_E ok428 *(src port, prio) -+ (dst port, prio) -+ (src port, prio) -+ (dst port, prio) -+429 * | | | | | | | |430 * |exceeded | |exceeded | |exceeded | |exceeded |431 * v | v | v | v |432 * BUF_P_RSRV_I ok| BUF_P_RSRV_E ok| REF_P_RSRV_I ok| REF_P_RSRV_E ok|433 * (src port) ----+ (dst port) ----+ (src port) ----+ (dst port) -----+434 * | | | | | | | |435 * |exceeded | |exceeded | |exceeded | |exceeded |436 * v | v | v | v |437 * BUF_PRIO_SHR_I ok| BUF_PRIO_SHR_E ok| REF_PRIO_SHR_I ok| REF_PRIO_SHR_E ok|438 * (prio) ------+ (prio) ------+ (prio) ------+ (prio) -------+439 * | | | | | | | |440 * |exceeded | |exceeded | |exceeded | |exceeded |441 * v | v | v | v |442 * BUF_COL_SHR_I ok| BUF_COL_SHR_E ok| REF_COL_SHR_I ok| REF_COL_SHR_E ok|443 * (dp) -------+ (dp) -------+ (dp) -------+ (dp) --------+444 * | | | | | | | |445 * |exceeded | |exceeded | |exceeded | |exceeded |446 * v v v v v v v v447 * fail success fail success fail success fail success448 * | | | | | | | |449 * v v v v v v v v450 * +-----+----+ +-----+----+ +-----+----+ +-----+-----+451 * | | | |452 * +-------> OR <-------+ +-------> OR <-------+453 * | |454 * v v455 * +----------------> AND <-----------------+456 * |457 * v458 * FIFO drop / accept459 *460 * We are modeling each of the 4 parallel lookups as a devlink-sb pool.461 * At least one (ingress or egress) memory pool and one (ingress or egress)462 * frame reference pool need to have resources for frame acceptance to succeed.463 *464 * The following watermarks are controlled explicitly through devlink-sb:465 * BUF_Q_RSRV_I, BUF_Q_RSRV_E, REF_Q_RSRV_I, REF_Q_RSRV_E466 * BUF_P_RSRV_I, BUF_P_RSRV_E, REF_P_RSRV_I, REF_P_RSRV_E467 * The following watermarks are controlled implicitly through devlink-sb:468 * BUF_COL_SHR_I, BUF_COL_SHR_E, REF_COL_SHR_I, REF_COL_SHR_E469 * The following watermarks are unused and disabled:470 * BUF_PRIO_SHR_I, BUF_PRIO_SHR_E, REF_PRIO_SHR_I, REF_PRIO_SHR_E471 *472 * This function overrides the hardware defaults with more sane ones (no473 * reservations by default, let sharing use all resources) and disables the474 * unused watermarks.475 */476static void ocelot_watermark_init(struct ocelot *ocelot)477{478 int all_tcs = GENMASK(OCELOT_NUM_TC - 1, 0);479 int port;480 481 ocelot_write(ocelot, all_tcs, QSYS_RES_QOS_MODE);482 483 for (port = 0; port <= ocelot->num_phys_ports; port++)484 ocelot_disable_reservation_watermarks(ocelot, port);485 486 ocelot_disable_tc_sharing_watermarks(ocelot);487 ocelot_setup_sharing_watermarks(ocelot);488}489 490/* Watermark encode491 * Bit 8: Unit; 0:1, 1:16492 * Bit 7-0: Value to be multiplied with unit493 */494u16 ocelot_wm_enc(u16 value)495{496 WARN_ON(value >= 16 * BIT(8));497 498 if (value >= BIT(8))499 return BIT(8) | (value / 16);500 501 return value;502}503EXPORT_SYMBOL(ocelot_wm_enc);504 505u16 ocelot_wm_dec(u16 wm)506{507 if (wm & BIT(8))508 return (wm & GENMASK(7, 0)) * 16;509 510 return wm;511}512EXPORT_SYMBOL(ocelot_wm_dec);513 514void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse)515{516 *inuse = (val & GENMASK(23, 12)) >> 12;517 *maxuse = val & GENMASK(11, 0);518}519EXPORT_SYMBOL(ocelot_wm_stat);520 521/* Pool size and type are fixed up at runtime. Keeping this structure to522 * look up the cell size multipliers.523 */524static const struct devlink_sb_pool_info ocelot_sb_pool[] = {525 [OCELOT_SB_BUF] = {526 .cell_size = OCELOT_BUFFER_CELL_SZ,527 .threshold_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC,528 },529 [OCELOT_SB_REF] = {530 .cell_size = 1,531 .threshold_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC,532 },533};534 535/* Returns the pool size configured through ocelot_sb_pool_set */536int ocelot_sb_pool_get(struct ocelot *ocelot, unsigned int sb_index,537 u16 pool_index,538 struct devlink_sb_pool_info *pool_info)539{540 if (sb_index >= OCELOT_SB_NUM)541 return -ENODEV;542 if (pool_index >= OCELOT_SB_POOL_NUM)543 return -ENODEV;544 545 *pool_info = ocelot_sb_pool[sb_index];546 pool_info->size = ocelot->pool_size[sb_index][pool_index];547 if (pool_index)548 pool_info->pool_type = DEVLINK_SB_POOL_TYPE_INGRESS;549 else550 pool_info->pool_type = DEVLINK_SB_POOL_TYPE_EGRESS;551 552 return 0;553}554EXPORT_SYMBOL(ocelot_sb_pool_get);555 556/* The pool size received here configures the total amount of resources used on557 * ingress (or on egress, depending upon the pool index). The pool size, minus558 * the values for the port and port-tc reservations, is written into the559 * COL_SHR(dp=0) sharing watermark.560 */561int ocelot_sb_pool_set(struct ocelot *ocelot, unsigned int sb_index,562 u16 pool_index, u32 size,563 enum devlink_sb_threshold_type threshold_type,564 struct netlink_ext_ack *extack)565{566 u32 old_pool_size;567 int err;568 569 if (sb_index >= OCELOT_SB_NUM) {570 NL_SET_ERR_MSG_MOD(extack,571 "Invalid sb, use 0 for buffers and 1 for frame references");572 return -ENODEV;573 }574 if (pool_index >= OCELOT_SB_POOL_NUM) {575 NL_SET_ERR_MSG_MOD(extack,576 "Invalid pool, use 0 for ingress and 1 for egress");577 return -ENODEV;578 }579 if (threshold_type != DEVLINK_SB_THRESHOLD_TYPE_STATIC) {580 NL_SET_ERR_MSG_MOD(extack,581 "Only static threshold supported");582 return -EOPNOTSUPP;583 }584 585 old_pool_size = ocelot->pool_size[sb_index][pool_index];586 ocelot->pool_size[sb_index][pool_index] = size;587 588 err = ocelot_watermark_validate(ocelot, extack);589 if (err) {590 ocelot->pool_size[sb_index][pool_index] = old_pool_size;591 return err;592 }593 594 ocelot_setup_sharing_watermarks(ocelot);595 596 return 0;597}598EXPORT_SYMBOL(ocelot_sb_pool_set);599 600/* This retrieves the configuration made with ocelot_sb_port_pool_set */601int ocelot_sb_port_pool_get(struct ocelot *ocelot, int port,602 unsigned int sb_index, u16 pool_index,603 u32 *p_threshold)604{605 int wm_index;606 607 switch (sb_index) {608 case OCELOT_SB_BUF:609 if (pool_index == OCELOT_SB_POOL_ING)610 wm_index = BUF_P_RSRV_I(port);611 else612 wm_index = BUF_P_RSRV_E(port);613 break;614 case OCELOT_SB_REF:615 if (pool_index == OCELOT_SB_POOL_ING)616 wm_index = REF_P_RSRV_I(port);617 else618 wm_index = REF_P_RSRV_E(port);619 break;620 default:621 return -ENODEV;622 }623 624 *p_threshold = ocelot_wm_read(ocelot, wm_index);625 *p_threshold *= ocelot_sb_pool[sb_index].cell_size;626 627 return 0;628}629EXPORT_SYMBOL(ocelot_sb_port_pool_get);630 631/* This configures the P_RSRV per-port reserved resource watermark */632int ocelot_sb_port_pool_set(struct ocelot *ocelot, int port,633 unsigned int sb_index, u16 pool_index,634 u32 threshold, struct netlink_ext_ack *extack)635{636 int wm_index, err;637 u32 old_thr;638 639 switch (sb_index) {640 case OCELOT_SB_BUF:641 if (pool_index == OCELOT_SB_POOL_ING)642 wm_index = BUF_P_RSRV_I(port);643 else644 wm_index = BUF_P_RSRV_E(port);645 break;646 case OCELOT_SB_REF:647 if (pool_index == OCELOT_SB_POOL_ING)648 wm_index = REF_P_RSRV_I(port);649 else650 wm_index = REF_P_RSRV_E(port);651 break;652 default:653 NL_SET_ERR_MSG_MOD(extack, "Invalid shared buffer");654 return -ENODEV;655 }656 657 threshold /= ocelot_sb_pool[sb_index].cell_size;658 659 old_thr = ocelot_wm_read(ocelot, wm_index);660 ocelot_wm_write(ocelot, wm_index, threshold);661 662 err = ocelot_watermark_validate(ocelot, extack);663 if (err) {664 ocelot_wm_write(ocelot, wm_index, old_thr);665 return err;666 }667 668 ocelot_setup_sharing_watermarks(ocelot);669 670 return 0;671}672EXPORT_SYMBOL(ocelot_sb_port_pool_set);673 674/* This retrieves the configuration done by ocelot_sb_tc_pool_bind_set */675int ocelot_sb_tc_pool_bind_get(struct ocelot *ocelot, int port,676 unsigned int sb_index, u16 tc_index,677 enum devlink_sb_pool_type pool_type,678 u16 *p_pool_index, u32 *p_threshold)679{680 int wm_index;681 682 switch (sb_index) {683 case OCELOT_SB_BUF:684 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)685 wm_index = BUF_Q_RSRV_I(port, tc_index);686 else687 wm_index = BUF_Q_RSRV_E(port, tc_index);688 break;689 case OCELOT_SB_REF:690 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)691 wm_index = REF_Q_RSRV_I(port, tc_index);692 else693 wm_index = REF_Q_RSRV_E(port, tc_index);694 break;695 default:696 return -ENODEV;697 }698 699 *p_threshold = ocelot_wm_read(ocelot, wm_index);700 *p_threshold *= ocelot_sb_pool[sb_index].cell_size;701 702 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)703 *p_pool_index = 0;704 else705 *p_pool_index = 1;706 707 return 0;708}709EXPORT_SYMBOL(ocelot_sb_tc_pool_bind_get);710 711/* This configures the Q_RSRV per-port-tc reserved resource watermark */712int ocelot_sb_tc_pool_bind_set(struct ocelot *ocelot, int port,713 unsigned int sb_index, u16 tc_index,714 enum devlink_sb_pool_type pool_type,715 u16 pool_index, u32 threshold,716 struct netlink_ext_ack *extack)717{718 int wm_index, err;719 u32 old_thr;720 721 /* Paranoid check? */722 if (pool_index == OCELOT_SB_POOL_ING &&723 pool_type != DEVLINK_SB_POOL_TYPE_INGRESS)724 return -EINVAL;725 if (pool_index == OCELOT_SB_POOL_EGR &&726 pool_type != DEVLINK_SB_POOL_TYPE_EGRESS)727 return -EINVAL;728 729 switch (sb_index) {730 case OCELOT_SB_BUF:731 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)732 wm_index = BUF_Q_RSRV_I(port, tc_index);733 else734 wm_index = BUF_Q_RSRV_E(port, tc_index);735 break;736 case OCELOT_SB_REF:737 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)738 wm_index = REF_Q_RSRV_I(port, tc_index);739 else740 wm_index = REF_Q_RSRV_E(port, tc_index);741 break;742 default:743 NL_SET_ERR_MSG_MOD(extack, "Invalid shared buffer");744 return -ENODEV;745 }746 747 threshold /= ocelot_sb_pool[sb_index].cell_size;748 749 old_thr = ocelot_wm_read(ocelot, wm_index);750 ocelot_wm_write(ocelot, wm_index, threshold);751 err = ocelot_watermark_validate(ocelot, extack);752 if (err) {753 ocelot_wm_write(ocelot, wm_index, old_thr);754 return err;755 }756 757 ocelot_setup_sharing_watermarks(ocelot);758 759 return 0;760}761EXPORT_SYMBOL(ocelot_sb_tc_pool_bind_set);762 763/* The hardware does not support atomic snapshots, we'll read out the764 * occupancy registers individually and have this as just a stub.765 */766int ocelot_sb_occ_snapshot(struct ocelot *ocelot, unsigned int sb_index)767{768 return 0;769}770EXPORT_SYMBOL(ocelot_sb_occ_snapshot);771 772/* The watermark occupancy registers are cleared upon read,773 * so let's read them.774 */775int ocelot_sb_occ_max_clear(struct ocelot *ocelot, unsigned int sb_index)776{777 u32 inuse, maxuse;778 int port, prio;779 780 switch (sb_index) {781 case OCELOT_SB_BUF:782 for (port = 0; port <= ocelot->num_phys_ports; port++) {783 for (prio = 0; prio < OCELOT_NUM_TC; prio++) {784 ocelot_wm_status(ocelot, BUF_Q_RSRV_I(port, prio),785 &inuse, &maxuse);786 ocelot_wm_status(ocelot, BUF_Q_RSRV_E(port, prio),787 &inuse, &maxuse);788 }789 ocelot_wm_status(ocelot, BUF_P_RSRV_I(port),790 &inuse, &maxuse);791 ocelot_wm_status(ocelot, BUF_P_RSRV_E(port),792 &inuse, &maxuse);793 }794 break;795 case OCELOT_SB_REF:796 for (port = 0; port <= ocelot->num_phys_ports; port++) {797 for (prio = 0; prio < OCELOT_NUM_TC; prio++) {798 ocelot_wm_status(ocelot, REF_Q_RSRV_I(port, prio),799 &inuse, &maxuse);800 ocelot_wm_status(ocelot, REF_Q_RSRV_E(port, prio),801 &inuse, &maxuse);802 }803 ocelot_wm_status(ocelot, REF_P_RSRV_I(port),804 &inuse, &maxuse);805 ocelot_wm_status(ocelot, REF_P_RSRV_E(port),806 &inuse, &maxuse);807 }808 break;809 default:810 return -ENODEV;811 }812 813 return 0;814}815EXPORT_SYMBOL(ocelot_sb_occ_max_clear);816 817/* This retrieves the watermark occupancy for per-port P_RSRV watermarks */818int ocelot_sb_occ_port_pool_get(struct ocelot *ocelot, int port,819 unsigned int sb_index, u16 pool_index,820 u32 *p_cur, u32 *p_max)821{822 int wm_index;823 824 switch (sb_index) {825 case OCELOT_SB_BUF:826 if (pool_index == OCELOT_SB_POOL_ING)827 wm_index = BUF_P_RSRV_I(port);828 else829 wm_index = BUF_P_RSRV_E(port);830 break;831 case OCELOT_SB_REF:832 if (pool_index == OCELOT_SB_POOL_ING)833 wm_index = REF_P_RSRV_I(port);834 else835 wm_index = REF_P_RSRV_E(port);836 break;837 default:838 return -ENODEV;839 }840 841 ocelot_wm_status(ocelot, wm_index, p_cur, p_max);842 *p_cur *= ocelot_sb_pool[sb_index].cell_size;843 *p_max *= ocelot_sb_pool[sb_index].cell_size;844 845 return 0;846}847EXPORT_SYMBOL(ocelot_sb_occ_port_pool_get);848 849/* This retrieves the watermark occupancy for per-port-tc Q_RSRV watermarks */850int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,851 unsigned int sb_index, u16 tc_index,852 enum devlink_sb_pool_type pool_type,853 u32 *p_cur, u32 *p_max)854{855 int wm_index;856 857 switch (sb_index) {858 case OCELOT_SB_BUF:859 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)860 wm_index = BUF_Q_RSRV_I(port, tc_index);861 else862 wm_index = BUF_Q_RSRV_E(port, tc_index);863 break;864 case OCELOT_SB_REF:865 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)866 wm_index = REF_Q_RSRV_I(port, tc_index);867 else868 wm_index = REF_Q_RSRV_E(port, tc_index);869 break;870 default:871 return -ENODEV;872 }873 874 ocelot_wm_status(ocelot, wm_index, p_cur, p_max);875 *p_cur *= ocelot_sb_pool[sb_index].cell_size;876 *p_max *= ocelot_sb_pool[sb_index].cell_size;877 878 return 0;879}880EXPORT_SYMBOL(ocelot_sb_occ_tc_port_bind_get);881 882int ocelot_devlink_sb_register(struct ocelot *ocelot)883{884 int err;885 886 err = devlink_sb_register(ocelot->devlink, OCELOT_SB_BUF,887 ocelot->packet_buffer_size, 1, 1,888 OCELOT_NUM_TC, OCELOT_NUM_TC);889 if (err)890 return err;891 892 err = devlink_sb_register(ocelot->devlink, OCELOT_SB_REF,893 ocelot->num_frame_refs, 1, 1,894 OCELOT_NUM_TC, OCELOT_NUM_TC);895 if (err) {896 devlink_sb_unregister(ocelot->devlink, OCELOT_SB_BUF);897 return err;898 }899 900 ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_ING] = ocelot->packet_buffer_size;901 ocelot->pool_size[OCELOT_SB_BUF][OCELOT_SB_POOL_EGR] = ocelot->packet_buffer_size;902 ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_ING] = ocelot->num_frame_refs;903 ocelot->pool_size[OCELOT_SB_REF][OCELOT_SB_POOL_EGR] = ocelot->num_frame_refs;904 905 ocelot_watermark_init(ocelot);906 907 return 0;908}909EXPORT_SYMBOL(ocelot_devlink_sb_register);910 911void ocelot_devlink_sb_unregister(struct ocelot *ocelot)912{913 devlink_sb_unregister(ocelot->devlink, OCELOT_SB_BUF);914 devlink_sb_unregister(ocelot->devlink, OCELOT_SB_REF);915}916EXPORT_SYMBOL(ocelot_devlink_sb_unregister);917