diff --git a/Documentation/ABI/testing/sysfs-kernel-dmaheap b/Documentation/ABI/testing/sysfs-kernel-dmaheap new file mode 100644 index 000000000000..f496181e9bf8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-dmaheap @@ -0,0 +1,7 @@ +What: /sys/kernel/dma_heap/total_pools_kb +Date: Feb 2021 +KernelVersion: 5.10 +Contact: Hridya Valsaraju , +Description: + The total_pools_kb file is read-only and specifies how much + memory in Kb is allocated to DMA-BUF heap pools. diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c index 011415745bd4..4fb22001b2ca 100644 --- a/drivers/dma-buf/dma-heap.c +++ b/drivers/dma-buf/dma-heap.c @@ -383,21 +383,81 @@ static char *dma_heap_devnode(struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "dma_heap/%s", dev_name(dev)); } +static ssize_t total_pools_kb_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct dma_heap *heap; + u64 total_pool_size = 0; + + mutex_lock(&heap_list_lock); + list_for_each_entry(heap, &heap_list, list) { + if (heap->ops->get_pool_size) + total_pool_size += heap->ops->get_pool_size(heap); + } + mutex_unlock(&heap_list_lock); + + return sysfs_emit(buf, "%llu\n", total_pool_size / 1024); +} + +static struct kobj_attribute total_pools_kb_attr = + __ATTR_RO(total_pools_kb); + +static struct attribute *dma_heap_sysfs_attrs[] = { + &total_pools_kb_attr.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(dma_heap_sysfs); + +static struct kobject *dma_heap_kobject; + +static int dma_heap_sysfs_setup(void) +{ + int ret; + + dma_heap_kobject = kobject_create_and_add("dma_heap", kernel_kobj); + if (!dma_heap_kobject) + return -ENOMEM; + + ret = sysfs_create_groups(dma_heap_kobject, dma_heap_sysfs_groups); + if (ret) { + kobject_put(dma_heap_kobject); + return ret; + } + + return 0; +} + +static void dma_heap_sysfs_teardown(void) +{ + kobject_put(dma_heap_kobject); +} + static int dma_heap_init(void) { int ret; - ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); + ret = dma_heap_sysfs_setup(); if (ret) return ret; + ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); + if (ret) + goto err_chrdev; + dma_heap_class = class_create(THIS_MODULE, DEVNAME); if (IS_ERR(dma_heap_class)) { - unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); - return PTR_ERR(dma_heap_class); + ret = PTR_ERR(dma_heap_class); + goto err_class; } dma_heap_class->devnode = dma_heap_devnode; return 0; + +err_class: + unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); +err_chrdev: + dma_heap_sysfs_teardown(); + return ret; } subsys_initcall(dma_heap_init); diff --git a/include/linux/dma-heap.h b/include/linux/dma-heap.h index 44f1050c1716..a1a190ebc461 100644 --- a/include/linux/dma-heap.h +++ b/include/linux/dma-heap.h @@ -17,6 +17,7 @@ struct dma_heap; /** * struct dma_heap_ops - ops to operate on a given heap * @allocate: allocate dmabuf and return struct dma_buf ptr + * @get_pool_size: if heap maintains memory pools, get pool size in bytes * * allocate returns dmabuf on success, ERR_PTR(-errno) on error. */ @@ -25,6 +26,7 @@ struct dma_heap_ops { unsigned long len, unsigned long fd_flags, unsigned long heap_flags); + long (*get_pool_size)(struct dma_heap *heap); }; /**