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