diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 851d02b54e89..e3271ccbe327 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -448,6 +448,7 @@ struct kgsl_process_private { struct kgsl_pagetable *pagetable; struct list_head list; struct kobject kobj; + struct kobject kobj_memtype; struct dentry *debug_root; struct { atomic64_t cur; diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index ce05655c1687..3343ce49fc89 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -24,6 +24,41 @@ static bool sharedmem_noretry_flag; static DEFINE_MUTEX(kernel_map_global_lock); +#define MEMTYPE(_type, _name) { \ + .type = _type, \ + .attr = { .name = _name, .mode = 0444 } \ +} + +struct kgsl_memtype { + unsigned int type; + struct attribute attr; +}; + +static const struct kgsl_memtype memtypes[] = { + MEMTYPE(KGSL_MEMTYPE_OBJECTANY, "any(0)"), + MEMTYPE(KGSL_MEMTYPE_FRAMEBUFFER, "framebuffer"), + MEMTYPE(KGSL_MEMTYPE_RENDERBUFFER, "renderbuffer"), + MEMTYPE(KGSL_MEMTYPE_ARRAYBUFFER, "arraybuffer"), + MEMTYPE(KGSL_MEMTYPE_ELEMENTARRAYBUFFER, "elementarraybuffer"), + MEMTYPE(KGSL_MEMTYPE_VERTEXARRAYBUFFER, "vertexarraybuffer"), + MEMTYPE(KGSL_MEMTYPE_TEXTURE, "texture"), + MEMTYPE(KGSL_MEMTYPE_SURFACE, "surface"), + MEMTYPE(KGSL_MEMTYPE_EGL_SURFACE, "egl_surface"), + MEMTYPE(KGSL_MEMTYPE_GL, "gl"), + MEMTYPE(KGSL_MEMTYPE_CL, "cl"), + MEMTYPE(KGSL_MEMTYPE_CL_BUFFER_MAP, "cl_buffer_map"), + MEMTYPE(KGSL_MEMTYPE_CL_BUFFER_NOMAP, "cl_buffer_nomap"), + MEMTYPE(KGSL_MEMTYPE_CL_IMAGE_MAP, "cl_image_map"), + MEMTYPE(KGSL_MEMTYPE_CL_IMAGE_NOMAP, "cl_image_nomap"), + MEMTYPE(KGSL_MEMTYPE_CL_KERNEL_STACK, "cl_kernel_stack"), + MEMTYPE(KGSL_MEMTYPE_COMMAND, "command"), + MEMTYPE(KGSL_MEMTYPE_2D, "2d"), + MEMTYPE(KGSL_MEMTYPE_EGL_IMAGE, "egl_image"), + MEMTYPE(KGSL_MEMTYPE_EGL_SHADOW, "egl_shadow"), + MEMTYPE(KGSL_MEMTYPE_MULTISAMPLE, "egl_multisample"), + MEMTYPE(KGSL_MEMTYPE_KERNEL, "kernel"), +}; + /* An attribute for showing per-process memory statistics */ struct kgsl_mem_entry_attribute { struct attribute attr; @@ -183,6 +218,49 @@ static ssize_t mem_entry_sysfs_show(struct kobject *kobj, return ret; } +static ssize_t memtype_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct kgsl_process_private *priv; + struct kgsl_memtype *memtype; + struct kgsl_mem_entry *entry; + u64 size = 0; + int id = 0; + + /* + * kgsl_process_init_sysfs takes a refcount to the process_private, + * which is put when the kobj is released. This implies that priv will + * not be freed until this function completes, and no further locking + * is needed. + */ + priv = container_of(kobj, struct kgsl_process_private, kobj_memtype); + memtype = container_of(attr, struct kgsl_memtype, attr); + + spin_lock(&priv->mem_lock); + for (entry = idr_get_next(&priv->mem_idr, &id); entry; + id++, entry = idr_get_next(&priv->mem_idr, &id)) { + struct kgsl_memdesc *memdesc; + unsigned int type; + + if (kgsl_mem_entry_get(entry) == 0) + continue; + spin_unlock(&priv->mem_lock); + + memdesc = &entry->memdesc; + type = MEMFLAGS(memdesc->flags, KGSL_MEMTYPE_MASK, + KGSL_MEMTYPE_SHIFT); + + if (type == memtype->type) + size += memdesc->size; + + kgsl_mem_entry_put(entry); + spin_lock(&priv->mem_lock); + } + spin_unlock(&priv->mem_lock); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", size); +} + static void mem_entry_release(struct kobject *kobj) { struct kgsl_process_private *priv; @@ -201,6 +279,14 @@ static struct kobj_type ktype_mem_entry = { .release = &mem_entry_release, }; +static const struct sysfs_ops memtype_sysfs_ops = { + .show = memtype_sysfs_show, +}; + +static struct kobj_type ktype_memtype = { + .sysfs_ops = &memtype_sysfs_ops, +}; + static struct mem_entry_stats mem_stats[] = { MEM_ENTRY_STAT(KGSL_MEM_ENTRY_KERNEL, kernel), MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, user), @@ -220,6 +306,11 @@ kgsl_process_uninit_sysfs(struct kgsl_process_private *private) &mem_stats[i].max_attr.attr); } + + for (i = 0; i < ARRAY_SIZE(memtypes); i++) + sysfs_remove_file(&private->kobj_memtype, &memtypes[i].attr); + + kobject_put(&private->kobj_memtype); kobject_put(&private->kobj); } @@ -268,6 +359,21 @@ void kgsl_process_init_sysfs(struct kgsl_device *device, WARN(1, "Couldn't create sysfs file '%s'\n", debug_memstats[i].attr.name); } + + if (kobject_init_and_add(&private->kobj_memtype, &ktype_memtype, + &private->kobj, "memtype")) { + dev_err(device->dev, + "Unable to add memtype sysfs for process %d\n", + pid_nr(private->pid)); + return; + } + + for (i = 0; i < ARRAY_SIZE(memtypes); i++) { + if (sysfs_create_file(&private->kobj_memtype, + &memtypes[i].attr)) + WARN(1, "Couldn't create sysfs file '%s'\n", + memtypes[i].attr.name); + } } static ssize_t memstat_show(struct device *dev, @@ -790,42 +896,20 @@ kgsl_sharedmem_writeq(const struct kgsl_memdesc *memdesc, wmb(); } -static const char * const memtype_str[] = { - [KGSL_MEMTYPE_OBJECTANY] = "any(0)", - [KGSL_MEMTYPE_FRAMEBUFFER] = "framebuffer", - [KGSL_MEMTYPE_RENDERBUFFER] = "renderbuffer", - [KGSL_MEMTYPE_ARRAYBUFFER] = "arraybuffer", - [KGSL_MEMTYPE_ELEMENTARRAYBUFFER] = "elementarraybuffer", - [KGSL_MEMTYPE_VERTEXARRAYBUFFER] = "vertexarraybuffer", - [KGSL_MEMTYPE_TEXTURE] = "texture", - [KGSL_MEMTYPE_SURFACE] = "surface", - [KGSL_MEMTYPE_EGL_SURFACE] = "egl_surface", - [KGSL_MEMTYPE_GL] = "gl", - [KGSL_MEMTYPE_CL] = "cl", - [KGSL_MEMTYPE_CL_BUFFER_MAP] = "cl_buffer_map", - [KGSL_MEMTYPE_CL_BUFFER_NOMAP] = "cl_buffer_nomap", - [KGSL_MEMTYPE_CL_IMAGE_MAP] = "cl_image_map", - [KGSL_MEMTYPE_CL_IMAGE_NOMAP] = "cl_image_nomap", - [KGSL_MEMTYPE_CL_KERNEL_STACK] = "cl_kernel_stack", - [KGSL_MEMTYPE_COMMAND] = "command", - [KGSL_MEMTYPE_2D] = "2d", - [KGSL_MEMTYPE_EGL_IMAGE] = "egl_image", - [KGSL_MEMTYPE_EGL_SHADOW] = "egl_shadow", - [KGSL_MEMTYPE_MULTISAMPLE] = "egl_multisample", - /* KGSL_MEMTYPE_KERNEL handled below, to avoid huge array */ -}; - void kgsl_get_memory_usage(char *name, size_t name_size, uint64_t memflags) { unsigned int type = MEMFLAGS(memflags, KGSL_MEMTYPE_MASK, KGSL_MEMTYPE_SHIFT); + int i; - if (type == KGSL_MEMTYPE_KERNEL) - strlcpy(name, "kernel", name_size); - else if (type < ARRAY_SIZE(memtype_str) && memtype_str[type] != NULL) - strlcpy(name, memtype_str[type], name_size); - else - snprintf(name, name_size, "VK/others(%3d)", type); + for (i = 0; i < ARRAY_SIZE(memtypes); i++) { + if (memtypes[i].type == type) { + strlcpy(name, memtypes[i].attr.name, name_size); + return; + } + } + + snprintf(name, name_size, "VK/others(%3d)", type); } int kgsl_memdesc_sg_dma(struct kgsl_memdesc *memdesc,