1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) Rockchip Electronics Co., Ltd.
4 *
5 * Author:
6 * Huang Lee <Putin.li@rock-chips.com>
7 */
8
9 #define pr_fmt(fmt) "rve_debugger: " fmt
10
11 #include <linux/slab.h>
12 #include <linux/delay.h>
13 #include <linux/syscalls.h>
14 #include <linux/debugfs.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17
18 #include "rve.h"
19 #include "rve_debugger.h"
20 #include "rve_drv.h"
21
22 #define RVE_DEBUGGER_ROOT_NAME "rve"
23
24 #define STR_ENABLE(en) (en ? "EN" : "DIS")
25
26 int RVE_DEBUG_REG;
27 int RVE_DEBUG_MSG;
28 int RVE_DEBUG_TIME;
29 int RVE_DEBUG_CHECK_MODE;
30 int RVE_DEBUG_NONUSE;
31 int RVE_DEBUG_INT_FLAG;
32 int RVE_DEBUG_MONITOR;
33
rve_debug_show(struct seq_file * m,void * data)34 static int rve_debug_show(struct seq_file *m, void *data)
35 {
36 seq_printf(m, "REG [%s]\n"
37 "MSG [%s]\n"
38 "TIME [%s]\n"
39 "INT [%s]\n"
40 "CHECK [%s]\n"
41 "STOP [%s]\n"
42 "MONITOR [%s]",
43 STR_ENABLE(RVE_DEBUG_REG),
44 STR_ENABLE(RVE_DEBUG_MSG),
45 STR_ENABLE(RVE_DEBUG_TIME),
46 STR_ENABLE(RVE_DEBUG_INT_FLAG),
47 STR_ENABLE(RVE_DEBUG_CHECK_MODE),
48 STR_ENABLE(RVE_DEBUG_NONUSE),
49 STR_ENABLE(RVE_DEBUG_MONITOR));
50
51 seq_puts(m, "\nhelp:\n");
52 seq_puts(m,
53 " 'echo reg > debug' to enable/disable register log printing.\n");
54 seq_puts(m,
55 " 'echo msg > debug' to enable/disable message log printing.\n");
56 seq_puts(m,
57 " 'echo time > debug' to enable/disable time log printing.\n");
58 seq_puts(m,
59 " 'echo int > debug' to enable/disable interruppt log printing.\n");
60 seq_puts(m, " 'echo check > debug' to enable/disable check mode.\n");
61 seq_puts(m,
62 " 'echo stop > debug' to enable/disable stop using hardware\n");
63 seq_puts(m, " 'echo mon > debug' to enable/disable monitor");
64
65 return 0;
66 }
67
rve_debug_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)68 static ssize_t rve_debug_write(struct file *file, const char __user *ubuf,
69 size_t len, loff_t *offp)
70 {
71 char buf[14];
72
73 if (len > sizeof(buf) - 1)
74 return -EINVAL;
75 if (copy_from_user(buf, ubuf, len))
76 return -EFAULT;
77 buf[len - 1] = '\0';
78
79 if (strncmp(buf, "reg", 4) == 0) {
80 if (RVE_DEBUG_REG) {
81 RVE_DEBUG_REG = 0;
82 pr_err("close rve reg!\n");
83 } else {
84 RVE_DEBUG_REG = 1;
85 pr_err("open rve reg!\n");
86 }
87 } else if (strncmp(buf, "msg", 3) == 0) {
88 if (RVE_DEBUG_MSG) {
89 RVE_DEBUG_MSG = 0;
90 pr_err("close rve test MSG!\n");
91 } else {
92 RVE_DEBUG_MSG = 1;
93 pr_err("open rve test MSG!\n");
94 }
95 } else if (strncmp(buf, "time", 4) == 0) {
96 if (RVE_DEBUG_TIME) {
97 RVE_DEBUG_TIME = 0;
98 pr_err("close rve test time!\n");
99 } else {
100 RVE_DEBUG_TIME = 1;
101 pr_err("open rve test time!\n");
102 }
103 } else if (strncmp(buf, "check", 5) == 0) {
104 if (RVE_DEBUG_CHECK_MODE) {
105 RVE_DEBUG_CHECK_MODE = 0;
106 pr_err("close rve check flag!\n");
107 } else {
108 RVE_DEBUG_CHECK_MODE = 1;
109 pr_err("open rve check flag!\n");
110 }
111 } else if (strncmp(buf, "stop", 4) == 0) {
112 if (RVE_DEBUG_NONUSE) {
113 RVE_DEBUG_NONUSE = 0;
114 pr_err("using rve hardware!\n");
115 } else {
116 RVE_DEBUG_NONUSE = 1;
117 pr_err("stop using rve hardware!\n");
118 }
119 } else if (strncmp(buf, "int", 3) == 0) {
120 if (RVE_DEBUG_INT_FLAG) {
121 RVE_DEBUG_INT_FLAG = 0;
122 pr_err("close inturrupt MSG!\n");
123 } else {
124 RVE_DEBUG_INT_FLAG = 1;
125 pr_err("open inturrupt MSG!\n");
126 }
127 } else if (strncmp(buf, "mon", 3) == 0) {
128 if (RVE_DEBUG_MONITOR) {
129 RVE_DEBUG_MONITOR = 0;
130 pr_err("close monitor!\n");
131 } else {
132 RVE_DEBUG_MONITOR = 1;
133 pr_err("open monitor!\n");
134 }
135 } else if (strncmp(buf, "slt", 3) == 0) {
136 pr_err("Null");
137 }
138
139 return len;
140 }
141
rve_version_show(struct seq_file * m,void * data)142 static int rve_version_show(struct seq_file *m, void *data)
143 {
144 seq_printf(m, "%s: v%s\n", DRIVER_DESC, DRIVER_VERSION);
145
146 return 0;
147 }
148
rve_load_show(struct seq_file * m,void * data)149 static int rve_load_show(struct seq_file *m, void *data)
150 {
151 struct rve_scheduler_t *scheduler = NULL;
152 struct rve_sche_pid_info_t *pid_info = NULL;
153 unsigned long flags;
154 int i;
155 int load;
156 u32 busy_time_total;
157
158 seq_printf(m, "num of scheduler = %d\n", rve_drvdata->num_of_scheduler);
159 seq_printf(m, "================= load ==================\n");
160
161 scheduler = rve_drvdata->scheduler[0];
162
163 seq_printf(m, "scheduler[0]: %s\n", dev_driver_string(scheduler->dev));
164
165 spin_lock_irqsave(&scheduler->irq_lock, flags);
166
167 busy_time_total = scheduler->timer.busy_time_record;
168 pid_info = scheduler->session.pid_info;
169
170 spin_unlock_irqrestore(&scheduler->irq_lock, flags);
171
172 load = (busy_time_total * 100000 / RVE_LOAD_INTERVAL);
173 seq_printf(m, "\t load = %d\n", load);
174
175 seq_printf(m, "---------------- PID INFO ---------------\n");
176
177 for (i = 0; i < RVE_MAX_PID_INFO; i++) {
178 seq_printf(m, "\t [pid: %d] hw_time_total = %llu us\n",
179 pid_info[i].pid, ktime_to_us(pid_info[i].hw_time_total));
180 seq_printf(m, "\t\t last_job_rd_bandwidth: %u bytes/s\n",
181 pid_info[i].last_job_rd_bandwidth);
182 seq_printf(m, "\t\t last_job_wr_bandwidth: %u bytes/s\n",
183 pid_info[i].last_job_wr_bandwidth);
184 seq_printf(m, "\t\t last_job_cycle_cnt/s: %u\n",
185 pid_info[i].last_job_cycle_cnt);
186 }
187 return 0;
188 }
189
rve_scheduler_show(struct seq_file * m,void * data)190 static int rve_scheduler_show(struct seq_file *m, void *data)
191 {
192 struct rve_scheduler_t *scheduler = NULL;
193 int i;
194 unsigned long flags;
195
196 int pd_refcount;
197 uint64_t total_int_cnt;
198 uint32_t rd_bandwidth, wr_bandwidth, cycle_cnt;
199
200 seq_printf(m, "num of scheduler = %d\n", rve_drvdata->num_of_scheduler);
201 seq_printf(m, "===================================\n");
202
203 for (i = 0; i < rve_drvdata->num_of_scheduler; i++) {
204 scheduler = rve_drvdata->scheduler[i];
205
206 spin_lock_irqsave(&scheduler->irq_lock, flags);
207
208 pd_refcount = scheduler->session.pd_refcount;
209 total_int_cnt = scheduler->session.total_int_cnt;
210 rd_bandwidth = scheduler->session.rd_bandwidth;
211 wr_bandwidth = scheduler->session.wr_bandwidth;
212 cycle_cnt = scheduler->session.cycle_cnt;
213
214 spin_unlock_irqrestore(&scheduler->irq_lock, flags);
215
216 seq_printf(m, "scheduler[%d]: %s\n", i, dev_driver_string(scheduler->dev));
217 seq_printf(m, "-----------------------------------\n");
218 seq_printf(m, "pd_ref = %d\n", pd_refcount);
219 seq_printf(m, "total_int_cnt = %llu\n", total_int_cnt);
220 seq_printf(m, "rd_bandwidth: %u bytes/s\t wr_bandwidth: %u bytes/s\n",
221 rd_bandwidth, wr_bandwidth);
222 seq_printf(m, "cycle_cnt/s: %u\n", cycle_cnt);
223 }
224
225 return 0;
226 }
227
rve_ctx_manager_show(struct seq_file * m,void * data)228 static int rve_ctx_manager_show(struct seq_file *m, void *data)
229 {
230 int id;
231 struct rve_pending_ctx_manager *ctx_manager;
232 struct rve_internal_ctx_t *ctx;
233 unsigned long flags;
234 int cmd_num = 0;
235 int finished_job_count = 0;
236 bool status = false;
237 pid_t pid;
238
239 u32 last_job_hw_use_time;
240 u32 last_job_use_time;
241 u32 hw_time_total;
242 u32 max_cost_time_per_sec;
243
244 ctx_manager = rve_drvdata->pend_ctx_manager;
245
246 seq_puts(m, "rve internal ctx dump:\n");
247 seq_printf(m, "ctx count = %d\n", ctx_manager->ctx_count);
248
249 spin_lock_irqsave(&ctx_manager->lock, flags);
250
251 idr_for_each_entry(&ctx_manager->ctx_id_idr, ctx, id) {
252 seq_printf(m, "================= ctx id: %d =================\n", ctx->id);
253
254 spin_unlock_irqrestore(&ctx_manager->lock, flags);
255
256 spin_lock_irqsave(&ctx->lock, flags);
257
258 cmd_num = ctx->cmd_num;
259 finished_job_count = ctx->finished_job_count;
260 status = ctx->is_running;
261 pid = ctx->debug_info.pid;
262 last_job_hw_use_time = ctx->debug_info.last_job_hw_use_time;
263 last_job_use_time = ctx->debug_info.last_job_use_time;
264 hw_time_total = ctx->debug_info.hw_time_total;
265 max_cost_time_per_sec = ctx->debug_info.max_cost_time_per_sec;
266
267 spin_unlock_irqrestore(&ctx->lock, flags);
268
269 seq_printf(m, "----------------- RVE CTX INFO -----------------\n");
270 seq_printf(m, "\t [pid: %d] status: %s\n", pid, status ? "active" : "pending");
271 seq_printf(m, "\t set cmd num: %d\t finish job sum: %d\n",
272 cmd_num, finished_job_count);
273 seq_printf(m, "\t last_job_use_time: %u us\t last_job_hw_use_time: %u us",
274 last_job_use_time, last_job_hw_use_time);
275 seq_printf(m, "\t hw_time_total: %u us\t max_cost_time_per_sec: %u us",
276 hw_time_total, max_cost_time_per_sec);
277
278 seq_printf(m, "----------------- RVE INVOKE INFO -----------------\n");
279 /* TODO: */
280
281 spin_lock_irqsave(&ctx_manager->lock, flags);
282 }
283
284 spin_unlock_irqrestore(&ctx_manager->lock, flags);
285
286 return 0;
287 }
288
289
290 struct rve_debugger_list rve_debugger_root_list[] = {
291 {"debug", rve_debug_show, rve_debug_write, NULL},
292 {"driver_version", rve_version_show, NULL, NULL},
293 {"load", rve_load_show, NULL, NULL},
294 {"scheduler_status", rve_scheduler_show, NULL, NULL},
295 {"ctx_manager", rve_ctx_manager_show, NULL, NULL},
296 };
297
rve_debugger_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)298 static ssize_t rve_debugger_write(struct file *file, const char __user *ubuf,
299 size_t len, loff_t *offp)
300 {
301 struct seq_file *priv = file->private_data;
302 struct rve_debugger_node *node = priv->private;
303
304 if (node->info_ent->write)
305 return node->info_ent->write(file, ubuf, len, offp);
306 else
307 return len;
308 }
309
310 #ifdef CONFIG_ROCKCHIP_RVE_DEBUG_FS
311
rve_debugfs_open(struct inode * inode,struct file * file)312 static int rve_debugfs_open(struct inode *inode, struct file *file)
313 {
314 struct rve_debugger_node *node = inode->i_private;
315
316 return single_open(file, node->info_ent->show, node);
317 }
318
319 static const struct file_operations rve_debugfs_fops = {
320 .owner = THIS_MODULE,
321 .open = rve_debugfs_open,
322 .read = seq_read,
323 .llseek = seq_lseek,
324 .release = single_release,
325 .write = rve_debugger_write,
326 };
327
rve_debugfs_remove_files(struct rve_debugger * debugger)328 static int rve_debugfs_remove_files(struct rve_debugger *debugger)
329 {
330 struct rve_debugger_node *pos, *q;
331 struct list_head *entry_list;
332
333 mutex_lock(&debugger->debugfs_lock);
334
335 /* Delete debugfs entry list */
336 entry_list = &debugger->debugfs_entry_list;
337 list_for_each_entry_safe(pos, q, entry_list, list) {
338 if (pos->dent == NULL)
339 continue;
340 list_del(&pos->list);
341 kfree(pos);
342 pos = NULL;
343 }
344
345 /* Delete all debugfs node in this directory */
346 debugfs_remove_recursive(debugger->debugfs_dir);
347 debugger->debugfs_dir = NULL;
348
349 mutex_unlock(&debugger->debugfs_lock);
350
351 return 0;
352 }
353
rve_debugfs_create_files(const struct rve_debugger_list * files,int count,struct dentry * root,struct rve_debugger * debugger)354 static int rve_debugfs_create_files(const struct rve_debugger_list *files,
355 int count, struct dentry *root,
356 struct rve_debugger *debugger)
357 {
358 int i;
359 struct dentry *ent;
360 struct rve_debugger_node *tmp;
361
362 for (i = 0; i < count; i++) {
363 tmp = kmalloc(sizeof(struct rve_debugger_node), GFP_KERNEL);
364 if (tmp == NULL) {
365 pr_err("Cannot alloc node path /sys/kernel/debug/%pd/%s\n",
366 root, files[i].name);
367 goto MALLOC_FAIL;
368 }
369
370 tmp->info_ent = &files[i];
371 tmp->debugger = debugger;
372
373 ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
374 root, tmp, &rve_debugfs_fops);
375 if (!ent) {
376 pr_err("Cannot create /sys/kernel/debug/%pd/%s\n", root,
377 files[i].name);
378 goto CREATE_FAIL;
379 }
380
381 tmp->dent = ent;
382
383 mutex_lock(&debugger->debugfs_lock);
384 list_add_tail(&tmp->list, &debugger->debugfs_entry_list);
385 mutex_unlock(&debugger->debugfs_lock);
386 }
387
388 return 0;
389
390 CREATE_FAIL:
391 kfree(tmp);
392 MALLOC_FAIL:
393 rve_debugfs_remove_files(debugger);
394
395 return -1;
396 }
397
rve_debugfs_remove(void)398 int rve_debugfs_remove(void)
399 {
400 struct rve_debugger *debugger;
401
402 debugger = rve_drvdata->debugger;
403
404 rve_debugfs_remove_files(debugger);
405
406 return 0;
407 }
408
rve_debugfs_init(void)409 int rve_debugfs_init(void)
410 {
411 int ret;
412 struct rve_debugger *debugger;
413
414 debugger = rve_drvdata->debugger;
415
416 debugger->debugfs_dir =
417 debugfs_create_dir(RVE_DEBUGGER_ROOT_NAME, NULL);
418 if (IS_ERR_OR_NULL(debugger->debugfs_dir)) {
419 pr_err("failed on mkdir /sys/kernel/debug/%s\n",
420 RVE_DEBUGGER_ROOT_NAME);
421 debugger->debugfs_dir = NULL;
422 return -EIO;
423 }
424
425 ret = rve_debugfs_create_files(rve_debugger_root_list, ARRAY_SIZE(rve_debugger_root_list),
426 debugger->debugfs_dir, debugger);
427 if (ret) {
428 pr_err("Could not install rve_debugger_root_list debugfs\n");
429 goto CREATE_FAIL;
430 }
431
432 return 0;
433
434 CREATE_FAIL:
435 rve_debugfs_remove();
436
437 return ret;
438 }
439 #endif /* #ifdef CONFIG_ROCKCHIP_RVE_DEBUG_FS */
440
441 #ifdef CONFIG_ROCKCHIP_RVE_PROC_FS
rve_procfs_open(struct inode * inode,struct file * file)442 static int rve_procfs_open(struct inode *inode, struct file *file)
443 {
444 struct rve_debugger_node *node = PDE_DATA(inode);
445
446 return single_open(file, node->info_ent->show, node);
447 }
448
449 static const struct proc_ops rve_procfs_fops = {
450 .proc_open = rve_procfs_open,
451 .proc_read = seq_read,
452 .proc_lseek = seq_lseek,
453 .proc_release = single_release,
454 .proc_write = rve_debugger_write,
455 };
456
rve_procfs_remove_files(struct rve_debugger * debugger)457 static int rve_procfs_remove_files(struct rve_debugger *debugger)
458 {
459 struct rve_debugger_node *pos, *q;
460 struct list_head *entry_list;
461
462 mutex_lock(&debugger->procfs_lock);
463
464 /* Delete procfs entry list */
465 entry_list = &debugger->procfs_entry_list;
466 list_for_each_entry_safe(pos, q, entry_list, list) {
467 if (pos->pent == NULL)
468 continue;
469 list_del(&pos->list);
470 kfree(pos);
471 pos = NULL;
472 }
473
474 /* Delete all procfs node in this directory */
475 proc_remove(debugger->procfs_dir);
476 debugger->procfs_dir = NULL;
477
478 mutex_unlock(&debugger->procfs_lock);
479
480 return 0;
481 }
482
rve_procfs_create_files(const struct rve_debugger_list * files,int count,struct proc_dir_entry * root,struct rve_debugger * debugger)483 static int rve_procfs_create_files(const struct rve_debugger_list *files,
484 int count, struct proc_dir_entry *root,
485 struct rve_debugger *debugger)
486 {
487 int i;
488 struct proc_dir_entry *ent;
489 struct rve_debugger_node *tmp;
490
491 for (i = 0; i < count; i++) {
492 tmp = kmalloc(sizeof(struct rve_debugger_node), GFP_KERNEL);
493 if (tmp == NULL) {
494 pr_err("Cannot alloc node path for /proc/%s/%s\n",
495 RVE_DEBUGGER_ROOT_NAME, files[i].name);
496 goto MALLOC_FAIL;
497 }
498
499 tmp->info_ent = &files[i];
500 tmp->debugger = debugger;
501
502 ent = proc_create_data(files[i].name, S_IFREG | S_IRUGO,
503 root, &rve_procfs_fops, tmp);
504 if (!ent) {
505 pr_err("Cannot create /proc/%s/%s\n",
506 RVE_DEBUGGER_ROOT_NAME, files[i].name);
507 goto CREATE_FAIL;
508 }
509
510 tmp->pent = ent;
511
512 mutex_lock(&debugger->procfs_lock);
513 list_add_tail(&tmp->list, &debugger->procfs_entry_list);
514 mutex_unlock(&debugger->procfs_lock);
515 }
516
517 return 0;
518
519 CREATE_FAIL:
520 kfree(tmp);
521 MALLOC_FAIL:
522 rve_procfs_remove_files(debugger);
523 return -1;
524 }
525
rve_procfs_remove(void)526 int rve_procfs_remove(void)
527 {
528 struct rve_debugger *debugger;
529
530 debugger = rve_drvdata->debugger;
531
532 rve_procfs_remove_files(debugger);
533
534 return 0;
535 }
536
rve_procfs_init(void)537 int rve_procfs_init(void)
538 {
539 int ret;
540 struct rve_debugger *debugger;
541
542 debugger = rve_drvdata->debugger;
543
544 debugger->procfs_dir = proc_mkdir(RVE_DEBUGGER_ROOT_NAME, NULL);
545 if (IS_ERR_OR_NULL(debugger->procfs_dir)) {
546 pr_err("failed on mkdir /proc/%s\n", RVE_DEBUGGER_ROOT_NAME);
547 debugger->procfs_dir = NULL;
548 return -EIO;
549 }
550
551 ret = rve_procfs_create_files(rve_debugger_root_list, ARRAY_SIZE(rve_debugger_root_list),
552 debugger->procfs_dir, debugger);
553 if (ret) {
554 pr_err("Could not install rve_debugger_root_list procfs\n");
555 goto CREATE_FAIL;
556 }
557
558 return 0;
559
560 CREATE_FAIL:
561 rve_procfs_remove();
562
563 return ret;
564 }
565 #endif /* #ifdef CONFIG_ROCKCHIP_RVE_PROC_FS */
566
567