net/mlx5e: Add support to modify hardware flow meter parameters
The policing rate and burst from user are converted to flow meter parameters in hardware. These parameters are set or modified by ACCESS_ASO WQE, add function to support it. Signed-off-by: Jianbo Liu <jianbol@nvidia.com> Reviewed-by: Roi Dayan <roid@nvidia.com> Reviewed-by: Ariel Levkovich <lariel@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
This commit is contained in:
Родитель
74e6b2a874
Коммит
6ddac26cf7
|
@ -5,6 +5,22 @@
|
|||
#include "en/tc/post_act.h"
|
||||
#include "meter.h"
|
||||
|
||||
#define MLX5_START_COLOR_SHIFT 28
|
||||
#define MLX5_METER_MODE_SHIFT 24
|
||||
#define MLX5_CBS_EXP_SHIFT 24
|
||||
#define MLX5_CBS_MAN_SHIFT 16
|
||||
#define MLX5_CIR_EXP_SHIFT 8
|
||||
|
||||
/* cir = 8*(10^9)*cir_mantissa/(2^cir_exponent)) bits/s */
|
||||
#define MLX5_CONST_CIR 8000000000ULL
|
||||
#define MLX5_CALC_CIR(m, e) ((MLX5_CONST_CIR * (m)) >> (e))
|
||||
#define MLX5_MAX_CIR ((MLX5_CONST_CIR * 0x100) - 1)
|
||||
|
||||
/* cbs = cbs_mantissa*2^cbs_exponent */
|
||||
#define MLX5_CALC_CBS(m, e) ((m) << (e))
|
||||
#define MLX5_MAX_CBS ((0x100ULL << 0x1F) - 1)
|
||||
#define MLX5_MAX_HW_CBS 0x7FFFFFFF
|
||||
|
||||
struct mlx5e_flow_meters {
|
||||
enum mlx5_flow_namespace_type ns_type;
|
||||
struct mlx5_aso *aso;
|
||||
|
@ -16,6 +32,151 @@ struct mlx5e_flow_meters {
|
|||
struct mlx5e_post_act *post_act;
|
||||
};
|
||||
|
||||
static void
|
||||
mlx5e_flow_meter_cir_calc(u64 cir, u8 *man, u8 *exp)
|
||||
{
|
||||
s64 _cir, _delta, delta = S64_MAX;
|
||||
u8 e, _man = 0, _exp = 0;
|
||||
u64 m;
|
||||
|
||||
for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
|
||||
m = cir << e;
|
||||
if ((s64)m < 0) /* overflow */
|
||||
break;
|
||||
m /= MLX5_CONST_CIR;
|
||||
if (m > 0xFF) /* man width 8 bit */
|
||||
continue;
|
||||
_cir = MLX5_CALC_CIR(m, e);
|
||||
_delta = cir - _cir;
|
||||
if (_delta < delta) {
|
||||
_man = m;
|
||||
_exp = e;
|
||||
if (!_delta)
|
||||
goto found;
|
||||
delta = _delta;
|
||||
}
|
||||
}
|
||||
|
||||
found:
|
||||
*man = _man;
|
||||
*exp = _exp;
|
||||
}
|
||||
|
||||
static void
|
||||
mlx5e_flow_meter_cbs_calc(u64 cbs, u8 *man, u8 *exp)
|
||||
{
|
||||
s64 _cbs, _delta, delta = S64_MAX;
|
||||
u8 e, _man = 0, _exp = 0;
|
||||
u64 m;
|
||||
|
||||
for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
|
||||
m = cbs >> e;
|
||||
if (m > 0xFF) /* man width 8 bit */
|
||||
continue;
|
||||
_cbs = MLX5_CALC_CBS(m, e);
|
||||
_delta = cbs - _cbs;
|
||||
if (_delta < delta) {
|
||||
_man = m;
|
||||
_exp = e;
|
||||
if (!_delta)
|
||||
goto found;
|
||||
delta = _delta;
|
||||
}
|
||||
}
|
||||
|
||||
found:
|
||||
*man = _man;
|
||||
*exp = _exp;
|
||||
}
|
||||
|
||||
int
|
||||
mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_flow_meter_handle *meter,
|
||||
struct mlx5e_flow_meter_params *meter_params)
|
||||
{
|
||||
struct mlx5_wqe_aso_ctrl_seg *aso_ctrl;
|
||||
struct mlx5_wqe_aso_data_seg *aso_data;
|
||||
struct mlx5e_flow_meters *flow_meters;
|
||||
u8 cir_man, cir_exp, cbs_man, cbs_exp;
|
||||
struct mlx5_aso_wqe *aso_wqe;
|
||||
struct mlx5_aso *aso;
|
||||
u64 rate, burst;
|
||||
u8 ds_cnt;
|
||||
int err;
|
||||
|
||||
rate = meter_params->rate;
|
||||
burst = meter_params->burst;
|
||||
|
||||
/* HW treats each packet as 128 bytes in PPS mode */
|
||||
if (meter_params->mode == MLX5_RATE_LIMIT_PPS) {
|
||||
rate <<= 10;
|
||||
burst <<= 7;
|
||||
}
|
||||
|
||||
if (!rate || rate > MLX5_MAX_CIR || !burst || burst > MLX5_MAX_CBS)
|
||||
return -EINVAL;
|
||||
|
||||
/* HW has limitation of total 31 bits for cbs */
|
||||
if (burst > MLX5_MAX_HW_CBS) {
|
||||
mlx5_core_warn(mdev,
|
||||
"burst(%lld) is too large, use HW allowed value(%d)\n",
|
||||
burst, MLX5_MAX_HW_CBS);
|
||||
burst = MLX5_MAX_HW_CBS;
|
||||
}
|
||||
|
||||
mlx5_core_dbg(mdev, "meter mode=%d\n", meter_params->mode);
|
||||
mlx5e_flow_meter_cir_calc(rate, &cir_man, &cir_exp);
|
||||
mlx5_core_dbg(mdev, "rate=%lld, cir=%lld, exp=%d, man=%d\n",
|
||||
rate, MLX5_CALC_CIR(cir_man, cir_exp), cir_exp, cir_man);
|
||||
mlx5e_flow_meter_cbs_calc(burst, &cbs_man, &cbs_exp);
|
||||
mlx5_core_dbg(mdev, "burst=%lld, cbs=%lld, exp=%d, man=%d\n",
|
||||
burst, MLX5_CALC_CBS((u64)cbs_man, cbs_exp), cbs_exp, cbs_man);
|
||||
|
||||
if (!cir_man || !cbs_man)
|
||||
return -EINVAL;
|
||||
|
||||
flow_meters = meter->flow_meters;
|
||||
aso = flow_meters->aso;
|
||||
|
||||
mutex_lock(&flow_meters->aso_lock);
|
||||
aso_wqe = mlx5_aso_get_wqe(aso);
|
||||
ds_cnt = DIV_ROUND_UP(sizeof(struct mlx5_aso_wqe_data), MLX5_SEND_WQE_DS);
|
||||
mlx5_aso_build_wqe(aso, ds_cnt, aso_wqe, meter->obj_id,
|
||||
MLX5_ACCESS_ASO_OPC_MOD_FLOW_METER);
|
||||
|
||||
aso_ctrl = &aso_wqe->aso_ctrl;
|
||||
memset(aso_ctrl, 0, sizeof(*aso_ctrl));
|
||||
aso_ctrl->data_mask_mode = MLX5_ASO_DATA_MASK_MODE_BYTEWISE_64BYTE << 6;
|
||||
aso_ctrl->condition_1_0_operand = MLX5_ASO_ALWAYS_TRUE |
|
||||
MLX5_ASO_ALWAYS_TRUE << 4;
|
||||
aso_ctrl->data_offset_condition_operand = MLX5_ASO_LOGICAL_OR << 6;
|
||||
aso_ctrl->data_mask = cpu_to_be64(0x80FFFFFFULL << (meter->idx ? 0 : 32));
|
||||
|
||||
aso_data = (struct mlx5_wqe_aso_data_seg *)(aso_wqe + 1);
|
||||
memset(aso_data, 0, sizeof(*aso_data));
|
||||
aso_data->bytewise_data[meter->idx * 8] = cpu_to_be32((0x1 << 31) | /* valid */
|
||||
(MLX5_FLOW_METER_COLOR_GREEN << MLX5_START_COLOR_SHIFT));
|
||||
if (meter_params->mode == MLX5_RATE_LIMIT_PPS)
|
||||
aso_data->bytewise_data[meter->idx * 8] |=
|
||||
cpu_to_be32(MLX5_FLOW_METER_MODE_NUM_PACKETS << MLX5_METER_MODE_SHIFT);
|
||||
else
|
||||
aso_data->bytewise_data[meter->idx * 8] |=
|
||||
cpu_to_be32(MLX5_FLOW_METER_MODE_BYTES_IP_LENGTH << MLX5_METER_MODE_SHIFT);
|
||||
|
||||
aso_data->bytewise_data[meter->idx * 8 + 2] = cpu_to_be32((cbs_exp << MLX5_CBS_EXP_SHIFT) |
|
||||
(cbs_man << MLX5_CBS_MAN_SHIFT) |
|
||||
(cir_exp << MLX5_CIR_EXP_SHIFT) |
|
||||
cir_man);
|
||||
|
||||
mlx5_aso_post_wqe(aso, true, &aso_wqe->ctrl);
|
||||
|
||||
/* With newer FW, the wait for the first ASO WQE is more than 2us, put the wait 10ms. */
|
||||
err = mlx5_aso_poll_cq(aso, true, 10);
|
||||
mutex_unlock(&flow_meters->aso_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct mlx5e_flow_meters *
|
||||
mlx5e_flow_meters_init(struct mlx5e_priv *priv,
|
||||
enum mlx5_flow_namespace_type ns_type,
|
||||
|
|
|
@ -6,6 +6,28 @@
|
|||
|
||||
struct mlx5e_flow_meters;
|
||||
|
||||
enum mlx5e_flow_meter_mode {
|
||||
MLX5_RATE_LIMIT_BPS,
|
||||
MLX5_RATE_LIMIT_PPS,
|
||||
};
|
||||
|
||||
struct mlx5e_flow_meter_params {
|
||||
enum mlx5e_flow_meter_mode mode;
|
||||
u64 rate;
|
||||
u64 burst;
|
||||
};
|
||||
|
||||
struct mlx5e_flow_meter_handle {
|
||||
struct mlx5e_flow_meters *flow_meters;
|
||||
u32 obj_id;
|
||||
u8 idx;
|
||||
};
|
||||
|
||||
int
|
||||
mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_flow_meter_handle *meter,
|
||||
struct mlx5e_flow_meter_params *meter_params);
|
||||
|
||||
struct mlx5e_flow_meters *
|
||||
mlx5e_flow_meters_init(struct mlx5e_priv *priv,
|
||||
enum mlx5_flow_namespace_type ns_type,
|
||||
|
|
|
@ -44,6 +44,11 @@ struct mlx5_aso_wqe_data {
|
|||
struct mlx5_wqe_aso_data_seg aso_data;
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_ASO_LOGICAL_AND,
|
||||
MLX5_ASO_LOGICAL_OR,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_ASO_ALWAYS_FALSE,
|
||||
MLX5_ASO_ALWAYS_TRUE,
|
||||
|
@ -63,6 +68,10 @@ enum {
|
|||
MLX5_ASO_DATA_MASK_MODE_CALCULATED_64BYTE,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_ACCESS_ASO_OPC_MOD_FLOW_METER = 0x2,
|
||||
};
|
||||
|
||||
struct mlx5_aso;
|
||||
|
||||
void *mlx5_aso_get_wqe(struct mlx5_aso *aso);
|
||||
|
|
Загрузка…
Ссылка в новой задаче