diff options
author | Nogah Frankel <nogahf@mellanox.com> | 2018-02-28 04:44:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-28 12:06:00 -0500 |
commit | eed4baeb040aa41323d0091c18d36cc5a895792d (patch) | |
tree | a2a090d7370cb555ef226eaed3a8ad04e32b8e04 | |
parent | 56beda3db6020428885f0589a0ac16768ea94543 (diff) |
mlxsw: spectrum: qdiscs: Support qdisc per tclass
Add the option to set a qdisc per tclass. Match the qdisc to the tclass by
parent ID. Supported currently for sch_red only.
It allows offloading sch_prio as root qdisc and sch_red as its child.
(However, doing so might corrupt the stats for both parent and child.)
Signed-off-by: Nogah Frankel <nogahf@mellanox.com>
Reviewed-by: Yuval Mintz <yuvalm@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c | 62 |
2 files changed, 53 insertions, 10 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 2673310f92da..cc9786ff3b05 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h | |||
@@ -247,6 +247,7 @@ struct mlxsw_sp_port { | |||
247 | struct mlxsw_sp_port_sample *sample; | 247 | struct mlxsw_sp_port_sample *sample; |
248 | struct list_head vlans_list; | 248 | struct list_head vlans_list; |
249 | struct mlxsw_sp_qdisc *root_qdisc; | 249 | struct mlxsw_sp_qdisc *root_qdisc; |
250 | struct mlxsw_sp_qdisc *tclass_qdiscs; | ||
250 | unsigned acl_rule_count; | 251 | unsigned acl_rule_count; |
251 | struct mlxsw_sp_acl_block *ing_acl_block; | 252 | struct mlxsw_sp_acl_block *ing_acl_block; |
252 | struct mlxsw_sp_acl_block *eg_acl_block; | 253 | struct mlxsw_sp_acl_block *eg_acl_block; |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index 0b7670459051..858846a019ae 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include "reg.h" | 42 | #include "reg.h" |
43 | 43 | ||
44 | #define MLXSW_SP_PRIO_BAND_TO_TCLASS(band) (IEEE_8021QAZ_MAX_TCS - band - 1) | 44 | #define MLXSW_SP_PRIO_BAND_TO_TCLASS(band) (IEEE_8021QAZ_MAX_TCS - band - 1) |
45 | #define MLXSW_SP_PRIO_CHILD_TO_TCLASS(child) \ | ||
46 | MLXSW_SP_PRIO_BAND_TO_TCLASS((child - 1)) | ||
45 | 47 | ||
46 | enum mlxsw_sp_qdisc_type { | 48 | enum mlxsw_sp_qdisc_type { |
47 | MLXSW_SP_QDISC_NO_QDISC, | 49 | MLXSW_SP_QDISC_NO_QDISC, |
@@ -99,6 +101,26 @@ mlxsw_sp_qdisc_compare(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, u32 handle, | |||
99 | mlxsw_sp_qdisc->handle == handle; | 101 | mlxsw_sp_qdisc->handle == handle; |
100 | } | 102 | } |
101 | 103 | ||
104 | static struct mlxsw_sp_qdisc * | ||
105 | mlxsw_sp_qdisc_find(struct mlxsw_sp_port *mlxsw_sp_port, u32 parent, | ||
106 | bool root_only) | ||
107 | { | ||
108 | int tclass, child_index; | ||
109 | |||
110 | if (parent == TC_H_ROOT) | ||
111 | return mlxsw_sp_port->root_qdisc; | ||
112 | |||
113 | if (root_only || !mlxsw_sp_port->root_qdisc || | ||
114 | !mlxsw_sp_port->root_qdisc->ops || | ||
115 | TC_H_MAJ(parent) != mlxsw_sp_port->root_qdisc->handle || | ||
116 | TC_H_MIN(parent) > IEEE_8021QAZ_MAX_TCS) | ||
117 | return NULL; | ||
118 | |||
119 | child_index = TC_H_MIN(parent); | ||
120 | tclass = MLXSW_SP_PRIO_CHILD_TO_TCLASS(child_index); | ||
121 | return &mlxsw_sp_port->tclass_qdiscs[tclass]; | ||
122 | } | ||
123 | |||
102 | static int | 124 | static int |
103 | mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port, | 125 | mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port, |
104 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) | 126 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc) |
@@ -406,11 +428,10 @@ int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port, | |||
406 | { | 428 | { |
407 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; | 429 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; |
408 | 430 | ||
409 | if (p->parent != TC_H_ROOT) | 431 | mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false); |
432 | if (!mlxsw_sp_qdisc) | ||
410 | return -EOPNOTSUPP; | 433 | return -EOPNOTSUPP; |
411 | 434 | ||
412 | mlxsw_sp_qdisc = mlxsw_sp_port->root_qdisc; | ||
413 | |||
414 | if (p->command == TC_RED_REPLACE) | 435 | if (p->command == TC_RED_REPLACE) |
415 | return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, | 436 | return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, |
416 | mlxsw_sp_qdisc, | 437 | mlxsw_sp_qdisc, |
@@ -441,9 +462,12 @@ mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port, | |||
441 | { | 462 | { |
442 | int i; | 463 | int i; |
443 | 464 | ||
444 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | 465 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
445 | mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, | 466 | mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, |
446 | MLXSW_SP_PORT_DEFAULT_TCLASS); | 467 | MLXSW_SP_PORT_DEFAULT_TCLASS); |
468 | mlxsw_sp_qdisc_destroy(mlxsw_sp_port, | ||
469 | &mlxsw_sp_port->tclass_qdiscs[i]); | ||
470 | } | ||
447 | 471 | ||
448 | return 0; | 472 | return 0; |
449 | } | 473 | } |
@@ -569,10 +593,10 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port, | |||
569 | { | 593 | { |
570 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; | 594 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; |
571 | 595 | ||
572 | if (p->parent != TC_H_ROOT) | 596 | mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true); |
597 | if (!mlxsw_sp_qdisc) | ||
573 | return -EOPNOTSUPP; | 598 | return -EOPNOTSUPP; |
574 | 599 | ||
575 | mlxsw_sp_qdisc = mlxsw_sp_port->root_qdisc; | ||
576 | if (p->command == TC_PRIO_REPLACE) | 600 | if (p->command == TC_PRIO_REPLACE) |
577 | return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, | 601 | return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle, |
578 | mlxsw_sp_qdisc, | 602 | mlxsw_sp_qdisc, |
@@ -596,17 +620,35 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port, | |||
596 | 620 | ||
597 | int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port) | 621 | int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port) |
598 | { | 622 | { |
599 | mlxsw_sp_port->root_qdisc = kzalloc(sizeof(*mlxsw_sp_port->root_qdisc), | 623 | struct mlxsw_sp_qdisc *mlxsw_sp_qdisc; |
600 | GFP_KERNEL); | 624 | int i; |
601 | if (!mlxsw_sp_port->root_qdisc) | ||
602 | return -ENOMEM; | ||
603 | 625 | ||
626 | mlxsw_sp_qdisc = kzalloc(sizeof(*mlxsw_sp_qdisc), GFP_KERNEL); | ||
627 | if (!mlxsw_sp_qdisc) | ||
628 | goto err_root_qdisc_init; | ||
629 | |||
630 | mlxsw_sp_port->root_qdisc = mlxsw_sp_qdisc; | ||
604 | mlxsw_sp_port->root_qdisc->tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS; | 631 | mlxsw_sp_port->root_qdisc->tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS; |
605 | 632 | ||
633 | mlxsw_sp_qdisc = kzalloc(sizeof(*mlxsw_sp_qdisc) * IEEE_8021QAZ_MAX_TCS, | ||
634 | GFP_KERNEL); | ||
635 | if (!mlxsw_sp_qdisc) | ||
636 | goto err_tclass_qdiscs_init; | ||
637 | |||
638 | mlxsw_sp_port->tclass_qdiscs = mlxsw_sp_qdisc; | ||
639 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | ||
640 | mlxsw_sp_port->tclass_qdiscs[i].tclass_num = i; | ||
641 | |||
606 | return 0; | 642 | return 0; |
643 | |||
644 | err_tclass_qdiscs_init: | ||
645 | kfree(mlxsw_sp_port->root_qdisc); | ||
646 | err_root_qdisc_init: | ||
647 | return -ENOMEM; | ||
607 | } | 648 | } |
608 | 649 | ||
609 | void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port) | 650 | void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port) |
610 | { | 651 | { |
652 | kfree(mlxsw_sp_port->tclass_qdiscs); | ||
611 | kfree(mlxsw_sp_port->root_qdisc); | 653 | kfree(mlxsw_sp_port->root_qdisc); |
612 | } | 654 | } |