1312872Shselasky/*-
2312872Shselasky * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
3312872Shselasky *
4312872Shselasky * Redistribution and use in source and binary forms, with or without
5312872Shselasky * modification, are permitted provided that the following conditions
6312872Shselasky * are met:
7312872Shselasky * 1. Redistributions of source code must retain the above copyright
8312872Shselasky *    notice, this list of conditions and the following disclaimer.
9312872Shselasky * 2. Redistributions in binary form must reproduce the above copyright
10312872Shselasky *    notice, this list of conditions and the following disclaimer in the
11312872Shselasky *    documentation and/or other materials provided with the distribution.
12312872Shselasky *
13312872Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14312872Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15312872Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16312872Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17312872Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18312872Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19312872Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20312872Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21312872Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22312872Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23312872Shselasky * SUCH DAMAGE.
24312872Shselasky *
25312872Shselasky * $FreeBSD: stable/10/sys/dev/mlx5/mlx5_core/mlx5_diagnostics.c 322007 2017-08-03 14:14:13Z hselasky $
26312872Shselasky */
27312872Shselasky
28312872Shselasky#include <dev/mlx5/driver.h>
29312872Shselasky#include <dev/mlx5/diagnostics.h>
30312872Shselasky
31312872Shselaskyconst struct mlx5_core_diagnostics_entry
32312872Shselasky	mlx5_core_pci_diagnostics_table[
33312872Shselasky		MLX5_CORE_PCI_DIAGNOSTICS_NUM] = {
34312872Shselasky	MLX5_CORE_PCI_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
35312872Shselasky};
36312872Shselasky
37312872Shselaskyconst struct mlx5_core_diagnostics_entry
38312872Shselasky	mlx5_core_general_diagnostics_table[
39312872Shselasky		MLX5_CORE_GENERAL_DIAGNOSTICS_NUM] = {
40312872Shselasky	MLX5_CORE_GENERAL_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
41312872Shselasky};
42312872Shselasky
43312872Shselaskystatic int mlx5_core_get_index_of_diag_counter(
44312872Shselasky	const struct mlx5_core_diagnostics_entry *entry,
45312872Shselasky	int size, u16 counter_id)
46312872Shselasky{
47312872Shselasky	int x;
48312872Shselasky
49312872Shselasky	/* check for invalid counter ID */
50312872Shselasky	if (counter_id == 0)
51312872Shselasky		return -1;
52312872Shselasky
53312872Shselasky	/* lookup counter ID in table */
54312872Shselasky	for (x = 0; x != size; x++) {
55312872Shselasky		if (entry[x].counter_id == counter_id)
56312872Shselasky			return x;
57312872Shselasky	}
58312872Shselasky	return -1;
59312872Shselasky}
60312872Shselasky
61312872Shselaskystatic void mlx5_core_put_diag_counter(
62312872Shselasky	const struct mlx5_core_diagnostics_entry *entry,
63312872Shselasky	u64 *array, int size, u16 counter_id, u64 value)
64312872Shselasky{
65312872Shselasky	int x;
66312872Shselasky
67312872Shselasky	/* check for invalid counter ID */
68312872Shselasky	if (counter_id == 0)
69312872Shselasky		return;
70312872Shselasky
71312872Shselasky	/* lookup counter ID in table */
72312872Shselasky	for (x = 0; x != size; x++) {
73312872Shselasky		if (entry[x].counter_id == counter_id) {
74312872Shselasky			array[x] = value;
75312872Shselasky			break;
76312872Shselasky		}
77312872Shselasky	}
78312872Shselasky}
79312872Shselasky
80312872Shselaskyint mlx5_core_set_diagnostics_full(struct mlx5_core_dev *dev,
81312872Shselasky				   u8 enable_pci, u8 enable_general)
82312872Shselasky{
83312872Shselasky	void *diag_params_ctx;
84312872Shselasky	void *in;
85312872Shselasky	int numcounters;
86312872Shselasky	int inlen;
87312872Shselasky	int err;
88312872Shselasky	int x;
89312872Shselasky	int y;
90312872Shselasky
91312872Shselasky	if (MLX5_CAP_GEN(dev, debug) == 0)
92312872Shselasky		return 0;
93312872Shselasky
94312872Shselasky	numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
95312872Shselasky	if (numcounters == 0)
96312872Shselasky		return 0;
97312872Shselasky
98312872Shselasky	inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
99312872Shselasky	    MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
100312872Shselasky	in = mlx5_vzalloc(inlen);
101312872Shselasky	if (in == NULL)
102312872Shselasky		return -ENOMEM;
103312872Shselasky
104312872Shselasky	diag_params_ctx = MLX5_ADDR_OF(set_diagnostic_params_in, in,
105312872Shselasky				       diagnostic_params_ctx);
106312872Shselasky
107312872Shselasky	MLX5_SET(diagnostic_params_context, diag_params_ctx,
108312872Shselasky		 enable, enable_pci || enable_general);
109312872Shselasky	MLX5_SET(diagnostic_params_context, diag_params_ctx,
110312872Shselasky		 single, 1);
111312872Shselasky	MLX5_SET(diagnostic_params_context, diag_params_ctx,
112312872Shselasky		 on_demand, 1);
113312872Shselasky
114312872Shselasky	/* collect the counters we want to enable */
115312872Shselasky	for (x = y = 0; x != numcounters; x++) {
116312872Shselasky		u16 counter_id =
117312872Shselasky			MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id);
118312872Shselasky		int index = -1;
119312872Shselasky
120312872Shselasky		if (index < 0 && enable_pci != 0) {
121312872Shselasky			/* check if counter ID exists in local table */
122312872Shselasky			index = mlx5_core_get_index_of_diag_counter(
123312872Shselasky			    mlx5_core_pci_diagnostics_table,
124312872Shselasky			    MLX5_CORE_PCI_DIAGNOSTICS_NUM,
125312872Shselasky			    counter_id);
126312872Shselasky		}
127312872Shselasky		if (index < 0 && enable_general != 0) {
128312872Shselasky			/* check if counter ID exists in local table */
129312872Shselasky			index = mlx5_core_get_index_of_diag_counter(
130312872Shselasky			    mlx5_core_general_diagnostics_table,
131312872Shselasky			    MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
132312872Shselasky			    counter_id);
133312872Shselasky		}
134312872Shselasky		if (index < 0)
135312872Shselasky			continue;
136312872Shselasky
137312872Shselasky		MLX5_SET(diagnostic_params_context,
138312872Shselasky			 diag_params_ctx,
139312872Shselasky			 counter_id[y].counter_id,
140312872Shselasky			 counter_id);
141312872Shselasky		y++;
142312872Shselasky	}
143312872Shselasky
144312872Shselasky	/* recompute input length */
145312872Shselasky	inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
146312872Shselasky	    MLX5_ST_SZ_BYTES(diagnostic_counter) * y;
147312872Shselasky
148312872Shselasky	/* set number of counters */
149312872Shselasky	MLX5_SET(diagnostic_params_context, diag_params_ctx,
150312872Shselasky		 num_of_counters, y);
151312872Shselasky
152312872Shselasky	/* execute firmware command */
153312872Shselasky	err = mlx5_set_diagnostic_params(dev, in, inlen);
154312872Shselasky
155312872Shselasky	kvfree(in);
156312872Shselasky
157312872Shselasky	return err;
158312872Shselasky}
159312872Shselasky
160312872Shselaskyint mlx5_core_get_diagnostics_full(struct mlx5_core_dev *dev,
161312872Shselasky				   union mlx5_core_pci_diagnostics *pdiag,
162312872Shselasky				   union mlx5_core_general_diagnostics *pgen)
163312872Shselasky{
164312872Shselasky	void *out;
165312872Shselasky	void *in;
166312872Shselasky	int numcounters;
167312872Shselasky	int outlen;
168312872Shselasky	int inlen;
169312872Shselasky	int err;
170312872Shselasky	int x;
171312872Shselasky
172312872Shselasky	if (MLX5_CAP_GEN(dev, debug) == 0)
173312872Shselasky		return 0;
174312872Shselasky
175312872Shselasky	numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
176312872Shselasky	if (numcounters == 0)
177312872Shselasky		return 0;
178312872Shselasky
179312872Shselasky	outlen = MLX5_ST_SZ_BYTES(query_diagnostic_counters_out) +
180312872Shselasky	    MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
181312872Shselasky
182312872Shselasky	out = mlx5_vzalloc(outlen);
183312872Shselasky	if (out == NULL)
184312872Shselasky		return -ENOMEM;
185312872Shselasky
186312872Shselasky	err = mlx5_query_diagnostic_counters(dev, 1, 0, out, outlen);
187312872Shselasky	if (err == 0) {
188312872Shselasky		for (x = 0; x != numcounters; x++) {
189312872Shselasky			u16 counter_id = MLX5_GET(
190312872Shselasky			    query_diagnostic_counters_out,
191312872Shselasky			    out, diag_counter[x].counter_id);
192312872Shselasky			u64 counter_value = MLX5_GET64(
193312872Shselasky			    query_diagnostic_counters_out,
194312872Shselasky			    out, diag_counter[x].counter_value_h);
195312872Shselasky
196312872Shselasky			if (pdiag != NULL) {
197312872Shselasky				mlx5_core_put_diag_counter(
198312872Shselasky				    mlx5_core_pci_diagnostics_table,
199312872Shselasky				    pdiag->array,
200312872Shselasky				    MLX5_CORE_PCI_DIAGNOSTICS_NUM,
201312872Shselasky				    counter_id, counter_value);
202312872Shselasky			}
203312872Shselasky			if (pgen != NULL) {
204312872Shselasky				mlx5_core_put_diag_counter(
205312872Shselasky				    mlx5_core_general_diagnostics_table,
206312872Shselasky				    pgen->array,
207312872Shselasky				    MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
208312872Shselasky				    counter_id, counter_value);
209312872Shselasky			}
210312872Shselasky		}
211312872Shselasky	}
212312872Shselasky	kvfree(out);
213312872Shselasky
214312872Shselasky	if (pdiag != NULL) {
215312872Shselasky		inlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
216312872Shselasky		outlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
217312872Shselasky
218312872Shselasky		in = mlx5_vzalloc(inlen);
219312872Shselasky		if (in == NULL)
220312872Shselasky			return -ENOMEM;
221312872Shselasky
222312872Shselasky		out = mlx5_vzalloc(outlen);
223312872Shselasky		if (out == NULL) {
224312872Shselasky			kvfree(in);
225312872Shselasky			return -ENOMEM;
226312872Shselasky		}
227312872Shselasky		MLX5_SET(mpcnt_reg, in, grp,
228312872Shselasky			 MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
229312872Shselasky
230312872Shselasky		err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
231312872Shselasky					   MLX5_REG_MPCNT, 0, 0);
232312872Shselasky		if (err == 0) {
233312872Shselasky			void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
234312872Shselasky			    counter_set.pcie_performance_counters_data_layout);
235312872Shselasky
236312872Shselasky			pdiag->counter.rx_pci_errors =
237312872Shselasky			    MLX5_GET(pcie_performance_counters_data_layout,
238312872Shselasky				     pcounters, rx_errors);
239312872Shselasky			pdiag->counter.tx_pci_errors =
240312872Shselasky			    MLX5_GET(pcie_performance_counters_data_layout,
241312872Shselasky				     pcounters, tx_errors);
242312872Shselasky		}
243312872Shselasky		MLX5_SET(mpcnt_reg, in, grp,
244312872Shselasky			 MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP);
245312872Shselasky
246312872Shselasky		err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
247312872Shselasky		    MLX5_REG_MPCNT, 0, 0);
248312872Shselasky		if (err == 0) {
249312872Shselasky			void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
250312872Shselasky			    counter_set.pcie_timers_and_states_data_layout);
251312872Shselasky
252312872Shselasky			pdiag->counter.tx_pci_non_fatal_errors =
253312872Shselasky			    MLX5_GET(pcie_timers_and_states_data_layout,
254312872Shselasky				     pcounters, non_fatal_err_msg_sent);
255312872Shselasky			pdiag->counter.tx_pci_fatal_errors =
256312872Shselasky			    MLX5_GET(pcie_timers_and_states_data_layout,
257312872Shselasky				     pcounters, fatal_err_msg_sent);
258312872Shselasky		}
259312872Shselasky		kvfree(in);
260312872Shselasky		kvfree(out);
261312872Shselasky	}
262312872Shselasky	return 0;
263312872Shselasky}
264312872Shselasky
265312872Shselaskyint mlx5_core_supports_diagnostics(struct mlx5_core_dev *dev, u16 counter_id)
266312872Shselasky{
267312872Shselasky	int numcounters;
268312872Shselasky	int x;
269312872Shselasky
270312872Shselasky	if (MLX5_CAP_GEN(dev, debug) == 0)
271312872Shselasky		return 0;
272312872Shselasky
273312872Shselasky	/* check for any counter */
274312872Shselasky	if (counter_id == 0)
275312872Shselasky		return 1;
276312872Shselasky
277312872Shselasky	numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
278312872Shselasky
279312872Shselasky	/* check if counter ID exists in debug capability */
280312872Shselasky	for (x = 0; x != numcounters; x++) {
281312872Shselasky		if (MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id) ==
282312872Shselasky		    counter_id)
283312872Shselasky			return 1;
284312872Shselasky	}
285312872Shselasky	return 0;			/* not supported counter */
286312872Shselasky}
287