166d53750SHans Petter Selasky /*-
266d53750SHans Petter Selasky  * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
366d53750SHans Petter Selasky  *
466d53750SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
566d53750SHans Petter Selasky  * modification, are permitted provided that the following conditions
666d53750SHans Petter Selasky  * are met:
766d53750SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
866d53750SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
966d53750SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
1066d53750SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
1166d53750SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
1266d53750SHans Petter Selasky  *
1366d53750SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
1466d53750SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1566d53750SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1666d53750SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1766d53750SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1866d53750SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1966d53750SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2066d53750SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2166d53750SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2266d53750SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2366d53750SHans Petter Selasky  * SUCH DAMAGE.
2466d53750SHans Petter Selasky  *
2566d53750SHans Petter Selasky  * $FreeBSD$
2666d53750SHans Petter Selasky  */
2766d53750SHans Petter Selasky 
2866d53750SHans Petter Selasky #include <dev/mlx5/driver.h>
2966d53750SHans Petter Selasky #include <dev/mlx5/diagnostics.h>
3066d53750SHans Petter Selasky 
3166d53750SHans Petter Selasky const struct mlx5_core_diagnostics_entry
3266d53750SHans Petter Selasky 	mlx5_core_pci_diagnostics_table[
3366d53750SHans Petter Selasky 		MLX5_CORE_PCI_DIAGNOSTICS_NUM] = {
3466d53750SHans Petter Selasky 	MLX5_CORE_PCI_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
3566d53750SHans Petter Selasky };
3666d53750SHans Petter Selasky 
3766d53750SHans Petter Selasky const struct mlx5_core_diagnostics_entry
3866d53750SHans Petter Selasky 	mlx5_core_general_diagnostics_table[
3966d53750SHans Petter Selasky 		MLX5_CORE_GENERAL_DIAGNOSTICS_NUM] = {
4066d53750SHans Petter Selasky 	MLX5_CORE_GENERAL_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
4166d53750SHans Petter Selasky };
4266d53750SHans Petter Selasky 
4366d53750SHans Petter Selasky static int mlx5_core_get_index_of_diag_counter(
4466d53750SHans Petter Selasky 	const struct mlx5_core_diagnostics_entry *entry,
4566d53750SHans Petter Selasky 	int size, u16 counter_id)
4666d53750SHans Petter Selasky {
4766d53750SHans Petter Selasky 	int x;
4866d53750SHans Petter Selasky 
4966d53750SHans Petter Selasky 	/* check for invalid counter ID */
5066d53750SHans Petter Selasky 	if (counter_id == 0)
5166d53750SHans Petter Selasky 		return -1;
5266d53750SHans Petter Selasky 
5366d53750SHans Petter Selasky 	/* lookup counter ID in table */
5466d53750SHans Petter Selasky 	for (x = 0; x != size; x++) {
5566d53750SHans Petter Selasky 		if (entry[x].counter_id == counter_id)
5666d53750SHans Petter Selasky 			return x;
5766d53750SHans Petter Selasky 	}
5866d53750SHans Petter Selasky 	return -1;
5966d53750SHans Petter Selasky }
6066d53750SHans Petter Selasky 
6166d53750SHans Petter Selasky static void mlx5_core_put_diag_counter(
6266d53750SHans Petter Selasky 	const struct mlx5_core_diagnostics_entry *entry,
6366d53750SHans Petter Selasky 	u64 *array, int size, u16 counter_id, u64 value)
6466d53750SHans Petter Selasky {
6566d53750SHans Petter Selasky 	int x;
6666d53750SHans Petter Selasky 
6766d53750SHans Petter Selasky 	/* check for invalid counter ID */
6866d53750SHans Petter Selasky 	if (counter_id == 0)
6966d53750SHans Petter Selasky 		return;
7066d53750SHans Petter Selasky 
7166d53750SHans Petter Selasky 	/* lookup counter ID in table */
7266d53750SHans Petter Selasky 	for (x = 0; x != size; x++) {
7366d53750SHans Petter Selasky 		if (entry[x].counter_id == counter_id) {
7466d53750SHans Petter Selasky 			array[x] = value;
7566d53750SHans Petter Selasky 			break;
7666d53750SHans Petter Selasky 		}
7766d53750SHans Petter Selasky 	}
7866d53750SHans Petter Selasky }
7966d53750SHans Petter Selasky 
8066d53750SHans Petter Selasky int mlx5_core_set_diagnostics_full(struct mlx5_core_dev *dev,
8166d53750SHans Petter Selasky 				   u8 enable_pci, u8 enable_general)
8266d53750SHans Petter Selasky {
8366d53750SHans Petter Selasky 	void *diag_params_ctx;
8466d53750SHans Petter Selasky 	void *in;
8566d53750SHans Petter Selasky 	int numcounters;
8666d53750SHans Petter Selasky 	int inlen;
8766d53750SHans Petter Selasky 	int err;
8866d53750SHans Petter Selasky 	int x;
8966d53750SHans Petter Selasky 	int y;
9066d53750SHans Petter Selasky 
9166d53750SHans Petter Selasky 	if (MLX5_CAP_GEN(dev, debug) == 0)
9266d53750SHans Petter Selasky 		return 0;
9366d53750SHans Petter Selasky 
9466d53750SHans Petter Selasky 	numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
9566d53750SHans Petter Selasky 	if (numcounters == 0)
9666d53750SHans Petter Selasky 		return 0;
9766d53750SHans Petter Selasky 
9866d53750SHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
9966d53750SHans Petter Selasky 	    MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
10066d53750SHans Petter Selasky 	in = mlx5_vzalloc(inlen);
10166d53750SHans Petter Selasky 	if (in == NULL)
10266d53750SHans Petter Selasky 		return -ENOMEM;
10366d53750SHans Petter Selasky 
10466d53750SHans Petter Selasky 	diag_params_ctx = MLX5_ADDR_OF(set_diagnostic_params_in, in,
10566d53750SHans Petter Selasky 				       diagnostic_params_ctx);
10666d53750SHans Petter Selasky 
10766d53750SHans Petter Selasky 	MLX5_SET(diagnostic_params_context, diag_params_ctx,
10866d53750SHans Petter Selasky 		 enable, enable_pci || enable_general);
10966d53750SHans Petter Selasky 	MLX5_SET(diagnostic_params_context, diag_params_ctx,
11066d53750SHans Petter Selasky 		 single, 1);
11166d53750SHans Petter Selasky 	MLX5_SET(diagnostic_params_context, diag_params_ctx,
11266d53750SHans Petter Selasky 		 on_demand, 1);
11366d53750SHans Petter Selasky 
11466d53750SHans Petter Selasky 	/* collect the counters we want to enable */
11566d53750SHans Petter Selasky 	for (x = y = 0; x != numcounters; x++) {
11666d53750SHans Petter Selasky 		u16 counter_id =
11766d53750SHans Petter Selasky 			MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id);
11866d53750SHans Petter Selasky 		int index = -1;
11966d53750SHans Petter Selasky 
12066d53750SHans Petter Selasky 		if (index < 0 && enable_pci != 0) {
12166d53750SHans Petter Selasky 			/* check if counter ID exists in local table */
12266d53750SHans Petter Selasky 			index = mlx5_core_get_index_of_diag_counter(
12366d53750SHans Petter Selasky 			    mlx5_core_pci_diagnostics_table,
12466d53750SHans Petter Selasky 			    MLX5_CORE_PCI_DIAGNOSTICS_NUM,
12566d53750SHans Petter Selasky 			    counter_id);
12666d53750SHans Petter Selasky 		}
12766d53750SHans Petter Selasky 		if (index < 0 && enable_general != 0) {
12866d53750SHans Petter Selasky 			/* check if counter ID exists in local table */
12966d53750SHans Petter Selasky 			index = mlx5_core_get_index_of_diag_counter(
13066d53750SHans Petter Selasky 			    mlx5_core_general_diagnostics_table,
13166d53750SHans Petter Selasky 			    MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
13266d53750SHans Petter Selasky 			    counter_id);
13366d53750SHans Petter Selasky 		}
13466d53750SHans Petter Selasky 		if (index < 0)
13566d53750SHans Petter Selasky 			continue;
13666d53750SHans Petter Selasky 
13766d53750SHans Petter Selasky 		MLX5_SET(diagnostic_params_context,
13866d53750SHans Petter Selasky 			 diag_params_ctx,
13966d53750SHans Petter Selasky 			 counter_id[y].counter_id,
14066d53750SHans Petter Selasky 			 counter_id);
14166d53750SHans Petter Selasky 		y++;
14266d53750SHans Petter Selasky 	}
14366d53750SHans Petter Selasky 
14466d53750SHans Petter Selasky 	/* recompute input length */
14566d53750SHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
14666d53750SHans Petter Selasky 	    MLX5_ST_SZ_BYTES(diagnostic_counter) * y;
14766d53750SHans Petter Selasky 
14866d53750SHans Petter Selasky 	/* set number of counters */
14966d53750SHans Petter Selasky 	MLX5_SET(diagnostic_params_context, diag_params_ctx,
15066d53750SHans Petter Selasky 		 num_of_counters, y);
15166d53750SHans Petter Selasky 
15266d53750SHans Petter Selasky 	/* execute firmware command */
15366d53750SHans Petter Selasky 	err = mlx5_set_diagnostic_params(dev, in, inlen);
15466d53750SHans Petter Selasky 
15566d53750SHans Petter Selasky 	kvfree(in);
15666d53750SHans Petter Selasky 
15766d53750SHans Petter Selasky 	return err;
15866d53750SHans Petter Selasky }
15966d53750SHans Petter Selasky 
16066d53750SHans Petter Selasky int mlx5_core_get_diagnostics_full(struct mlx5_core_dev *dev,
16166d53750SHans Petter Selasky 				   union mlx5_core_pci_diagnostics *pdiag,
16266d53750SHans Petter Selasky 				   union mlx5_core_general_diagnostics *pgen)
16366d53750SHans Petter Selasky {
16466d53750SHans Petter Selasky 	void *out;
16566d53750SHans Petter Selasky 	void *in;
16666d53750SHans Petter Selasky 	int numcounters;
16766d53750SHans Petter Selasky 	int outlen;
16866d53750SHans Petter Selasky 	int inlen;
16966d53750SHans Petter Selasky 	int err;
17066d53750SHans Petter Selasky 	int x;
17166d53750SHans Petter Selasky 
17266d53750SHans Petter Selasky 	if (MLX5_CAP_GEN(dev, debug) == 0)
17366d53750SHans Petter Selasky 		return 0;
17466d53750SHans Petter Selasky 
17566d53750SHans Petter Selasky 	numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
17666d53750SHans Petter Selasky 	if (numcounters == 0)
17766d53750SHans Petter Selasky 		return 0;
17866d53750SHans Petter Selasky 
17966d53750SHans Petter Selasky 	outlen = MLX5_ST_SZ_BYTES(query_diagnostic_counters_out) +
18066d53750SHans Petter Selasky 	    MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
18166d53750SHans Petter Selasky 
18266d53750SHans Petter Selasky 	out = mlx5_vzalloc(outlen);
18366d53750SHans Petter Selasky 	if (out == NULL)
18466d53750SHans Petter Selasky 		return -ENOMEM;
18566d53750SHans Petter Selasky 
18666d53750SHans Petter Selasky 	err = mlx5_query_diagnostic_counters(dev, 1, 0, out, outlen);
18766d53750SHans Petter Selasky 	if (err == 0) {
18866d53750SHans Petter Selasky 		for (x = 0; x != numcounters; x++) {
18966d53750SHans Petter Selasky 			u16 counter_id = MLX5_GET(
19066d53750SHans Petter Selasky 			    query_diagnostic_counters_out,
19166d53750SHans Petter Selasky 			    out, diag_counter[x].counter_id);
19266d53750SHans Petter Selasky 			u64 counter_value = MLX5_GET64(
19366d53750SHans Petter Selasky 			    query_diagnostic_counters_out,
19466d53750SHans Petter Selasky 			    out, diag_counter[x].counter_value_h);
19566d53750SHans Petter Selasky 
19666d53750SHans Petter Selasky 			if (pdiag != NULL) {
19766d53750SHans Petter Selasky 				mlx5_core_put_diag_counter(
19866d53750SHans Petter Selasky 				    mlx5_core_pci_diagnostics_table,
19966d53750SHans Petter Selasky 				    pdiag->array,
20066d53750SHans Petter Selasky 				    MLX5_CORE_PCI_DIAGNOSTICS_NUM,
20166d53750SHans Petter Selasky 				    counter_id, counter_value);
20266d53750SHans Petter Selasky 			}
20366d53750SHans Petter Selasky 			if (pgen != NULL) {
20466d53750SHans Petter Selasky 				mlx5_core_put_diag_counter(
20566d53750SHans Petter Selasky 				    mlx5_core_general_diagnostics_table,
20666d53750SHans Petter Selasky 				    pgen->array,
20766d53750SHans Petter Selasky 				    MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
20866d53750SHans Petter Selasky 				    counter_id, counter_value);
20966d53750SHans Petter Selasky 			}
21066d53750SHans Petter Selasky 		}
21166d53750SHans Petter Selasky 	}
21266d53750SHans Petter Selasky 	kvfree(out);
21366d53750SHans Petter Selasky 
21466d53750SHans Petter Selasky 	if (pdiag != NULL) {
21566d53750SHans Petter Selasky 		inlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
21666d53750SHans Petter Selasky 		outlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
21766d53750SHans Petter Selasky 
21866d53750SHans Petter Selasky 		in = mlx5_vzalloc(inlen);
21966d53750SHans Petter Selasky 		if (in == NULL)
22066d53750SHans Petter Selasky 			return -ENOMEM;
22166d53750SHans Petter Selasky 
22266d53750SHans Petter Selasky 		out = mlx5_vzalloc(outlen);
22366d53750SHans Petter Selasky 		if (out == NULL) {
22466d53750SHans Petter Selasky 			kvfree(in);
22566d53750SHans Petter Selasky 			return -ENOMEM;
22666d53750SHans Petter Selasky 		}
22766d53750SHans Petter Selasky 		MLX5_SET(mpcnt_reg, in, grp,
22866d53750SHans Petter Selasky 			 MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
22966d53750SHans Petter Selasky 
23066d53750SHans Petter Selasky 		err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
23166d53750SHans Petter Selasky 					   MLX5_REG_MPCNT, 0, 0);
23266d53750SHans Petter Selasky 		if (err == 0) {
23366d53750SHans Petter Selasky 			void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
234c71a71baSHans Petter Selasky 			    counter_set.pcie_perf_counters);
23566d53750SHans Petter Selasky 
23666d53750SHans Petter Selasky 			pdiag->counter.rx_pci_errors =
237c71a71baSHans Petter Selasky 			    MLX5_GET(pcie_perf_counters,
23866d53750SHans Petter Selasky 				     pcounters, rx_errors);
23966d53750SHans Petter Selasky 			pdiag->counter.tx_pci_errors =
240c71a71baSHans Petter Selasky 			    MLX5_GET(pcie_perf_counters,
24166d53750SHans Petter Selasky 				     pcounters, tx_errors);
24266d53750SHans Petter Selasky 		}
24366d53750SHans Petter Selasky 		MLX5_SET(mpcnt_reg, in, grp,
24466d53750SHans Petter Selasky 			 MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP);
24566d53750SHans Petter Selasky 
24666d53750SHans Petter Selasky 		err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
24766d53750SHans Petter Selasky 		    MLX5_REG_MPCNT, 0, 0);
24866d53750SHans Petter Selasky 		if (err == 0) {
24966d53750SHans Petter Selasky 			void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
250c71a71baSHans Petter Selasky 			    counter_set.pcie_timers_states);
25166d53750SHans Petter Selasky 
25266d53750SHans Petter Selasky 			pdiag->counter.tx_pci_non_fatal_errors =
253c71a71baSHans Petter Selasky 			    MLX5_GET(pcie_timers_states,
25466d53750SHans Petter Selasky 				     pcounters, non_fatal_err_msg_sent);
25566d53750SHans Petter Selasky 			pdiag->counter.tx_pci_fatal_errors =
256c71a71baSHans Petter Selasky 			    MLX5_GET(pcie_timers_states,
25766d53750SHans Petter Selasky 				     pcounters, fatal_err_msg_sent);
25866d53750SHans Petter Selasky 		}
25966d53750SHans Petter Selasky 		kvfree(in);
26066d53750SHans Petter Selasky 		kvfree(out);
26166d53750SHans Petter Selasky 	}
26266d53750SHans Petter Selasky 	return 0;
26366d53750SHans Petter Selasky }
26466d53750SHans Petter Selasky 
26566d53750SHans Petter Selasky int mlx5_core_supports_diagnostics(struct mlx5_core_dev *dev, u16 counter_id)
26666d53750SHans Petter Selasky {
26766d53750SHans Petter Selasky 	int numcounters;
26866d53750SHans Petter Selasky 	int x;
26966d53750SHans Petter Selasky 
27066d53750SHans Petter Selasky 	if (MLX5_CAP_GEN(dev, debug) == 0)
27166d53750SHans Petter Selasky 		return 0;
27266d53750SHans Petter Selasky 
27366d53750SHans Petter Selasky 	/* check for any counter */
27466d53750SHans Petter Selasky 	if (counter_id == 0)
27566d53750SHans Petter Selasky 		return 1;
27666d53750SHans Petter Selasky 
27766d53750SHans Petter Selasky 	numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
27866d53750SHans Petter Selasky 
27966d53750SHans Petter Selasky 	/* check if counter ID exists in debug capability */
28066d53750SHans Petter Selasky 	for (x = 0; x != numcounters; x++) {
28166d53750SHans Petter Selasky 		if (MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id) ==
28266d53750SHans Petter Selasky 		    counter_id)
28366d53750SHans Petter Selasky 			return 1;
28466d53750SHans Petter Selasky 	}
28566d53750SHans Petter Selasky 	return 0;			/* not supported counter */
28666d53750SHans Petter Selasky }
287