1 /* 2 * Copyright (c) 2013-2017, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33 #include <linux/debugfs.h> 34 35 #include "mlx5_ib.h" 36 #include "cmd.h" 37 38 enum mlx5_ib_cong_node_type { 39 MLX5_IB_RROCE_ECN_RP = 1, 40 MLX5_IB_RROCE_ECN_NP = 2, 41 }; 42 43 static const char * const mlx5_ib_dbg_cc_name[] = { 44 "rp_clamp_tgt_rate", 45 "rp_clamp_tgt_rate_ati", 46 "rp_time_reset", 47 "rp_byte_reset", 48 "rp_threshold", 49 "rp_ai_rate", 50 "rp_hai_rate", 51 "rp_min_dec_fac", 52 "rp_min_rate", 53 "rp_rate_to_set_on_first_cnp", 54 "rp_dce_tcp_g", 55 "rp_dce_tcp_rtt", 56 "rp_rate_reduce_monitor_period", 57 "rp_initial_alpha_value", 58 "rp_gd", 59 "np_cnp_dscp", 60 "np_cnp_prio_mode", 61 "np_cnp_prio", 62 }; 63 64 #define MLX5_IB_RP_CLAMP_TGT_RATE_ATTR BIT(1) 65 #define MLX5_IB_RP_CLAMP_TGT_RATE_ATI_ATTR BIT(2) 66 #define MLX5_IB_RP_TIME_RESET_ATTR BIT(3) 67 #define MLX5_IB_RP_BYTE_RESET_ATTR BIT(4) 68 #define MLX5_IB_RP_THRESHOLD_ATTR BIT(5) 69 #define MLX5_IB_RP_AI_RATE_ATTR BIT(7) 70 #define MLX5_IB_RP_HAI_RATE_ATTR BIT(8) 71 #define MLX5_IB_RP_MIN_DEC_FAC_ATTR BIT(9) 72 #define MLX5_IB_RP_MIN_RATE_ATTR BIT(10) 73 #define MLX5_IB_RP_RATE_TO_SET_ON_FIRST_CNP_ATTR BIT(11) 74 #define MLX5_IB_RP_DCE_TCP_G_ATTR BIT(12) 75 #define MLX5_IB_RP_DCE_TCP_RTT_ATTR BIT(13) 76 #define MLX5_IB_RP_RATE_REDUCE_MONITOR_PERIOD_ATTR BIT(14) 77 #define MLX5_IB_RP_INITIAL_ALPHA_VALUE_ATTR BIT(15) 78 #define MLX5_IB_RP_GD_ATTR BIT(16) 79 80 #define MLX5_IB_NP_CNP_DSCP_ATTR BIT(3) 81 #define MLX5_IB_NP_CNP_PRIO_MODE_ATTR BIT(4) 82 83 static enum mlx5_ib_cong_node_type 84 mlx5_ib_param_to_node(enum mlx5_ib_dbg_cc_types param_offset) 85 { 86 if (param_offset >= MLX5_IB_DBG_CC_RP_CLAMP_TGT_RATE && 87 param_offset <= MLX5_IB_DBG_CC_RP_GD) 88 return MLX5_IB_RROCE_ECN_RP; 89 else 90 return MLX5_IB_RROCE_ECN_NP; 91 } 92 93 static u32 mlx5_get_cc_param_val(void *field, int offset) 94 { 95 switch (offset) { 96 case MLX5_IB_DBG_CC_RP_CLAMP_TGT_RATE: 97 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 98 clamp_tgt_rate); 99 case MLX5_IB_DBG_CC_RP_CLAMP_TGT_RATE_ATI: 100 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 101 clamp_tgt_rate_after_time_inc); 102 case MLX5_IB_DBG_CC_RP_TIME_RESET: 103 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 104 rpg_time_reset); 105 case MLX5_IB_DBG_CC_RP_BYTE_RESET: 106 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 107 rpg_byte_reset); 108 case MLX5_IB_DBG_CC_RP_THRESHOLD: 109 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 110 rpg_threshold); 111 case MLX5_IB_DBG_CC_RP_AI_RATE: 112 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 113 rpg_ai_rate); 114 case MLX5_IB_DBG_CC_RP_HAI_RATE: 115 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 116 rpg_hai_rate); 117 case MLX5_IB_DBG_CC_RP_MIN_DEC_FAC: 118 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 119 rpg_min_dec_fac); 120 case MLX5_IB_DBG_CC_RP_MIN_RATE: 121 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 122 rpg_min_rate); 123 case MLX5_IB_DBG_CC_RP_RATE_TO_SET_ON_FIRST_CNP: 124 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 125 rate_to_set_on_first_cnp); 126 case MLX5_IB_DBG_CC_RP_DCE_TCP_G: 127 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 128 dce_tcp_g); 129 case MLX5_IB_DBG_CC_RP_DCE_TCP_RTT: 130 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 131 dce_tcp_rtt); 132 case MLX5_IB_DBG_CC_RP_RATE_REDUCE_MONITOR_PERIOD: 133 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 134 rate_reduce_monitor_period); 135 case MLX5_IB_DBG_CC_RP_INITIAL_ALPHA_VALUE: 136 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 137 initial_alpha_value); 138 case MLX5_IB_DBG_CC_RP_GD: 139 return MLX5_GET(cong_control_r_roce_ecn_rp, field, 140 rpg_gd); 141 case MLX5_IB_DBG_CC_NP_CNP_DSCP: 142 return MLX5_GET(cong_control_r_roce_ecn_np, field, 143 cnp_dscp); 144 case MLX5_IB_DBG_CC_NP_CNP_PRIO_MODE: 145 return MLX5_GET(cong_control_r_roce_ecn_np, field, 146 cnp_prio_mode); 147 case MLX5_IB_DBG_CC_NP_CNP_PRIO: 148 return MLX5_GET(cong_control_r_roce_ecn_np, field, 149 cnp_802p_prio); 150 default: 151 return 0; 152 } 153 } 154 155 static void mlx5_ib_set_cc_param_mask_val(void *field, int offset, 156 u32 var, u32 *attr_mask) 157 { 158 switch (offset) { 159 case MLX5_IB_DBG_CC_RP_CLAMP_TGT_RATE: 160 *attr_mask |= MLX5_IB_RP_CLAMP_TGT_RATE_ATTR; 161 MLX5_SET(cong_control_r_roce_ecn_rp, field, 162 clamp_tgt_rate, var); 163 break; 164 case MLX5_IB_DBG_CC_RP_CLAMP_TGT_RATE_ATI: 165 *attr_mask |= MLX5_IB_RP_CLAMP_TGT_RATE_ATI_ATTR; 166 MLX5_SET(cong_control_r_roce_ecn_rp, field, 167 clamp_tgt_rate_after_time_inc, var); 168 break; 169 case MLX5_IB_DBG_CC_RP_TIME_RESET: 170 *attr_mask |= MLX5_IB_RP_TIME_RESET_ATTR; 171 MLX5_SET(cong_control_r_roce_ecn_rp, field, 172 rpg_time_reset, var); 173 break; 174 case MLX5_IB_DBG_CC_RP_BYTE_RESET: 175 *attr_mask |= MLX5_IB_RP_BYTE_RESET_ATTR; 176 MLX5_SET(cong_control_r_roce_ecn_rp, field, 177 rpg_byte_reset, var); 178 break; 179 case MLX5_IB_DBG_CC_RP_THRESHOLD: 180 *attr_mask |= MLX5_IB_RP_THRESHOLD_ATTR; 181 MLX5_SET(cong_control_r_roce_ecn_rp, field, 182 rpg_threshold, var); 183 break; 184 case MLX5_IB_DBG_CC_RP_AI_RATE: 185 *attr_mask |= MLX5_IB_RP_AI_RATE_ATTR; 186 MLX5_SET(cong_control_r_roce_ecn_rp, field, 187 rpg_ai_rate, var); 188 break; 189 case MLX5_IB_DBG_CC_RP_HAI_RATE: 190 *attr_mask |= MLX5_IB_RP_HAI_RATE_ATTR; 191 MLX5_SET(cong_control_r_roce_ecn_rp, field, 192 rpg_hai_rate, var); 193 break; 194 case MLX5_IB_DBG_CC_RP_MIN_DEC_FAC: 195 *attr_mask |= MLX5_IB_RP_MIN_DEC_FAC_ATTR; 196 MLX5_SET(cong_control_r_roce_ecn_rp, field, 197 rpg_min_dec_fac, var); 198 break; 199 case MLX5_IB_DBG_CC_RP_MIN_RATE: 200 *attr_mask |= MLX5_IB_RP_MIN_RATE_ATTR; 201 MLX5_SET(cong_control_r_roce_ecn_rp, field, 202 rpg_min_rate, var); 203 break; 204 case MLX5_IB_DBG_CC_RP_RATE_TO_SET_ON_FIRST_CNP: 205 *attr_mask |= MLX5_IB_RP_RATE_TO_SET_ON_FIRST_CNP_ATTR; 206 MLX5_SET(cong_control_r_roce_ecn_rp, field, 207 rate_to_set_on_first_cnp, var); 208 break; 209 case MLX5_IB_DBG_CC_RP_DCE_TCP_G: 210 *attr_mask |= MLX5_IB_RP_DCE_TCP_G_ATTR; 211 MLX5_SET(cong_control_r_roce_ecn_rp, field, 212 dce_tcp_g, var); 213 break; 214 case MLX5_IB_DBG_CC_RP_DCE_TCP_RTT: 215 *attr_mask |= MLX5_IB_RP_DCE_TCP_RTT_ATTR; 216 MLX5_SET(cong_control_r_roce_ecn_rp, field, 217 dce_tcp_rtt, var); 218 break; 219 case MLX5_IB_DBG_CC_RP_RATE_REDUCE_MONITOR_PERIOD: 220 *attr_mask |= MLX5_IB_RP_RATE_REDUCE_MONITOR_PERIOD_ATTR; 221 MLX5_SET(cong_control_r_roce_ecn_rp, field, 222 rate_reduce_monitor_period, var); 223 break; 224 case MLX5_IB_DBG_CC_RP_INITIAL_ALPHA_VALUE: 225 *attr_mask |= MLX5_IB_RP_INITIAL_ALPHA_VALUE_ATTR; 226 MLX5_SET(cong_control_r_roce_ecn_rp, field, 227 initial_alpha_value, var); 228 break; 229 case MLX5_IB_DBG_CC_RP_GD: 230 *attr_mask |= MLX5_IB_RP_GD_ATTR; 231 MLX5_SET(cong_control_r_roce_ecn_rp, field, 232 rpg_gd, var); 233 break; 234 case MLX5_IB_DBG_CC_NP_CNP_DSCP: 235 *attr_mask |= MLX5_IB_NP_CNP_DSCP_ATTR; 236 MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_dscp, var); 237 break; 238 case MLX5_IB_DBG_CC_NP_CNP_PRIO_MODE: 239 *attr_mask |= MLX5_IB_NP_CNP_PRIO_MODE_ATTR; 240 MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_prio_mode, var); 241 break; 242 case MLX5_IB_DBG_CC_NP_CNP_PRIO: 243 *attr_mask |= MLX5_IB_NP_CNP_PRIO_MODE_ATTR; 244 MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_prio_mode, 0); 245 MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_802p_prio, var); 246 break; 247 } 248 } 249 250 static int mlx5_ib_get_cc_params(struct mlx5_ib_dev *dev, int offset, u32 *var) 251 { 252 int outlen = MLX5_ST_SZ_BYTES(query_cong_params_out); 253 void *out; 254 void *field; 255 int err; 256 enum mlx5_ib_cong_node_type node; 257 258 out = kvzalloc(outlen, GFP_KERNEL); 259 if (!out) 260 return -ENOMEM; 261 262 node = mlx5_ib_param_to_node(offset); 263 264 err = mlx5_cmd_query_cong_params(dev->mdev, node, out, outlen); 265 if (err) 266 goto free; 267 268 field = MLX5_ADDR_OF(query_cong_params_out, out, congestion_parameters); 269 *var = mlx5_get_cc_param_val(field, offset); 270 271 free: 272 kvfree(out); 273 return err; 274 } 275 276 static int mlx5_ib_set_cc_params(struct mlx5_ib_dev *dev, int offset, u32 var) 277 { 278 int inlen = MLX5_ST_SZ_BYTES(modify_cong_params_in); 279 void *in; 280 void *field; 281 enum mlx5_ib_cong_node_type node; 282 u32 attr_mask = 0; 283 int err; 284 285 in = kvzalloc(inlen, GFP_KERNEL); 286 if (!in) 287 return -ENOMEM; 288 289 MLX5_SET(modify_cong_params_in, in, opcode, 290 MLX5_CMD_OP_MODIFY_CONG_PARAMS); 291 292 node = mlx5_ib_param_to_node(offset); 293 MLX5_SET(modify_cong_params_in, in, cong_protocol, node); 294 295 field = MLX5_ADDR_OF(modify_cong_params_in, in, congestion_parameters); 296 mlx5_ib_set_cc_param_mask_val(field, offset, var, &attr_mask); 297 298 field = MLX5_ADDR_OF(modify_cong_params_in, in, field_select); 299 MLX5_SET(field_select_r_roce_rp, field, field_select_r_roce_rp, 300 attr_mask); 301 302 err = mlx5_cmd_modify_cong_params(dev->mdev, in, inlen); 303 kvfree(in); 304 return err; 305 } 306 307 static ssize_t set_param(struct file *filp, const char __user *buf, 308 size_t count, loff_t *pos) 309 { 310 struct mlx5_ib_dbg_param *param = filp->private_data; 311 int offset = param->offset; 312 char lbuf[11] = { }; 313 u32 var; 314 int ret; 315 316 if (count > sizeof(lbuf)) 317 return -EINVAL; 318 319 if (copy_from_user(lbuf, buf, count)) 320 return -EFAULT; 321 322 lbuf[sizeof(lbuf) - 1] = '\0'; 323 324 if (kstrtou32(lbuf, 0, &var)) 325 return -EINVAL; 326 327 ret = mlx5_ib_set_cc_params(param->dev, offset, var); 328 return ret ? ret : count; 329 } 330 331 static ssize_t get_param(struct file *filp, char __user *buf, size_t count, 332 loff_t *pos) 333 { 334 struct mlx5_ib_dbg_param *param = filp->private_data; 335 int offset = param->offset; 336 u32 var = 0; 337 int ret; 338 char lbuf[11]; 339 340 if (*pos) 341 return 0; 342 343 ret = mlx5_ib_get_cc_params(param->dev, offset, &var); 344 if (ret) 345 return ret; 346 347 ret = snprintf(lbuf, sizeof(lbuf), "%d\n", var); 348 if (ret < 0) 349 return ret; 350 351 if (copy_to_user(buf, lbuf, ret)) 352 return -EFAULT; 353 354 *pos += ret; 355 return ret; 356 } 357 358 static const struct file_operations dbg_cc_fops = { 359 .owner = THIS_MODULE, 360 .open = simple_open, 361 .write = set_param, 362 .read = get_param, 363 }; 364 365 void mlx5_ib_cleanup_cong_debugfs(struct mlx5_ib_dev *dev) 366 { 367 if (!mlx5_debugfs_root || 368 !dev->dbg_cc_params || 369 !dev->dbg_cc_params->root) 370 return; 371 372 debugfs_remove_recursive(dev->dbg_cc_params->root); 373 kfree(dev->dbg_cc_params); 374 dev->dbg_cc_params = NULL; 375 } 376 377 int mlx5_ib_init_cong_debugfs(struct mlx5_ib_dev *dev) 378 { 379 struct mlx5_ib_dbg_cc_params *dbg_cc_params; 380 int i; 381 382 if (!mlx5_debugfs_root) 383 goto out; 384 385 if (!MLX5_CAP_GEN(dev->mdev, cc_query_allowed) || 386 !MLX5_CAP_GEN(dev->mdev, cc_modify_allowed)) 387 goto out; 388 389 dbg_cc_params = kzalloc(sizeof(*dbg_cc_params), GFP_KERNEL); 390 if (!dbg_cc_params) 391 goto out; 392 393 dev->dbg_cc_params = dbg_cc_params; 394 395 dbg_cc_params->root = debugfs_create_dir("cc_params", 396 dev->mdev->priv.dbg_root); 397 if (!dbg_cc_params->root) 398 goto err; 399 400 for (i = 0; i < MLX5_IB_DBG_CC_MAX; i++) { 401 dbg_cc_params->params[i].offset = i; 402 dbg_cc_params->params[i].dev = dev; 403 dbg_cc_params->params[i].dentry = 404 debugfs_create_file(mlx5_ib_dbg_cc_name[i], 405 0600, dbg_cc_params->root, 406 &dbg_cc_params->params[i], 407 &dbg_cc_fops); 408 if (!dbg_cc_params->params[i].dentry) 409 goto err; 410 } 411 out: return 0; 412 413 err: 414 mlx5_ib_warn(dev, "cong debugfs failure\n"); 415 mlx5_ib_cleanup_cong_debugfs(dev); 416 /* 417 * We don't want to fail driver if debugfs failed to initialize, 418 * so we are not forwarding error to the user. 419 */ 420 return 0; 421 } 422