.. | .. |
---|
31 | 31 | |
---|
32 | 32 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
---|
33 | 33 | |
---|
| 34 | +#define SHOW_GPU_MEM_DATA(type, format) \ |
---|
| 35 | +{ \ |
---|
| 36 | + unsigned int i, j; \ |
---|
| 37 | + const type *ptr = (type *)cpu_addr; \ |
---|
| 38 | + const unsigned int col_width = sizeof(type); \ |
---|
| 39 | + const unsigned int row_width = (col_width == sizeof(u64)) ? 32 : 16; \ |
---|
| 40 | + const unsigned int num_cols = row_width / col_width; \ |
---|
| 41 | + for (i = 0; i < PAGE_SIZE; i += row_width) { \ |
---|
| 42 | + seq_printf(m, "%016llx:", gpu_addr + i); \ |
---|
| 43 | + for (j = 0; j < num_cols; j++) \ |
---|
| 44 | + seq_printf(m, format, ptr[j]); \ |
---|
| 45 | + ptr += num_cols; \ |
---|
| 46 | + seq_putc(m, '\n'); \ |
---|
| 47 | + } \ |
---|
| 48 | +} |
---|
| 49 | + |
---|
34 | 50 | struct debug_mem_mapping { |
---|
35 | 51 | struct list_head node; |
---|
36 | 52 | |
---|
.. | .. |
---|
44 | 60 | struct debug_mem_data { |
---|
45 | 61 | struct list_head mapping_list; |
---|
46 | 62 | struct kbase_context *kctx; |
---|
| 63 | + unsigned int column_width; |
---|
47 | 64 | }; |
---|
48 | 65 | |
---|
49 | 66 | struct debug_mem_seq_off { |
---|
.. | .. |
---|
111 | 128 | struct debug_mem_data *mem_data = m->private; |
---|
112 | 129 | struct debug_mem_seq_off *data = v; |
---|
113 | 130 | struct debug_mem_mapping *map; |
---|
114 | | - int i, j; |
---|
| 131 | + unsigned long long gpu_addr; |
---|
115 | 132 | struct page *page; |
---|
116 | | - uint32_t *mapping; |
---|
| 133 | + void *cpu_addr; |
---|
117 | 134 | pgprot_t prot = PAGE_KERNEL; |
---|
118 | 135 | |
---|
119 | 136 | map = list_entry(data->lh, struct debug_mem_mapping, node); |
---|
.. | .. |
---|
130 | 147 | prot = pgprot_writecombine(prot); |
---|
131 | 148 | |
---|
132 | 149 | page = as_page(map->alloc->pages[data->offset]); |
---|
133 | | - mapping = vmap(&page, 1, VM_MAP, prot); |
---|
134 | | - if (!mapping) |
---|
| 150 | + cpu_addr = vmap(&page, 1, VM_MAP, prot); |
---|
| 151 | + if (!cpu_addr) |
---|
135 | 152 | goto out; |
---|
136 | 153 | |
---|
137 | | - for (i = 0; i < PAGE_SIZE; i += 4*sizeof(*mapping)) { |
---|
138 | | - seq_printf(m, "%016llx:", i + ((map->start_pfn + |
---|
139 | | - data->offset) << PAGE_SHIFT)); |
---|
| 154 | + gpu_addr = (map->start_pfn + data->offset) << PAGE_SHIFT; |
---|
140 | 155 | |
---|
141 | | - for (j = 0; j < 4*sizeof(*mapping); j += sizeof(*mapping)) |
---|
142 | | - seq_printf(m, " %08x", mapping[(i+j)/sizeof(*mapping)]); |
---|
143 | | - seq_putc(m, '\n'); |
---|
| 156 | + /* Cases for 4 supported values of column_width for showing |
---|
| 157 | + * the GPU memory contents. |
---|
| 158 | + */ |
---|
| 159 | + switch (mem_data->column_width) { |
---|
| 160 | + case 1: |
---|
| 161 | + SHOW_GPU_MEM_DATA(u8, " %02hhx"); |
---|
| 162 | + break; |
---|
| 163 | + case 2: |
---|
| 164 | + SHOW_GPU_MEM_DATA(u16, " %04hx"); |
---|
| 165 | + break; |
---|
| 166 | + case 4: |
---|
| 167 | + SHOW_GPU_MEM_DATA(u32, " %08x"); |
---|
| 168 | + break; |
---|
| 169 | + case 8: |
---|
| 170 | + SHOW_GPU_MEM_DATA(u64, " %016llx"); |
---|
| 171 | + break; |
---|
| 172 | + default: |
---|
| 173 | + dev_warn(mem_data->kctx->kbdev->dev, "Unexpected column width"); |
---|
144 | 174 | } |
---|
145 | 175 | |
---|
146 | | - vunmap(mapping); |
---|
| 176 | + vunmap(cpu_addr); |
---|
147 | 177 | |
---|
148 | 178 | seq_putc(m, '\n'); |
---|
149 | 179 | |
---|
.. | .. |
---|
207 | 237 | if (get_file_rcu(kctx->filp) == 0) |
---|
208 | 238 | return -ENOENT; |
---|
209 | 239 | |
---|
| 240 | + /* Check if file was opened in write mode. GPU memory contents |
---|
| 241 | + * are returned only when the file is not opened in write mode. |
---|
| 242 | + */ |
---|
| 243 | + if (file->f_mode & FMODE_WRITE) { |
---|
| 244 | + file->private_data = kctx; |
---|
| 245 | + return 0; |
---|
| 246 | + } |
---|
| 247 | + |
---|
210 | 248 | ret = seq_open(file, &ops); |
---|
211 | 249 | if (ret) |
---|
212 | 250 | goto open_fail; |
---|
.. | .. |
---|
222 | 260 | INIT_LIST_HEAD(&mem_data->mapping_list); |
---|
223 | 261 | |
---|
224 | 262 | kbase_gpu_vm_lock(kctx); |
---|
| 263 | + |
---|
| 264 | + mem_data->column_width = kctx->mem_view_column_width; |
---|
225 | 265 | |
---|
226 | 266 | ret = debug_mem_zone_open(&kctx->reg_rbtree_same, mem_data); |
---|
227 | 267 | if (ret != 0) { |
---|
.. | .. |
---|
240 | 280 | kbase_gpu_vm_unlock(kctx); |
---|
241 | 281 | goto out; |
---|
242 | 282 | } |
---|
| 283 | + |
---|
| 284 | +#if MALI_USE_CSF |
---|
| 285 | + ret = debug_mem_zone_open(&kctx->reg_rbtree_exec_fixed, mem_data); |
---|
| 286 | + if (ret != 0) { |
---|
| 287 | + kbase_gpu_vm_unlock(kctx); |
---|
| 288 | + goto out; |
---|
| 289 | + } |
---|
| 290 | + |
---|
| 291 | + ret = debug_mem_zone_open(&kctx->reg_rbtree_fixed, mem_data); |
---|
| 292 | + if (ret != 0) { |
---|
| 293 | + kbase_gpu_vm_unlock(kctx); |
---|
| 294 | + goto out; |
---|
| 295 | + } |
---|
| 296 | +#endif |
---|
243 | 297 | |
---|
244 | 298 | kbase_gpu_vm_unlock(kctx); |
---|
245 | 299 | |
---|
.. | .. |
---|
270 | 324 | static int debug_mem_release(struct inode *inode, struct file *file) |
---|
271 | 325 | { |
---|
272 | 326 | struct kbase_context *const kctx = inode->i_private; |
---|
273 | | - struct seq_file *sfile = file->private_data; |
---|
274 | | - struct debug_mem_data *mem_data = sfile->private; |
---|
275 | | - struct debug_mem_mapping *mapping; |
---|
276 | 327 | |
---|
277 | | - seq_release(inode, file); |
---|
| 328 | + /* If the file wasn't opened in write mode, then release the |
---|
| 329 | + * memory allocated to show the GPU memory contents. |
---|
| 330 | + */ |
---|
| 331 | + if (!(file->f_mode & FMODE_WRITE)) { |
---|
| 332 | + struct seq_file *sfile = file->private_data; |
---|
| 333 | + struct debug_mem_data *mem_data = sfile->private; |
---|
| 334 | + struct debug_mem_mapping *mapping; |
---|
278 | 335 | |
---|
279 | | - while (!list_empty(&mem_data->mapping_list)) { |
---|
280 | | - mapping = list_first_entry(&mem_data->mapping_list, |
---|
| 336 | + seq_release(inode, file); |
---|
| 337 | + |
---|
| 338 | + while (!list_empty(&mem_data->mapping_list)) { |
---|
| 339 | + mapping = list_first_entry(&mem_data->mapping_list, |
---|
281 | 340 | struct debug_mem_mapping, node); |
---|
282 | | - kbase_mem_phy_alloc_put(mapping->alloc); |
---|
283 | | - list_del(&mapping->node); |
---|
284 | | - kfree(mapping); |
---|
285 | | - } |
---|
| 341 | + kbase_mem_phy_alloc_put(mapping->alloc); |
---|
| 342 | + list_del(&mapping->node); |
---|
| 343 | + kfree(mapping); |
---|
| 344 | + } |
---|
286 | 345 | |
---|
287 | | - kfree(mem_data); |
---|
| 346 | + kfree(mem_data); |
---|
| 347 | + } |
---|
288 | 348 | |
---|
289 | 349 | fput(kctx->filp); |
---|
290 | 350 | |
---|
291 | 351 | return 0; |
---|
| 352 | +} |
---|
| 353 | + |
---|
| 354 | +static ssize_t debug_mem_write(struct file *file, const char __user *ubuf, |
---|
| 355 | + size_t count, loff_t *ppos) |
---|
| 356 | +{ |
---|
| 357 | + struct kbase_context *const kctx = file->private_data; |
---|
| 358 | + unsigned int column_width = 0; |
---|
| 359 | + int ret = 0; |
---|
| 360 | + |
---|
| 361 | + CSTD_UNUSED(ppos); |
---|
| 362 | + |
---|
| 363 | + ret = kstrtouint_from_user(ubuf, count, 0, &column_width); |
---|
| 364 | + |
---|
| 365 | + if (ret) |
---|
| 366 | + return ret; |
---|
| 367 | + if (!is_power_of_2(column_width)) { |
---|
| 368 | + dev_dbg(kctx->kbdev->dev, |
---|
| 369 | + "Column width %u not a multiple of power of 2", column_width); |
---|
| 370 | + return -EINVAL; |
---|
| 371 | + } |
---|
| 372 | + if (column_width > 8) { |
---|
| 373 | + dev_dbg(kctx->kbdev->dev, |
---|
| 374 | + "Column width %u greater than 8 not supported", column_width); |
---|
| 375 | + return -EINVAL; |
---|
| 376 | + } |
---|
| 377 | + |
---|
| 378 | + kbase_gpu_vm_lock(kctx); |
---|
| 379 | + kctx->mem_view_column_width = column_width; |
---|
| 380 | + kbase_gpu_vm_unlock(kctx); |
---|
| 381 | + |
---|
| 382 | + return count; |
---|
292 | 383 | } |
---|
293 | 384 | |
---|
294 | 385 | static const struct file_operations kbase_debug_mem_view_fops = { |
---|
.. | .. |
---|
296 | 387 | .open = debug_mem_open, |
---|
297 | 388 | .release = debug_mem_release, |
---|
298 | 389 | .read = seq_read, |
---|
| 390 | + .write = debug_mem_write, |
---|
299 | 391 | .llseek = seq_lseek |
---|
300 | 392 | }; |
---|
301 | 393 | |
---|
.. | .. |
---|
308 | 400 | WARN_ON(IS_ERR_OR_NULL(kctx->kctx_dentry))) |
---|
309 | 401 | return; |
---|
310 | 402 | |
---|
| 403 | + /* Default column width is 4 */ |
---|
| 404 | + kctx->mem_view_column_width = sizeof(u32); |
---|
| 405 | + |
---|
311 | 406 | debugfs_create_file("mem_view", 0400, kctx->kctx_dentry, kctx, |
---|
312 | 407 | &kbase_debug_mem_view_fops); |
---|
313 | 408 | } |
---|