net/mlx5e: Monitor counters commands support
authorEyal Davidovich <eyald@mellanox.com>
Mon, 8 Oct 2018 09:16:01 +0000 (12:16 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Tue, 11 Dec 2018 22:52:20 +0000 (14:52 -0800)
new file monitor_stats.c for the new API.
add arm_monitor_counter new command support.
add set_monitor_counter new command support.

The device can monitor specific counters and provide an event to notify
when these counters are changed.
The monitoring is done in best effort manner where the minimum
notification period is 200 ms, however when the device is loaded, the
notification might be delayed.
To configure the required counters to be monitored, the
SET_MONITOR_COUNTER command shall be used with a list of counters to be
monitored.
The device firmware can monitor up to HCA_CAP.max_num_of_monitor_counters.
The configuration is done based on counter type (such as ppcnt, q counter,
etc) and additional param according to the type of counter selected.
Upon monitor counter change, the device will generate
Monitor_Counter_Change event.
The device will not generate new events unless the driver re-arms the
monitoring functionality, using the ARM_MONITOR_COUNTER command.

Signed-off-by: Eyal Davidovich <eyald@mellanox.com>
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h [new file with mode: 0644]

index 40764d87413aeddf436b5af1f4a3d94fd89127d6..9678051b8ff1ec27389aa34a7c13e59a61b4256e 100644 (file)
@@ -22,7 +22,7 @@ mlx5_core-y :=        main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
 #
 mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
                en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o \
-               en_selftest.o en/port.o
+               en_selftest.o en/port.o en/monitor_stats.o
 
 #
 # Netdev extra
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
new file mode 100644 (file)
index 0000000..0f010ef
--- /dev/null
@@ -0,0 +1,126 @@
+/* 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));
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h
new file mode 100644 (file)
index 0000000..e1ac4b3
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#ifndef __MLX5_MONITOR_H__
+#define __MLX5_MONITOR_H__
+
+int  mlx5e_monitor_counter_supported(struct mlx5e_priv *priv);
+void mlx5e_monitor_counter_init(struct mlx5e_priv *priv);
+void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv);
+void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv);
+
+#endif /* __MLX5_MONITOR_H__ */