mlx5_diagnostics.c revision 322006
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/11/sys/dev/mlx5/mlx5_core/mlx5_diagnostics.c 322006 2017-08-03 14:12:23Z 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