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