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 28ee9d634bSKonstantin Belousov #include "opt_rss.h" 29ee9d634bSKonstantin Belousov #include "opt_ratelimit.h" 30ee9d634bSKonstantin Belousov 3166d53750SHans Petter Selasky #include <dev/mlx5/driver.h> 32048ddb58SHans Petter Selasky #include <dev/mlx5/port.h> 3366d53750SHans Petter Selasky #include <dev/mlx5/diagnostics.h> 34048ddb58SHans Petter Selasky #include <dev/mlx5/mlx5_core/mlx5_core.h> 35048ddb58SHans Petter Selasky #include <net/sff8472.h> 3666d53750SHans Petter Selasky 3766d53750SHans Petter Selasky const struct mlx5_core_diagnostics_entry 3866d53750SHans Petter Selasky mlx5_core_pci_diagnostics_table[ 3966d53750SHans Petter Selasky MLX5_CORE_PCI_DIAGNOSTICS_NUM] = { 4066d53750SHans Petter Selasky MLX5_CORE_PCI_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY) 4166d53750SHans Petter Selasky }; 4266d53750SHans Petter Selasky 4366d53750SHans Petter Selasky const struct mlx5_core_diagnostics_entry 4466d53750SHans Petter Selasky mlx5_core_general_diagnostics_table[ 4566d53750SHans Petter Selasky MLX5_CORE_GENERAL_DIAGNOSTICS_NUM] = { 4666d53750SHans Petter Selasky MLX5_CORE_GENERAL_DIAGNOSTICS(MLX5_CORE_DIAGNOSTICS_ENTRY) 4766d53750SHans Petter Selasky }; 4866d53750SHans Petter Selasky 4966d53750SHans Petter Selasky static int mlx5_core_get_index_of_diag_counter( 5066d53750SHans Petter Selasky const struct mlx5_core_diagnostics_entry *entry, 5166d53750SHans Petter Selasky int size, u16 counter_id) 5266d53750SHans Petter Selasky { 5366d53750SHans Petter Selasky int x; 5466d53750SHans Petter Selasky 5566d53750SHans Petter Selasky /* check for invalid counter ID */ 5666d53750SHans Petter Selasky if (counter_id == 0) 5766d53750SHans Petter Selasky return -1; 5866d53750SHans Petter Selasky 5966d53750SHans Petter Selasky /* lookup counter ID in table */ 6066d53750SHans Petter Selasky for (x = 0; x != size; x++) { 6166d53750SHans Petter Selasky if (entry[x].counter_id == counter_id) 6266d53750SHans Petter Selasky return x; 6366d53750SHans Petter Selasky } 6466d53750SHans Petter Selasky return -1; 6566d53750SHans Petter Selasky } 6666d53750SHans Petter Selasky 6766d53750SHans Petter Selasky static void mlx5_core_put_diag_counter( 6866d53750SHans Petter Selasky const struct mlx5_core_diagnostics_entry *entry, 6966d53750SHans Petter Selasky u64 *array, int size, u16 counter_id, u64 value) 7066d53750SHans Petter Selasky { 7166d53750SHans Petter Selasky int x; 7266d53750SHans Petter Selasky 7366d53750SHans Petter Selasky /* check for invalid counter ID */ 7466d53750SHans Petter Selasky if (counter_id == 0) 7566d53750SHans Petter Selasky return; 7666d53750SHans Petter Selasky 7766d53750SHans Petter Selasky /* lookup counter ID in table */ 7866d53750SHans Petter Selasky for (x = 0; x != size; x++) { 7966d53750SHans Petter Selasky if (entry[x].counter_id == counter_id) { 8066d53750SHans Petter Selasky array[x] = value; 8166d53750SHans Petter Selasky break; 8266d53750SHans Petter Selasky } 8366d53750SHans Petter Selasky } 8466d53750SHans Petter Selasky } 8566d53750SHans Petter Selasky 8666d53750SHans Petter Selasky int mlx5_core_set_diagnostics_full(struct mlx5_core_dev *dev, 8766d53750SHans Petter Selasky u8 enable_pci, u8 enable_general) 8866d53750SHans Petter Selasky { 8966d53750SHans Petter Selasky void *diag_params_ctx; 9066d53750SHans Petter Selasky void *in; 9166d53750SHans Petter Selasky int numcounters; 9266d53750SHans Petter Selasky int inlen; 9366d53750SHans Petter Selasky int err; 9466d53750SHans Petter Selasky int x; 9566d53750SHans Petter Selasky int y; 9666d53750SHans Petter Selasky 9766d53750SHans Petter Selasky if (MLX5_CAP_GEN(dev, debug) == 0) 9866d53750SHans Petter Selasky return 0; 9966d53750SHans Petter Selasky 10066d53750SHans Petter Selasky numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters); 10166d53750SHans Petter Selasky if (numcounters == 0) 10266d53750SHans Petter Selasky return 0; 10366d53750SHans Petter Selasky 10466d53750SHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) + 10566d53750SHans Petter Selasky MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters; 10666d53750SHans Petter Selasky in = mlx5_vzalloc(inlen); 10766d53750SHans Petter Selasky if (in == NULL) 10866d53750SHans Petter Selasky return -ENOMEM; 10966d53750SHans Petter Selasky 11066d53750SHans Petter Selasky diag_params_ctx = MLX5_ADDR_OF(set_diagnostic_params_in, in, 11166d53750SHans Petter Selasky diagnostic_params_ctx); 11266d53750SHans Petter Selasky 11366d53750SHans Petter Selasky MLX5_SET(diagnostic_params_context, diag_params_ctx, 11466d53750SHans Petter Selasky enable, enable_pci || enable_general); 11566d53750SHans Petter Selasky MLX5_SET(diagnostic_params_context, diag_params_ctx, 11666d53750SHans Petter Selasky single, 1); 11766d53750SHans Petter Selasky MLX5_SET(diagnostic_params_context, diag_params_ctx, 11866d53750SHans Petter Selasky on_demand, 1); 11966d53750SHans Petter Selasky 12066d53750SHans Petter Selasky /* collect the counters we want to enable */ 12166d53750SHans Petter Selasky for (x = y = 0; x != numcounters; x++) { 12266d53750SHans Petter Selasky u16 counter_id = 12366d53750SHans Petter Selasky MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id); 12466d53750SHans Petter Selasky int index = -1; 12566d53750SHans Petter Selasky 12666d53750SHans Petter Selasky if (index < 0 && enable_pci != 0) { 12766d53750SHans Petter Selasky /* check if counter ID exists in local table */ 12866d53750SHans Petter Selasky index = mlx5_core_get_index_of_diag_counter( 12966d53750SHans Petter Selasky mlx5_core_pci_diagnostics_table, 13066d53750SHans Petter Selasky MLX5_CORE_PCI_DIAGNOSTICS_NUM, 13166d53750SHans Petter Selasky counter_id); 13266d53750SHans Petter Selasky } 13366d53750SHans Petter Selasky if (index < 0 && enable_general != 0) { 13466d53750SHans Petter Selasky /* check if counter ID exists in local table */ 13566d53750SHans Petter Selasky index = mlx5_core_get_index_of_diag_counter( 13666d53750SHans Petter Selasky mlx5_core_general_diagnostics_table, 13766d53750SHans Petter Selasky MLX5_CORE_GENERAL_DIAGNOSTICS_NUM, 13866d53750SHans Petter Selasky counter_id); 13966d53750SHans Petter Selasky } 14066d53750SHans Petter Selasky if (index < 0) 14166d53750SHans Petter Selasky continue; 14266d53750SHans Petter Selasky 14366d53750SHans Petter Selasky MLX5_SET(diagnostic_params_context, 14466d53750SHans Petter Selasky diag_params_ctx, 14566d53750SHans Petter Selasky counter_id[y].counter_id, 14666d53750SHans Petter Selasky counter_id); 14766d53750SHans Petter Selasky y++; 14866d53750SHans Petter Selasky } 14966d53750SHans Petter Selasky 15066d53750SHans Petter Selasky /* recompute input length */ 15166d53750SHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(set_diagnostic_params_in) + 15266d53750SHans Petter Selasky MLX5_ST_SZ_BYTES(diagnostic_counter) * y; 15366d53750SHans Petter Selasky 15466d53750SHans Petter Selasky /* set number of counters */ 15566d53750SHans Petter Selasky MLX5_SET(diagnostic_params_context, diag_params_ctx, 15666d53750SHans Petter Selasky num_of_counters, y); 15766d53750SHans Petter Selasky 15866d53750SHans Petter Selasky /* execute firmware command */ 15966d53750SHans Petter Selasky err = mlx5_set_diagnostic_params(dev, in, inlen); 16066d53750SHans Petter Selasky 16166d53750SHans Petter Selasky kvfree(in); 16266d53750SHans Petter Selasky 16366d53750SHans Petter Selasky return err; 16466d53750SHans Petter Selasky } 16566d53750SHans Petter Selasky 16666d53750SHans Petter Selasky int mlx5_core_get_diagnostics_full(struct mlx5_core_dev *dev, 16766d53750SHans Petter Selasky union mlx5_core_pci_diagnostics *pdiag, 16866d53750SHans Petter Selasky union mlx5_core_general_diagnostics *pgen) 16966d53750SHans Petter Selasky { 17066d53750SHans Petter Selasky void *out; 17166d53750SHans Petter Selasky void *in; 17266d53750SHans Petter Selasky int numcounters; 17366d53750SHans Petter Selasky int outlen; 17466d53750SHans Petter Selasky int inlen; 17566d53750SHans Petter Selasky int err; 17666d53750SHans Petter Selasky int x; 17766d53750SHans Petter Selasky 17866d53750SHans Petter Selasky if (MLX5_CAP_GEN(dev, debug) == 0) 17966d53750SHans Petter Selasky return 0; 18066d53750SHans Petter Selasky 18166d53750SHans Petter Selasky numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters); 18266d53750SHans Petter Selasky if (numcounters == 0) 18366d53750SHans Petter Selasky return 0; 18466d53750SHans Petter Selasky 18566d53750SHans Petter Selasky outlen = MLX5_ST_SZ_BYTES(query_diagnostic_counters_out) + 18666d53750SHans Petter Selasky MLX5_ST_SZ_BYTES(diagnostic_counter) * numcounters; 18766d53750SHans Petter Selasky 18866d53750SHans Petter Selasky out = mlx5_vzalloc(outlen); 18966d53750SHans Petter Selasky if (out == NULL) 19066d53750SHans Petter Selasky return -ENOMEM; 19166d53750SHans Petter Selasky 19266d53750SHans Petter Selasky err = mlx5_query_diagnostic_counters(dev, 1, 0, out, outlen); 19366d53750SHans Petter Selasky if (err == 0) { 19466d53750SHans Petter Selasky for (x = 0; x != numcounters; x++) { 19566d53750SHans Petter Selasky u16 counter_id = MLX5_GET( 19666d53750SHans Petter Selasky query_diagnostic_counters_out, 19766d53750SHans Petter Selasky out, diag_counter[x].counter_id); 19866d53750SHans Petter Selasky u64 counter_value = MLX5_GET64( 19966d53750SHans Petter Selasky query_diagnostic_counters_out, 20066d53750SHans Petter Selasky out, diag_counter[x].counter_value_h); 20166d53750SHans Petter Selasky 20266d53750SHans Petter Selasky if (pdiag != NULL) { 20366d53750SHans Petter Selasky mlx5_core_put_diag_counter( 20466d53750SHans Petter Selasky mlx5_core_pci_diagnostics_table, 20566d53750SHans Petter Selasky pdiag->array, 20666d53750SHans Petter Selasky MLX5_CORE_PCI_DIAGNOSTICS_NUM, 20766d53750SHans Petter Selasky counter_id, counter_value); 20866d53750SHans Petter Selasky } 20966d53750SHans Petter Selasky if (pgen != NULL) { 21066d53750SHans Petter Selasky mlx5_core_put_diag_counter( 21166d53750SHans Petter Selasky mlx5_core_general_diagnostics_table, 21266d53750SHans Petter Selasky pgen->array, 21366d53750SHans Petter Selasky MLX5_CORE_GENERAL_DIAGNOSTICS_NUM, 21466d53750SHans Petter Selasky counter_id, counter_value); 21566d53750SHans Petter Selasky } 21666d53750SHans Petter Selasky } 21766d53750SHans Petter Selasky } 21866d53750SHans Petter Selasky kvfree(out); 21966d53750SHans Petter Selasky 22066d53750SHans Petter Selasky if (pdiag != NULL) { 22166d53750SHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(mpcnt_reg); 22266d53750SHans Petter Selasky outlen = MLX5_ST_SZ_BYTES(mpcnt_reg); 22366d53750SHans Petter Selasky 22466d53750SHans Petter Selasky in = mlx5_vzalloc(inlen); 22566d53750SHans Petter Selasky if (in == NULL) 22666d53750SHans Petter Selasky return -ENOMEM; 22766d53750SHans Petter Selasky 22866d53750SHans Petter Selasky out = mlx5_vzalloc(outlen); 22966d53750SHans Petter Selasky if (out == NULL) { 23066d53750SHans Petter Selasky kvfree(in); 23166d53750SHans Petter Selasky return -ENOMEM; 23266d53750SHans Petter Selasky } 23366d53750SHans Petter Selasky MLX5_SET(mpcnt_reg, in, grp, 23466d53750SHans Petter Selasky MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP); 23566d53750SHans Petter Selasky 23666d53750SHans Petter Selasky err = mlx5_core_access_reg(dev, in, inlen, out, outlen, 23766d53750SHans Petter Selasky MLX5_REG_MPCNT, 0, 0); 23866d53750SHans Petter Selasky if (err == 0) { 23966d53750SHans Petter Selasky void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out, 240c71a71baSHans Petter Selasky counter_set.pcie_perf_counters); 24166d53750SHans Petter Selasky 24266d53750SHans Petter Selasky pdiag->counter.rx_pci_errors = 243c71a71baSHans Petter Selasky MLX5_GET(pcie_perf_counters, 24466d53750SHans Petter Selasky pcounters, rx_errors); 24566d53750SHans Petter Selasky pdiag->counter.tx_pci_errors = 246c71a71baSHans Petter Selasky MLX5_GET(pcie_perf_counters, 24766d53750SHans Petter Selasky pcounters, tx_errors); 24866d53750SHans Petter Selasky } 24966d53750SHans Petter Selasky MLX5_SET(mpcnt_reg, in, grp, 25066d53750SHans Petter Selasky MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP); 25166d53750SHans Petter Selasky 25266d53750SHans Petter Selasky err = mlx5_core_access_reg(dev, in, inlen, out, outlen, 25366d53750SHans Petter Selasky MLX5_REG_MPCNT, 0, 0); 25466d53750SHans Petter Selasky if (err == 0) { 25566d53750SHans Petter Selasky void *pcounters = MLX5_ADDR_OF(mpcnt_reg, out, 256c71a71baSHans Petter Selasky counter_set.pcie_timers_states); 25766d53750SHans Petter Selasky 25866d53750SHans Petter Selasky pdiag->counter.tx_pci_non_fatal_errors = 259c71a71baSHans Petter Selasky MLX5_GET(pcie_timers_states, 26066d53750SHans Petter Selasky pcounters, non_fatal_err_msg_sent); 26166d53750SHans Petter Selasky pdiag->counter.tx_pci_fatal_errors = 262c71a71baSHans Petter Selasky MLX5_GET(pcie_timers_states, 26366d53750SHans Petter Selasky pcounters, fatal_err_msg_sent); 26466d53750SHans Petter Selasky } 26566d53750SHans Petter Selasky kvfree(in); 26666d53750SHans Petter Selasky kvfree(out); 26766d53750SHans Petter Selasky } 26866d53750SHans Petter Selasky return 0; 26966d53750SHans Petter Selasky } 27066d53750SHans Petter Selasky 27166d53750SHans Petter Selasky int mlx5_core_supports_diagnostics(struct mlx5_core_dev *dev, u16 counter_id) 27266d53750SHans Petter Selasky { 27366d53750SHans Petter Selasky int numcounters; 27466d53750SHans Petter Selasky int x; 27566d53750SHans Petter Selasky 27666d53750SHans Petter Selasky if (MLX5_CAP_GEN(dev, debug) == 0) 27766d53750SHans Petter Selasky return 0; 27866d53750SHans Petter Selasky 27966d53750SHans Petter Selasky /* check for any counter */ 28066d53750SHans Petter Selasky if (counter_id == 0) 28166d53750SHans Petter Selasky return 1; 28266d53750SHans Petter Selasky 28366d53750SHans Petter Selasky numcounters = MLX5_CAP_GEN(dev, num_of_diagnostic_counters); 28466d53750SHans Petter Selasky 28566d53750SHans Petter Selasky /* check if counter ID exists in debug capability */ 28666d53750SHans Petter Selasky for (x = 0; x != numcounters; x++) { 28766d53750SHans Petter Selasky if (MLX5_CAP_DEBUG(dev, diagnostic_counter[x].counter_id) == 28866d53750SHans Petter Selasky counter_id) 28966d53750SHans Petter Selasky return 1; 29066d53750SHans Petter Selasky } 29166d53750SHans Petter Selasky return 0; /* not supported counter */ 29266d53750SHans Petter Selasky } 293048ddb58SHans Petter Selasky 294048ddb58SHans Petter Selasky /* 295048ddb58SHans Petter Selasky * Read the first three bytes of the eeprom in order to get the needed info 296048ddb58SHans Petter Selasky * for the whole reading. 297048ddb58SHans Petter Selasky * Byte 0 - Identifier byte 298048ddb58SHans Petter Selasky * Byte 1 - Revision byte 299048ddb58SHans Petter Selasky * Byte 2 - Status byte 300048ddb58SHans Petter Selasky */ 301048ddb58SHans Petter Selasky int 302048ddb58SHans Petter Selasky mlx5_get_eeprom_info(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom) 303048ddb58SHans Petter Selasky { 304048ddb58SHans Petter Selasky u32 data = 0; 305048ddb58SHans Petter Selasky int size_read = 0; 306048ddb58SHans Petter Selasky int ret; 307048ddb58SHans Petter Selasky 308048ddb58SHans Petter Selasky ret = mlx5_query_module_num(dev, &eeprom->module_num); 309048ddb58SHans Petter Selasky if (ret) { 310048ddb58SHans Petter Selasky mlx5_core_err(dev, "Failed query module error=%d\n", ret); 311048ddb58SHans Petter Selasky return (-ret); 312048ddb58SHans Petter Selasky } 313048ddb58SHans Petter Selasky 314048ddb58SHans Petter Selasky /* Read the first three bytes to get Identifier, Revision and Status */ 315048ddb58SHans Petter Selasky ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num, 316048ddb58SHans Petter Selasky eeprom->device_addr, MLX5_EEPROM_INFO_BYTES, eeprom->module_num, &data, 317048ddb58SHans Petter Selasky &size_read); 318048ddb58SHans Petter Selasky if (ret) { 319048ddb58SHans Petter Selasky mlx5_core_err(dev, 320048ddb58SHans Petter Selasky "Failed query EEPROM module error=0x%x\n", ret); 321048ddb58SHans Petter Selasky return (-ret); 322048ddb58SHans Petter Selasky } 323048ddb58SHans Petter Selasky 324048ddb58SHans Petter Selasky switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) { 325048ddb58SHans Petter Selasky case SFF_8024_ID_QSFP: 326048ddb58SHans Petter Selasky eeprom->type = MLX5_ETH_MODULE_SFF_8436; 327048ddb58SHans Petter Selasky eeprom->len = MLX5_ETH_MODULE_SFF_8436_LEN; 328048ddb58SHans Petter Selasky break; 329048ddb58SHans Petter Selasky case SFF_8024_ID_QSFPPLUS: 330048ddb58SHans Petter Selasky case SFF_8024_ID_QSFP28: 331048ddb58SHans Petter Selasky if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 || 332048ddb58SHans Petter Selasky ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) { 333048ddb58SHans Petter Selasky eeprom->type = MLX5_ETH_MODULE_SFF_8636; 334048ddb58SHans Petter Selasky eeprom->len = MLX5_ETH_MODULE_SFF_8636_LEN; 335048ddb58SHans Petter Selasky } else { 336048ddb58SHans Petter Selasky eeprom->type = MLX5_ETH_MODULE_SFF_8436; 337048ddb58SHans Petter Selasky eeprom->len = MLX5_ETH_MODULE_SFF_8436_LEN; 338048ddb58SHans Petter Selasky } 339048ddb58SHans Petter Selasky if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0) 340048ddb58SHans Petter Selasky eeprom->page_valid = 1; 341048ddb58SHans Petter Selasky break; 342048ddb58SHans Petter Selasky case SFF_8024_ID_SFP: 343048ddb58SHans Petter Selasky eeprom->type = MLX5_ETH_MODULE_SFF_8472; 344048ddb58SHans Petter Selasky eeprom->len = MLX5_ETH_MODULE_SFF_8472_LEN; 345048ddb58SHans Petter Selasky break; 346048ddb58SHans Petter Selasky default: 347048ddb58SHans Petter Selasky mlx5_core_err(dev, "Not recognized cable type = 0x%x(%s)\n", 348048ddb58SHans Petter Selasky data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK, 349048ddb58SHans Petter Selasky sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]); 350048ddb58SHans Petter Selasky return (EINVAL); 351048ddb58SHans Petter Selasky } 352048ddb58SHans Petter Selasky return (0); 353048ddb58SHans Petter Selasky } 354048ddb58SHans Petter Selasky 355048ddb58SHans Petter Selasky /* Read both low and high pages of the eeprom */ 356048ddb58SHans Petter Selasky int 357048ddb58SHans Petter Selasky mlx5_get_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *ee) 358048ddb58SHans Petter Selasky { 359048ddb58SHans Petter Selasky int size_read = 0; 360048ddb58SHans Petter Selasky int ret; 361048ddb58SHans Petter Selasky 362048ddb58SHans Petter Selasky if (ee->len == 0) 363048ddb58SHans Petter Selasky return (EINVAL); 364048ddb58SHans Petter Selasky 365048ddb58SHans Petter Selasky /* Read low page of the eeprom */ 366048ddb58SHans Petter Selasky while (ee->device_addr < ee->len) { 367048ddb58SHans Petter Selasky ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr, 368048ddb58SHans Petter Selasky ee->len - ee->device_addr, ee->module_num, 369048ddb58SHans Petter Selasky ee->data + (ee->device_addr / 4), &size_read); 370048ddb58SHans Petter Selasky if (ret) { 371048ddb58SHans Petter Selasky mlx5_core_err(dev, 372048ddb58SHans Petter Selasky "Failed reading EEPROM, error = 0x%02x\n", ret); 373048ddb58SHans Petter Selasky return (-ret); 374048ddb58SHans Petter Selasky } 375048ddb58SHans Petter Selasky ee->device_addr += size_read; 376048ddb58SHans Petter Selasky } 377048ddb58SHans Petter Selasky 378048ddb58SHans Petter Selasky /* Read high page of the eeprom */ 379048ddb58SHans Petter Selasky if (ee->page_valid == 1) { 380048ddb58SHans Petter Selasky ee->device_addr = MLX5_EEPROM_HIGH_PAGE_OFFSET; 381048ddb58SHans Petter Selasky ee->page_num = MLX5_EEPROM_HIGH_PAGE; 382048ddb58SHans Petter Selasky size_read = 0; 383048ddb58SHans Petter Selasky while (ee->device_addr < MLX5_EEPROM_PAGE_LENGTH) { 384048ddb58SHans Petter Selasky ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, 385048ddb58SHans Petter Selasky ee->device_addr, MLX5_EEPROM_PAGE_LENGTH - ee->device_addr, 386048ddb58SHans Petter Selasky ee->module_num, ee->data + (ee->len / 4) + 387048ddb58SHans Petter Selasky ((ee->device_addr - MLX5_EEPROM_HIGH_PAGE_OFFSET) / 4), 388048ddb58SHans Petter Selasky &size_read); 389048ddb58SHans Petter Selasky if (ret) { 390048ddb58SHans Petter Selasky mlx5_core_err(dev, 391048ddb58SHans Petter Selasky "Failed reading EEPROM, error = 0x%02x\n", 392048ddb58SHans Petter Selasky ret); 393048ddb58SHans Petter Selasky return (-ret); 394048ddb58SHans Petter Selasky } 395048ddb58SHans Petter Selasky ee->device_addr += size_read; 396048ddb58SHans Petter Selasky } 397048ddb58SHans Petter Selasky } 398048ddb58SHans Petter Selasky return (0); 399048ddb58SHans Petter Selasky } 400048ddb58SHans Petter Selasky 401048ddb58SHans Petter Selasky /* 402048ddb58SHans Petter Selasky * Read cable EEPROM module information by first inspecting the first 403048ddb58SHans Petter Selasky * three bytes to get the initial information for a whole reading. 404048ddb58SHans Petter Selasky * Information will be printed to dmesg. 405048ddb58SHans Petter Selasky */ 406048ddb58SHans Petter Selasky int 407048ddb58SHans Petter Selasky mlx5_read_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom) 408048ddb58SHans Petter Selasky { 409048ddb58SHans Petter Selasky int error; 410048ddb58SHans Petter Selasky 411048ddb58SHans Petter Selasky eeprom->i2c_addr = MLX5_I2C_ADDR_LOW; 412048ddb58SHans Petter Selasky eeprom->device_addr = 0; 413048ddb58SHans Petter Selasky eeprom->page_num = MLX5_EEPROM_LOW_PAGE; 414048ddb58SHans Petter Selasky eeprom->page_valid = 0; 415048ddb58SHans Petter Selasky 416048ddb58SHans Petter Selasky /* Read three first bytes to get important info */ 417048ddb58SHans Petter Selasky error = mlx5_get_eeprom_info(dev, eeprom); 418048ddb58SHans Petter Selasky if (error) { 419048ddb58SHans Petter Selasky mlx5_core_err(dev, 420048ddb58SHans Petter Selasky "Failed reading EEPROM initial information\n"); 421048ddb58SHans Petter Selasky return (error); 422048ddb58SHans Petter Selasky } 423048ddb58SHans Petter Selasky /* 424048ddb58SHans Petter Selasky * Allocate needed length buffer and additional space for 425048ddb58SHans Petter Selasky * page 0x03 426048ddb58SHans Petter Selasky */ 427048ddb58SHans Petter Selasky eeprom->data = malloc(eeprom->len + MLX5_EEPROM_PAGE_LENGTH, 428048ddb58SHans Petter Selasky M_MLX5_EEPROM, M_WAITOK | M_ZERO); 429048ddb58SHans Petter Selasky 430048ddb58SHans Petter Selasky /* Read the whole eeprom information */ 431048ddb58SHans Petter Selasky error = mlx5_get_eeprom(dev, eeprom); 432048ddb58SHans Petter Selasky if (error) { 433048ddb58SHans Petter Selasky mlx5_core_err(dev, "Failed reading EEPROM\n"); 434048ddb58SHans Petter Selasky error = 0; 435048ddb58SHans Petter Selasky /* 436048ddb58SHans Petter Selasky * Continue printing partial information in case of 437048ddb58SHans Petter Selasky * an error 438048ddb58SHans Petter Selasky */ 439048ddb58SHans Petter Selasky } 440048ddb58SHans Petter Selasky free(eeprom->data, M_MLX5_EEPROM); 441048ddb58SHans Petter Selasky 442048ddb58SHans Petter Selasky return (error); 443048ddb58SHans Petter Selasky } 444048ddb58SHans Petter Selasky 445048ddb58SHans Petter Selasky 446