Merge branch 'mlxsw-qdisc-refactoring'
Jiri Pirko says: ==================== mlxsw qdisc refactoring This patchset refactors the qdisc handling in mlxsw driver in order to make it more object oriented like. It helps readability, laying the groundwork for the offloading of additional qdiscs by the driver This patchset also makes the qdiscs statistics more generic. Patch 1 moves the qdiscs declaration to the spectrum_qdisc.c Patches 2-3 clean the offloaded stats requests. Patch 2 changes the RED generic stats struct to be sharable by other offloaded qdiscs. Patch 3 changes the xstats request to be like the stats. Note that these patches are outside the driver scope. Patches 4-5 clean the statistics related functions and structs within the driver. Patches 6-7 decrease the need for the same parameters to be sent to many functions. Patches 8-11 create a functions pointers struct, to make the qdiscs handling more object oriented like. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c92342b0bf
|
@ -3085,6 +3085,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
|||
goto err_port_fids_init;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_tc_qdisc_init(mlxsw_sp_port);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC qdiscs\n",
|
||||
mlxsw_sp_port->local_port);
|
||||
goto err_port_qdiscs_init;
|
||||
}
|
||||
|
||||
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
|
||||
if (IS_ERR(mlxsw_sp_port_vlan)) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",
|
||||
|
@ -3113,6 +3120,8 @@ err_register_netdev:
|
|||
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
|
||||
err_port_vlan_get:
|
||||
mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
|
||||
err_port_qdiscs_init:
|
||||
mlxsw_sp_port_fids_fini(mlxsw_sp_port);
|
||||
err_port_fids_init:
|
||||
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
|
||||
|
@ -3148,6 +3157,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
|||
mlxsw_sp->ports[local_port] = NULL;
|
||||
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_vlan_flush(mlxsw_sp_port);
|
||||
mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_fids_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
|
||||
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
|
||||
|
|
|
@ -204,29 +204,6 @@ struct mlxsw_sp_port_vlan {
|
|||
struct list_head bridge_vlan_node;
|
||||
};
|
||||
|
||||
enum mlxsw_sp_qdisc_type {
|
||||
MLXSW_SP_QDISC_NO_QDISC,
|
||||
MLXSW_SP_QDISC_RED,
|
||||
};
|
||||
|
||||
struct mlxsw_sp_qdisc {
|
||||
u32 handle;
|
||||
enum mlxsw_sp_qdisc_type type;
|
||||
struct red_stats xstats_base;
|
||||
union {
|
||||
struct {
|
||||
u64 tail_drop_base;
|
||||
u64 ecn_base;
|
||||
u64 wred_drop_base;
|
||||
} red;
|
||||
} xstats;
|
||||
|
||||
u64 tx_bytes;
|
||||
u64 tx_packets;
|
||||
u64 drops;
|
||||
u64 overlimits;
|
||||
};
|
||||
|
||||
/* No need an internal lock; At worse - miss a single periodic iteration */
|
||||
struct mlxsw_sp_port_xstats {
|
||||
u64 ecn;
|
||||
|
@ -269,7 +246,7 @@ struct mlxsw_sp_port {
|
|||
} periodic_hw_stats;
|
||||
struct mlxsw_sp_port_sample *sample;
|
||||
struct list_head vlans_list;
|
||||
struct mlxsw_sp_qdisc root_qdisc;
|
||||
struct mlxsw_sp_qdisc *root_qdisc;
|
||||
unsigned acl_rule_count;
|
||||
};
|
||||
|
||||
|
@ -584,6 +561,8 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
|
|||
struct tc_cls_flower_offload *f);
|
||||
|
||||
/* spectrum_qdisc.c */
|
||||
int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port);
|
||||
void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port);
|
||||
int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct tc_red_qopt_offload *p);
|
||||
|
||||
|
|
|
@ -41,6 +41,138 @@
|
|||
#include "spectrum.h"
|
||||
#include "reg.h"
|
||||
|
||||
enum mlxsw_sp_qdisc_type {
|
||||
MLXSW_SP_QDISC_NO_QDISC,
|
||||
MLXSW_SP_QDISC_RED,
|
||||
};
|
||||
|
||||
struct mlxsw_sp_qdisc_ops {
|
||||
enum mlxsw_sp_qdisc_type type;
|
||||
int (*check_params)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
void *params);
|
||||
int (*replace)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *params);
|
||||
int (*destroy)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc);
|
||||
int (*get_stats)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
struct tc_qopt_offload_stats *stats_ptr);
|
||||
int (*get_xstats)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
void *xstats_ptr);
|
||||
void (*clean_stats)(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc);
|
||||
};
|
||||
|
||||
struct mlxsw_sp_qdisc {
|
||||
u32 handle;
|
||||
u8 tclass_num;
|
||||
union {
|
||||
struct red_stats red;
|
||||
} xstats_base;
|
||||
struct mlxsw_sp_qdisc_stats {
|
||||
u64 tx_bytes;
|
||||
u64 tx_packets;
|
||||
u64 drops;
|
||||
u64 overlimits;
|
||||
} stats_base;
|
||||
|
||||
struct mlxsw_sp_qdisc_ops *ops;
|
||||
};
|
||||
|
||||
static bool
|
||||
mlxsw_sp_qdisc_compare(struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, u32 handle,
|
||||
enum mlxsw_sp_qdisc_type type)
|
||||
{
|
||||
return mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops &&
|
||||
mlxsw_sp_qdisc->ops->type == type &&
|
||||
mlxsw_sp_qdisc->handle == handle;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!mlxsw_sp_qdisc)
|
||||
return 0;
|
||||
|
||||
if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->destroy)
|
||||
err = mlxsw_sp_qdisc->ops->destroy(mlxsw_sp_port,
|
||||
mlxsw_sp_qdisc);
|
||||
|
||||
mlxsw_sp_qdisc->handle = TC_H_UNSPEC;
|
||||
mlxsw_sp_qdisc->ops = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
struct mlxsw_sp_qdisc_ops *ops, void *params)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mlxsw_sp_qdisc->ops && mlxsw_sp_qdisc->ops->type != ops->type)
|
||||
/* In case this location contained a different qdisc of the
|
||||
* same type we can override the old qdisc configuration.
|
||||
* Otherwise, we need to remove the old qdisc before setting the
|
||||
* new one.
|
||||
*/
|
||||
mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
|
||||
err = ops->check_params(mlxsw_sp_port, mlxsw_sp_qdisc, params);
|
||||
if (err)
|
||||
goto err_bad_param;
|
||||
|
||||
err = ops->replace(mlxsw_sp_port, mlxsw_sp_qdisc, params);
|
||||
if (err)
|
||||
goto err_config;
|
||||
|
||||
if (mlxsw_sp_qdisc->handle != handle) {
|
||||
mlxsw_sp_qdisc->ops = ops;
|
||||
if (ops->clean_stats)
|
||||
ops->clean_stats(mlxsw_sp_port, mlxsw_sp_qdisc);
|
||||
}
|
||||
|
||||
mlxsw_sp_qdisc->handle = handle;
|
||||
return 0;
|
||||
|
||||
err_bad_param:
|
||||
err_config:
|
||||
mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_get_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
struct tc_qopt_offload_stats *stats_ptr)
|
||||
{
|
||||
if (mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops &&
|
||||
mlxsw_sp_qdisc->ops->get_stats)
|
||||
return mlxsw_sp_qdisc->ops->get_stats(mlxsw_sp_port,
|
||||
mlxsw_sp_qdisc,
|
||||
stats_ptr);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_get_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
void *xstats_ptr)
|
||||
{
|
||||
if (mlxsw_sp_qdisc && mlxsw_sp_qdisc->ops &&
|
||||
mlxsw_sp_qdisc->ops->get_xstats)
|
||||
return mlxsw_sp_qdisc->ops->get_xstats(mlxsw_sp_port,
|
||||
mlxsw_sp_qdisc,
|
||||
xstats_ptr);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
int tclass_num, u32 min, u32 max,
|
||||
|
@ -79,80 +211,76 @@ mlxsw_sp_tclass_congestion_disable(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_setup_tc_qdisc_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
int tclass_num)
|
||||
mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
||||
{
|
||||
struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base;
|
||||
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
||||
struct mlxsw_sp_qdisc_stats *stats_base;
|
||||
struct mlxsw_sp_port_xstats *xstats;
|
||||
struct rtnl_link_stats64 *stats;
|
||||
struct red_stats *red_base;
|
||||
|
||||
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
||||
stats = &mlxsw_sp_port->periodic_hw_stats.stats;
|
||||
stats_base = &mlxsw_sp_qdisc->stats_base;
|
||||
red_base = &mlxsw_sp_qdisc->xstats_base.red;
|
||||
|
||||
mlxsw_sp_qdisc->tx_packets = stats->tx_packets;
|
||||
mlxsw_sp_qdisc->tx_bytes = stats->tx_bytes;
|
||||
stats_base->tx_packets = stats->tx_packets;
|
||||
stats_base->tx_bytes = stats->tx_bytes;
|
||||
|
||||
switch (mlxsw_sp_qdisc->type) {
|
||||
case MLXSW_SP_QDISC_RED:
|
||||
xstats_base->prob_mark = xstats->ecn;
|
||||
xstats_base->prob_drop = xstats->wred_drop[tclass_num];
|
||||
xstats_base->pdrop = xstats->tail_drop[tclass_num];
|
||||
red_base->prob_mark = xstats->ecn;
|
||||
red_base->prob_drop = xstats->wred_drop[tclass_num];
|
||||
red_base->pdrop = xstats->tail_drop[tclass_num];
|
||||
|
||||
mlxsw_sp_qdisc->overlimits = xstats_base->prob_drop +
|
||||
xstats_base->prob_mark;
|
||||
mlxsw_sp_qdisc->drops = xstats_base->prob_drop +
|
||||
xstats_base->pdrop;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
stats_base->overlimits = red_base->prob_drop + red_base->prob_mark;
|
||||
stats_base->drops = red_base->prob_drop + red_base->pdrop;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
int tclass_num)
|
||||
mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mlxsw_sp_qdisc->handle != handle)
|
||||
return 0;
|
||||
|
||||
err = mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port, tclass_num);
|
||||
mlxsw_sp_qdisc->handle = TC_H_UNSPEC;
|
||||
mlxsw_sp_qdisc->type = MLXSW_SP_QDISC_NO_QDISC;
|
||||
|
||||
return err;
|
||||
return mlxsw_sp_tclass_congestion_disable(mlxsw_sp_port,
|
||||
mlxsw_sp_qdisc->tclass_num);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
int tclass_num,
|
||||
struct tc_red_qopt_offload_params *p)
|
||||
mlxsw_sp_qdisc_red_check_params(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
void *params)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
u32 min, max;
|
||||
u64 prob;
|
||||
int err = 0;
|
||||
struct tc_red_qopt_offload_params *p = params;
|
||||
|
||||
if (p->min > p->max) {
|
||||
dev_err(mlxsw_sp->bus_info->dev,
|
||||
"spectrum: RED: min %u is bigger then max %u\n", p->min,
|
||||
p->max);
|
||||
goto err_bad_param;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) {
|
||||
dev_err(mlxsw_sp->bus_info->dev,
|
||||
"spectrum: RED: max value %u is too big\n", p->max);
|
||||
goto err_bad_param;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p->min == 0 || p->max == 0) {
|
||||
dev_err(mlxsw_sp->bus_info->dev,
|
||||
"spectrum: RED: 0 value is illegal for min and max\n");
|
||||
goto err_bad_param;
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
void *params)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct tc_red_qopt_offload_params *p = params;
|
||||
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
||||
u32 min, max;
|
||||
u64 prob;
|
||||
|
||||
/* calculate probability in percentage */
|
||||
prob = p->probability;
|
||||
|
@ -161,116 +289,132 @@ mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
|||
prob = DIV_ROUND_UP(prob, 1 << 16);
|
||||
min = mlxsw_sp_bytes_cells(mlxsw_sp, p->min);
|
||||
max = mlxsw_sp_bytes_cells(mlxsw_sp, p->max);
|
||||
err = mlxsw_sp_tclass_congestion_enable(mlxsw_sp_port, tclass_num, min,
|
||||
max, prob, p->is_ecn);
|
||||
if (err)
|
||||
goto err_config;
|
||||
|
||||
mlxsw_sp_qdisc->type = MLXSW_SP_QDISC_RED;
|
||||
if (mlxsw_sp_qdisc->handle != handle)
|
||||
mlxsw_sp_setup_tc_qdisc_clean_stats(mlxsw_sp_port,
|
||||
mlxsw_sp_qdisc,
|
||||
tclass_num);
|
||||
|
||||
mlxsw_sp_qdisc->handle = handle;
|
||||
return 0;
|
||||
|
||||
err_bad_param:
|
||||
err = -EINVAL;
|
||||
err_config:
|
||||
mlxsw_sp_qdisc_red_destroy(mlxsw_sp_port, mlxsw_sp_qdisc->handle,
|
||||
mlxsw_sp_qdisc, tclass_num);
|
||||
return err;
|
||||
return mlxsw_sp_tclass_congestion_enable(mlxsw_sp_port, tclass_num, min,
|
||||
max, prob, p->is_ecn);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
int tclass_num, struct red_stats *res)
|
||||
void *xstats_ptr)
|
||||
{
|
||||
struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base;
|
||||
struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base.red;
|
||||
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
||||
struct mlxsw_sp_port_xstats *xstats;
|
||||
|
||||
if (mlxsw_sp_qdisc->handle != handle ||
|
||||
mlxsw_sp_qdisc->type != MLXSW_SP_QDISC_RED)
|
||||
return -EOPNOTSUPP;
|
||||
struct red_stats *res = xstats_ptr;
|
||||
int early_drops, marks, pdrops;
|
||||
|
||||
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
||||
|
||||
res->prob_drop = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
|
||||
res->prob_mark = xstats->ecn - xstats_base->prob_mark;
|
||||
res->pdrop = xstats->tail_drop[tclass_num] - xstats_base->pdrop;
|
||||
early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
|
||||
marks = xstats->ecn - xstats_base->prob_mark;
|
||||
pdrops = xstats->tail_drop[tclass_num] - xstats_base->pdrop;
|
||||
|
||||
res->pdrop += pdrops;
|
||||
res->prob_drop += early_drops;
|
||||
res->prob_mark += marks;
|
||||
|
||||
xstats_base->pdrop += pdrops;
|
||||
xstats_base->prob_drop += early_drops;
|
||||
xstats_base->prob_mark += marks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
|
||||
mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
|
||||
int tclass_num,
|
||||
struct tc_red_qopt_offload_stats *res)
|
||||
struct tc_qopt_offload_stats *stats_ptr)
|
||||
{
|
||||
u64 tx_bytes, tx_packets, overlimits, drops;
|
||||
u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
|
||||
struct mlxsw_sp_qdisc_stats *stats_base;
|
||||
struct mlxsw_sp_port_xstats *xstats;
|
||||
struct rtnl_link_stats64 *stats;
|
||||
|
||||
if (mlxsw_sp_qdisc->handle != handle ||
|
||||
mlxsw_sp_qdisc->type != MLXSW_SP_QDISC_RED)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;
|
||||
stats = &mlxsw_sp_port->periodic_hw_stats.stats;
|
||||
stats_base = &mlxsw_sp_qdisc->stats_base;
|
||||
|
||||
tx_bytes = stats->tx_bytes - mlxsw_sp_qdisc->tx_bytes;
|
||||
tx_packets = stats->tx_packets - mlxsw_sp_qdisc->tx_packets;
|
||||
tx_bytes = stats->tx_bytes - stats_base->tx_bytes;
|
||||
tx_packets = stats->tx_packets - stats_base->tx_packets;
|
||||
overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
|
||||
mlxsw_sp_qdisc->overlimits;
|
||||
stats_base->overlimits;
|
||||
drops = xstats->wred_drop[tclass_num] + xstats->tail_drop[tclass_num] -
|
||||
mlxsw_sp_qdisc->drops;
|
||||
stats_base->drops;
|
||||
|
||||
_bstats_update(res->bstats, tx_bytes, tx_packets);
|
||||
res->qstats->overlimits += overlimits;
|
||||
res->qstats->drops += drops;
|
||||
res->qstats->backlog += mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
|
||||
xstats->backlog[tclass_num]);
|
||||
_bstats_update(stats_ptr->bstats, tx_bytes, tx_packets);
|
||||
stats_ptr->qstats->overlimits += overlimits;
|
||||
stats_ptr->qstats->drops += drops;
|
||||
stats_ptr->qstats->backlog +=
|
||||
mlxsw_sp_cells_bytes(mlxsw_sp_port->mlxsw_sp,
|
||||
xstats->backlog[tclass_num]);
|
||||
|
||||
mlxsw_sp_qdisc->drops += drops;
|
||||
mlxsw_sp_qdisc->overlimits += overlimits;
|
||||
mlxsw_sp_qdisc->tx_bytes += tx_bytes;
|
||||
mlxsw_sp_qdisc->tx_packets += tx_packets;
|
||||
stats_base->drops += drops;
|
||||
stats_base->overlimits += overlimits;
|
||||
stats_base->tx_bytes += tx_bytes;
|
||||
stats_base->tx_packets += tx_packets;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MLXSW_SP_PORT_DEFAULT_TCLASS 0
|
||||
|
||||
static struct mlxsw_sp_qdisc_ops mlxsw_sp_qdisc_ops_red = {
|
||||
.type = MLXSW_SP_QDISC_RED,
|
||||
.check_params = mlxsw_sp_qdisc_red_check_params,
|
||||
.replace = mlxsw_sp_qdisc_red_replace,
|
||||
.destroy = mlxsw_sp_qdisc_red_destroy,
|
||||
.get_stats = mlxsw_sp_qdisc_get_red_stats,
|
||||
.get_xstats = mlxsw_sp_qdisc_get_red_xstats,
|
||||
.clean_stats = mlxsw_sp_setup_tc_qdisc_red_clean_stats,
|
||||
};
|
||||
|
||||
int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct tc_red_qopt_offload *p)
|
||||
{
|
||||
struct mlxsw_sp_qdisc *mlxsw_sp_qdisc;
|
||||
int tclass_num;
|
||||
|
||||
if (p->parent != TC_H_ROOT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mlxsw_sp_qdisc = &mlxsw_sp_port->root_qdisc;
|
||||
tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS;
|
||||
mlxsw_sp_qdisc = mlxsw_sp_port->root_qdisc;
|
||||
|
||||
if (p->command == TC_RED_REPLACE)
|
||||
return mlxsw_sp_qdisc_replace(mlxsw_sp_port, p->handle,
|
||||
mlxsw_sp_qdisc,
|
||||
&mlxsw_sp_qdisc_ops_red,
|
||||
&p->set);
|
||||
|
||||
if (!mlxsw_sp_qdisc_compare(mlxsw_sp_qdisc, p->handle,
|
||||
MLXSW_SP_QDISC_RED))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (p->command) {
|
||||
case TC_RED_REPLACE:
|
||||
return mlxsw_sp_qdisc_red_replace(mlxsw_sp_port, p->handle,
|
||||
mlxsw_sp_qdisc, tclass_num,
|
||||
&p->set);
|
||||
case TC_RED_DESTROY:
|
||||
return mlxsw_sp_qdisc_red_destroy(mlxsw_sp_port, p->handle,
|
||||
mlxsw_sp_qdisc, tclass_num);
|
||||
return mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
|
||||
case TC_RED_XSTATS:
|
||||
return mlxsw_sp_qdisc_get_red_xstats(mlxsw_sp_port, p->handle,
|
||||
mlxsw_sp_qdisc, tclass_num,
|
||||
p->xstats);
|
||||
return mlxsw_sp_qdisc_get_xstats(mlxsw_sp_port, mlxsw_sp_qdisc,
|
||||
p->xstats);
|
||||
case TC_RED_STATS:
|
||||
return mlxsw_sp_qdisc_get_red_stats(mlxsw_sp_port, p->handle,
|
||||
mlxsw_sp_qdisc, tclass_num,
|
||||
&p->stats);
|
||||
return mlxsw_sp_qdisc_get_stats(mlxsw_sp_port, mlxsw_sp_qdisc,
|
||||
&p->stats);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
mlxsw_sp_port->root_qdisc->tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlxsw_sp_tc_qdisc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
kfree(mlxsw_sp_port->root_qdisc);
|
||||
}
|
||||
|
|
|
@ -731,6 +731,11 @@ struct tc_cookie {
|
|||
u32 len;
|
||||
};
|
||||
|
||||
struct tc_qopt_offload_stats {
|
||||
struct gnet_stats_basic_packed *bstats;
|
||||
struct gnet_stats_queue *qstats;
|
||||
};
|
||||
|
||||
enum tc_red_command {
|
||||
TC_RED_REPLACE,
|
||||
TC_RED_DESTROY,
|
||||
|
@ -744,10 +749,6 @@ struct tc_red_qopt_offload_params {
|
|||
u32 probability;
|
||||
bool is_ecn;
|
||||
};
|
||||
struct tc_red_qopt_offload_stats {
|
||||
struct gnet_stats_basic_packed *bstats;
|
||||
struct gnet_stats_queue *qstats;
|
||||
};
|
||||
|
||||
struct tc_red_qopt_offload {
|
||||
enum tc_red_command command;
|
||||
|
@ -755,7 +756,7 @@ struct tc_red_qopt_offload {
|
|||
u32 parent;
|
||||
union {
|
||||
struct tc_red_qopt_offload_params set;
|
||||
struct tc_red_qopt_offload_stats stats;
|
||||
struct tc_qopt_offload_stats stats;
|
||||
struct red_stats *xstats;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -344,32 +344,24 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
|
|||
{
|
||||
struct red_sched_data *q = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct tc_red_xstats st = {
|
||||
.early = q->stats.prob_drop + q->stats.forced_drop,
|
||||
.pdrop = q->stats.pdrop,
|
||||
.other = q->stats.other,
|
||||
.marked = q->stats.prob_mark + q->stats.forced_mark,
|
||||
};
|
||||
struct tc_red_xstats st = {0};
|
||||
|
||||
if (sch->flags & TCQ_F_OFFLOADED) {
|
||||
struct red_stats hw_stats = {0};
|
||||
struct tc_red_qopt_offload hw_stats_request = {
|
||||
.command = TC_RED_XSTATS,
|
||||
.handle = sch->handle,
|
||||
.parent = sch->parent,
|
||||
{
|
||||
.xstats = &hw_stats,
|
||||
.xstats = &q->stats,
|
||||
},
|
||||
};
|
||||
if (!dev->netdev_ops->ndo_setup_tc(dev,
|
||||
TC_SETUP_QDISC_RED,
|
||||
&hw_stats_request)) {
|
||||
st.early += hw_stats.prob_drop + hw_stats.forced_drop;
|
||||
st.pdrop += hw_stats.pdrop;
|
||||
st.other += hw_stats.other;
|
||||
st.marked += hw_stats.prob_mark + hw_stats.forced_mark;
|
||||
}
|
||||
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED,
|
||||
&hw_stats_request);
|
||||
}
|
||||
st.early = q->stats.prob_drop + q->stats.forced_drop;
|
||||
st.pdrop = q->stats.pdrop;
|
||||
st.other = q->stats.other;
|
||||
st.marked = q->stats.prob_mark + q->stats.forced_mark;
|
||||
|
||||
return gnet_stats_copy_app(d, &st, sizeof(st));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue