1 /**
2  * IBM Accelerator Family 'GenWQE'
3  *
4  * (C) Copyright IBM Corp. 2013
5  *
6  * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
7  * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
8  * Author: Michael Jung <mijung@gmx.net>
9  * Author: Michael Ruettger <michael@ibmra.de>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License (version 2 only)
13  * as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  */
20 
21 /*
22  * Debugfs interfaces for the GenWQE card. Help to debug potential
23  * problems. Dump internal chip state for debugging and failure
24  * determination.
25  */
26 
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/debugfs.h>
30 #include <linux/seq_file.h>
31 #include <linux/uaccess.h>
32 
33 #include "card_base.h"
34 #include "card_ddcb.h"
35 
36 static void dbg_uidn_show(struct seq_file *s, struct genwqe_reg *regs,
37 			  int entries)
38 {
39 	unsigned int i;
40 	u32 v_hi, v_lo;
41 
42 	for (i = 0; i < entries; i++) {
43 		v_hi = (regs[i].val >> 32) & 0xffffffff;
44 		v_lo = (regs[i].val)       & 0xffffffff;
45 
46 		seq_printf(s, "  0x%08x 0x%08x 0x%08x 0x%08x EXT_ERR_REC\n",
47 			   regs[i].addr, regs[i].idx, v_hi, v_lo);
48 	}
49 }
50 
51 static int curr_dbg_uidn_show(struct seq_file *s, void *unused, int uid)
52 {
53 	struct genwqe_dev *cd = s->private;
54 	int entries;
55 	struct genwqe_reg *regs;
56 
57 	entries = genwqe_ffdc_buff_size(cd, uid);
58 	if (entries < 0)
59 		return -EINVAL;
60 
61 	if (entries == 0)
62 		return 0;
63 
64 	regs = kcalloc(entries, sizeof(*regs), GFP_KERNEL);
65 	if (regs == NULL)
66 		return -ENOMEM;
67 
68 	genwqe_stop_traps(cd); /* halt the traps while dumping data */
69 	genwqe_ffdc_buff_read(cd, uid, regs, entries);
70 	genwqe_start_traps(cd);
71 
72 	dbg_uidn_show(s, regs, entries);
73 	kfree(regs);
74 	return 0;
75 }
76 
77 static int curr_dbg_uid0_show(struct seq_file *s, void *unused)
78 {
79 	return curr_dbg_uidn_show(s, unused, 0);
80 }
81 
82 DEFINE_SHOW_ATTRIBUTE(curr_dbg_uid0);
83 
84 static int curr_dbg_uid1_show(struct seq_file *s, void *unused)
85 {
86 	return curr_dbg_uidn_show(s, unused, 1);
87 }
88 
89 DEFINE_SHOW_ATTRIBUTE(curr_dbg_uid1);
90 
91 static int curr_dbg_uid2_show(struct seq_file *s, void *unused)
92 {
93 	return curr_dbg_uidn_show(s, unused, 2);
94 }
95 
96 DEFINE_SHOW_ATTRIBUTE(curr_dbg_uid2);
97 
98 static int prev_dbg_uidn_show(struct seq_file *s, void *unused, int uid)
99 {
100 	struct genwqe_dev *cd = s->private;
101 
102 	dbg_uidn_show(s, cd->ffdc[uid].regs,  cd->ffdc[uid].entries);
103 	return 0;
104 }
105 
106 static int prev_dbg_uid0_show(struct seq_file *s, void *unused)
107 {
108 	return prev_dbg_uidn_show(s, unused, 0);
109 }
110 
111 DEFINE_SHOW_ATTRIBUTE(prev_dbg_uid0);
112 
113 static int prev_dbg_uid1_show(struct seq_file *s, void *unused)
114 {
115 	return prev_dbg_uidn_show(s, unused, 1);
116 }
117 
118 DEFINE_SHOW_ATTRIBUTE(prev_dbg_uid1);
119 
120 static int prev_dbg_uid2_show(struct seq_file *s, void *unused)
121 {
122 	return prev_dbg_uidn_show(s, unused, 2);
123 }
124 
125 DEFINE_SHOW_ATTRIBUTE(prev_dbg_uid2);
126 
127 static int curr_regs_show(struct seq_file *s, void *unused)
128 {
129 	struct genwqe_dev *cd = s->private;
130 	unsigned int i;
131 	struct genwqe_reg *regs;
132 
133 	regs = kcalloc(GENWQE_FFDC_REGS, sizeof(*regs), GFP_KERNEL);
134 	if (regs == NULL)
135 		return -ENOMEM;
136 
137 	genwqe_stop_traps(cd);
138 	genwqe_read_ffdc_regs(cd, regs, GENWQE_FFDC_REGS, 1);
139 	genwqe_start_traps(cd);
140 
141 	for (i = 0; i < GENWQE_FFDC_REGS; i++) {
142 		if (regs[i].addr == 0xffffffff)
143 			break;  /* invalid entries */
144 
145 		if (regs[i].val == 0x0ull)
146 			continue;  /* do not print 0x0 FIRs */
147 
148 		seq_printf(s, "  0x%08x 0x%016llx\n",
149 			   regs[i].addr, regs[i].val);
150 	}
151 	return 0;
152 }
153 
154 DEFINE_SHOW_ATTRIBUTE(curr_regs);
155 
156 static int prev_regs_show(struct seq_file *s, void *unused)
157 {
158 	struct genwqe_dev *cd = s->private;
159 	unsigned int i;
160 	struct genwqe_reg *regs = cd->ffdc[GENWQE_DBG_REGS].regs;
161 
162 	if (regs == NULL)
163 		return -EINVAL;
164 
165 	for (i = 0; i < GENWQE_FFDC_REGS; i++) {
166 		if (regs[i].addr == 0xffffffff)
167 			break;  /* invalid entries */
168 
169 		if (regs[i].val == 0x0ull)
170 			continue;  /* do not print 0x0 FIRs */
171 
172 		seq_printf(s, "  0x%08x 0x%016llx\n",
173 			   regs[i].addr, regs[i].val);
174 	}
175 	return 0;
176 }
177 
178 DEFINE_SHOW_ATTRIBUTE(prev_regs);
179 
180 static int jtimer_show(struct seq_file *s, void *unused)
181 {
182 	struct genwqe_dev *cd = s->private;
183 	unsigned int vf_num;
184 	u64 jtimer;
185 
186 	jtimer = genwqe_read_vreg(cd, IO_SLC_VF_APPJOB_TIMEOUT, 0);
187 	seq_printf(s, "  PF   0x%016llx %d msec\n", jtimer,
188 		   GENWQE_PF_JOBTIMEOUT_MSEC);
189 
190 	for (vf_num = 0; vf_num < cd->num_vfs; vf_num++) {
191 		jtimer = genwqe_read_vreg(cd, IO_SLC_VF_APPJOB_TIMEOUT,
192 					  vf_num + 1);
193 		seq_printf(s, "  VF%-2d 0x%016llx %d msec\n", vf_num, jtimer,
194 			   cd->vf_jobtimeout_msec[vf_num]);
195 	}
196 	return 0;
197 }
198 
199 DEFINE_SHOW_ATTRIBUTE(jtimer);
200 
201 static int queue_working_time_show(struct seq_file *s, void *unused)
202 {
203 	struct genwqe_dev *cd = s->private;
204 	unsigned int vf_num;
205 	u64 t;
206 
207 	t = genwqe_read_vreg(cd, IO_SLC_VF_QUEUE_WTIME, 0);
208 	seq_printf(s, "  PF   0x%016llx\n", t);
209 
210 	for (vf_num = 0; vf_num < cd->num_vfs; vf_num++) {
211 		t = genwqe_read_vreg(cd, IO_SLC_VF_QUEUE_WTIME, vf_num + 1);
212 		seq_printf(s, "  VF%-2d 0x%016llx\n", vf_num, t);
213 	}
214 	return 0;
215 }
216 
217 DEFINE_SHOW_ATTRIBUTE(queue_working_time);
218 
219 static int ddcb_info_show(struct seq_file *s, void *unused)
220 {
221 	struct genwqe_dev *cd = s->private;
222 	unsigned int i;
223 	struct ddcb_queue *queue;
224 	struct ddcb *pddcb;
225 
226 	queue = &cd->queue;
227 	seq_puts(s, "DDCB QUEUE:\n");
228 	seq_printf(s, "  ddcb_max:            %d\n"
229 		   "  ddcb_daddr:          %016llx - %016llx\n"
230 		   "  ddcb_vaddr:          %p\n"
231 		   "  ddcbs_in_flight:     %u\n"
232 		   "  ddcbs_max_in_flight: %u\n"
233 		   "  ddcbs_completed:     %u\n"
234 		   "  return_on_busy:      %u\n"
235 		   "  wait_on_busy:        %u\n"
236 		   "  irqs_processed:      %u\n",
237 		   queue->ddcb_max, (long long)queue->ddcb_daddr,
238 		   (long long)queue->ddcb_daddr +
239 		   (queue->ddcb_max * DDCB_LENGTH),
240 		   queue->ddcb_vaddr, queue->ddcbs_in_flight,
241 		   queue->ddcbs_max_in_flight, queue->ddcbs_completed,
242 		   queue->return_on_busy, queue->wait_on_busy,
243 		   cd->irqs_processed);
244 
245 	/* Hardware State */
246 	seq_printf(s, "  0x%08x 0x%016llx IO_QUEUE_CONFIG\n"
247 		   "  0x%08x 0x%016llx IO_QUEUE_STATUS\n"
248 		   "  0x%08x 0x%016llx IO_QUEUE_SEGMENT\n"
249 		   "  0x%08x 0x%016llx IO_QUEUE_INITSQN\n"
250 		   "  0x%08x 0x%016llx IO_QUEUE_WRAP\n"
251 		   "  0x%08x 0x%016llx IO_QUEUE_OFFSET\n"
252 		   "  0x%08x 0x%016llx IO_QUEUE_WTIME\n"
253 		   "  0x%08x 0x%016llx IO_QUEUE_ERRCNTS\n"
254 		   "  0x%08x 0x%016llx IO_QUEUE_LRW\n",
255 		   queue->IO_QUEUE_CONFIG,
256 		   __genwqe_readq(cd, queue->IO_QUEUE_CONFIG),
257 		   queue->IO_QUEUE_STATUS,
258 		   __genwqe_readq(cd, queue->IO_QUEUE_STATUS),
259 		   queue->IO_QUEUE_SEGMENT,
260 		   __genwqe_readq(cd, queue->IO_QUEUE_SEGMENT),
261 		   queue->IO_QUEUE_INITSQN,
262 		   __genwqe_readq(cd, queue->IO_QUEUE_INITSQN),
263 		   queue->IO_QUEUE_WRAP,
264 		   __genwqe_readq(cd, queue->IO_QUEUE_WRAP),
265 		   queue->IO_QUEUE_OFFSET,
266 		   __genwqe_readq(cd, queue->IO_QUEUE_OFFSET),
267 		   queue->IO_QUEUE_WTIME,
268 		   __genwqe_readq(cd, queue->IO_QUEUE_WTIME),
269 		   queue->IO_QUEUE_ERRCNTS,
270 		   __genwqe_readq(cd, queue->IO_QUEUE_ERRCNTS),
271 		   queue->IO_QUEUE_LRW,
272 		   __genwqe_readq(cd, queue->IO_QUEUE_LRW));
273 
274 	seq_printf(s, "DDCB list (ddcb_act=%d/ddcb_next=%d):\n",
275 		   queue->ddcb_act, queue->ddcb_next);
276 
277 	pddcb = queue->ddcb_vaddr;
278 	for (i = 0; i < queue->ddcb_max; i++) {
279 		seq_printf(s, "  %-3d: RETC=%03x SEQ=%04x HSI/SHI=%02x/%02x ",
280 			   i, be16_to_cpu(pddcb->retc_16),
281 			   be16_to_cpu(pddcb->seqnum_16),
282 			   pddcb->hsi, pddcb->shi);
283 		seq_printf(s, "PRIV=%06llx CMD=%02x\n",
284 			   be64_to_cpu(pddcb->priv_64), pddcb->cmd);
285 		pddcb++;
286 	}
287 	return 0;
288 }
289 
290 DEFINE_SHOW_ATTRIBUTE(ddcb_info);
291 
292 static int info_show(struct seq_file *s, void *unused)
293 {
294 	struct genwqe_dev *cd = s->private;
295 	u64 app_id, slu_id, bitstream = -1;
296 	struct pci_dev *pci_dev = cd->pci_dev;
297 
298 	slu_id = __genwqe_readq(cd, IO_SLU_UNITCFG);
299 	app_id = __genwqe_readq(cd, IO_APP_UNITCFG);
300 
301 	if (genwqe_is_privileged(cd))
302 		bitstream = __genwqe_readq(cd, IO_SLU_BITSTREAM);
303 
304 	seq_printf(s, "%s driver version: %s\n"
305 		   "    Device Name/Type: %s %s CardIdx: %d\n"
306 		   "    SLU/APP Config  : 0x%016llx/0x%016llx\n"
307 		   "    Build Date      : %u/%x/%u\n"
308 		   "    Base Clock      : %u MHz\n"
309 		   "    Arch/SVN Release: %u/%llx\n"
310 		   "    Bitstream       : %llx\n",
311 		   GENWQE_DEVNAME, DRV_VERSION, dev_name(&pci_dev->dev),
312 		   genwqe_is_privileged(cd) ?
313 		   "Physical" : "Virtual or no SR-IOV",
314 		   cd->card_idx, slu_id, app_id,
315 		   (u16)((slu_id >> 12) & 0x0fLLU),	   /* month */
316 		   (u16)((slu_id >>  4) & 0xffLLU),	   /* day */
317 		   (u16)((slu_id >> 16) & 0x0fLLU) + 2010, /* year */
318 		   genwqe_base_clock_frequency(cd),
319 		   (u16)((slu_id >> 32) & 0xffLLU), slu_id >> 40,
320 		   bitstream);
321 
322 	return 0;
323 }
324 
325 DEFINE_SHOW_ATTRIBUTE(info);
326 
327 int genwqe_init_debugfs(struct genwqe_dev *cd)
328 {
329 	struct dentry *root;
330 	struct dentry *file;
331 	int ret;
332 	char card_name[64];
333 	char name[64];
334 	unsigned int i;
335 
336 	sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx);
337 
338 	root = debugfs_create_dir(card_name, cd->debugfs_genwqe);
339 	if (!root) {
340 		ret = -ENOMEM;
341 		goto err0;
342 	}
343 
344 	/* non privileged interfaces are done here */
345 	file = debugfs_create_file("ddcb_info", S_IRUGO, root, cd,
346 				   &ddcb_info_fops);
347 	if (!file) {
348 		ret = -ENOMEM;
349 		goto err1;
350 	}
351 
352 	file = debugfs_create_file("info", S_IRUGO, root, cd,
353 				   &info_fops);
354 	if (!file) {
355 		ret = -ENOMEM;
356 		goto err1;
357 	}
358 
359 	file = debugfs_create_x64("err_inject", 0666, root, &cd->err_inject);
360 	if (!file) {
361 		ret = -ENOMEM;
362 		goto err1;
363 	}
364 
365 	file = debugfs_create_u32("ddcb_software_timeout", 0666, root,
366 				  &cd->ddcb_software_timeout);
367 	if (!file) {
368 		ret = -ENOMEM;
369 		goto err1;
370 	}
371 
372 	file = debugfs_create_u32("kill_timeout", 0666, root,
373 				  &cd->kill_timeout);
374 	if (!file) {
375 		ret = -ENOMEM;
376 		goto err1;
377 	}
378 
379 	/* privileged interfaces follow here */
380 	if (!genwqe_is_privileged(cd)) {
381 		cd->debugfs_root = root;
382 		return 0;
383 	}
384 
385 	file = debugfs_create_file("curr_regs", S_IRUGO, root, cd,
386 				   &curr_regs_fops);
387 	if (!file) {
388 		ret = -ENOMEM;
389 		goto err1;
390 	}
391 
392 	file = debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd,
393 				   &curr_dbg_uid0_fops);
394 	if (!file) {
395 		ret = -ENOMEM;
396 		goto err1;
397 	}
398 
399 	file = debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd,
400 				   &curr_dbg_uid1_fops);
401 	if (!file) {
402 		ret = -ENOMEM;
403 		goto err1;
404 	}
405 
406 	file = debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd,
407 				   &curr_dbg_uid2_fops);
408 	if (!file) {
409 		ret = -ENOMEM;
410 		goto err1;
411 	}
412 
413 	file = debugfs_create_file("prev_regs", S_IRUGO, root, cd,
414 				   &prev_regs_fops);
415 	if (!file) {
416 		ret = -ENOMEM;
417 		goto err1;
418 	}
419 
420 	file = debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd,
421 				   &prev_dbg_uid0_fops);
422 	if (!file) {
423 		ret = -ENOMEM;
424 		goto err1;
425 	}
426 
427 	file = debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd,
428 				   &prev_dbg_uid1_fops);
429 	if (!file) {
430 		ret = -ENOMEM;
431 		goto err1;
432 	}
433 
434 	file = debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd,
435 				   &prev_dbg_uid2_fops);
436 	if (!file) {
437 		ret = -ENOMEM;
438 		goto err1;
439 	}
440 
441 	for (i = 0; i <  GENWQE_MAX_VFS; i++) {
442 		sprintf(name, "vf%u_jobtimeout_msec", i);
443 
444 		file = debugfs_create_u32(name, 0666, root,
445 					  &cd->vf_jobtimeout_msec[i]);
446 		if (!file) {
447 			ret = -ENOMEM;
448 			goto err1;
449 		}
450 	}
451 
452 	file = debugfs_create_file("jobtimer", S_IRUGO, root, cd,
453 				   &jtimer_fops);
454 	if (!file) {
455 		ret = -ENOMEM;
456 		goto err1;
457 	}
458 
459 	file = debugfs_create_file("queue_working_time", S_IRUGO, root, cd,
460 				   &queue_working_time_fops);
461 	if (!file) {
462 		ret = -ENOMEM;
463 		goto err1;
464 	}
465 
466 	file = debugfs_create_u32("skip_recovery", 0666, root,
467 				  &cd->skip_recovery);
468 	if (!file) {
469 		ret = -ENOMEM;
470 		goto err1;
471 	}
472 
473 	file = debugfs_create_u32("use_platform_recovery", 0666, root,
474 				  &cd->use_platform_recovery);
475 	if (!file) {
476 		ret = -ENOMEM;
477 		goto err1;
478 	}
479 
480 	cd->debugfs_root = root;
481 	return 0;
482 err1:
483 	debugfs_remove_recursive(root);
484 err0:
485 	return ret;
486 }
487 
488 void genqwe_exit_debugfs(struct genwqe_dev *cd)
489 {
490 	debugfs_remove_recursive(cd->debugfs_root);
491 }
492