The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mlx5/mlx5_core/mlx5_diagnostics.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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$
   26  */
   27 
   28 #include "opt_rss.h"
   29 #include "opt_ratelimit.h"
   30 
   31 #include <dev/mlx5/driver.h>
   32 #include <dev/mlx5/port.h>
   33 #include <dev/mlx5/diagnostics.h>
   34 #include <dev/mlx5/mlx5_core/mlx5_core.h>
   35 #include <net/sff8472.h>
   36 
   37 const struct mlx5_core_diagnostics_entry
   38         mlx5_core_pci_diagnostics_table[
   39                 MLX5_CORE_PCI_DIAGNOSTICS_NUM] = {
   40         MLX5_CORE_PCI_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
   41 };
   42 
   43 const struct mlx5_core_diagnostics_entry
   44         mlx5_core_general_diagnostics_table[
   45                 MLX5_CORE_GENERAL_DIAGNOSTICS_NUM] = {
   46         MLX5_CORE_GENERAL_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY)
   47 };
   48 
   49 static int mlx5_core_get_index_of_diag_counter(
   50         const struct mlx5_core_diagnostics_entry *entry,
   51         int size, u16 counter_id)
   52 {
   53         int x;
   54 
   55         /* check for invalid counter ID */
   56         if (counter_id == 0)
   57                 return -1;
   58 
   59         /* lookup counter ID in table */
   60         for (x = 0; x != size; x++) {
   61                 if (entry[x].counter_id == counter_id)
   62                         return x;
   63         }
   64         return -1;
   65 }
   66 
   67 static void mlx5_core_put_diag_counter(
   68         const struct mlx5_core_diagnostics_entry *entry,
   69         u64 *array, int size, u16 counter_id, u64 value)
   70 {
   71         int x;
   72 
   73         /* check for invalid counter ID */
   74         if (counter_id == 0)
   75                 return;
   76 
   77         /* lookup counter ID in table */
   78         for (x = 0; x != size; x++) {
   79                 if (entry[x].counter_id == counter_id) {
   80                         array[x] = value;
   81                         break;
   82                 }
   83         }
   84 }
   85 
   86 int mlx5_core_set_diagnostics_full(struct mlx5_core_dev *dev,
   87                                    u8 enable_pci, u8 enable_general)
   88 {
   89         void *diag_params_ctx;
   90         void *in;
   91         int numcounters;
   92         int inlen;
   93         int err;
   94         int x;
   95         int y;
   96 
   97         if (MLX5_CAP_GEN(dev, debug) == 0)
   98                 return 0;
   99 
  100         numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
  101         if (numcounters == 0)
  102                 return 0;
  103 
  104         inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
  105             MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
  106         in = mlx5_vzalloc(inlen);
  107         if (in == NULL)
  108                 return -ENOMEM;
  109 
  110         diag_params_ctx = MLX5_ADDR_OF(set_diagnostic_params_in, in,
  111                                        diagnostic_params_ctx);
  112 
  113         MLX5_SET(diagnostic_params_context, diag_params_ctx,
  114                  enable, enable_pci || enable_general);
  115         MLX5_SET(diagnostic_params_context, diag_params_ctx,
  116                  single, 1);
  117         MLX5_SET(diagnostic_params_context, diag_params_ctx,
  118                  on_demand, 1);
  119 
  120         /* collect the counters we want to enable */
  121         for (x = y = 0; x != numcounters; x++) {
  122                 u16 counter_id =
  123                         MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id);
  124                 int index = -1;
  125 
  126                 if (index < 0 && enable_pci != 0) {
  127                         /* check if counter ID exists in local table */
  128                         index = mlx5_core_get_index_of_diag_counter(
  129                             mlx5_core_pci_diagnostics_table,
  130                             MLX5_CORE_PCI_DIAGNOSTICS_NUM,
  131                             counter_id);
  132                 }
  133                 if (index < 0 && enable_general != 0) {
  134                         /* check if counter ID exists in local table */
  135                         index = mlx5_core_get_index_of_diag_counter(
  136                             mlx5_core_general_diagnostics_table,
  137                             MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
  138                             counter_id);
  139                 }
  140                 if (index < 0)
  141                         continue;
  142 
  143                 MLX5_SET(diagnostic_params_context,
  144                          diag_params_ctx,
  145                          counter_id[y].counter_id,
  146                          counter_id);
  147                 y++;
  148         }
  149 
  150         /* recompute input length */
  151         inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) +
  152             MLX5_ST_SZ_BYTES(diagnostic_counter) * y;
  153 
  154         /* set number of counters */
  155         MLX5_SET(diagnostic_params_context, diag_params_ctx,
  156                  num_of_counters, y);
  157 
  158         /* execute firmware command */
  159         err = mlx5_set_diagnostic_params(dev, in, inlen);
  160 
  161         kvfree(in);
  162 
  163         return err;
  164 }
  165 
  166 int mlx5_core_get_diagnostics_full(struct mlx5_core_dev *dev,
  167                                    union mlx5_core_pci_diagnostics *pdiag,
  168                                    union mlx5_core_general_diagnostics *pgen)
  169 {
  170         void *out;
  171         void *in;
  172         int numcounters;
  173         int outlen;
  174         int inlen;
  175         int err;
  176         int x;
  177 
  178         if (MLX5_CAP_GEN(dev, debug) == 0)
  179                 return 0;
  180 
  181         numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
  182         if (numcounters == 0)
  183                 return 0;
  184 
  185         outlen = MLX5_ST_SZ_BYTES(query_diagnostic_counters_out) +
  186             MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters;
  187 
  188         out = mlx5_vzalloc(outlen);
  189         if (out == NULL)
  190                 return -ENOMEM;
  191 
  192         err = mlx5_query_diagnostic_counters(dev, 1, 0, out, outlen);
  193         if (err == 0) {
  194                 for (x = 0; x != numcounters; x++) {
  195                         u16 counter_id = MLX5_GET(
  196                             query_diagnostic_counters_out,
  197                             out, diag_counter[x].counter_id);
  198                         u64 counter_value = MLX5_GET64(
  199                             query_diagnostic_counters_out,
  200                             out, diag_counter[x].counter_value_h);
  201 
  202                         if (pdiag != NULL) {
  203                                 mlx5_core_put_diag_counter(
  204                                     mlx5_core_pci_diagnostics_table,
  205                                     pdiag->array,
  206                                     MLX5_CORE_PCI_DIAGNOSTICS_NUM,
  207                                     counter_id, counter_value);
  208                         }
  209                         if (pgen != NULL) {
  210                                 mlx5_core_put_diag_counter(
  211                                     mlx5_core_general_diagnostics_table,
  212                                     pgen->array,
  213                                     MLX5_CORE_GENERAL_DIAGNOSTICS_NUM,
  214                                     counter_id, counter_value);
  215                         }
  216                 }
  217         }
  218         kvfree(out);
  219 
  220         if (pdiag != NULL) {
  221                 inlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
  222                 outlen = MLX5_ST_SZ_BYTES(mpcnt_reg);
  223 
  224                 in = mlx5_vzalloc(inlen);
  225                 if (in == NULL)
  226                         return -ENOMEM;
  227 
  228                 out = mlx5_vzalloc(outlen);
  229                 if (out == NULL) {
  230                         kvfree(in);
  231                         return -ENOMEM;
  232                 }
  233                 MLX5_SET(mpcnt_reg, in, grp,
  234                          MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
  235 
  236                 err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
  237                                            MLX5_REG_MPCNT, 0, 0);
  238                 if (err == 0) {
  239                         void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
  240                             counter_set.pcie_perf_counters);
  241 
  242                         pdiag->counter.rx_pci_errors =
  243                             MLX5_GET(pcie_perf_counters,
  244                                      pcounters, rx_errors);
  245                         pdiag->counter.tx_pci_errors =
  246                             MLX5_GET(pcie_perf_counters,
  247                                      pcounters, tx_errors);
  248                 }
  249                 MLX5_SET(mpcnt_reg, in, grp,
  250                          MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP);
  251 
  252                 err = mlx5_core_access_reg(dev, in, inlen, out, outlen,
  253                     MLX5_REG_MPCNT, 0, 0);
  254                 if (err == 0) {
  255                         void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out,
  256                             counter_set.pcie_timers_states);
  257 
  258                         pdiag->counter.tx_pci_non_fatal_errors =
  259                             MLX5_GET(pcie_timers_states,
  260                                      pcounters, non_fatal_err_msg_sent);
  261                         pdiag->counter.tx_pci_fatal_errors =
  262                             MLX5_GET(pcie_timers_states,
  263                                      pcounters, fatal_err_msg_sent);
  264                 }
  265                 kvfree(in);
  266                 kvfree(out);
  267         }
  268         return 0;
  269 }
  270 
  271 int mlx5_core_supports_diagnostics(struct mlx5_core_dev *dev, u16 counter_id)
  272 {
  273         int numcounters;
  274         int x;
  275 
  276         if (MLX5_CAP_GEN(dev, debug) == 0)
  277                 return 0;
  278 
  279         /* check for any counter */
  280         if (counter_id == 0)
  281                 return 1;
  282 
  283         numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters);
  284 
  285         /* check if counter ID exists in debug capability */
  286         for (x = 0; x != numcounters; x++) {
  287                 if (MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id) ==
  288                     counter_id)
  289                         return 1;
  290         }
  291         return 0;                       /* not supported counter */
  292 }
  293 
  294 /*
  295  * Read the first three bytes of the eeprom in order to get the needed info
  296  * for the whole reading.
  297  * Byte 0 - Identifier byte
  298  * Byte 1 - Revision byte
  299  * Byte 2 - Status byte
  300  */
  301 int
  302 mlx5_get_eeprom_info(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom)
  303 {
  304         u32 data = 0;
  305         int size_read = 0;
  306         int ret;
  307 
  308         ret = mlx5_query_module_num(dev, &eeprom->module_num);
  309         if (ret) {
  310                 mlx5_core_err(dev, "Failed query module error=%d\n", ret);
  311                 return (-ret);
  312         }
  313 
  314         /* Read the first three bytes to get Identifier, Revision and Status */
  315         ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
  316             eeprom->device_addr, MLX5_EEPROM_INFO_BYTES, eeprom->module_num, &data,
  317             &size_read);
  318         if (ret) {
  319                 mlx5_core_err(dev,
  320                     "Failed query EEPROM module error=0x%x\n", ret);
  321                 return (-ret);
  322         }
  323 
  324         switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
  325         case SFF_8024_ID_QSFP:
  326                 eeprom->type = MLX5_ETH_MODULE_SFF_8436;
  327                 eeprom->len = MLX5_ETH_MODULE_SFF_8436_LEN;
  328                 break;
  329         case SFF_8024_ID_QSFPPLUS:
  330         case SFF_8024_ID_QSFP28:
  331                 if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
  332                     ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
  333                         eeprom->type = MLX5_ETH_MODULE_SFF_8636;
  334                         eeprom->len = MLX5_ETH_MODULE_SFF_8636_LEN;
  335                 } else {
  336                         eeprom->type = MLX5_ETH_MODULE_SFF_8436;
  337                         eeprom->len = MLX5_ETH_MODULE_SFF_8436_LEN;
  338                 }
  339                 if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
  340                         eeprom->page_valid = 1;
  341                 break;
  342         case SFF_8024_ID_SFP:
  343                 eeprom->type = MLX5_ETH_MODULE_SFF_8472;
  344                 eeprom->len = MLX5_ETH_MODULE_SFF_8472_LEN;
  345                 break;
  346         default:
  347                 mlx5_core_err(dev, "Not recognized cable type = 0x%x(%s)\n",
  348                     data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
  349                     sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
  350                 return (EINVAL);
  351         }
  352         return (0);
  353 }
  354 
  355 /* Read both low and high pages of the eeprom */
  356 int
  357 mlx5_get_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *ee)
  358 {
  359         int size_read = 0;
  360         int ret;
  361 
  362         if (ee->len == 0)
  363                 return (EINVAL);
  364 
  365         /* Read low page of the eeprom */
  366         while (ee->device_addr < ee->len) {
  367                 ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
  368                     ee->len - ee->device_addr, ee->module_num,
  369                     ee->data + (ee->device_addr / 4), &size_read);
  370                 if (ret) {
  371                         mlx5_core_err(dev,
  372                             "Failed reading EEPROM, error = 0x%02x\n", ret);
  373                         return (-ret);
  374                 }
  375                 ee->device_addr += size_read;
  376         }
  377 
  378         /* Read high page of the eeprom */
  379         if (ee->page_valid == 1) {
  380                 ee->device_addr = MLX5_EEPROM_HIGH_PAGE_OFFSET;
  381                 ee->page_num = MLX5_EEPROM_HIGH_PAGE;
  382                 size_read = 0;
  383                 while (ee->device_addr < MLX5_EEPROM_PAGE_LENGTH) {
  384                         ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
  385                             ee->device_addr, MLX5_EEPROM_PAGE_LENGTH - ee->device_addr,
  386                             ee->module_num, ee->data + (ee->len / 4) +
  387                             ((ee->device_addr - MLX5_EEPROM_HIGH_PAGE_OFFSET) / 4),
  388                             &size_read);
  389                         if (ret) {
  390                                 mlx5_core_err(dev,
  391                                     "Failed reading EEPROM, error = 0x%02x\n",
  392                                     ret);
  393                                 return (-ret);
  394                         }
  395                         ee->device_addr += size_read;
  396                 }
  397         }
  398         return (0);
  399 }
  400 
  401 /*
  402  * Read cable EEPROM module information by first inspecting the first
  403  * three bytes to get the initial information for a whole reading.
  404  * Information will be printed to dmesg.
  405  */
  406 int
  407 mlx5_read_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom)
  408 {
  409         int error;
  410 
  411         eeprom->i2c_addr = MLX5_I2C_ADDR_LOW;
  412         eeprom->device_addr = 0;
  413         eeprom->page_num = MLX5_EEPROM_LOW_PAGE;
  414         eeprom->page_valid = 0;
  415 
  416         /* Read three first bytes to get important info */
  417         error = mlx5_get_eeprom_info(dev, eeprom);
  418         if (error) {
  419                 mlx5_core_err(dev,
  420                     "Failed reading EEPROM initial information\n");
  421                 return (error);
  422         }
  423         /*
  424          * Allocate needed length buffer and additional space for
  425          * page 0x03
  426          */
  427         eeprom->data = malloc(eeprom->len + MLX5_EEPROM_PAGE_LENGTH,
  428             M_MLX5_EEPROM, M_WAITOK | M_ZERO);
  429 
  430         /* Read the whole eeprom information */
  431         error = mlx5_get_eeprom(dev, eeprom);
  432         if (error) {
  433                 mlx5_core_err(dev, "Failed reading EEPROM\n");
  434                 error = 0;
  435                 /*
  436                  * Continue printing partial information in case of
  437                  * an error
  438                  */
  439         }
  440         free(eeprom->data, M_MLX5_EEPROM);
  441 
  442         return (error);
  443 }
  444 
  445 

Cache object: 4727f969f48fe9e928dd8173f5738fed


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.