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