Merge tag 'tag-chrome-platform-for-v5.11' of git://git.kernel.org/pub/scm/linux/kerne...
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / monitor_stats.c
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 }