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