--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#include "en.h"
+#include "monitor_stats.h"
+
+/* Driver will set the following watch counters list:
+ * Ppcnt.802_3:
+ * a_in_range_length_errors      Type: 0x0, Counter:  0x0, group_id = N/A
+ * a_out_of_range_length_field   Type: 0x0, Counter:  0x1, group_id = N/A
+ * a_frame_too_long_errors       Type: 0x0, Counter:  0x2, group_id = N/A
+ * a_frame_check_sequence_errors Type: 0x0, Counter:  0x3, group_id = N/A
+ * a_alignment_errors            Type: 0x0, Counter:  0x4, group_id = N/A
+ * if_out_discards               Type: 0x0, Counter:  0x5, group_id = N/A
+ * Q_Counters:
+ * Q[index].rx_out_of_buffer   Type: 0x1, Counter:  0x4, group_id = counter_ix
+ */
+
+#define NUM_REQ_PPCNT_COUNTER_S1 MLX5_CMD_SET_MONITOR_NUM_PPCNT_COUNTER_SET1
+#define NUM_REQ_Q_COUNTERS_S1    MLX5_CMD_SET_MONITOR_NUM_Q_COUNTERS_SET1
+
+int mlx5e_monitor_counter_supported(struct mlx5e_priv *priv)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+
+       if (!MLX5_CAP_GEN(mdev, max_num_of_monitor_counters))
+               return false;
+       if (MLX5_CAP_PCAM_REG(mdev, ppcnt) &&
+           MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters) <
+           NUM_REQ_PPCNT_COUNTER_S1)
+               return false;
+       if (MLX5_CAP_GEN(mdev, num_q_monitor_counters) <
+           NUM_REQ_Q_COUNTERS_S1)
+               return false;
+       return true;
+}
+
+void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv)
+{
+       u32  in[MLX5_ST_SZ_DW(arm_monitor_counter_in)]  = {};
+       u32 out[MLX5_ST_SZ_DW(arm_monitor_counter_out)] = {};
+
+       MLX5_SET(arm_monitor_counter_in, in, opcode,
+                MLX5_CMD_OP_ARM_MONITOR_COUNTER);
+       mlx5_cmd_exec(priv->mdev, in, sizeof(in), out, sizeof(out));
+}
+
+static int fill_monitor_counter_ppcnt_set1(int cnt, u32 *in)
+{
+       enum mlx5_monitor_counter_ppcnt ppcnt_cnt;
+
+       for (ppcnt_cnt = 0;
+            ppcnt_cnt < NUM_REQ_PPCNT_COUNTER_S1;
+            ppcnt_cnt++, cnt++) {
+               MLX5_SET(set_monitor_counter_in, in,
+                        monitor_counter[cnt].type,
+                        MLX5_QUERY_MONITOR_CNT_TYPE_PPCNT);
+               MLX5_SET(set_monitor_counter_in, in,
+                        monitor_counter[cnt].counter,
+                        ppcnt_cnt);
+       }
+       return ppcnt_cnt;
+}
+
+static int fill_monitor_counter_q_counter_set1(int cnt, int q_counter, u32 *in)
+{
+       MLX5_SET(set_monitor_counter_in, in,
+                monitor_counter[cnt].type,
+                MLX5_QUERY_MONITOR_CNT_TYPE_Q_COUNTER);
+       MLX5_SET(set_monitor_counter_in, in,
+                monitor_counter[cnt].counter,
+                MLX5_QUERY_MONITOR_Q_COUNTER_RX_OUT_OF_BUFFER);
+       MLX5_SET(set_monitor_counter_in, in,
+                monitor_counter[cnt].counter_group_id,
+                q_counter);
+       return 1;
+}
+
+/* check if mlx5e_monitor_counter_supported before calling this function*/
+static void mlx5e_set_monitor_counter(struct mlx5e_priv *priv)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       int max_num_of_counters = MLX5_CAP_GEN(mdev, max_num_of_monitor_counters);
+       int num_q_counters      = MLX5_CAP_GEN(mdev, num_q_monitor_counters);
+       int num_ppcnt_counters  = !MLX5_CAP_PCAM_REG(mdev, ppcnt) ? 0 :
+                                 MLX5_CAP_GEN(mdev, num_ppcnt_monitor_counters);
+       u32  in[MLX5_ST_SZ_DW(set_monitor_counter_in)]  = {};
+       u32 out[MLX5_ST_SZ_DW(set_monitor_counter_out)] = {};
+       int q_counter = priv->q_counter;
+       int cnt = 0;
+
+       if (num_ppcnt_counters  >=  NUM_REQ_PPCNT_COUNTER_S1 &&
+           max_num_of_counters >= (NUM_REQ_PPCNT_COUNTER_S1 + cnt))
+               cnt += fill_monitor_counter_ppcnt_set1(cnt, in);
+
+       if (num_q_counters      >=  NUM_REQ_Q_COUNTERS_S1 &&
+           max_num_of_counters >= (NUM_REQ_Q_COUNTERS_S1 + cnt) &&
+           q_counter)
+               cnt += fill_monitor_counter_q_counter_set1(cnt, q_counter, in);
+
+       MLX5_SET(set_monitor_counter_in, in, num_of_counters, cnt);
+       MLX5_SET(set_monitor_counter_in, in, opcode,
+                MLX5_CMD_OP_SET_MONITOR_COUNTER);
+
+       mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+}
+
+/* check if mlx5e_monitor_counter_supported before calling this function*/
+void mlx5e_monitor_counter_init(struct mlx5e_priv *priv)
+{
+       mlx5e_set_monitor_counter(priv);
+       mlx5e_monitor_counter_arm(priv);
+}
+
+/* check if mlx5e_monitor_counter_supported before calling this function*/
+void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv)
+{
+       u32  in[MLX5_ST_SZ_DW(set_monitor_counter_in)]  = {};
+       u32 out[MLX5_ST_SZ_DW(set_monitor_counter_out)] = {};
+
+       MLX5_SET(set_monitor_counter_in, in, num_of_counters, 0);
+       MLX5_SET(set_monitor_counter_in, in, opcode,
+                MLX5_CMD_OP_SET_MONITOR_COUNTER);
+
+       mlx5_cmd_exec(priv->mdev, in, sizeof(in), out, sizeof(out));
+}