diff options
-rw-r--r-- | drivers/gpu/nvgpu/Makefile | 7 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c | 188 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/include/nvgpu/fecs_trace.h | 60 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/debug_fecs_trace.c | 154 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/debug_fecs_trace.h | 30 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/module.c | 8 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_linux.h | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_ops.c | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_ops_gp106.c | 5 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_ops_gp10b.c | 5 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_ops_gv100.c | 5 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_ops_gv11b.c | 30 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/os_ops_gv11b.h | 24 |
13 files changed, 349 insertions, 175 deletions
diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index a3372cef..3b6a022a 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile | |||
@@ -53,6 +53,7 @@ nvgpu-y += \ | |||
53 | os/linux/os_ops_gp10b.o \ | 53 | os/linux/os_ops_gp10b.o \ |
54 | os/linux/os_ops_gp106.o \ | 54 | os/linux/os_ops_gp106.o \ |
55 | os/linux/os_ops_gv100.o \ | 55 | os/linux/os_ops_gv100.o \ |
56 | os/linux/os_ops_gv11b.o \ | ||
56 | os/linux/kmem.o \ | 57 | os/linux/kmem.o \ |
57 | os/linux/timers.o \ | 58 | os/linux/timers.o \ |
58 | os/linux/ioctl.o \ | 59 | os/linux/ioctl.o \ |
@@ -115,6 +116,12 @@ endif | |||
115 | nvgpu-$(CONFIG_GK20A_CTXSW_TRACE) += \ | 116 | nvgpu-$(CONFIG_GK20A_CTXSW_TRACE) += \ |
116 | os/linux/ctxsw_trace.o | 117 | os/linux/ctxsw_trace.o |
117 | 118 | ||
119 | ifeq ($(CONFIG_GK20A_CTXSW_TRACE),y) | ||
120 | nvgpu-$(CONFIG_DEBUG_FS) += \ | ||
121 | os/linux/debug_fecs_trace.o | ||
122 | endif | ||
123 | |||
124 | |||
118 | nvgpu-$(CONFIG_TEGRA_GK20A) += \ | 125 | nvgpu-$(CONFIG_TEGRA_GK20A) += \ |
119 | os/linux/module.o \ | 126 | os/linux/module.o \ |
120 | os/linux/module_usermode.o \ | 127 | os/linux/module_usermode.o \ |
diff --git a/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c b/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c index 3134df4d..b30d1743 100644 --- a/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c | |||
@@ -20,10 +20,6 @@ | |||
20 | * DEALINGS IN THE SOFTWARE. | 20 | * DEALINGS IN THE SOFTWARE. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #ifdef CONFIG_DEBUG_FS | ||
24 | #include <linux/debugfs.h> | ||
25 | #endif | ||
26 | |||
27 | #include <nvgpu/kmem.h> | 23 | #include <nvgpu/kmem.h> |
28 | #include <nvgpu/dma.h> | 24 | #include <nvgpu/dma.h> |
29 | #include <nvgpu/enabled.h> | 25 | #include <nvgpu/enabled.h> |
@@ -43,32 +39,13 @@ | |||
43 | #include "fecs_trace_gk20a.h" | 39 | #include "fecs_trace_gk20a.h" |
44 | #include "gk20a.h" | 40 | #include "gk20a.h" |
45 | #include "gr_gk20a.h" | 41 | #include "gr_gk20a.h" |
46 | #include "os/linux/os_linux.h" | ||
47 | 42 | ||
48 | #include <nvgpu/log.h> | 43 | #include <nvgpu/log.h> |
44 | #include <nvgpu/fecs_trace.h> | ||
49 | 45 | ||
50 | #include <nvgpu/hw/gk20a/hw_ctxsw_prog_gk20a.h> | 46 | #include <nvgpu/hw/gk20a/hw_ctxsw_prog_gk20a.h> |
51 | #include <nvgpu/hw/gk20a/hw_gr_gk20a.h> | 47 | #include <nvgpu/hw/gk20a/hw_gr_gk20a.h> |
52 | 48 | ||
53 | /* | ||
54 | * If HW circular buffer is getting too many "buffer full" conditions, | ||
55 | * increasing this constant should help (it drives Linux' internal buffer size). | ||
56 | */ | ||
57 | #define GK20A_FECS_TRACE_NUM_RECORDS (1 << 10) | ||
58 | #define GK20A_FECS_TRACE_HASH_BITS 8 /* 2^8 */ | ||
59 | #define GK20A_FECS_TRACE_FRAME_PERIOD_US (1000000ULL/60ULL) | ||
60 | #define GK20A_FECS_TRACE_PTIMER_SHIFT 5 | ||
61 | |||
62 | struct gk20a_fecs_trace_record { | ||
63 | u32 magic_lo; | ||
64 | u32 magic_hi; | ||
65 | u32 context_id; | ||
66 | u32 context_ptr; | ||
67 | u32 new_context_id; | ||
68 | u32 new_context_ptr; | ||
69 | u64 ts[]; | ||
70 | }; | ||
71 | |||
72 | struct gk20a_fecs_trace_hash_ent { | 49 | struct gk20a_fecs_trace_hash_ent { |
73 | u32 context_ptr; | 50 | u32 context_ptr; |
74 | pid_t pid; | 51 | pid_t pid; |
@@ -85,29 +62,33 @@ struct gk20a_fecs_trace { | |||
85 | }; | 62 | }; |
86 | 63 | ||
87 | #ifdef CONFIG_GK20A_CTXSW_TRACE | 64 | #ifdef CONFIG_GK20A_CTXSW_TRACE |
88 | static inline u32 gk20a_fecs_trace_record_ts_tag_v(u64 ts) | 65 | u32 gk20a_fecs_trace_record_ts_tag_invalid_ts_v(void) |
66 | { | ||
67 | return ctxsw_prog_record_timestamp_timestamp_hi_tag_invalid_timestamp_v(); | ||
68 | } | ||
69 | |||
70 | u32 gk20a_fecs_trace_record_ts_tag_v(u64 ts) | ||
89 | { | 71 | { |
90 | return ctxsw_prog_record_timestamp_timestamp_hi_tag_v((u32) (ts >> 32)); | 72 | return ctxsw_prog_record_timestamp_timestamp_hi_tag_v((u32) (ts >> 32)); |
91 | } | 73 | } |
92 | 74 | ||
93 | static inline u64 gk20a_fecs_trace_record_ts_timestamp_v(u64 ts) | 75 | u64 gk20a_fecs_trace_record_ts_timestamp_v(u64 ts) |
94 | { | 76 | { |
95 | return ts & ~(((u64)ctxsw_prog_record_timestamp_timestamp_hi_tag_m()) << 32); | 77 | return ts & ~(((u64)ctxsw_prog_record_timestamp_timestamp_hi_tag_m()) << 32); |
96 | } | 78 | } |
97 | 79 | ||
98 | |||
99 | static u32 gk20a_fecs_trace_fecs_context_ptr(struct gk20a *g, struct channel_gk20a *ch) | 80 | static u32 gk20a_fecs_trace_fecs_context_ptr(struct gk20a *g, struct channel_gk20a *ch) |
100 | { | 81 | { |
101 | return (u32) (nvgpu_inst_block_addr(g, &ch->inst_block) >> 12LL); | 82 | return (u32) (nvgpu_inst_block_addr(g, &ch->inst_block) >> 12LL); |
102 | } | 83 | } |
103 | 84 | ||
104 | static inline int gk20a_fecs_trace_num_ts(void) | 85 | int gk20a_fecs_trace_num_ts(void) |
105 | { | 86 | { |
106 | return (ctxsw_prog_record_timestamp_record_size_in_bytes_v() | 87 | return (ctxsw_prog_record_timestamp_record_size_in_bytes_v() |
107 | - sizeof(struct gk20a_fecs_trace_record)) / sizeof(u64); | 88 | - sizeof(struct gk20a_fecs_trace_record)) / sizeof(u64); |
108 | } | 89 | } |
109 | 90 | ||
110 | static struct gk20a_fecs_trace_record *gk20a_fecs_trace_get_record( | 91 | struct gk20a_fecs_trace_record *gk20a_fecs_trace_get_record( |
111 | struct gk20a *g, int idx) | 92 | struct gk20a *g, int idx) |
112 | { | 93 | { |
113 | struct nvgpu_mem *mem = &g->gr.global_ctx_buffer[FECS_TRACE_BUFFER].mem; | 94 | struct nvgpu_mem *mem = &g->gr.global_ctx_buffer[FECS_TRACE_BUFFER].mem; |
@@ -117,7 +98,7 @@ static struct gk20a_fecs_trace_record *gk20a_fecs_trace_get_record( | |||
117 | + (idx * ctxsw_prog_record_timestamp_record_size_in_bytes_v())); | 98 | + (idx * ctxsw_prog_record_timestamp_record_size_in_bytes_v())); |
118 | } | 99 | } |
119 | 100 | ||
120 | static bool gk20a_fecs_trace_is_valid_record(struct gk20a_fecs_trace_record *r) | 101 | bool gk20a_fecs_trace_is_valid_record(struct gk20a_fecs_trace_record *r) |
121 | { | 102 | { |
122 | /* | 103 | /* |
123 | * testing magic_hi should suffice. magic_lo is sometimes used | 104 | * testing magic_hi should suffice. magic_lo is sometimes used |
@@ -127,13 +108,13 @@ static bool gk20a_fecs_trace_is_valid_record(struct gk20a_fecs_trace_record *r) | |||
127 | == ctxsw_prog_record_timestamp_magic_value_hi_v_value_v()); | 108 | == ctxsw_prog_record_timestamp_magic_value_hi_v_value_v()); |
128 | } | 109 | } |
129 | 110 | ||
130 | static int gk20a_fecs_trace_get_read_index(struct gk20a *g) | 111 | int gk20a_fecs_trace_get_read_index(struct gk20a *g) |
131 | { | 112 | { |
132 | return gr_gk20a_elpg_protected_call(g, | 113 | return gr_gk20a_elpg_protected_call(g, |
133 | gk20a_readl(g, gr_fecs_mailbox1_r())); | 114 | gk20a_readl(g, gr_fecs_mailbox1_r())); |
134 | } | 115 | } |
135 | 116 | ||
136 | static int gk20a_fecs_trace_get_write_index(struct gk20a *g) | 117 | int gk20a_fecs_trace_get_write_index(struct gk20a *g) |
137 | { | 118 | { |
138 | return gr_gk20a_elpg_protected_call(g, | 119 | return gr_gk20a_elpg_protected_call(g, |
139 | gk20a_readl(g, gr_fecs_mailbox0_r())); | 120 | gk20a_readl(g, gr_fecs_mailbox0_r())); |
@@ -424,147 +405,6 @@ size_t gk20a_fecs_trace_buffer_size(struct gk20a *g) | |||
424 | * ctxsw_prog_record_timestamp_record_size_in_bytes_v(); | 405 | * ctxsw_prog_record_timestamp_record_size_in_bytes_v(); |
425 | } | 406 | } |
426 | 407 | ||
427 | #ifdef CONFIG_DEBUG_FS | ||
428 | /* | ||
429 | * The sequence iterator functions. We simply use the count of the | ||
430 | * next line as our internal position. | ||
431 | */ | ||
432 | static void *gk20a_fecs_trace_debugfs_ring_seq_start( | ||
433 | struct seq_file *s, loff_t *pos) | ||
434 | { | ||
435 | if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS) | ||
436 | return NULL; | ||
437 | |||
438 | return pos; | ||
439 | } | ||
440 | |||
441 | static void *gk20a_fecs_trace_debugfs_ring_seq_next( | ||
442 | struct seq_file *s, void *v, loff_t *pos) | ||
443 | { | ||
444 | ++(*pos); | ||
445 | if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS) | ||
446 | return NULL; | ||
447 | return pos; | ||
448 | } | ||
449 | |||
450 | static void gk20a_fecs_trace_debugfs_ring_seq_stop( | ||
451 | struct seq_file *s, void *v) | ||
452 | { | ||
453 | } | ||
454 | |||
455 | static int gk20a_fecs_trace_debugfs_ring_seq_show( | ||
456 | struct seq_file *s, void *v) | ||
457 | { | ||
458 | loff_t *pos = (loff_t *) v; | ||
459 | struct gk20a *g = *(struct gk20a **)s->private; | ||
460 | struct gk20a_fecs_trace_record *r = | ||
461 | gk20a_fecs_trace_get_record(g, *pos); | ||
462 | int i; | ||
463 | const u32 invalid_tag = | ||
464 | ctxsw_prog_record_timestamp_timestamp_hi_tag_invalid_timestamp_v(); | ||
465 | u32 tag; | ||
466 | u64 timestamp; | ||
467 | |||
468 | seq_printf(s, "record #%lld (%p)\n", *pos, r); | ||
469 | seq_printf(s, "\tmagic_lo=%08x\n", r->magic_lo); | ||
470 | seq_printf(s, "\tmagic_hi=%08x\n", r->magic_hi); | ||
471 | if (gk20a_fecs_trace_is_valid_record(r)) { | ||
472 | seq_printf(s, "\tcontext_ptr=%08x\n", r->context_ptr); | ||
473 | seq_printf(s, "\tcontext_id=%08x\n", r->context_id); | ||
474 | seq_printf(s, "\tnew_context_ptr=%08x\n", r->new_context_ptr); | ||
475 | seq_printf(s, "\tnew_context_id=%08x\n", r->new_context_id); | ||
476 | for (i = 0; i < gk20a_fecs_trace_num_ts(); i++) { | ||
477 | tag = gk20a_fecs_trace_record_ts_tag_v(r->ts[i]); | ||
478 | if (tag == invalid_tag) | ||
479 | continue; | ||
480 | timestamp = gk20a_fecs_trace_record_ts_timestamp_v(r->ts[i]); | ||
481 | timestamp <<= GK20A_FECS_TRACE_PTIMER_SHIFT; | ||
482 | seq_printf(s, "\ttag=%02x timestamp=%012llx\n", tag, timestamp); | ||
483 | } | ||
484 | } | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * Tie them all together into a set of seq_operations. | ||
490 | */ | ||
491 | static const struct seq_operations gk20a_fecs_trace_debugfs_ring_seq_ops = { | ||
492 | .start = gk20a_fecs_trace_debugfs_ring_seq_start, | ||
493 | .next = gk20a_fecs_trace_debugfs_ring_seq_next, | ||
494 | .stop = gk20a_fecs_trace_debugfs_ring_seq_stop, | ||
495 | .show = gk20a_fecs_trace_debugfs_ring_seq_show | ||
496 | }; | ||
497 | |||
498 | /* | ||
499 | * Time to set up the file operations for our /proc file. In this case, | ||
500 | * all we need is an open function which sets up the sequence ops. | ||
501 | */ | ||
502 | |||
503 | static int gk20a_ctxsw_debugfs_ring_open(struct inode *inode, | ||
504 | struct file *file) | ||
505 | { | ||
506 | struct gk20a **p; | ||
507 | |||
508 | if (!capable(CAP_SYS_ADMIN)) | ||
509 | return -EPERM; | ||
510 | |||
511 | p = __seq_open_private(file, &gk20a_fecs_trace_debugfs_ring_seq_ops, | ||
512 | sizeof(struct gk20a *)); | ||
513 | if (!p) | ||
514 | return -ENOMEM; | ||
515 | |||
516 | *p = (struct gk20a *)inode->i_private; | ||
517 | return 0; | ||
518 | }; | ||
519 | |||
520 | /* | ||
521 | * The file operations structure contains our open function along with | ||
522 | * set of the canned seq_ ops. | ||
523 | */ | ||
524 | static const struct file_operations gk20a_fecs_trace_debugfs_ring_fops = { | ||
525 | .owner = THIS_MODULE, | ||
526 | .open = gk20a_ctxsw_debugfs_ring_open, | ||
527 | .read = seq_read, | ||
528 | .llseek = seq_lseek, | ||
529 | .release = seq_release_private | ||
530 | }; | ||
531 | |||
532 | static int gk20a_fecs_trace_debugfs_read(void *arg, u64 *val) | ||
533 | { | ||
534 | *val = gk20a_fecs_trace_get_read_index((struct gk20a *)arg); | ||
535 | return 0; | ||
536 | } | ||
537 | DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_read_fops, | ||
538 | gk20a_fecs_trace_debugfs_read, NULL, "%llu\n"); | ||
539 | |||
540 | static int gk20a_fecs_trace_debugfs_write(void *arg, u64 *val) | ||
541 | { | ||
542 | *val = gk20a_fecs_trace_get_write_index((struct gk20a *)arg); | ||
543 | return 0; | ||
544 | } | ||
545 | DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_write_fops, | ||
546 | gk20a_fecs_trace_debugfs_write, NULL, "%llu\n"); | ||
547 | |||
548 | static void gk20a_fecs_trace_debugfs_init(struct gk20a *g) | ||
549 | { | ||
550 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
551 | |||
552 | debugfs_create_file("ctxsw_trace_read", 0600, l->debugfs, g, | ||
553 | &gk20a_fecs_trace_debugfs_read_fops); | ||
554 | debugfs_create_file("ctxsw_trace_write", 0600, l->debugfs, g, | ||
555 | &gk20a_fecs_trace_debugfs_write_fops); | ||
556 | debugfs_create_file("ctxsw_trace_ring", 0600, l->debugfs, g, | ||
557 | &gk20a_fecs_trace_debugfs_ring_fops); | ||
558 | } | ||
559 | |||
560 | #else | ||
561 | |||
562 | static void gk20a_fecs_trace_debugfs_init(struct gk20a *g) | ||
563 | { | ||
564 | } | ||
565 | |||
566 | #endif /* CONFIG_DEBUG_FS */ | ||
567 | |||
568 | int gk20a_fecs_trace_init(struct gk20a *g) | 408 | int gk20a_fecs_trace_init(struct gk20a *g) |
569 | { | 409 | { |
570 | struct gk20a_fecs_trace *trace; | 410 | struct gk20a_fecs_trace *trace; |
@@ -589,8 +429,6 @@ int gk20a_fecs_trace_init(struct gk20a *g) | |||
589 | 429 | ||
590 | __nvgpu_set_enabled(g, NVGPU_SUPPORT_FECS_CTXSW_TRACE, true); | 430 | __nvgpu_set_enabled(g, NVGPU_SUPPORT_FECS_CTXSW_TRACE, true); |
591 | 431 | ||
592 | gk20a_fecs_trace_debugfs_init(g); | ||
593 | |||
594 | trace->init = true; | 432 | trace->init = true; |
595 | 433 | ||
596 | return 0; | 434 | return 0; |
diff --git a/drivers/gpu/nvgpu/include/nvgpu/fecs_trace.h b/drivers/gpu/nvgpu/include/nvgpu/fecs_trace.h new file mode 100644 index 00000000..5dc35302 --- /dev/null +++ b/drivers/gpu/nvgpu/include/nvgpu/fecs_trace.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef NVGPU_FECS_TRACE_H | ||
24 | #define NVGPU_FECS_TRACE_H | ||
25 | |||
26 | struct gk20a; | ||
27 | |||
28 | /* | ||
29 | * If HW circular buffer is getting too many "buffer full" conditions, | ||
30 | * increasing this constant should help (it drives Linux' internal buffer size). | ||
31 | */ | ||
32 | #define GK20A_FECS_TRACE_NUM_RECORDS (1 << 10) | ||
33 | #define GK20A_FECS_TRACE_HASH_BITS 8 /* 2^8 */ | ||
34 | #define GK20A_FECS_TRACE_FRAME_PERIOD_US (1000000ULL/60ULL) | ||
35 | #define GK20A_FECS_TRACE_PTIMER_SHIFT 5 | ||
36 | |||
37 | struct gk20a_fecs_trace_record { | ||
38 | u32 magic_lo; | ||
39 | u32 magic_hi; | ||
40 | u32 context_id; | ||
41 | u32 context_ptr; | ||
42 | u32 new_context_id; | ||
43 | u32 new_context_ptr; | ||
44 | u64 ts[]; | ||
45 | }; | ||
46 | |||
47 | #ifdef CONFIG_GK20A_CTXSW_TRACE | ||
48 | u32 gk20a_fecs_trace_record_ts_tag_invalid_ts_v(void); | ||
49 | u32 gk20a_fecs_trace_record_ts_tag_v(u64 ts); | ||
50 | u64 gk20a_fecs_trace_record_ts_timestamp_v(u64 ts); | ||
51 | int gk20a_fecs_trace_num_ts(void); | ||
52 | struct gk20a_fecs_trace_record *gk20a_fecs_trace_get_record(struct gk20a *g, | ||
53 | int idx); | ||
54 | bool gk20a_fecs_trace_is_valid_record(struct gk20a_fecs_trace_record *r); | ||
55 | int gk20a_fecs_trace_get_read_index(struct gk20a *g); | ||
56 | int gk20a_fecs_trace_get_write_index(struct gk20a *g); | ||
57 | |||
58 | #endif /* CONFIG_GK20A_CTXSW_TRACE */ | ||
59 | |||
60 | #endif | ||
diff --git a/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.c b/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.c new file mode 100644 index 00000000..9e72d2ce --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/debugfs.h> | ||
18 | |||
19 | #include <nvgpu/fecs_trace.h> | ||
20 | |||
21 | #include "os_linux.h" | ||
22 | |||
23 | /* | ||
24 | * The sequence iterator functions. We simply use the count of the | ||
25 | * next line as our internal position. | ||
26 | */ | ||
27 | static void *gk20a_fecs_trace_debugfs_ring_seq_start( | ||
28 | struct seq_file *s, loff_t *pos) | ||
29 | { | ||
30 | if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS) | ||
31 | return NULL; | ||
32 | |||
33 | return pos; | ||
34 | } | ||
35 | |||
36 | static void *gk20a_fecs_trace_debugfs_ring_seq_next( | ||
37 | struct seq_file *s, void *v, loff_t *pos) | ||
38 | { | ||
39 | ++(*pos); | ||
40 | if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS) | ||
41 | return NULL; | ||
42 | return pos; | ||
43 | } | ||
44 | |||
45 | static void gk20a_fecs_trace_debugfs_ring_seq_stop( | ||
46 | struct seq_file *s, void *v) | ||
47 | { | ||
48 | } | ||
49 | |||
50 | static int gk20a_fecs_trace_debugfs_ring_seq_show( | ||
51 | struct seq_file *s, void *v) | ||
52 | { | ||
53 | loff_t *pos = (loff_t *) v; | ||
54 | struct gk20a *g = *(struct gk20a **)s->private; | ||
55 | struct gk20a_fecs_trace_record *r = | ||
56 | gk20a_fecs_trace_get_record(g, *pos); | ||
57 | int i; | ||
58 | const u32 invalid_tag = gk20a_fecs_trace_record_ts_tag_invalid_ts_v(); | ||
59 | u32 tag; | ||
60 | u64 timestamp; | ||
61 | |||
62 | seq_printf(s, "record #%lld (%p)\n", *pos, r); | ||
63 | seq_printf(s, "\tmagic_lo=%08x\n", r->magic_lo); | ||
64 | seq_printf(s, "\tmagic_hi=%08x\n", r->magic_hi); | ||
65 | if (gk20a_fecs_trace_is_valid_record(r)) { | ||
66 | seq_printf(s, "\tcontext_ptr=%08x\n", r->context_ptr); | ||
67 | seq_printf(s, "\tcontext_id=%08x\n", r->context_id); | ||
68 | seq_printf(s, "\tnew_context_ptr=%08x\n", r->new_context_ptr); | ||
69 | seq_printf(s, "\tnew_context_id=%08x\n", r->new_context_id); | ||
70 | for (i = 0; i < gk20a_fecs_trace_num_ts(); i++) { | ||
71 | tag = gk20a_fecs_trace_record_ts_tag_v(r->ts[i]); | ||
72 | if (tag == invalid_tag) | ||
73 | continue; | ||
74 | timestamp = gk20a_fecs_trace_record_ts_timestamp_v(r->ts[i]); | ||
75 | timestamp <<= GK20A_FECS_TRACE_PTIMER_SHIFT; | ||
76 | seq_printf(s, "\ttag=%02x timestamp=%012llx\n", tag, timestamp); | ||
77 | } | ||
78 | } | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Tie them all together into a set of seq_operations. | ||
84 | */ | ||
85 | static const struct seq_operations gk20a_fecs_trace_debugfs_ring_seq_ops = { | ||
86 | .start = gk20a_fecs_trace_debugfs_ring_seq_start, | ||
87 | .next = gk20a_fecs_trace_debugfs_ring_seq_next, | ||
88 | .stop = gk20a_fecs_trace_debugfs_ring_seq_stop, | ||
89 | .show = gk20a_fecs_trace_debugfs_ring_seq_show | ||
90 | }; | ||
91 | |||
92 | /* | ||
93 | * Time to set up the file operations for our /proc file. In this case, | ||
94 | * all we need is an open function which sets up the sequence ops. | ||
95 | */ | ||
96 | |||
97 | static int gk20a_ctxsw_debugfs_ring_open(struct inode *inode, | ||
98 | struct file *file) | ||
99 | { | ||
100 | struct gk20a **p; | ||
101 | |||
102 | if (!capable(CAP_SYS_ADMIN)) | ||
103 | return -EPERM; | ||
104 | |||
105 | p = __seq_open_private(file, &gk20a_fecs_trace_debugfs_ring_seq_ops, | ||
106 | sizeof(struct gk20a *)); | ||
107 | if (!p) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | *p = (struct gk20a *)inode->i_private; | ||
111 | return 0; | ||
112 | }; | ||
113 | |||
114 | /* | ||
115 | * The file operations structure contains our open function along with | ||
116 | * set of the canned seq_ ops. | ||
117 | */ | ||
118 | static const struct file_operations gk20a_fecs_trace_debugfs_ring_fops = { | ||
119 | .owner = THIS_MODULE, | ||
120 | .open = gk20a_ctxsw_debugfs_ring_open, | ||
121 | .read = seq_read, | ||
122 | .llseek = seq_lseek, | ||
123 | .release = seq_release_private | ||
124 | }; | ||
125 | |||
126 | static int gk20a_fecs_trace_debugfs_read(void *arg, u64 *val) | ||
127 | { | ||
128 | *val = gk20a_fecs_trace_get_read_index((struct gk20a *)arg); | ||
129 | return 0; | ||
130 | } | ||
131 | DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_read_fops, | ||
132 | gk20a_fecs_trace_debugfs_read, NULL, "%llu\n"); | ||
133 | |||
134 | static int gk20a_fecs_trace_debugfs_write(void *arg, u64 *val) | ||
135 | { | ||
136 | *val = gk20a_fecs_trace_get_write_index((struct gk20a *)arg); | ||
137 | return 0; | ||
138 | } | ||
139 | DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_write_fops, | ||
140 | gk20a_fecs_trace_debugfs_write, NULL, "%llu\n"); | ||
141 | |||
142 | int nvgpu_fecs_trace_init_debugfs(struct gk20a *g) | ||
143 | { | ||
144 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
145 | |||
146 | debugfs_create_file("ctxsw_trace_read", 0600, l->debugfs, g, | ||
147 | &gk20a_fecs_trace_debugfs_read_fops); | ||
148 | debugfs_create_file("ctxsw_trace_write", 0600, l->debugfs, g, | ||
149 | &gk20a_fecs_trace_debugfs_write_fops); | ||
150 | debugfs_create_file("ctxsw_trace_ring", 0600, l->debugfs, g, | ||
151 | &gk20a_fecs_trace_debugfs_ring_fops); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
diff --git a/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.h b/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.h new file mode 100644 index 00000000..a545f2db --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef LINUX_DEBUG_FECS_TRACE_H | ||
18 | #define LINUX_DEBUG_FECS_TRACE_H | ||
19 | |||
20 | struct gk20a; | ||
21 | |||
22 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_GK20A_CTXSW_TRACE) | ||
23 | int nvgpu_fecs_trace_init_debugfs(struct gk20a *g); | ||
24 | #else | ||
25 | int nvgpu_fecs_trace_init_debugfs(struct gk20a *g) | ||
26 | { | ||
27 | return 0; | ||
28 | } | ||
29 | #endif | ||
30 | #endif | ||
diff --git a/drivers/gpu/nvgpu/os/linux/module.c b/drivers/gpu/nvgpu/os/linux/module.c index 85439b88..ff4d9a4c 100644 --- a/drivers/gpu/nvgpu/os/linux/module.c +++ b/drivers/gpu/nvgpu/os/linux/module.c | |||
@@ -216,6 +216,14 @@ int nvgpu_finalize_poweron_linux(struct nvgpu_os_linux *l) | |||
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | if (l->ops.fecs_trace.init_debugfs) { | ||
220 | err = l->ops.fecs_trace.init_debugfs(g); | ||
221 | if (err) { | ||
222 | nvgpu_err(g, "failed to init linux fecs trace debugfs"); | ||
223 | return err; | ||
224 | } | ||
225 | } | ||
226 | |||
219 | err = nvgpu_pmgr_init_debugfs_linux(l); | 227 | err = nvgpu_pmgr_init_debugfs_linux(l); |
220 | if (err) { | 228 | if (err) { |
221 | nvgpu_err(g, "failed to init linux pmgr debugfs"); | 229 | nvgpu_err(g, "failed to init linux pmgr debugfs"); |
diff --git a/drivers/gpu/nvgpu/os/linux/os_linux.h b/drivers/gpu/nvgpu/os/linux/os_linux.h index ff871fe5..a9a9ebb6 100644 --- a/drivers/gpu/nvgpu/os/linux/os_linux.h +++ b/drivers/gpu/nvgpu/os/linux/os_linux.h | |||
@@ -46,6 +46,10 @@ struct nvgpu_os_linux_ops { | |||
46 | struct { | 46 | struct { |
47 | int (*init_debugfs)(struct gk20a *g); | 47 | int (*init_debugfs)(struct gk20a *g); |
48 | } therm; | 48 | } therm; |
49 | |||
50 | struct { | ||
51 | int (*init_debugfs)(struct gk20a *g); | ||
52 | } fecs_trace; | ||
49 | }; | 53 | }; |
50 | 54 | ||
51 | struct nvgpu_os_linux { | 55 | struct nvgpu_os_linux { |
diff --git a/drivers/gpu/nvgpu/os/linux/os_ops.c b/drivers/gpu/nvgpu/os/linux/os_ops.c index 5c2eb25c..f1ab4b15 100644 --- a/drivers/gpu/nvgpu/os/linux/os_ops.c +++ b/drivers/gpu/nvgpu/os/linux/os_ops.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include "os_ops_gm20b.h" | 19 | #include "os_ops_gm20b.h" |
20 | #include "os_ops_gp10b.h" | 20 | #include "os_ops_gp10b.h" |
21 | #include "os_ops_gp106.h" | 21 | #include "os_ops_gp106.h" |
22 | #include "os_ops_gv11b.h" | ||
22 | #include "os_ops_gv100.h" | 23 | #include "os_ops_gv100.h" |
23 | 24 | ||
24 | #if defined(CONFIG_TEGRA_GPU_NEXT) | 25 | #if defined(CONFIG_TEGRA_GPU_NEXT) |
@@ -44,6 +45,9 @@ int nvgpu_init_os_linux_ops(struct nvgpu_os_linux *l) | |||
44 | case NVGPU_GPUID_GV100: | 45 | case NVGPU_GPUID_GV100: |
45 | nvgpu_gv100_init_os_ops(l); | 46 | nvgpu_gv100_init_os_ops(l); |
46 | break; | 47 | break; |
48 | case NVGPU_GPUID_GV11B: | ||
49 | nvgpu_gv11b_init_os_ops(l); | ||
50 | break; | ||
47 | #if defined(CONFIG_TEGRA_GPU_NEXT) | 51 | #if defined(CONFIG_TEGRA_GPU_NEXT) |
48 | case NVGPU_GPUID_NEXT: | 52 | case NVGPU_GPUID_NEXT: |
49 | NVGPU_NEXT_INIT_OS_OPS(l); | 53 | NVGPU_NEXT_INIT_OS_OPS(l); |
diff --git a/drivers/gpu/nvgpu/os/linux/os_ops_gp106.c b/drivers/gpu/nvgpu/os/linux/os_ops_gp106.c index 662f4551..14f1b004 100644 --- a/drivers/gpu/nvgpu/os/linux/os_ops_gp106.c +++ b/drivers/gpu/nvgpu/os/linux/os_ops_gp106.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "debug_clk_gp106.h" | 19 | #include "debug_clk_gp106.h" |
20 | #include "debug_therm_gp106.h" | 20 | #include "debug_therm_gp106.h" |
21 | #include "debug_fecs_trace.h" | ||
21 | 22 | ||
22 | static struct nvgpu_os_linux_ops gp106_os_linux_ops = { | 23 | static struct nvgpu_os_linux_ops gp106_os_linux_ops = { |
23 | .clk = { | 24 | .clk = { |
@@ -26,10 +27,14 @@ static struct nvgpu_os_linux_ops gp106_os_linux_ops = { | |||
26 | .therm = { | 27 | .therm = { |
27 | .init_debugfs = gp106_therm_init_debugfs, | 28 | .init_debugfs = gp106_therm_init_debugfs, |
28 | }, | 29 | }, |
30 | .fecs_trace = { | ||
31 | .init_debugfs = nvgpu_fecs_trace_init_debugfs, | ||
32 | }, | ||
29 | }; | 33 | }; |
30 | 34 | ||
31 | void nvgpu_gp106_init_os_ops(struct nvgpu_os_linux *l) | 35 | void nvgpu_gp106_init_os_ops(struct nvgpu_os_linux *l) |
32 | { | 36 | { |
33 | l->ops.clk = gp106_os_linux_ops.clk; | 37 | l->ops.clk = gp106_os_linux_ops.clk; |
34 | l->ops.therm = gp106_os_linux_ops.therm; | 38 | l->ops.therm = gp106_os_linux_ops.therm; |
39 | l->ops.fecs_trace = gp106_os_linux_ops.fecs_trace; | ||
35 | } | 40 | } |
diff --git a/drivers/gpu/nvgpu/os/linux/os_ops_gp10b.c b/drivers/gpu/nvgpu/os/linux/os_ops_gp10b.c index 984dcdc0..e2891f73 100644 --- a/drivers/gpu/nvgpu/os/linux/os_ops_gp10b.c +++ b/drivers/gpu/nvgpu/os/linux/os_ops_gp10b.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "os_linux.h" | 17 | #include "os_linux.h" |
18 | 18 | ||
19 | #include "cde_gp10b.h" | 19 | #include "cde_gp10b.h" |
20 | #include "debug_fecs_trace.h" | ||
20 | 21 | ||
21 | static struct nvgpu_os_linux_ops gp10b_os_linux_ops = { | 22 | static struct nvgpu_os_linux_ops gp10b_os_linux_ops = { |
22 | #ifdef CONFIG_NVGPU_SUPPORT_CDE | 23 | #ifdef CONFIG_NVGPU_SUPPORT_CDE |
@@ -26,6 +27,9 @@ static struct nvgpu_os_linux_ops gp10b_os_linux_ops = { | |||
26 | .populate_scatter_buffer = gp10b_populate_scatter_buffer, | 27 | .populate_scatter_buffer = gp10b_populate_scatter_buffer, |
27 | }, | 28 | }, |
28 | #endif | 29 | #endif |
30 | .fecs_trace = { | ||
31 | .init_debugfs = nvgpu_fecs_trace_init_debugfs, | ||
32 | }, | ||
29 | }; | 33 | }; |
30 | 34 | ||
31 | void nvgpu_gp10b_init_os_ops(struct nvgpu_os_linux *l) | 35 | void nvgpu_gp10b_init_os_ops(struct nvgpu_os_linux *l) |
@@ -33,4 +37,5 @@ void nvgpu_gp10b_init_os_ops(struct nvgpu_os_linux *l) | |||
33 | #ifdef CONFIG_NVGPU_SUPPORT_CDE | 37 | #ifdef CONFIG_NVGPU_SUPPORT_CDE |
34 | l->ops.cde = gp10b_os_linux_ops.cde; | 38 | l->ops.cde = gp10b_os_linux_ops.cde; |
35 | #endif | 39 | #endif |
40 | l->ops.fecs_trace = gp10b_os_linux_ops.fecs_trace; | ||
36 | } | 41 | } |
diff --git a/drivers/gpu/nvgpu/os/linux/os_ops_gv100.c b/drivers/gpu/nvgpu/os/linux/os_ops_gv100.c index 7a5174a4..f5c5a604 100644 --- a/drivers/gpu/nvgpu/os/linux/os_ops_gv100.c +++ b/drivers/gpu/nvgpu/os/linux/os_ops_gv100.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "debug_clk_gp106.h" | 19 | #include "debug_clk_gp106.h" |
20 | #include "debug_therm_gp106.h" | 20 | #include "debug_therm_gp106.h" |
21 | #include "debug_fecs_trace.h" | ||
21 | 22 | ||
22 | static struct nvgpu_os_linux_ops gv100_os_linux_ops = { | 23 | static struct nvgpu_os_linux_ops gv100_os_linux_ops = { |
23 | .clk = { | 24 | .clk = { |
@@ -26,10 +27,14 @@ static struct nvgpu_os_linux_ops gv100_os_linux_ops = { | |||
26 | .therm = { | 27 | .therm = { |
27 | .init_debugfs = gp106_therm_init_debugfs, | 28 | .init_debugfs = gp106_therm_init_debugfs, |
28 | }, | 29 | }, |
30 | .fecs_trace = { | ||
31 | .init_debugfs = nvgpu_fecs_trace_init_debugfs, | ||
32 | }, | ||
29 | }; | 33 | }; |
30 | 34 | ||
31 | void nvgpu_gv100_init_os_ops(struct nvgpu_os_linux *l) | 35 | void nvgpu_gv100_init_os_ops(struct nvgpu_os_linux *l) |
32 | { | 36 | { |
33 | l->ops.clk = gv100_os_linux_ops.clk; | 37 | l->ops.clk = gv100_os_linux_ops.clk; |
34 | l->ops.therm = gv100_os_linux_ops.therm; | 38 | l->ops.therm = gv100_os_linux_ops.therm; |
39 | l->ops.fecs_trace = gv100_os_linux_ops.fecs_trace; | ||
35 | } | 40 | } |
diff --git a/drivers/gpu/nvgpu/os/linux/os_ops_gv11b.c b/drivers/gpu/nvgpu/os/linux/os_ops_gv11b.c new file mode 100644 index 00000000..a82ad0ab --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/os_ops_gv11b.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include "os_linux.h" | ||
18 | |||
19 | #include "debug_fecs_trace.h" | ||
20 | |||
21 | static struct nvgpu_os_linux_ops gv11b_os_linux_ops = { | ||
22 | .fecs_trace = { | ||
23 | .init_debugfs = nvgpu_fecs_trace_init_debugfs, | ||
24 | }, | ||
25 | }; | ||
26 | |||
27 | void nvgpu_gv11b_init_os_ops(struct nvgpu_os_linux *l) | ||
28 | { | ||
29 | l->ops.fecs_trace = gv11b_os_linux_ops.fecs_trace; | ||
30 | } | ||
diff --git a/drivers/gpu/nvgpu/os/linux/os_ops_gv11b.h b/drivers/gpu/nvgpu/os/linux/os_ops_gv11b.h new file mode 100644 index 00000000..eef6c4ac --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/os_ops_gv11b.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef LINUX_OS_OPS_GV11B_H | ||
18 | #define LINUX_OS_OPS_GV11B_H | ||
19 | |||
20 | struct nvgpu_os_linux; | ||
21 | |||
22 | void nvgpu_gv11b_init_os_ops(struct nvgpu_os_linux *l); | ||
23 | |||
24 | #endif | ||