1dc7e38acSHans Petter Selasky /*- 2dc7e38acSHans Petter Selasky * Copyright (c) 2015 Mellanox Technologies. All rights reserved. 3dc7e38acSHans Petter Selasky * 4dc7e38acSHans Petter Selasky * Redistribution and use in source and binary forms, with or without 5dc7e38acSHans Petter Selasky * modification, are permitted provided that the following conditions 6dc7e38acSHans Petter Selasky * are met: 7dc7e38acSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 8dc7e38acSHans Petter Selasky * notice, this list of conditions and the following disclaimer. 9dc7e38acSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 10dc7e38acSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 11dc7e38acSHans Petter Selasky * documentation and/or other materials provided with the distribution. 12dc7e38acSHans Petter Selasky * 13dc7e38acSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14dc7e38acSHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15dc7e38acSHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16dc7e38acSHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17dc7e38acSHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18dc7e38acSHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19dc7e38acSHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20dc7e38acSHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21dc7e38acSHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22dc7e38acSHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23dc7e38acSHans Petter Selasky * SUCH DAMAGE. 24dc7e38acSHans Petter Selasky * 25dc7e38acSHans Petter Selasky * $FreeBSD$ 26dc7e38acSHans Petter Selasky */ 27dc7e38acSHans Petter Selasky 28dc7e38acSHans Petter Selasky #include "en.h" 29dc7e38acSHans Petter Selasky #include <net/sff8472.h> 30dc7e38acSHans Petter Selasky 31dc7e38acSHans Petter Selasky void 32dc7e38acSHans Petter Selasky mlx5e_create_stats(struct sysctl_ctx_list *ctx, 33dc7e38acSHans Petter Selasky struct sysctl_oid_list *parent, const char *buffer, 34dc7e38acSHans Petter Selasky const char **desc, unsigned num, u64 * arg) 35dc7e38acSHans Petter Selasky { 36dc7e38acSHans Petter Selasky struct sysctl_oid *node; 37dc7e38acSHans Petter Selasky unsigned x; 38dc7e38acSHans Petter Selasky 39dc7e38acSHans Petter Selasky sysctl_ctx_init(ctx); 40dc7e38acSHans Petter Selasky 41dc7e38acSHans Petter Selasky node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, 42dc7e38acSHans Petter Selasky buffer, CTLFLAG_RD, NULL, "Statistics"); 43dc7e38acSHans Petter Selasky if (node == NULL) 44dc7e38acSHans Petter Selasky return; 45dc7e38acSHans Petter Selasky for (x = 0; x != num; x++) { 46dc7e38acSHans Petter Selasky SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 47dc7e38acSHans Petter Selasky desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]); 48dc7e38acSHans Petter Selasky } 49dc7e38acSHans Petter Selasky } 50dc7e38acSHans Petter Selasky 51dc7e38acSHans Petter Selasky static int 52dc7e38acSHans Petter Selasky mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS) 53dc7e38acSHans Petter Selasky { 54dc7e38acSHans Petter Selasky struct mlx5e_priv *priv = arg1; 55dc7e38acSHans Petter Selasky uint64_t value; 56dc7e38acSHans Petter Selasky int was_opened; 57dc7e38acSHans Petter Selasky int error; 58dc7e38acSHans Petter Selasky 59dc7e38acSHans Petter Selasky PRIV_LOCK(priv); 60dc7e38acSHans Petter Selasky value = priv->params_ethtool.arg[arg2]; 61ec0143b2SHans Petter Selasky if (req != NULL) { 62dc7e38acSHans Petter Selasky error = sysctl_handle_64(oidp, &value, 0, req); 63dc7e38acSHans Petter Selasky if (error || req->newptr == NULL || 64dc7e38acSHans Petter Selasky value == priv->params_ethtool.arg[arg2]) 65dc7e38acSHans Petter Selasky goto done; 66dc7e38acSHans Petter Selasky 67dc7e38acSHans Petter Selasky /* assign new value */ 68dc7e38acSHans Petter Selasky priv->params_ethtool.arg[arg2] = value; 69ec0143b2SHans Petter Selasky } else { 70ec0143b2SHans Petter Selasky error = 0; 71ec0143b2SHans Petter Selasky } 72dc7e38acSHans Petter Selasky /* check if device is gone */ 73dc7e38acSHans Petter Selasky if (priv->gone) { 74dc7e38acSHans Petter Selasky error = ENXIO; 75dc7e38acSHans Petter Selasky goto done; 76dc7e38acSHans Petter Selasky } 77f03f517bSHans Petter Selasky /* import RX coal time */ 78f03f517bSHans Petter Selasky if (priv->params_ethtool.rx_coalesce_usecs < 1) 79f03f517bSHans Petter Selasky priv->params_ethtool.rx_coalesce_usecs = 0; 80f03f517bSHans Petter Selasky else if (priv->params_ethtool.rx_coalesce_usecs > 81f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_period)) { 82f03f517bSHans Petter Selasky priv->params_ethtool.rx_coalesce_usecs = 83f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_period); 84f03f517bSHans Petter Selasky } 85f03f517bSHans Petter Selasky priv->params.rx_cq_moderation_usec = priv->params_ethtool.rx_coalesce_usecs; 86f03f517bSHans Petter Selasky 87f03f517bSHans Petter Selasky /* import RX coal pkts */ 88f03f517bSHans Petter Selasky if (priv->params_ethtool.rx_coalesce_pkts < 1) 89f03f517bSHans Petter Selasky priv->params_ethtool.rx_coalesce_pkts = 0; 90f03f517bSHans Petter Selasky else if (priv->params_ethtool.rx_coalesce_pkts > 91f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_max_count)) { 92f03f517bSHans Petter Selasky priv->params_ethtool.rx_coalesce_pkts = 93f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_max_count); 94f03f517bSHans Petter Selasky } 95f03f517bSHans Petter Selasky priv->params.rx_cq_moderation_pkts = priv->params_ethtool.rx_coalesce_pkts; 96f03f517bSHans Petter Selasky 97f03f517bSHans Petter Selasky /* import TX coal time */ 98f03f517bSHans Petter Selasky if (priv->params_ethtool.tx_coalesce_usecs < 1) 99f03f517bSHans Petter Selasky priv->params_ethtool.tx_coalesce_usecs = 0; 100f03f517bSHans Petter Selasky else if (priv->params_ethtool.tx_coalesce_usecs > 101f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_period)) { 102f03f517bSHans Petter Selasky priv->params_ethtool.tx_coalesce_usecs = 103f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_period); 104f03f517bSHans Petter Selasky } 105f03f517bSHans Petter Selasky priv->params.tx_cq_moderation_usec = priv->params_ethtool.tx_coalesce_usecs; 106f03f517bSHans Petter Selasky 107f03f517bSHans Petter Selasky /* import TX coal pkts */ 108f03f517bSHans Petter Selasky if (priv->params_ethtool.tx_coalesce_pkts < 1) 109f03f517bSHans Petter Selasky priv->params_ethtool.tx_coalesce_pkts = 0; 110f03f517bSHans Petter Selasky else if (priv->params_ethtool.tx_coalesce_pkts > 111f03f517bSHans Petter Selasky MLX5E_FLD_MAX(cqc, cq_max_count)) { 112f03f517bSHans Petter Selasky priv->params_ethtool.tx_coalesce_pkts = MLX5E_FLD_MAX(cqc, cq_max_count); 113f03f517bSHans Petter Selasky } 114f03f517bSHans Petter Selasky priv->params.tx_cq_moderation_pkts = priv->params_ethtool.tx_coalesce_pkts; 115dc7e38acSHans Petter Selasky 116dc7e38acSHans Petter Selasky if (&priv->params_ethtool.arg[arg2] == &priv->params_ethtool.rx_pauseframe_control || 117dc7e38acSHans Petter Selasky &priv->params_ethtool.arg[arg2] == &priv->params_ethtool.tx_pauseframe_control) { 118dc7e38acSHans Petter Selasky /* range check parameters */ 119dc7e38acSHans Petter Selasky priv->params_ethtool.rx_pauseframe_control = 120dc7e38acSHans Petter Selasky priv->params_ethtool.rx_pauseframe_control ? 1 : 0; 121dc7e38acSHans Petter Selasky priv->params_ethtool.tx_pauseframe_control = 122dc7e38acSHans Petter Selasky priv->params_ethtool.tx_pauseframe_control ? 1 : 0; 123dc7e38acSHans Petter Selasky 124dc7e38acSHans Petter Selasky /* update firmware */ 125dc7e38acSHans Petter Selasky error = -mlx5_set_port_pause(priv->mdev, 1, 126dc7e38acSHans Petter Selasky priv->params_ethtool.rx_pauseframe_control, 127dc7e38acSHans Petter Selasky priv->params_ethtool.tx_pauseframe_control); 128dc7e38acSHans Petter Selasky goto done; 129dc7e38acSHans Petter Selasky } 130dc7e38acSHans Petter Selasky 131dc7e38acSHans Petter Selasky was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); 132f03f517bSHans Petter Selasky if (was_opened) { 133f03f517bSHans Petter Selasky u64 *xarg = priv->params_ethtool.arg + arg2; 134dc7e38acSHans Petter Selasky 135f03f517bSHans Petter Selasky if (xarg == &priv->params_ethtool.tx_coalesce_pkts || 136f03f517bSHans Petter Selasky xarg == &priv->params_ethtool.rx_coalesce_pkts || 137f03f517bSHans Petter Selasky xarg == &priv->params_ethtool.tx_coalesce_usecs || 138f03f517bSHans Petter Selasky xarg == &priv->params_ethtool.rx_coalesce_usecs) { 139f03f517bSHans Petter Selasky /* avoid downing and upping the network interface */ 140f03f517bSHans Petter Selasky error = mlx5e_refresh_channel_params(priv); 141f03f517bSHans Petter Selasky goto done; 142f03f517bSHans Petter Selasky } 143f03f517bSHans Petter Selasky mlx5e_close_locked(priv->ifp); 144f03f517bSHans Petter Selasky } 145dc7e38acSHans Petter Selasky /* import TX queue size */ 146dc7e38acSHans Petter Selasky if (priv->params_ethtool.tx_queue_size < 147dc7e38acSHans Petter Selasky (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { 148dc7e38acSHans Petter Selasky priv->params_ethtool.tx_queue_size = 149dc7e38acSHans Petter Selasky (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); 150dc7e38acSHans Petter Selasky } else if (priv->params_ethtool.tx_queue_size > 151dc7e38acSHans Petter Selasky priv->params_ethtool.tx_queue_size_max) { 152dc7e38acSHans Petter Selasky priv->params_ethtool.tx_queue_size = 153dc7e38acSHans Petter Selasky priv->params_ethtool.tx_queue_size_max; 154dc7e38acSHans Petter Selasky } 155dc7e38acSHans Petter Selasky priv->params.log_sq_size = 156dc7e38acSHans Petter Selasky order_base_2(priv->params_ethtool.tx_queue_size); 157dc7e38acSHans Petter Selasky 158dc7e38acSHans Petter Selasky /* import RX queue size */ 159dc7e38acSHans Petter Selasky if (priv->params_ethtool.rx_queue_size < 160dc7e38acSHans Petter Selasky (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { 161dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size = 162dc7e38acSHans Petter Selasky (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); 163dc7e38acSHans Petter Selasky } else if (priv->params_ethtool.rx_queue_size > 164dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size_max) { 165dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size = 166dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size_max; 167dc7e38acSHans Petter Selasky } 168dc7e38acSHans Petter Selasky priv->params.log_rq_size = 169dc7e38acSHans Petter Selasky order_base_2(priv->params_ethtool.rx_queue_size); 170dc7e38acSHans Petter Selasky 171dc7e38acSHans Petter Selasky priv->params.min_rx_wqes = min_t (u16, 172dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size - 1, 173dc7e38acSHans Petter Selasky MLX5E_PARAMS_DEFAULT_MIN_RX_WQES); 174dc7e38acSHans Petter Selasky 175dc7e38acSHans Petter Selasky /* import number of channels */ 176dc7e38acSHans Petter Selasky if (priv->params_ethtool.channels < 1) 177dc7e38acSHans Petter Selasky priv->params_ethtool.channels = 1; 178dc7e38acSHans Petter Selasky else if (priv->params_ethtool.channels > 179dc7e38acSHans Petter Selasky (u64) priv->mdev->priv.eq_table.num_comp_vectors) { 180dc7e38acSHans Petter Selasky priv->params_ethtool.channels = 181dc7e38acSHans Petter Selasky (u64) priv->mdev->priv.eq_table.num_comp_vectors; 182dc7e38acSHans Petter Selasky } 183dc7e38acSHans Petter Selasky priv->params.num_channels = priv->params_ethtool.channels; 184dc7e38acSHans Petter Selasky 185dc7e38acSHans Petter Selasky /* import RX mode */ 186dc7e38acSHans Petter Selasky if (priv->params_ethtool.rx_coalesce_mode != 0) 187dc7e38acSHans Petter Selasky priv->params_ethtool.rx_coalesce_mode = 1; 188dc7e38acSHans Petter Selasky priv->params.rx_cq_moderation_mode = priv->params_ethtool.rx_coalesce_mode; 189dc7e38acSHans Petter Selasky 19074540a31SHans Petter Selasky /* import TX mode */ 19174540a31SHans Petter Selasky if (priv->params_ethtool.tx_coalesce_mode != 0) 19274540a31SHans Petter Selasky priv->params_ethtool.tx_coalesce_mode = 1; 19374540a31SHans Petter Selasky priv->params.tx_cq_moderation_mode = priv->params_ethtool.tx_coalesce_mode; 19474540a31SHans Petter Selasky 195dc7e38acSHans Petter Selasky /* we always agree to turn off HW LRO - but not always to turn on */ 196dc7e38acSHans Petter Selasky if (priv->params_ethtool.hw_lro) { 197dc7e38acSHans Petter Selasky if (priv->params_ethtool.hw_lro != 1) { 198dc7e38acSHans Petter Selasky priv->params_ethtool.hw_lro = priv->params.hw_lro_en; 199dc7e38acSHans Petter Selasky error = EINVAL; 200dc7e38acSHans Petter Selasky goto done; 201dc7e38acSHans Petter Selasky } 202dc7e38acSHans Petter Selasky if (priv->ifp->if_capenable & IFCAP_LRO) 203dc7e38acSHans Petter Selasky priv->params.hw_lro_en = !!MLX5_CAP_ETH(priv->mdev, lro_cap); 20436c1007dSHans Petter Selasky else { 20536c1007dSHans Petter Selasky /* set the correct (0) value to params_ethtool.hw_lro, issue a warning and return error */ 20636c1007dSHans Petter Selasky priv->params_ethtool.hw_lro = 0; 20736c1007dSHans Petter Selasky error = EINVAL; 20836c1007dSHans Petter Selasky if_printf(priv->ifp, "Can't set HW_LRO to a device with LRO turned off"); 20936c1007dSHans Petter Selasky goto done; 21036c1007dSHans Petter Selasky } 211bb3853c6SHans Petter Selasky } else { 212dc7e38acSHans Petter Selasky priv->params.hw_lro_en = false; 213dc7e38acSHans Petter Selasky } 214dc7e38acSHans Petter Selasky 21590cc1c77SHans Petter Selasky if (&priv->params_ethtool.arg[arg2] == 21690cc1c77SHans Petter Selasky &priv->params_ethtool.cqe_zipping) { 21790cc1c77SHans Petter Selasky if (priv->params_ethtool.cqe_zipping && 21890cc1c77SHans Petter Selasky MLX5_CAP_GEN(priv->mdev, cqe_compression)) { 21990cc1c77SHans Petter Selasky priv->params.cqe_zipping_en = true; 22090cc1c77SHans Petter Selasky priv->params_ethtool.cqe_zipping = 1; 22190cc1c77SHans Petter Selasky } else { 22290cc1c77SHans Petter Selasky priv->params.cqe_zipping_en = false; 22390cc1c77SHans Petter Selasky priv->params_ethtool.cqe_zipping = 0; 22490cc1c77SHans Petter Selasky } 22590cc1c77SHans Petter Selasky } 22690cc1c77SHans Petter Selasky 227dc7e38acSHans Petter Selasky if (was_opened) 228dc7e38acSHans Petter Selasky mlx5e_open_locked(priv->ifp); 229dc7e38acSHans Petter Selasky done: 230dc7e38acSHans Petter Selasky PRIV_UNLOCK(priv); 231dc7e38acSHans Petter Selasky return (error); 232dc7e38acSHans Petter Selasky } 233dc7e38acSHans Petter Selasky 234dc7e38acSHans Petter Selasky /* 235dc7e38acSHans Petter Selasky * Read the first three bytes of the eeprom in order to get the needed info 236dc7e38acSHans Petter Selasky * for the whole reading. 237dc7e38acSHans Petter Selasky * Byte 0 - Identifier byte 238dc7e38acSHans Petter Selasky * Byte 1 - Revision byte 239dc7e38acSHans Petter Selasky * Byte 2 - Status byte 240dc7e38acSHans Petter Selasky */ 241dc7e38acSHans Petter Selasky static int 242dc7e38acSHans Petter Selasky mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom) 243dc7e38acSHans Petter Selasky { 244dc7e38acSHans Petter Selasky struct mlx5_core_dev *dev = priv->mdev; 245dc7e38acSHans Petter Selasky u32 data = 0; 246dc7e38acSHans Petter Selasky int size_read = 0; 247dc7e38acSHans Petter Selasky int ret; 248dc7e38acSHans Petter Selasky 249dc7e38acSHans Petter Selasky ret = mlx5_query_module_num(dev, &eeprom->module_num); 250dc7e38acSHans Petter Selasky if (ret) { 251dc7e38acSHans Petter Selasky if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n", 252dc7e38acSHans Petter Selasky __func__, __LINE__, ret); 253dc7e38acSHans Petter Selasky return (ret); 254dc7e38acSHans Petter Selasky } 255dc7e38acSHans Petter Selasky 256dc7e38acSHans Petter Selasky /* Read the first three bytes to get Identifier, Revision and Status */ 257dc7e38acSHans Petter Selasky ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num, 258dc7e38acSHans Petter Selasky eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data, 259dc7e38acSHans Petter Selasky &size_read); 260dc7e38acSHans Petter Selasky if (ret) { 261dc7e38acSHans Petter Selasky if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n", 262dc7e38acSHans Petter Selasky __func__, __LINE__, ret); 263dc7e38acSHans Petter Selasky return (ret); 264dc7e38acSHans Petter Selasky } 265dc7e38acSHans Petter Selasky 266dc7e38acSHans Petter Selasky switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) { 267dc7e38acSHans Petter Selasky case SFF_8024_ID_QSFP: 268dc7e38acSHans Petter Selasky eeprom->type = MLX5E_ETH_MODULE_SFF_8436; 269dc7e38acSHans Petter Selasky eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN; 270dc7e38acSHans Petter Selasky break; 271dc7e38acSHans Petter Selasky case SFF_8024_ID_QSFPPLUS: 272dc7e38acSHans Petter Selasky case SFF_8024_ID_QSFP28: 273dc7e38acSHans Petter Selasky if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 || 274dc7e38acSHans Petter Selasky ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) { 275dc7e38acSHans Petter Selasky eeprom->type = MLX5E_ETH_MODULE_SFF_8636; 276dc7e38acSHans Petter Selasky eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN; 277dc7e38acSHans Petter Selasky } else { 278dc7e38acSHans Petter Selasky eeprom->type = MLX5E_ETH_MODULE_SFF_8436; 279dc7e38acSHans Petter Selasky eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN; 280dc7e38acSHans Petter Selasky } 281dc7e38acSHans Petter Selasky if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0) 282dc7e38acSHans Petter Selasky eeprom->page_valid = 1; 283dc7e38acSHans Petter Selasky break; 284dc7e38acSHans Petter Selasky case SFF_8024_ID_SFP: 285dc7e38acSHans Petter Selasky eeprom->type = MLX5E_ETH_MODULE_SFF_8472; 286dc7e38acSHans Petter Selasky eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN; 287dc7e38acSHans Petter Selasky break; 288dc7e38acSHans Petter Selasky default: 2897e1b8bc0SHans Petter Selasky if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n", 2907e1b8bc0SHans Petter Selasky __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK, 2917e1b8bc0SHans Petter Selasky sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]); 292dc7e38acSHans Petter Selasky return (EINVAL); 293dc7e38acSHans Petter Selasky } 294dc7e38acSHans Petter Selasky return (0); 295dc7e38acSHans Petter Selasky } 296dc7e38acSHans Petter Selasky 297dc7e38acSHans Petter Selasky /* Read both low and high pages of the eeprom */ 298dc7e38acSHans Petter Selasky static int 299dc7e38acSHans Petter Selasky mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee) 300dc7e38acSHans Petter Selasky { 301dc7e38acSHans Petter Selasky struct mlx5_core_dev *dev = priv->mdev; 302dc7e38acSHans Petter Selasky int size_read = 0; 303dc7e38acSHans Petter Selasky int ret; 304dc7e38acSHans Petter Selasky 305dc7e38acSHans Petter Selasky if (ee->len == 0) 306dc7e38acSHans Petter Selasky return (EINVAL); 307dc7e38acSHans Petter Selasky 308dc7e38acSHans Petter Selasky /* Read low page of the eeprom */ 309dc7e38acSHans Petter Selasky while (ee->device_addr < ee->len) { 310dc7e38acSHans Petter Selasky ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr, 311dc7e38acSHans Petter Selasky ee->len - ee->device_addr, ee->module_num, 312dc7e38acSHans Petter Selasky ee->data + (ee->device_addr / 4), &size_read); 313dc7e38acSHans Petter Selasky if (ret) { 314dc7e38acSHans Petter Selasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom, " 315dc7e38acSHans Petter Selasky "error = 0x%02x\n", __func__, __LINE__, ret); 316dc7e38acSHans Petter Selasky return (ret); 317dc7e38acSHans Petter Selasky } 318dc7e38acSHans Petter Selasky ee->device_addr += size_read; 319dc7e38acSHans Petter Selasky } 320dc7e38acSHans Petter Selasky 321dc7e38acSHans Petter Selasky /* Read high page of the eeprom */ 322dc7e38acSHans Petter Selasky if (ee->page_valid) { 323dc7e38acSHans Petter Selasky ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET; 324dc7e38acSHans Petter Selasky ee->page_num = MLX5E_EEPROM_HIGH_PAGE; 325dc7e38acSHans Petter Selasky size_read = 0; 326dc7e38acSHans Petter Selasky while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) { 327dc7e38acSHans Petter Selasky ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, 328dc7e38acSHans Petter Selasky ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr, 329dc7e38acSHans Petter Selasky ee->module_num, ee->data + (ee->len / 4) + 330dc7e38acSHans Petter Selasky ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4), 331dc7e38acSHans Petter Selasky &size_read); 332dc7e38acSHans Petter Selasky if (ret) { 333dc7e38acSHans Petter Selasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom, " 334dc7e38acSHans Petter Selasky "error = 0x%02x\n", __func__, __LINE__, ret); 335dc7e38acSHans Petter Selasky return (ret); 336dc7e38acSHans Petter Selasky } 337dc7e38acSHans Petter Selasky ee->device_addr += size_read; 338dc7e38acSHans Petter Selasky } 339dc7e38acSHans Petter Selasky } 340dc7e38acSHans Petter Selasky return (0); 341dc7e38acSHans Petter Selasky } 342dc7e38acSHans Petter Selasky 343dc7e38acSHans Petter Selasky static void 344dc7e38acSHans Petter Selasky mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom) 345dc7e38acSHans Petter Selasky { 346ee41fc8fSHans Petter Selasky int row; 347ee41fc8fSHans Petter Selasky int index_in_row; 348ee41fc8fSHans Petter Selasky int byte_to_write = 0; 349ee41fc8fSHans Petter Selasky int line_length = 16; 350dc7e38acSHans Petter Selasky 351dc7e38acSHans Petter Selasky printf("\nOffset\t\tValues\n"); 352ee41fc8fSHans Petter Selasky printf("------\t\t------"); 353ee41fc8fSHans Petter Selasky while (byte_to_write < eeprom->len) { 354ee41fc8fSHans Petter Selasky printf("\n0x%04X\t\t", byte_to_write); 355ee41fc8fSHans Petter Selasky for (index_in_row = 0; index_in_row < line_length; index_in_row++) { 356ee41fc8fSHans Petter Selasky printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]); 357ee41fc8fSHans Petter Selasky byte_to_write++; 358dc7e38acSHans Petter Selasky } 359dc7e38acSHans Petter Selasky } 360dc7e38acSHans Petter Selasky 361dc7e38acSHans Petter Selasky if (eeprom->page_valid) { 362dc7e38acSHans Petter Selasky row = MLX5E_EEPROM_HIGH_PAGE_OFFSET; 363ee41fc8fSHans Petter Selasky printf("\n\nUpper Page 0x03\n"); 364dc7e38acSHans Petter Selasky printf("\nOffset\t\tValues\n"); 365ee41fc8fSHans Petter Selasky printf("------\t\t------"); 366dc7e38acSHans Petter Selasky while (row < MLX5E_EEPROM_PAGE_LENGTH) { 367ee41fc8fSHans Petter Selasky printf("\n0x%04X\t\t", row); 368ee41fc8fSHans Petter Selasky for (index_in_row = 0; index_in_row < line_length; index_in_row++) { 369ee41fc8fSHans Petter Selasky printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]); 370ee41fc8fSHans Petter Selasky byte_to_write++; 371dc7e38acSHans Petter Selasky row++; 372dc7e38acSHans Petter Selasky } 373dc7e38acSHans Petter Selasky } 374dc7e38acSHans Petter Selasky } 375dc7e38acSHans Petter Selasky } 376dc7e38acSHans Petter Selasky 377dc7e38acSHans Petter Selasky /* 378dc7e38acSHans Petter Selasky * Read cable EEPROM module information by first inspecting the first 379dc7e38acSHans Petter Selasky * three bytes to get the initial information for a whole reading. 380dc7e38acSHans Petter Selasky * Information will be printed to dmesg. 381dc7e38acSHans Petter Selasky */ 382dc7e38acSHans Petter Selasky static int 383dc7e38acSHans Petter Selasky mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS) 384dc7e38acSHans Petter Selasky { 385dc7e38acSHans Petter Selasky struct mlx5e_priv *priv = arg1; 386dc7e38acSHans Petter Selasky struct mlx5e_eeprom eeprom; 387dc7e38acSHans Petter Selasky int error; 388dc7e38acSHans Petter Selasky int result = 0; 389dc7e38acSHans Petter Selasky 390dc7e38acSHans Petter Selasky PRIV_LOCK(priv); 391dc7e38acSHans Petter Selasky error = sysctl_handle_int(oidp, &result, 0, req); 392dc7e38acSHans Petter Selasky if (error || !req->newptr) 393dc7e38acSHans Petter Selasky goto done; 394dc7e38acSHans Petter Selasky 395dc7e38acSHans Petter Selasky /* Check if device is gone */ 396dc7e38acSHans Petter Selasky if (priv->gone) { 397dc7e38acSHans Petter Selasky error = ENXIO; 398dc7e38acSHans Petter Selasky goto done; 399dc7e38acSHans Petter Selasky } 400dc7e38acSHans Petter Selasky 401dc7e38acSHans Petter Selasky if (result == 1) { 402dc7e38acSHans Petter Selasky eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW; 403dc7e38acSHans Petter Selasky eeprom.device_addr = 0; 404dc7e38acSHans Petter Selasky eeprom.page_num = MLX5E_EEPROM_LOW_PAGE; 405dc7e38acSHans Petter Selasky eeprom.page_valid = 0; 406dc7e38acSHans Petter Selasky 407dc7e38acSHans Petter Selasky /* Read three first bytes to get important info */ 408dc7e38acSHans Petter Selasky error = mlx5e_get_eeprom_info(priv, &eeprom); 409dc7e38acSHans Petter Selasky if (error) { 410dc7e38acSHans Petter Selasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom's " 411dc7e38acSHans Petter Selasky "initial information\n", __func__, __LINE__); 412dc7e38acSHans Petter Selasky error = 0; 413dc7e38acSHans Petter Selasky goto done; 414dc7e38acSHans Petter Selasky } 415bb3853c6SHans Petter Selasky /* 416bb3853c6SHans Petter Selasky * Allocate needed length buffer and additional space for 417bb3853c6SHans Petter Selasky * page 0x03 418bb3853c6SHans Petter Selasky */ 419dc7e38acSHans Petter Selasky eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH, 420dc7e38acSHans Petter Selasky M_MLX5EN, M_WAITOK | M_ZERO); 421dc7e38acSHans Petter Selasky 422dc7e38acSHans Petter Selasky /* Read the whole eeprom information */ 423dc7e38acSHans Petter Selasky error = mlx5e_get_eeprom(priv, &eeprom); 424dc7e38acSHans Petter Selasky if (error) { 425dc7e38acSHans Petter Selasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n", 426dc7e38acSHans Petter Selasky __func__, __LINE__); 427dc7e38acSHans Petter Selasky error = 0; 428bb3853c6SHans Petter Selasky /* 429bb3853c6SHans Petter Selasky * Continue printing partial information in case of 430bb3853c6SHans Petter Selasky * an error 431bb3853c6SHans Petter Selasky */ 432dc7e38acSHans Petter Selasky } 433dc7e38acSHans Petter Selasky mlx5e_print_eeprom(&eeprom); 434dc7e38acSHans Petter Selasky free(eeprom.data, M_MLX5EN); 435dc7e38acSHans Petter Selasky } 436dc7e38acSHans Petter Selasky done: 437dc7e38acSHans Petter Selasky PRIV_UNLOCK(priv); 438dc7e38acSHans Petter Selasky return (error); 439dc7e38acSHans Petter Selasky } 440dc7e38acSHans Petter Selasky 441dc7e38acSHans Petter Selasky static const char *mlx5e_params_desc[] = { 442dc7e38acSHans Petter Selasky MLX5E_PARAMS(MLX5E_STATS_DESC) 443dc7e38acSHans Petter Selasky }; 444dc7e38acSHans Petter Selasky 445dc7e38acSHans Petter Selasky static const char *mlx5e_port_stats_debug_desc[] = { 446dc7e38acSHans Petter Selasky MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC) 447dc7e38acSHans Petter Selasky }; 448dc7e38acSHans Petter Selasky 449dc7e38acSHans Petter Selasky static int 450dc7e38acSHans Petter Selasky mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS) 451dc7e38acSHans Petter Selasky { 452dc7e38acSHans Petter Selasky struct mlx5e_priv *priv = arg1; 453dc7e38acSHans Petter Selasky int error; 454dc7e38acSHans Petter Selasky int sys_debug; 455dc7e38acSHans Petter Selasky 456dc7e38acSHans Petter Selasky sys_debug = priv->sysctl_debug; 457dc7e38acSHans Petter Selasky error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req); 458dc7e38acSHans Petter Selasky if (error || !req->newptr) 459dc7e38acSHans Petter Selasky return (error); 460dc7e38acSHans Petter Selasky priv->sysctl_debug = !!priv->sysctl_debug; 461dc7e38acSHans Petter Selasky if (sys_debug == priv->sysctl_debug) 462dc7e38acSHans Petter Selasky return (error); 463dc7e38acSHans Petter Selasky if (priv->sysctl_debug) 464dc7e38acSHans Petter Selasky mlx5e_create_stats(&priv->stats.port_stats_debug.ctx, 465dc7e38acSHans Petter Selasky SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats", 466dc7e38acSHans Petter Selasky mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM, 467dc7e38acSHans Petter Selasky priv->stats.port_stats_debug.arg); 468dc7e38acSHans Petter Selasky else 469dc7e38acSHans Petter Selasky sysctl_ctx_free(&priv->stats.port_stats_debug.ctx); 470dc7e38acSHans Petter Selasky return (error); 471dc7e38acSHans Petter Selasky } 472dc7e38acSHans Petter Selasky 473dc7e38acSHans Petter Selasky void 474dc7e38acSHans Petter Selasky mlx5e_create_ethtool(struct mlx5e_priv *priv) 475dc7e38acSHans Petter Selasky { 476dc7e38acSHans Petter Selasky struct sysctl_oid *node; 477dc7e38acSHans Petter Selasky const char *pnameunit; 478dc7e38acSHans Petter Selasky unsigned x; 479dc7e38acSHans Petter Selasky 480dc7e38acSHans Petter Selasky /* set some defaults */ 481dc7e38acSHans Petter Selasky priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; 482dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; 483dc7e38acSHans Petter Selasky priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size; 484dc7e38acSHans Petter Selasky priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size; 485dc7e38acSHans Petter Selasky priv->params_ethtool.channels = priv->params.num_channels; 486dc7e38acSHans Petter Selasky priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count); 487dc7e38acSHans Petter Selasky priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period); 488dc7e38acSHans Petter Selasky priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode; 489dc7e38acSHans Petter Selasky priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; 490dc7e38acSHans Petter Selasky priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts; 49174540a31SHans Petter Selasky priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode; 492dc7e38acSHans Petter Selasky priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; 493dc7e38acSHans Petter Selasky priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts; 494dc7e38acSHans Petter Selasky priv->params_ethtool.hw_lro = priv->params.hw_lro_en; 49590cc1c77SHans Petter Selasky priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en; 496dc7e38acSHans Petter Selasky 497dc7e38acSHans Petter Selasky /* create root node */ 498dc7e38acSHans Petter Selasky node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 499dc7e38acSHans Petter Selasky SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 500dc7e38acSHans Petter Selasky "conf", CTLFLAG_RW, NULL, "Configuration"); 501dc7e38acSHans Petter Selasky if (node == NULL) 502dc7e38acSHans Petter Selasky return; 503dc7e38acSHans Petter Selasky for (x = 0; x != MLX5E_PARAMS_NUM; x++) { 504dc7e38acSHans Petter Selasky /* check for read-only parameter */ 505dc7e38acSHans Petter Selasky if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL) { 506dc7e38acSHans Petter Selasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 507dc7e38acSHans Petter Selasky mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD | 508dc7e38acSHans Petter Selasky CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 509dc7e38acSHans Petter Selasky mlx5e_params_desc[2 * x + 1]); 510dc7e38acSHans Petter Selasky } else { 511ec0143b2SHans Petter Selasky #if (__FreeBSD_version < 1100000) 512ec0143b2SHans Petter Selasky char path[64]; 513ec0143b2SHans Petter Selasky #endif 514ec0143b2SHans Petter Selasky /* 515ec0143b2SHans Petter Selasky * NOTE: In FreeBSD-11 and newer the 516ec0143b2SHans Petter Selasky * CTLFLAG_RWTUN flag will take care of 517ec0143b2SHans Petter Selasky * loading default sysctl value from the 518ec0143b2SHans Petter Selasky * kernel environment, if any: 519ec0143b2SHans Petter Selasky */ 520dc7e38acSHans Petter Selasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 521dc7e38acSHans Petter Selasky mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN | 522dc7e38acSHans Petter Selasky CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 523dc7e38acSHans Petter Selasky mlx5e_params_desc[2 * x + 1]); 524ec0143b2SHans Petter Selasky 525ec0143b2SHans Petter Selasky #if (__FreeBSD_version < 1100000) 526ec0143b2SHans Petter Selasky /* compute path for sysctl */ 527ec0143b2SHans Petter Selasky snprintf(path, sizeof(path), "dev.mce.%d.conf.%s", 528ec0143b2SHans Petter Selasky device_get_unit(priv->mdev->pdev->dev.bsddev), 529ec0143b2SHans Petter Selasky mlx5e_params_desc[2 * x]); 530ec0143b2SHans Petter Selasky 531ec0143b2SHans Petter Selasky /* try to fetch tunable, if any */ 532ec0143b2SHans Petter Selasky if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x])) 533ec0143b2SHans Petter Selasky mlx5e_ethtool_handler(NULL, priv, x, NULL); 534ec0143b2SHans Petter Selasky #endif 535dc7e38acSHans Petter Selasky } 536dc7e38acSHans Petter Selasky } 537dc7e38acSHans Petter Selasky 538dc7e38acSHans Petter Selasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 539dc7e38acSHans Petter Selasky "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 540dc7e38acSHans Petter Selasky 0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics"); 541dc7e38acSHans Petter Selasky 542dc7e38acSHans Petter Selasky pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); 543dc7e38acSHans Petter Selasky 544dc7e38acSHans Petter Selasky SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), 545dc7e38acSHans Petter Selasky OID_AUTO, "device_name", CTLFLAG_RD, 546dc7e38acSHans Petter Selasky __DECONST(void *, pnameunit), 0, 547dc7e38acSHans Petter Selasky "PCI device name"); 548dc7e38acSHans Petter Selasky 549dc7e38acSHans Petter Selasky /* EEPROM support */ 550dc7e38acSHans Petter Selasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info", 551dc7e38acSHans Petter Selasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 552dc7e38acSHans Petter Selasky mlx5e_read_eeprom, "I", "EEPROM information"); 553dc7e38acSHans Petter Selasky } 554