123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2002,2008-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/debugfs.h>
- #include <linux/io.h>
- #include "kgsl_debugfs.h"
- #include "kgsl_device.h"
- #include "kgsl_pool.h"
- #include "kgsl_sharedmem.h"
- struct dentry *kgsl_debugfs_dir, *mempools_debugfs;
- static struct dentry *proc_d_debugfs;
- static void kgsl_qdss_gfx_register_probe(struct kgsl_device *device)
- {
- struct resource *res;
- res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM,
- "qdss_gfx");
- if (res == NULL)
- return;
- device->qdss_gfx_virt = devm_ioremap(&device->pdev->dev, res->start,
- resource_size(res));
- if (device->qdss_gfx_virt == NULL)
- dev_warn(device->dev, "qdss_gfx ioremap failed\n");
- }
- static int _isdb_set(void *data, u64 val)
- {
- struct kgsl_device *device = data;
- if (device->qdss_gfx_virt == NULL)
- kgsl_qdss_gfx_register_probe(device);
- device->set_isdb_breakpoint = val ? true : false;
- return 0;
- }
- static int _isdb_get(void *data, u64 *val)
- {
- struct kgsl_device *device = data;
- *val = device->set_isdb_breakpoint ? 1 : 0;
- return 0;
- }
- DEFINE_DEBUGFS_ATTRIBUTE(_isdb_fops, _isdb_get, _isdb_set, "%llu\n");
- static int globals_show(struct seq_file *s, void *unused)
- {
- struct kgsl_device *device = s->private;
- struct kgsl_global_memdesc *md;
- list_for_each_entry(md, &device->globals, node) {
- struct kgsl_memdesc *memdesc = &md->memdesc;
- char flags[6];
- flags[0] = memdesc->priv & KGSL_MEMDESC_PRIVILEGED ? 'p' : '-';
- flags[1] = !(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 'w' : '-';
- flags[2] = kgsl_memdesc_is_secured(memdesc) ? 's' : '-';
- flags[3] = memdesc->priv & KGSL_MEMDESC_RANDOM ? 'r' : '-';
- flags[4] = memdesc->priv & KGSL_MEMDESC_UCODE ? 'u' : '-';
- flags[5] = '\0';
- seq_printf(s, "0x%pK-0x%pK %16llu %5s %s\n",
- (u64 *)(uintptr_t) memdesc->gpuaddr,
- (u64 *)(uintptr_t) (memdesc->gpuaddr +
- memdesc->size - 1), memdesc->size, flags,
- md->name);
- }
- return 0;
- }
- DEFINE_SHOW_ATTRIBUTE(globals);
- static int _pool_size_get(void *data, u64 *val)
- {
- *val = (u64) kgsl_pool_size_total();
- return 0;
- }
- DEFINE_DEBUGFS_ATTRIBUTE(_pool_size_fops, _pool_size_get, NULL, "%llu\n");
- DEFINE_DEBUGFS_ATTRIBUTE(_reserved_fops,
- kgsl_pool_reserved_get, NULL, "%llu\n");
- DEFINE_DEBUGFS_ATTRIBUTE(_page_count_fops,
- kgsl_pool_page_count_get, NULL, "%llu\n");
- void kgsl_pool_init_debugfs(struct dentry *pool_debugfs,
- char *name, void *pool)
- {
- struct dentry *dentry;
- pool_debugfs = debugfs_create_dir(name, mempools_debugfs);
- if (IS_ERR_OR_NULL(pool_debugfs)) {
- WARN((pool_debugfs == NULL),
- "Unable to create debugfs dir for %s\n", name);
- pool_debugfs = NULL;
- return;
- }
- dentry = debugfs_create_file("reserved", 0444,
- pool_debugfs, pool, &_reserved_fops);
- WARN((IS_ERR_OR_NULL(dentry)),
- "Unable to create 'reserved' file for %s\n", name);
- dentry = debugfs_create_file("count", 0444,
- pool_debugfs, pool, &_page_count_fops);
- WARN((IS_ERR_OR_NULL(dentry)),
- "Unable to create 'count' file for %s\n", name);
- }
- void kgsl_device_debugfs_init(struct kgsl_device *device)
- {
- struct dentry *snapshot_dir;
- if (IS_ERR_OR_NULL(kgsl_debugfs_dir))
- return;
- device->d_debugfs = debugfs_create_dir(device->name,
- kgsl_debugfs_dir);
- debugfs_create_file("globals", 0444, device->d_debugfs, device,
- &globals_fops);
- snapshot_dir = debugfs_create_dir("snapshot", kgsl_debugfs_dir);
- debugfs_create_file("break_isdb", 0644, snapshot_dir, device,
- &_isdb_fops);
- }
- void kgsl_device_debugfs_close(struct kgsl_device *device)
- {
- debugfs_remove_recursive(device->d_debugfs);
- }
- static const char *memtype_str(int memtype)
- {
- if (memtype == KGSL_MEM_ENTRY_KERNEL)
- return "gpumem";
- else if (memtype == KGSL_MEM_ENTRY_USER)
- return "usermem";
- else if (memtype == KGSL_MEM_ENTRY_ION)
- return "ion";
- return "unknown";
- }
- static char get_alignflag(const struct kgsl_memdesc *m)
- {
- int align = kgsl_memdesc_get_align(m);
- if (align >= ilog2(SZ_1M))
- return 'L';
- else if (align >= ilog2(SZ_64K))
- return 'l';
- return '-';
- }
- static char get_cacheflag(const struct kgsl_memdesc *m)
- {
- static const char table[] = {
- [KGSL_CACHEMODE_WRITECOMBINE] = '-',
- [KGSL_CACHEMODE_UNCACHED] = 'u',
- [KGSL_CACHEMODE_WRITEBACK] = 'b',
- [KGSL_CACHEMODE_WRITETHROUGH] = 't',
- };
- return table[kgsl_memdesc_get_cachemode(m)];
- }
- static int print_mem_entry(void *data, void *ptr)
- {
- struct seq_file *s = data;
- struct kgsl_mem_entry *entry = ptr;
- char flags[11];
- char usage[16];
- struct kgsl_memdesc *m = &entry->memdesc;
- unsigned int usermem_type = kgsl_memdesc_usermem_type(m);
- int egl_surface_count = 0, egl_image_count = 0;
- unsigned long inode_number = 0;
- u32 map_count = atomic_read(&entry->map_count);
- flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
- flags[1] = '-';
- flags[2] = !(m->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 'w' : '-';
- flags[3] = get_alignflag(m);
- flags[4] = get_cacheflag(m);
- flags[5] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
- /* Show Y if at least one vma has this entry mapped (could be multiple) */
- flags[6] = map_count ? 'Y' : 'N';
- flags[7] = kgsl_memdesc_is_secured(m) ? 's' : '-';
- flags[8] = '-';
- flags[9] = m->flags & KGSL_MEMFLAGS_VBO ? 'v' : '-';
- flags[10] = '\0';
- kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
- if (usermem_type == KGSL_MEM_ENTRY_ION) {
- kgsl_get_egl_counts(entry, &egl_surface_count,
- &egl_image_count);
- inode_number = kgsl_get_dmabuf_inode_number(entry);
- }
- seq_printf(s, "%pK %pK %16llu %5d %10s %10s %16s %5d %10d %6d %6d %10lu",
- (uint64_t *)(uintptr_t) m->gpuaddr,
- /*
- * Show zero for the useraddr - we can't reliably track
- * that value for multiple vmas anyway
- */
- NULL, m->size, entry->id, flags,
- memtype_str(usermem_type),
- usage, (m->sgt ? m->sgt->nents : 0), map_count,
- egl_surface_count, egl_image_count, inode_number);
- if (entry->metadata[0] != 0)
- seq_printf(s, " %s", entry->metadata);
- seq_putc(s, '\n');
- return 0;
- }
- static struct kgsl_mem_entry *process_mem_seq_find(struct seq_file *s,
- void *ptr, loff_t pos)
- {
- struct kgsl_mem_entry *entry = ptr;
- struct kgsl_process_private *private = s->private;
- int id = 0;
- loff_t temp_pos = 1;
- if (entry != SEQ_START_TOKEN)
- id = entry->id + 1;
- spin_lock(&private->mem_lock);
- for (entry = idr_get_next(&private->mem_idr, &id); entry;
- id++, entry = idr_get_next(&private->mem_idr, &id),
- temp_pos++) {
- if (temp_pos == pos && kgsl_mem_entry_get(entry)) {
- spin_unlock(&private->mem_lock);
- goto found;
- }
- }
- spin_unlock(&private->mem_lock);
- entry = NULL;
- found:
- if (ptr != SEQ_START_TOKEN)
- kgsl_mem_entry_put(ptr);
- return entry;
- }
- static void *process_mem_seq_start(struct seq_file *s, loff_t *pos)
- {
- loff_t seq_file_offset = *pos;
- if (seq_file_offset == 0)
- return SEQ_START_TOKEN;
- else
- return process_mem_seq_find(s, SEQ_START_TOKEN,
- seq_file_offset);
- }
- static void process_mem_seq_stop(struct seq_file *s, void *ptr)
- {
- if (ptr && ptr != SEQ_START_TOKEN)
- kgsl_mem_entry_put(ptr);
- }
- static void *process_mem_seq_next(struct seq_file *s, void *ptr,
- loff_t *pos)
- {
- ++*pos;
- return process_mem_seq_find(s, ptr, 1);
- }
- static int process_mem_seq_show(struct seq_file *s, void *ptr)
- {
- if (ptr == SEQ_START_TOKEN) {
- seq_printf(s, "%16s %16s %16s %5s %10s %10s %16s %5s %10s %6s %6s %10s\n",
- "gpuaddr", "useraddr", "size", "id", "flags", "type",
- "usage", "sglen", "mapcnt", "eglsrf", "eglimg", "inode");
- return 0;
- } else
- return print_mem_entry(s, ptr);
- }
- static const struct seq_operations process_mem_seq_fops = {
- .start = process_mem_seq_start,
- .stop = process_mem_seq_stop,
- .next = process_mem_seq_next,
- .show = process_mem_seq_show,
- };
- static int process_mem_open(struct inode *inode, struct file *file)
- {
- int ret;
- pid_t pid = (pid_t) (unsigned long) inode->i_private;
- struct seq_file *s = NULL;
- struct kgsl_process_private *private = NULL;
- private = kgsl_process_private_find(pid);
- if (!private)
- return -ENODEV;
- ret = seq_open(file, &process_mem_seq_fops);
- if (ret)
- kgsl_process_private_put(private);
- else {
- s = file->private_data;
- s->private = private;
- }
- return ret;
- }
- static int process_mem_release(struct inode *inode, struct file *file)
- {
- struct kgsl_process_private *private =
- ((struct seq_file *)file->private_data)->private;
- if (private)
- kgsl_process_private_put(private);
- return seq_release(inode, file);
- }
- static const struct file_operations process_mem_fops = {
- .open = process_mem_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = process_mem_release,
- };
- static int print_vbo_ranges(int id, void *ptr, void *data)
- {
- kgsl_memdesc_print_vbo_ranges(ptr, data);
- return 0;
- }
- static int vbo_print(struct seq_file *s, void *unused)
- {
- struct kgsl_process_private *private = s->private;
- seq_puts(s, "id child range\n");
- spin_lock(&private->mem_lock);
- idr_for_each(&private->mem_idr, print_vbo_ranges, s);
- spin_unlock(&private->mem_lock);
- return 0;
- }
- static int vbo_open(struct inode *inode, struct file *file)
- {
- pid_t pid = (pid_t) (unsigned long) inode->i_private;
- struct kgsl_process_private *private;
- int ret;
- private = kgsl_process_private_find(pid);
- if (!private)
- return -ENODEV;
- ret = single_open(file, vbo_print, private);
- if (ret)
- kgsl_process_private_put(private);
- return ret;
- }
- static const struct file_operations vbo_fops = {
- .open = vbo_open,
- .read = seq_read,
- .llseek = seq_lseek,
- /* Reuse the same release function */
- .release = process_mem_release,
- };
- /**
- * kgsl_process_init_debugfs() - Initialize debugfs for a process
- * @private: Pointer to process private structure created for the process
- *
- * kgsl_process_init_debugfs() is called at the time of creating the
- * process struct when a process opens kgsl device for the first time.
- * This function is not fatal - all we do is print a warning message if
- * the files can't be created
- */
- void kgsl_process_init_debugfs(struct kgsl_process_private *private)
- {
- unsigned char name[16];
- struct dentry *dentry;
- snprintf(name, sizeof(name), "%d", pid_nr(private->pid));
- private->debug_root = debugfs_create_dir(name, proc_d_debugfs);
- if (IS_ERR(private->debug_root)) {
- WARN_ONCE("Unable to create debugfs dir for %s\n", name);
- private->debug_root = NULL;
- return;
- }
- dentry = debugfs_create_file("mem", 0444, private->debug_root,
- (void *) ((unsigned long) pid_nr(private->pid)), &process_mem_fops);
- if (IS_ERR(dentry))
- WARN_ONCE("Unable to create 'mem' file for %s\n", name);
- debugfs_create_file("vbos", 0444, private->debug_root,
- (void *) ((unsigned long) pid_nr(private->pid)), &vbo_fops);
- }
- void kgsl_core_debugfs_init(void)
- {
- struct dentry *debug_dir, *dentry;
- kgsl_debugfs_dir = debugfs_create_dir("kgsl", NULL);
- if (IS_ERR_OR_NULL(kgsl_debugfs_dir))
- return;
- debug_dir = debugfs_create_dir("debug", kgsl_debugfs_dir);
- proc_d_debugfs = debugfs_create_dir("proc", kgsl_debugfs_dir);
- debugfs_create_bool("strict_memory", 0644, debug_dir,
- &kgsl_sharedmem_noretry_flag);
- mempools_debugfs = debugfs_create_dir("mempools", kgsl_debugfs_dir);
- if (IS_ERR_OR_NULL(mempools_debugfs))
- return;
- dentry = debugfs_create_file("pool_size", 0444,
- mempools_debugfs, NULL, &_pool_size_fops);
- WARN((IS_ERR_OR_NULL(dentry)),
- "Unable to create 'pool_size' file for mempools\n");
- }
- void kgsl_core_debugfs_close(void)
- {
- debugfs_remove_recursive(kgsl_debugfs_dir);
- }
|