]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/mlx5/mlx5_core/mlx5_diagnostics.c
MFC r312872:
[FreeBSD/stable/10.git] / sys / dev / mlx5 / mlx5_core / mlx5_diagnostics.c
1 /*-
2  * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #include <dev/mlx5/driver.h>
29 #include <dev/mlx5/diagnostics.h>
30
31 const struct mlx5_core_diagnostics_entry
32         mlx5_core_pci_diagnostics_table[
33                 MLX5_CORE_PCI_DIAGNOSTICS_NUM] = {
34         MLX5_CORE_PCI_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
35 };
36
37 const struct mlx5_core_diagnostics_entry
38         mlx5_core_general_diagnostics_table[
39                 MLX5_CORE_GENERAL_DIAGNOSTICS_NUM] = {
40         MLX5_CORE_GENERAL_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
41 };
42
43 static int mlx5_core_get_index_of_diag_counter(
44         const struct mlx5_core_diagnostics_entry *entry,
45         int size, u16 counter_id)
46 {
47         int x;
48
49         /* check for invalid counter ID */
50         if (counter_id == 0)
51                 return -1;
52
53         /* lookup counter ID in table */
54         for (x = 0; x != size; x++) {
55                 if (entry[x].counter_id == counter_id)
56                         return x;
57         }
58         return -1;
59 }
60
61 static void mlx5_core_put_diag_counter(
62         const struct mlx5_core_diagnostics_entry *entry,
63         u64 *array, int size, u16 counter_id, u64 value)
64 {
65         int x;
66
67         /* check for invalid counter ID */
68         if (counter_id == 0)
69                 return;
70
71         /* lookup counter ID in table */
72         for (x = 0; x != size; x++) {
73                 if (entry[x].counter_id == counter_id) {
74                         array[x] = value;
75                         break;
76                 }
77         }
78 }
79
80 int mlx5_core_set_diagnostics_full(struct mlx5_core_dev *dev,
81                                    u8 enable_pci, u8 enable_general)
82 {
83         void *diag_params_ctx;
84         void *in;
85         int numcounters;
86         int inlen;
87         int err;
88         int x;
89         int y;
90
91         if (MLX5_CAP_GEN(dev, debug) == 0)
92                 return 0;
93
94         numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
95         if (numcounters == 0)
96                 return 0;
97
98         inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
99             MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
100         in = mlx5_vzalloc(inlen);
101         if (in == NULL)
102                 return -ENOMEM;
103
104         diag_params_ctx = MLX5_ADDR_OF(set_diagnostic_params_in, in,
105                                        diagnostic_params_ctx);
106
107         MLX5_SET(diagnostic_params_context, diag_params_ctx,
108                  enable, enable_pci || enable_general);
109         MLX5_SET(diagnostic_params_context, diag_params_ctx,
110                  single, 1);
111         MLX5_SET(diagnostic_params_context, diag_params_ctx,
112                  on_demand, 1);
113
114         /* collect the counters we want to enable */
115         for (x = y = 0; x != numcounters; x++) {
116                 u16 counter_id =
117                         MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id);
118                 int index = -1;
119
120                 if (index < 0 && enable_pci != 0) {
121                         /* check if counter ID exists in local table */
122                         index = mlx5_core_get_index_of_diag_counter(
123                             mlx5_core_pci_diagnostics_table,
124                             MLX5_CORE_PCI_DIAGNOSTICS_NUM,
125                             counter_id);
126                 }
127                 if (index < 0 && enable_general != 0) {
128                         /* check if counter ID exists in local table */
129                         index = mlx5_core_get_index_of_diag_counter(
130                             mlx5_core_general_diagnostics_table,
131                             MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
132                             counter_id);
133                 }
134                 if (index < 0)
135                         continue;
136
137                 MLX5_SET(diagnostic_params_context,
138                          diag_params_ctx,
139                          counter_id[y].counter_id,
140                          counter_id);
141                 y++;
142         }
143
144         /* recompute input length */
145         inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
146             MLX5_ST_SZ_BYTES(diagnostic_counter) * y;
147
148         /* set number of counters */
149         MLX5_SET(diagnostic_params_context, diag_params_ctx,
150                  num_of_counters, y);
151
152         /* execute firmware command */
153         err = mlx5_set_diagnostic_params(dev, in, inlen);
154
155         kvfree(in);
156
157         return err;
158 }
159
160 int mlx5_core_get_diagnostics_full(struct mlx5_core_dev *dev,
161                                    union mlx5_core_pci_diagnostics *pdiag,
162                                    union mlx5_core_general_diagnostics *pgen)
163 {
164         void *out;
165         void *in;
166         int numcounters;
167         int outlen;
168         int inlen;
169         int err;
170         int x;
171
172         if (MLX5_CAP_GEN(dev, debug) == 0)
173                 return 0;
174
175         numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
176         if (numcounters == 0)
177                 return 0;
178
179         outlen = MLX5_ST_SZ_BYTES(query_diagnostic_counters_out) +
180             MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
181
182         out = mlx5_vzalloc(outlen);
183         if (out == NULL)
184                 return -ENOMEM;
185
186         err = mlx5_query_diagnostic_counters(dev, 1, 0, out, outlen);
187         if (err == 0) {
188                 for (x = 0; x != numcounters; x++) {
189                         u16 counter_id = MLX5_GET(
190                             query_diagnostic_counters_out,
191                             out, diag_counter[x].counter_id);
192                         u64 counter_value = MLX5_GET64(
193                             query_diagnostic_counters_out,
194                             out, diag_counter[x].counter_value_h);
195
196                         if (pdiag != NULL) {
197                                 mlx5_core_put_diag_counter(
198                                     mlx5_core_pci_diagnostics_table,
199                                     pdiag->array,
200                                     MLX5_CORE_PCI_DIAGNOSTICS_NUM,
201                                     counter_id, counter_value);
202                         }
203                         if (pgen != NULL) {
204                                 mlx5_core_put_diag_counter(
205                                     mlx5_core_general_diagnostics_table,
206                                     pgen->array,
207                                     MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
208                                     counter_id, counter_value);
209                         }
210                 }
211         }
212         kvfree(out);
213
214         if (pdiag != NULL) {
215                 inlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
216                 outlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
217
218                 in = mlx5_vzalloc(inlen);
219                 if (in == NULL)
220                         return -ENOMEM;
221
222                 out = mlx5_vzalloc(outlen);
223                 if (out == NULL) {
224                         kvfree(in);
225                         return -ENOMEM;
226                 }
227                 MLX5_SET(mpcnt_reg, in, grp,
228                          MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
229
230                 err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
231                                            MLX5_REG_MPCNT, 0, 0);
232                 if (err == 0) {
233                         void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
234                             counter_set.pcie_performance_counters_data_layout);
235
236                         pdiag->counter.rx_pci_errors =
237                             MLX5_GET(pcie_performance_counters_data_layout,
238                                      pcounters, rx_errors);
239                         pdiag->counter.tx_pci_errors =
240                             MLX5_GET(pcie_performance_counters_data_layout,
241                                      pcounters, tx_errors);
242                 }
243                 MLX5_SET(mpcnt_reg, in, grp,
244                          MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP);
245
246                 err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
247                     MLX5_REG_MPCNT, 0, 0);
248                 if (err == 0) {
249                         void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
250                             counter_set.pcie_timers_and_states_data_layout);
251
252                         pdiag->counter.tx_pci_non_fatal_errors =
253                             MLX5_GET(pcie_timers_and_states_data_layout,
254                                      pcounters, non_fatal_err_msg_sent);
255                         pdiag->counter.tx_pci_fatal_errors =
256                             MLX5_GET(pcie_timers_and_states_data_layout,
257                                      pcounters, fatal_err_msg_sent);
258                 }
259                 kvfree(in);
260                 kvfree(out);
261         }
262         return 0;
263 }
264
265 int mlx5_core_supports_diagnostics(struct mlx5_core_dev *dev, u16 counter_id)
266 {
267         int numcounters;
268         int x;
269
270         if (MLX5_CAP_GEN(dev, debug) == 0)
271                 return 0;
272
273         /* check for any counter */
274         if (counter_id == 0)
275                 return 1;
276
277         numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
278
279         /* check if counter ID exists in debug capability */
280         for (x = 0; x != numcounters; x++) {
281                 if (MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id) ==
282                     counter_id)
283                         return 1;
284         }
285         return 0;                       /* not supported counter */
286 }