xref: /linux/drivers/infiniband/hw/hns/hns_roce_debugfs.c (revision 1fc5a74b108fc90951890ec513ac81869f5eaff1)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2023 Hisilicon Limited.
4  */
5 
6 #include <linux/cleanup.h>
7 #include <linux/debugfs.h>
8 #include <linux/device.h>
9 #include <linux/pci.h>
10 
11 #include "hns_roce_device.h"
12 #include "hns_roce_hw_v2.h"
13 
14 static struct dentry *hns_roce_dbgfs_root;
15 
hns_debugfs_seqfile_open(struct inode * inode,struct file * f)16 static int hns_debugfs_seqfile_open(struct inode *inode, struct file *f)
17 {
18 	struct hns_debugfs_seqfile *seqfile = inode->i_private;
19 
20 	return single_open(f, seqfile->read, seqfile->data);
21 }
22 
hns_debugfs_seqfile_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)23 static ssize_t hns_debugfs_seqfile_write(struct file *file,
24 					 const char __user *buffer,
25 					 size_t count, loff_t *ppos)
26 {
27 	struct hns_debugfs_seqfile *seqfile = file_inode(file)->i_private;
28 	char buf[16] = {};
29 
30 	if (!seqfile->write)
31 		return -EOPNOTSUPP;
32 
33 	if (count >= sizeof(buf))
34 		return -EINVAL;
35 
36 	if (copy_from_user(buf, buffer, count))
37 		return -EFAULT;
38 
39 	return seqfile->write(buf, count, seqfile->data);
40 }
41 
42 static const struct file_operations hns_debugfs_seqfile_fops = {
43 	.owner = THIS_MODULE,
44 	.open = hns_debugfs_seqfile_open,
45 	.release = single_release,
46 	.read = seq_read,
47 	.write = hns_debugfs_seqfile_write,
48 	.llseek = seq_lseek
49 };
50 
51 static const char * const sw_stat_info[] = {
52 	[HNS_ROCE_DFX_AEQE_CNT] = "aeqe",
53 	[HNS_ROCE_DFX_CEQE_CNT] = "ceqe",
54 	[HNS_ROCE_DFX_CMDS_CNT] = "cmds",
55 	[HNS_ROCE_DFX_CMDS_ERR_CNT] = "cmds_err",
56 	[HNS_ROCE_DFX_MBX_POSTED_CNT] = "posted_mbx",
57 	[HNS_ROCE_DFX_MBX_POLLED_CNT] = "polled_mbx",
58 	[HNS_ROCE_DFX_MBX_EVENT_CNT] = "mbx_event",
59 	[HNS_ROCE_DFX_QP_CREATE_ERR_CNT] = "qp_create_err",
60 	[HNS_ROCE_DFX_QP_MODIFY_ERR_CNT] = "qp_modify_err",
61 	[HNS_ROCE_DFX_CQ_CREATE_ERR_CNT] = "cq_create_err",
62 	[HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT] = "cq_modify_err",
63 	[HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT] = "srq_create_err",
64 	[HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT] = "srq_modify_err",
65 	[HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT] = "xrcd_alloc_err",
66 	[HNS_ROCE_DFX_MR_REG_ERR_CNT] = "mr_reg_err",
67 	[HNS_ROCE_DFX_MR_REREG_ERR_CNT] = "mr_rereg_err",
68 	[HNS_ROCE_DFX_AH_CREATE_ERR_CNT] = "ah_create_err",
69 	[HNS_ROCE_DFX_MMAP_ERR_CNT] = "mmap_err",
70 	[HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT] = "uctx_alloc_err",
71 };
72 
sw_stat_debugfs_show(struct seq_file * file,void * offset)73 static int sw_stat_debugfs_show(struct seq_file *file, void *offset)
74 {
75 	struct hns_roce_dev *hr_dev = file->private;
76 	int i;
77 
78 	for (i = 0; i < HNS_ROCE_DFX_CNT_TOTAL; i++)
79 		seq_printf(file, "%-20s --- %lld\n", sw_stat_info[i],
80 			   atomic64_read(&hr_dev->dfx_cnt[i]));
81 
82 	return 0;
83 }
84 
create_sw_stat_debugfs(struct hns_roce_dev * hr_dev,struct dentry * parent)85 static void create_sw_stat_debugfs(struct hns_roce_dev *hr_dev,
86 				   struct dentry *parent)
87 {
88 	struct hns_sw_stat_debugfs *dbgfs = &hr_dev->dbgfs.sw_stat_root;
89 
90 	dbgfs->sw_stat.read = sw_stat_debugfs_show;
91 	dbgfs->sw_stat.data = hr_dev;
92 
93 	dbgfs->root = debugfs_create_dir("sw_stat", parent);
94 	debugfs_create_file("sw_stat", 0400, dbgfs->root, &dbgfs->sw_stat,
95 			    &hns_debugfs_seqfile_fops);
96 }
97 
98 #define __HNS_SCC_ATTR(_name, _type, _offset, _size, _min, _max) {	\
99 	.name = _name,							\
100 	.algo_type = _type,						\
101 	.offset = _offset,						\
102 	.size = _size,							\
103 	.min = _min,							\
104 	.max = _max,							\
105 }
106 
107 #define HNS_DCQCN_CC_ATTR_RW(_name, NAME)				\
108 	__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_DCQCN,			\
109 			HNS_ROCE_DCQCN_##NAME##_OFS,			\
110 			HNS_ROCE_DCQCN_##NAME##_SZ,			\
111 			0, HNS_ROCE_DCQCN_##NAME##_MAX)
112 
113 #define HNS_LDCP_CC_ATTR_RW(_name, NAME)				\
114 	__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_LDCP,			\
115 			HNS_ROCE_LDCP_##NAME##_OFS,			\
116 			HNS_ROCE_LDCP_##NAME##_SZ,			\
117 			0, HNS_ROCE_LDCP_##NAME##_MAX)
118 
119 #define HNS_HC3_CC_ATTR_RW(_name, NAME)				\
120 	__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_HC3,			\
121 			HNS_ROCE_HC3_##NAME##_OFS,			\
122 			HNS_ROCE_HC3_##NAME##_SZ,			\
123 			HNS_ROCE_HC3_##NAME##_MIN,			\
124 			HNS_ROCE_HC3_##NAME##_MAX)
125 
126 #define HNS_DIP_CC_ATTR_RW(_name, NAME)				\
127 	__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_DIP,			\
128 			HNS_ROCE_DIP_##NAME##_OFS,			\
129 			HNS_ROCE_DIP_##NAME##_SZ,			\
130 			0, HNS_ROCE_DIP_##NAME##_MAX)
131 
132 static const struct hns_roce_cong_attr {
133 	enum hns_roce_cong_type cong_type;
134 	const char *name;
135 	struct hns_roce_cc_param_attr params[HNS_ROCE_CC_PARAM_MAX_NUM];
136 } cong_attrs[] = {
137 	{ CONG_TYPE_DCQCN, "dcqcn_cc_param",
138 		{
139 			HNS_DCQCN_CC_ATTR_RW("ai", AI),
140 			HNS_DCQCN_CC_ATTR_RW("f", F),
141 			HNS_DCQCN_CC_ATTR_RW("tkp", TKP),
142 			HNS_DCQCN_CC_ATTR_RW("tmp", TMP),
143 			HNS_DCQCN_CC_ATTR_RW("alp", ALP),
144 			HNS_DCQCN_CC_ATTR_RW("max_speed", MAX_SPEED),
145 			HNS_DCQCN_CC_ATTR_RW("g", G),
146 			HNS_DCQCN_CC_ATTR_RW("al", AL),
147 			HNS_DCQCN_CC_ATTR_RW("cnp_time", CNP_TIME),
148 			HNS_DCQCN_CC_ATTR_RW("ashift", ASHIFT),
149 		}
150 	},
151 	{ CONG_TYPE_LDCP, "ldcp_cc_param",
152 		{
153 			HNS_LDCP_CC_ATTR_RW("cwd0", CWD0),
154 			HNS_LDCP_CC_ATTR_RW("alpha", ALPHA),
155 			HNS_LDCP_CC_ATTR_RW("gamma", GAMMA),
156 			HNS_LDCP_CC_ATTR_RW("beta", BETA),
157 			HNS_LDCP_CC_ATTR_RW("eta", ETA),
158 		}
159 	},
160 	{ CONG_TYPE_HC3, "hc3_cc_param",
161 		{
162 			HNS_HC3_CC_ATTR_RW("initial_window", INITIAL_WINDOW),
163 			HNS_HC3_CC_ATTR_RW("bandwidth", BANDWIDTH),
164 			HNS_HC3_CC_ATTR_RW("qlen_shift", QLEN_SHIFT),
165 			HNS_HC3_CC_ATTR_RW("port_usage_shift", PORT_USAGE_SHIFT),
166 			HNS_HC3_CC_ATTR_RW("over_period", OVER_PERIOD),
167 			HNS_HC3_CC_ATTR_RW("max_stage", MAX_STAGE),
168 			HNS_HC3_CC_ATTR_RW("gamma_shift", GAMMA_SHIFT),
169 		}
170 	},
171 	{ CONG_TYPE_DIP, "dip_cc_param",
172 		{
173 			HNS_DIP_CC_ATTR_RW("ai", AI),
174 			HNS_DIP_CC_ATTR_RW("f", F),
175 			HNS_DIP_CC_ATTR_RW("tkp", TKP),
176 			HNS_DIP_CC_ATTR_RW("tmp", TMP),
177 			HNS_DIP_CC_ATTR_RW("alp", ALP),
178 			HNS_DIP_CC_ATTR_RW("max_speed", MAX_SPEED),
179 			HNS_DIP_CC_ATTR_RW("g", G),
180 			HNS_DIP_CC_ATTR_RW("al", AL),
181 			HNS_DIP_CC_ATTR_RW("cnp_time", CNP_TIME),
182 			HNS_DIP_CC_ATTR_RW("ashift", ASHIFT),
183 		}
184 	}
185 };
186 
cc_param_debugfs_show(struct seq_file * file,void * offset)187 static int cc_param_debugfs_show(struct seq_file *file, void *offset)
188 {
189 	struct hns_cc_param_seqfile *param_seqfile = file->private;
190 	const struct hns_roce_cc_param_attr *param_attr = param_seqfile->param_attr;
191 	int algo_type = param_attr->algo_type;
192 	int index = param_seqfile->index;
193 	struct hns_roce_dev *hr_dev =
194 		container_of(param_seqfile, struct hns_roce_dev,
195 			     dbgfs.cc_param_root[algo_type].params[index]);
196 	struct hns_roce_scc_param *scc_param;
197 	__le32 val = 0;
198 
199 	scc_param = &hr_dev->scc_param[algo_type];
200 
201 	scoped_guard(mutex, &scc_param->scc_mutex) {
202 		memcpy(&val,
203 		       (void *)scc_param->param + param_attr->offset,
204 		       param_attr->size);
205 	}
206 
207 	seq_printf(file, "%u\n", le32_to_cpu(val));
208 
209 	return 0;
210 }
211 
cc_param_debugfs_store(char * buf,size_t count,void * data)212 static ssize_t cc_param_debugfs_store(char *buf, size_t count, void *data)
213 {
214 	struct hns_cc_param_seqfile *param_seqfile = data;
215 	const struct hns_roce_cc_param_attr *param_attr = param_seqfile->param_attr;
216 	int algo_type = param_attr->algo_type;
217 	int index = param_seqfile->index;
218 	struct hns_roce_dev *hr_dev =
219 		container_of(param_seqfile, struct hns_roce_dev,
220 			     dbgfs.cc_param_root[algo_type].params[index]);
221 	struct hns_roce_scc_param *scc_param;
222 	__le32 attr_val, old_val = 0;
223 	u32 val;
224 	int ret;
225 
226 	if (kstrtou32(buf, 0, &val))
227 		return -EINVAL;
228 
229 	if (val > param_attr->max || val < param_attr->min)
230 		return -EINVAL;
231 
232 	attr_val = cpu_to_le32(val);
233 	scc_param = &hr_dev->scc_param[algo_type];
234 	guard(mutex)(&scc_param->scc_mutex);
235 
236 	memcpy(&old_val, (void *)scc_param->param + param_attr->offset,
237 	       param_attr->size);
238 	memcpy((void *)scc_param->param + param_attr->offset, &attr_val,
239 	       param_attr->size);
240 
241 	ret = hr_dev->hw->config_scc_param(hr_dev, algo_type);
242 	if (ret) {
243 		memcpy((void *)scc_param->param + param_attr->offset, &old_val,
244 		       param_attr->size);
245 		return ret;
246 	}
247 
248 	return count;
249 }
250 
get_default_scc_param(struct hns_roce_dev * hr_dev)251 static void get_default_scc_param(struct hns_roce_dev *hr_dev)
252 {
253 	int ret;
254 	int i;
255 
256 	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
257 		ret = hr_dev->hw->query_scc_param(hr_dev, i);
258 		if (ret && ret != -EOPNOTSUPP)
259 			ibdev_warn_ratelimited(&hr_dev->ib_dev,
260 					       "failed to get default parameters of scc algo %d, ret = %d.\n",
261 					       i, ret);
262 	}
263 }
264 
hns_roce_alloc_scc_param(struct hns_roce_dev * hr_dev)265 static int hns_roce_alloc_scc_param(struct hns_roce_dev *hr_dev)
266 {
267 	struct hns_roce_scc_param *scc_param;
268 	int i;
269 
270 	scc_param = kvzalloc_objs(*scc_param, HNS_ROCE_SCC_ALGO_TOTAL);
271 	if (!scc_param)
272 		return -ENOMEM;
273 
274 	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
275 		scc_param[i].algo_type = i;
276 		scc_param[i].hr_dev = hr_dev;
277 		mutex_init(&scc_param[i].scc_mutex);
278 	}
279 
280 	hr_dev->scc_param = scc_param;
281 
282 	get_default_scc_param(hr_dev);
283 
284 	return 0;
285 }
286 
hns_roce_dealloc_scc_param(struct hns_roce_dev * hr_dev)287 static void hns_roce_dealloc_scc_param(struct hns_roce_dev *hr_dev)
288 {
289 	int i;
290 
291 	if (!hr_dev->scc_param)
292 		return;
293 
294 	for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++)
295 		mutex_destroy(&hr_dev->scc_param[i].scc_mutex);
296 
297 	kvfree(hr_dev->scc_param);
298 }
299 
create_cc_param_debugfs(struct hns_roce_dev * hr_dev,struct dentry * parent)300 static void create_cc_param_debugfs(struct hns_roce_dev *hr_dev,
301 				    struct dentry *parent)
302 {
303 	const struct hns_roce_cong_attr *cong_attr;
304 	struct hns_cc_param_debugfs *dbgfs;
305 	int i, j;
306 	int ret;
307 
308 	if (hr_dev->pci_dev->revision <= PCI_REVISION_ID_HIP08 ||
309 	    !(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL) ||
310 	    hr_dev->is_vf)
311 		return;
312 
313 	ret = hns_roce_alloc_scc_param(hr_dev);
314 	if (ret)
315 		return;
316 
317 	for (i = 0; i < CONG_TYPE_MAX_NUM; i++) {
318 		cong_attr = &cong_attrs[i];
319 		if (!test_bit(cong_attr->cong_type,
320 			      (unsigned long *)&hr_dev->caps.cong_cap))
321 			continue;
322 
323 		dbgfs = &hr_dev->dbgfs.cc_param_root[i];
324 		dbgfs->root = debugfs_create_dir(cong_attr->name, parent);
325 		for (j = 0; j < HNS_ROCE_CC_PARAM_MAX_NUM; j++) {
326 			if (!cong_attr->params[j].name)
327 				break;
328 			dbgfs->params[j].param_attr = &cong_attr->params[j];
329 			dbgfs->params[j].index = j;
330 			dbgfs->params[j].seqfile.read = cc_param_debugfs_show;
331 			dbgfs->params[j].seqfile.write = cc_param_debugfs_store;
332 			dbgfs->params[j].seqfile.data = &dbgfs->params[j];
333 			debugfs_create_file(cong_attr->params[j].name, 0600,
334 					    dbgfs->root,
335 					    &dbgfs->params[j].seqfile,
336 					    &hns_debugfs_seqfile_fops);
337 		}
338 	}
339 }
340 
341 /* debugfs for device */
hns_roce_register_debugfs(struct hns_roce_dev * hr_dev)342 void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev)
343 {
344 	struct hns_roce_dev_debugfs *dbgfs = &hr_dev->dbgfs;
345 
346 	dbgfs->root = debugfs_create_dir(pci_name(hr_dev->pci_dev),
347 					 hns_roce_dbgfs_root);
348 
349 	create_sw_stat_debugfs(hr_dev, dbgfs->root);
350 	create_cc_param_debugfs(hr_dev, dbgfs->root);
351 }
352 
hns_roce_unregister_debugfs(struct hns_roce_dev * hr_dev)353 void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev)
354 {
355 	debugfs_remove_recursive(hr_dev->dbgfs.root);
356 	hns_roce_dealloc_scc_param(hr_dev);
357 }
358 
359 /* debugfs for hns module */
hns_roce_init_debugfs(void)360 void hns_roce_init_debugfs(void)
361 {
362 	hns_roce_dbgfs_root = debugfs_create_dir("hns_roce", NULL);
363 }
364 
hns_roce_cleanup_debugfs(void)365 void hns_roce_cleanup_debugfs(void)
366 {
367 	debugfs_remove_recursive(hns_roce_dbgfs_root);
368 	hns_roce_dbgfs_root = NULL;
369 }
370