linux/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/* Copyright (c) 2018 Mellanox Technologies. */
   3
   4#include "en.h"
   5#include "monitor_stats.h"
   6#include "lib/eq.h"
   7
   8/* Driver will set the following watch counters list:
   9 * Ppcnt.802_3:
  10 * a_in_range_length_errors      Type: 0x0, Counter:  0x0, group_id = N/A
  11 * a_out_of_range_length_field   Type: 0x0, Counter:  0x1, group_id = N/A
  12 * a_frame_too_long_errors       Type: 0x0, Counter:  0x2, group_id = N/A
  13 * a_frame_check_sequence_errors Type: 0x0, Counter:  0x3, group_id = N/A
  14 * a_alignment_errors            Type: 0x0, Counter:  0x4, group_id = N/A
  15 * if_out_discards               Type: 0x0, Counter:  0x5, group_id = N/A
  16 * Q_Counters:
  17 * Q[index].rx_out_of_buffer   Type: 0x1, Counter:  0x4, group_id = counter_ix
  18 */
  19
  20#define NUM_REQ_PPCNT_COUNTER_S1 MLX5_CMD_SET_MONITOR_NUM_PPCNT_COUNTER_SET1
  21#define NUM_REQ_Q_COUNTERS_S1    MLX5_CMD_SET_MONITOR_NUM_Q_COUNTERS_SET1
  22
  23int mlx5e_monitor_counter_supported(struct mlx5e_priv *priv)
  24{
  25        struct mlx5_core_dev *mdev = priv->mdev;
  26
  27        if (!MLX5_CAP_GEN(mdev, max_num_of_monitor_counters))
  28                return false;
  29        if (MLX5_CAP_PCAM_REG(mdev, ppcnt) &&
  30            MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters) <
  31            NUM_REQ_PPCNT_COUNTER_S1)
  32                return false;
  33        if (MLX5_CAP_GEN(mdev, num_q_monitor_counters) <
  34            NUM_REQ_Q_COUNTERS_S1)
  35                return false;
  36        return true;
  37}
  38
  39void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv)
  40{
  41        u32  in[MLX5_ST_SZ_DW(arm_monitor_counter_in)]  = {};
  42        u32 out[MLX5_ST_SZ_DW(arm_monitor_counter_out)] = {};
  43
  44        MLX5_SET(arm_monitor_counter_in, in, opcode,
  45                 MLX5_CMD_OP_ARM_MONITOR_COUNTER);
  46        mlx5_cmd_exec(priv->mdev, in, sizeof(in), out, sizeof(out));
  47}
  48
  49static void mlx5e_monitor_counters_work(struct work_struct *work)
  50{
  51        struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
  52                                               monitor_counters_work);
  53
  54        mutex_lock(&priv->state_lock);
  55        mlx5e_update_ndo_stats(priv);
  56        mutex_unlock(&priv->state_lock);
  57        mlx5e_monitor_counter_arm(priv);
  58}
  59
  60static int mlx5e_monitor_event_handler(struct notifier_block *nb,
  61                                       unsigned long event, void *eqe)
  62{
  63        struct mlx5e_priv *priv = mlx5_nb_cof(nb, struct mlx5e_priv,
  64                                              monitor_counters_nb);
  65        queue_work(priv->wq, &priv->monitor_counters_work);
  66        return NOTIFY_OK;
  67}
  68
  69static void mlx5e_monitor_counter_start(struct mlx5e_priv *priv)
  70{
  71        MLX5_NB_INIT(&priv->monitor_counters_nb, mlx5e_monitor_event_handler,
  72                     MONITOR_COUNTER);
  73        mlx5_eq_notifier_register(priv->mdev, &priv->monitor_counters_nb);
  74}
  75
  76static void mlx5e_monitor_counter_stop(struct mlx5e_priv *priv)
  77{
  78        mlx5_eq_notifier_unregister(priv->mdev, &priv->monitor_counters_nb);
  79        cancel_work_sync(&priv->monitor_counters_work);
  80}
  81
  82static int fill_monitor_counter_ppcnt_set1(int cnt, u32 *in)
  83{
  84        enum mlx5_monitor_counter_ppcnt ppcnt_cnt;
  85
  86        for (ppcnt_cnt = 0;
  87             ppcnt_cnt < NUM_REQ_PPCNT_COUNTER_S1;
  88             ppcnt_cnt++, cnt++) {
  89                MLX5_SET(set_monitor_counter_in, in,
  90                         monitor_counter[cnt].type,
  91                         MLX5_QUERY_MONITOR_CNT_TYPE_PPCNT);
  92                MLX5_SET(set_monitor_counter_in, in,
  93                         monitor_counter[cnt].counter,
  94                         ppcnt_cnt);
  95        }
  96        return ppcnt_cnt;
  97}
  98
  99static int fill_monitor_counter_q_counter_set1(int cnt, int q_counter, u32 *in)
 100{
 101        MLX5_SET(set_monitor_counter_in, in,
 102                 monitor_counter[cnt].type,
 103                 MLX5_QUERY_MONITOR_CNT_TYPE_Q_COUNTER);
 104        MLX5_SET(set_monitor_counter_in, in,
 105                 monitor_counter[cnt].counter,
 106                 MLX5_QUERY_MONITOR_Q_COUNTER_RX_OUT_OF_BUFFER);
 107        MLX5_SET(set_monitor_counter_in, in,
 108                 monitor_counter[cnt].counter_group_id,
 109                 q_counter);
 110        return 1;
 111}
 112
 113/* check if mlx5e_monitor_counter_supported before calling this function*/
 114static void mlx5e_set_monitor_counter(struct mlx5e_priv *priv)
 115{
 116        struct mlx5_core_dev *mdev = priv->mdev;
 117        int max_num_of_counters = MLX5_CAP_GEN(mdev, max_num_of_monitor_counters);
 118        int num_q_counters      = MLX5_CAP_GEN(mdev, num_q_monitor_counters);
 119        int num_ppcnt_counters  = !MLX5_CAP_PCAM_REG(mdev, ppcnt) ? 0 :
 120                                  MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters);
 121        u32  in[MLX5_ST_SZ_DW(set_monitor_counter_in)]  = {};
 122        u32 out[MLX5_ST_SZ_DW(set_monitor_counter_out)] = {};
 123        int q_counter = priv->q_counter;
 124        int cnt = 0;
 125
 126        if (num_ppcnt_counters  >=  NUM_REQ_PPCNT_COUNTER_S1 &&
 127            max_num_of_counters >= (NUM_REQ_PPCNT_COUNTER_S1 + cnt))
 128                cnt += fill_monitor_counter_ppcnt_set1(cnt, in);
 129
 130        if (num_q_counters      >=  NUM_REQ_Q_COUNTERS_S1 &&
 131            max_num_of_counters >= (NUM_REQ_Q_COUNTERS_S1 + cnt) &&
 132            q_counter)
 133                cnt += fill_monitor_counter_q_counter_set1(cnt, q_counter, in);
 134
 135        MLX5_SET(set_monitor_counter_in, in, num_of_counters, cnt);
 136        MLX5_SET(set_monitor_counter_in, in, opcode,
 137                 MLX5_CMD_OP_SET_MONITOR_COUNTER);
 138
 139        mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
 140}
 141
 142/* check if mlx5e_monitor_counter_supported before calling this function*/
 143void mlx5e_monitor_counter_init(struct mlx5e_priv *priv)
 144{
 145        INIT_WORK(&priv->monitor_counters_work, mlx5e_monitor_counters_work);
 146        mlx5e_monitor_counter_start(priv);
 147        mlx5e_set_monitor_counter(priv);
 148        mlx5e_monitor_counter_arm(priv);
 149        queue_work(priv->wq, &priv->update_stats_work);
 150}
 151
 152static void mlx5e_monitor_counter_disable(struct mlx5e_priv *priv)
 153{
 154        u32  in[MLX5_ST_SZ_DW(set_monitor_counter_in)]  = {};
 155        u32 out[MLX5_ST_SZ_DW(set_monitor_counter_out)] = {};
 156
 157        MLX5_SET(set_monitor_counter_in, in, num_of_counters, 0);
 158        MLX5_SET(set_monitor_counter_in, in, opcode,
 159                 MLX5_CMD_OP_SET_MONITOR_COUNTER);
 160
 161        mlx5_cmd_exec(priv->mdev, in, sizeof(in), out, sizeof(out));
 162}
 163
 164/* check if mlx5e_monitor_counter_supported before calling this function*/
 165void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv)
 166{
 167        mlx5e_monitor_counter_disable(priv);
 168        mlx5e_monitor_counter_stop(priv);
 169}
 170