1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/errno.h> 6 #include <linux/netdevice.h> 7 #include <net/pkt_cls.h> 8 #include <net/red.h> 9 10 #include "spectrum.h" 11 #include "spectrum_span.h" 12 #include "reg.h" 13 14 #define MLXSW_SP_PRIO_BAND_TO_TCLASS(band) (IEEE_8021QAZ_MAX_TCS - band - 1) 15 #define MLXSW_SP_PRIO_CHILD_TO_TCLASS(child) \ 16 MLXSW_SP_PRIO_BAND_TO_TCLASS((child - 1)) 17 18 enum mlxsw_sp_qdisc_type { 19 MLXSW_SP_QDISC_NO_QDISC, 20 MLXSW_SP_QDISC_RED, 21 MLXSW_SP_QDISC_PRIO, 22 MLXSW_SP_QDISC_ETS, 23 MLXSW_SP_QDISC_TBF, 24 MLXSW_SP_QDISC_FIFO, 25 }; 26 27 struct mlxsw_sp_qdisc; 28 29 struct mlxsw_sp_qdisc_ops { 30 enum mlxsw_sp_qdisc_type type; 31 int (*check_params)(struct mlxsw_sp_port *mlxsw_sp_port, 32 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 33 void *params); 34 int (*replace)(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 35 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *params); 36 int (*destroy)(struct mlxsw_sp_port *mlxsw_sp_port, 37 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc); 38 int (*get_stats)(struct mlxsw_sp_port *mlxsw_sp_port, 39 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 40 struct tc_qopt_offload_stats *stats_ptr); 41 int (*get_xstats)(struct mlxsw_sp_port *mlxsw_sp_port, 42 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 43 void *xstats_ptr); 44 void (*clean_stats)(struct mlxsw_sp_port *mlxsw_sp_port, 45 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc); 46 /* unoffload - to be used for a qdisc that stops being offloaded without 47 * being destroyed. 48 */ 49 void (*unoffload)(struct mlxsw_sp_port *mlxsw_sp_port, 50 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *params); 51 }; 52 53 struct mlxsw_sp_qdisc { 54 u32 handle; 55 u8 tclass_num; 56 u8 prio_bitmap; 57 union { 58 struct red_stats red; 59 } xstats_base; 60 struct mlxsw_sp_qdisc_stats { 61 u64 tx_bytes; 62 u64 tx_packets; 63 u64 drops; 64 u64 overlimits; 65 u64 backlog; 66 } stats_base; 67 68 struct mlxsw_sp_qdisc_ops *ops; 69 }; 70 71 struct mlxsw_sp_qdisc_state { 72 struct mlxsw_sp_qdisc root_qdisc; 73 struct mlxsw_sp_qdisc tclass_qdiscs[IEEE_8021QAZ_MAX_TCS]; 74 75 /* When a PRIO or ETS are added, the invisible FIFOs in their bands are 76 * created first. When notifications for these FIFOs arrive, it is not 77 * known what qdisc their parent handle refers to. It could be a 78 * newly-created PRIO that will replace the currently-offloaded one, or 79 * it could be e.g. a RED that will be attached below it. 80 * 81 * As the notifications start to arrive, use them to note what the 82 * future parent handle is, and keep track of which child FIFOs were 83 * seen. Then when the parent is known, retroactively offload those 84 * FIFOs. 85 */ 86 u32 future_handle; 87 bool future_fifos[IEEE_8021QAZ_MAX_TCS]; 88 }; 89 90 static bool 91 mlxsw_sp_qdisc_compare(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, u32 handle, 92 enum mlxsw_sp_qdisc_type type) 93 { 94 return mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops && 95 mlxsw_sp_qdisc->ops->type == type && 96 mlxsw_sp_qdisc->handle == handle; 97 } 98 99 static struct mlxsw_sp_qdisc * 100 mlxsw_sp_qdisc_find(struct mlxsw_sp_port *mlxsw_sp_port, u32 parent, 101 bool root_only) 102 { 103 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 104 int tclass, child_index; 105 106 if (parent == TC_H_ROOT) 107 return &qdisc_state->root_qdisc; 108 109 if (root_only || !qdisc_state || 110 !qdisc_state->root_qdisc.ops || 111 TC_H_MAJ(parent) != qdisc_state->root_qdisc.handle || 112 TC_H_MIN(parent) > IEEE_8021QAZ_MAX_TCS) 113 return NULL; 114 115 child_index = TC_H_MIN(parent); 116 tclass = MLXSW_SP_PRIO_CHILD_TO_TCLASS(child_index); 117 return &qdisc_state->tclass_qdiscs[tclass]; 118 } 119 120 static struct mlxsw_sp_qdisc * 121 mlxsw_sp_qdisc_find_by_handle(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle) 122 { 123 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 124 int i; 125 126 if (qdisc_state->root_qdisc.handle == handle) 127 return &qdisc_state->root_qdisc; 128 129 if (qdisc_state->root_qdisc.handle == TC_H_UNSPEC) 130 return NULL; 131 132 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 133 if (qdisc_state->tclass_qdiscs[i].handle == handle) 134 return &qdisc_state->tclass_qdiscs[i]; 135 136 return NULL; 137 } 138 139 static int 140 mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 141 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 142 { 143 int err = 0; 144 145 if (!mlxsw_sp_qdisc) 146 return 0; 147 148 if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->destroy) 149 err = mlxsw_sp_qdisc->ops->destroy(mlxsw_sp_port, 150 mlxsw_sp_qdisc); 151 152 mlxsw_sp_qdisc->handle = TC_H_UNSPEC; 153 mlxsw_sp_qdisc->ops = NULL; 154 return err; 155 } 156 157 static int 158 mlxsw_sp_qdisc_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 159 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 160 struct mlxsw_sp_qdisc_ops *ops, void *params) 161 { 162 int err; 163 164 if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->type != ops->type) 165 /* In case this location contained a different qdisc of the 166 * same type we can override the old qdisc configuration. 167 * Otherwise, we need to remove the old qdisc before setting the 168 * new one. 169 */ 170 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc); 171 err = ops->check_params(mlxsw_sp_port, mlxsw_sp_qdisc, params); 172 if (err) 173 goto err_bad_param; 174 175 err = ops->replace(mlxsw_sp_port, handle, mlxsw_sp_qdisc, params); 176 if (err) 177 goto err_config; 178 179 /* Check if the Qdisc changed. That includes a situation where an 180 * invisible Qdisc replaces another one, or is being added for the 181 * first time. 182 */ 183 if (mlxsw_sp_qdisc->handle != handle || handle == TC_H_UNSPEC) { 184 mlxsw_sp_qdisc->ops = ops; 185 if (ops->clean_stats) 186 ops->clean_stats(mlxsw_sp_port, mlxsw_sp_qdisc); 187 } 188 189 mlxsw_sp_qdisc->handle = handle; 190 return 0; 191 192 err_bad_param: 193 err_config: 194 if (mlxsw_sp_qdisc->handle == handle && ops->unoffload) 195 ops->unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, params); 196 197 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc); 198 return err; 199 } 200 201 static int 202 mlxsw_sp_qdisc_get_stats(struct mlxsw_sp_port *mlxsw_sp_port, 203 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 204 struct tc_qopt_offload_stats *stats_ptr) 205 { 206 if (mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops && 207 mlxsw_sp_qdisc->ops->get_stats) 208 return mlxsw_sp_qdisc->ops->get_stats(mlxsw_sp_port, 209 mlxsw_sp_qdisc, 210 stats_ptr); 211 212 return -EOPNOTSUPP; 213 } 214 215 static int 216 mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port, 217 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 218 void *xstats_ptr) 219 { 220 if (mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops && 221 mlxsw_sp_qdisc->ops->get_xstats) 222 return mlxsw_sp_qdisc->ops->get_xstats(mlxsw_sp_port, 223 mlxsw_sp_qdisc, 224 xstats_ptr); 225 226 return -EOPNOTSUPP; 227 } 228 229 static u64 230 mlxsw_sp_xstats_backlog(struct mlxsw_sp_port_xstats *xstats, int tclass_num) 231 { 232 return xstats->backlog[tclass_num] + 233 xstats->backlog[tclass_num + 8]; 234 } 235 236 static u64 237 mlxsw_sp_xstats_tail_drop(struct mlxsw_sp_port_xstats *xstats, int tclass_num) 238 { 239 return xstats->tail_drop[tclass_num] + 240 xstats->tail_drop[tclass_num + 8]; 241 } 242 243 static void 244 mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats, 245 u8 prio_bitmap, u64 *tx_packets, 246 u64 *tx_bytes) 247 { 248 int i; 249 250 *tx_packets = 0; 251 *tx_bytes = 0; 252 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 253 if (prio_bitmap & BIT(i)) { 254 *tx_packets += xstats->tx_packets[i]; 255 *tx_bytes += xstats->tx_bytes[i]; 256 } 257 } 258 } 259 260 static void 261 mlxsw_sp_qdisc_collect_tc_stats(struct mlxsw_sp_port *mlxsw_sp_port, 262 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 263 u64 *p_tx_bytes, u64 *p_tx_packets, 264 u64 *p_drops, u64 *p_backlog) 265 { 266 u8 tclass_num = mlxsw_sp_qdisc->tclass_num; 267 struct mlxsw_sp_port_xstats *xstats; 268 u64 tx_bytes, tx_packets; 269 270 xstats = &mlxsw_sp_port->periodic_hw_stats.xstats; 271 mlxsw_sp_qdisc_bstats_per_priority_get(xstats, 272 mlxsw_sp_qdisc->prio_bitmap, 273 &tx_packets, &tx_bytes); 274 275 *p_tx_packets += tx_packets; 276 *p_tx_bytes += tx_bytes; 277 *p_drops += xstats->wred_drop[tclass_num] + 278 mlxsw_sp_xstats_tail_drop(xstats, tclass_num); 279 *p_backlog += mlxsw_sp_xstats_backlog(xstats, tclass_num); 280 } 281 282 static void 283 mlxsw_sp_qdisc_update_stats(struct mlxsw_sp *mlxsw_sp, 284 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 285 u64 tx_bytes, u64 tx_packets, 286 u64 drops, u64 backlog, 287 struct tc_qopt_offload_stats *stats_ptr) 288 { 289 struct mlxsw_sp_qdisc_stats *stats_base = &mlxsw_sp_qdisc->stats_base; 290 291 tx_bytes -= stats_base->tx_bytes; 292 tx_packets -= stats_base->tx_packets; 293 drops -= stats_base->drops; 294 backlog -= stats_base->backlog; 295 296 _bstats_update(stats_ptr->bstats, tx_bytes, tx_packets); 297 stats_ptr->qstats->drops += drops; 298 stats_ptr->qstats->backlog += mlxsw_sp_cells_bytes(mlxsw_sp, backlog); 299 300 stats_base->backlog += backlog; 301 stats_base->drops += drops; 302 stats_base->tx_bytes += tx_bytes; 303 stats_base->tx_packets += tx_packets; 304 } 305 306 static void 307 mlxsw_sp_qdisc_get_tc_stats(struct mlxsw_sp_port *mlxsw_sp_port, 308 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 309 struct tc_qopt_offload_stats *stats_ptr) 310 { 311 u64 tx_packets = 0; 312 u64 tx_bytes = 0; 313 u64 backlog = 0; 314 u64 drops = 0; 315 316 mlxsw_sp_qdisc_collect_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 317 &tx_bytes, &tx_packets, 318 &drops, &backlog); 319 mlxsw_sp_qdisc_update_stats(mlxsw_sp_port->mlxsw_sp, mlxsw_sp_qdisc, 320 tx_bytes, tx_packets, drops, backlog, 321 stats_ptr); 322 } 323 324 static int 325 mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port, 326 int tclass_num, u32 min, u32 max, 327 u32 probability, bool is_wred, bool is_ecn) 328 { 329 char cwtpm_cmd[MLXSW_REG_CWTPM_LEN]; 330 char cwtp_cmd[MLXSW_REG_CWTP_LEN]; 331 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 332 int err; 333 334 mlxsw_reg_cwtp_pack(cwtp_cmd, mlxsw_sp_port->local_port, tclass_num); 335 mlxsw_reg_cwtp_profile_pack(cwtp_cmd, MLXSW_REG_CWTP_DEFAULT_PROFILE, 336 roundup(min, MLXSW_REG_CWTP_MIN_VALUE), 337 roundup(max, MLXSW_REG_CWTP_MIN_VALUE), 338 probability); 339 340 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtp), cwtp_cmd); 341 if (err) 342 return err; 343 344 mlxsw_reg_cwtpm_pack(cwtpm_cmd, mlxsw_sp_port->local_port, tclass_num, 345 MLXSW_REG_CWTP_DEFAULT_PROFILE, is_wred, is_ecn); 346 347 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd); 348 } 349 350 static int 351 mlxsw_sp_tclass_congestion_disable(struct mlxsw_sp_port *mlxsw_sp_port, 352 int tclass_num) 353 { 354 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 355 char cwtpm_cmd[MLXSW_REG_CWTPM_LEN]; 356 357 mlxsw_reg_cwtpm_pack(cwtpm_cmd, mlxsw_sp_port->local_port, tclass_num, 358 MLXSW_REG_CWTPM_RESET_PROFILE, false, false); 359 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd); 360 } 361 362 static void 363 mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port, 364 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 365 { 366 u8 tclass_num = mlxsw_sp_qdisc->tclass_num; 367 struct mlxsw_sp_qdisc_stats *stats_base; 368 struct mlxsw_sp_port_xstats *xstats; 369 struct red_stats *red_base; 370 371 xstats = &mlxsw_sp_port->periodic_hw_stats.xstats; 372 stats_base = &mlxsw_sp_qdisc->stats_base; 373 red_base = &mlxsw_sp_qdisc->xstats_base.red; 374 375 mlxsw_sp_qdisc_bstats_per_priority_get(xstats, 376 mlxsw_sp_qdisc->prio_bitmap, 377 &stats_base->tx_packets, 378 &stats_base->tx_bytes); 379 red_base->prob_drop = xstats->wred_drop[tclass_num]; 380 red_base->pdrop = mlxsw_sp_xstats_tail_drop(xstats, tclass_num); 381 382 stats_base->overlimits = red_base->prob_drop + red_base->prob_mark; 383 stats_base->drops = red_base->prob_drop + red_base->pdrop; 384 385 stats_base->backlog = 0; 386 } 387 388 static int 389 mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 390 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 391 { 392 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 393 struct mlxsw_sp_qdisc *root_qdisc = &qdisc_state->root_qdisc; 394 395 if (root_qdisc != mlxsw_sp_qdisc) 396 root_qdisc->stats_base.backlog -= 397 mlxsw_sp_qdisc->stats_base.backlog; 398 399 return mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port, 400 mlxsw_sp_qdisc->tclass_num); 401 } 402 403 static int 404 mlxsw_sp_qdisc_red_check_params(struct mlxsw_sp_port *mlxsw_sp_port, 405 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 406 void *params) 407 { 408 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 409 struct tc_red_qopt_offload_params *p = params; 410 411 if (p->min > p->max) { 412 dev_err(mlxsw_sp->bus_info->dev, 413 "spectrum: RED: min %u is bigger then max %u\n", p->min, 414 p->max); 415 return -EINVAL; 416 } 417 if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, 418 GUARANTEED_SHARED_BUFFER)) { 419 dev_err(mlxsw_sp->bus_info->dev, 420 "spectrum: RED: max value %u is too big\n", p->max); 421 return -EINVAL; 422 } 423 if (p->min == 0 || p->max == 0) { 424 dev_err(mlxsw_sp->bus_info->dev, 425 "spectrum: RED: 0 value is illegal for min and max\n"); 426 return -EINVAL; 427 } 428 return 0; 429 } 430 431 static int 432 mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 433 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 434 void *params) 435 { 436 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 437 struct tc_red_qopt_offload_params *p = params; 438 u8 tclass_num = mlxsw_sp_qdisc->tclass_num; 439 u32 min, max; 440 u64 prob; 441 442 /* calculate probability in percentage */ 443 prob = p->probability; 444 prob *= 100; 445 prob = DIV_ROUND_UP(prob, 1 << 16); 446 prob = DIV_ROUND_UP(prob, 1 << 16); 447 min = mlxsw_sp_bytes_cells(mlxsw_sp, p->min); 448 max = mlxsw_sp_bytes_cells(mlxsw_sp, p->max); 449 return mlxsw_sp_tclass_congestion_enable(mlxsw_sp_port, tclass_num, 450 min, max, prob, 451 !p->is_nodrop, p->is_ecn); 452 } 453 454 static void 455 mlxsw_sp_qdisc_leaf_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, 456 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 457 struct gnet_stats_queue *qstats) 458 { 459 u64 backlog; 460 461 backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp, 462 mlxsw_sp_qdisc->stats_base.backlog); 463 qstats->backlog -= backlog; 464 mlxsw_sp_qdisc->stats_base.backlog = 0; 465 } 466 467 static void 468 mlxsw_sp_qdisc_red_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, 469 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 470 void *params) 471 { 472 struct tc_red_qopt_offload_params *p = params; 473 474 mlxsw_sp_qdisc_leaf_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, p->qstats); 475 } 476 477 static int 478 mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port, 479 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 480 void *xstats_ptr) 481 { 482 struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base.red; 483 u8 tclass_num = mlxsw_sp_qdisc->tclass_num; 484 struct mlxsw_sp_port_xstats *xstats; 485 struct red_stats *res = xstats_ptr; 486 int early_drops, pdrops; 487 488 xstats = &mlxsw_sp_port->periodic_hw_stats.xstats; 489 490 early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop; 491 pdrops = mlxsw_sp_xstats_tail_drop(xstats, tclass_num) - 492 xstats_base->pdrop; 493 494 res->pdrop += pdrops; 495 res->prob_drop += early_drops; 496 497 xstats_base->pdrop += pdrops; 498 xstats_base->prob_drop += early_drops; 499 return 0; 500 } 501 502 static int 503 mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port, 504 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 505 struct tc_qopt_offload_stats *stats_ptr) 506 { 507 u8 tclass_num = mlxsw_sp_qdisc->tclass_num; 508 struct mlxsw_sp_qdisc_stats *stats_base; 509 struct mlxsw_sp_port_xstats *xstats; 510 u64 overlimits; 511 512 xstats = &mlxsw_sp_port->periodic_hw_stats.xstats; 513 stats_base = &mlxsw_sp_qdisc->stats_base; 514 515 mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, stats_ptr); 516 overlimits = xstats->wred_drop[tclass_num] - stats_base->overlimits; 517 518 stats_ptr->qstats->overlimits += overlimits; 519 stats_base->overlimits += overlimits; 520 521 return 0; 522 } 523 524 #define MLXSW_SP_PORT_DEFAULT_TCLASS 0 525 526 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_red = { 527 .type = MLXSW_SP_QDISC_RED, 528 .check_params = mlxsw_sp_qdisc_red_check_params, 529 .replace = mlxsw_sp_qdisc_red_replace, 530 .unoffload = mlxsw_sp_qdisc_red_unoffload, 531 .destroy = mlxsw_sp_qdisc_red_destroy, 532 .get_stats = mlxsw_sp_qdisc_get_red_stats, 533 .get_xstats = mlxsw_sp_qdisc_get_red_xstats, 534 .clean_stats = mlxsw_sp_setup_tc_qdisc_red_clean_stats, 535 }; 536 537 int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port, 538 struct tc_red_qopt_offload *p) 539 { 540 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; 541 542 mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false); 543 if (!mlxsw_sp_qdisc) 544 return -EOPNOTSUPP; 545 546 if (p->command == TC_RED_REPLACE) 547 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, 548 mlxsw_sp_qdisc, 549 &mlxsw_sp_qdisc_ops_red, 550 &p->set); 551 552 if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle, 553 MLXSW_SP_QDISC_RED)) 554 return -EOPNOTSUPP; 555 556 switch (p->command) { 557 case TC_RED_DESTROY: 558 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc); 559 case TC_RED_XSTATS: 560 return mlxsw_sp_qdisc_get_xstats(mlxsw_sp_port, mlxsw_sp_qdisc, 561 p->xstats); 562 case TC_RED_STATS: 563 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 564 &p->stats); 565 default: 566 return -EOPNOTSUPP; 567 } 568 } 569 570 static void 571 mlxsw_sp_setup_tc_qdisc_leaf_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port, 572 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 573 { 574 u64 backlog_cells = 0; 575 u64 tx_packets = 0; 576 u64 tx_bytes = 0; 577 u64 drops = 0; 578 579 mlxsw_sp_qdisc_collect_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 580 &tx_bytes, &tx_packets, 581 &drops, &backlog_cells); 582 583 mlxsw_sp_qdisc->stats_base.tx_packets = tx_packets; 584 mlxsw_sp_qdisc->stats_base.tx_bytes = tx_bytes; 585 mlxsw_sp_qdisc->stats_base.drops = drops; 586 mlxsw_sp_qdisc->stats_base.backlog = 0; 587 } 588 589 static int 590 mlxsw_sp_qdisc_tbf_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 591 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 592 { 593 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 594 struct mlxsw_sp_qdisc *root_qdisc = &qdisc_state->root_qdisc; 595 596 if (root_qdisc != mlxsw_sp_qdisc) 597 root_qdisc->stats_base.backlog -= 598 mlxsw_sp_qdisc->stats_base.backlog; 599 600 return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 601 MLXSW_REG_QEEC_HR_SUBGROUP, 602 mlxsw_sp_qdisc->tclass_num, 0, 603 MLXSW_REG_QEEC_MAS_DIS, 0); 604 } 605 606 static int 607 mlxsw_sp_qdisc_tbf_bs(struct mlxsw_sp_port *mlxsw_sp_port, 608 u32 max_size, u8 *p_burst_size) 609 { 610 /* TBF burst size is configured in bytes. The ASIC burst size value is 611 * ((2 ^ bs) * 512 bits. Convert the TBF bytes to 512-bit units. 612 */ 613 u32 bs512 = max_size / 64; 614 u8 bs = fls(bs512); 615 616 if (!bs) 617 return -EINVAL; 618 --bs; 619 620 /* Demand a power of two. */ 621 if ((1 << bs) != bs512) 622 return -EINVAL; 623 624 if (bs < mlxsw_sp_port->mlxsw_sp->lowest_shaper_bs || 625 bs > MLXSW_REG_QEEC_HIGHEST_SHAPER_BS) 626 return -EINVAL; 627 628 *p_burst_size = bs; 629 return 0; 630 } 631 632 static u32 633 mlxsw_sp_qdisc_tbf_max_size(u8 bs) 634 { 635 return (1U << bs) * 64; 636 } 637 638 static u64 639 mlxsw_sp_qdisc_tbf_rate_kbps(struct tc_tbf_qopt_offload_replace_params *p) 640 { 641 /* TBF interface is in bytes/s, whereas Spectrum ASIC is configured in 642 * Kbits/s. 643 */ 644 return div_u64(p->rate.rate_bytes_ps, 1000) * 8; 645 } 646 647 static int 648 mlxsw_sp_qdisc_tbf_check_params(struct mlxsw_sp_port *mlxsw_sp_port, 649 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 650 void *params) 651 { 652 struct tc_tbf_qopt_offload_replace_params *p = params; 653 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 654 u64 rate_kbps = mlxsw_sp_qdisc_tbf_rate_kbps(p); 655 u8 burst_size; 656 int err; 657 658 if (rate_kbps >= MLXSW_REG_QEEC_MAS_DIS) { 659 dev_err(mlxsw_sp_port->mlxsw_sp->bus_info->dev, 660 "spectrum: TBF: rate of %lluKbps must be below %u\n", 661 rate_kbps, MLXSW_REG_QEEC_MAS_DIS); 662 return -EINVAL; 663 } 664 665 err = mlxsw_sp_qdisc_tbf_bs(mlxsw_sp_port, p->max_size, &burst_size); 666 if (err) { 667 u8 highest_shaper_bs = MLXSW_REG_QEEC_HIGHEST_SHAPER_BS; 668 669 dev_err(mlxsw_sp->bus_info->dev, 670 "spectrum: TBF: invalid burst size of %u, must be a power of two between %u and %u", 671 p->max_size, 672 mlxsw_sp_qdisc_tbf_max_size(mlxsw_sp->lowest_shaper_bs), 673 mlxsw_sp_qdisc_tbf_max_size(highest_shaper_bs)); 674 return -EINVAL; 675 } 676 677 return 0; 678 } 679 680 static int 681 mlxsw_sp_qdisc_tbf_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 682 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 683 void *params) 684 { 685 struct tc_tbf_qopt_offload_replace_params *p = params; 686 u64 rate_kbps = mlxsw_sp_qdisc_tbf_rate_kbps(p); 687 u8 burst_size; 688 int err; 689 690 err = mlxsw_sp_qdisc_tbf_bs(mlxsw_sp_port, p->max_size, &burst_size); 691 if (WARN_ON_ONCE(err)) 692 /* check_params above was supposed to reject this value. */ 693 return -EINVAL; 694 695 /* Configure subgroup shaper, so that both UC and MC traffic is subject 696 * to shaping. That is unlike RED, however UC queue lengths are going to 697 * be different than MC ones due to different pool and quota 698 * configurations, so the configuration is not applicable. For shaper on 699 * the other hand, subjecting the overall stream to the configured 700 * shaper makes sense. Also note that that is what we do for 701 * ieee_setmaxrate(). 702 */ 703 return mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 704 MLXSW_REG_QEEC_HR_SUBGROUP, 705 mlxsw_sp_qdisc->tclass_num, 0, 706 rate_kbps, burst_size); 707 } 708 709 static void 710 mlxsw_sp_qdisc_tbf_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, 711 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 712 void *params) 713 { 714 struct tc_tbf_qopt_offload_replace_params *p = params; 715 716 mlxsw_sp_qdisc_leaf_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, p->qstats); 717 } 718 719 static int 720 mlxsw_sp_qdisc_get_tbf_stats(struct mlxsw_sp_port *mlxsw_sp_port, 721 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 722 struct tc_qopt_offload_stats *stats_ptr) 723 { 724 mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 725 stats_ptr); 726 return 0; 727 } 728 729 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_tbf = { 730 .type = MLXSW_SP_QDISC_TBF, 731 .check_params = mlxsw_sp_qdisc_tbf_check_params, 732 .replace = mlxsw_sp_qdisc_tbf_replace, 733 .unoffload = mlxsw_sp_qdisc_tbf_unoffload, 734 .destroy = mlxsw_sp_qdisc_tbf_destroy, 735 .get_stats = mlxsw_sp_qdisc_get_tbf_stats, 736 .clean_stats = mlxsw_sp_setup_tc_qdisc_leaf_clean_stats, 737 }; 738 739 int mlxsw_sp_setup_tc_tbf(struct mlxsw_sp_port *mlxsw_sp_port, 740 struct tc_tbf_qopt_offload *p) 741 { 742 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; 743 744 mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false); 745 if (!mlxsw_sp_qdisc) 746 return -EOPNOTSUPP; 747 748 if (p->command == TC_TBF_REPLACE) 749 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, 750 mlxsw_sp_qdisc, 751 &mlxsw_sp_qdisc_ops_tbf, 752 &p->replace_params); 753 754 if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle, 755 MLXSW_SP_QDISC_TBF)) 756 return -EOPNOTSUPP; 757 758 switch (p->command) { 759 case TC_TBF_DESTROY: 760 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc); 761 case TC_TBF_STATS: 762 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 763 &p->stats); 764 default: 765 return -EOPNOTSUPP; 766 } 767 } 768 769 static int 770 mlxsw_sp_qdisc_fifo_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 771 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 772 { 773 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 774 struct mlxsw_sp_qdisc *root_qdisc = &qdisc_state->root_qdisc; 775 776 if (root_qdisc != mlxsw_sp_qdisc) 777 root_qdisc->stats_base.backlog -= 778 mlxsw_sp_qdisc->stats_base.backlog; 779 return 0; 780 } 781 782 static int 783 mlxsw_sp_qdisc_fifo_check_params(struct mlxsw_sp_port *mlxsw_sp_port, 784 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 785 void *params) 786 { 787 return 0; 788 } 789 790 static int 791 mlxsw_sp_qdisc_fifo_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 792 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 793 void *params) 794 { 795 return 0; 796 } 797 798 static int 799 mlxsw_sp_qdisc_get_fifo_stats(struct mlxsw_sp_port *mlxsw_sp_port, 800 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 801 struct tc_qopt_offload_stats *stats_ptr) 802 { 803 mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 804 stats_ptr); 805 return 0; 806 } 807 808 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_fifo = { 809 .type = MLXSW_SP_QDISC_FIFO, 810 .check_params = mlxsw_sp_qdisc_fifo_check_params, 811 .replace = mlxsw_sp_qdisc_fifo_replace, 812 .destroy = mlxsw_sp_qdisc_fifo_destroy, 813 .get_stats = mlxsw_sp_qdisc_get_fifo_stats, 814 .clean_stats = mlxsw_sp_setup_tc_qdisc_leaf_clean_stats, 815 }; 816 817 int mlxsw_sp_setup_tc_fifo(struct mlxsw_sp_port *mlxsw_sp_port, 818 struct tc_fifo_qopt_offload *p) 819 { 820 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 821 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; 822 int tclass, child_index; 823 u32 parent_handle; 824 825 /* Invisible FIFOs are tracked in future_handle and future_fifos. Make 826 * sure that not more than one qdisc is created for a port at a time. 827 * RTNL is a simple proxy for that. 828 */ 829 ASSERT_RTNL(); 830 831 mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false); 832 if (!mlxsw_sp_qdisc && p->handle == TC_H_UNSPEC) { 833 parent_handle = TC_H_MAJ(p->parent); 834 if (parent_handle != qdisc_state->future_handle) { 835 /* This notifications is for a different Qdisc than 836 * previously. Wipe the future cache. 837 */ 838 memset(qdisc_state->future_fifos, 0, 839 sizeof(qdisc_state->future_fifos)); 840 qdisc_state->future_handle = parent_handle; 841 } 842 843 child_index = TC_H_MIN(p->parent); 844 tclass = MLXSW_SP_PRIO_CHILD_TO_TCLASS(child_index); 845 if (tclass < IEEE_8021QAZ_MAX_TCS) { 846 if (p->command == TC_FIFO_REPLACE) 847 qdisc_state->future_fifos[tclass] = true; 848 else if (p->command == TC_FIFO_DESTROY) 849 qdisc_state->future_fifos[tclass] = false; 850 } 851 } 852 if (!mlxsw_sp_qdisc) 853 return -EOPNOTSUPP; 854 855 if (p->command == TC_FIFO_REPLACE) { 856 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, 857 mlxsw_sp_qdisc, 858 &mlxsw_sp_qdisc_ops_fifo, NULL); 859 } 860 861 if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle, 862 MLXSW_SP_QDISC_FIFO)) 863 return -EOPNOTSUPP; 864 865 switch (p->command) { 866 case TC_FIFO_DESTROY: 867 if (p->handle == mlxsw_sp_qdisc->handle) 868 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, 869 mlxsw_sp_qdisc); 870 return 0; 871 case TC_FIFO_STATS: 872 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 873 &p->stats); 874 case TC_FIFO_REPLACE: /* Handled above. */ 875 break; 876 } 877 878 return -EOPNOTSUPP; 879 } 880 881 static int 882 __mlxsw_sp_qdisc_ets_destroy(struct mlxsw_sp_port *mlxsw_sp_port) 883 { 884 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 885 int i; 886 887 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 888 mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 889 MLXSW_SP_PORT_DEFAULT_TCLASS); 890 mlxsw_sp_port_ets_set(mlxsw_sp_port, 891 MLXSW_REG_QEEC_HR_SUBGROUP, 892 i, 0, false, 0); 893 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, 894 &qdisc_state->tclass_qdiscs[i]); 895 qdisc_state->tclass_qdiscs[i].prio_bitmap = 0; 896 } 897 898 return 0; 899 } 900 901 static int 902 mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 903 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 904 { 905 return __mlxsw_sp_qdisc_ets_destroy(mlxsw_sp_port); 906 } 907 908 static int 909 __mlxsw_sp_qdisc_ets_check_params(unsigned int nbands) 910 { 911 if (nbands > IEEE_8021QAZ_MAX_TCS) 912 return -EOPNOTSUPP; 913 914 return 0; 915 } 916 917 static int 918 mlxsw_sp_qdisc_prio_check_params(struct mlxsw_sp_port *mlxsw_sp_port, 919 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 920 void *params) 921 { 922 struct tc_prio_qopt_offload_params *p = params; 923 924 return __mlxsw_sp_qdisc_ets_check_params(p->bands); 925 } 926 927 static int 928 __mlxsw_sp_qdisc_ets_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 929 unsigned int nbands, 930 const unsigned int *quanta, 931 const unsigned int *weights, 932 const u8 *priomap) 933 { 934 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 935 struct mlxsw_sp_qdisc *child_qdisc; 936 int tclass, i, band, backlog; 937 u8 old_priomap; 938 int err; 939 940 for (band = 0; band < nbands; band++) { 941 tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band); 942 child_qdisc = &qdisc_state->tclass_qdiscs[tclass]; 943 old_priomap = child_qdisc->prio_bitmap; 944 child_qdisc->prio_bitmap = 0; 945 946 err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 947 MLXSW_REG_QEEC_HR_SUBGROUP, 948 tclass, 0, !!quanta[band], 949 weights[band]); 950 if (err) 951 return err; 952 953 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 954 if (priomap[i] == band) { 955 child_qdisc->prio_bitmap |= BIT(i); 956 if (BIT(i) & old_priomap) 957 continue; 958 err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, 959 i, tclass); 960 if (err) 961 return err; 962 } 963 } 964 if (old_priomap != child_qdisc->prio_bitmap && 965 child_qdisc->ops && child_qdisc->ops->clean_stats) { 966 backlog = child_qdisc->stats_base.backlog; 967 child_qdisc->ops->clean_stats(mlxsw_sp_port, 968 child_qdisc); 969 child_qdisc->stats_base.backlog = backlog; 970 } 971 972 if (handle == qdisc_state->future_handle && 973 qdisc_state->future_fifos[tclass]) { 974 err = mlxsw_sp_qdisc_replace(mlxsw_sp_port, TC_H_UNSPEC, 975 child_qdisc, 976 &mlxsw_sp_qdisc_ops_fifo, 977 NULL); 978 if (err) 979 return err; 980 } 981 } 982 for (; band < IEEE_8021QAZ_MAX_TCS; band++) { 983 tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band); 984 child_qdisc = &qdisc_state->tclass_qdiscs[tclass]; 985 child_qdisc->prio_bitmap = 0; 986 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, child_qdisc); 987 mlxsw_sp_port_ets_set(mlxsw_sp_port, 988 MLXSW_REG_QEEC_HR_SUBGROUP, 989 tclass, 0, false, 0); 990 } 991 992 qdisc_state->future_handle = TC_H_UNSPEC; 993 memset(qdisc_state->future_fifos, 0, sizeof(qdisc_state->future_fifos)); 994 return 0; 995 } 996 997 static int 998 mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 999 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1000 void *params) 1001 { 1002 struct tc_prio_qopt_offload_params *p = params; 1003 unsigned int zeroes[TCQ_ETS_MAX_BANDS] = {0}; 1004 1005 return __mlxsw_sp_qdisc_ets_replace(mlxsw_sp_port, handle, p->bands, 1006 zeroes, zeroes, p->priomap); 1007 } 1008 1009 static void 1010 __mlxsw_sp_qdisc_ets_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, 1011 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1012 struct gnet_stats_queue *qstats) 1013 { 1014 u64 backlog; 1015 1016 backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp, 1017 mlxsw_sp_qdisc->stats_base.backlog); 1018 qstats->backlog -= backlog; 1019 } 1020 1021 static void 1022 mlxsw_sp_qdisc_prio_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, 1023 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1024 void *params) 1025 { 1026 struct tc_prio_qopt_offload_params *p = params; 1027 1028 __mlxsw_sp_qdisc_ets_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, 1029 p->qstats); 1030 } 1031 1032 static int 1033 mlxsw_sp_qdisc_get_prio_stats(struct mlxsw_sp_port *mlxsw_sp_port, 1034 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1035 struct tc_qopt_offload_stats *stats_ptr) 1036 { 1037 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 1038 struct mlxsw_sp_qdisc *tc_qdisc; 1039 u64 tx_packets = 0; 1040 u64 tx_bytes = 0; 1041 u64 backlog = 0; 1042 u64 drops = 0; 1043 int i; 1044 1045 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 1046 tc_qdisc = &qdisc_state->tclass_qdiscs[i]; 1047 mlxsw_sp_qdisc_collect_tc_stats(mlxsw_sp_port, tc_qdisc, 1048 &tx_bytes, &tx_packets, 1049 &drops, &backlog); 1050 } 1051 1052 mlxsw_sp_qdisc_update_stats(mlxsw_sp_port->mlxsw_sp, mlxsw_sp_qdisc, 1053 tx_bytes, tx_packets, drops, backlog, 1054 stats_ptr); 1055 return 0; 1056 } 1057 1058 static void 1059 mlxsw_sp_setup_tc_qdisc_prio_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port, 1060 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 1061 { 1062 struct mlxsw_sp_qdisc_stats *stats_base; 1063 struct mlxsw_sp_port_xstats *xstats; 1064 struct rtnl_link_stats64 *stats; 1065 int i; 1066 1067 xstats = &mlxsw_sp_port->periodic_hw_stats.xstats; 1068 stats = &mlxsw_sp_port->periodic_hw_stats.stats; 1069 stats_base = &mlxsw_sp_qdisc->stats_base; 1070 1071 stats_base->tx_packets = stats->tx_packets; 1072 stats_base->tx_bytes = stats->tx_bytes; 1073 1074 stats_base->drops = 0; 1075 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 1076 stats_base->drops += mlxsw_sp_xstats_tail_drop(xstats, i); 1077 stats_base->drops += xstats->wred_drop[i]; 1078 } 1079 1080 mlxsw_sp_qdisc->stats_base.backlog = 0; 1081 } 1082 1083 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_prio = { 1084 .type = MLXSW_SP_QDISC_PRIO, 1085 .check_params = mlxsw_sp_qdisc_prio_check_params, 1086 .replace = mlxsw_sp_qdisc_prio_replace, 1087 .unoffload = mlxsw_sp_qdisc_prio_unoffload, 1088 .destroy = mlxsw_sp_qdisc_prio_destroy, 1089 .get_stats = mlxsw_sp_qdisc_get_prio_stats, 1090 .clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats, 1091 }; 1092 1093 static int 1094 mlxsw_sp_qdisc_ets_check_params(struct mlxsw_sp_port *mlxsw_sp_port, 1095 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1096 void *params) 1097 { 1098 struct tc_ets_qopt_offload_replace_params *p = params; 1099 1100 return __mlxsw_sp_qdisc_ets_check_params(p->bands); 1101 } 1102 1103 static int 1104 mlxsw_sp_qdisc_ets_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, 1105 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1106 void *params) 1107 { 1108 struct tc_ets_qopt_offload_replace_params *p = params; 1109 1110 return __mlxsw_sp_qdisc_ets_replace(mlxsw_sp_port, handle, p->bands, 1111 p->quanta, p->weights, p->priomap); 1112 } 1113 1114 static void 1115 mlxsw_sp_qdisc_ets_unoffload(struct mlxsw_sp_port *mlxsw_sp_port, 1116 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1117 void *params) 1118 { 1119 struct tc_ets_qopt_offload_replace_params *p = params; 1120 1121 __mlxsw_sp_qdisc_ets_unoffload(mlxsw_sp_port, mlxsw_sp_qdisc, 1122 p->qstats); 1123 } 1124 1125 static int 1126 mlxsw_sp_qdisc_ets_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 1127 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) 1128 { 1129 return __mlxsw_sp_qdisc_ets_destroy(mlxsw_sp_port); 1130 } 1131 1132 static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_ets = { 1133 .type = MLXSW_SP_QDISC_ETS, 1134 .check_params = mlxsw_sp_qdisc_ets_check_params, 1135 .replace = mlxsw_sp_qdisc_ets_replace, 1136 .unoffload = mlxsw_sp_qdisc_ets_unoffload, 1137 .destroy = mlxsw_sp_qdisc_ets_destroy, 1138 .get_stats = mlxsw_sp_qdisc_get_prio_stats, 1139 .clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats, 1140 }; 1141 1142 /* Linux allows linking of Qdiscs to arbitrary classes (so long as the resulting 1143 * graph is free of cycles). These operations do not change the parent handle 1144 * though, which means it can be incomplete (if there is more than one class 1145 * where the Qdisc in question is grafted) or outright wrong (if the Qdisc was 1146 * linked to a different class and then removed from the original class). 1147 * 1148 * E.g. consider this sequence of operations: 1149 * 1150 * # tc qdisc add dev swp1 root handle 1: prio 1151 * # tc qdisc add dev swp1 parent 1:3 handle 13: red limit 1000000 avpkt 10000 1152 * RED: set bandwidth to 10Mbit 1153 * # tc qdisc link dev swp1 handle 13: parent 1:2 1154 * 1155 * At this point, both 1:2 and 1:3 have the same RED Qdisc instance as their 1156 * child. But RED will still only claim that 1:3 is its parent. If it's removed 1157 * from that band, its only parent will be 1:2, but it will continue to claim 1158 * that it is in fact 1:3. 1159 * 1160 * The notification for child Qdisc replace (e.g. TC_RED_REPLACE) comes before 1161 * the notification for parent graft (e.g. TC_PRIO_GRAFT). We take the replace 1162 * notification to offload the child Qdisc, based on its parent handle, and use 1163 * the graft operation to validate that the class where the child is actually 1164 * grafted corresponds to the parent handle. If the two don't match, we 1165 * unoffload the child. 1166 */ 1167 static int 1168 __mlxsw_sp_qdisc_ets_graft(struct mlxsw_sp_port *mlxsw_sp_port, 1169 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1170 u8 band, u32 child_handle) 1171 { 1172 struct mlxsw_sp_qdisc_state *qdisc_state = mlxsw_sp_port->qdisc; 1173 int tclass_num = MLXSW_SP_PRIO_BAND_TO_TCLASS(band); 1174 struct mlxsw_sp_qdisc *old_qdisc; 1175 1176 if (band < IEEE_8021QAZ_MAX_TCS && 1177 qdisc_state->tclass_qdiscs[tclass_num].handle == child_handle) 1178 return 0; 1179 1180 if (!child_handle) { 1181 /* This is an invisible FIFO replacing the original Qdisc. 1182 * Ignore it--the original Qdisc's destroy will follow. 1183 */ 1184 return 0; 1185 } 1186 1187 /* See if the grafted qdisc is already offloaded on any tclass. If so, 1188 * unoffload it. 1189 */ 1190 old_qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port, 1191 child_handle); 1192 if (old_qdisc) 1193 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, old_qdisc); 1194 1195 mlxsw_sp_qdisc_destroy(mlxsw_sp_port, 1196 &qdisc_state->tclass_qdiscs[tclass_num]); 1197 return -EOPNOTSUPP; 1198 } 1199 1200 static int 1201 mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port, 1202 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, 1203 struct tc_prio_qopt_offload_graft_params *p) 1204 { 1205 return __mlxsw_sp_qdisc_ets_graft(mlxsw_sp_port, mlxsw_sp_qdisc, 1206 p->band, p->child_handle); 1207 } 1208 1209 int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port, 1210 struct tc_prio_qopt_offload *p) 1211 { 1212 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; 1213 1214 mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true); 1215 if (!mlxsw_sp_qdisc) 1216 return -EOPNOTSUPP; 1217 1218 if (p->command == TC_PRIO_REPLACE) 1219 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, 1220 mlxsw_sp_qdisc, 1221 &mlxsw_sp_qdisc_ops_prio, 1222 &p->replace_params); 1223 1224 if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle, 1225 MLXSW_SP_QDISC_PRIO)) 1226 return -EOPNOTSUPP; 1227 1228 switch (p->command) { 1229 case TC_PRIO_DESTROY: 1230 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc); 1231 case TC_PRIO_STATS: 1232 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 1233 &p->stats); 1234 case TC_PRIO_GRAFT: 1235 return mlxsw_sp_qdisc_prio_graft(mlxsw_sp_port, mlxsw_sp_qdisc, 1236 &p->graft_params); 1237 default: 1238 return -EOPNOTSUPP; 1239 } 1240 } 1241 1242 int mlxsw_sp_setup_tc_ets(struct mlxsw_sp_port *mlxsw_sp_port, 1243 struct tc_ets_qopt_offload *p) 1244 { 1245 struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; 1246 1247 mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true); 1248 if (!mlxsw_sp_qdisc) 1249 return -EOPNOTSUPP; 1250 1251 if (p->command == TC_ETS_REPLACE) 1252 return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, 1253 mlxsw_sp_qdisc, 1254 &mlxsw_sp_qdisc_ops_ets, 1255 &p->replace_params); 1256 1257 if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle, 1258 MLXSW_SP_QDISC_ETS)) 1259 return -EOPNOTSUPP; 1260 1261 switch (p->command) { 1262 case TC_ETS_DESTROY: 1263 return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc); 1264 case TC_ETS_STATS: 1265 return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc, 1266 &p->stats); 1267 case TC_ETS_GRAFT: 1268 return __mlxsw_sp_qdisc_ets_graft(mlxsw_sp_port, mlxsw_sp_qdisc, 1269 p->graft_params.band, 1270 p->graft_params.child_handle); 1271 default: 1272 return -EOPNOTSUPP; 1273 } 1274 } 1275 1276 struct mlxsw_sp_qevent_block { 1277 struct list_head binding_list; 1278 struct list_head mall_entry_list; 1279 struct mlxsw_sp *mlxsw_sp; 1280 }; 1281 1282 struct mlxsw_sp_qevent_binding { 1283 struct list_head list; 1284 struct mlxsw_sp_port *mlxsw_sp_port; 1285 u32 handle; 1286 int tclass_num; 1287 enum mlxsw_sp_span_trigger span_trigger; 1288 }; 1289 1290 static LIST_HEAD(mlxsw_sp_qevent_block_cb_list); 1291 1292 static int mlxsw_sp_qevent_span_configure(struct mlxsw_sp *mlxsw_sp, 1293 struct mlxsw_sp_mall_entry *mall_entry, 1294 struct mlxsw_sp_qevent_binding *qevent_binding, 1295 const struct mlxsw_sp_span_agent_parms *agent_parms, 1296 int *p_span_id) 1297 { 1298 struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port; 1299 struct mlxsw_sp_span_trigger_parms trigger_parms = {}; 1300 int span_id; 1301 int err; 1302 1303 err = mlxsw_sp_span_agent_get(mlxsw_sp, &span_id, agent_parms); 1304 if (err) 1305 return err; 1306 1307 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, true); 1308 if (err) 1309 goto err_analyzed_port_get; 1310 1311 trigger_parms.span_id = span_id; 1312 err = mlxsw_sp_span_agent_bind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port, 1313 &trigger_parms); 1314 if (err) 1315 goto err_agent_bind; 1316 1317 err = mlxsw_sp_span_trigger_enable(mlxsw_sp_port, qevent_binding->span_trigger, 1318 qevent_binding->tclass_num); 1319 if (err) 1320 goto err_trigger_enable; 1321 1322 *p_span_id = span_id; 1323 return 0; 1324 1325 err_trigger_enable: 1326 mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port, 1327 &trigger_parms); 1328 err_agent_bind: 1329 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true); 1330 err_analyzed_port_get: 1331 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 1332 return err; 1333 } 1334 1335 static void mlxsw_sp_qevent_span_deconfigure(struct mlxsw_sp *mlxsw_sp, 1336 struct mlxsw_sp_qevent_binding *qevent_binding, 1337 int span_id) 1338 { 1339 struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port; 1340 struct mlxsw_sp_span_trigger_parms trigger_parms = { 1341 .span_id = span_id, 1342 }; 1343 1344 mlxsw_sp_span_trigger_disable(mlxsw_sp_port, qevent_binding->span_trigger, 1345 qevent_binding->tclass_num); 1346 mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port, 1347 &trigger_parms); 1348 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true); 1349 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 1350 } 1351 1352 static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp, 1353 struct mlxsw_sp_mall_entry *mall_entry, 1354 struct mlxsw_sp_qevent_binding *qevent_binding) 1355 { 1356 struct mlxsw_sp_span_agent_parms agent_parms = { 1357 .to_dev = mall_entry->mirror.to_dev, 1358 }; 1359 1360 return mlxsw_sp_qevent_span_configure(mlxsw_sp, mall_entry, qevent_binding, 1361 &agent_parms, &mall_entry->mirror.span_id); 1362 } 1363 1364 static void mlxsw_sp_qevent_mirror_deconfigure(struct mlxsw_sp *mlxsw_sp, 1365 struct mlxsw_sp_mall_entry *mall_entry, 1366 struct mlxsw_sp_qevent_binding *qevent_binding) 1367 { 1368 mlxsw_sp_qevent_span_deconfigure(mlxsw_sp, qevent_binding, mall_entry->mirror.span_id); 1369 } 1370 1371 static int mlxsw_sp_qevent_trap_configure(struct mlxsw_sp *mlxsw_sp, 1372 struct mlxsw_sp_mall_entry *mall_entry, 1373 struct mlxsw_sp_qevent_binding *qevent_binding) 1374 { 1375 struct mlxsw_sp_span_agent_parms agent_parms = {}; 1376 int err; 1377 1378 err = mlxsw_sp_trap_group_policer_hw_id_get(mlxsw_sp, 1379 DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS, 1380 &agent_parms.policer_enable, 1381 &agent_parms.policer_id); 1382 if (err) 1383 return err; 1384 1385 return mlxsw_sp_qevent_span_configure(mlxsw_sp, mall_entry, qevent_binding, 1386 &agent_parms, &mall_entry->trap.span_id); 1387 } 1388 1389 static void mlxsw_sp_qevent_trap_deconfigure(struct mlxsw_sp *mlxsw_sp, 1390 struct mlxsw_sp_mall_entry *mall_entry, 1391 struct mlxsw_sp_qevent_binding *qevent_binding) 1392 { 1393 mlxsw_sp_qevent_span_deconfigure(mlxsw_sp, qevent_binding, mall_entry->trap.span_id); 1394 } 1395 1396 static int mlxsw_sp_qevent_entry_configure(struct mlxsw_sp *mlxsw_sp, 1397 struct mlxsw_sp_mall_entry *mall_entry, 1398 struct mlxsw_sp_qevent_binding *qevent_binding) 1399 { 1400 switch (mall_entry->type) { 1401 case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: 1402 return mlxsw_sp_qevent_mirror_configure(mlxsw_sp, mall_entry, qevent_binding); 1403 case MLXSW_SP_MALL_ACTION_TYPE_TRAP: 1404 return mlxsw_sp_qevent_trap_configure(mlxsw_sp, mall_entry, qevent_binding); 1405 default: 1406 /* This should have been validated away. */ 1407 WARN_ON(1); 1408 return -EOPNOTSUPP; 1409 } 1410 } 1411 1412 static void mlxsw_sp_qevent_entry_deconfigure(struct mlxsw_sp *mlxsw_sp, 1413 struct mlxsw_sp_mall_entry *mall_entry, 1414 struct mlxsw_sp_qevent_binding *qevent_binding) 1415 { 1416 switch (mall_entry->type) { 1417 case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: 1418 return mlxsw_sp_qevent_mirror_deconfigure(mlxsw_sp, mall_entry, qevent_binding); 1419 case MLXSW_SP_MALL_ACTION_TYPE_TRAP: 1420 return mlxsw_sp_qevent_trap_deconfigure(mlxsw_sp, mall_entry, qevent_binding); 1421 default: 1422 WARN_ON(1); 1423 return; 1424 } 1425 } 1426 1427 static int mlxsw_sp_qevent_binding_configure(struct mlxsw_sp_qevent_block *qevent_block, 1428 struct mlxsw_sp_qevent_binding *qevent_binding) 1429 { 1430 struct mlxsw_sp_mall_entry *mall_entry; 1431 int err; 1432 1433 list_for_each_entry(mall_entry, &qevent_block->mall_entry_list, list) { 1434 err = mlxsw_sp_qevent_entry_configure(qevent_block->mlxsw_sp, mall_entry, 1435 qevent_binding); 1436 if (err) 1437 goto err_entry_configure; 1438 } 1439 1440 return 0; 1441 1442 err_entry_configure: 1443 list_for_each_entry_continue_reverse(mall_entry, &qevent_block->mall_entry_list, list) 1444 mlxsw_sp_qevent_entry_deconfigure(qevent_block->mlxsw_sp, mall_entry, 1445 qevent_binding); 1446 return err; 1447 } 1448 1449 static void mlxsw_sp_qevent_binding_deconfigure(struct mlxsw_sp_qevent_block *qevent_block, 1450 struct mlxsw_sp_qevent_binding *qevent_binding) 1451 { 1452 struct mlxsw_sp_mall_entry *mall_entry; 1453 1454 list_for_each_entry(mall_entry, &qevent_block->mall_entry_list, list) 1455 mlxsw_sp_qevent_entry_deconfigure(qevent_block->mlxsw_sp, mall_entry, 1456 qevent_binding); 1457 } 1458 1459 static int mlxsw_sp_qevent_block_configure(struct mlxsw_sp_qevent_block *qevent_block) 1460 { 1461 struct mlxsw_sp_qevent_binding *qevent_binding; 1462 int err; 1463 1464 list_for_each_entry(qevent_binding, &qevent_block->binding_list, list) { 1465 err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding); 1466 if (err) 1467 goto err_binding_configure; 1468 } 1469 1470 return 0; 1471 1472 err_binding_configure: 1473 list_for_each_entry_continue_reverse(qevent_binding, &qevent_block->binding_list, list) 1474 mlxsw_sp_qevent_binding_deconfigure(qevent_block, qevent_binding); 1475 return err; 1476 } 1477 1478 static void mlxsw_sp_qevent_block_deconfigure(struct mlxsw_sp_qevent_block *qevent_block) 1479 { 1480 struct mlxsw_sp_qevent_binding *qevent_binding; 1481 1482 list_for_each_entry(qevent_binding, &qevent_block->binding_list, list) 1483 mlxsw_sp_qevent_binding_deconfigure(qevent_block, qevent_binding); 1484 } 1485 1486 static struct mlxsw_sp_mall_entry * 1487 mlxsw_sp_qevent_mall_entry_find(struct mlxsw_sp_qevent_block *block, unsigned long cookie) 1488 { 1489 struct mlxsw_sp_mall_entry *mall_entry; 1490 1491 list_for_each_entry(mall_entry, &block->mall_entry_list, list) 1492 if (mall_entry->cookie == cookie) 1493 return mall_entry; 1494 1495 return NULL; 1496 } 1497 1498 static int mlxsw_sp_qevent_mall_replace(struct mlxsw_sp *mlxsw_sp, 1499 struct mlxsw_sp_qevent_block *qevent_block, 1500 struct tc_cls_matchall_offload *f) 1501 { 1502 struct mlxsw_sp_mall_entry *mall_entry; 1503 struct flow_action_entry *act; 1504 int err; 1505 1506 /* It should not currently be possible to replace a matchall rule. So 1507 * this must be a new rule. 1508 */ 1509 if (!list_empty(&qevent_block->mall_entry_list)) { 1510 NL_SET_ERR_MSG(f->common.extack, "At most one filter supported"); 1511 return -EOPNOTSUPP; 1512 } 1513 if (f->rule->action.num_entries != 1) { 1514 NL_SET_ERR_MSG(f->common.extack, "Only singular actions supported"); 1515 return -EOPNOTSUPP; 1516 } 1517 if (f->common.chain_index) { 1518 NL_SET_ERR_MSG(f->common.extack, "Only chain 0 is supported"); 1519 return -EOPNOTSUPP; 1520 } 1521 if (f->common.protocol != htons(ETH_P_ALL)) { 1522 NL_SET_ERR_MSG(f->common.extack, "Protocol matching not supported"); 1523 return -EOPNOTSUPP; 1524 } 1525 1526 act = &f->rule->action.entries[0]; 1527 if (!(act->hw_stats & FLOW_ACTION_HW_STATS_DISABLED)) { 1528 NL_SET_ERR_MSG(f->common.extack, "HW counters not supported on qevents"); 1529 return -EOPNOTSUPP; 1530 } 1531 1532 mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL); 1533 if (!mall_entry) 1534 return -ENOMEM; 1535 mall_entry->cookie = f->cookie; 1536 1537 if (act->id == FLOW_ACTION_MIRRED) { 1538 mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR; 1539 mall_entry->mirror.to_dev = act->dev; 1540 } else if (act->id == FLOW_ACTION_TRAP) { 1541 mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_TRAP; 1542 } else { 1543 NL_SET_ERR_MSG(f->common.extack, "Unsupported action"); 1544 err = -EOPNOTSUPP; 1545 goto err_unsupported_action; 1546 } 1547 1548 list_add_tail(&mall_entry->list, &qevent_block->mall_entry_list); 1549 1550 err = mlxsw_sp_qevent_block_configure(qevent_block); 1551 if (err) 1552 goto err_block_configure; 1553 1554 return 0; 1555 1556 err_block_configure: 1557 list_del(&mall_entry->list); 1558 err_unsupported_action: 1559 kfree(mall_entry); 1560 return err; 1561 } 1562 1563 static void mlxsw_sp_qevent_mall_destroy(struct mlxsw_sp_qevent_block *qevent_block, 1564 struct tc_cls_matchall_offload *f) 1565 { 1566 struct mlxsw_sp_mall_entry *mall_entry; 1567 1568 mall_entry = mlxsw_sp_qevent_mall_entry_find(qevent_block, f->cookie); 1569 if (!mall_entry) 1570 return; 1571 1572 mlxsw_sp_qevent_block_deconfigure(qevent_block); 1573 1574 list_del(&mall_entry->list); 1575 kfree(mall_entry); 1576 } 1577 1578 static int mlxsw_sp_qevent_block_mall_cb(struct mlxsw_sp_qevent_block *qevent_block, 1579 struct tc_cls_matchall_offload *f) 1580 { 1581 struct mlxsw_sp *mlxsw_sp = qevent_block->mlxsw_sp; 1582 1583 switch (f->command) { 1584 case TC_CLSMATCHALL_REPLACE: 1585 return mlxsw_sp_qevent_mall_replace(mlxsw_sp, qevent_block, f); 1586 case TC_CLSMATCHALL_DESTROY: 1587 mlxsw_sp_qevent_mall_destroy(qevent_block, f); 1588 return 0; 1589 default: 1590 return -EOPNOTSUPP; 1591 } 1592 } 1593 1594 static int mlxsw_sp_qevent_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 1595 { 1596 struct mlxsw_sp_qevent_block *qevent_block = cb_priv; 1597 1598 switch (type) { 1599 case TC_SETUP_CLSMATCHALL: 1600 return mlxsw_sp_qevent_block_mall_cb(qevent_block, type_data); 1601 default: 1602 return -EOPNOTSUPP; 1603 } 1604 } 1605 1606 static struct mlxsw_sp_qevent_block *mlxsw_sp_qevent_block_create(struct mlxsw_sp *mlxsw_sp, 1607 struct net *net) 1608 { 1609 struct mlxsw_sp_qevent_block *qevent_block; 1610 1611 qevent_block = kzalloc(sizeof(*qevent_block), GFP_KERNEL); 1612 if (!qevent_block) 1613 return NULL; 1614 1615 INIT_LIST_HEAD(&qevent_block->binding_list); 1616 INIT_LIST_HEAD(&qevent_block->mall_entry_list); 1617 qevent_block->mlxsw_sp = mlxsw_sp; 1618 return qevent_block; 1619 } 1620 1621 static void 1622 mlxsw_sp_qevent_block_destroy(struct mlxsw_sp_qevent_block *qevent_block) 1623 { 1624 WARN_ON(!list_empty(&qevent_block->binding_list)); 1625 WARN_ON(!list_empty(&qevent_block->mall_entry_list)); 1626 kfree(qevent_block); 1627 } 1628 1629 static void mlxsw_sp_qevent_block_release(void *cb_priv) 1630 { 1631 struct mlxsw_sp_qevent_block *qevent_block = cb_priv; 1632 1633 mlxsw_sp_qevent_block_destroy(qevent_block); 1634 } 1635 1636 static struct mlxsw_sp_qevent_binding * 1637 mlxsw_sp_qevent_binding_create(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, int tclass_num, 1638 enum mlxsw_sp_span_trigger span_trigger) 1639 { 1640 struct mlxsw_sp_qevent_binding *binding; 1641 1642 binding = kzalloc(sizeof(*binding), GFP_KERNEL); 1643 if (!binding) 1644 return ERR_PTR(-ENOMEM); 1645 1646 binding->mlxsw_sp_port = mlxsw_sp_port; 1647 binding->handle = handle; 1648 binding->tclass_num = tclass_num; 1649 binding->span_trigger = span_trigger; 1650 return binding; 1651 } 1652 1653 static void 1654 mlxsw_sp_qevent_binding_destroy(struct mlxsw_sp_qevent_binding *binding) 1655 { 1656 kfree(binding); 1657 } 1658 1659 static struct mlxsw_sp_qevent_binding * 1660 mlxsw_sp_qevent_binding_lookup(struct mlxsw_sp_qevent_block *block, 1661 struct mlxsw_sp_port *mlxsw_sp_port, 1662 u32 handle, 1663 enum mlxsw_sp_span_trigger span_trigger) 1664 { 1665 struct mlxsw_sp_qevent_binding *qevent_binding; 1666 1667 list_for_each_entry(qevent_binding, &block->binding_list, list) 1668 if (qevent_binding->mlxsw_sp_port == mlxsw_sp_port && 1669 qevent_binding->handle == handle && 1670 qevent_binding->span_trigger == span_trigger) 1671 return qevent_binding; 1672 return NULL; 1673 } 1674 1675 static int mlxsw_sp_setup_tc_block_qevent_bind(struct mlxsw_sp_port *mlxsw_sp_port, 1676 struct flow_block_offload *f, 1677 enum mlxsw_sp_span_trigger span_trigger) 1678 { 1679 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1680 struct mlxsw_sp_qevent_binding *qevent_binding; 1681 struct mlxsw_sp_qevent_block *qevent_block; 1682 struct flow_block_cb *block_cb; 1683 struct mlxsw_sp_qdisc *qdisc; 1684 bool register_block = false; 1685 int err; 1686 1687 block_cb = flow_block_cb_lookup(f->block, mlxsw_sp_qevent_block_cb, mlxsw_sp); 1688 if (!block_cb) { 1689 qevent_block = mlxsw_sp_qevent_block_create(mlxsw_sp, f->net); 1690 if (!qevent_block) 1691 return -ENOMEM; 1692 block_cb = flow_block_cb_alloc(mlxsw_sp_qevent_block_cb, mlxsw_sp, qevent_block, 1693 mlxsw_sp_qevent_block_release); 1694 if (IS_ERR(block_cb)) { 1695 mlxsw_sp_qevent_block_destroy(qevent_block); 1696 return PTR_ERR(block_cb); 1697 } 1698 register_block = true; 1699 } else { 1700 qevent_block = flow_block_cb_priv(block_cb); 1701 } 1702 flow_block_cb_incref(block_cb); 1703 1704 qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port, f->sch->handle); 1705 if (!qdisc) { 1706 NL_SET_ERR_MSG(f->extack, "Qdisc not offloaded"); 1707 err = -ENOENT; 1708 goto err_find_qdisc; 1709 } 1710 1711 if (WARN_ON(mlxsw_sp_qevent_binding_lookup(qevent_block, mlxsw_sp_port, f->sch->handle, 1712 span_trigger))) { 1713 err = -EEXIST; 1714 goto err_binding_exists; 1715 } 1716 1717 qevent_binding = mlxsw_sp_qevent_binding_create(mlxsw_sp_port, f->sch->handle, 1718 qdisc->tclass_num, span_trigger); 1719 if (IS_ERR(qevent_binding)) { 1720 err = PTR_ERR(qevent_binding); 1721 goto err_binding_create; 1722 } 1723 1724 err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding); 1725 if (err) 1726 goto err_binding_configure; 1727 1728 list_add(&qevent_binding->list, &qevent_block->binding_list); 1729 1730 if (register_block) { 1731 flow_block_cb_add(block_cb, f); 1732 list_add_tail(&block_cb->driver_list, &mlxsw_sp_qevent_block_cb_list); 1733 } 1734 1735 return 0; 1736 1737 err_binding_configure: 1738 mlxsw_sp_qevent_binding_destroy(qevent_binding); 1739 err_binding_create: 1740 err_binding_exists: 1741 err_find_qdisc: 1742 if (!flow_block_cb_decref(block_cb)) 1743 flow_block_cb_free(block_cb); 1744 return err; 1745 } 1746 1747 static void mlxsw_sp_setup_tc_block_qevent_unbind(struct mlxsw_sp_port *mlxsw_sp_port, 1748 struct flow_block_offload *f, 1749 enum mlxsw_sp_span_trigger span_trigger) 1750 { 1751 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1752 struct mlxsw_sp_qevent_binding *qevent_binding; 1753 struct mlxsw_sp_qevent_block *qevent_block; 1754 struct flow_block_cb *block_cb; 1755 1756 block_cb = flow_block_cb_lookup(f->block, mlxsw_sp_qevent_block_cb, mlxsw_sp); 1757 if (!block_cb) 1758 return; 1759 qevent_block = flow_block_cb_priv(block_cb); 1760 1761 qevent_binding = mlxsw_sp_qevent_binding_lookup(qevent_block, mlxsw_sp_port, f->sch->handle, 1762 span_trigger); 1763 if (!qevent_binding) 1764 return; 1765 1766 list_del(&qevent_binding->list); 1767 mlxsw_sp_qevent_binding_deconfigure(qevent_block, qevent_binding); 1768 mlxsw_sp_qevent_binding_destroy(qevent_binding); 1769 1770 if (!flow_block_cb_decref(block_cb)) { 1771 flow_block_cb_remove(block_cb, f); 1772 list_del(&block_cb->driver_list); 1773 } 1774 } 1775 1776 static int mlxsw_sp_setup_tc_block_qevent(struct mlxsw_sp_port *mlxsw_sp_port, 1777 struct flow_block_offload *f, 1778 enum mlxsw_sp_span_trigger span_trigger) 1779 { 1780 f->driver_block_list = &mlxsw_sp_qevent_block_cb_list; 1781 1782 switch (f->command) { 1783 case FLOW_BLOCK_BIND: 1784 return mlxsw_sp_setup_tc_block_qevent_bind(mlxsw_sp_port, f, span_trigger); 1785 case FLOW_BLOCK_UNBIND: 1786 mlxsw_sp_setup_tc_block_qevent_unbind(mlxsw_sp_port, f, span_trigger); 1787 return 0; 1788 default: 1789 return -EOPNOTSUPP; 1790 } 1791 } 1792 1793 int mlxsw_sp_setup_tc_block_qevent_early_drop(struct mlxsw_sp_port *mlxsw_sp_port, 1794 struct flow_block_offload *f) 1795 { 1796 return mlxsw_sp_setup_tc_block_qevent(mlxsw_sp_port, f, MLXSW_SP_SPAN_TRIGGER_EARLY_DROP); 1797 } 1798 1799 int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port) 1800 { 1801 struct mlxsw_sp_qdisc_state *qdisc_state; 1802 int i; 1803 1804 qdisc_state = kzalloc(sizeof(*qdisc_state), GFP_KERNEL); 1805 if (!qdisc_state) 1806 return -ENOMEM; 1807 1808 qdisc_state->root_qdisc.prio_bitmap = 0xff; 1809 qdisc_state->root_qdisc.tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS; 1810 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 1811 qdisc_state->tclass_qdiscs[i].tclass_num = i; 1812 1813 mlxsw_sp_port->qdisc = qdisc_state; 1814 return 0; 1815 } 1816 1817 void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port) 1818 { 1819 kfree(mlxsw_sp_port->qdisc); 1820 } 1821