|
@@ -42,6 +42,8 @@
|
|
#include "reg.h"
|
|
#include "reg.h"
|
|
|
|
|
|
#define MLXSW_SP_PRIO_BAND_TO_TCLASS(band) (IEEE_8021QAZ_MAX_TCS - band - 1)
|
|
#define MLXSW_SP_PRIO_BAND_TO_TCLASS(band) (IEEE_8021QAZ_MAX_TCS - band - 1)
|
|
|
|
+#define MLXSW_SP_PRIO_CHILD_TO_TCLASS(child) \
|
|
|
|
+ MLXSW_SP_PRIO_BAND_TO_TCLASS((child - 1))
|
|
|
|
|
|
enum mlxsw_sp_qdisc_type {
|
|
enum mlxsw_sp_qdisc_type {
|
|
MLXSW_SP_QDISC_NO_QDISC,
|
|
MLXSW_SP_QDISC_NO_QDISC,
|
|
@@ -76,6 +78,7 @@ struct mlxsw_sp_qdisc_ops {
|
|
struct mlxsw_sp_qdisc {
|
|
struct mlxsw_sp_qdisc {
|
|
u32 handle;
|
|
u32 handle;
|
|
u8 tclass_num;
|
|
u8 tclass_num;
|
|
|
|
+ u8 prio_bitmap;
|
|
union {
|
|
union {
|
|
struct red_stats red;
|
|
struct red_stats red;
|
|
} xstats_base;
|
|
} xstats_base;
|
|
@@ -99,6 +102,44 @@ mlxsw_sp_qdisc_compare(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, u32 handle,
|
|
mlxsw_sp_qdisc->handle == handle;
|
|
mlxsw_sp_qdisc->handle == handle;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static struct mlxsw_sp_qdisc *
|
|
|
|
+mlxsw_sp_qdisc_find(struct mlxsw_sp_port *mlxsw_sp_port, u32 parent,
|
|
|
|
+ bool root_only)
|
|
|
|
+{
|
|
|
|
+ int tclass, child_index;
|
|
|
|
+
|
|
|
|
+ if (parent == TC_H_ROOT)
|
|
|
|
+ return mlxsw_sp_port->root_qdisc;
|
|
|
|
+
|
|
|
|
+ if (root_only || !mlxsw_sp_port->root_qdisc ||
|
|
|
|
+ !mlxsw_sp_port->root_qdisc->ops ||
|
|
|
|
+ TC_H_MAJ(parent) != mlxsw_sp_port->root_qdisc->handle ||
|
|
|
|
+ TC_H_MIN(parent) > IEEE_8021QAZ_MAX_TCS)
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ child_index = TC_H_MIN(parent);
|
|
|
|
+ tclass = MLXSW_SP_PRIO_CHILD_TO_TCLASS(child_index);
|
|
|
|
+ return &mlxsw_sp_port->tclass_qdiscs[tclass];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct mlxsw_sp_qdisc *
|
|
|
|
+mlxsw_sp_qdisc_find_by_handle(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if (mlxsw_sp_port->root_qdisc->handle == handle)
|
|
|
|
+ return mlxsw_sp_port->root_qdisc;
|
|
|
|
+
|
|
|
|
+ if (mlxsw_sp_port->root_qdisc->handle == TC_H_UNSPEC)
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
|
|
|
|
+ if (mlxsw_sp_port->tclass_qdiscs[i].handle == handle)
|
|
|
|
+ return &mlxsw_sp_port->tclass_qdiscs[i];
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
static int
|
|
static int
|
|
mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
|
@@ -185,6 +226,23 @@ mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+mlxsw_sp_qdisc_bstats_per_priority_get(struct mlxsw_sp_port_xstats *xstats,
|
|
|
|
+ u8 prio_bitmap, u64 *tx_packets,
|
|
|
|
+ u64 *tx_bytes)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ *tx_packets = 0;
|
|
|
|
+ *tx_bytes = 0;
|
|
|
|
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
|
|
+ if (prio_bitmap & BIT(i)) {
|
|
|
|
+ *tx_packets += xstats->tx_packets[i];
|
|
|
|
+ *tx_bytes += xstats->tx_bytes[i];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static int
|
|
static int
|
|
mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
int tclass_num, u32 min, u32 max,
|
|
int tclass_num, u32 min, u32 max,
|
|
@@ -230,17 +288,16 @@ mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
|
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
|
struct mlxsw_sp_qdisc_stats *stats_base;
|
|
struct mlxsw_sp_qdisc_stats *stats_base;
|
|
struct mlxsw_sp_port_xstats *xstats;
|
|
struct mlxsw_sp_port_xstats *xstats;
|
|
- struct rtnl_link_stats64 *stats;
|
|
|
|
struct red_stats *red_base;
|
|
struct red_stats *red_base;
|
|
|
|
|
|
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
|
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
|
- stats = &mlxsw_sp_port->periodic_hw_stats.stats;
|
|
|
|
stats_base = &mlxsw_sp_qdisc->stats_base;
|
|
stats_base = &mlxsw_sp_qdisc->stats_base;
|
|
red_base = &mlxsw_sp_qdisc->xstats_base.red;
|
|
red_base = &mlxsw_sp_qdisc->xstats_base.red;
|
|
|
|
|
|
- stats_base->tx_packets = stats->tx_packets;
|
|
|
|
- stats_base->tx_bytes = stats->tx_bytes;
|
|
|
|
-
|
|
|
|
|
|
+ mlxsw_sp_qdisc_bstats_per_priority_get(xstats,
|
|
|
|
+ mlxsw_sp_qdisc->prio_bitmap,
|
|
|
|
+ &stats_base->tx_packets,
|
|
|
|
+ &stats_base->tx_bytes);
|
|
red_base->prob_mark = xstats->ecn;
|
|
red_base->prob_mark = xstats->ecn;
|
|
red_base->prob_drop = xstats->wred_drop[tclass_num];
|
|
red_base->prob_drop = xstats->wred_drop[tclass_num];
|
|
red_base->pdrop = xstats->tail_drop[tclass_num];
|
|
red_base->pdrop = xstats->tail_drop[tclass_num];
|
|
@@ -255,6 +312,12 @@ static int
|
|
mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
|
{
|
|
{
|
|
|
|
+ struct mlxsw_sp_qdisc *root_qdisc = mlxsw_sp_port->root_qdisc;
|
|
|
|
+
|
|
|
|
+ if (root_qdisc != mlxsw_sp_qdisc)
|
|
|
|
+ root_qdisc->stats_base.backlog -=
|
|
|
|
+ mlxsw_sp_qdisc->stats_base.backlog;
|
|
|
|
+
|
|
return mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port,
|
|
return mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port,
|
|
mlxsw_sp_qdisc->tclass_num);
|
|
mlxsw_sp_qdisc->tclass_num);
|
|
}
|
|
}
|
|
@@ -319,6 +382,7 @@ mlxsw_sp_qdisc_red_unoffload(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
|
|
backlog = mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
|
|
mlxsw_sp_qdisc->stats_base.backlog);
|
|
mlxsw_sp_qdisc->stats_base.backlog);
|
|
p->qstats->backlog -= backlog;
|
|
p->qstats->backlog -= backlog;
|
|
|
|
+ mlxsw_sp_qdisc->stats_base.backlog = 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
@@ -357,14 +421,16 @@ mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
|
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
|
struct mlxsw_sp_qdisc_stats *stats_base;
|
|
struct mlxsw_sp_qdisc_stats *stats_base;
|
|
struct mlxsw_sp_port_xstats *xstats;
|
|
struct mlxsw_sp_port_xstats *xstats;
|
|
- struct rtnl_link_stats64 *stats;
|
|
|
|
|
|
|
|
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
|
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
|
- stats = &mlxsw_sp_port->periodic_hw_stats.stats;
|
|
|
|
stats_base = &mlxsw_sp_qdisc->stats_base;
|
|
stats_base = &mlxsw_sp_qdisc->stats_base;
|
|
|
|
|
|
- tx_bytes = stats->tx_bytes - stats_base->tx_bytes;
|
|
|
|
- tx_packets = stats->tx_packets - stats_base->tx_packets;
|
|
|
|
|
|
+ mlxsw_sp_qdisc_bstats_per_priority_get(xstats,
|
|
|
|
+ mlxsw_sp_qdisc->prio_bitmap,
|
|
|
|
+ &tx_packets, &tx_bytes);
|
|
|
|
+ tx_bytes = tx_bytes - stats_base->tx_bytes;
|
|
|
|
+ tx_packets = tx_packets - stats_base->tx_packets;
|
|
|
|
+
|
|
overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
|
|
overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
|
|
stats_base->overlimits;
|
|
stats_base->overlimits;
|
|
drops = xstats->wred_drop[tclass_num] + xstats->tail_drop[tclass_num] -
|
|
drops = xstats->wred_drop[tclass_num] + xstats->tail_drop[tclass_num] -
|
|
@@ -406,11 +472,10 @@ int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
{
|
|
{
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
|
|
|
|
|
|
- if (p->parent != TC_H_ROOT)
|
|
|
|
|
|
+ mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, false);
|
|
|
|
+ if (!mlxsw_sp_qdisc)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- mlxsw_sp_qdisc = mlxsw_sp_port->root_qdisc;
|
|
|
|
-
|
|
|
|
if (p->command == TC_RED_REPLACE)
|
|
if (p->command == TC_RED_REPLACE)
|
|
return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
|
|
return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
|
|
mlxsw_sp_qdisc,
|
|
mlxsw_sp_qdisc,
|
|
@@ -441,9 +506,13 @@ mlxsw_sp_qdisc_prio_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
|
|
|
|
|
|
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
|
|
mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
|
|
MLXSW_SP_PORT_DEFAULT_TCLASS);
|
|
MLXSW_SP_PORT_DEFAULT_TCLASS);
|
|
|
|
+ mlxsw_sp_qdisc_destroy(mlxsw_sp_port,
|
|
|
|
+ &mlxsw_sp_port->tclass_qdiscs[i]);
|
|
|
|
+ mlxsw_sp_port->tclass_qdiscs[i].prio_bitmap = 0;
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -467,16 +536,41 @@ mlxsw_sp_qdisc_prio_replace(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
void *params)
|
|
void *params)
|
|
{
|
|
{
|
|
struct tc_prio_qopt_offload_params *p = params;
|
|
struct tc_prio_qopt_offload_params *p = params;
|
|
- int tclass, i;
|
|
|
|
|
|
+ struct mlxsw_sp_qdisc *child_qdisc;
|
|
|
|
+ int tclass, i, band, backlog;
|
|
|
|
+ u8 old_priomap;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
- for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
|
|
- tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(p->priomap[i]);
|
|
|
|
- err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, tclass);
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
|
|
+ for (band = 0; band < p->bands; band++) {
|
|
|
|
+ tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
|
|
|
|
+ child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass];
|
|
|
|
+ old_priomap = child_qdisc->prio_bitmap;
|
|
|
|
+ child_qdisc->prio_bitmap = 0;
|
|
|
|
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
|
|
+ if (p->priomap[i] == band) {
|
|
|
|
+ child_qdisc->prio_bitmap |= BIT(i);
|
|
|
|
+ if (BIT(i) & old_priomap)
|
|
|
|
+ continue;
|
|
|
|
+ err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port,
|
|
|
|
+ i, tclass);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (old_priomap != child_qdisc->prio_bitmap &&
|
|
|
|
+ child_qdisc->ops && child_qdisc->ops->clean_stats) {
|
|
|
|
+ backlog = child_qdisc->stats_base.backlog;
|
|
|
|
+ child_qdisc->ops->clean_stats(mlxsw_sp_port,
|
|
|
|
+ child_qdisc);
|
|
|
|
+ child_qdisc->stats_base.backlog = backlog;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for (; band < IEEE_8021QAZ_MAX_TCS; band++) {
|
|
|
|
+ tclass = MLXSW_SP_PRIO_BAND_TO_TCLASS(band);
|
|
|
|
+ child_qdisc = &mlxsw_sp_port->tclass_qdiscs[tclass];
|
|
|
|
+ child_qdisc->prio_bitmap = 0;
|
|
|
|
+ mlxsw_sp_qdisc_destroy(mlxsw_sp_port, child_qdisc);
|
|
}
|
|
}
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -513,6 +607,7 @@ mlxsw_sp_qdisc_get_prio_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
|
|
|
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
drops += xstats->tail_drop[i];
|
|
drops += xstats->tail_drop[i];
|
|
|
|
+ drops += xstats->wred_drop[i];
|
|
backlog += xstats->backlog[i];
|
|
backlog += xstats->backlog[i];
|
|
}
|
|
}
|
|
drops = drops - stats_base->drops;
|
|
drops = drops - stats_base->drops;
|
|
@@ -548,8 +643,10 @@ mlxsw_sp_setup_tc_qdisc_prio_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
stats_base->tx_bytes = stats->tx_bytes;
|
|
stats_base->tx_bytes = stats->tx_bytes;
|
|
|
|
|
|
stats_base->drops = 0;
|
|
stats_base->drops = 0;
|
|
- for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
|
|
|
|
|
|
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
|
stats_base->drops += xstats->tail_drop[i];
|
|
stats_base->drops += xstats->tail_drop[i];
|
|
|
|
+ stats_base->drops += xstats->wred_drop[i];
|
|
|
|
+ }
|
|
|
|
|
|
mlxsw_sp_qdisc->stats_base.backlog = 0;
|
|
mlxsw_sp_qdisc->stats_base.backlog = 0;
|
|
}
|
|
}
|
|
@@ -564,15 +661,48 @@ static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_prio = {
|
|
.clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats,
|
|
.clean_stats = mlxsw_sp_setup_tc_qdisc_prio_clean_stats,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/* Grafting is not supported in mlxsw. It will result in un-offloading of the
|
|
|
|
+ * grafted qdisc as well as the qdisc in the qdisc new location.
|
|
|
|
+ * (However, if the graft is to the location where the qdisc is already at, it
|
|
|
|
+ * will be ignored completely and won't cause un-offloading).
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
|
+ struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
|
|
|
+ struct tc_prio_qopt_offload_graft_params *p)
|
|
|
|
+{
|
|
|
|
+ int tclass_num = MLXSW_SP_PRIO_BAND_TO_TCLASS(p->band);
|
|
|
|
+ struct mlxsw_sp_qdisc *old_qdisc;
|
|
|
|
+
|
|
|
|
+ /* Check if the grafted qdisc is already in its "new" location. If so -
|
|
|
|
+ * nothing needs to be done.
|
|
|
|
+ */
|
|
|
|
+ if (p->band < IEEE_8021QAZ_MAX_TCS &&
|
|
|
|
+ mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == p->child_handle)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* See if the grafted qdisc is already offloaded on any tclass. If so,
|
|
|
|
+ * unoffload it.
|
|
|
|
+ */
|
|
|
|
+ old_qdisc = mlxsw_sp_qdisc_find_by_handle(mlxsw_sp_port,
|
|
|
|
+ p->child_handle);
|
|
|
|
+ if (old_qdisc)
|
|
|
|
+ mlxsw_sp_qdisc_destroy(mlxsw_sp_port, old_qdisc);
|
|
|
|
+
|
|
|
|
+ mlxsw_sp_qdisc_destroy(mlxsw_sp_port,
|
|
|
|
+ &mlxsw_sp_port->tclass_qdiscs[tclass_num]);
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+}
|
|
|
|
+
|
|
int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
struct tc_prio_qopt_offload *p)
|
|
struct tc_prio_qopt_offload *p)
|
|
{
|
|
{
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
|
|
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
|
|
|
|
|
|
- if (p->parent != TC_H_ROOT)
|
|
|
|
|
|
+ mlxsw_sp_qdisc = mlxsw_sp_qdisc_find(mlxsw_sp_port, p->parent, true);
|
|
|
|
+ if (!mlxsw_sp_qdisc)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- mlxsw_sp_qdisc = mlxsw_sp_port->root_qdisc;
|
|
|
|
if (p->command == TC_PRIO_REPLACE)
|
|
if (p->command == TC_PRIO_REPLACE)
|
|
return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
|
|
return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
|
|
mlxsw_sp_qdisc,
|
|
mlxsw_sp_qdisc,
|
|
@@ -589,6 +719,9 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
case TC_PRIO_STATS:
|
|
case TC_PRIO_STATS:
|
|
return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
|
|
return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
|
|
&p->stats);
|
|
&p->stats);
|
|
|
|
+ case TC_PRIO_GRAFT:
|
|
|
|
+ return mlxsw_sp_qdisc_prio_graft(mlxsw_sp_port, mlxsw_sp_qdisc,
|
|
|
|
+ &p->graft_params);
|
|
default:
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
}
|
|
}
|
|
@@ -596,17 +729,36 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
|
|
|
int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port)
|
|
int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port)
|
|
{
|
|
{
|
|
- mlxsw_sp_port->root_qdisc = kzalloc(sizeof(*mlxsw_sp_port->root_qdisc),
|
|
|
|
- GFP_KERNEL);
|
|
|
|
- if (!mlxsw_sp_port->root_qdisc)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
|
|
|
|
+ int i;
|
|
|
|
|
|
|
|
+ mlxsw_sp_qdisc = kzalloc(sizeof(*mlxsw_sp_qdisc), GFP_KERNEL);
|
|
|
|
+ if (!mlxsw_sp_qdisc)
|
|
|
|
+ goto err_root_qdisc_init;
|
|
|
|
+
|
|
|
|
+ mlxsw_sp_port->root_qdisc = mlxsw_sp_qdisc;
|
|
|
|
+ mlxsw_sp_port->root_qdisc->prio_bitmap = 0xff;
|
|
mlxsw_sp_port->root_qdisc->tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS;
|
|
mlxsw_sp_port->root_qdisc->tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS;
|
|
|
|
|
|
|
|
+ mlxsw_sp_qdisc = kzalloc(sizeof(*mlxsw_sp_qdisc) * IEEE_8021QAZ_MAX_TCS,
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
+ if (!mlxsw_sp_qdisc)
|
|
|
|
+ goto err_tclass_qdiscs_init;
|
|
|
|
+
|
|
|
|
+ mlxsw_sp_port->tclass_qdiscs = mlxsw_sp_qdisc;
|
|
|
|
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
|
|
|
|
+ mlxsw_sp_port->tclass_qdiscs[i].tclass_num = i;
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+err_tclass_qdiscs_init:
|
|
|
|
+ kfree(mlxsw_sp_port->root_qdisc);
|
|
|
|
+err_root_qdisc_init:
|
|
|
|
+ return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
|
|
void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
|
|
{
|
|
{
|
|
|
|
+ kfree(mlxsw_sp_port->tclass_qdiscs);
|
|
kfree(mlxsw_sp_port->root_qdisc);
|
|
kfree(mlxsw_sp_port->root_qdisc);
|
|
}
|
|
}
|