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 
mlx5e_monitor_counter_supported(struct mlx5e_priv * priv)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 
mlx5e_monitor_counter_arm(struct mlx5e_priv * priv)39 void 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 
mlx5e_monitor_counters_work(struct work_struct * work)49 static 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 
mlx5e_monitor_event_handler(struct notifier_block * nb,unsigned long event,void * eqe)60 static 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 
mlx5e_monitor_counter_start(struct mlx5e_priv * priv)69 static 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 
mlx5e_monitor_counter_stop(struct mlx5e_priv * priv)76 static 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 
fill_monitor_counter_ppcnt_set1(int cnt,u32 * in)82 static 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 
fill_monitor_counter_q_counter_set1(int cnt,int q_counter,u32 * in)99 static 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*/
mlx5e_set_monitor_counter(struct mlx5e_priv * priv)114 static 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*/
mlx5e_monitor_counter_init(struct mlx5e_priv * priv)143 void 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 
mlx5e_monitor_counter_disable(struct mlx5e_priv * priv)152 static 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*/
mlx5e_monitor_counter_cleanup(struct mlx5e_priv * priv)165 void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv)
166 {
167 	mlx5e_monitor_counter_disable(priv);
168 	mlx5e_monitor_counter_stop(priv);
169 }
170