mlx5_en_ethtool.c revision 331577
1290650Shselasky/*- 2290650Shselasky * Copyright (c) 2015 Mellanox Technologies. All rights reserved. 3290650Shselasky * 4290650Shselasky * Redistribution and use in source and binary forms, with or without 5290650Shselasky * modification, are permitted provided that the following conditions 6290650Shselasky * are met: 7290650Shselasky * 1. Redistributions of source code must retain the above copyright 8290650Shselasky * notice, this list of conditions and the following disclaimer. 9290650Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10290650Shselasky * notice, this list of conditions and the following disclaimer in the 11290650Shselasky * documentation and/or other materials provided with the distribution. 12290650Shselasky * 13290650Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14290650Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15290650Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16290650Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17290650Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18290650Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19290650Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20290650Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21290650Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22290650Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23290650Shselasky * SUCH DAMAGE. 24290650Shselasky * 25290650Shselasky * $FreeBSD: stable/11/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c 331577 2018-03-26 20:27:08Z hselasky $ 26290650Shselasky */ 27290650Shselasky 28290650Shselasky#include "en.h" 29290650Shselasky#include <net/sff8472.h> 30290650Shselasky 31290650Shselaskyvoid 32290650Shselaskymlx5e_create_stats(struct sysctl_ctx_list *ctx, 33290650Shselasky struct sysctl_oid_list *parent, const char *buffer, 34290650Shselasky const char **desc, unsigned num, u64 * arg) 35290650Shselasky{ 36290650Shselasky struct sysctl_oid *node; 37290650Shselasky unsigned x; 38290650Shselasky 39290650Shselasky sysctl_ctx_init(ctx); 40290650Shselasky 41290650Shselasky node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, 42290650Shselasky buffer, CTLFLAG_RD, NULL, "Statistics"); 43290650Shselasky if (node == NULL) 44290650Shselasky return; 45290650Shselasky for (x = 0; x != num; x++) { 46290650Shselasky SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 47290650Shselasky desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]); 48290650Shselasky } 49290650Shselasky} 50290650Shselasky 51300277Shselaskystatic void 52300277Shselaskymlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv) 53300277Shselasky{ 54300277Shselasky /* 55300277Shselasky * Limit the maximum distance between completion events to 56300277Shselasky * half of the currently set TX queue size. 57300277Shselasky * 58300277Shselasky * The maximum number of queue entries a single IP packet can 59300277Shselasky * consume is given by MLX5_SEND_WQE_MAX_WQEBBS. 60300277Shselasky * 61300277Shselasky * The worst case max value is then given as below: 62300277Shselasky */ 63300277Shselasky uint64_t max = priv->params_ethtool.tx_queue_size / 64300277Shselasky (2 * MLX5_SEND_WQE_MAX_WQEBBS); 65300277Shselasky 66300277Shselasky /* 67300277Shselasky * Update the maximum completion factor value in case the 68300277Shselasky * tx_queue_size field changed. Ensure we don't overflow 69300277Shselasky * 16-bits. 70300277Shselasky */ 71300277Shselasky if (max < 1) 72300277Shselasky max = 1; 73300277Shselasky else if (max > 65535) 74300277Shselasky max = 65535; 75300277Shselasky priv->params_ethtool.tx_completion_fact_max = max; 76300277Shselasky 77300277Shselasky /* 78300277Shselasky * Verify that the current TX completion factor is within the 79300277Shselasky * given limits: 80300277Shselasky */ 81300277Shselasky if (priv->params_ethtool.tx_completion_fact < 1) 82300277Shselasky priv->params_ethtool.tx_completion_fact = 1; 83300277Shselasky else if (priv->params_ethtool.tx_completion_fact > max) 84300277Shselasky priv->params_ethtool.tx_completion_fact = max; 85300277Shselasky} 86300277Shselasky 87331577Shselaskystatic int 88331577Shselaskymlx5e_getmaxrate(struct mlx5e_priv *priv) 89331577Shselasky{ 90331577Shselasky struct mlx5_core_dev *mdev = priv->mdev; 91331577Shselasky u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 92331577Shselasky u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 93331577Shselasky int err; 94331577Shselasky int i; 95331577Shselasky 96331577Shselasky PRIV_LOCK(priv); 97331577Shselasky err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit); 98331577Shselasky if (err) 99331577Shselasky goto done; 100331577Shselasky 101331577Shselasky for (i = 0; i <= mlx5_max_tc(mdev); i++) { 102331577Shselasky switch (max_bw_unit[i]) { 103331577Shselasky case MLX5_100_MBPS_UNIT: 104331577Shselasky priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB; 105331577Shselasky break; 106331577Shselasky case MLX5_GBPS_UNIT: 107331577Shselasky priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB; 108331577Shselasky break; 109331577Shselasky case MLX5_BW_NO_LIMIT: 110331577Shselasky priv->params_ethtool.max_bw_value[i] = 0; 111331577Shselasky break; 112331577Shselasky default: 113331577Shselasky priv->params_ethtool.max_bw_value[i] = -1; 114331577Shselasky WARN_ONCE(true, "non-supported BW unit"); 115331577Shselasky break; 116331577Shselasky } 117331577Shselasky } 118331577Shselaskydone: 119331577Shselasky PRIV_UNLOCK(priv); 120331577Shselasky return (err); 121331577Shselasky} 122331577Shselasky 123331577Shselaskystatic int 124331577Shselaskymlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS) 125331577Shselasky{ 126331577Shselasky struct mlx5e_priv *priv = arg1; 127331577Shselasky int prio_index = arg2; 128331577Shselasky struct mlx5_core_dev *mdev = priv->mdev; 129331577Shselasky u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 130331577Shselasky u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 131331577Shselasky int i, err; 132331577Shselasky u64 bw_val; 133331577Shselasky u64 result = priv->params_ethtool.max_bw_value[prio_index]; 134331577Shselasky const u64 upper_limit_mbps = 255 * MLX5E_100MB; 135331577Shselasky const u64 upper_limit_gbps = 255 * MLX5E_1GB; 136331577Shselasky 137331577Shselasky PRIV_LOCK(priv); 138331577Shselasky err = sysctl_handle_64(oidp, &result, 0, req); 139331577Shselasky if (err || !req->newptr || 140331577Shselasky result == priv->params_ethtool.max_bw_value[prio_index]) 141331577Shselasky goto done; 142331577Shselasky 143331577Shselasky if (result % MLX5E_100MB) { 144331577Shselasky err = ERANGE; 145331577Shselasky goto done; 146331577Shselasky } 147331577Shselasky 148331577Shselasky memset(max_bw_value, 0, sizeof(max_bw_value)); 149331577Shselasky memset(max_bw_unit, 0, sizeof(max_bw_unit)); 150331577Shselasky 151331577Shselasky for (i = 0; i <= mlx5_max_tc(mdev); i++) { 152331577Shselasky bw_val = (i == prio_index) ? result : priv->params_ethtool.max_bw_value[i]; 153331577Shselasky 154331577Shselasky if (!bw_val) { 155331577Shselasky max_bw_unit[i] = MLX5_BW_NO_LIMIT; 156331577Shselasky } else if (bw_val > upper_limit_gbps) { 157331577Shselasky result = 0; 158331577Shselasky max_bw_unit[i] = MLX5_BW_NO_LIMIT; 159331577Shselasky } else if (bw_val <= upper_limit_mbps) { 160331577Shselasky max_bw_value[i] = howmany(bw_val, MLX5E_100MB); 161331577Shselasky max_bw_unit[i] = MLX5_100_MBPS_UNIT; 162331577Shselasky } else { 163331577Shselasky max_bw_value[i] = howmany(bw_val, MLX5E_1GB); 164331577Shselasky max_bw_unit[i] = MLX5_GBPS_UNIT; 165331577Shselasky } 166331577Shselasky } 167331577Shselasky 168331577Shselasky err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit); 169331577Shselasky if (err) 170331577Shselasky goto done; 171331577Shselasky 172331577Shselasky priv->params_ethtool.max_bw_value[prio_index] = result; 173331577Shselaskydone: 174331577Shselasky PRIV_UNLOCK(priv); 175331577Shselasky return (err); 176331577Shselasky} 177331577Shselasky 178300282Shselasky#define MLX5_PARAM_OFFSET(n) \ 179300282Shselasky __offsetof(struct mlx5e_priv, params_ethtool.n) 180300282Shselasky 181290650Shselaskystatic int 182290650Shselaskymlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS) 183290650Shselasky{ 184290650Shselasky struct mlx5e_priv *priv = arg1; 185290650Shselasky uint64_t value; 186321995Shselasky int mode_modify; 187290650Shselasky int was_opened; 188290650Shselasky int error; 189290650Shselasky 190290650Shselasky PRIV_LOCK(priv); 191290650Shselasky value = priv->params_ethtool.arg[arg2]; 192292837Shselasky if (req != NULL) { 193292837Shselasky error = sysctl_handle_64(oidp, &value, 0, req); 194292837Shselasky if (error || req->newptr == NULL || 195292837Shselasky value == priv->params_ethtool.arg[arg2]) 196292837Shselasky goto done; 197290650Shselasky 198292837Shselasky /* assign new value */ 199292837Shselasky priv->params_ethtool.arg[arg2] = value; 200292837Shselasky } else { 201292837Shselasky error = 0; 202292837Shselasky } 203290650Shselasky /* check if device is gone */ 204290650Shselasky if (priv->gone) { 205290650Shselasky error = ENXIO; 206290650Shselasky goto done; 207290650Shselasky } 208300282Shselasky was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); 209321995Shselasky mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify); 210290650Shselasky 211300282Shselasky switch (MLX5_PARAM_OFFSET(arg[arg2])) { 212300282Shselasky case MLX5_PARAM_OFFSET(rx_coalesce_usecs): 213300282Shselasky /* import RX coal time */ 214300282Shselasky if (priv->params_ethtool.rx_coalesce_usecs < 1) 215300282Shselasky priv->params_ethtool.rx_coalesce_usecs = 0; 216300282Shselasky else if (priv->params_ethtool.rx_coalesce_usecs > 217300282Shselasky MLX5E_FLD_MAX(cqc, cq_period)) { 218300282Shselasky priv->params_ethtool.rx_coalesce_usecs = 219300282Shselasky MLX5E_FLD_MAX(cqc, cq_period); 220300282Shselasky } 221300282Shselasky priv->params.rx_cq_moderation_usec = 222300282Shselasky priv->params_ethtool.rx_coalesce_usecs; 223292949Shselasky 224300282Shselasky /* check to avoid down and up the network interface */ 225300282Shselasky if (was_opened) 226300282Shselasky error = mlx5e_refresh_channel_params(priv); 227300282Shselasky break; 228292949Shselasky 229300282Shselasky case MLX5_PARAM_OFFSET(rx_coalesce_pkts): 230300282Shselasky /* import RX coal pkts */ 231300282Shselasky if (priv->params_ethtool.rx_coalesce_pkts < 1) 232300282Shselasky priv->params_ethtool.rx_coalesce_pkts = 0; 233300282Shselasky else if (priv->params_ethtool.rx_coalesce_pkts > 234300282Shselasky MLX5E_FLD_MAX(cqc, cq_max_count)) { 235300282Shselasky priv->params_ethtool.rx_coalesce_pkts = 236300282Shselasky MLX5E_FLD_MAX(cqc, cq_max_count); 237300282Shselasky } 238300282Shselasky priv->params.rx_cq_moderation_pkts = 239300282Shselasky priv->params_ethtool.rx_coalesce_pkts; 240292949Shselasky 241300282Shselasky /* check to avoid down and up the network interface */ 242300282Shselasky if (was_opened) 243300282Shselasky error = mlx5e_refresh_channel_params(priv); 244300282Shselasky break; 245292949Shselasky 246300282Shselasky case MLX5_PARAM_OFFSET(tx_coalesce_usecs): 247300282Shselasky /* import TX coal time */ 248300282Shselasky if (priv->params_ethtool.tx_coalesce_usecs < 1) 249300282Shselasky priv->params_ethtool.tx_coalesce_usecs = 0; 250300282Shselasky else if (priv->params_ethtool.tx_coalesce_usecs > 251300282Shselasky MLX5E_FLD_MAX(cqc, cq_period)) { 252300282Shselasky priv->params_ethtool.tx_coalesce_usecs = 253300282Shselasky MLX5E_FLD_MAX(cqc, cq_period); 254300282Shselasky } 255300282Shselasky priv->params.tx_cq_moderation_usec = 256300282Shselasky priv->params_ethtool.tx_coalesce_usecs; 257300282Shselasky 258300282Shselasky /* check to avoid down and up the network interface */ 259300282Shselasky if (was_opened) 260292949Shselasky error = mlx5e_refresh_channel_params(priv); 261300282Shselasky break; 262300282Shselasky 263300282Shselasky case MLX5_PARAM_OFFSET(tx_coalesce_pkts): 264300282Shselasky /* import TX coal pkts */ 265300282Shselasky if (priv->params_ethtool.tx_coalesce_pkts < 1) 266300282Shselasky priv->params_ethtool.tx_coalesce_pkts = 0; 267300282Shselasky else if (priv->params_ethtool.tx_coalesce_pkts > 268300282Shselasky MLX5E_FLD_MAX(cqc, cq_max_count)) { 269300282Shselasky priv->params_ethtool.tx_coalesce_pkts = 270300282Shselasky MLX5E_FLD_MAX(cqc, cq_max_count); 271292949Shselasky } 272300282Shselasky priv->params.tx_cq_moderation_pkts = 273300282Shselasky priv->params_ethtool.tx_coalesce_pkts; 274300282Shselasky 275300282Shselasky /* check to avoid down and up the network interface */ 276300282Shselasky if (was_opened) 277300282Shselasky error = mlx5e_refresh_channel_params(priv); 278300282Shselasky break; 279300282Shselasky 280300282Shselasky case MLX5_PARAM_OFFSET(tx_queue_size): 281300282Shselasky /* network interface must be down */ 282300282Shselasky if (was_opened) 283300282Shselasky mlx5e_close_locked(priv->ifp); 284300282Shselasky 285300282Shselasky /* import TX queue size */ 286300282Shselasky if (priv->params_ethtool.tx_queue_size < 287300282Shselasky (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { 288300282Shselasky priv->params_ethtool.tx_queue_size = 289300282Shselasky (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); 290300282Shselasky } else if (priv->params_ethtool.tx_queue_size > 291300282Shselasky priv->params_ethtool.tx_queue_size_max) { 292300282Shselasky priv->params_ethtool.tx_queue_size = 293300282Shselasky priv->params_ethtool.tx_queue_size_max; 294300282Shselasky } 295300282Shselasky /* store actual TX queue size */ 296300282Shselasky priv->params.log_sq_size = 297300282Shselasky order_base_2(priv->params_ethtool.tx_queue_size); 298290650Shselasky priv->params_ethtool.tx_queue_size = 299300282Shselasky 1 << priv->params.log_sq_size; 300290650Shselasky 301300282Shselasky /* verify TX completion factor */ 302300282Shselasky mlx5e_ethtool_sync_tx_completion_fact(priv); 303300282Shselasky 304300282Shselasky /* restart network interface, if any */ 305300282Shselasky if (was_opened) 306300282Shselasky mlx5e_open_locked(priv->ifp); 307300282Shselasky break; 308300282Shselasky 309300282Shselasky case MLX5_PARAM_OFFSET(rx_queue_size): 310300282Shselasky /* network interface must be down */ 311300282Shselasky if (was_opened) 312300282Shselasky mlx5e_close_locked(priv->ifp); 313300282Shselasky 314300282Shselasky /* import RX queue size */ 315300282Shselasky if (priv->params_ethtool.rx_queue_size < 316300282Shselasky (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { 317300282Shselasky priv->params_ethtool.rx_queue_size = 318300282Shselasky (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); 319300282Shselasky } else if (priv->params_ethtool.rx_queue_size > 320300282Shselasky priv->params_ethtool.rx_queue_size_max) { 321300282Shselasky priv->params_ethtool.rx_queue_size = 322300282Shselasky priv->params_ethtool.rx_queue_size_max; 323300282Shselasky } 324300282Shselasky /* store actual RX queue size */ 325300282Shselasky priv->params.log_rq_size = 326300282Shselasky order_base_2(priv->params_ethtool.rx_queue_size); 327290650Shselasky priv->params_ethtool.rx_queue_size = 328300282Shselasky 1 << priv->params.log_rq_size; 329290650Shselasky 330300282Shselasky /* update least number of RX WQEs */ 331300282Shselasky priv->params.min_rx_wqes = min( 332300282Shselasky priv->params_ethtool.rx_queue_size - 1, 333300282Shselasky MLX5E_PARAMS_DEFAULT_MIN_RX_WQES); 334290650Shselasky 335300282Shselasky /* restart network interface, if any */ 336300282Shselasky if (was_opened) 337300282Shselasky mlx5e_open_locked(priv->ifp); 338300282Shselasky break; 339290650Shselasky 340300282Shselasky case MLX5_PARAM_OFFSET(channels): 341300282Shselasky /* network interface must be down */ 342300282Shselasky if (was_opened) 343300282Shselasky mlx5e_close_locked(priv->ifp); 344290650Shselasky 345300282Shselasky /* import number of channels */ 346300282Shselasky if (priv->params_ethtool.channels < 1) 347300282Shselasky priv->params_ethtool.channels = 1; 348300282Shselasky else if (priv->params_ethtool.channels > 349300282Shselasky (u64) priv->mdev->priv.eq_table.num_comp_vectors) { 350300282Shselasky priv->params_ethtool.channels = 351300282Shselasky (u64) priv->mdev->priv.eq_table.num_comp_vectors; 352300282Shselasky } 353300282Shselasky priv->params.num_channels = priv->params_ethtool.channels; 354291932Shselasky 355300282Shselasky /* restart network interface, if any */ 356300282Shselasky if (was_opened) 357300282Shselasky mlx5e_open_locked(priv->ifp); 358300282Shselasky break; 359300282Shselasky 360300282Shselasky case MLX5_PARAM_OFFSET(rx_coalesce_mode): 361300282Shselasky /* network interface must be down */ 362321995Shselasky if (was_opened != 0 && mode_modify == 0) 363300282Shselasky mlx5e_close_locked(priv->ifp); 364300282Shselasky 365300282Shselasky /* import RX coalesce mode */ 366300282Shselasky if (priv->params_ethtool.rx_coalesce_mode != 0) 367300282Shselasky priv->params_ethtool.rx_coalesce_mode = 1; 368300282Shselasky priv->params.rx_cq_moderation_mode = 369300282Shselasky priv->params_ethtool.rx_coalesce_mode; 370300282Shselasky 371300282Shselasky /* restart network interface, if any */ 372321995Shselasky if (was_opened != 0) { 373321995Shselasky if (mode_modify == 0) 374321995Shselasky mlx5e_open_locked(priv->ifp); 375321995Shselasky else 376321995Shselasky error = mlx5e_refresh_channel_params(priv); 377321995Shselasky } 378300282Shselasky break; 379300282Shselasky 380300282Shselasky case MLX5_PARAM_OFFSET(tx_coalesce_mode): 381300282Shselasky /* network interface must be down */ 382321995Shselasky if (was_opened != 0 && mode_modify == 0) 383300282Shselasky mlx5e_close_locked(priv->ifp); 384300282Shselasky 385300282Shselasky /* import TX coalesce mode */ 386300282Shselasky if (priv->params_ethtool.tx_coalesce_mode != 0) 387300282Shselasky priv->params_ethtool.tx_coalesce_mode = 1; 388300282Shselasky priv->params.tx_cq_moderation_mode = 389300282Shselasky priv->params_ethtool.tx_coalesce_mode; 390300282Shselasky 391300282Shselasky /* restart network interface, if any */ 392321995Shselasky if (was_opened != 0) { 393321995Shselasky if (mode_modify == 0) 394321995Shselasky mlx5e_open_locked(priv->ifp); 395321995Shselasky else 396321995Shselasky error = mlx5e_refresh_channel_params(priv); 397321995Shselasky } 398300282Shselasky break; 399300282Shselasky 400300282Shselasky case MLX5_PARAM_OFFSET(hw_lro): 401300282Shselasky /* network interface must be down */ 402300282Shselasky if (was_opened) 403300282Shselasky mlx5e_close_locked(priv->ifp); 404300282Shselasky 405300282Shselasky /* import HW LRO mode */ 406300282Shselasky if (priv->params_ethtool.hw_lro != 0) { 407300282Shselasky if ((priv->ifp->if_capenable & IFCAP_LRO) && 408300282Shselasky MLX5_CAP_ETH(priv->mdev, lro_cap)) { 409300282Shselasky priv->params.hw_lro_en = 1; 410300282Shselasky priv->params_ethtool.hw_lro = 1; 411300282Shselasky } else { 412300282Shselasky priv->params.hw_lro_en = 0; 413300282Shselasky priv->params_ethtool.hw_lro = 0; 414300282Shselasky error = EINVAL; 415300282Shselasky 416300282Shselasky if_printf(priv->ifp, "Can't enable HW LRO: " 417300282Shselasky "The HW or SW LRO feature is disabled\n"); 418300282Shselasky } 419294319Shselasky } else { 420294319Shselasky priv->params.hw_lro_en = 0; 421291068Shselasky } 422300282Shselasky /* restart network interface, if any */ 423300282Shselasky if (was_opened) 424300282Shselasky mlx5e_open_locked(priv->ifp); 425300282Shselasky break; 426290650Shselasky 427300282Shselasky case MLX5_PARAM_OFFSET(cqe_zipping): 428300282Shselasky /* network interface must be down */ 429300282Shselasky if (was_opened) 430300282Shselasky mlx5e_close_locked(priv->ifp); 431300282Shselasky 432300282Shselasky /* import CQE zipping mode */ 433292838Shselasky if (priv->params_ethtool.cqe_zipping && 434292838Shselasky MLX5_CAP_GEN(priv->mdev, cqe_compression)) { 435292838Shselasky priv->params.cqe_zipping_en = true; 436292838Shselasky priv->params_ethtool.cqe_zipping = 1; 437292838Shselasky } else { 438292838Shselasky priv->params.cqe_zipping_en = false; 439292838Shselasky priv->params_ethtool.cqe_zipping = 0; 440292838Shselasky } 441300282Shselasky /* restart network interface, if any */ 442300282Shselasky if (was_opened) 443300282Shselasky mlx5e_open_locked(priv->ifp); 444300282Shselasky break; 445300277Shselasky 446321999Shselasky case MLX5_PARAM_OFFSET(tx_bufring_disable): 447321999Shselasky /* rangecheck input value */ 448321999Shselasky priv->params_ethtool.tx_bufring_disable = 449321999Shselasky priv->params_ethtool.tx_bufring_disable ? 1 : 0; 450321999Shselasky 451321999Shselasky /* reconfigure the sendqueues, if any */ 452321999Shselasky if (was_opened) { 453321999Shselasky mlx5e_close_locked(priv->ifp); 454321999Shselasky mlx5e_open_locked(priv->ifp); 455321999Shselasky } 456321999Shselasky break; 457321999Shselasky 458300282Shselasky case MLX5_PARAM_OFFSET(tx_completion_fact): 459300282Shselasky /* network interface must be down */ 460300282Shselasky if (was_opened) 461300282Shselasky mlx5e_close_locked(priv->ifp); 462300282Shselasky 463300277Shselasky /* verify parameter */ 464300277Shselasky mlx5e_ethtool_sync_tx_completion_fact(priv); 465300282Shselasky 466300282Shselasky /* restart network interface, if any */ 467300282Shselasky if (was_opened) 468300282Shselasky mlx5e_open_locked(priv->ifp); 469300282Shselasky break; 470300282Shselasky 471331568Shselasky case MLX5_PARAM_OFFSET(modify_tx_dma): 472331568Shselasky /* check if network interface is opened */ 473331568Shselasky if (was_opened) { 474331568Shselasky priv->params_ethtool.modify_tx_dma = 475331568Shselasky priv->params_ethtool.modify_tx_dma ? 1 : 0; 476331568Shselasky /* modify tx according to value */ 477331568Shselasky mlx5e_modify_tx_dma(priv, value != 0); 478331568Shselasky } else { 479331568Shselasky /* if closed force enable tx */ 480331568Shselasky priv->params_ethtool.modify_tx_dma = 0; 481331568Shselasky } 482331568Shselasky break; 483331568Shselasky 484331568Shselasky case MLX5_PARAM_OFFSET(modify_rx_dma): 485331568Shselasky /* check if network interface is opened */ 486331568Shselasky if (was_opened) { 487331568Shselasky priv->params_ethtool.modify_rx_dma = 488331568Shselasky priv->params_ethtool.modify_rx_dma ? 1 : 0; 489331568Shselasky /* modify rx according to value */ 490331568Shselasky mlx5e_modify_rx_dma(priv, value != 0); 491331568Shselasky } else { 492331568Shselasky /* if closed force enable rx */ 493331568Shselasky priv->params_ethtool.modify_rx_dma = 0; 494331568Shselasky } 495331568Shselasky break; 496331568Shselasky 497322006Shselasky case MLX5_PARAM_OFFSET(diag_pci_enable): 498322006Shselasky priv->params_ethtool.diag_pci_enable = 499322006Shselasky priv->params_ethtool.diag_pci_enable ? 1 : 0; 500322006Shselasky 501322006Shselasky error = -mlx5_core_set_diagnostics_full(priv->mdev, 502322006Shselasky priv->params_ethtool.diag_pci_enable, 503322006Shselasky priv->params_ethtool.diag_general_enable); 504322006Shselasky break; 505322006Shselasky 506322006Shselasky case MLX5_PARAM_OFFSET(diag_general_enable): 507322006Shselasky priv->params_ethtool.diag_general_enable = 508322006Shselasky priv->params_ethtool.diag_general_enable ? 1 : 0; 509322006Shselasky 510322006Shselasky error = -mlx5_core_set_diagnostics_full(priv->mdev, 511322006Shselasky priv->params_ethtool.diag_pci_enable, 512322006Shselasky priv->params_ethtool.diag_general_enable); 513322006Shselasky break; 514322006Shselasky 515331569Shselasky case MLX5_PARAM_OFFSET(mc_local_lb): 516331569Shselasky priv->params_ethtool.mc_local_lb = 517331569Shselasky priv->params_ethtool.mc_local_lb ? 1 : 0; 518331569Shselasky 519331569Shselasky if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 520331569Shselasky error = mlx5_nic_vport_modify_local_lb(priv->mdev, 521331569Shselasky MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb); 522331569Shselasky } else { 523331569Shselasky error = EOPNOTSUPP; 524331569Shselasky } 525331569Shselasky break; 526331569Shselasky 527331569Shselasky case MLX5_PARAM_OFFSET(uc_local_lb): 528331569Shselasky priv->params_ethtool.uc_local_lb = 529331569Shselasky priv->params_ethtool.uc_local_lb ? 1 : 0; 530331569Shselasky 531331569Shselasky if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 532331569Shselasky error = mlx5_nic_vport_modify_local_lb(priv->mdev, 533331569Shselasky MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb); 534331569Shselasky } else { 535331569Shselasky error = EOPNOTSUPP; 536331569Shselasky } 537331569Shselasky break; 538331569Shselasky 539300282Shselasky default: 540300282Shselasky break; 541300277Shselasky } 542290650Shselaskydone: 543290650Shselasky PRIV_UNLOCK(priv); 544290650Shselasky return (error); 545290650Shselasky} 546290650Shselasky 547290650Shselasky/* 548290650Shselasky * Read the first three bytes of the eeprom in order to get the needed info 549290650Shselasky * for the whole reading. 550290650Shselasky * Byte 0 - Identifier byte 551290650Shselasky * Byte 1 - Revision byte 552290650Shselasky * Byte 2 - Status byte 553290650Shselasky */ 554290650Shselaskystatic int 555290650Shselaskymlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom) 556290650Shselasky{ 557290650Shselasky struct mlx5_core_dev *dev = priv->mdev; 558290650Shselasky u32 data = 0; 559290650Shselasky int size_read = 0; 560290650Shselasky int ret; 561290650Shselasky 562290650Shselasky ret = mlx5_query_module_num(dev, &eeprom->module_num); 563290650Shselasky if (ret) { 564290650Shselasky if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n", 565290650Shselasky __func__, __LINE__, ret); 566290650Shselasky return (ret); 567290650Shselasky } 568290650Shselasky 569290650Shselasky /* Read the first three bytes to get Identifier, Revision and Status */ 570290650Shselasky ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num, 571290650Shselasky eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data, 572290650Shselasky &size_read); 573290650Shselasky if (ret) { 574290650Shselasky if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n", 575290650Shselasky __func__, __LINE__, ret); 576290650Shselasky return (ret); 577290650Shselasky } 578290650Shselasky 579290650Shselasky switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) { 580290650Shselasky case SFF_8024_ID_QSFP: 581290650Shselasky eeprom->type = MLX5E_ETH_MODULE_SFF_8436; 582290650Shselasky eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN; 583290650Shselasky break; 584290650Shselasky case SFF_8024_ID_QSFPPLUS: 585290650Shselasky case SFF_8024_ID_QSFP28: 586290650Shselasky if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 || 587291070Shselasky ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) { 588290650Shselasky eeprom->type = MLX5E_ETH_MODULE_SFF_8636; 589290650Shselasky eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN; 590290650Shselasky } else { 591290650Shselasky eeprom->type = MLX5E_ETH_MODULE_SFF_8436; 592290650Shselasky eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN; 593290650Shselasky } 594290650Shselasky if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0) 595290650Shselasky eeprom->page_valid = 1; 596290650Shselasky break; 597290650Shselasky case SFF_8024_ID_SFP: 598290650Shselasky eeprom->type = MLX5E_ETH_MODULE_SFF_8472; 599290650Shselasky eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN; 600290650Shselasky break; 601290650Shselasky default: 602291067Shselasky if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n", 603291067Shselasky __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK, 604291067Shselasky sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]); 605290650Shselasky return (EINVAL); 606290650Shselasky } 607290650Shselasky return (0); 608290650Shselasky} 609290650Shselasky 610290650Shselasky/* Read both low and high pages of the eeprom */ 611290650Shselaskystatic int 612290650Shselaskymlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee) 613290650Shselasky{ 614290650Shselasky struct mlx5_core_dev *dev = priv->mdev; 615290650Shselasky int size_read = 0; 616290650Shselasky int ret; 617290650Shselasky 618290650Shselasky if (ee->len == 0) 619290650Shselasky return (EINVAL); 620290650Shselasky 621290650Shselasky /* Read low page of the eeprom */ 622290650Shselasky while (ee->device_addr < ee->len) { 623290650Shselasky ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr, 624290650Shselasky ee->len - ee->device_addr, ee->module_num, 625291070Shselasky ee->data + (ee->device_addr / 4), &size_read); 626290650Shselasky if (ret) { 627290650Shselasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom, " 628290650Shselasky "error = 0x%02x\n", __func__, __LINE__, ret); 629290650Shselasky return (ret); 630290650Shselasky } 631290650Shselasky ee->device_addr += size_read; 632290650Shselasky } 633290650Shselasky 634290650Shselasky /* Read high page of the eeprom */ 635290650Shselasky if (ee->page_valid) { 636290650Shselasky ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET; 637290650Shselasky ee->page_num = MLX5E_EEPROM_HIGH_PAGE; 638290650Shselasky size_read = 0; 639290650Shselasky while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) { 640290650Shselasky ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, 641290650Shselasky ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr, 642291070Shselasky ee->module_num, ee->data + (ee->len / 4) + 643291070Shselasky ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4), 644290650Shselasky &size_read); 645290650Shselasky if (ret) { 646290650Shselasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom, " 647290650Shselasky "error = 0x%02x\n", __func__, __LINE__, ret); 648290650Shselasky return (ret); 649290650Shselasky } 650290650Shselasky ee->device_addr += size_read; 651290650Shselasky } 652290650Shselasky } 653290650Shselasky return (0); 654290650Shselasky} 655290650Shselasky 656290650Shselaskystatic void 657290650Shselaskymlx5e_print_eeprom(struct mlx5e_eeprom *eeprom) 658290650Shselasky{ 659292835Shselasky int row; 660292835Shselasky int index_in_row; 661292835Shselasky int byte_to_write = 0; 662292835Shselasky int line_length = 16; 663290650Shselasky 664290650Shselasky printf("\nOffset\t\tValues\n"); 665292835Shselasky printf("------\t\t------"); 666292835Shselasky while (byte_to_write < eeprom->len) { 667292835Shselasky printf("\n0x%04X\t\t", byte_to_write); 668292835Shselasky for (index_in_row = 0; index_in_row < line_length; index_in_row++) { 669292835Shselasky printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]); 670292835Shselasky byte_to_write++; 671290650Shselasky } 672290650Shselasky } 673290650Shselasky 674290650Shselasky if (eeprom->page_valid) { 675290650Shselasky row = MLX5E_EEPROM_HIGH_PAGE_OFFSET; 676292835Shselasky printf("\n\nUpper Page 0x03\n"); 677290650Shselasky printf("\nOffset\t\tValues\n"); 678292835Shselasky printf("------\t\t------"); 679290650Shselasky while (row < MLX5E_EEPROM_PAGE_LENGTH) { 680292835Shselasky printf("\n0x%04X\t\t", row); 681292835Shselasky for (index_in_row = 0; index_in_row < line_length; index_in_row++) { 682292835Shselasky printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]); 683292835Shselasky byte_to_write++; 684290650Shselasky row++; 685290650Shselasky } 686290650Shselasky } 687290650Shselasky } 688290650Shselasky} 689290650Shselasky 690290650Shselasky/* 691290650Shselasky * Read cable EEPROM module information by first inspecting the first 692290650Shselasky * three bytes to get the initial information for a whole reading. 693290650Shselasky * Information will be printed to dmesg. 694290650Shselasky */ 695290650Shselaskystatic int 696290650Shselaskymlx5e_read_eeprom(SYSCTL_HANDLER_ARGS) 697290650Shselasky{ 698290650Shselasky struct mlx5e_priv *priv = arg1; 699290650Shselasky struct mlx5e_eeprom eeprom; 700290650Shselasky int error; 701290650Shselasky int result = 0; 702290650Shselasky 703290650Shselasky PRIV_LOCK(priv); 704290650Shselasky error = sysctl_handle_int(oidp, &result, 0, req); 705290650Shselasky if (error || !req->newptr) 706290650Shselasky goto done; 707290650Shselasky 708290650Shselasky /* Check if device is gone */ 709290650Shselasky if (priv->gone) { 710290650Shselasky error = ENXIO; 711290650Shselasky goto done; 712290650Shselasky } 713290650Shselasky 714290650Shselasky if (result == 1) { 715290650Shselasky eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW; 716290650Shselasky eeprom.device_addr = 0; 717290650Shselasky eeprom.page_num = MLX5E_EEPROM_LOW_PAGE; 718290650Shselasky eeprom.page_valid = 0; 719290650Shselasky 720290650Shselasky /* Read three first bytes to get important info */ 721290650Shselasky error = mlx5e_get_eeprom_info(priv, &eeprom); 722290650Shselasky if (error) { 723290650Shselasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom's " 724290650Shselasky "initial information\n", __func__, __LINE__); 725290650Shselasky error = 0; 726290650Shselasky goto done; 727290650Shselasky } 728291070Shselasky /* 729291070Shselasky * Allocate needed length buffer and additional space for 730291070Shselasky * page 0x03 731291070Shselasky */ 732290650Shselasky eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH, 733290650Shselasky M_MLX5EN, M_WAITOK | M_ZERO); 734290650Shselasky 735290650Shselasky /* Read the whole eeprom information */ 736290650Shselasky error = mlx5e_get_eeprom(priv, &eeprom); 737290650Shselasky if (error) { 738290650Shselasky if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n", 739290650Shselasky __func__, __LINE__); 740290650Shselasky error = 0; 741291070Shselasky /* 742291070Shselasky * Continue printing partial information in case of 743291070Shselasky * an error 744291070Shselasky */ 745290650Shselasky } 746290650Shselasky mlx5e_print_eeprom(&eeprom); 747290650Shselasky free(eeprom.data, M_MLX5EN); 748290650Shselasky } 749290650Shselaskydone: 750290650Shselasky PRIV_UNLOCK(priv); 751290650Shselasky return (error); 752290650Shselasky} 753290650Shselasky 754290650Shselaskystatic const char *mlx5e_params_desc[] = { 755290650Shselasky MLX5E_PARAMS(MLX5E_STATS_DESC) 756290650Shselasky}; 757290650Shselasky 758290650Shselaskystatic const char *mlx5e_port_stats_debug_desc[] = { 759290650Shselasky MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC) 760290650Shselasky}; 761290650Shselasky 762290650Shselaskystatic int 763290650Shselaskymlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS) 764290650Shselasky{ 765290650Shselasky struct mlx5e_priv *priv = arg1; 766290650Shselasky int error; 767290650Shselasky int sys_debug; 768290650Shselasky 769290650Shselasky sys_debug = priv->sysctl_debug; 770290650Shselasky error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req); 771290650Shselasky if (error || !req->newptr) 772290650Shselasky return (error); 773290650Shselasky priv->sysctl_debug = !!priv->sysctl_debug; 774290650Shselasky if (sys_debug == priv->sysctl_debug) 775290650Shselasky return (error); 776290650Shselasky if (priv->sysctl_debug) 777290650Shselasky mlx5e_create_stats(&priv->stats.port_stats_debug.ctx, 778290650Shselasky SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats", 779290650Shselasky mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM, 780290650Shselasky priv->stats.port_stats_debug.arg); 781290650Shselasky else 782290650Shselasky sysctl_ctx_free(&priv->stats.port_stats_debug.ctx); 783290650Shselasky return (error); 784290650Shselasky} 785290650Shselasky 786322006Shselaskystatic void 787322006Shselaskymlx5e_create_diagnostics(struct mlx5e_priv *priv) 788322006Shselasky{ 789322006Shselasky struct mlx5_core_diagnostics_entry entry; 790322006Shselasky struct sysctl_ctx_list *ctx; 791322006Shselasky struct sysctl_oid *node; 792322006Shselasky int x; 793322006Shselasky 794322006Shselasky /* sysctl context we are using */ 795322006Shselasky ctx = &priv->sysctl_ctx; 796322006Shselasky 797322006Shselasky /* create root node */ 798322006Shselasky node = SYSCTL_ADD_NODE(ctx, 799322006Shselasky SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 800322006Shselasky "diagnostics", CTLFLAG_RD, NULL, "Diagnostics"); 801322006Shselasky if (node == NULL) 802322006Shselasky return; 803322006Shselasky 804322006Shselasky /* create PCI diagnostics */ 805322006Shselasky for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) { 806322006Shselasky entry = mlx5_core_pci_diagnostics_table[x]; 807322006Shselasky if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0) 808322006Shselasky continue; 809322006Shselasky SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 810322006Shselasky entry.desc, CTLFLAG_RD, priv->params_pci.array + x, 811322006Shselasky "PCI diagnostics counter"); 812322006Shselasky } 813322006Shselasky 814322006Shselasky /* create general diagnostics */ 815322006Shselasky for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) { 816322006Shselasky entry = mlx5_core_general_diagnostics_table[x]; 817322006Shselasky if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0) 818322006Shselasky continue; 819322006Shselasky SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 820322006Shselasky entry.desc, CTLFLAG_RD, priv->params_general.array + x, 821322006Shselasky "General diagnostics counter"); 822322006Shselasky } 823322006Shselasky} 824322006Shselasky 825290650Shselaskyvoid 826290650Shselaskymlx5e_create_ethtool(struct mlx5e_priv *priv) 827290650Shselasky{ 828331577Shselasky struct mlx5_core_dev *mdev = priv->mdev; 829331577Shselasky struct sysctl_oid *node, *qos_node; 830290650Shselasky const char *pnameunit; 831290650Shselasky unsigned x; 832331577Shselasky int i; 833290650Shselasky 834290650Shselasky /* set some defaults */ 835290650Shselasky priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; 836290650Shselasky priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; 837290650Shselasky priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size; 838290650Shselasky priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size; 839290650Shselasky priv->params_ethtool.channels = priv->params.num_channels; 840290650Shselasky priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count); 841290650Shselasky priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period); 842290650Shselasky priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode; 843290650Shselasky priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; 844290650Shselasky priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts; 845291932Shselasky priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode; 846290650Shselasky priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; 847290650Shselasky priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts; 848290650Shselasky priv->params_ethtool.hw_lro = priv->params.hw_lro_en; 849292838Shselasky priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en; 850300277Shselasky mlx5e_ethtool_sync_tx_completion_fact(priv); 851290650Shselasky 852331569Shselasky /* get default values for local loopback, if any */ 853331569Shselasky if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 854331569Shselasky int err; 855331569Shselasky u8 val; 856331569Shselasky 857331569Shselasky err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val); 858331569Shselasky if (err == 0) 859331569Shselasky priv->params_ethtool.mc_local_lb = val; 860331569Shselasky 861331569Shselasky err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val); 862331569Shselasky if (err == 0) 863331569Shselasky priv->params_ethtool.uc_local_lb = val; 864331569Shselasky } 865331569Shselasky 866290650Shselasky /* create root node */ 867290650Shselasky node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 868290650Shselasky SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 869290650Shselasky "conf", CTLFLAG_RW, NULL, "Configuration"); 870290650Shselasky if (node == NULL) 871290650Shselasky return; 872290650Shselasky for (x = 0; x != MLX5E_PARAMS_NUM; x++) { 873290650Shselasky /* check for read-only parameter */ 874331570Shselasky if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL || 875331570Shselasky strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) { 876290650Shselasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 877290650Shselasky mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD | 878290650Shselasky CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 879290650Shselasky mlx5e_params_desc[2 * x + 1]); 880290650Shselasky } else { 881292837Shselasky#if (__FreeBSD_version < 1100000) 882292837Shselasky char path[64]; 883292837Shselasky#endif 884292837Shselasky /* 885292837Shselasky * NOTE: In FreeBSD-11 and newer the 886292837Shselasky * CTLFLAG_RWTUN flag will take care of 887292837Shselasky * loading default sysctl value from the 888292837Shselasky * kernel environment, if any: 889292837Shselasky */ 890290650Shselasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 891290650Shselasky mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN | 892290650Shselasky CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 893290650Shselasky mlx5e_params_desc[2 * x + 1]); 894292837Shselasky 895292837Shselasky#if (__FreeBSD_version < 1100000) 896292837Shselasky /* compute path for sysctl */ 897292837Shselasky snprintf(path, sizeof(path), "dev.mce.%d.conf.%s", 898292837Shselasky device_get_unit(priv->mdev->pdev->dev.bsddev), 899292837Shselasky mlx5e_params_desc[2 * x]); 900292837Shselasky 901292837Shselasky /* try to fetch tunable, if any */ 902292837Shselasky if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x])) 903292837Shselasky mlx5e_ethtool_handler(NULL, priv, x, NULL); 904292837Shselasky#endif 905290650Shselasky } 906290650Shselasky } 907290650Shselasky 908290650Shselasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 909290650Shselasky "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 910290650Shselasky 0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics"); 911290650Shselasky 912290650Shselasky pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); 913290650Shselasky 914290650Shselasky SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), 915290650Shselasky OID_AUTO, "device_name", CTLFLAG_RD, 916290650Shselasky __DECONST(void *, pnameunit), 0, 917290650Shselasky "PCI device name"); 918290650Shselasky 919290650Shselasky /* EEPROM support */ 920290650Shselasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info", 921290650Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 922290650Shselasky mlx5e_read_eeprom, "I", "EEPROM information"); 923322006Shselasky 924322006Shselasky /* Diagnostics support */ 925322006Shselasky mlx5e_create_diagnostics(priv); 926331577Shselasky 927331577Shselasky /* create qos node */ 928331577Shselasky qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 929331577Shselasky SYSCTL_CHILDREN(node), OID_AUTO, 930331577Shselasky "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration"); 931331577Shselasky if (node == NULL) 932331577Shselasky return; 933331577Shselasky 934331577Shselasky /* Prioriry rate limit support */ 935331577Shselasky if (mlx5e_getmaxrate(priv)) 936331577Shselasky return; 937331577Shselasky 938331577Shselasky for (i = 0; i <= mlx5_max_tc(mdev); i++) { 939331577Shselasky char name[32]; 940331577Shselasky snprintf(name, sizeof(name), "tc_%d_max_rate", i); 941331577Shselasky SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 942331577Shselasky OID_AUTO, name, CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, 943331577Shselasky priv, i, mlx5e_tc_maxrate_handler, "QU", 944331577Shselasky "Max rate for priority, specified in kilobits, where kilo=1000, \ 945331577Shselasky max_rate must be divisible by 100000"); 946331577Shselasky } 947290650Shselasky} 948