mlx5_diagnostics.c revision 322007
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: stable/10/sys/dev/mlx5/mlx5_core/mlx5_diagnostics.c 322007 2017-08-03 14:14:13Z hselasky $
26 */
27
28#include <dev/mlx5/driver.h>
29#include <dev/mlx5/diagnostics.h>
30
31const 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
37const 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
43static 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
61static 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
80int 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
160int 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
265int 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}
287