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, u8 port_num, 251 int offset, u32 *var) 252 { 253 int outlen = MLX5_ST_SZ_BYTES(query_cong_params_out); 254 void *out; 255 void *field; 256 int err; 257 enum mlx5_ib_cong_node_type node; 258 struct mlx5_core_dev *mdev; 259 260 /* Takes a 1-based port number */ 261 mdev = mlx5_ib_get_native_port_mdev(dev, port_num + 1, NULL); 262 if (!mdev) 263 return -ENODEV; 264 265 out = kvzalloc(outlen, GFP_KERNEL); 266 if (!out) { 267 err = -ENOMEM; 268 goto alloc_err; 269 } 270 271 node = mlx5_ib_param_to_node(offset); 272 273 err = mlx5_cmd_query_cong_params(mdev, node, out, outlen); 274 if (err) 275 goto free; 276 277 field = MLX5_ADDR_OF(query_cong_params_out, out, congestion_parameters); 278 *var = mlx5_get_cc_param_val(field, offset); 279 280 free: 281 kvfree(out); 282 alloc_err: 283 mlx5_ib_put_native_port_mdev(dev, port_num + 1); 284 return err; 285 } 286 287 static int mlx5_ib_set_cc_params(struct mlx5_ib_dev *dev, u8 port_num, 288 int offset, u32 var) 289 { 290 int inlen = MLX5_ST_SZ_BYTES(modify_cong_params_in); 291 void *in; 292 void *field; 293 enum mlx5_ib_cong_node_type node; 294 struct mlx5_core_dev *mdev; 295 u32 attr_mask = 0; 296 int err; 297 298 /* Takes a 1-based port number */ 299 mdev = mlx5_ib_get_native_port_mdev(dev, port_num + 1, NULL); 300 if (!mdev) 301 return -ENODEV; 302 303 in = kvzalloc(inlen, GFP_KERNEL); 304 if (!in) { 305 err = -ENOMEM; 306 goto alloc_err; 307 } 308 309 MLX5_SET(modify_cong_params_in, in, opcode, 310 MLX5_CMD_OP_MODIFY_CONG_PARAMS); 311 312 node = mlx5_ib_param_to_node(offset); 313 MLX5_SET(modify_cong_params_in, in, cong_protocol, node); 314 315 field = MLX5_ADDR_OF(modify_cong_params_in, in, congestion_parameters); 316 mlx5_ib_set_cc_param_mask_val(field, offset, var, &attr_mask); 317 318 field = MLX5_ADDR_OF(modify_cong_params_in, in, field_select); 319 MLX5_SET(field_select_r_roce_rp, field, field_select_r_roce_rp, 320 attr_mask); 321 322 err = mlx5_cmd_modify_cong_params(mdev, in, inlen); 323 kvfree(in); 324 alloc_err: 325 mlx5_ib_put_native_port_mdev(dev, port_num + 1); 326 return err; 327 } 328 329 static ssize_t set_param(struct file *filp, const char __user *buf, 330 size_t count, loff_t *pos) 331 { 332 struct mlx5_ib_dbg_param *param = filp->private_data; 333 int offset = param->offset; 334 char lbuf[11] = { }; 335 u32 var; 336 int ret; 337 338 if (count > sizeof(lbuf)) 339 return -EINVAL; 340 341 if (copy_from_user(lbuf, buf, count)) 342 return -EFAULT; 343 344 lbuf[sizeof(lbuf) - 1] = '\0'; 345 346 if (kstrtou32(lbuf, 0, &var)) 347 return -EINVAL; 348 349 ret = mlx5_ib_set_cc_params(param->dev, param->port_num, offset, var); 350 return ret ? ret : count; 351 } 352 353 static ssize_t get_param(struct file *filp, char __user *buf, size_t count, 354 loff_t *pos) 355 { 356 struct mlx5_ib_dbg_param *param = filp->private_data; 357 int offset = param->offset; 358 u32 var = 0; 359 int ret; 360 char lbuf[11]; 361 362 if (*pos) 363 return 0; 364 365 ret = mlx5_ib_get_cc_params(param->dev, param->port_num, offset, &var); 366 if (ret) 367 return ret; 368 369 ret = snprintf(lbuf, sizeof(lbuf), "%d\n", var); 370 if (ret < 0) 371 return ret; 372 373 if (copy_to_user(buf, lbuf, ret)) 374 return -EFAULT; 375 376 *pos += ret; 377 return ret; 378 } 379 380 static const struct file_operations dbg_cc_fops = { 381 .owner = THIS_MODULE, 382 .open = simple_open, 383 .write = set_param, 384 .read = get_param, 385 }; 386 387 void mlx5_ib_cleanup_cong_debugfs(struct mlx5_ib_dev *dev, u8 port_num) 388 { 389 if (!mlx5_debugfs_root || 390 !dev->port[port_num].dbg_cc_params || 391 !dev->port[port_num].dbg_cc_params->root) 392 return; 393 394 debugfs_remove_recursive(dev->port[port_num].dbg_cc_params->root); 395 kfree(dev->port[port_num].dbg_cc_params); 396 dev->port[port_num].dbg_cc_params = NULL; 397 } 398 399 int mlx5_ib_init_cong_debugfs(struct mlx5_ib_dev *dev, u8 port_num) 400 { 401 struct mlx5_ib_dbg_cc_params *dbg_cc_params; 402 struct mlx5_core_dev *mdev; 403 int i; 404 405 if (!mlx5_debugfs_root) 406 goto out; 407 408 /* Takes a 1-based port number */ 409 mdev = mlx5_ib_get_native_port_mdev(dev, port_num + 1, NULL); 410 if (!mdev) 411 goto out; 412 413 if (!MLX5_CAP_GEN(mdev, cc_query_allowed) || 414 !MLX5_CAP_GEN(mdev, cc_modify_allowed)) 415 goto put_mdev; 416 417 dbg_cc_params = kzalloc(sizeof(*dbg_cc_params), GFP_KERNEL); 418 if (!dbg_cc_params) 419 goto err; 420 421 dev->port[port_num].dbg_cc_params = dbg_cc_params; 422 423 dbg_cc_params->root = debugfs_create_dir("cc_params", 424 mdev->priv.dbg_root); 425 if (!dbg_cc_params->root) 426 goto err; 427 428 for (i = 0; i < MLX5_IB_DBG_CC_MAX; i++) { 429 dbg_cc_params->params[i].offset = i; 430 dbg_cc_params->params[i].dev = dev; 431 dbg_cc_params->params[i].port_num = port_num; 432 dbg_cc_params->params[i].dentry = 433 debugfs_create_file(mlx5_ib_dbg_cc_name[i], 434 0600, dbg_cc_params->root, 435 &dbg_cc_params->params[i], 436 &dbg_cc_fops); 437 if (!dbg_cc_params->params[i].dentry) 438 goto err; 439 } 440 441 put_mdev: 442 mlx5_ib_put_native_port_mdev(dev, port_num + 1); 443 out: 444 return 0; 445 446 err: 447 mlx5_ib_warn(dev, "cong debugfs failure\n"); 448 mlx5_ib_cleanup_cong_debugfs(dev, port_num); 449 mlx5_ib_put_native_port_mdev(dev, port_num + 1); 450 451 /* 452 * We don't want to fail driver if debugfs failed to initialize, 453 * so we are not forwarding error to the user. 454 */ 455 return 0; 456 } 457