xref: /linux/drivers/infiniband/hw/bnxt_re/debugfs.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
2 /*
3  * Copyright (c) 2024, Broadcom. All rights reserved.  The term
4  * Broadcom refers to Broadcom Limited and/or its subsidiaries.
5  *
6  * Description: Debugfs component of the bnxt_re driver
7  */
8 
9 #include <linux/debugfs.h>
10 #include <linux/pci.h>
11 #include <linux/seq_file.h>
12 #include <rdma/ib_addr.h>
13 #include <linux/bnxt/ulp.h>
14 
15 #include "roce_hsi.h"
16 #include "qplib_res.h"
17 #include "qplib_sp.h"
18 #include "qplib_fp.h"
19 #include "qplib_rcfw.h"
20 #include "bnxt_re.h"
21 #include "ib_verbs.h"
22 #include "debugfs.h"
23 
24 static struct dentry *bnxt_re_debugfs_root;
25 
26 static const char * const bnxt_re_cq_coal_str[] = {
27 	"buf_maxtime",
28 	"normal_maxbuf",
29 	"during_maxbuf",
30 	"en_ring_idle_mode",
31 	"enable",
32 };
33 
34 static const char * const bnxt_re_cc_gen0_name[] = {
35 	"enable_cc",
36 	"run_avg_weight_g",
37 	"num_phase_per_state",
38 	"init_cr",
39 	"init_tr",
40 	"tos_ecn",
41 	"tos_dscp",
42 	"alt_vlan_pcp",
43 	"alt_vlan_dscp",
44 	"rtt",
45 	"cc_mode",
46 	"tcp_cp",
47 	"tx_queue",
48 	"inactivity_cp",
49 };
50 
51 static inline const char *bnxt_re_qp_state_str(u8 state)
52 {
53 	switch (state) {
54 	case CMDQ_MODIFY_QP_NEW_STATE_RESET:
55 		return "RST";
56 	case CMDQ_MODIFY_QP_NEW_STATE_INIT:
57 		return "INIT";
58 	case CMDQ_MODIFY_QP_NEW_STATE_RTR:
59 		return "RTR";
60 	case CMDQ_MODIFY_QP_NEW_STATE_RTS:
61 		return "RTS";
62 	case CMDQ_MODIFY_QP_NEW_STATE_SQE:
63 		return "SQER";
64 	case CMDQ_MODIFY_QP_NEW_STATE_SQD:
65 		return "SQD";
66 	case CMDQ_MODIFY_QP_NEW_STATE_ERR:
67 		return "ERR";
68 	default:
69 		return "Invalid QP state";
70 	}
71 }
72 
73 static inline const char *bnxt_re_qp_type_str(u8 type)
74 {
75 	switch (type) {
76 	case CMDQ_CREATE_QP1_TYPE_GSI: return "QP1";
77 	case CMDQ_CREATE_QP_TYPE_GSI: return "QP1";
78 	case CMDQ_CREATE_QP_TYPE_RC: return "RC";
79 	case CMDQ_CREATE_QP_TYPE_UD: return "UD";
80 	case CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE: return "RAW_ETHERTYPE";
81 	default: return "Invalid transport type";
82 	}
83 }
84 
85 static ssize_t qp_info_read(struct file *filep,
86 			    char __user *buffer,
87 			    size_t count, loff_t *ppos)
88 {
89 	struct bnxt_re_qp *qp = filep->private_data;
90 	struct bnxt_qplib_qp *qplib_qp;
91 	u32 rate_limit = 0;
92 	char *buf;
93 	int len;
94 
95 	if (*ppos)
96 		return 0;
97 
98 	qplib_qp = &qp->qplib_qp;
99 	if (qplib_qp->shaper_allocation_status)
100 		rate_limit = qplib_qp->rate_limit;
101 
102 	buf = kasprintf(GFP_KERNEL,
103 			"QPN\t\t: %d\n"
104 			"transport\t: %s\n"
105 			"state\t\t: %s\n"
106 			"mtu\t\t: %d\n"
107 			"timeout\t\t: %d\n"
108 			"remote QPN\t: %d\n"
109 			"shaper allocated : %d\n"
110 			"rate limit\t: %d kbps\n",
111 			qp->qplib_qp.id,
112 			bnxt_re_qp_type_str(qp->qplib_qp.type),
113 			bnxt_re_qp_state_str(qp->qplib_qp.state),
114 			qp->qplib_qp.mtu,
115 			qp->qplib_qp.timeout,
116 			qp->qplib_qp.dest_qpn,
117 			qplib_qp->shaper_allocation_status,
118 			rate_limit);
119 	if (!buf)
120 		return -ENOMEM;
121 	if (count < strlen(buf)) {
122 		kfree(buf);
123 		return -ENOSPC;
124 	}
125 	len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
126 	kfree(buf);
127 	return len;
128 }
129 
130 static const struct file_operations debugfs_qp_fops = {
131 	.owner = THIS_MODULE,
132 	.open = simple_open,
133 	.read = qp_info_read,
134 };
135 
136 void bnxt_re_debug_add_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp)
137 {
138 	char resn[32];
139 
140 	sprintf(resn, "0x%x", qp->qplib_qp.id);
141 	qp->dentry = debugfs_create_file(resn, 0400, rdev->qp_debugfs, qp, &debugfs_qp_fops);
142 }
143 
144 void bnxt_re_debug_rem_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp)
145 {
146 	debugfs_remove(qp->dentry);
147 }
148 
149 static int map_cc_config_offset_gen0_ext0(u32 offset, struct bnxt_qplib_cc_param *ccparam, u32 *val)
150 {
151 	u64 map_offset;
152 
153 	map_offset = BIT(offset);
154 
155 	switch (map_offset) {
156 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC:
157 		*val = ccparam->enable;
158 		break;
159 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G:
160 		*val = ccparam->g;
161 		break;
162 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE:
163 		*val = ccparam->nph_per_state;
164 		break;
165 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR:
166 		*val = ccparam->init_cr;
167 		break;
168 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR:
169 		*val = ccparam->init_tr;
170 		break;
171 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN:
172 		*val = ccparam->tos_ecn;
173 		break;
174 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP:
175 		*val =  ccparam->tos_dscp;
176 		break;
177 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP:
178 		*val = ccparam->alt_vlan_pcp;
179 		break;
180 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP:
181 		*val = ccparam->alt_tos_dscp;
182 		break;
183 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT:
184 	       *val = ccparam->rtt;
185 		break;
186 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE:
187 		*val = ccparam->cc_mode;
188 		break;
189 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP:
190 		*val =  ccparam->tcp_cp;
191 		break;
192 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP:
193 		*val = ccparam->inact_th;
194 		break;
195 	default:
196 		return -EINVAL;
197 	}
198 
199 	return 0;
200 }
201 
202 static ssize_t bnxt_re_cc_config_get(struct file *filp, char __user *buffer,
203 				     size_t usr_buf_len, loff_t *ppos)
204 {
205 	struct bnxt_re_cc_param *dbg_cc_param = filp->private_data;
206 	struct bnxt_re_dev *rdev = dbg_cc_param->rdev;
207 	struct bnxt_qplib_cc_param ccparam = {};
208 	u32 offset = dbg_cc_param->offset;
209 	char buf[16];
210 	u32 val;
211 	int rc;
212 
213 	rc = bnxt_qplib_query_cc_param(&rdev->qplib_res, &ccparam);
214 	if (rc)
215 		return rc;
216 
217 	rc = map_cc_config_offset_gen0_ext0(offset, &ccparam, &val);
218 	if (rc)
219 		return rc;
220 
221 	rc = snprintf(buf, sizeof(buf), "%d\n", val);
222 	if (rc < 0)
223 		return rc;
224 
225 	return simple_read_from_buffer(buffer, usr_buf_len, ppos, (u8 *)(buf), rc);
226 }
227 
228 static int bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offset, u32 val)
229 {
230 	u32 modify_mask;
231 
232 	modify_mask = BIT(offset);
233 
234 	switch (modify_mask) {
235 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC:
236 		ccparam->enable = val;
237 		break;
238 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G:
239 		ccparam->g = val;
240 		break;
241 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE:
242 		ccparam->nph_per_state = val;
243 		break;
244 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR:
245 		ccparam->init_cr = val;
246 		break;
247 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR:
248 		ccparam->init_tr = val;
249 		break;
250 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN:
251 		ccparam->tos_ecn = val;
252 		break;
253 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP:
254 		ccparam->tos_dscp = val;
255 		break;
256 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP:
257 		ccparam->alt_vlan_pcp = val;
258 		break;
259 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP:
260 		ccparam->alt_tos_dscp = val;
261 		break;
262 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT:
263 		ccparam->rtt = val;
264 		break;
265 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE:
266 		ccparam->cc_mode = val;
267 		break;
268 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP:
269 		ccparam->tcp_cp = val;
270 		break;
271 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TX_QUEUE:
272 		return -EOPNOTSUPP;
273 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP:
274 		ccparam->inact_th = val;
275 		break;
276 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TIME_PER_PHASE:
277 		ccparam->time_pph = val;
278 		break;
279 	case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_PKTS_PER_PHASE:
280 		ccparam->pkts_pph = val;
281 		break;
282 	}
283 
284 	ccparam->mask = modify_mask;
285 	return 0;
286 }
287 
288 static int bnxt_re_configure_cc(struct bnxt_re_dev *rdev, u32 gen_ext, u32 offset, u32 val)
289 {
290 	struct bnxt_qplib_cc_param ccparam = { };
291 	int rc;
292 
293 	if (gen_ext != CC_CONFIG_GEN0_EXT0)
294 		return -EOPNOTSUPP;
295 
296 	rc = bnxt_re_fill_gen0_ext0(&ccparam, offset, val);
297 	if (rc)
298 		return rc;
299 
300 	bnxt_qplib_modify_cc(&rdev->qplib_res, &ccparam);
301 	return 0;
302 }
303 
304 static ssize_t bnxt_re_cc_config_set(struct file *filp, const char __user *buffer,
305 				     size_t count, loff_t *ppos)
306 {
307 	struct bnxt_re_cc_param *dbg_cc_param = filp->private_data;
308 	struct bnxt_re_dev *rdev = dbg_cc_param->rdev;
309 	u32 offset = dbg_cc_param->offset;
310 	u8 cc_gen = dbg_cc_param->cc_gen;
311 	u32 val;
312 	int rc;
313 
314 	rc = kstrtou32_from_user(buffer, count, 0, &val);
315 	if (!rc)
316 		rc = bnxt_re_configure_cc(rdev, cc_gen, offset, val);
317 	return rc ? rc : count;
318 }
319 
320 static const struct file_operations bnxt_re_cc_config_ops = {
321 	.owner = THIS_MODULE,
322 	.open = simple_open,
323 	.read = bnxt_re_cc_config_get,
324 	.write = bnxt_re_cc_config_set,
325 };
326 
327 static int info_show(struct seq_file *m, void *unused)
328 {
329 	struct bnxt_re_dev *rdev = m->private;
330 	struct bnxt_re_res_cntrs *res_s = &rdev->stats.res;
331 
332 	seq_puts(m, "Info:\n");
333 	seq_printf(m, "Device Name\t\t: %s\n", dev_name(&rdev->ibdev.dev));
334 	seq_printf(m, "PD Watermark\t\t: %llu\n", res_s->pd_watermark);
335 	seq_printf(m, "AH Watermark\t\t: %llu\n", res_s->ah_watermark);
336 	seq_printf(m, "QP Watermark\t\t: %llu\n", res_s->qp_watermark);
337 	seq_printf(m, "RC QP Watermark\t\t: %llu\n", res_s->rc_qp_watermark);
338 	seq_printf(m, "UD QP Watermark\t\t: %llu\n", res_s->ud_qp_watermark);
339 	seq_printf(m, "SRQ Watermark\t\t: %llu\n", res_s->srq_watermark);
340 	seq_printf(m, "CQ Watermark\t\t: %llu\n", res_s->cq_watermark);
341 	seq_printf(m, "MR Watermark\t\t: %llu\n", res_s->mr_watermark);
342 	seq_printf(m, "MW Watermark\t\t: %llu\n", res_s->mw_watermark);
343 	seq_printf(m, "CQ Resize Count\t\t: %d\n", atomic_read(&res_s->resize_count));
344 	if (rdev->pacing.dbr_pacing) {
345 		seq_printf(m, "DB Pacing Reschedule\t: %llu\n", rdev->stats.pacing.resched);
346 		seq_printf(m, "DB Pacing Complete\t: %llu\n", rdev->stats.pacing.complete);
347 		seq_printf(m, "DB Pacing Alerts\t: %llu\n", rdev->stats.pacing.alerts);
348 		seq_printf(m, "DB FIFO Register\t: 0x%x\n",
349 			   readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off));
350 	}
351 
352 	return 0;
353 }
354 DEFINE_SHOW_ATTRIBUTE(info);
355 
356 static void bnxt_re_debugfs_add_info(struct bnxt_re_dev *rdev)
357 {
358 	debugfs_create_file("info", 0400, rdev->dbg_root, rdev, &info_fops);
359 }
360 
361 static ssize_t cq_coal_cfg_write(struct file *file,
362 				 const char __user *buf,
363 				 size_t count, loff_t *pos)
364 {
365 	struct seq_file *s = file->private_data;
366 	struct bnxt_re_cq_coal_param *param = s->private;
367 	struct bnxt_re_dev *rdev = param->rdev;
368 	int ret, offset = param->offset;
369 	u32 val;
370 
371 	ret = kstrtou32_from_user(buf, count, 0, &val);
372 	if (ret)
373 		return ret;
374 
375 	switch (offset) {
376 	case BNXT_RE_COAL_CQ_BUF_MAXTIME:
377 		if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_BUF_MAXTIME)
378 			return -EINVAL;
379 		rdev->cq_coalescing.buf_maxtime = val;
380 		break;
381 	case BNXT_RE_COAL_CQ_NORMAL_MAXBUF:
382 		if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_NORMAL_MAXBUF)
383 			return -EINVAL;
384 		rdev->cq_coalescing.normal_maxbuf = val;
385 		break;
386 	case BNXT_RE_COAL_CQ_DURING_MAXBUF:
387 		if (val < 1 || val > BNXT_QPLIB_CQ_COAL_MAX_DURING_MAXBUF)
388 			return -EINVAL;
389 		rdev->cq_coalescing.during_maxbuf = val;
390 		break;
391 	case BNXT_RE_COAL_CQ_EN_RING_IDLE_MODE:
392 		if (val > BNXT_QPLIB_CQ_COAL_MAX_EN_RING_IDLE_MODE)
393 			return -EINVAL;
394 		rdev->cq_coalescing.en_ring_idle_mode = val;
395 		break;
396 	case BNXT_RE_COAL_CQ_ENABLE:
397 		if (val > 1)
398 			return -EINVAL;
399 		rdev->cq_coalescing.enable = val;
400 		break;
401 	default:
402 		return -EINVAL;
403 	}
404 	return  count;
405 }
406 
407 static int cq_coal_cfg_show(struct seq_file *s, void *unused)
408 {
409 	struct bnxt_re_cq_coal_param *param = s->private;
410 	struct bnxt_re_dev *rdev = param->rdev;
411 	int offset = param->offset;
412 	u32 val = 0;
413 
414 	switch (offset) {
415 	case BNXT_RE_COAL_CQ_BUF_MAXTIME:
416 		val = rdev->cq_coalescing.buf_maxtime;
417 		break;
418 	case BNXT_RE_COAL_CQ_NORMAL_MAXBUF:
419 		val = rdev->cq_coalescing.normal_maxbuf;
420 		break;
421 	case BNXT_RE_COAL_CQ_DURING_MAXBUF:
422 		val = rdev->cq_coalescing.during_maxbuf;
423 		break;
424 	case BNXT_RE_COAL_CQ_EN_RING_IDLE_MODE:
425 		val = rdev->cq_coalescing.en_ring_idle_mode;
426 		break;
427 	case BNXT_RE_COAL_CQ_ENABLE:
428 		val = rdev->cq_coalescing.enable;
429 		break;
430 	default:
431 		return -EINVAL;
432 	}
433 
434 	seq_printf(s, "%u\n", val);
435 	return 0;
436 }
437 DEFINE_SHOW_STORE_ATTRIBUTE(cq_coal_cfg);
438 
439 static void bnxt_re_cleanup_cq_coal_debugfs(struct bnxt_re_dev *rdev)
440 {
441 	debugfs_remove_recursive(rdev->cq_coal_cfg);
442 	kfree(rdev->cq_coal_cfg_params);
443 }
444 
445 static void bnxt_re_init_cq_coal_debugfs(struct bnxt_re_dev *rdev)
446 {
447 	struct bnxt_re_dbg_cq_coal_params *dbg_cq_coal_params;
448 	int i;
449 
450 	if (!_is_cq_coalescing_supported(rdev->dev_attr->dev_cap_flags2))
451 		return;
452 
453 	dbg_cq_coal_params = kzalloc_obj(*dbg_cq_coal_params);
454 	if (!dbg_cq_coal_params)
455 		return;
456 
457 	rdev->cq_coal_cfg = debugfs_create_dir("cq_coal_cfg", rdev->dbg_root);
458 	rdev->cq_coal_cfg_params = dbg_cq_coal_params;
459 
460 	for (i = 0; i < BNXT_RE_COAL_CQ_MAX; i++) {
461 		dbg_cq_coal_params->params[i].offset = i;
462 		dbg_cq_coal_params->params[i].rdev = rdev;
463 		debugfs_create_file(bnxt_re_cq_coal_str[i],
464 				    0600, rdev->cq_coal_cfg,
465 				    &dbg_cq_coal_params->params[i],
466 				    &cq_coal_cfg_fops);
467 	}
468 }
469 
470 void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev)
471 {
472 	struct pci_dev *pdev = rdev->en_dev->pdev;
473 	struct bnxt_re_dbg_cc_config_params *cc_params;
474 	int i;
475 
476 	rdev->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), bnxt_re_debugfs_root);
477 
478 	rdev->qp_debugfs = debugfs_create_dir("QPs", rdev->dbg_root);
479 	rdev->cc_config = debugfs_create_dir("cc_config", rdev->dbg_root);
480 
481 	bnxt_re_debugfs_add_info(rdev);
482 
483 	rdev->cc_config_params = kzalloc_obj(*cc_params);
484 	if (!rdev->cc_config_params)
485 		return;
486 
487 	for (i = 0; i < BNXT_RE_CC_PARAM_GEN0; i++) {
488 		struct bnxt_re_cc_param *tmp_params = &rdev->cc_config_params->gen0_parms[i];
489 
490 		tmp_params->rdev = rdev;
491 		tmp_params->offset = i;
492 		tmp_params->cc_gen = CC_CONFIG_GEN0_EXT0;
493 		tmp_params->dentry = debugfs_create_file(bnxt_re_cc_gen0_name[i], 0400,
494 							 rdev->cc_config, tmp_params,
495 							 &bnxt_re_cc_config_ops);
496 	}
497 
498 	bnxt_re_init_cq_coal_debugfs(rdev);
499 }
500 
501 void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev)
502 {
503 	bnxt_re_cleanup_cq_coal_debugfs(rdev);
504 	debugfs_remove_recursive(rdev->qp_debugfs);
505 	debugfs_remove_recursive(rdev->cc_config);
506 	kfree(rdev->cc_config_params);
507 	debugfs_remove_recursive(rdev->dbg_root);
508 	rdev->dbg_root = NULL;
509 }
510 
511 void bnxt_re_register_debugfs(void)
512 {
513 	bnxt_re_debugfs_root = debugfs_create_dir("bnxt_re", NULL);
514 }
515 
516 void bnxt_re_unregister_debugfs(void)
517 {
518 	debugfs_remove(bnxt_re_debugfs_root);
519 }
520