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 23static int mlx5e_monitor_counter_cap(struct mlx5_core_dev *mdev) 24{ 25 if (!MLX5_CAP_GEN(mdev, max_num_of_monitor_counters)) 26 return false; 27 if (MLX5_CAP_PCAM_REG(mdev, ppcnt) && 28 MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters) < 29 NUM_REQ_PPCNT_COUNTER_S1) 30 return false; 31 if (MLX5_CAP_GEN(mdev, num_q_monitor_counters) < 32 NUM_REQ_Q_COUNTERS_S1) 33 return false; 34 return true; 35} 36 37int mlx5e_monitor_counter_supported(struct mlx5e_priv *priv) 38{ 39 struct mlx5_core_dev *pos; 40 int i; 41 42 mlx5_sd_for_each_dev(i, priv->mdev, pos) 43 if (!mlx5e_monitor_counter_cap(pos)) 44 return false; 45 return true; 46} 47 48static void mlx5e_monitor_counter_arm(struct mlx5_core_dev *mdev) 49{ 50 u32 in[MLX5_ST_SZ_DW(arm_monitor_counter_in)] = {}; 51 52 MLX5_SET(arm_monitor_counter_in, in, opcode, 53 MLX5_CMD_OP_ARM_MONITOR_COUNTER); 54 mlx5_cmd_exec_in(mdev, arm_monitor_counter, in); 55} 56 57static void mlx5e_monitor_counters_work(struct work_struct *work) 58{ 59 struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, 60 monitor_counters_work); 61 struct mlx5_core_dev *pos; 62 int i; 63 64 mutex_lock(&priv->state_lock); 65 mlx5e_stats_update_ndo_stats(priv); 66 mutex_unlock(&priv->state_lock); 67 mlx5_sd_for_each_dev(i, priv->mdev, pos) 68 mlx5e_monitor_counter_arm(pos); 69} 70 71static int mlx5e_monitor_event_handler(struct notifier_block *nb, 72 unsigned long event, void *eqe) 73{ 74 struct mlx5e_priv *priv = mlx5_nb_cof(nb, struct mlx5e_priv, 75 monitor_counters_nb); 76 queue_work(priv->wq, &priv->monitor_counters_work); 77 return NOTIFY_OK; 78} 79 80static int fill_monitor_counter_ppcnt_set1(int cnt, u32 *in) 81{ 82 enum mlx5_monitor_counter_ppcnt ppcnt_cnt; 83 84 for (ppcnt_cnt = 0; 85 ppcnt_cnt < NUM_REQ_PPCNT_COUNTER_S1; 86 ppcnt_cnt++, cnt++) { 87 MLX5_SET(set_monitor_counter_in, in, 88 monitor_counter[cnt].type, 89 MLX5_QUERY_MONITOR_CNT_TYPE_PPCNT); 90 MLX5_SET(set_monitor_counter_in, in, 91 monitor_counter[cnt].counter, 92 ppcnt_cnt); 93 } 94 return ppcnt_cnt; 95} 96 97static int fill_monitor_counter_q_counter_set1(int cnt, int q_counter, u32 *in) 98{ 99 MLX5_SET(set_monitor_counter_in, in, 100 monitor_counter[cnt].type, 101 MLX5_QUERY_MONITOR_CNT_TYPE_Q_COUNTER); 102 MLX5_SET(set_monitor_counter_in, in, 103 monitor_counter[cnt].counter, 104 MLX5_QUERY_MONITOR_Q_COUNTER_RX_OUT_OF_BUFFER); 105 MLX5_SET(set_monitor_counter_in, in, 106 monitor_counter[cnt].counter_group_id, 107 q_counter); 108 return 1; 109} 110 111/* check if mlx5e_monitor_counter_supported before calling this function*/ 112static void mlx5e_set_monitor_counter(struct mlx5_core_dev *mdev, int q_counter) 113{ 114 int max_num_of_counters = MLX5_CAP_GEN(mdev, max_num_of_monitor_counters); 115 int num_q_counters = MLX5_CAP_GEN(mdev, num_q_monitor_counters); 116 int num_ppcnt_counters = !MLX5_CAP_PCAM_REG(mdev, ppcnt) ? 0 : 117 MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters); 118 u32 in[MLX5_ST_SZ_DW(set_monitor_counter_in)] = {}; 119 int cnt = 0; 120 121 if (num_ppcnt_counters >= NUM_REQ_PPCNT_COUNTER_S1 && 122 max_num_of_counters >= (NUM_REQ_PPCNT_COUNTER_S1 + cnt)) 123 cnt += fill_monitor_counter_ppcnt_set1(cnt, in); 124 125 if (num_q_counters >= NUM_REQ_Q_COUNTERS_S1 && 126 max_num_of_counters >= (NUM_REQ_Q_COUNTERS_S1 + cnt) && 127 q_counter) 128 cnt += fill_monitor_counter_q_counter_set1(cnt, q_counter, in); 129 130 MLX5_SET(set_monitor_counter_in, in, num_of_counters, cnt); 131 MLX5_SET(set_monitor_counter_in, in, opcode, 132 MLX5_CMD_OP_SET_MONITOR_COUNTER); 133 134 mlx5_cmd_exec_in(mdev, set_monitor_counter, in); 135} 136 137/* check if mlx5e_monitor_counter_supported before calling this function*/ 138void mlx5e_monitor_counter_init(struct mlx5e_priv *priv) 139{ 140 struct mlx5_core_dev *pos; 141 int i; 142 143 INIT_WORK(&priv->monitor_counters_work, mlx5e_monitor_counters_work); 144 MLX5_NB_INIT(&priv->monitor_counters_nb, mlx5e_monitor_event_handler, 145 MONITOR_COUNTER); 146 mlx5_sd_for_each_dev(i, priv->mdev, pos) { 147 mlx5_eq_notifier_register(pos, &priv->monitor_counters_nb); 148 mlx5e_set_monitor_counter(pos, priv->q_counter[i]); 149 mlx5e_monitor_counter_arm(pos); 150 } 151 queue_work(priv->wq, &priv->update_stats_work); 152} 153 154/* check if mlx5e_monitor_counter_supported before calling this function*/ 155void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv) 156{ 157 u32 in[MLX5_ST_SZ_DW(set_monitor_counter_in)] = {}; 158 struct mlx5_core_dev *pos; 159 int i; 160 161 MLX5_SET(set_monitor_counter_in, in, opcode, 162 MLX5_CMD_OP_SET_MONITOR_COUNTER); 163 164 mlx5_sd_for_each_dev(i, priv->mdev, pos) { 165 mlx5_cmd_exec_in(pos, set_monitor_counter, in); 166 mlx5_eq_notifier_unregister(pos, &priv->monitor_counters_nb); 167 } 168 cancel_work_sync(&priv->monitor_counters_work); 169} 170