12f8bc491SEyal Davidovich /* SPDX-License-Identifier: GPL-2.0 */
22f8bc491SEyal Davidovich /* Copyright (c) 2018 Mellanox Technologies. */
32f8bc491SEyal Davidovich 
42f8bc491SEyal Davidovich #include "en.h"
52f8bc491SEyal Davidovich #include "monitor_stats.h"
65c7e8bbbSEyal Davidovich #include "lib/eq.h"
72f8bc491SEyal Davidovich 
82f8bc491SEyal Davidovich /* Driver will set the following watch counters list:
92f8bc491SEyal Davidovich  * Ppcnt.802_3:
102f8bc491SEyal Davidovich  * a_in_range_length_errors      Type: 0x0, Counter:  0x0, group_id = N/A
112f8bc491SEyal Davidovich  * a_out_of_range_length_field   Type: 0x0, Counter:  0x1, group_id = N/A
122f8bc491SEyal Davidovich  * a_frame_too_long_errors       Type: 0x0, Counter:  0x2, group_id = N/A
132f8bc491SEyal Davidovich  * a_frame_check_sequence_errors Type: 0x0, Counter:  0x3, group_id = N/A
142f8bc491SEyal Davidovich  * a_alignment_errors            Type: 0x0, Counter:  0x4, group_id = N/A
152f8bc491SEyal Davidovich  * if_out_discards               Type: 0x0, Counter:  0x5, group_id = N/A
162f8bc491SEyal Davidovich  * Q_Counters:
172f8bc491SEyal Davidovich  * Q[index].rx_out_of_buffer   Type: 0x1, Counter:  0x4, group_id = counter_ix
182f8bc491SEyal Davidovich  */
192f8bc491SEyal Davidovich 
202f8bc491SEyal Davidovich #define NUM_REQ_PPCNT_COUNTER_S1 MLX5_CMD_SET_MONITOR_NUM_PPCNT_COUNTER_SET1
212f8bc491SEyal Davidovich #define NUM_REQ_Q_COUNTERS_S1    MLX5_CMD_SET_MONITOR_NUM_Q_COUNTERS_SET1
222f8bc491SEyal Davidovich 
mlx5e_monitor_counter_supported(struct mlx5e_priv * priv)232f8bc491SEyal Davidovich int mlx5e_monitor_counter_supported(struct mlx5e_priv *priv)
242f8bc491SEyal Davidovich {
252f8bc491SEyal Davidovich 	struct mlx5_core_dev *mdev = priv->mdev;
262f8bc491SEyal Davidovich 
272f8bc491SEyal Davidovich 	if (!MLX5_CAP_GEN(mdev, max_num_of_monitor_counters))
282f8bc491SEyal Davidovich 		return false;
292f8bc491SEyal Davidovich 	if (MLX5_CAP_PCAM_REG(mdev, ppcnt) &&
302f8bc491SEyal Davidovich 	    MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters) <
312f8bc491SEyal Davidovich 	    NUM_REQ_PPCNT_COUNTER_S1)
322f8bc491SEyal Davidovich 		return false;
332f8bc491SEyal Davidovich 	if (MLX5_CAP_GEN(mdev, num_q_monitor_counters) <
342f8bc491SEyal Davidovich 	    NUM_REQ_Q_COUNTERS_S1)
352f8bc491SEyal Davidovich 		return false;
362f8bc491SEyal Davidovich 	return true;
372f8bc491SEyal Davidovich }
382f8bc491SEyal Davidovich 
mlx5e_monitor_counter_arm(struct mlx5e_priv * priv)392f8bc491SEyal Davidovich void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv)
402f8bc491SEyal Davidovich {
412f8bc491SEyal Davidovich 	u32 in[MLX5_ST_SZ_DW(arm_monitor_counter_in)] = {};
422f8bc491SEyal Davidovich 
432f8bc491SEyal Davidovich 	MLX5_SET(arm_monitor_counter_in, in, opcode,
442f8bc491SEyal Davidovich 		 MLX5_CMD_OP_ARM_MONITOR_COUNTER);
45a184cda1SLeon Romanovsky 	mlx5_cmd_exec_in(priv->mdev, arm_monitor_counter, in);
462f8bc491SEyal Davidovich }
472f8bc491SEyal Davidovich 
mlx5e_monitor_counters_work(struct work_struct * work)485c7e8bbbSEyal Davidovich static void mlx5e_monitor_counters_work(struct work_struct *work)
495c7e8bbbSEyal Davidovich {
505c7e8bbbSEyal Davidovich 	struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
515c7e8bbbSEyal Davidovich 					       monitor_counters_work);
525c7e8bbbSEyal Davidovich 
535c7e8bbbSEyal Davidovich 	mutex_lock(&priv->state_lock);
54b521105bSAlaa Hleihel 	mlx5e_stats_update_ndo_stats(priv);
555c7e8bbbSEyal Davidovich 	mutex_unlock(&priv->state_lock);
565c7e8bbbSEyal Davidovich 	mlx5e_monitor_counter_arm(priv);
575c7e8bbbSEyal Davidovich }
585c7e8bbbSEyal Davidovich 
mlx5e_monitor_event_handler(struct notifier_block * nb,unsigned long event,void * eqe)595c7e8bbbSEyal Davidovich static int mlx5e_monitor_event_handler(struct notifier_block *nb,
605c7e8bbbSEyal Davidovich 				       unsigned long event, void *eqe)
615c7e8bbbSEyal Davidovich {
625c7e8bbbSEyal Davidovich 	struct mlx5e_priv *priv = mlx5_nb_cof(nb, struct mlx5e_priv,
635c7e8bbbSEyal Davidovich 					      monitor_counters_nb);
645c7e8bbbSEyal Davidovich 	queue_work(priv->wq, &priv->monitor_counters_work);
655c7e8bbbSEyal Davidovich 	return NOTIFY_OK;
665c7e8bbbSEyal Davidovich }
675c7e8bbbSEyal Davidovich 
fill_monitor_counter_ppcnt_set1(int cnt,u32 * in)682f8bc491SEyal Davidovich static int fill_monitor_counter_ppcnt_set1(int cnt, u32 *in)
692f8bc491SEyal Davidovich {
702f8bc491SEyal Davidovich 	enum mlx5_monitor_counter_ppcnt ppcnt_cnt;
712f8bc491SEyal Davidovich 
722f8bc491SEyal Davidovich 	for (ppcnt_cnt = 0;
732f8bc491SEyal Davidovich 	     ppcnt_cnt < NUM_REQ_PPCNT_COUNTER_S1;
742f8bc491SEyal Davidovich 	     ppcnt_cnt++, cnt++) {
752f8bc491SEyal Davidovich 		MLX5_SET(set_monitor_counter_in, in,
762f8bc491SEyal Davidovich 			 monitor_counter[cnt].type,
772f8bc491SEyal Davidovich 			 MLX5_QUERY_MONITOR_CNT_TYPE_PPCNT);
782f8bc491SEyal Davidovich 		MLX5_SET(set_monitor_counter_in, in,
792f8bc491SEyal Davidovich 			 monitor_counter[cnt].counter,
802f8bc491SEyal Davidovich 			 ppcnt_cnt);
812f8bc491SEyal Davidovich 	}
822f8bc491SEyal Davidovich 	return ppcnt_cnt;
832f8bc491SEyal Davidovich }
842f8bc491SEyal Davidovich 
fill_monitor_counter_q_counter_set1(int cnt,int q_counter,u32 * in)852f8bc491SEyal Davidovich static int fill_monitor_counter_q_counter_set1(int cnt, int q_counter, u32 *in)
862f8bc491SEyal Davidovich {
872f8bc491SEyal Davidovich 	MLX5_SET(set_monitor_counter_in, in,
882f8bc491SEyal Davidovich 		 monitor_counter[cnt].type,
892f8bc491SEyal Davidovich 		 MLX5_QUERY_MONITOR_CNT_TYPE_Q_COUNTER);
902f8bc491SEyal Davidovich 	MLX5_SET(set_monitor_counter_in, in,
912f8bc491SEyal Davidovich 		 monitor_counter[cnt].counter,
922f8bc491SEyal Davidovich 		 MLX5_QUERY_MONITOR_Q_COUNTER_RX_OUT_OF_BUFFER);
932f8bc491SEyal Davidovich 	MLX5_SET(set_monitor_counter_in, in,
942f8bc491SEyal Davidovich 		 monitor_counter[cnt].counter_group_id,
952f8bc491SEyal Davidovich 		 q_counter);
962f8bc491SEyal Davidovich 	return 1;
972f8bc491SEyal Davidovich }
982f8bc491SEyal Davidovich 
992f8bc491SEyal Davidovich /* check if mlx5e_monitor_counter_supported before calling this function*/
mlx5e_set_monitor_counter(struct mlx5e_priv * priv)1002f8bc491SEyal Davidovich static void mlx5e_set_monitor_counter(struct mlx5e_priv *priv)
1012f8bc491SEyal Davidovich {
1022f8bc491SEyal Davidovich 	struct mlx5_core_dev *mdev = priv->mdev;
1032f8bc491SEyal Davidovich 	int max_num_of_counters = MLX5_CAP_GEN(mdev, max_num_of_monitor_counters);
1042f8bc491SEyal Davidovich 	int num_q_counters      = MLX5_CAP_GEN(mdev, num_q_monitor_counters);
1052f8bc491SEyal Davidovich 	int num_ppcnt_counters  = !MLX5_CAP_PCAM_REG(mdev, ppcnt) ? 0 :
1062f8bc491SEyal Davidovich 				  MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters);
1072f8bc491SEyal Davidovich 	u32 in[MLX5_ST_SZ_DW(set_monitor_counter_in)] = {};
1082f8bc491SEyal Davidovich 	int q_counter = priv->q_counter;
1092f8bc491SEyal Davidovich 	int cnt	= 0;
1102f8bc491SEyal Davidovich 
1112f8bc491SEyal Davidovich 	if (num_ppcnt_counters  >=  NUM_REQ_PPCNT_COUNTER_S1 &&
1122f8bc491SEyal Davidovich 	    max_num_of_counters >= (NUM_REQ_PPCNT_COUNTER_S1 + cnt))
1132f8bc491SEyal Davidovich 		cnt += fill_monitor_counter_ppcnt_set1(cnt, in);
1142f8bc491SEyal Davidovich 
1152f8bc491SEyal Davidovich 	if (num_q_counters      >=  NUM_REQ_Q_COUNTERS_S1 &&
1162f8bc491SEyal Davidovich 	    max_num_of_counters >= (NUM_REQ_Q_COUNTERS_S1 + cnt) &&
1172f8bc491SEyal Davidovich 	    q_counter)
1182f8bc491SEyal Davidovich 		cnt += fill_monitor_counter_q_counter_set1(cnt, q_counter, in);
1192f8bc491SEyal Davidovich 
1202f8bc491SEyal Davidovich 	MLX5_SET(set_monitor_counter_in, in, num_of_counters, cnt);
1212f8bc491SEyal Davidovich 	MLX5_SET(set_monitor_counter_in, in, opcode,
1222f8bc491SEyal Davidovich 		 MLX5_CMD_OP_SET_MONITOR_COUNTER);
1232f8bc491SEyal Davidovich 
124a184cda1SLeon Romanovsky 	mlx5_cmd_exec_in(mdev, set_monitor_counter, in);
1252f8bc491SEyal Davidovich }
1262f8bc491SEyal Davidovich 
1272f8bc491SEyal Davidovich /* check if mlx5e_monitor_counter_supported before calling this function*/
mlx5e_monitor_counter_init(struct mlx5e_priv * priv)1282f8bc491SEyal Davidovich void mlx5e_monitor_counter_init(struct mlx5e_priv *priv)
1292f8bc491SEyal Davidovich {
1305c7e8bbbSEyal Davidovich 	INIT_WORK(&priv->monitor_counters_work, mlx5e_monitor_counters_work);
131a184cda1SLeon Romanovsky 	MLX5_NB_INIT(&priv->monitor_counters_nb, mlx5e_monitor_event_handler,
132a184cda1SLeon Romanovsky 		     MONITOR_COUNTER);
133a184cda1SLeon Romanovsky 	mlx5_eq_notifier_register(priv->mdev, &priv->monitor_counters_nb);
134a184cda1SLeon Romanovsky 
1352f8bc491SEyal Davidovich 	mlx5e_set_monitor_counter(priv);
1362f8bc491SEyal Davidovich 	mlx5e_monitor_counter_arm(priv);
1375c7e8bbbSEyal Davidovich 	queue_work(priv->wq, &priv->update_stats_work);
1382f8bc491SEyal Davidovich }
1392f8bc491SEyal Davidovich 
1405c7e8bbbSEyal Davidovich /* check if mlx5e_monitor_counter_supported before calling this function*/
mlx5e_monitor_counter_cleanup(struct mlx5e_priv * priv)1415c7e8bbbSEyal Davidovich void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv)
1425c7e8bbbSEyal Davidovich {
143a184cda1SLeon Romanovsky 	u32 in[MLX5_ST_SZ_DW(set_monitor_counter_in)] = {};
144a184cda1SLeon Romanovsky 
145a184cda1SLeon Romanovsky 	MLX5_SET(set_monitor_counter_in, in, opcode,
146a184cda1SLeon Romanovsky 		 MLX5_CMD_OP_SET_MONITOR_COUNTER);
147a184cda1SLeon Romanovsky 
148a184cda1SLeon Romanovsky 	mlx5_cmd_exec_in(priv->mdev, set_monitor_counter, in);
149a184cda1SLeon Romanovsky 	mlx5_eq_notifier_unregister(priv->mdev, &priv->monitor_counters_nb);
150a184cda1SLeon Romanovsky 	cancel_work_sync(&priv->monitor_counters_work);
1515c7e8bbbSEyal Davidovich }
152