aboutsummaryrefslogtreecommitdiffstats
path: root/nvdebug_entry.c
diff options
context:
space:
mode:
Diffstat (limited to 'nvdebug_entry.c')
-rw-r--r--nvdebug_entry.c476
1 files changed, 459 insertions, 17 deletions
diff --git a/nvdebug_entry.c b/nvdebug_entry.c
index 3a10e13..c0cfa63 100644
--- a/nvdebug_entry.c
+++ b/nvdebug_entry.c
@@ -15,7 +15,7 @@
15 15
16// Enable to intercept and log GPU interrupts. Historically used to benchmark 16// Enable to intercept and log GPU interrupts. Historically used to benchmark
17// interrupt latency. 17// interrupt latency.
18#define INTERRUPT_DEBUG 0 18#define INTERRUPT_DEBUG
19 19
20// MIT is GPL-compatible. We need to be GPL-compatible for symbols like 20// MIT is GPL-compatible. We need to be GPL-compatible for symbols like
21// platform_bus_type or bus_find_device_by_name... 21// platform_bus_type or bus_find_device_by_name...
@@ -28,12 +28,20 @@ extern struct file_operations runlist_file_ops;
28extern struct file_operations preempt_tsg_file_ops; 28extern struct file_operations preempt_tsg_file_ops;
29extern struct file_operations disable_channel_file_ops; 29extern struct file_operations disable_channel_file_ops;
30extern struct file_operations enable_channel_file_ops; 30extern struct file_operations enable_channel_file_ops;
31extern struct file_operations wfi_preempt_channel_file_ops;
32extern struct file_operations cta_preempt_channel_file_ops;
33extern struct file_operations cil_preempt_channel_file_ops;
31extern struct file_operations resubmit_runlist_file_ops; 34extern struct file_operations resubmit_runlist_file_ops;
35extern struct file_operations preempt_runlist_file_ops;
36extern struct file_operations ack_bad_tsg_file_ops;
37extern struct file_operations map_mem_chid_file_ops;
38extern struct file_operations map_mem_ctxid_file_ops;
32extern struct file_operations switch_to_tsg_file_ops; 39extern struct file_operations switch_to_tsg_file_ops;
33// device_info_procfs.c 40// device_info_procfs.c
34extern struct file_operations device_info_file_ops; 41extern struct file_operations device_info_file_ops;
35extern struct file_operations nvdebug_read_reg32_file_ops; 42extern struct file_operations nvdebug_read_reg32_file_ops;
36extern struct file_operations nvdebug_read_reg_range_file_ops; 43extern struct file_operations nvdebug_read_reg_range_file_ops;
44extern struct file_operations nvdebug_read_part_file_ops;
37extern struct file_operations local_memory_file_ops; 45extern struct file_operations local_memory_file_ops;
38// copy_topology_procfs.c 46// copy_topology_procfs.c
39extern struct file_operations copy_topology_file_ops; 47extern struct file_operations copy_topology_file_ops;
@@ -71,9 +79,271 @@ const struct file_operations* compat_ops(const struct file_operations* ops) {
71} 79}
72#endif 80#endif
73 81
74#if INTERRUPT_DEBUG 82#ifdef INTERRUPT_DEBUG
83
84void nvdebug_fifo_intr(struct nvdebug_state *g) {
85 uint32_t fifo_intr_mask;// = nvdebug_readl(g, 0x02100); // PFIFO_INTR_0
86 fifo_intr_mask = nvdebug_readl(g, 0x02100); // PFIFO_INTR_0
87 if (fifo_intr_mask & 1 << 0)
88 printk(KERN_INFO "[nvdebug] - Interrupt BIND_ERROR.\n");
89 if (fifo_intr_mask & 1 << 1)
90 printk(KERN_INFO "[nvdebug] - Interrupt CTXSW_TIMEOUT.\n");
91 if (fifo_intr_mask & 1 << 4)
92 printk(KERN_INFO "[nvdebug] - Interrupt RUNLIST_IDLE.\n");
93 if (fifo_intr_mask & 1 << 5)
94 printk(KERN_INFO "[nvdebug] - Interrupt RUNLIST_AND_ENG_IDLE.\n");
95 if (fifo_intr_mask & 1 << 6)
96 printk(KERN_INFO "[nvdebug] - Interrupt RUNLIST_ACQUIRE.\n");
97 if (fifo_intr_mask & 1 << 7)
98 printk(KERN_INFO "[nvdebug] - Interrupt RUNLIST_ACQUIRE_AND_ENG_IDLE.\n");
99 if (fifo_intr_mask & 1 << 8)
100 printk(KERN_INFO "[nvdebug] - Interrupt SCHED_ERROR.\n");
101 if (fifo_intr_mask & 1 << 16)
102 printk(KERN_INFO "[nvdebug] - Interrupt CHSW_ERROR.\n");
103 if (fifo_intr_mask & 1 << 23)
104 printk(KERN_INFO "[nvdebug] - Interrupt MEMOP_TIMEOUT.\n");
105 if (fifo_intr_mask & 1 << 24)
106 printk(KERN_INFO "[nvdebug] - Interrupt LB_ERROR.\n");
107 if (fifo_intr_mask & 1 << 25) // OLD; Pascal
108 printk(KERN_INFO "[nvdebug] - Interrupt REPLAYABLE_FAULT_ERROR.\n");
109 if (fifo_intr_mask & 1 << 27) // OLD; Pascal
110 printk(KERN_INFO "[nvdebug] - Interrupt DROPPED_MMU_FAULT.\n");
111 if (fifo_intr_mask & 1 << 28) { // On Pascal, this is MMU_FAULT
112 if (g->chip_id <= NV_CHIP_ID_VOLTA) // MMU_FAULT on Pascal (nvgpu, l4t/l4t-r28.1:drivers/gpu/nvgpu/include/nvgpu/hw/gp10b/hw_fifo_gp10b.h)
113 printk(KERN_INFO "[nvdebug] - Interrupt MMU_FAULT.\n");
114 else // Repurposed starting with Turing: open-gpu-doc/manuals/turing/tu104/dev_fifo.ref.txt
115 printk(KERN_INFO "[nvdebug] - Interrupt TSG_PREEMPT_COMPLETE.\n");
116 }
117 if (fifo_intr_mask & 1 << 29)
118 printk(KERN_INFO "[nvdebug] - Interrupt PBDMA_INTR.\n");
119 if (fifo_intr_mask & 1 << 30) {
120 printk(KERN_INFO "[nvdebug] - Interrupt RUNLIST_EVENT.\n");
121 uint32_t fifo_runlist_intr_mask = nvdebug_readl(g, 0x02A00); // PFIFO_INTR_RUNLIST
122 printk(KERN_INFO "[nvdebug] - Event %#x.\n", fifo_runlist_intr_mask);
123 }
124 if (fifo_intr_mask & 1 << 31)
125 printk(KERN_INFO "[nvdebug] - Interrupt CHANNEL_INTR.\n");
126}
127
75irqreturn_t nvdebug_irq_tap(int irq_num, void * dev) { 128irqreturn_t nvdebug_irq_tap(int irq_num, void * dev) {
76 printk(KERN_INFO "[nvdebug] Interrupt tap triggered on IRQ %d.\n", irq_num); 129 struct nvdebug_state *g = dev;
130 u64 time = ktime_get_raw_ns(); // CLOCK_MONOTONTIC_RAW
131 // NV_PMC_INTR does not exist on Ada, so use NV_FUNC_PRIV_CPU_INTR_TOP
132 // Note that this also appears to exist on Turing
133 if (g->chip_id >= NV_CHIP_ID_TURING) {//AMPERE) {
134 int i;
135 // Despite being an indexed register, it is only documented to have on, and could only support two
136 uint32_t intr_mask0 = nvdebug_readl(g, NV_VIRTUAL_FUNCTION_FULL_PHYS_OFFSET + 0x1600); // NV_FUNC_PRIV_CPU_INTR_TOP(0)
137 uint32_t intr_mask1 = nvdebug_readl(g, NV_VIRTUAL_FUNCTION_FULL_PHYS_OFFSET + 0x1604); // NV_FUNC_PRIV_CPU_INTR_TOP(1)
138 printk(KERN_INFO "[nvdebug] Interrupt on IRQ %d with CPU_INTR_TOP(0) %#010x, ...(1) %#010x @ %llu.\n", irq_num, intr_mask0, intr_mask1, time);
139 for (i = 0; i < 8; i++) {
140 uint32_t leaf = nvdebug_readl(g, NV_VIRTUAL_FUNCTION_FULL_PHYS_OFFSET + 0x1000 + i*4); // NV_FUNC_PRIV_CPU_INTR_LEAF(0) to ...(7)
141 if (leaf)
142 printk(KERN_INFO "[nvdebug] - Interrupt leaf %d: %#010x\n", i, leaf);
143 // 131-133 & 64 are faults on tu104??? (open-gpu-doc/manuals/turing/tu104/pri_mmu_hub.ref.txt)
144 if (136 / 32 == i && 1 << (136 % 32) & leaf) // PFIFO0 ga100
145 printk(KERN_INFO "[nvdebug] - Interrupt on PFIFO0.\n");
146 if (137 / 32 == i && 1 << (137 % 32) & leaf) // PFIFO1 ga100
147 printk(KERN_INFO "[nvdebug] - Interrupt on PFIFO1.\n");
148 if (148 / 32 == i && 1 << (148 % 32) & leaf) // TIMER ga100
149 printk(KERN_INFO "[nvdebug] - Interrupt on PTIMER.\n");
150 if (152 / 32 == i && 1 << (152 % 32) & leaf) // PMU ga100
151 printk(KERN_INFO "[nvdebug] - Interrupt on PMU.\n");
152 if (156 / 32 == i && 1 << (156 % 32) & leaf) { // PBUS ga100
153 printk(KERN_INFO "[nvdebug] - Interrupt on PBUS.\n");
154 uint32_t bus_intr = nvdebug_readl(g, 0x1100); // BUS_INTR_0
155 if (bus_intr & 1 << 2) {
156 // use timer_pri_timeout_save_0_r
157 uint32_t SAVE_0 = nvdebug_readl(g, 0x00009084); // NV_PTIMER_PRI_TIMEOUT_SAVE_0
158 printk(KERN_INFO "[nvdebug] - Interrupt PRI_FECSERR on %s to address %#010x %stargeting FECS.\n", SAVE_0 & 0x2 ? "write" : "read", SAVE_0 & 0x00fffffc, SAVE_0 & 0x80000000 ? "" : "not ");
159 uint32_t SAVE_1 = nvdebug_readl(g, 0x00009088); // NV_PTIMER_PRI_TIMEOUT_SAVE_1
160 if (SAVE_1)
161 printk(KERN_INFO "[nvdebug] Data written: %#010x\n", SAVE_1);
162 uint32_t errcode = readl(g->regs + 0x0000908C); // NV_PTIMER_PRI_TIMEOUT_FECS_ERRCODE
163 if (errcode)
164 printk(KERN_INFO "[nvdebug] FECS Error Code: %#010x\n", errcode);
165 // badf5040 is a "client error" (0) of "no such address" (40)
166 // See linux-nvgpu/drivers/gpu/nvgpu/hal/priv_ring/priv_ring_ga10b_fusa.c
167 // for how to decode.
168 }
169 if (bus_intr & 1 << 3)
170 printk(KERN_INFO "[nvdebug] - Interrupt PRI_TIMEOUT.\n");
171 if (bus_intr & 1 << 4)
172 printk(KERN_INFO "[nvdebug] - Interrupt FB_REQ_TIMEOUT.\n");
173 if (bus_intr & 1 << 5)
174 printk(KERN_INFO "[nvdebug] - Interrupt FB_ACK_TIMEOUT.\n");
175 if (bus_intr & 1 << 6)
176 printk(KERN_INFO "[nvdebug] - Interrupt FB_ACK_EXTRA.\n");
177 if (bus_intr & 1 << 7)
178 printk(KERN_INFO "[nvdebug] - Interrupt FB_RDATA_TIMEOUT.\n");
179 if (bus_intr & 1 << 8)
180 printk(KERN_INFO "[nvdebug] - Interrupt FB_RDATA_EXTRA.\n");
181 if (bus_intr & 1 << 26)
182 printk(KERN_INFO "[nvdebug] - Interrupt SW.\n");
183 if (bus_intr & 1 << 27)
184 printk(KERN_INFO "[nvdebug] - Interrupt POSTED_DEADLOCK_TIMEOUT.\n");
185 if (bus_intr & 1 << 28)
186 printk(KERN_INFO "[nvdebug] - Interrupt MPMU.\n");
187 if (bus_intr & 1 << 31)
188 printk(KERN_INFO "[nvdebug] - Interrupt ACCESS_TIMEOUT.\n");
189 }
190 if (158 / 32 == i && 1 << (158 % 32) & leaf) // PRIV_RING ga100
191 printk(KERN_INFO "[nvdebug] - Interrupt on PRIV_RING.\n");
192 if (192 / 32 == i && 1 << (192 % 32) & leaf) // LEGACY_ENGINE_STALL ga100
193 printk(KERN_INFO "[nvdebug] - Interrupt on LEGACY_ENGINE_STALL.\n");
194 if (160 / 32 == i && 1 << (160 % 32) & leaf) { // (likely) rl0 ga100
195 printk(KERN_INFO "[nvdebug] - Interrupt on RUNLIST0.\n");
196 uint32_t off;
197 get_runlist_ram(g, 0, &off);
198 uint32_t rl_intr = nvdebug_readl(g, off+0x100);
199 printk(KERN_INFO "[nvdebug] - RUNLIST_INTR_0: %#x\n", rl_intr);
200 if (1 << 12 && rl_intr) { // BAD_TSG
201 printk(KERN_INFO "[nvdebug] - BAD_TSG: %#x\n", nvdebug_readl(g, off+0x174));
202 }
203 }
204 // Also getting 160, 161, and 162
205
206 //uint32_t off;
207 //get_runlist_ram(g, 12, &off);
208 //printk(KERN_INFO "[nvdebug] - rl10 vector id 0 is %x\n", nvdebug_readl(g, off+0x160)); // NV_RUNLIST_INTR_VECTORID(0)
209 // 160 is rl0 (C/G, LCE0, LCE1) vector id 0
210 // 168 is rl11 (LCE3) vector id 0
211 // 169 is rl12 (LCE4) vector id 0
212 // 171 is rl1 (SEC) vector id 0
213 // 176 is rl10 (LCE2) vector id 0
214 // 224 is rl0 vector id 1
215 // Only some interrupt vectors are hardcoded
216 }
217 // each subtree has two leafs? Each bit at the top corresponds to a subtree?
218 // So, if bit 0 is set, that means subtree 0 (concept) and leaves 0 and 1
219 // So, if bit 1 is set, that means subtree 1 (concept) and leaves 2 and 3
220 // the #define'd interrupt vectors all seem to fall in the lower leaf of subtree 2,
221 // except for INTR_HUB_ACCESS_CNTR_INTR_VECTOR is in the lower leaf of subtree 1
222 if (g->chip_id >= NV_CHIP_ID_AMPERE)
223 return IRQ_NONE;
224 }
225 uint32_t intr_mask = nvdebug_readl(g, 0x0100); // NV_PMC_INTR
226 printk(KERN_INFO "[nvdebug] Interrupt on IRQ %d with MC_INTR %#010x @ %llu.\n", irq_num, intr_mask, time);
227 // IDs likely changed Ampere+
228 //if (g->chip_id >= NV_CHIP_ID_AMPERE) {
229 // CIC is central interrupt controller
230 // the u32 passed around nvgpu cic functions is one of the
231 // enable is nvgpu_cic_mon_intr_stall_unit_config(unit)
232 // - Calls intr_stall_unit_config(unit)
233 // - for ga, calls unit = ga10b_intr_map_mc_stall_unit_to_intr_unit(unit) (doesn't do much)
234 // - for ga, calls nvgpu_cic_mon_intr_get_unit_info()
235 // - Does *subtree = g->mc.intr_unit_info[unit].subtree;
236 // *subtree_mask = g->mc.intr_unit_info[unit].subtree_mask;
237 // - for ga, calls ga10b_intr_config() w/ subtree info
238 //uint32_t intr_stats = nvdebug_readl(g, 1600
239 //return IRQ_NONE;