diff options
Diffstat (limited to 'nvdebug_entry.c')
-rw-r--r-- | nvdebug_entry.c | 68 |
1 files changed, 44 insertions, 24 deletions
diff --git a/nvdebug_entry.c b/nvdebug_entry.c index fa35fb2..60fb7af 100644 --- a/nvdebug_entry.c +++ b/nvdebug_entry.c | |||
@@ -18,19 +18,38 @@ MODULE_LICENSE("Dual MIT/GPL"); | |||
18 | MODULE_AUTHOR("Joshua Bakita"); | 18 | MODULE_AUTHOR("Joshua Bakita"); |
19 | MODULE_DESCRIPTION("A scheduling debugging module for NVIDIA GPUs"); | 19 | MODULE_DESCRIPTION("A scheduling debugging module for NVIDIA GPUs"); |
20 | 20 | ||
21 | extern const struct file_operations runlist_file_ops; | 21 | extern struct file_operations runlist_file_ops; |
22 | extern const struct file_operations preempt_tsg_file_ops; | 22 | extern struct file_operations preempt_tsg_file_ops; |
23 | extern const struct file_operations disable_channel_file_ops; | 23 | extern struct file_operations disable_channel_file_ops; |
24 | extern const struct file_operations enable_channel_file_ops; | 24 | extern struct file_operations enable_channel_file_ops; |
25 | extern const struct file_operations switch_to_tsg_file_ops; | 25 | extern struct file_operations switch_to_tsg_file_ops; |
26 | extern const struct file_operations device_info_file_ops; | 26 | extern struct file_operations device_info_file_ops; |
27 | extern const struct file_operations nvdebug_read_reg32_file_ops; | 27 | extern struct file_operations nvdebug_read_reg32_file_ops; |
28 | 28 | ||
29 | // Bus types are global symbols in the kernel | 29 | // Bus types are global symbols in the kernel |
30 | extern struct bus_type platform_bus_type; | 30 | extern struct bus_type platform_bus_type; |
31 | struct nvdebug_state g_nvdebug_state[NVDEBUG_MAX_DEVICES]; | 31 | struct nvdebug_state g_nvdebug_state[NVDEBUG_MAX_DEVICES]; |
32 | unsigned int g_nvdebug_devices = 0; | 32 | unsigned int g_nvdebug_devices = 0; |
33 | 33 | ||
34 | // Starting in Kernel 5.6, proc_ops is required instead of file_operations | ||
35 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) | ||
36 | // This rewrites the struct to the proc_ops layout on newer kernels | ||
37 | const struct proc_ops* compat_ops(const struct file_operations* ops) { | ||
38 | struct proc_ops new_ops; | ||
39 | new_ops.proc_open = ops->open; | ||
40 | new_ops.proc_read = ops->read; | ||
41 | new_ops.proc_write = ops->write; | ||
42 | new_ops.proc_lseek = ops->llseek; | ||
43 | new_ops.proc_release = ops->release; | ||
44 | memcpy((void*)ops, &new_ops, sizeof(new_ops)); | ||
45 | return (struct proc_ops*)ops; | ||
46 | } | ||
47 | #else | ||
48 | const struct file_operations* compat_ops(const struct file_operations* ops) { | ||
49 | return ops; | ||
50 | } | ||
51 | #endif | ||
52 | |||
34 | // TEMP | 53 | // TEMP |
35 | irqreturn_t nvdebug_irq_tap(int irq_num, void * dev) { | 54 | irqreturn_t nvdebug_irq_tap(int irq_num, void * dev) { |
36 | printk(KERN_INFO "[nvdebug] Interrupt tap triggered on IRQ %d.\n", irq_num); | 55 | printk(KERN_INFO "[nvdebug] Interrupt tap triggered on IRQ %d.\n", irq_num); |
@@ -56,19 +75,20 @@ int probe_and_cache_device(void) { | |||
56 | }; | 75 | }; |
57 | int i = 0; | 76 | int i = 0; |
58 | // Search the platform bus for the first device that matches our name | 77 | // Search the platform bus for the first device that matches our name |
59 | // Search for GV10B (Jetson Xavier) | 78 | // Search for GA10B (Jetson Orin) |
79 | while (!dev && (temp_dev = bus_find_device_by_name(&platform_bus_type, dev, "17000000.ga10b"))) | ||
80 | dev = temp_dev; | ||
81 | // Search for GV11B (Jetson Xavier) | ||
60 | while (!dev && (temp_dev = bus_find_device_by_name(&platform_bus_type, dev, "17000000.gv11b"))) | 82 | while (!dev && (temp_dev = bus_find_device_by_name(&platform_bus_type, dev, "17000000.gv11b"))) |
61 | dev = temp_dev; | 83 | dev = temp_dev; |
62 | // Search for GP10B (Jetson TX2) | 84 | // Search for GP10B (Jetson TX2) |
63 | while (!dev && (temp_dev = bus_find_device_by_name(&platform_bus_type, dev, "17000000.gp10b"))) | 85 | while (!dev && (temp_dev = bus_find_device_by_name(&platform_bus_type, dev, "17000000.gp10b"))) |
64 | dev = temp_dev; | 86 | dev = temp_dev; |
65 | // TODO: Support other platform bus devices (gk20a, gm20b) | 87 | // TODO: Support other platform bus devices (gk20a - TK1, gm20b - TX1) |
66 | if (dev) { | 88 | if (dev) { |
67 | struct nvgpu_os_linux *l; | ||
68 | mc_boot_0_t ids; | 89 | mc_boot_0_t ids; |
69 | g_nvdebug_state[i].g = get_gk20a(dev); | 90 | g_nvdebug_state[i].g = get_gk20a(dev); |
70 | l = container_of(g_nvdebug_state[i].g, struct nvgpu_os_linux, g); | 91 | g_nvdebug_state[i].regs = gk20a_regs(g_nvdebug_state[i].g); |
71 | g_nvdebug_state[i].regs = l->regs; | ||
72 | if (!g_nvdebug_state[i].regs) | 92 | if (!g_nvdebug_state[i].regs) |
73 | return -EADDRNOTAVAIL; | 93 | return -EADDRNOTAVAIL; |
74 | ids.raw = nvdebug_readl(&g_nvdebug_state[i], NV_MC_BOOT_0); | 94 | ids.raw = nvdebug_readl(&g_nvdebug_state[i], NV_MC_BOOT_0); |
@@ -139,7 +159,7 @@ int create_runlist_files(int device_id, struct proc_dir_entry *dir) { | |||
139 | for (rl_id = 0; rl_id <= max_rl_id; rl_id++) { | 159 | for (rl_id = 0; rl_id <= max_rl_id; rl_id++) { |
140 | snprintf(runlist_name, 12, "runlist%d", rl_id); | 160 | snprintf(runlist_name, 12, "runlist%d", rl_id); |
141 | rl_entry = proc_create_data( | 161 | rl_entry = proc_create_data( |
142 | runlist_name, 0444, dir, &runlist_file_ops, | 162 | runlist_name, 0444, dir, compat_ops(&runlist_file_ops), |
143 | (void*)(uintptr_t)rl_id); | 163 | (void*)(uintptr_t)rl_id); |
144 | if (!rl_entry) | 164 | if (!rl_entry) |
145 | return -ENOMEM; | 165 | return -ENOMEM; |
@@ -165,7 +185,7 @@ int create_tpc_mask_files(int device_id, struct proc_dir_entry *dir) { | |||
165 | // If GPC is enabled, create an entry to read disabled TPCs mask | 185 | // If GPC is enabled, create an entry to read disabled TPCs mask |
166 | snprintf(file_name, 20, "gpc%d_tpc_mask", i); | 186 | snprintf(file_name, 20, "gpc%d_tpc_mask", i); |
167 | gpc_tpc_mask_entry = proc_create_data( | 187 | gpc_tpc_mask_entry = proc_create_data( |
168 | file_name, 0444, dir, &nvdebug_read_reg32_file_ops, | 188 | file_name, 0444, dir, compat_ops(&nvdebug_read_reg32_file_ops), |
169 | (void*)(uintptr_t)NV_FUSE_TPC_FOR_GPC(i)); | 189 | (void*)(uintptr_t)NV_FUSE_TPC_FOR_GPC(i)); |
170 | if (!gpc_tpc_mask_entry) | 190 | if (!gpc_tpc_mask_entry) |
171 | return -ENOMEM; | 191 | return -ENOMEM; |
@@ -197,46 +217,46 @@ int __init nvdebug_init(void) { | |||
197 | tpc_masks_create_err = create_tpc_mask_files(device_id, dir); | 217 | tpc_masks_create_err = create_tpc_mask_files(device_id, dir); |
198 | // Create file `/proc/gpu#/preempt_tsg`, world writable | 218 | // Create file `/proc/gpu#/preempt_tsg`, world writable |
199 | preempt_entry = proc_create_data( | 219 | preempt_entry = proc_create_data( |
200 | "preempt_tsg", 0222, dir, &preempt_tsg_file_ops, | 220 | "preempt_tsg", 0222, dir, compat_ops(&preempt_tsg_file_ops), |
201 | (void*)device_id); | 221 | (void*)device_id); |
202 | // Create file `/proc/gpu#/disable_channel`, world writable | 222 | // Create file `/proc/gpu#/disable_channel`, world writable |
203 | disable_channel_entry = proc_create_data( | 223 | disable_channel_entry = proc_create_data( |
204 | "disable_channel", 0222, dir, &disable_channel_file_ops, | 224 | "disable_channel", 0222, dir, compat_ops(&disable_channel_file_ops), |
205 | (void*)device_id); | 225 | (void*)device_id); |
206 | // Create file `/proc/gpu#/enable_channel`, world writable | 226 | // Create file `/proc/gpu#/enable_channel`, world writable |
207 | enable_channel_entry = proc_create_data( | 227 | enable_channel_entry = proc_create_data( |
208 | "enable_channel", 0222, dir, &enable_channel_file_ops, | 228 | "enable_channel", 0222, dir, compat_ops(&enable_channel_file_ops), |
209 | (void*)device_id); | 229 | (void*)device_id); |
210 | // Create file `/proc/gpu#/switch_to_tsg`, world writable | 230 | // Create file `/proc/gpu#/switch_to_tsg`, world writable |
211 | switch_to_tsg_entry = proc_create_data( | 231 | switch_to_tsg_entry = proc_create_data( |
212 | "switch_to_tsg", 0222, dir, &switch_to_tsg_file_ops, | 232 | "switch_to_tsg", 0222, dir, compat_ops(&switch_to_tsg_file_ops), |
213 | (void*)device_id); | 233 | (void*)device_id); |
214 | // Create file `/proc/gpu#/device_info`, world readable | 234 | // Create file `/proc/gpu#/device_info`, world readable |
215 | device_info_entry = proc_create_data( | 235 | device_info_entry = proc_create_data( |
216 | "device_info", 0444, dir, &device_info_file_ops, | 236 | "device_info", 0444, dir, compat_ops(&device_info_file_ops), |
217 | (void*)device_id); | 237 | (void*)device_id); |
218 | // Create file `/proc/gpu#/num_gpcs`, world readable | 238 | // Create file `/proc/gpu#/num_gpcs`, world readable |
219 | num_gpcs_entry = proc_create_data( | 239 | num_gpcs_entry = proc_create_data( |
220 | "num_gpcs", 0444, dir, &nvdebug_read_reg32_file_ops, | 240 | "num_gpcs", 0444, dir, compat_ops(&nvdebug_read_reg32_file_ops), |
221 | (void*)NV_PTOP_SCAL_NUM_GPCS); | 241 | (void*)NV_PTOP_SCAL_NUM_GPCS); |
222 | // Create file `/proc/gpu#/num_tpc_per_gpc`, world readable | 242 | // Create file `/proc/gpu#/num_tpc_per_gpc`, world readable |
223 | num_gpcs_entry = proc_create_data( | 243 | num_gpcs_entry = proc_create_data( |
224 | "num_tpc_per_gpc", 0444, dir, &nvdebug_read_reg32_file_ops, | 244 | "num_tpc_per_gpc", 0444, dir, compat_ops(&nvdebug_read_reg32_file_ops), |
225 | (void*)NV_PTOP_SCAL_NUM_TPC_PER_GPC); | 245 | (void*)NV_PTOP_SCAL_NUM_TPC_PER_GPC); |
226 | // Create file `/proc/gpu#/num_ces`, world readable | 246 | // Create file `/proc/gpu#/num_ces`, world readable |
227 | num_gpcs_entry = proc_create_data( | 247 | num_gpcs_entry = proc_create_data( |
228 | "num_ces", 0444, dir, &nvdebug_read_reg32_file_ops, | 248 | "num_ces", 0444, dir, compat_ops(&nvdebug_read_reg32_file_ops), |
229 | (void*)NV_PTOP_SCAL_NUM_CES); | 249 | (void*)NV_PTOP_SCAL_NUM_CES); |
230 | // Create file `/proc/gpu#/num_ces`, world readable | 250 | // Create file `/proc/gpu#/num_ces`, world readable |
231 | num_gpcs_entry = proc_create_data( | 251 | num_gpcs_entry = proc_create_data( |
232 | "gpc_mask", 0444, dir, &nvdebug_read_reg32_file_ops, | 252 | "gpc_mask", 0444, dir, compat_ops(&nvdebug_read_reg32_file_ops), |
233 | (void*)NV_FUSE_GPC); | 253 | (void*)NV_FUSE_GPC); |
234 | // In both nouveau and nvgpu, the PCE_MAP register is only available on Volta+ | 254 | // In both nouveau and nvgpu, the PCE_MAP register is only available on Volta+ |
235 | if (g_nvdebug_state[res].chip_id >= NV_CHIP_ID_VOLTA) { | 255 | if (g_nvdebug_state[res].chip_id >= NV_CHIP_ID_VOLTA) { |
236 | // TODO: Redo to num_pces | 256 | // TODO: Redo to num_pces |
237 | // Create file `/proc/gpu#/pce_map`, world readable | 257 | // Create file `/proc/gpu#/pce_map`, world readable |
238 | num_gpcs_entry = proc_create_data( | 258 | num_gpcs_entry = proc_create_data( |
239 | "pce_map", 0444, dir, &nvdebug_read_reg32_file_ops, | 259 | "pce_map", 0444, dir, compat_ops(&nvdebug_read_reg32_file_ops), |
240 | (void*)NV_CE_PCE_MAP); | 260 | (void*)NV_CE_PCE_MAP); |
241 | } | 261 | } |
242 | // ProcFS entry creation only fails if out of memory | 262 | // ProcFS entry creation only fails if out of memory |