diff --git a/drivers/gpu/nvgpu/os/linux/debug_gr.c b/drivers/gpu/nvgpu/os/linux/debug_gr.c index 28d241b0f..74b7015e1 100644 --- a/drivers/gpu/nvgpu/os/linux/debug_gr.c +++ b/drivers/gpu/nvgpu/os/linux/debug_gr.c @@ -14,6 +14,7 @@ #include #include +#include #include "common/gr/ctx_priv.h" #include "common/gr/gr_priv.h" @@ -22,8 +23,248 @@ #include "os_linux.h" #include +#include #include +#ifdef CONFIG_NVGPU_COMPRESSION +static int cbc_status_debug_show(struct seq_file *s, void *unused) +{ + struct gk20a *g = s->private; + struct nvgpu_cbc *cbc = g->cbc; + + if (!cbc) { + nvgpu_err(g, "cbc is not initialized"); + return -EBADFD; + } + seq_printf(s, "cbc.compbit_backing_size: %u\n", + cbc->compbit_backing_size); + seq_printf(s, "cbc.comptags_per_cacheline: %u\n", + cbc->comptags_per_cacheline); + seq_printf(s, "cbc.gobs_per_comptagline_per_slice: %u\n", + cbc->gobs_per_comptagline_per_slice); + seq_printf(s, "cbc.max_comptag_lines: %u\n", + cbc->max_comptag_lines); + seq_printf(s, "cbc.comp_tags.size: %lu\n", + cbc->comp_tags.size); + seq_printf(s, "cbc.compbit_store.base_hw: %llu\n", + cbc->compbit_store.base_hw); + if (nvgpu_mem_is_valid(&cbc->compbit_store.mem)) { + seq_printf(s, "cbc.compbit_store.mem.aperture: %u\n", + cbc->compbit_store.mem.aperture); + seq_printf(s, "cbc.compbit_store.mem.size: %zu\n", + cbc->compbit_store.mem.size); + seq_printf(s, "cbc.compbit_store.mem.aligned_size: %zu\n", + cbc->compbit_store.mem.aligned_size); + seq_printf(s, "cbc.compbit_store.mem.gpu_va: %llu\n", + cbc->compbit_store.mem.gpu_va); + seq_printf(s, "cbc.compbit_store.mem.skip_wmb: %u\n", + cbc->compbit_store.mem.skip_wmb); + seq_printf(s, "cbc.compbit_store.mem.free_gpu_va: %u\n", + cbc->compbit_store.mem.free_gpu_va); + seq_printf(s, "cbc.compbit_store.mem.mem_flags: %lu\n", + cbc->compbit_store.mem.mem_flags); + seq_printf(s, "cbc.compbit_store.mem.cpu_va: %px\n", + cbc->compbit_store.mem.cpu_va); + seq_printf(s, "cbc.compbit_store.mem.pa: %llx\n", + nvgpu_mem_get_addr(g, &cbc->compbit_store.mem)); + } else { + seq_printf(s, "cbc.compbit_store.mem: invalid\n"); + } + return 0; +} + +static int cbc_status_debug_open(struct inode *inode, struct file *file) +{ + int err = 0; + struct gk20a *g = (struct gk20a *)inode->i_private; + + if (!capable(CAP_SYS_ADMIN)) { + return -EPERM; + } + g = nvgpu_get(g); + if (!g) { + return -ENODEV; + } + err = gk20a_busy(g); + if (err < 0) { + nvgpu_err(g, "Couldn't power-up gpu"); + goto put; + } + err = nvgpu_cbc_init_support(g); + if (err < 0) { + nvgpu_err(g, "cbc init failed"); + goto idle; + } + err = single_open(file, cbc_status_debug_show, inode->i_private); + if (err < 0) { + nvgpu_err(g, "single open failed"); + goto idle; + } + return err; + +idle: + gk20a_idle(g); +put: + nvgpu_put(g); + return err; +} + +static int cbc_status_debug_release(struct inode *inode, struct file *file) +{ + struct gk20a *g = (struct gk20a *)inode->i_private; + + gk20a_idle(g); + nvgpu_put(g); + return single_release(inode, file); +} + +static const struct file_operations cbc_status_debug_fops = { + .open = cbc_status_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = cbc_status_debug_release, +}; + +static ssize_t cbc_ctrl_debug_write_cmd(struct file *f, const char __user *cmd, size_t len, loff_t *off) +{ + char cmd_buf[32]; + struct gk20a *g = f->private_data; + struct nvgpu_cbc *cbc = g->cbc; + const size_t original_len = len; + int err = 0; + + if (!cbc) { + nvgpu_err(g, "cbc is not initialized"); + return -EINVAL; + } + if (len == 0 || len >= sizeof(cmd_buf)) { + nvgpu_err(g, "invalid cmd len: %zu", len); + return -EINVAL; + } + if (copy_from_user(cmd_buf, cmd, len)) { + nvgpu_err(g, "failed to read cmd"); + return -EFAULT; + } + if (cmd_buf[len - 1] == '\n') { + len = len - 1; + } + cmd_buf[len] = '\x00'; + + if (strncmp("cbc_clean", cmd_buf, len) == 0) { + // Flush the comptag store to L2. + err = g->ops.cbc.ctrl(g, nvgpu_cbc_op_clean, 0, 0); + if (err == 0) { + // From from L2 to memory. + err = g->ops.mm.cache.l2_flush(g, false); + } + } else { + nvgpu_err(g, "Unknown cmd: %s", cmd_buf); + err = -EINVAL; + } + return err < 0 ? err : (ssize_t)original_len; +} + +static int cbc_ctrl_debug_open(struct inode *inode, struct file *file) +{ + int err = 0; + struct gk20a *g = inode->i_private; + + if (!capable(CAP_SYS_ADMIN)) { + return -EPERM; + } + g = nvgpu_get(g); + if (!g) { + return -ENODEV; + } + err = gk20a_busy(g); + if (err < 0) { + nvgpu_err(g, "Couldn't power-up gpu"); + goto put; + } + err = nvgpu_cbc_init_support(g); + if (err < 0) { + nvgpu_err(g, "cbc init failed"); + goto idle; + } + file->private_data = g; + return err; + +idle: + gk20a_idle(g); +put: + nvgpu_put(g); + return err; +} + +static int cbc_ctrl_debug_release(struct inode *inode, struct file *file) +{ + struct gk20a *g = file->private_data; + + if (g) { + gk20a_idle(g); + nvgpu_put(g); + } + return 0; +} + +static int cbc_ctrl_debug_mmap_cbc_store(struct file *f, struct vm_area_struct *vma) +{ + struct gk20a *g = f->private_data; + struct nvgpu_cbc *cbc = g->cbc; + unsigned long mapping_size = 0U; + int err = 0; + u64 cbc_store_pa = 0; + pgprot_t prot = pgprot_noncached(vma->vm_page_prot); + + if (vma->vm_flags & VM_WRITE) { + return -EPERM; + } + if (!(vma->vm_flags & VM_SHARED)) { + return -EINVAL; + } + if (!cbc) { + nvgpu_err(g, "cbc is not initialized"); + err = -EINVAL; + goto done; + } + if (nvgpu_mem_is_valid(&cbc->compbit_store.mem) == 0) { + nvgpu_err(g, "cbc compbit store memory is not valid"); + err = -EINVAL; + goto done; + } + mapping_size = (vma->vm_end - vma->vm_start); + if (mapping_size != cbc->compbit_store.mem.size) { + nvgpu_err(g, "mapping size (%lx) is unequal to store size (%lx)", + mapping_size, cbc->compbit_store.mem.size); + err = -EINVAL; + goto done; + } + if (vma->vm_pgoff != 0UL) { + err = -EINVAL; + goto done; + } + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE | + VM_DONTDUMP | VM_PFNMAP; + vma->vm_flags &= ~VM_MAYWRITE; + cbc_store_pa = nvgpu_mem_get_addr(g, &cbc->compbit_store.mem); + err = remap_pfn_range(vma, vma->vm_start, cbc_store_pa >> PAGE_SHIFT, + mapping_size, prot); + if (err < 0) { + nvgpu_err(g, "Failed to remap %llx to user space", cbc_store_pa); + } + +done: + return err; +} + +static const struct file_operations cbc_ctrl_debug_fops = { + .open = cbc_ctrl_debug_open, + .release = cbc_ctrl_debug_release, + .write = cbc_ctrl_debug_write_cmd, + .mmap = cbc_ctrl_debug_mmap_cbc_store, +}; +#endif /* CONFIG_NVGPU_COMPRESSION */ + static int gr_default_attrib_cb_size_show(struct seq_file *s, void *data) { struct gk20a *g = s->private; @@ -230,6 +471,18 @@ int gr_gk20a_debugfs_init(struct gk20a *g) if (!d) return -ENOMEM; +#ifdef CONFIG_NVGPU_COMPRESSION + d = debugfs_create_file("cbc_status", S_IRUSR, l->debugfs, g, + &cbc_status_debug_fops); + if (!d) + return -ENOMEM; + /* Using debugfs_create_file_unsafe to allow mmap */ + d = debugfs_create_file_unsafe("cbc_ctrl", S_IRUSR | S_IWUSR, + l->debugfs, g, &cbc_ctrl_debug_fops); + if (!d) + return -ENOMEM; +#endif /* CONFIG_NVGPU_COMPRESSION */ + if (!g->is_virtual) { d = debugfs_create_file( "dump_ctxsw_stats_on_channel_close", S_IRUGO|S_IWUSR,