aboutsummaryrefslogtreecommitdiffstats
path: root/runlist_procfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'runlist_procfs.c')
-rw-r--r--runlist_procfs.c645
1 files changed, 636 insertions, 9 deletions
diff --git a/runlist_procfs.c b/runlist_procfs.c
index b2159f6..a3a6df3 100644
--- a/runlist_procfs.c
+++ b/runlist_procfs.c
@@ -1,12 +1,117 @@
1#include <linux/seq_file.h> // For seq_* functions and types 1#include <linux/seq_file.h> // For seq_* functions and types
2#include <linux/version.h> // Macros to detect kernel version 2#include <linux/version.h> // Macros to detect kernel version
3#include <linux/platform_device.h> // For platform_get_resource()
4#include <linux/pci.h> // For pci_resource_start()
5#include <linux/iommu.h> // For iommu_ functions
6#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
7#include <linux/dma-map-ops.h> // For get_dma_ops()
8#endif
3 9
4#include "nvdebug_linux.h" 10#include "nvdebug_linux.h"
5 11
6// Uncomment to expand channel status information when printing the runlist 12// We cannot touch PRAMIN (via page table operations or ctxsw access) if we're
13// using it to walk the runlist
14//#ifndef FALLBACK_TO_PRAMIN
15// Uncomment to expand channel status, instance, and context information when
16// printing the runlist
7#define DETAILED_CHANNEL_INFO 17#define DETAILED_CHANNEL_INFO
18//#endif
8 19
9#ifdef DETAILED_CHANNEL_INFO 20#ifdef DETAILED_CHANNEL_INFO
21// Print the channel instance and context swtich blocks
22// XXX: THIS IS UNSAFE ON KEPLER!
23// instance_deref() will call into the page table logic, which may move PRAMIN
24// PRAMIN appears heavily utilized by the driver on Bonham (at least), and
25// moving it causes problems.
26static int runlist_detail_seq_show_inst(struct seq_file *s, struct nvdebug_state *g, char *prefix, uint64_t instance_ptr, enum INST_TARGET instance_target) {
27 instance_ctrl_t *inst = NULL;
28 context_switch_ctrl_t *ctxsw = NULL;
29 int i;
30
31#ifdef FALLBACK_TO_PRAMIN
32 bar0_window_t win;
33 win.raw = nvdebug_readl(g, NV_XAL_EP_BAR0_WINDOW_BASE);
34 inst = g->regs + NV_PRAMIN + addr_to_pramin_mut(g, instance_ptr, instance_target);
35#else
36 if (IS_ERR(inst = instance_deref(g, instance_ptr, instance_target)))
37 return PTR_ERR(ctxsw);
38#endif // FALLBACK_TO_PRAMIN
39 // If unable to access instance block, skip
40 if (!inst)
41 return 0;
42
43 // Print the channel instance block
44 // As an ID, use upper 52 bits of the instance address (lower 12 are zero)
45 //seq_printf(s, "%s+- Inst %-13llx-+\n", prefix, instance_ptr >> 12);
46 seq_printf(s, "%s|= Instance Block ====|\n", prefix);
47 seq_printf(s, "%s| Target Engine: %2d|\n", prefix, inst->fc_target);
48 seq_printf(s, "%s| Privileged: %1d|\n", prefix, inst->fc_config_is_priv);
49 seq_printf(s, "%s| Channel VEID: %2d|\n", prefix, inst->fc_chan_info_veid);
50 seq_printf(s, "%s| WFI PTR: |\n", prefix);
51 seq_printf(s, "%s| %#018llx|\n", prefix, (uint64_t)inst->engine_wfi_ptr << 12);
52 seq_printf(s, "%s| %20s|\n", prefix, target_to_text(inst->engine_wfi_target));
53 seq_printf(s, "%s| Virtual address? %d|\n", prefix, inst->engine_wfi_is_virtual);
54 seq_printf(s, "%s| WFI VEID: %2d|\n", prefix, inst->engine_wfi_veid);
55 seq_printf(s, "%s| All PDB PTR: |\n", prefix);
56 seq_printf(s, "%s| %#018llx|\n", prefix, (u64)inst->pdb.page_dir << 12);
57 seq_printf(s, "%s| %20s|\n", prefix, target_to_text(inst->pdb.target));
58 seq_printf(s, "%s| %20s|\n", prefix, inst->pdb.is_volatile ? "volatile" : "non-volatile");
59// seq_printf(s, "%s|raw: %0#10lx|\n", prefix, inst->pdb.raw);
60 seq_printf(s, "%s| Num subcontexts: %2ld|\n", prefix, hweight64(inst->subcontext_pdb_valid));
61 // Print configuration of every enabled subcontext
62 for (i = 0; i < 64; i++) {
63 // Skip subcontexts without their enable bit set
64 if (!(1 & (inst->subcontext_pdb_valid >> i)))
65 continue;
66 seq_printf(s, "%s| CPU SC%02d ASID%7d|\n", prefix, i, inst->subcontext[i].pasid);
67 seq_printf(s, "%s| SC%02d PDB PTR: |\n", prefix, i);
68 seq_printf(s, "%s| %#018llx|\n", prefix, ((u64)inst->subcontext[i].pdb.page_dir_hi << 32) | ((u64)inst->subcontext[i].pdb.page_dir_lo << 12));
69 seq_printf(s, "%s| %20s|\n", prefix, target_to_text(inst->subcontext[i].pdb.target));
70 seq_printf(s, "%s| %20s|\n", prefix, inst->subcontext[i].pdb.is_volatile ? "volatile" : "non-volatile");
71// seq_printf(s, "%s|raw: %0#10lx|\n", prefix, inst->subcontext[i].pdb.raw);
72 }
73
74 // XXX: CTXSW is only accessible via PRAMIN. Accessing PRAMIN appears to
75 // either be broken, or race with the driver on Kepler (gk104 tested). So,
76 // do not attempt to touch the CTXSW block on Kepler.
77 // TODO: This check should be moved into addr_to_pramin_mut().
78 if (g->chip_id < NV_CHIP_ID_MAXWELL)
79 return 0;
80 // End XXX
81
82 if (IS_ERR(ctxsw = get_ctxsw(g, inst))) {
83#ifdef FALLBACK_TO_PRAMIN
84 nvdebug_writel(g, NV_XAL_EP_BAR0_WINDOW_BASE, win.raw);
85#endif
86 return PTR_ERR(ctxsw);
87 }
88 // If unable to access CTXSW block, skip
89 if (!ctxsw) {
90#ifdef FALLBACK_TO_PRAMIN
91 nvdebug_writel(g, NV_XAL_EP_BAR0_WINDOW_BASE, win.raw);
92#endif
93 return 0;
94 }
95 // Access and print the preemption mode and context ID
96 seq_printf(s, "%s|= Context State =====|\n", prefix);
97 seq_printf(s, "%s| Ctx. ID: %#10x|\n", prefix, ctxsw->context_id);
98 // No other CTXSW fields are supported pre-Pascal
99 if (g->chip_id < NV_CHIP_ID_PASCAL)
100 return 0;
101 seq_printf(s, "%s| Gfx. Preemption:%4s|\n", prefix,
102 graphics_preempt_type_to_text(ctxsw->graphics_preemption_options));
103 seq_printf(s, "%s| Cmp. Preemption:%4s|\n", prefix,
104 compute_preempt_type_to_text(ctxsw->compute_preemption_options));
105 seq_printf(s, "%s| #WFI Saves:%9d|\n", prefix, ctxsw->num_wfi_save_operations);
106 seq_printf(s, "%s| #CTA Saves:%9d|\n", prefix, ctxsw->num_cta_save_operations);
107 seq_printf(s, "%s| #GFXP Saves:%8d|\n", prefix, ctxsw->num_gfxp_save_operations);
108 seq_printf(s, "%s| #CILP Saves:%8d|\n", prefix, ctxsw->num_cilp_save_operations);
109#ifdef FALLBACK_TO_PRAMIN
110 nvdebug_writel(g, NV_XAL_EP_BAR0_WINDOW_BASE, win.raw);
111#endif
112 return 0;
113}
114
10/* Print channel details using PCCSR (Programmable Channel Control System RAM?) 115/* Print channel details using PCCSR (Programmable Channel Control System RAM?)
11 @param s Pointer to state from seq_file subsystem to pass to seq_printf 116 @param s Pointer to state from seq_file subsystem to pass to seq_printf
12 @param g Pointer to our internal GPU state 117 @param g Pointer to our internal GPU state
@@ -32,16 +137,19 @@ static int runlist_detail_seq_show_chan(struct seq_file *s, struct nvdebug_state
32 seq_printf(s, "%s| %#018llx|\n", prefix, instance_ptr); 137 seq_printf(s, "%s| %#018llx|\n", prefix, instance_ptr);
33 seq_printf(s, "%s| %20s|\n", prefix, target_to_text(chan.inst_target)); 138 seq_printf(s, "%s| %20s|\n", prefix, target_to_text(chan.inst_target));
34 seq_printf(s, "%s| Instance bound: %d|\n", prefix, chan.inst_bind); 139 seq_printf(s, "%s| Instance bound: %d|\n", prefix, chan.inst_bind);
35 return 0; 140 // Print instance block
141 return runlist_detail_seq_show_inst(s, g, prefix, instance_ptr, chan.inst_target);
36} 142}
37 143
38/* `runlist_detail_seq_show_chan()`, but for Ampere+ 144/* `runlist_detail_seq_show_chan()`, but for Ampere+
145 @param instance_ptr Address for the channel instance block
146 @param instance_target Aperture of `instance_ptr`
39 @param runlist_pri_base Base of the RLRAM region for this runlist 147 @param runlist_pri_base Base of the RLRAM region for this runlist
40 148
41 `runlist_pri_base` is necessary, since Channel RAM is now per-runlist on 149 `runlist_pri_base` is necessary, since Channel RAM is now per-runlist on
42 Ampere+, and its location is configured in Runlist RAM. 150 Ampere+, and its location is configured in Runlist RAM.
43*/ 151*/
44static int runlist_detail_seq_show_chan_ga100(struct seq_file *s, struct nvdebug_state *g, uint32_t chid, char *prefix, uint32_t runlist_pri_base) { 152static int runlist_detail_seq_show_chan_ga100(struct seq_file *s, struct nvdebug_state *g, uint32_t chid, char *prefix, uint32_t runlist_pri_base, uint64_t instance_ptr, enum INST_TARGET instance_target) {
45 runlist_channel_config_t channel_config; 153 runlist_channel_config_t channel_config;
46 channel_ctrl_ga100_t chan; 154 channel_ctrl_ga100_t chan;
47 155
@@ -63,7 +171,7 @@ static int runlist_detail_seq_show_chan_ga100(struct seq_file *s, struct nvdebug
63 seq_printf(s, "%s| PBDMA Busy: %d|\n", prefix, chan.pbdma_busy); 171 seq_printf(s, "%s| PBDMA Busy: %d|\n", prefix, chan.pbdma_busy);
64 seq_printf(s, "%s| ENG Busy: %d|\n", prefix, chan.eng_busy); 172 seq_printf(s, "%s| ENG Busy: %d|\n", prefix, chan.eng_busy);
65 seq_printf(s, "%s| Acquire Fail: %d|\n", prefix, chan.acquire_fail); 173 seq_printf(s, "%s| Acquire Fail: %d|\n", prefix, chan.acquire_fail);
66 return 0; 174 return runlist_detail_seq_show_inst(s, g, prefix, instance_ptr, instance_target);
67} 175}
68#endif 176#endif
69 177
@@ -173,7 +281,7 @@ static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) {
173 if (g->chip_id < NV_CHIP_ID_AMPERE) 281 if (g->chip_id < NV_CHIP_ID_AMPERE)
174 runlist_detail_seq_show_chan(s, g, chid(g, entry), indt); 282 runlist_detail_seq_show_chan(s, g, chid(g, entry), indt);
175 else 283 else
176 runlist_detail_seq_show_chan_ga100(s, g, chid(g, entry), indt, rl_iter->runlist_pri_base); 284 runlist_detail_seq_show_chan_ga100(s, g, chid(g, entry), indt, rl_iter->runlist_pri_base, instance_ptr, inst_target(g, entry));
177#endif 285#endif
178 seq_printf(s, "%s+---------------------+\n", indt); 286 seq_printf(s, "%s+---------------------+\n", indt);
179 } 287 }
@@ -232,15 +340,17 @@ struct file_operations preempt_tsg_file_ops = {
232 340
233ssize_t resubmit_runlist_file_write(struct file *f, const char __user *buffer, 341ssize_t resubmit_runlist_file_write(struct file *f, const char __user *buffer,
234 size_t count, loff_t *off) { 342 size_t count, loff_t *off) {
235 uint32_t target_runlist; 343 uint32_t target_runlist, target_offset;
236 struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; 344 struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)];
237 // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec 345 // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec
238 int err = kstrtou32_from_user(buffer, count, 0, &target_runlist); 346 int err = kstrtou32_from_user(buffer, count, 0, &target_offset);
239 if (err) 347 if (err)
240 return err; 348 return err;
349 // (Ab)use the PDE_DATA field for the runlist ID
350 target_runlist = file2gpuidx(f);
241 351
242 // resubmit_runlist() checks that target_runlist is valid 352 // resubmit_runlist() checks that target_runlist is valid
243 if ((err = resubmit_runlist(g, target_runlist))) 353 if ((err = resubmit_runlist(g, target_runlist, target_offset)))
244 return err; 354 return err;
245 355
246 return count; 356 return count;
@@ -351,6 +461,54 @@ struct file_operations enable_channel_file_ops = {
351 .llseek = default_llseek, 461 .llseek = default_llseek,
352}; 462};
353 463
464ssize_t comm_preempt_channel_file_write(struct file *f, const char __user *buf,
465 size_t count, loff_t *off,
466 enum COMPUTE_PREEMPT_TYPE mode) {
467 uint32_t target_channel, target_runlist;
468 struct nvdebug_state *g = &g_nvdebug_state[file2parentgpuidx(f)];
469 // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec
470 int err = kstrtou32_from_user(buf, count, 0, &target_channel);
471 if (err)
472 return err;
473 // (Ab)use the PDE_DATA field used by file2gpuidx() for the runlist ID
474 target_runlist = file2gpuidx(f);
475 // Set preemption mode for the context of this channel