diff options
Diffstat (limited to 'nvdebug_entry.c')
| -rw-r--r-- | nvdebug_entry.c | 476 |
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; | |||
| 28 | extern struct file_operations preempt_tsg_file_ops; | 28 | extern struct file_operations preempt_tsg_file_ops; |
| 29 | extern struct file_operations disable_channel_file_ops; | 29 | extern struct file_operations disable_channel_file_ops; |
| 30 | extern struct file_operations enable_channel_file_ops; | 30 | extern struct file_operations enable_channel_file_ops; |
| 31 | extern struct file_operations wfi_preempt_channel_file_ops; | ||
| 32 | extern struct file_operations cta_preempt_channel_file_ops; | ||
| 33 | extern struct file_operations cil_preempt_channel_file_ops; | ||
| 31 | extern struct file_operations resubmit_runlist_file_ops; | 34 | extern struct file_operations resubmit_runlist_file_ops; |
| 35 | extern struct file_operations preempt_runlist_file_ops; | ||
| 36 | extern struct file_operations ack_bad_tsg_file_ops; | ||
| 37 | extern struct file_operations map_mem_chid_file_ops; | ||
| 38 | extern struct file_operations map_mem_ctxid_file_ops; | ||
| 32 | extern struct file_operations switch_to_tsg_file_ops; | 39 | extern struct file_operations switch_to_tsg_file_ops; |
| 33 | // device_info_procfs.c | 40 | // device_info_procfs.c |
| 34 | extern struct file_operations device_info_file_ops; | 41 | extern struct file_operations device_info_file_ops; |
| 35 | extern struct file_operations nvdebug_read_reg32_file_ops; | 42 | extern struct file_operations nvdebug_read_reg32_file_ops; |
| 36 | extern struct file_operations nvdebug_read_reg_range_file_ops; | 43 | extern struct file_operations nvdebug_read_reg_range_file_ops; |
| 44 | extern struct file_operations nvdebug_read_part_file_ops; | ||
| 37 | extern struct file_operations local_memory_file_ops; | 45 | extern struct file_operations local_memory_file_ops; |
| 38 | // copy_topology_procfs.c | 46 | // copy_topology_procfs.c |
| 39 | extern struct file_operations copy_topology_file_ops; | 47 | extern 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 | |||
| 84 | void 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 | |||
| 75 | irqreturn_t nvdebug_irq_tap(int irq_num, void * dev) { | 128 | irqreturn_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 | ||
