122851890Sopenharmony_ciFrom c31b4def60d6d4b0669aea357113f7eb87c84e67 Mon Sep 17 00:00:00 2001 222851890Sopenharmony_ciFrom: ygopenhm <ygopenhm@vyagoo.com> 322851890Sopenharmony_ciDate: Wed, 6 Jul 2022 11:13:34 +0800 422851890Sopenharmony_ciSubject: [PATCH] kernel 522851890Sopenharmony_ci 622851890Sopenharmony_ciSigned-off-by: ygopenhm <ygopenhm@vyagoo.com> 722851890Sopenharmony_ci--- 822851890Sopenharmony_ci Kconfig | 2 + 922851890Sopenharmony_ci Makefile | 2 + 1022851890Sopenharmony_ci drivers/dma-buf/Kconfig | 24 - 1122851890Sopenharmony_ci drivers/dma-buf/Makefile | 3 - 1222851890Sopenharmony_ci drivers/dma-buf/dma-buf.c | 53 +- 1322851890Sopenharmony_ci drivers/dma-buf/dma-heap.c | 223 +++++-- 1422851890Sopenharmony_ci drivers/dma-buf/heaps/Kconfig | 16 +- 1522851890Sopenharmony_ci drivers/dma-buf/heaps/Makefile | 3 +- 1622851890Sopenharmony_ci drivers/dma-buf/heaps/cma_heap.c | 338 +++++++++-- 1722851890Sopenharmony_ci drivers/dma-buf/heaps/deferred-free-helper.c | 139 +++++ 1822851890Sopenharmony_ci drivers/dma-buf/heaps/deferred-free-helper.h | 57 ++ 1922851890Sopenharmony_ci drivers/dma-buf/heaps/heap-helpers.c | 1 - 2022851890Sopenharmony_ci drivers/dma-buf/heaps/page_pool.c | 247 ++++++++ 2122851890Sopenharmony_ci drivers/dma-buf/heaps/page_pool.h | 55 ++ 2222851890Sopenharmony_ci drivers/dma-buf/heaps/system_heap.c | 576 +++++++++++++++++-- 2322851890Sopenharmony_ci drivers/gpu/drm/drm_gem_framebuffer_helper.c | 7 +- 2422851890Sopenharmony_ci drivers/gpu/drm/drm_vblank.c | 2 +- 2522851890Sopenharmony_ci include/linux/dma-buf.h | 29 +- 2622851890Sopenharmony_ci include/linux/dma-heap.h | 62 +- 2722851890Sopenharmony_ci kernel/sched/core.c | 3 + 2822851890Sopenharmony_ci 20 files changed, 1580 insertions(+), 262 deletions(-) 2922851890Sopenharmony_ci create mode 100755 drivers/dma-buf/heaps/deferred-free-helper.c 3022851890Sopenharmony_ci create mode 100755 drivers/dma-buf/heaps/deferred-free-helper.h 3122851890Sopenharmony_ci create mode 100755 drivers/dma-buf/heaps/page_pool.c 3222851890Sopenharmony_ci create mode 100755 drivers/dma-buf/heaps/page_pool.h 3322851890Sopenharmony_ci 3422851890Sopenharmony_cidiff --git a/Kconfig b/Kconfig 3522851890Sopenharmony_ciindex 745bc773f..e6c33a96d 100644 3622851890Sopenharmony_ci--- a/Kconfig 3722851890Sopenharmony_ci+++ b/Kconfig 3822851890Sopenharmony_ci@@ -7,6 +7,8 @@ mainmenu "Linux/$(ARCH) $(KERNELVERSION) Kernel Configuration" 3922851890Sopenharmony_ci 4022851890Sopenharmony_ci source "scripts/Kconfig.include" 4122851890Sopenharmony_ci 4222851890Sopenharmony_ci+source "bsp/Kconfig" 4322851890Sopenharmony_ci+ 4422851890Sopenharmony_ci source "init/Kconfig" 4522851890Sopenharmony_ci 4622851890Sopenharmony_ci source "kernel/Kconfig.freezer" 4722851890Sopenharmony_cidiff --git a/Makefile b/Makefile 4822851890Sopenharmony_ciindex dce02fbb7..a60ed51b8 100644 4922851890Sopenharmony_ci--- a/Makefile 5022851890Sopenharmony_ci+++ b/Makefile 5122851890Sopenharmony_ci@@ -491,6 +491,7 @@ LINUXINCLUDE := \ 5222851890Sopenharmony_ci -I$(objtree)/arch/$(SRCARCH)/include/generated \ 5322851890Sopenharmony_ci $(if $(building_out_of_srctree),-I$(srctree)/include) \ 5422851890Sopenharmony_ci -I$(objtree)/include \ 5522851890Sopenharmony_ci+ -I$(srctree)/bsp/include \ 5622851890Sopenharmony_ci $(USERINCLUDE) 5722851890Sopenharmony_ci 5822851890Sopenharmony_ci KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE 5922851890Sopenharmony_ci@@ -650,6 +651,7 @@ ifeq ($(KBUILD_EXTMOD),) 6022851890Sopenharmony_ci # Objects we will link into vmlinux / subdirs we need to visit 6122851890Sopenharmony_ci core-y := init/ usr/ 6222851890Sopenharmony_ci drivers-y := drivers/ sound/ 6322851890Sopenharmony_ci+drivers-y += bsp/ 6422851890Sopenharmony_ci drivers-$(CONFIG_SAMPLES) += samples/ 6522851890Sopenharmony_ci drivers-y += net/ virt/ 6622851890Sopenharmony_ci libs-y := lib/ 6722851890Sopenharmony_cidiff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig 6822851890Sopenharmony_ciindex 594b77d89..3ca7de37d 100644 6922851890Sopenharmony_ci--- a/drivers/dma-buf/Kconfig 7022851890Sopenharmony_ci+++ b/drivers/dma-buf/Kconfig 7122851890Sopenharmony_ci@@ -56,19 +56,6 @@ config DMABUF_SELFTESTS 7222851890Sopenharmony_ci default n 7322851890Sopenharmony_ci depends on DMA_SHARED_BUFFER 7422851890Sopenharmony_ci 7522851890Sopenharmony_ci-config DMABUF_PROCESS_INFO 7622851890Sopenharmony_ci- bool "Show dmabuf usage of all processes" 7722851890Sopenharmony_ci- default n 7822851890Sopenharmony_ci- depends on DMA_SHARED_BUFFER 7922851890Sopenharmony_ci- depends on PROC_FS || DEBUG_FS 8022851890Sopenharmony_ci- help 8122851890Sopenharmony_ci- Choose this option to show dmabuf objects usage of all processes. 8222851890Sopenharmony_ci- Firstly, with this option, when a process creates a dmabuf object, 8322851890Sopenharmony_ci- its pid and task_comm will be recorded in the dmabuf. 8422851890Sopenharmony_ci- Secondly, this option creates dma_buf/process_bufinfo file in 8522851890Sopenharmony_ci- debugfs (if DEBUG_FS enabled) and process_dmabuf_info file in procfs 8622851890Sopenharmony_ci- (if PROC_FS enabled) to show dmabuf objects usage of all processes. 8722851890Sopenharmony_ci- 8822851890Sopenharmony_ci menuconfig DMABUF_HEAPS 8922851890Sopenharmony_ci bool "DMA-BUF Userland Memory Heaps" 9022851890Sopenharmony_ci select DMA_SHARED_BUFFER 9122851890Sopenharmony_ci@@ -78,17 +65,6 @@ menuconfig DMABUF_HEAPS 9222851890Sopenharmony_ci allows userspace to allocate dma-bufs that can be shared 9322851890Sopenharmony_ci between drivers. 9422851890Sopenharmony_ci 9522851890Sopenharmony_ci-menuconfig DMABUF_SYSFS_STATS 9622851890Sopenharmony_ci- bool "DMA-BUF sysfs statistics" 9722851890Sopenharmony_ci- depends on DMA_SHARED_BUFFER 9822851890Sopenharmony_ci- help 9922851890Sopenharmony_ci- Choose this option to enable DMA-BUF sysfs statistics 10022851890Sopenharmony_ci- in location /sys/kernel/dmabuf/buffers. 10122851890Sopenharmony_ci- 10222851890Sopenharmony_ci- /sys/kernel/dmabuf/buffers/<inode_number> will contain 10322851890Sopenharmony_ci- statistics for the DMA-BUF with the unique inode number 10422851890Sopenharmony_ci- <inode_number>. 10522851890Sopenharmony_ci- 10622851890Sopenharmony_ci source "drivers/dma-buf/heaps/Kconfig" 10722851890Sopenharmony_ci 10822851890Sopenharmony_ci endmenu 10922851890Sopenharmony_cidiff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile 11022851890Sopenharmony_ciindex cfbc5e3da..995e05f60 100644 11122851890Sopenharmony_ci--- a/drivers/dma-buf/Makefile 11222851890Sopenharmony_ci+++ b/drivers/dma-buf/Makefile 11322851890Sopenharmony_ci@@ -6,7 +6,6 @@ obj-$(CONFIG_DMABUF_HEAPS) += heaps/ 11422851890Sopenharmony_ci obj-$(CONFIG_SYNC_FILE) += sync_file.o 11522851890Sopenharmony_ci obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o 11622851890Sopenharmony_ci obj-$(CONFIG_UDMABUF) += udmabuf.o 11722851890Sopenharmony_ci-obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o 11822851890Sopenharmony_ci 11922851890Sopenharmony_ci dmabuf_selftests-y := \ 12022851890Sopenharmony_ci selftest.o \ 12122851890Sopenharmony_ci@@ -14,5 +13,3 @@ dmabuf_selftests-y := \ 12222851890Sopenharmony_ci st-dma-fence-chain.o 12322851890Sopenharmony_ci 12422851890Sopenharmony_ci obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o 12522851890Sopenharmony_ci- 12622851890Sopenharmony_ci-obj-$(CONFIG_DMABUF_PROCESS_INFO) += dma-buf-process-info.o 12722851890Sopenharmony_cidiff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c 12822851890Sopenharmony_ciindex b6ae42d59..922416b3a 100644 12922851890Sopenharmony_ci--- a/drivers/dma-buf/dma-buf.c 13022851890Sopenharmony_ci+++ b/drivers/dma-buf/dma-buf.c 13122851890Sopenharmony_ci@@ -29,9 +29,6 @@ 13222851890Sopenharmony_ci #include <uapi/linux/dma-buf.h> 13322851890Sopenharmony_ci #include <uapi/linux/magic.h> 13422851890Sopenharmony_ci 13522851890Sopenharmony_ci-#include "dma-buf-sysfs-stats.h" 13622851890Sopenharmony_ci-#include "dma-buf-process-info.h" 13722851890Sopenharmony_ci- 13822851890Sopenharmony_ci static inline int is_dma_buf_file(struct file *); 13922851890Sopenharmony_ci 14022851890Sopenharmony_ci struct dma_buf_list { 14122851890Sopenharmony_ci@@ -82,7 +79,6 @@ static void dma_buf_release(struct dentry *dentry) 14222851890Sopenharmony_ci if (dmabuf->resv == (struct dma_resv *)&dmabuf[1]) 14322851890Sopenharmony_ci dma_resv_fini(dmabuf->resv); 14422851890Sopenharmony_ci 14522851890Sopenharmony_ci- dma_buf_stats_teardown(dmabuf); 14622851890Sopenharmony_ci module_put(dmabuf->owner); 14722851890Sopenharmony_ci kfree(dmabuf->name); 14822851890Sopenharmony_ci kfree(dmabuf); 14922851890Sopenharmony_ci@@ -583,10 +579,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) 15022851890Sopenharmony_ci file->f_mode |= FMODE_LSEEK; 15122851890Sopenharmony_ci dmabuf->file = file; 15222851890Sopenharmony_ci 15322851890Sopenharmony_ci- ret = dma_buf_stats_setup(dmabuf); 15422851890Sopenharmony_ci- if (ret) 15522851890Sopenharmony_ci- goto err_sysfs; 15622851890Sopenharmony_ci- 15722851890Sopenharmony_ci mutex_init(&dmabuf->lock); 15822851890Sopenharmony_ci INIT_LIST_HEAD(&dmabuf->attachments); 15922851890Sopenharmony_ci 16022851890Sopenharmony_ci@@ -594,17 +586,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) 16122851890Sopenharmony_ci list_add(&dmabuf->list_node, &db_list.head); 16222851890Sopenharmony_ci mutex_unlock(&db_list.lock); 16322851890Sopenharmony_ci 16422851890Sopenharmony_ci- init_dma_buf_task_info(dmabuf); 16522851890Sopenharmony_ci return dmabuf; 16622851890Sopenharmony_ci 16722851890Sopenharmony_ci-err_sysfs: 16822851890Sopenharmony_ci- /* 16922851890Sopenharmony_ci- * Set file->f_path.dentry->d_fsdata to NULL so that when 17022851890Sopenharmony_ci- * dma_buf_release() gets invoked by dentry_ops, it exits 17122851890Sopenharmony_ci- * early before calling the release() dma_buf op. 17222851890Sopenharmony_ci- */ 17322851890Sopenharmony_ci- file->f_path.dentry->d_fsdata = NULL; 17422851890Sopenharmony_ci- fput(file); 17522851890Sopenharmony_ci err_dmabuf: 17622851890Sopenharmony_ci kfree(dmabuf); 17722851890Sopenharmony_ci err_module: 17822851890Sopenharmony_ci@@ -1304,10 +1287,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) 17922851890Sopenharmony_ci return ret; 18022851890Sopenharmony_ci 18122851890Sopenharmony_ci seq_puts(s, "\nDma-buf Objects:\n"); 18222851890Sopenharmony_ci- seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\t" 18322851890Sopenharmony_ci- "%-16s\t%-16s\t%-16s\n", 18422851890Sopenharmony_ci- "size", "flags", "mode", "count", "ino", 18522851890Sopenharmony_ci- "buf_name", "exp_pid", "exp_task_comm"); 18622851890Sopenharmony_ci+ seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\n", 18722851890Sopenharmony_ci+ "size", "flags", "mode", "count", "ino"); 18822851890Sopenharmony_ci 18922851890Sopenharmony_ci list_for_each_entry(buf_obj, &db_list.head, list_node) { 19022851890Sopenharmony_ci 19122851890Sopenharmony_ci@@ -1315,16 +1296,13 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) 19222851890Sopenharmony_ci if (ret) 19322851890Sopenharmony_ci goto error_unlock; 19422851890Sopenharmony_ci 19522851890Sopenharmony_ci- seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\t" 19622851890Sopenharmony_ci- "%-16d\t%-16s\n", 19722851890Sopenharmony_ci+ seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\n", 19822851890Sopenharmony_ci buf_obj->size, 19922851890Sopenharmony_ci buf_obj->file->f_flags, buf_obj->file->f_mode, 20022851890Sopenharmony_ci file_count(buf_obj->file), 20122851890Sopenharmony_ci buf_obj->exp_name, 20222851890Sopenharmony_ci file_inode(buf_obj->file)->i_ino, 20322851890Sopenharmony_ci- buf_obj->name ?: "NULL", 20422851890Sopenharmony_ci- dma_buf_exp_pid(buf_obj), 20522851890Sopenharmony_ci- dma_buf_exp_task_comm(buf_obj) ?: "NULL"); 20622851890Sopenharmony_ci+ buf_obj->name ?: ""); 20722851890Sopenharmony_ci 20822851890Sopenharmony_ci robj = buf_obj->resv; 20922851890Sopenharmony_ci while (true) { 21022851890Sopenharmony_ci@@ -1405,7 +1383,6 @@ static int dma_buf_init_debugfs(void) 21122851890Sopenharmony_ci err = PTR_ERR(d); 21222851890Sopenharmony_ci } 21322851890Sopenharmony_ci 21422851890Sopenharmony_ci- dma_buf_process_info_init_debugfs(dma_buf_debugfs_dir); 21522851890Sopenharmony_ci return err; 21622851890Sopenharmony_ci } 21722851890Sopenharmony_ci 21822851890Sopenharmony_ci@@ -1423,27 +1400,8 @@ static inline void dma_buf_uninit_debugfs(void) 21922851890Sopenharmony_ci } 22022851890Sopenharmony_ci #endif 22122851890Sopenharmony_ci 22222851890Sopenharmony_ci-#ifdef CONFIG_DMABUF_PROCESS_INFO 22322851890Sopenharmony_ci-struct dma_buf *get_dma_buf_from_file(struct file *f) 22422851890Sopenharmony_ci-{ 22522851890Sopenharmony_ci- if (IS_ERR_OR_NULL(f)) 22622851890Sopenharmony_ci- return NULL; 22722851890Sopenharmony_ci- 22822851890Sopenharmony_ci- if (!is_dma_buf_file(f)) 22922851890Sopenharmony_ci- return NULL; 23022851890Sopenharmony_ci- 23122851890Sopenharmony_ci- return f->private_data; 23222851890Sopenharmony_ci-} 23322851890Sopenharmony_ci-#endif /* CONFIG_DMABUF_PROCESS_INFO */ 23422851890Sopenharmony_ci- 23522851890Sopenharmony_ci static int __init dma_buf_init(void) 23622851890Sopenharmony_ci { 23722851890Sopenharmony_ci- int ret; 23822851890Sopenharmony_ci- 23922851890Sopenharmony_ci- ret = dma_buf_init_sysfs_statistics(); 24022851890Sopenharmony_ci- if (ret) 24122851890Sopenharmony_ci- return ret; 24222851890Sopenharmony_ci- 24322851890Sopenharmony_ci dma_buf_mnt = kern_mount(&dma_buf_fs_type); 24422851890Sopenharmony_ci if (IS_ERR(dma_buf_mnt)) 24522851890Sopenharmony_ci return PTR_ERR(dma_buf_mnt); 24622851890Sopenharmony_ci@@ -1451,7 +1409,6 @@ static int __init dma_buf_init(void) 24722851890Sopenharmony_ci mutex_init(&db_list.lock); 24822851890Sopenharmony_ci INIT_LIST_HEAD(&db_list.head); 24922851890Sopenharmony_ci dma_buf_init_debugfs(); 25022851890Sopenharmony_ci- dma_buf_process_info_init_procfs(); 25122851890Sopenharmony_ci return 0; 25222851890Sopenharmony_ci } 25322851890Sopenharmony_ci subsys_initcall(dma_buf_init); 25422851890Sopenharmony_ci@@ -1460,7 +1417,5 @@ static void __exit dma_buf_deinit(void) 25522851890Sopenharmony_ci { 25622851890Sopenharmony_ci dma_buf_uninit_debugfs(); 25722851890Sopenharmony_ci kern_unmount(dma_buf_mnt); 25822851890Sopenharmony_ci- dma_buf_uninit_sysfs_statistics(); 25922851890Sopenharmony_ci- dma_buf_process_info_uninit_procfs(); 26022851890Sopenharmony_ci } 26122851890Sopenharmony_ci __exitcall(dma_buf_deinit); 26222851890Sopenharmony_cidiff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c 26322851890Sopenharmony_ciindex 70e410c64..26d59b48f 100644 26422851890Sopenharmony_ci--- a/drivers/dma-buf/dma-heap.c 26522851890Sopenharmony_ci+++ b/drivers/dma-buf/dma-heap.c 26622851890Sopenharmony_ci@@ -14,6 +14,7 @@ 26722851890Sopenharmony_ci #include <linux/xarray.h> 26822851890Sopenharmony_ci #include <linux/list.h> 26922851890Sopenharmony_ci #include <linux/slab.h> 27022851890Sopenharmony_ci+#include <linux/nospec.h> 27122851890Sopenharmony_ci #include <linux/uaccess.h> 27222851890Sopenharmony_ci #include <linux/syscalls.h> 27322851890Sopenharmony_ci #include <linux/dma-heap.h> 27422851890Sopenharmony_ci@@ -30,6 +31,7 @@ 27522851890Sopenharmony_ci * @heap_devt heap device node 27622851890Sopenharmony_ci * @list list head connecting to list of heaps 27722851890Sopenharmony_ci * @heap_cdev heap char device 27822851890Sopenharmony_ci+ * @heap_dev heap device struct 27922851890Sopenharmony_ci * 28022851890Sopenharmony_ci * Represents a heap of memory from which buffers can be made. 28122851890Sopenharmony_ci */ 28222851890Sopenharmony_ci@@ -40,6 +42,8 @@ struct dma_heap { 28322851890Sopenharmony_ci dev_t heap_devt; 28422851890Sopenharmony_ci struct list_head list; 28522851890Sopenharmony_ci struct cdev heap_cdev; 28622851890Sopenharmony_ci+ struct kref refcount; 28722851890Sopenharmony_ci+ struct device *heap_dev; 28822851890Sopenharmony_ci }; 28922851890Sopenharmony_ci 29022851890Sopenharmony_ci static LIST_HEAD(heap_list); 29122851890Sopenharmony_ci@@ -48,20 +52,72 @@ static dev_t dma_heap_devt; 29222851890Sopenharmony_ci static struct class *dma_heap_class; 29322851890Sopenharmony_ci static DEFINE_XARRAY_ALLOC(dma_heap_minors); 29422851890Sopenharmony_ci 29522851890Sopenharmony_ci-static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, 29622851890Sopenharmony_ci- unsigned int fd_flags, 29722851890Sopenharmony_ci- unsigned int heap_flags) 29822851890Sopenharmony_ci+struct dma_heap *dma_heap_find(const char *name) 29922851890Sopenharmony_ci { 30022851890Sopenharmony_ci+ struct dma_heap *h; 30122851890Sopenharmony_ci+ 30222851890Sopenharmony_ci+ mutex_lock(&heap_list_lock); 30322851890Sopenharmony_ci+ list_for_each_entry(h, &heap_list, list) { 30422851890Sopenharmony_ci+ if (!strcmp(h->name, name)) { 30522851890Sopenharmony_ci+ kref_get(&h->refcount); 30622851890Sopenharmony_ci+ mutex_unlock(&heap_list_lock); 30722851890Sopenharmony_ci+ return h; 30822851890Sopenharmony_ci+ } 30922851890Sopenharmony_ci+ } 31022851890Sopenharmony_ci+ mutex_unlock(&heap_list_lock); 31122851890Sopenharmony_ci+ return NULL; 31222851890Sopenharmony_ci+} 31322851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_find); 31422851890Sopenharmony_ci+ 31522851890Sopenharmony_ci+ 31622851890Sopenharmony_ci+void dma_heap_buffer_free(struct dma_buf *dmabuf) 31722851890Sopenharmony_ci+{ 31822851890Sopenharmony_ci+ dma_buf_put(dmabuf); 31922851890Sopenharmony_ci+} 32022851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_buffer_free); 32122851890Sopenharmony_ci+ 32222851890Sopenharmony_ci+struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, 32322851890Sopenharmony_ci+ unsigned int fd_flags, 32422851890Sopenharmony_ci+ unsigned int heap_flags) 32522851890Sopenharmony_ci+{ 32622851890Sopenharmony_ci+ if (fd_flags & ~DMA_HEAP_VALID_FD_FLAGS) 32722851890Sopenharmony_ci+ return ERR_PTR(-EINVAL); 32822851890Sopenharmony_ci+ 32922851890Sopenharmony_ci+ if (heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS) 33022851890Sopenharmony_ci+ return ERR_PTR(-EINVAL); 33122851890Sopenharmony_ci /* 33222851890Sopenharmony_ci * Allocations from all heaps have to begin 33322851890Sopenharmony_ci * and end on page boundaries. 33422851890Sopenharmony_ci */ 33522851890Sopenharmony_ci len = PAGE_ALIGN(len); 33622851890Sopenharmony_ci if (!len) 33722851890Sopenharmony_ci- return -EINVAL; 33822851890Sopenharmony_ci+ return ERR_PTR(-EINVAL); 33922851890Sopenharmony_ci 34022851890Sopenharmony_ci return heap->ops->allocate(heap, len, fd_flags, heap_flags); 34122851890Sopenharmony_ci } 34222851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_buffer_alloc); 34322851890Sopenharmony_ci+ 34422851890Sopenharmony_ci+int dma_heap_bufferfd_alloc(struct dma_heap *heap, size_t len, 34522851890Sopenharmony_ci+ unsigned int fd_flags, 34622851890Sopenharmony_ci+ unsigned int heap_flags) 34722851890Sopenharmony_ci+{ 34822851890Sopenharmony_ci+ struct dma_buf *dmabuf; 34922851890Sopenharmony_ci+ int fd; 35022851890Sopenharmony_ci+ 35122851890Sopenharmony_ci+ dmabuf = dma_heap_buffer_alloc(heap, len, fd_flags, heap_flags); 35222851890Sopenharmony_ci+ 35322851890Sopenharmony_ci+ if (IS_ERR(dmabuf)) 35422851890Sopenharmony_ci+ return PTR_ERR(dmabuf); 35522851890Sopenharmony_ci+ 35622851890Sopenharmony_ci+ fd = dma_buf_fd(dmabuf, fd_flags); 35722851890Sopenharmony_ci+ if (fd < 0) { 35822851890Sopenharmony_ci+ dma_buf_put(dmabuf); 35922851890Sopenharmony_ci+ /* just return, as put will call release and that will free */ 36022851890Sopenharmony_ci+ } 36122851890Sopenharmony_ci+ return fd; 36222851890Sopenharmony_ci+ 36322851890Sopenharmony_ci+} 36422851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_bufferfd_alloc); 36522851890Sopenharmony_ci 36622851890Sopenharmony_ci static int dma_heap_open(struct inode *inode, struct file *file) 36722851890Sopenharmony_ci { 36822851890Sopenharmony_ci@@ -89,15 +145,9 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data) 36922851890Sopenharmony_ci if (heap_allocation->fd) 37022851890Sopenharmony_ci return -EINVAL; 37122851890Sopenharmony_ci 37222851890Sopenharmony_ci- if (heap_allocation->fd_flags & ~DMA_HEAP_VALID_FD_FLAGS) 37322851890Sopenharmony_ci- return -EINVAL; 37422851890Sopenharmony_ci- 37522851890Sopenharmony_ci- if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS) 37622851890Sopenharmony_ci- return -EINVAL; 37722851890Sopenharmony_ci- 37822851890Sopenharmony_ci- fd = dma_heap_buffer_alloc(heap, heap_allocation->len, 37922851890Sopenharmony_ci- heap_allocation->fd_flags, 38022851890Sopenharmony_ci- heap_allocation->heap_flags); 38122851890Sopenharmony_ci+ fd = dma_heap_bufferfd_alloc(heap, heap_allocation->len, 38222851890Sopenharmony_ci+ heap_allocation->fd_flags, 38322851890Sopenharmony_ci+ heap_allocation->heap_flags); 38422851890Sopenharmony_ci if (fd < 0) 38522851890Sopenharmony_ci return fd; 38622851890Sopenharmony_ci 38722851890Sopenharmony_ci@@ -123,6 +173,7 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd, 38822851890Sopenharmony_ci if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds)) 38922851890Sopenharmony_ci return -EINVAL; 39022851890Sopenharmony_ci 39122851890Sopenharmony_ci+ nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds)); 39222851890Sopenharmony_ci /* Get the kernel ioctl cmd that matches */ 39322851890Sopenharmony_ci kcmd = dma_heap_ioctl_cmds[nr]; 39422851890Sopenharmony_ci 39522851890Sopenharmony_ci@@ -189,6 +240,47 @@ void *dma_heap_get_drvdata(struct dma_heap *heap) 39622851890Sopenharmony_ci { 39722851890Sopenharmony_ci return heap->priv; 39822851890Sopenharmony_ci } 39922851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_get_drvdata); 40022851890Sopenharmony_ci+ 40122851890Sopenharmony_ci+static void dma_heap_release(struct kref *ref) 40222851890Sopenharmony_ci+{ 40322851890Sopenharmony_ci+ struct dma_heap *heap = container_of(ref, struct dma_heap, refcount); 40422851890Sopenharmony_ci+ int minor = MINOR(heap->heap_devt); 40522851890Sopenharmony_ci+ 40622851890Sopenharmony_ci+ /* Note, we already holding the heap_list_lock here */ 40722851890Sopenharmony_ci+ list_del(&heap->list); 40822851890Sopenharmony_ci+ 40922851890Sopenharmony_ci+ device_destroy(dma_heap_class, heap->heap_devt); 41022851890Sopenharmony_ci+ cdev_del(&heap->heap_cdev); 41122851890Sopenharmony_ci+ xa_erase(&dma_heap_minors, minor); 41222851890Sopenharmony_ci+ 41322851890Sopenharmony_ci+ kfree(heap); 41422851890Sopenharmony_ci+} 41522851890Sopenharmony_ci+ 41622851890Sopenharmony_ci+void dma_heap_put(struct dma_heap *h) 41722851890Sopenharmony_ci+{ 41822851890Sopenharmony_ci+ /* 41922851890Sopenharmony_ci+ * Take the heap_list_lock now to avoid racing with code 42022851890Sopenharmony_ci+ * scanning the list and then taking a kref. 42122851890Sopenharmony_ci+ */ 42222851890Sopenharmony_ci+ mutex_lock(&heap_list_lock); 42322851890Sopenharmony_ci+ kref_put(&h->refcount, dma_heap_release); 42422851890Sopenharmony_ci+ mutex_unlock(&heap_list_lock); 42522851890Sopenharmony_ci+} 42622851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_put); 42722851890Sopenharmony_ci+ 42822851890Sopenharmony_ci+/** 42922851890Sopenharmony_ci+ * dma_heap_get_dev() - get device struct for the heap 43022851890Sopenharmony_ci+ * @heap: DMA-Heap to retrieve device struct from 43122851890Sopenharmony_ci+ * 43222851890Sopenharmony_ci+ * Returns: 43322851890Sopenharmony_ci+ * The device struct for the heap. 43422851890Sopenharmony_ci+ */ 43522851890Sopenharmony_ci+struct device *dma_heap_get_dev(struct dma_heap *heap) 43622851890Sopenharmony_ci+{ 43722851890Sopenharmony_ci+ return heap->heap_dev; 43822851890Sopenharmony_ci+} 43922851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_get_dev); 44022851890Sopenharmony_ci 44122851890Sopenharmony_ci /** 44222851890Sopenharmony_ci * dma_heap_get_name() - get heap name 44322851890Sopenharmony_ci@@ -201,11 +293,11 @@ const char *dma_heap_get_name(struct dma_heap *heap) 44422851890Sopenharmony_ci { 44522851890Sopenharmony_ci return heap->name; 44622851890Sopenharmony_ci } 44722851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_get_name); 44822851890Sopenharmony_ci 44922851890Sopenharmony_ci struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) 45022851890Sopenharmony_ci { 45122851890Sopenharmony_ci- struct dma_heap *heap, *h, *err_ret; 45222851890Sopenharmony_ci- struct device *dev_ret; 45322851890Sopenharmony_ci+ struct dma_heap *heap, *err_ret; 45422851890Sopenharmony_ci unsigned int minor; 45522851890Sopenharmony_ci int ret; 45622851890Sopenharmony_ci 45722851890Sopenharmony_ci@@ -220,21 +312,19 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) 45822851890Sopenharmony_ci } 45922851890Sopenharmony_ci 46022851890Sopenharmony_ci /* check the name is unique */ 46122851890Sopenharmony_ci- mutex_lock(&heap_list_lock); 46222851890Sopenharmony_ci- list_for_each_entry(h, &heap_list, list) { 46322851890Sopenharmony_ci- if (!strcmp(h->name, exp_info->name)) { 46422851890Sopenharmony_ci- mutex_unlock(&heap_list_lock); 46522851890Sopenharmony_ci- pr_err("dma_heap: Already registered heap named %s\n", 46622851890Sopenharmony_ci- exp_info->name); 46722851890Sopenharmony_ci- return ERR_PTR(-EINVAL); 46822851890Sopenharmony_ci- } 46922851890Sopenharmony_ci+ heap = dma_heap_find(exp_info->name); 47022851890Sopenharmony_ci+ if (heap) { 47122851890Sopenharmony_ci+ pr_err("dma_heap: Already registered heap named %s\n", 47222851890Sopenharmony_ci+ exp_info->name); 47322851890Sopenharmony_ci+ dma_heap_put(heap); 47422851890Sopenharmony_ci+ return ERR_PTR(-EINVAL); 47522851890Sopenharmony_ci } 47622851890Sopenharmony_ci- mutex_unlock(&heap_list_lock); 47722851890Sopenharmony_ci 47822851890Sopenharmony_ci heap = kzalloc(sizeof(*heap), GFP_KERNEL); 47922851890Sopenharmony_ci if (!heap) 48022851890Sopenharmony_ci return ERR_PTR(-ENOMEM); 48122851890Sopenharmony_ci 48222851890Sopenharmony_ci+ kref_init(&heap->refcount); 48322851890Sopenharmony_ci heap->name = exp_info->name; 48422851890Sopenharmony_ci heap->ops = exp_info->ops; 48522851890Sopenharmony_ci heap->priv = exp_info->priv; 48622851890Sopenharmony_ci@@ -259,16 +349,20 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) 48722851890Sopenharmony_ci goto err1; 48822851890Sopenharmony_ci } 48922851890Sopenharmony_ci 49022851890Sopenharmony_ci- dev_ret = device_create(dma_heap_class, 49122851890Sopenharmony_ci- NULL, 49222851890Sopenharmony_ci- heap->heap_devt, 49322851890Sopenharmony_ci- NULL, 49422851890Sopenharmony_ci- heap->name); 49522851890Sopenharmony_ci- if (IS_ERR(dev_ret)) { 49622851890Sopenharmony_ci+ heap->heap_dev = device_create(dma_heap_class, 49722851890Sopenharmony_ci+ NULL, 49822851890Sopenharmony_ci+ heap->heap_devt, 49922851890Sopenharmony_ci+ NULL, 50022851890Sopenharmony_ci+ heap->name); 50122851890Sopenharmony_ci+ if (IS_ERR(heap->heap_dev)) { 50222851890Sopenharmony_ci pr_err("dma_heap: Unable to create device\n"); 50322851890Sopenharmony_ci- err_ret = ERR_CAST(dev_ret); 50422851890Sopenharmony_ci+ err_ret = ERR_CAST(heap->heap_dev); 50522851890Sopenharmony_ci goto err2; 50622851890Sopenharmony_ci } 50722851890Sopenharmony_ci+ 50822851890Sopenharmony_ci+ /* Make sure it doesn't disappear on us */ 50922851890Sopenharmony_ci+ heap->heap_dev = get_device(heap->heap_dev); 51022851890Sopenharmony_ci+ 51122851890Sopenharmony_ci /* Add heap to the list */ 51222851890Sopenharmony_ci mutex_lock(&heap_list_lock); 51322851890Sopenharmony_ci list_add(&heap->list, &heap_list); 51422851890Sopenharmony_ci@@ -284,27 +378,88 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) 51522851890Sopenharmony_ci kfree(heap); 51622851890Sopenharmony_ci return err_ret; 51722851890Sopenharmony_ci } 51822851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dma_heap_add); 51922851890Sopenharmony_ci 52022851890Sopenharmony_ci static char *dma_heap_devnode(struct device *dev, umode_t *mode) 52122851890Sopenharmony_ci { 52222851890Sopenharmony_ci return kasprintf(GFP_KERNEL, "dma_heap/%s", dev_name(dev)); 52322851890Sopenharmony_ci } 52422851890Sopenharmony_ci 52522851890Sopenharmony_ci+static ssize_t total_pools_kb_show(struct kobject *kobj, 52622851890Sopenharmony_ci+ struct kobj_attribute *attr, char *buf) 52722851890Sopenharmony_ci+{ 52822851890Sopenharmony_ci+ struct dma_heap *heap; 52922851890Sopenharmony_ci+ u64 total_pool_size = 0; 53022851890Sopenharmony_ci+ 53122851890Sopenharmony_ci+ mutex_lock(&heap_list_lock); 53222851890Sopenharmony_ci+ list_for_each_entry(heap, &heap_list, list) { 53322851890Sopenharmony_ci+ if (heap->ops->get_pool_size) 53422851890Sopenharmony_ci+ total_pool_size += heap->ops->get_pool_size(heap); 53522851890Sopenharmony_ci+ } 53622851890Sopenharmony_ci+ mutex_unlock(&heap_list_lock); 53722851890Sopenharmony_ci+ 53822851890Sopenharmony_ci+ return sysfs_emit(buf, "%llu\n", total_pool_size / 1024); 53922851890Sopenharmony_ci+} 54022851890Sopenharmony_ci+ 54122851890Sopenharmony_ci+static struct kobj_attribute total_pools_kb_attr = 54222851890Sopenharmony_ci+ __ATTR_RO(total_pools_kb); 54322851890Sopenharmony_ci+ 54422851890Sopenharmony_ci+static struct attribute *dma_heap_sysfs_attrs[] = { 54522851890Sopenharmony_ci+ &total_pools_kb_attr.attr, 54622851890Sopenharmony_ci+ NULL, 54722851890Sopenharmony_ci+}; 54822851890Sopenharmony_ci+ 54922851890Sopenharmony_ci+ATTRIBUTE_GROUPS(dma_heap_sysfs); 55022851890Sopenharmony_ci+ 55122851890Sopenharmony_ci+static struct kobject *dma_heap_kobject; 55222851890Sopenharmony_ci+ 55322851890Sopenharmony_ci+static int dma_heap_sysfs_setup(void) 55422851890Sopenharmony_ci+{ 55522851890Sopenharmony_ci+ int ret; 55622851890Sopenharmony_ci+ 55722851890Sopenharmony_ci+ dma_heap_kobject = kobject_create_and_add("dma_heap", kernel_kobj); 55822851890Sopenharmony_ci+ if (!dma_heap_kobject) 55922851890Sopenharmony_ci+ return -ENOMEM; 56022851890Sopenharmony_ci+ 56122851890Sopenharmony_ci+ ret = sysfs_create_groups(dma_heap_kobject, dma_heap_sysfs_groups); 56222851890Sopenharmony_ci+ if (ret) { 56322851890Sopenharmony_ci+ kobject_put(dma_heap_kobject); 56422851890Sopenharmony_ci+ return ret; 56522851890Sopenharmony_ci+ } 56622851890Sopenharmony_ci+ 56722851890Sopenharmony_ci+ return 0; 56822851890Sopenharmony_ci+} 56922851890Sopenharmony_ci+ 57022851890Sopenharmony_ci+static void dma_heap_sysfs_teardown(void) 57122851890Sopenharmony_ci+{ 57222851890Sopenharmony_ci+ kobject_put(dma_heap_kobject); 57322851890Sopenharmony_ci+} 57422851890Sopenharmony_ci+ 57522851890Sopenharmony_ci static int dma_heap_init(void) 57622851890Sopenharmony_ci { 57722851890Sopenharmony_ci int ret; 57822851890Sopenharmony_ci 57922851890Sopenharmony_ci- ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); 58022851890Sopenharmony_ci+ ret = dma_heap_sysfs_setup(); 58122851890Sopenharmony_ci if (ret) 58222851890Sopenharmony_ci return ret; 58322851890Sopenharmony_ci 58422851890Sopenharmony_ci+ ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); 58522851890Sopenharmony_ci+ if (ret) 58622851890Sopenharmony_ci+ goto err_chrdev; 58722851890Sopenharmony_ci+ 58822851890Sopenharmony_ci dma_heap_class = class_create(THIS_MODULE, DEVNAME); 58922851890Sopenharmony_ci if (IS_ERR(dma_heap_class)) { 59022851890Sopenharmony_ci- unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); 59122851890Sopenharmony_ci- return PTR_ERR(dma_heap_class); 59222851890Sopenharmony_ci+ ret = PTR_ERR(dma_heap_class); 59322851890Sopenharmony_ci+ goto err_class; 59422851890Sopenharmony_ci } 59522851890Sopenharmony_ci dma_heap_class->devnode = dma_heap_devnode; 59622851890Sopenharmony_ci 59722851890Sopenharmony_ci return 0; 59822851890Sopenharmony_ci+ 59922851890Sopenharmony_ci+err_class: 60022851890Sopenharmony_ci+ unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); 60122851890Sopenharmony_ci+err_chrdev: 60222851890Sopenharmony_ci+ dma_heap_sysfs_teardown(); 60322851890Sopenharmony_ci+ return ret; 60422851890Sopenharmony_ci } 60522851890Sopenharmony_ci subsys_initcall(dma_heap_init); 60622851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig 60722851890Sopenharmony_ciindex a5eef06c4..ff52efa83 100644 60822851890Sopenharmony_ci--- a/drivers/dma-buf/heaps/Kconfig 60922851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/Kconfig 61022851890Sopenharmony_ci@@ -1,12 +1,22 @@ 61122851890Sopenharmony_ci+menuconfig DMABUF_HEAPS_DEFERRED_FREE 61222851890Sopenharmony_ci+ bool "DMA-BUF heaps deferred-free library" 61322851890Sopenharmony_ci+ help 61422851890Sopenharmony_ci+ Choose this option to enable the DMA-BUF heaps deferred-free library. 61522851890Sopenharmony_ci+ 61622851890Sopenharmony_ci+menuconfig DMABUF_HEAPS_PAGE_POOL 61722851890Sopenharmony_ci+ bool "DMA-BUF heaps page-pool library" 61822851890Sopenharmony_ci+ help 61922851890Sopenharmony_ci+ Choose this option to enable the DMA-BUF heaps page-pool library. 62022851890Sopenharmony_ci+ 62122851890Sopenharmony_ci config DMABUF_HEAPS_SYSTEM 62222851890Sopenharmony_ci- bool "DMA-BUF System Heap" 62322851890Sopenharmony_ci- depends on DMABUF_HEAPS 62422851890Sopenharmony_ci+ tristate "DMA-BUF System Heap" 62522851890Sopenharmony_ci+ depends on DMABUF_HEAPS && DMABUF_HEAPS_DEFERRED_FREE && DMABUF_HEAPS_PAGE_POOL 62622851890Sopenharmony_ci help 62722851890Sopenharmony_ci Choose this option to enable the system dmabuf heap. The system heap 62822851890Sopenharmony_ci is backed by pages from the buddy allocator. If in doubt, say Y. 62922851890Sopenharmony_ci 63022851890Sopenharmony_ci config DMABUF_HEAPS_CMA 63122851890Sopenharmony_ci- bool "DMA-BUF CMA Heap" 63222851890Sopenharmony_ci+ tristate "DMA-BUF CMA Heap" 63322851890Sopenharmony_ci depends on DMABUF_HEAPS && DMA_CMA 63422851890Sopenharmony_ci help 63522851890Sopenharmony_ci Choose this option to enable dma-buf CMA heap. This heap is backed 63622851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile 63722851890Sopenharmony_ciindex 6e54cdec3..4d4cd94a3 100644 63822851890Sopenharmony_ci--- a/drivers/dma-buf/heaps/Makefile 63922851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/Makefile 64022851890Sopenharmony_ci@@ -1,4 +1,5 @@ 64122851890Sopenharmony_ci # SPDX-License-Identifier: GPL-2.0 64222851890Sopenharmony_ci-obj-y += heap-helpers.o 64322851890Sopenharmony_ci+obj-$(CONFIG_DMABUF_HEAPS_DEFERRED_FREE) += deferred-free-helper.o 64422851890Sopenharmony_ci+obj-$(CONFIG_DMABUF_HEAPS_PAGE_POOL) += page_pool.o 64522851890Sopenharmony_ci obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o 64622851890Sopenharmony_ci obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o 64722851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c 64822851890Sopenharmony_ciindex e55384dc1..fd564aa70 100644 64922851890Sopenharmony_ci--- a/drivers/dma-buf/heaps/cma_heap.c 65022851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/cma_heap.c 65122851890Sopenharmony_ci@@ -2,76 +2,306 @@ 65222851890Sopenharmony_ci /* 65322851890Sopenharmony_ci * DMABUF CMA heap exporter 65422851890Sopenharmony_ci * 65522851890Sopenharmony_ci- * Copyright (C) 2012, 2019 Linaro Ltd. 65622851890Sopenharmony_ci+ * Copyright (C) 2012, 2019, 2020 Linaro Ltd. 65722851890Sopenharmony_ci * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson. 65822851890Sopenharmony_ci+ * 65922851890Sopenharmony_ci+ * Also utilizing parts of Andrew Davis' SRAM heap: 66022851890Sopenharmony_ci+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 66122851890Sopenharmony_ci+ * Andrew F. Davis <afd@ti.com> 66222851890Sopenharmony_ci */ 66322851890Sopenharmony_ci- 66422851890Sopenharmony_ci #include <linux/cma.h> 66522851890Sopenharmony_ci-#include <linux/device.h> 66622851890Sopenharmony_ci #include <linux/dma-buf.h> 66722851890Sopenharmony_ci #include <linux/dma-heap.h> 66822851890Sopenharmony_ci #include <linux/dma-map-ops.h> 66922851890Sopenharmony_ci #include <linux/err.h> 67022851890Sopenharmony_ci-#include <linux/errno.h> 67122851890Sopenharmony_ci #include <linux/highmem.h> 67222851890Sopenharmony_ci+#include <linux/io.h> 67322851890Sopenharmony_ci+#include <linux/mm.h> 67422851890Sopenharmony_ci #include <linux/module.h> 67522851890Sopenharmony_ci-#include <linux/slab.h> 67622851890Sopenharmony_ci #include <linux/scatterlist.h> 67722851890Sopenharmony_ci-#include <linux/sched/signal.h> 67822851890Sopenharmony_ci+#include <linux/slab.h> 67922851890Sopenharmony_ci+#include <linux/vmalloc.h> 68022851890Sopenharmony_ci 68122851890Sopenharmony_ci-#include "heap-helpers.h" 68222851890Sopenharmony_ci 68322851890Sopenharmony_ci struct cma_heap { 68422851890Sopenharmony_ci struct dma_heap *heap; 68522851890Sopenharmony_ci struct cma *cma; 68622851890Sopenharmony_ci }; 68722851890Sopenharmony_ci 68822851890Sopenharmony_ci-static void cma_heap_free(struct heap_helper_buffer *buffer) 68922851890Sopenharmony_ci+struct cma_heap_buffer { 69022851890Sopenharmony_ci+ struct cma_heap *heap; 69122851890Sopenharmony_ci+ struct list_head attachments; 69222851890Sopenharmony_ci+ struct mutex lock; 69322851890Sopenharmony_ci+ unsigned long len; 69422851890Sopenharmony_ci+ struct page *cma_pages; 69522851890Sopenharmony_ci+ struct page **pages; 69622851890Sopenharmony_ci+ pgoff_t pagecount; 69722851890Sopenharmony_ci+ int vmap_cnt; 69822851890Sopenharmony_ci+ void *vaddr; 69922851890Sopenharmony_ci+}; 70022851890Sopenharmony_ci+ 70122851890Sopenharmony_ci+struct dma_heap_attachment { 70222851890Sopenharmony_ci+ struct device *dev; 70322851890Sopenharmony_ci+ struct sg_table table; 70422851890Sopenharmony_ci+ struct list_head list; 70522851890Sopenharmony_ci+ bool mapped; 70622851890Sopenharmony_ci+}; 70722851890Sopenharmony_ci+ 70822851890Sopenharmony_ci+static int cma_heap_attach(struct dma_buf *dmabuf, 70922851890Sopenharmony_ci+ struct dma_buf_attachment *attachment) 71022851890Sopenharmony_ci+{ 71122851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 71222851890Sopenharmony_ci+ struct dma_heap_attachment *a; 71322851890Sopenharmony_ci+ int ret; 71422851890Sopenharmony_ci+ 71522851890Sopenharmony_ci+ a = kzalloc(sizeof(*a), GFP_KERNEL); 71622851890Sopenharmony_ci+ if (!a) 71722851890Sopenharmony_ci+ return -ENOMEM; 71822851890Sopenharmony_ci+ 71922851890Sopenharmony_ci+ ret = sg_alloc_table_from_pages(&a->table, buffer->pages, 72022851890Sopenharmony_ci+ buffer->pagecount, 0, 72122851890Sopenharmony_ci+ buffer->pagecount << PAGE_SHIFT, 72222851890Sopenharmony_ci+ GFP_KERNEL); 72322851890Sopenharmony_ci+ if (ret) { 72422851890Sopenharmony_ci+ kfree(a); 72522851890Sopenharmony_ci+ return ret; 72622851890Sopenharmony_ci+ } 72722851890Sopenharmony_ci+ 72822851890Sopenharmony_ci+ a->dev = attachment->dev; 72922851890Sopenharmony_ci+ INIT_LIST_HEAD(&a->list); 73022851890Sopenharmony_ci+ a->mapped = false; 73122851890Sopenharmony_ci+ 73222851890Sopenharmony_ci+ attachment->priv = a; 73322851890Sopenharmony_ci+ 73422851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 73522851890Sopenharmony_ci+ list_add(&a->list, &buffer->attachments); 73622851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 73722851890Sopenharmony_ci+ 73822851890Sopenharmony_ci+ return 0; 73922851890Sopenharmony_ci+} 74022851890Sopenharmony_ci+ 74122851890Sopenharmony_ci+static void cma_heap_detach(struct dma_buf *dmabuf, 74222851890Sopenharmony_ci+ struct dma_buf_attachment *attachment) 74322851890Sopenharmony_ci+{ 74422851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 74522851890Sopenharmony_ci+ struct dma_heap_attachment *a = attachment->priv; 74622851890Sopenharmony_ci+ 74722851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 74822851890Sopenharmony_ci+ list_del(&a->list); 74922851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 75022851890Sopenharmony_ci+ 75122851890Sopenharmony_ci+ sg_free_table(&a->table); 75222851890Sopenharmony_ci+ kfree(a); 75322851890Sopenharmony_ci+} 75422851890Sopenharmony_ci+ 75522851890Sopenharmony_ci+static struct sg_table *cma_heap_map_dma_buf(struct dma_buf_attachment *attachment, 75622851890Sopenharmony_ci+ enum dma_data_direction direction) 75722851890Sopenharmony_ci { 75822851890Sopenharmony_ci- struct cma_heap *cma_heap = dma_heap_get_drvdata(buffer->heap); 75922851890Sopenharmony_ci- unsigned long nr_pages = buffer->pagecount; 76022851890Sopenharmony_ci- struct page *cma_pages = buffer->priv_virt; 76122851890Sopenharmony_ci+ struct dma_heap_attachment *a = attachment->priv; 76222851890Sopenharmony_ci+ struct sg_table *table = &a->table; 76322851890Sopenharmony_ci+ int attrs = attachment->dma_map_attrs; 76422851890Sopenharmony_ci+ int ret; 76522851890Sopenharmony_ci+ 76622851890Sopenharmony_ci+ ret = dma_map_sgtable(attachment->dev, table, direction, attrs); 76722851890Sopenharmony_ci+ if (ret) 76822851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 76922851890Sopenharmony_ci+ a->mapped = true; 77022851890Sopenharmony_ci+ return table; 77122851890Sopenharmony_ci+} 77222851890Sopenharmony_ci+ 77322851890Sopenharmony_ci+static void cma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, 77422851890Sopenharmony_ci+ struct sg_table *table, 77522851890Sopenharmony_ci+ enum dma_data_direction direction) 77622851890Sopenharmony_ci+{ 77722851890Sopenharmony_ci+ struct dma_heap_attachment *a = attachment->priv; 77822851890Sopenharmony_ci+ int attrs = attachment->dma_map_attrs; 77922851890Sopenharmony_ci+ 78022851890Sopenharmony_ci+ a->mapped = false; 78122851890Sopenharmony_ci+ dma_unmap_sgtable(attachment->dev, table, direction, attrs); 78222851890Sopenharmony_ci+} 78322851890Sopenharmony_ci+ 78422851890Sopenharmony_ci+static int cma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, 78522851890Sopenharmony_ci+ enum dma_data_direction direction) 78622851890Sopenharmony_ci+{ 78722851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 78822851890Sopenharmony_ci+ struct dma_heap_attachment *a; 78922851890Sopenharmony_ci+ 79022851890Sopenharmony_ci+ if (buffer->vmap_cnt) 79122851890Sopenharmony_ci+ invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); 79222851890Sopenharmony_ci+ 79322851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 79422851890Sopenharmony_ci+ list_for_each_entry(a, &buffer->attachments, list) { 79522851890Sopenharmony_ci+ if (!a->mapped) 79622851890Sopenharmony_ci+ continue; 79722851890Sopenharmony_ci+ dma_sync_sgtable_for_cpu(a->dev, &a->table, direction); 79822851890Sopenharmony_ci+ } 79922851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 80022851890Sopenharmony_ci+ 80122851890Sopenharmony_ci+ return 0; 80222851890Sopenharmony_ci+} 80322851890Sopenharmony_ci+ 80422851890Sopenharmony_ci+static int cma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, 80522851890Sopenharmony_ci+ enum dma_data_direction direction) 80622851890Sopenharmony_ci+{ 80722851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 80822851890Sopenharmony_ci+ struct dma_heap_attachment *a; 80922851890Sopenharmony_ci+ 81022851890Sopenharmony_ci+ if (buffer->vmap_cnt) 81122851890Sopenharmony_ci+ flush_kernel_vmap_range(buffer->vaddr, buffer->len); 81222851890Sopenharmony_ci+ 81322851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 81422851890Sopenharmony_ci+ list_for_each_entry(a, &buffer->attachments, list) { 81522851890Sopenharmony_ci+ if (!a->mapped) 81622851890Sopenharmony_ci+ continue; 81722851890Sopenharmony_ci+ dma_sync_sgtable_for_device(a->dev, &a->table, direction); 81822851890Sopenharmony_ci+ } 81922851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 82022851890Sopenharmony_ci+ 82122851890Sopenharmony_ci+ return 0; 82222851890Sopenharmony_ci+} 82322851890Sopenharmony_ci+ 82422851890Sopenharmony_ci+static vm_fault_t cma_heap_vm_fault(struct vm_fault *vmf) 82522851890Sopenharmony_ci+{ 82622851890Sopenharmony_ci+ struct vm_area_struct *vma = vmf->vma; 82722851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = vma->vm_private_data; 82822851890Sopenharmony_ci+ 82922851890Sopenharmony_ci+ if (vmf->pgoff > buffer->pagecount) 83022851890Sopenharmony_ci+ return VM_FAULT_SIGBUS; 83122851890Sopenharmony_ci+ 83222851890Sopenharmony_ci+ vmf->page = buffer->pages[vmf->pgoff]; 83322851890Sopenharmony_ci+ get_page(vmf->page); 83422851890Sopenharmony_ci+ 83522851890Sopenharmony_ci+ return 0; 83622851890Sopenharmony_ci+} 83722851890Sopenharmony_ci+ 83822851890Sopenharmony_ci+static const struct vm_operations_struct dma_heap_vm_ops = { 83922851890Sopenharmony_ci+ .fault = cma_heap_vm_fault, 84022851890Sopenharmony_ci+}; 84122851890Sopenharmony_ci+ 84222851890Sopenharmony_ci+static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) 84322851890Sopenharmony_ci+{ 84422851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 84522851890Sopenharmony_ci+ 84622851890Sopenharmony_ci+ if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) 84722851890Sopenharmony_ci+ return -EINVAL; 84822851890Sopenharmony_ci+ 84922851890Sopenharmony_ci+ vma->vm_ops = &dma_heap_vm_ops; 85022851890Sopenharmony_ci+ vma->vm_private_data = buffer; 85122851890Sopenharmony_ci+ 85222851890Sopenharmony_ci+ return 0; 85322851890Sopenharmony_ci+} 85422851890Sopenharmony_ci+ 85522851890Sopenharmony_ci+static void *cma_heap_do_vmap(struct cma_heap_buffer *buffer) 85622851890Sopenharmony_ci+{ 85722851890Sopenharmony_ci+ void *vaddr; 85822851890Sopenharmony_ci+ 85922851890Sopenharmony_ci+ vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, PAGE_KERNEL); 86022851890Sopenharmony_ci+ if (!vaddr) 86122851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 86222851890Sopenharmony_ci+ 86322851890Sopenharmony_ci+ return vaddr; 86422851890Sopenharmony_ci+} 86522851890Sopenharmony_ci+ 86622851890Sopenharmony_ci+static void *cma_heap_vmap(struct dma_buf *dmabuf) 86722851890Sopenharmony_ci+{ 86822851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 86922851890Sopenharmony_ci+ void *vaddr; 87022851890Sopenharmony_ci+ 87122851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 87222851890Sopenharmony_ci+ if (buffer->vmap_cnt) { 87322851890Sopenharmony_ci+ buffer->vmap_cnt++; 87422851890Sopenharmony_ci+ vaddr = buffer->vaddr; 87522851890Sopenharmony_ci+ goto out; 87622851890Sopenharmony_ci+ } 87722851890Sopenharmony_ci+ 87822851890Sopenharmony_ci+ vaddr = cma_heap_do_vmap(buffer); 87922851890Sopenharmony_ci+ if (IS_ERR(vaddr)) 88022851890Sopenharmony_ci+ goto out; 88122851890Sopenharmony_ci+ 88222851890Sopenharmony_ci+ buffer->vaddr = vaddr; 88322851890Sopenharmony_ci+ buffer->vmap_cnt++; 88422851890Sopenharmony_ci+out: 88522851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 88622851890Sopenharmony_ci+ 88722851890Sopenharmony_ci+ return vaddr; 88822851890Sopenharmony_ci+} 88922851890Sopenharmony_ci+ 89022851890Sopenharmony_ci+static void cma_heap_vunmap(struct dma_buf *dmabuf, void *vaddr) 89122851890Sopenharmony_ci+{ 89222851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 89322851890Sopenharmony_ci+ 89422851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 89522851890Sopenharmony_ci+ if (!--buffer->vmap_cnt) { 89622851890Sopenharmony_ci+ vunmap(buffer->vaddr); 89722851890Sopenharmony_ci+ buffer->vaddr = NULL; 89822851890Sopenharmony_ci+ } 89922851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 90022851890Sopenharmony_ci+} 90122851890Sopenharmony_ci+ 90222851890Sopenharmony_ci+static void cma_heap_dma_buf_release(struct dma_buf *dmabuf) 90322851890Sopenharmony_ci+{ 90422851890Sopenharmony_ci+ struct cma_heap_buffer *buffer = dmabuf->priv; 90522851890Sopenharmony_ci+ struct cma_heap *cma_heap = buffer->heap; 90622851890Sopenharmony_ci+ 90722851890Sopenharmony_ci+ if (buffer->vmap_cnt > 0) { 90822851890Sopenharmony_ci+ WARN(1, "%s: buffer still mapped in the kernel\n", __func__); 90922851890Sopenharmony_ci+ vunmap(buffer->vaddr); 91022851890Sopenharmony_ci+ } 91122851890Sopenharmony_ci 91222851890Sopenharmony_ci /* free page list */ 91322851890Sopenharmony_ci kfree(buffer->pages); 91422851890Sopenharmony_ci /* release memory */ 91522851890Sopenharmony_ci- cma_release(cma_heap->cma, cma_pages, nr_pages); 91622851890Sopenharmony_ci+ cma_release(cma_heap->cma, buffer->cma_pages, buffer->pagecount); 91722851890Sopenharmony_ci kfree(buffer); 91822851890Sopenharmony_ci } 91922851890Sopenharmony_ci 92022851890Sopenharmony_ci-/* dmabuf heap CMA operations functions */ 92122851890Sopenharmony_ci-static int cma_heap_allocate(struct dma_heap *heap, 92222851890Sopenharmony_ci- unsigned long len, 92322851890Sopenharmony_ci- unsigned long fd_flags, 92422851890Sopenharmony_ci- unsigned long heap_flags) 92522851890Sopenharmony_ci+static const struct dma_buf_ops cma_heap_buf_ops = { 92622851890Sopenharmony_ci+ .attach = cma_heap_attach, 92722851890Sopenharmony_ci+ .detach = cma_heap_detach, 92822851890Sopenharmony_ci+ .map_dma_buf = cma_heap_map_dma_buf, 92922851890Sopenharmony_ci+ .unmap_dma_buf = cma_heap_unmap_dma_buf, 93022851890Sopenharmony_ci+ .begin_cpu_access = cma_heap_dma_buf_begin_cpu_access, 93122851890Sopenharmony_ci+ .end_cpu_access = cma_heap_dma_buf_end_cpu_access, 93222851890Sopenharmony_ci+ .mmap = cma_heap_mmap, 93322851890Sopenharmony_ci+ .vmap = cma_heap_vmap, 93422851890Sopenharmony_ci+ .vunmap = cma_heap_vunmap, 93522851890Sopenharmony_ci+ .release = cma_heap_dma_buf_release, 93622851890Sopenharmony_ci+}; 93722851890Sopenharmony_ci+ 93822851890Sopenharmony_ci+static struct dma_buf *cma_heap_allocate(struct dma_heap *heap, 93922851890Sopenharmony_ci+ unsigned long len, 94022851890Sopenharmony_ci+ unsigned long fd_flags, 94122851890Sopenharmony_ci+ unsigned long heap_flags) 94222851890Sopenharmony_ci { 94322851890Sopenharmony_ci struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); 94422851890Sopenharmony_ci- struct heap_helper_buffer *helper_buffer; 94522851890Sopenharmony_ci- struct page *cma_pages; 94622851890Sopenharmony_ci+ struct cma_heap_buffer *buffer; 94722851890Sopenharmony_ci+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 94822851890Sopenharmony_ci size_t size = PAGE_ALIGN(len); 94922851890Sopenharmony_ci- unsigned long nr_pages = size >> PAGE_SHIFT; 95022851890Sopenharmony_ci+ pgoff_t pagecount = size >> PAGE_SHIFT; 95122851890Sopenharmony_ci unsigned long align = get_order(size); 95222851890Sopenharmony_ci+ struct page *cma_pages; 95322851890Sopenharmony_ci struct dma_buf *dmabuf; 95422851890Sopenharmony_ci int ret = -ENOMEM; 95522851890Sopenharmony_ci pgoff_t pg; 95622851890Sopenharmony_ci 95722851890Sopenharmony_ci- if (align > CONFIG_CMA_ALIGNMENT) 95822851890Sopenharmony_ci- align = CONFIG_CMA_ALIGNMENT; 95922851890Sopenharmony_ci+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 96022851890Sopenharmony_ci+ if (!buffer) 96122851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 96222851890Sopenharmony_ci 96322851890Sopenharmony_ci- helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL); 96422851890Sopenharmony_ci- if (!helper_buffer) 96522851890Sopenharmony_ci- return -ENOMEM; 96622851890Sopenharmony_ci+ INIT_LIST_HEAD(&buffer->attachments); 96722851890Sopenharmony_ci+ mutex_init(&buffer->lock); 96822851890Sopenharmony_ci+ buffer->len = size; 96922851890Sopenharmony_ci 97022851890Sopenharmony_ci- init_heap_helper_buffer(helper_buffer, cma_heap_free); 97122851890Sopenharmony_ci- helper_buffer->heap = heap; 97222851890Sopenharmony_ci- helper_buffer->size = len; 97322851890Sopenharmony_ci+ if (align > CONFIG_CMA_ALIGNMENT) 97422851890Sopenharmony_ci+ align = CONFIG_CMA_ALIGNMENT; 97522851890Sopenharmony_ci 97622851890Sopenharmony_ci- cma_pages = cma_alloc(cma_heap->cma, nr_pages, align, false); 97722851890Sopenharmony_ci+ cma_pages = cma_alloc(cma_heap->cma, pagecount, align, GFP_KERNEL); 97822851890Sopenharmony_ci if (!cma_pages) 97922851890Sopenharmony_ci- goto free_buf; 98022851890Sopenharmony_ci+ goto free_buffer; 98122851890Sopenharmony_ci 98222851890Sopenharmony_ci+ /* Clear the cma pages */ 98322851890Sopenharmony_ci if (PageHighMem(cma_pages)) { 98422851890Sopenharmony_ci- unsigned long nr_clear_pages = nr_pages; 98522851890Sopenharmony_ci+ unsigned long nr_clear_pages = pagecount; 98622851890Sopenharmony_ci struct page *page = cma_pages; 98722851890Sopenharmony_ci 98822851890Sopenharmony_ci while (nr_clear_pages > 0) { 98922851890Sopenharmony_ci@@ -85,7 +315,6 @@ static int cma_heap_allocate(struct dma_heap *heap, 99022851890Sopenharmony_ci */ 99122851890Sopenharmony_ci if (fatal_signal_pending(current)) 99222851890Sopenharmony_ci goto free_cma; 99322851890Sopenharmony_ci- 99422851890Sopenharmony_ci page++; 99522851890Sopenharmony_ci nr_clear_pages--; 99622851890Sopenharmony_ci } 99722851890Sopenharmony_ci@@ -93,44 +322,41 @@ static int cma_heap_allocate(struct dma_heap *heap, 99822851890Sopenharmony_ci memset(page_address(cma_pages), 0, size); 99922851890Sopenharmony_ci } 100022851890Sopenharmony_ci 100122851890Sopenharmony_ci- helper_buffer->pagecount = nr_pages; 100222851890Sopenharmony_ci- helper_buffer->pages = kmalloc_array(helper_buffer->pagecount, 100322851890Sopenharmony_ci- sizeof(*helper_buffer->pages), 100422851890Sopenharmony_ci- GFP_KERNEL); 100522851890Sopenharmony_ci- if (!helper_buffer->pages) { 100622851890Sopenharmony_ci+ buffer->pages = kmalloc_array(pagecount, sizeof(*buffer->pages), GFP_KERNEL); 100722851890Sopenharmony_ci+ if (!buffer->pages) { 100822851890Sopenharmony_ci ret = -ENOMEM; 100922851890Sopenharmony_ci goto free_cma; 101022851890Sopenharmony_ci } 101122851890Sopenharmony_ci 101222851890Sopenharmony_ci- for (pg = 0; pg < helper_buffer->pagecount; pg++) 101322851890Sopenharmony_ci- helper_buffer->pages[pg] = &cma_pages[pg]; 101422851890Sopenharmony_ci+ for (pg = 0; pg < pagecount; pg++) 101522851890Sopenharmony_ci+ buffer->pages[pg] = &cma_pages[pg]; 101622851890Sopenharmony_ci+ 101722851890Sopenharmony_ci+ buffer->cma_pages = cma_pages; 101822851890Sopenharmony_ci+ buffer->heap = cma_heap; 101922851890Sopenharmony_ci+ buffer->pagecount = pagecount; 102022851890Sopenharmony_ci 102122851890Sopenharmony_ci /* create the dmabuf */ 102222851890Sopenharmony_ci- dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags); 102322851890Sopenharmony_ci+ exp_info.exp_name = dma_heap_get_name(heap); 102422851890Sopenharmony_ci+ exp_info.ops = &cma_heap_buf_ops; 102522851890Sopenharmony_ci+ exp_info.size = buffer->len; 102622851890Sopenharmony_ci+ exp_info.flags = fd_flags; 102722851890Sopenharmony_ci+ exp_info.priv = buffer; 102822851890Sopenharmony_ci+ dmabuf = dma_buf_export(&exp_info); 102922851890Sopenharmony_ci if (IS_ERR(dmabuf)) { 103022851890Sopenharmony_ci ret = PTR_ERR(dmabuf); 103122851890Sopenharmony_ci goto free_pages; 103222851890Sopenharmony_ci } 103322851890Sopenharmony_ci 103422851890Sopenharmony_ci- helper_buffer->dmabuf = dmabuf; 103522851890Sopenharmony_ci- helper_buffer->priv_virt = cma_pages; 103622851890Sopenharmony_ci- 103722851890Sopenharmony_ci- ret = dma_buf_fd(dmabuf, fd_flags); 103822851890Sopenharmony_ci- if (ret < 0) { 103922851890Sopenharmony_ci- dma_buf_put(dmabuf); 104022851890Sopenharmony_ci- /* just return, as put will call release and that will free */ 104122851890Sopenharmony_ci- return ret; 104222851890Sopenharmony_ci- } 104322851890Sopenharmony_ci- 104422851890Sopenharmony_ci- return ret; 104522851890Sopenharmony_ci+ return dmabuf; 104622851890Sopenharmony_ci 104722851890Sopenharmony_ci free_pages: 104822851890Sopenharmony_ci- kfree(helper_buffer->pages); 104922851890Sopenharmony_ci+ kfree(buffer->pages); 105022851890Sopenharmony_ci free_cma: 105122851890Sopenharmony_ci- cma_release(cma_heap->cma, cma_pages, nr_pages); 105222851890Sopenharmony_ci-free_buf: 105322851890Sopenharmony_ci- kfree(helper_buffer); 105422851890Sopenharmony_ci- return ret; 105522851890Sopenharmony_ci+ cma_release(cma_heap->cma, cma_pages, pagecount); 105622851890Sopenharmony_ci+free_buffer: 105722851890Sopenharmony_ci+ kfree(buffer); 105822851890Sopenharmony_ci+ 105922851890Sopenharmony_ci+ return ERR_PTR(ret); 106022851890Sopenharmony_ci } 106122851890Sopenharmony_ci 106222851890Sopenharmony_ci static const struct dma_heap_ops cma_heap_ops = { 106322851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/deferred-free-helper.c b/drivers/dma-buf/heaps/deferred-free-helper.c 106422851890Sopenharmony_cinew file mode 100755 106522851890Sopenharmony_ciindex 000000000..1330d279f 106622851890Sopenharmony_ci--- /dev/null 106722851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/deferred-free-helper.c 106822851890Sopenharmony_ci@@ -0,0 +1,139 @@ 106922851890Sopenharmony_ci+// SPDX-License-Identifier: GPL-2.0 107022851890Sopenharmony_ci+/* 107122851890Sopenharmony_ci+ * Deferred dmabuf freeing helper 107222851890Sopenharmony_ci+ * 107322851890Sopenharmony_ci+ * Copyright (C) 2020 Linaro, Ltd. 107422851890Sopenharmony_ci+ * 107522851890Sopenharmony_ci+ * Based on the ION page pool code 107622851890Sopenharmony_ci+ * Copyright (C) 2011 Google, Inc. 107722851890Sopenharmony_ci+ */ 107822851890Sopenharmony_ci+ 107922851890Sopenharmony_ci+#include <linux/freezer.h> 108022851890Sopenharmony_ci+#include <linux/list.h> 108122851890Sopenharmony_ci+#include <linux/slab.h> 108222851890Sopenharmony_ci+#include <linux/swap.h> 108322851890Sopenharmony_ci+#include <linux/sched/signal.h> 108422851890Sopenharmony_ci+ 108522851890Sopenharmony_ci+#include "deferred-free-helper.h" 108622851890Sopenharmony_ci+ 108722851890Sopenharmony_ci+static LIST_HEAD(free_list); 108822851890Sopenharmony_ci+static size_t list_nr_pages; 108922851890Sopenharmony_ci+wait_queue_head_t freelist_waitqueue; 109022851890Sopenharmony_ci+struct task_struct *freelist_task; 109122851890Sopenharmony_ci+static DEFINE_SPINLOCK(free_list_lock); 109222851890Sopenharmony_ci+ 109322851890Sopenharmony_ci+void deferred_free(struct deferred_freelist_item *item, 109422851890Sopenharmony_ci+ void (*free)(struct deferred_freelist_item*, 109522851890Sopenharmony_ci+ enum df_reason), 109622851890Sopenharmony_ci+ size_t nr_pages) 109722851890Sopenharmony_ci+{ 109822851890Sopenharmony_ci+ unsigned long flags; 109922851890Sopenharmony_ci+ 110022851890Sopenharmony_ci+ INIT_LIST_HEAD(&item->list); 110122851890Sopenharmony_ci+ item->nr_pages = nr_pages; 110222851890Sopenharmony_ci+ item->free = free; 110322851890Sopenharmony_ci+ 110422851890Sopenharmony_ci+ spin_lock_irqsave(&free_list_lock, flags); 110522851890Sopenharmony_ci+ list_add(&item->list, &free_list); 110622851890Sopenharmony_ci+ list_nr_pages += nr_pages; 110722851890Sopenharmony_ci+ spin_unlock_irqrestore(&free_list_lock, flags); 110822851890Sopenharmony_ci+ wake_up(&freelist_waitqueue); 110922851890Sopenharmony_ci+} 111022851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(deferred_free); 111122851890Sopenharmony_ci+ 111222851890Sopenharmony_ci+static size_t free_one_item(enum df_reason reason) 111322851890Sopenharmony_ci+{ 111422851890Sopenharmony_ci+ unsigned long flags; 111522851890Sopenharmony_ci+ size_t nr_pages; 111622851890Sopenharmony_ci+ struct deferred_freelist_item *item; 111722851890Sopenharmony_ci+ 111822851890Sopenharmony_ci+ spin_lock_irqsave(&free_list_lock, flags); 111922851890Sopenharmony_ci+ if (list_empty(&free_list)) { 112022851890Sopenharmony_ci+ spin_unlock_irqrestore(&free_list_lock, flags); 112122851890Sopenharmony_ci+ return 0; 112222851890Sopenharmony_ci+ } 112322851890Sopenharmony_ci+ item = list_first_entry(&free_list, struct deferred_freelist_item, list); 112422851890Sopenharmony_ci+ list_del(&item->list); 112522851890Sopenharmony_ci+ nr_pages = item->nr_pages; 112622851890Sopenharmony_ci+ list_nr_pages -= nr_pages; 112722851890Sopenharmony_ci+ spin_unlock_irqrestore(&free_list_lock, flags); 112822851890Sopenharmony_ci+ 112922851890Sopenharmony_ci+ item->free(item, reason); 113022851890Sopenharmony_ci+ return nr_pages; 113122851890Sopenharmony_ci+} 113222851890Sopenharmony_ci+ 113322851890Sopenharmony_ci+unsigned long get_freelist_nr_pages(void) 113422851890Sopenharmony_ci+{ 113522851890Sopenharmony_ci+ unsigned long nr_pages; 113622851890Sopenharmony_ci+ unsigned long flags; 113722851890Sopenharmony_ci+ 113822851890Sopenharmony_ci+ spin_lock_irqsave(&free_list_lock, flags); 113922851890Sopenharmony_ci+ nr_pages = list_nr_pages; 114022851890Sopenharmony_ci+ spin_unlock_irqrestore(&free_list_lock, flags); 114122851890Sopenharmony_ci+ return nr_pages; 114222851890Sopenharmony_ci+} 114322851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(get_freelist_nr_pages); 114422851890Sopenharmony_ci+ 114522851890Sopenharmony_ci+static unsigned long freelist_shrink_count(struct shrinker *shrinker, 114622851890Sopenharmony_ci+ struct shrink_control *sc) 114722851890Sopenharmony_ci+{ 114822851890Sopenharmony_ci+ return get_freelist_nr_pages(); 114922851890Sopenharmony_ci+} 115022851890Sopenharmony_ci+ 115122851890Sopenharmony_ci+static unsigned long freelist_shrink_scan(struct shrinker *shrinker, 115222851890Sopenharmony_ci+ struct shrink_control *sc) 115322851890Sopenharmony_ci+{ 115422851890Sopenharmony_ci+ unsigned long total_freed = 0; 115522851890Sopenharmony_ci+ 115622851890Sopenharmony_ci+ if (sc->nr_to_scan == 0) 115722851890Sopenharmony_ci+ return 0; 115822851890Sopenharmony_ci+ 115922851890Sopenharmony_ci+ while (total_freed < sc->nr_to_scan) { 116022851890Sopenharmony_ci+ size_t pages_freed = free_one_item(DF_UNDER_PRESSURE); 116122851890Sopenharmony_ci+ 116222851890Sopenharmony_ci+ if (!pages_freed) 116322851890Sopenharmony_ci+ break; 116422851890Sopenharmony_ci+ 116522851890Sopenharmony_ci+ total_freed += pages_freed; 116622851890Sopenharmony_ci+ } 116722851890Sopenharmony_ci+ 116822851890Sopenharmony_ci+ return total_freed; 116922851890Sopenharmony_ci+} 117022851890Sopenharmony_ci+ 117122851890Sopenharmony_ci+static struct shrinker freelist_shrinker = { 117222851890Sopenharmony_ci+ .count_objects = freelist_shrink_count, 117322851890Sopenharmony_ci+ .scan_objects = freelist_shrink_scan, 117422851890Sopenharmony_ci+ .seeks = DEFAULT_SEEKS, 117522851890Sopenharmony_ci+ .batch = 0, 117622851890Sopenharmony_ci+}; 117722851890Sopenharmony_ci+ 117822851890Sopenharmony_ci+static int deferred_free_thread(void *data) 117922851890Sopenharmony_ci+{ 118022851890Sopenharmony_ci+ while (true) { 118122851890Sopenharmony_ci+ wait_event_freezable(freelist_waitqueue, 118222851890Sopenharmony_ci+ get_freelist_nr_pages() > 0); 118322851890Sopenharmony_ci+ 118422851890Sopenharmony_ci+ free_one_item(DF_NORMAL); 118522851890Sopenharmony_ci+ } 118622851890Sopenharmony_ci+ 118722851890Sopenharmony_ci+ return 0; 118822851890Sopenharmony_ci+} 118922851890Sopenharmony_ci+ 119022851890Sopenharmony_ci+static int deferred_freelist_init(void) 119122851890Sopenharmony_ci+{ 119222851890Sopenharmony_ci+ list_nr_pages = 0; 119322851890Sopenharmony_ci+ 119422851890Sopenharmony_ci+ init_waitqueue_head(&freelist_waitqueue); 119522851890Sopenharmony_ci+ freelist_task = kthread_run(deferred_free_thread, NULL, 119622851890Sopenharmony_ci+ "%s", "dmabuf-deferred-free-worker"); 119722851890Sopenharmony_ci+ if (IS_ERR(freelist_task)) { 119822851890Sopenharmony_ci+ pr_err("Creating thread for deferred free failed\n"); 119922851890Sopenharmony_ci+ return -1; 120022851890Sopenharmony_ci+ } 120122851890Sopenharmony_ci+ sched_set_normal(freelist_task, 19); 120222851890Sopenharmony_ci+ 120322851890Sopenharmony_ci+ return register_shrinker(&freelist_shrinker); 120422851890Sopenharmony_ci+} 120522851890Sopenharmony_ci+module_init(deferred_freelist_init); 120622851890Sopenharmony_ci+MODULE_LICENSE("GPL v2"); 120722851890Sopenharmony_ci+ 120822851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/deferred-free-helper.h b/drivers/dma-buf/heaps/deferred-free-helper.h 120922851890Sopenharmony_cinew file mode 100755 121022851890Sopenharmony_ciindex 000000000..415440314 121122851890Sopenharmony_ci--- /dev/null 121222851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/deferred-free-helper.h 121322851890Sopenharmony_ci@@ -0,0 +1,57 @@ 121422851890Sopenharmony_ci+/* SPDX-License-Identifier: GPL-2.0 */ 121522851890Sopenharmony_ci+ 121622851890Sopenharmony_ci+#ifndef DEFERRED_FREE_HELPER_H 121722851890Sopenharmony_ci+#define DEFERRED_FREE_HELPER_H 121822851890Sopenharmony_ci+ 121922851890Sopenharmony_ci+/** 122022851890Sopenharmony_ci+ * df_reason - enum for reason why item was freed 122122851890Sopenharmony_ci+ * 122222851890Sopenharmony_ci+ * This provides a reason for why the free function was called 122322851890Sopenharmony_ci+ * on the item. This is useful when deferred_free is used in 122422851890Sopenharmony_ci+ * combination with a pagepool, so under pressure the page can 122522851890Sopenharmony_ci+ * be immediately freed. 122622851890Sopenharmony_ci+ * 122722851890Sopenharmony_ci+ * DF_NORMAL: Normal deferred free 122822851890Sopenharmony_ci+ * 122922851890Sopenharmony_ci+ * DF_UNDER_PRESSURE: Free was called because the system 123022851890Sopenharmony_ci+ * is under memory pressure. Usually 123122851890Sopenharmony_ci+ * from a shrinker. Avoid allocating 123222851890Sopenharmony_ci+ * memory in the free call, as it may 123322851890Sopenharmony_ci+ * fail. 123422851890Sopenharmony_ci+ */ 123522851890Sopenharmony_ci+enum df_reason { 123622851890Sopenharmony_ci+ DF_NORMAL, 123722851890Sopenharmony_ci+ DF_UNDER_PRESSURE, 123822851890Sopenharmony_ci+}; 123922851890Sopenharmony_ci+ 124022851890Sopenharmony_ci+/** 124122851890Sopenharmony_ci+ * deferred_freelist_item - item structure for deferred freelist 124222851890Sopenharmony_ci+ * 124322851890Sopenharmony_ci+ * This is to be added to the structure for whatever you want to 124422851890Sopenharmony_ci+ * defer freeing on. 124522851890Sopenharmony_ci+ * 124622851890Sopenharmony_ci+ * @nr_pages: number of pages used by item to be freed 124722851890Sopenharmony_ci+ * @free: function pointer to be called when freeing the item 124822851890Sopenharmony_ci+ * @list: list entry for the deferred list 124922851890Sopenharmony_ci+ */ 125022851890Sopenharmony_ci+struct deferred_freelist_item { 125122851890Sopenharmony_ci+ size_t nr_pages; 125222851890Sopenharmony_ci+ void (*free)(struct deferred_freelist_item *i, 125322851890Sopenharmony_ci+ enum df_reason reason); 125422851890Sopenharmony_ci+ struct list_head list; 125522851890Sopenharmony_ci+}; 125622851890Sopenharmony_ci+ 125722851890Sopenharmony_ci+/** 125822851890Sopenharmony_ci+ * deferred_free - call to add item to the deferred free list 125922851890Sopenharmony_ci+ * 126022851890Sopenharmony_ci+ * @item: Pointer to deferred_freelist_item field of a structure 126122851890Sopenharmony_ci+ * @free: Function pointer to the free call 126222851890Sopenharmony_ci+ * @nr_pages: number of pages to be freed 126322851890Sopenharmony_ci+ */ 126422851890Sopenharmony_ci+void deferred_free(struct deferred_freelist_item *item, 126522851890Sopenharmony_ci+ void (*free)(struct deferred_freelist_item *i, 126622851890Sopenharmony_ci+ enum df_reason reason), 126722851890Sopenharmony_ci+ size_t nr_pages); 126822851890Sopenharmony_ci+ 126922851890Sopenharmony_ci+unsigned long get_freelist_nr_pages(void); 127022851890Sopenharmony_ci+#endif 127122851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/heap-helpers.c b/drivers/dma-buf/heaps/heap-helpers.c 127222851890Sopenharmony_ciindex 35aa65bbf..d0696cf93 100644 127322851890Sopenharmony_ci--- a/drivers/dma-buf/heaps/heap-helpers.c 127422851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/heap-helpers.c 127522851890Sopenharmony_ci@@ -30,7 +30,6 @@ struct dma_buf *heap_helper_export_dmabuf(struct heap_helper_buffer *buffer, 127622851890Sopenharmony_ci { 127722851890Sopenharmony_ci DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 127822851890Sopenharmony_ci 127922851890Sopenharmony_ci- exp_info.exp_name = dma_heap_get_name(buffer->heap); 128022851890Sopenharmony_ci exp_info.ops = &heap_helper_ops; 128122851890Sopenharmony_ci exp_info.size = buffer->size; 128222851890Sopenharmony_ci exp_info.flags = fd_flags; 128322851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/page_pool.c b/drivers/dma-buf/heaps/page_pool.c 128422851890Sopenharmony_cinew file mode 100755 128522851890Sopenharmony_ciindex 000000000..b79e737ba 128622851890Sopenharmony_ci--- /dev/null 128722851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/page_pool.c 128822851890Sopenharmony_ci@@ -0,0 +1,247 @@ 128922851890Sopenharmony_ci+// SPDX-License-Identifier: GPL-2.0 129022851890Sopenharmony_ci+/* 129122851890Sopenharmony_ci+ * DMA BUF page pool system 129222851890Sopenharmony_ci+ * 129322851890Sopenharmony_ci+ * Copyright (C) 2020 Linaro Ltd. 129422851890Sopenharmony_ci+ * 129522851890Sopenharmony_ci+ * Based on the ION page pool code 129622851890Sopenharmony_ci+ * Copyright (C) 2011 Google, Inc. 129722851890Sopenharmony_ci+ */ 129822851890Sopenharmony_ci+ 129922851890Sopenharmony_ci+#include <linux/freezer.h> 130022851890Sopenharmony_ci+#include <linux/list.h> 130122851890Sopenharmony_ci+#include <linux/slab.h> 130222851890Sopenharmony_ci+#include <linux/swap.h> 130322851890Sopenharmony_ci+#include <linux/sched/signal.h> 130422851890Sopenharmony_ci+#include "page_pool.h" 130522851890Sopenharmony_ci+ 130622851890Sopenharmony_ci+static LIST_HEAD(pool_list); 130722851890Sopenharmony_ci+static DEFINE_MUTEX(pool_list_lock); 130822851890Sopenharmony_ci+ 130922851890Sopenharmony_ci+static inline 131022851890Sopenharmony_ci+struct page *dmabuf_page_pool_alloc_pages(struct dmabuf_page_pool *pool) 131122851890Sopenharmony_ci+{ 131222851890Sopenharmony_ci+ if (fatal_signal_pending(current)) 131322851890Sopenharmony_ci+ return NULL; 131422851890Sopenharmony_ci+ return alloc_pages(pool->gfp_mask, pool->order); 131522851890Sopenharmony_ci+} 131622851890Sopenharmony_ci+ 131722851890Sopenharmony_ci+static inline void dmabuf_page_pool_free_pages(struct dmabuf_page_pool *pool, 131822851890Sopenharmony_ci+ struct page *page) 131922851890Sopenharmony_ci+{ 132022851890Sopenharmony_ci+ __free_pages(page, pool->order); 132122851890Sopenharmony_ci+} 132222851890Sopenharmony_ci+ 132322851890Sopenharmony_ci+static void dmabuf_page_pool_add(struct dmabuf_page_pool *pool, struct page *page) 132422851890Sopenharmony_ci+{ 132522851890Sopenharmony_ci+ int index; 132622851890Sopenharmony_ci+ 132722851890Sopenharmony_ci+ if (PageHighMem(page)) 132822851890Sopenharmony_ci+ index = POOL_HIGHPAGE; 132922851890Sopenharmony_ci+ else 133022851890Sopenharmony_ci+ index = POOL_LOWPAGE; 133122851890Sopenharmony_ci+ 133222851890Sopenharmony_ci+ mutex_lock(&pool->mutex); 133322851890Sopenharmony_ci+ list_add_tail(&page->lru, &pool->items[index]); 133422851890Sopenharmony_ci+ pool->count[index]++; 133522851890Sopenharmony_ci+ mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE, 133622851890Sopenharmony_ci+ 1 << pool->order); 133722851890Sopenharmony_ci+ mutex_unlock(&pool->mutex); 133822851890Sopenharmony_ci+} 133922851890Sopenharmony_ci+ 134022851890Sopenharmony_ci+static struct page *dmabuf_page_pool_remove(struct dmabuf_page_pool *pool, int index) 134122851890Sopenharmony_ci+{ 134222851890Sopenharmony_ci+ struct page *page; 134322851890Sopenharmony_ci+ 134422851890Sopenharmony_ci+ mutex_lock(&pool->mutex); 134522851890Sopenharmony_ci+ page = list_first_entry_or_null(&pool->items[index], struct page, lru); 134622851890Sopenharmony_ci+ if (page) { 134722851890Sopenharmony_ci+ pool->count[index]--; 134822851890Sopenharmony_ci+ list_del(&page->lru); 134922851890Sopenharmony_ci+ mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE, 135022851890Sopenharmony_ci+ -(1 << pool->order)); 135122851890Sopenharmony_ci+ } 135222851890Sopenharmony_ci+ mutex_unlock(&pool->mutex); 135322851890Sopenharmony_ci+ 135422851890Sopenharmony_ci+ return page; 135522851890Sopenharmony_ci+} 135622851890Sopenharmony_ci+ 135722851890Sopenharmony_ci+static struct page *dmabuf_page_pool_fetch(struct dmabuf_page_pool *pool) 135822851890Sopenharmony_ci+{ 135922851890Sopenharmony_ci+ struct page *page = NULL; 136022851890Sopenharmony_ci+ 136122851890Sopenharmony_ci+ page = dmabuf_page_pool_remove(pool, POOL_HIGHPAGE); 136222851890Sopenharmony_ci+ if (!page) 136322851890Sopenharmony_ci+ page = dmabuf_page_pool_remove(pool, POOL_LOWPAGE); 136422851890Sopenharmony_ci+ 136522851890Sopenharmony_ci+ return page; 136622851890Sopenharmony_ci+} 136722851890Sopenharmony_ci+ 136822851890Sopenharmony_ci+struct page *dmabuf_page_pool_alloc(struct dmabuf_page_pool *pool) 136922851890Sopenharmony_ci+{ 137022851890Sopenharmony_ci+ struct page *page = NULL; 137122851890Sopenharmony_ci+ 137222851890Sopenharmony_ci+ if (WARN_ON(!pool)) 137322851890Sopenharmony_ci+ return NULL; 137422851890Sopenharmony_ci+ 137522851890Sopenharmony_ci+ page = dmabuf_page_pool_fetch(pool); 137622851890Sopenharmony_ci+ 137722851890Sopenharmony_ci+ if (!page) 137822851890Sopenharmony_ci+ page = dmabuf_page_pool_alloc_pages(pool); 137922851890Sopenharmony_ci+ return page; 138022851890Sopenharmony_ci+} 138122851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dmabuf_page_pool_alloc); 138222851890Sopenharmony_ci+ 138322851890Sopenharmony_ci+void dmabuf_page_pool_free(struct dmabuf_page_pool *pool, struct page *page) 138422851890Sopenharmony_ci+{ 138522851890Sopenharmony_ci+ if (WARN_ON(pool->order != compound_order(page))) 138622851890Sopenharmony_ci+ return; 138722851890Sopenharmony_ci+ 138822851890Sopenharmony_ci+ dmabuf_page_pool_add(pool, page); 138922851890Sopenharmony_ci+} 139022851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dmabuf_page_pool_free); 139122851890Sopenharmony_ci+ 139222851890Sopenharmony_ci+static int dmabuf_page_pool_total(struct dmabuf_page_pool *pool, bool high) 139322851890Sopenharmony_ci+{ 139422851890Sopenharmony_ci+ int count = pool->count[POOL_LOWPAGE]; 139522851890Sopenharmony_ci+ 139622851890Sopenharmony_ci+ if (high) 139722851890Sopenharmony_ci+ count += pool->count[POOL_HIGHPAGE]; 139822851890Sopenharmony_ci+ 139922851890Sopenharmony_ci+ return count << pool->order; 140022851890Sopenharmony_ci+} 140122851890Sopenharmony_ci+ 140222851890Sopenharmony_ci+struct dmabuf_page_pool *dmabuf_page_pool_create(gfp_t gfp_mask, unsigned int order) 140322851890Sopenharmony_ci+{ 140422851890Sopenharmony_ci+ struct dmabuf_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL); 140522851890Sopenharmony_ci+ int i; 140622851890Sopenharmony_ci+ 140722851890Sopenharmony_ci+ if (!pool) 140822851890Sopenharmony_ci+ return NULL; 140922851890Sopenharmony_ci+ 141022851890Sopenharmony_ci+ for (i = 0; i < POOL_TYPE_SIZE; i++) { 141122851890Sopenharmony_ci+ pool->count[i] = 0; 141222851890Sopenharmony_ci+ INIT_LIST_HEAD(&pool->items[i]); 141322851890Sopenharmony_ci+ } 141422851890Sopenharmony_ci+ pool->gfp_mask = gfp_mask | __GFP_COMP; 141522851890Sopenharmony_ci+ pool->order = order; 141622851890Sopenharmony_ci+ mutex_init(&pool->mutex); 141722851890Sopenharmony_ci+ 141822851890Sopenharmony_ci+ mutex_lock(&pool_list_lock); 141922851890Sopenharmony_ci+ list_add(&pool->list, &pool_list); 142022851890Sopenharmony_ci+ mutex_unlock(&pool_list_lock); 142122851890Sopenharmony_ci+ 142222851890Sopenharmony_ci+ return pool; 142322851890Sopenharmony_ci+} 142422851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dmabuf_page_pool_create); 142522851890Sopenharmony_ci+ 142622851890Sopenharmony_ci+void dmabuf_page_pool_destroy(struct dmabuf_page_pool *pool) 142722851890Sopenharmony_ci+{ 142822851890Sopenharmony_ci+ struct page *page; 142922851890Sopenharmony_ci+ int i; 143022851890Sopenharmony_ci+ 143122851890Sopenharmony_ci+ /* Remove us from the pool list */ 143222851890Sopenharmony_ci+ mutex_lock(&pool_list_lock); 143322851890Sopenharmony_ci+ list_del(&pool->list); 143422851890Sopenharmony_ci+ mutex_unlock(&pool_list_lock); 143522851890Sopenharmony_ci+ 143622851890Sopenharmony_ci+ /* Free any remaining pages in the pool */ 143722851890Sopenharmony_ci+ for (i = 0; i < POOL_TYPE_SIZE; i++) { 143822851890Sopenharmony_ci+ while ((page = dmabuf_page_pool_remove(pool, i))) 143922851890Sopenharmony_ci+ dmabuf_page_pool_free_pages(pool, page); 144022851890Sopenharmony_ci+ } 144122851890Sopenharmony_ci+ 144222851890Sopenharmony_ci+ kfree(pool); 144322851890Sopenharmony_ci+} 144422851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(dmabuf_page_pool_destroy); 144522851890Sopenharmony_ci+ 144622851890Sopenharmony_ci+static int dmabuf_page_pool_do_shrink(struct dmabuf_page_pool *pool, gfp_t gfp_mask, 144722851890Sopenharmony_ci+ int nr_to_scan) 144822851890Sopenharmony_ci+{ 144922851890Sopenharmony_ci+ int freed = 0; 145022851890Sopenharmony_ci+ bool high; 145122851890Sopenharmony_ci+ 145222851890Sopenharmony_ci+ if (current_is_kswapd()) 145322851890Sopenharmony_ci+ high = true; 145422851890Sopenharmony_ci+ else 145522851890Sopenharmony_ci+ high = !!(gfp_mask & __GFP_HIGHMEM); 145622851890Sopenharmony_ci+ 145722851890Sopenharmony_ci+ if (nr_to_scan == 0) 145822851890Sopenharmony_ci+ return dmabuf_page_pool_total(pool, high); 145922851890Sopenharmony_ci+ 146022851890Sopenharmony_ci+ while (freed < nr_to_scan) { 146122851890Sopenharmony_ci+ struct page *page; 146222851890Sopenharmony_ci+ 146322851890Sopenharmony_ci+ /* Try to free low pages first */ 146422851890Sopenharmony_ci+ page = dmabuf_page_pool_remove(pool, POOL_LOWPAGE); 146522851890Sopenharmony_ci+ if (!page) 146622851890Sopenharmony_ci+ page = dmabuf_page_pool_remove(pool, POOL_HIGHPAGE); 146722851890Sopenharmony_ci+ 146822851890Sopenharmony_ci+ if (!page) 146922851890Sopenharmony_ci+ break; 147022851890Sopenharmony_ci+ 147122851890Sopenharmony_ci+ dmabuf_page_pool_free_pages(pool, page); 147222851890Sopenharmony_ci+ freed += (1 << pool->order); 147322851890Sopenharmony_ci+ } 147422851890Sopenharmony_ci+ 147522851890Sopenharmony_ci+ return freed; 147622851890Sopenharmony_ci+} 147722851890Sopenharmony_ci+ 147822851890Sopenharmony_ci+static int dmabuf_page_pool_shrink(gfp_t gfp_mask, int nr_to_scan) 147922851890Sopenharmony_ci+{ 148022851890Sopenharmony_ci+ struct dmabuf_page_pool *pool; 148122851890Sopenharmony_ci+ int nr_total = 0; 148222851890Sopenharmony_ci+ int nr_freed; 148322851890Sopenharmony_ci+ int only_scan = 0; 148422851890Sopenharmony_ci+ 148522851890Sopenharmony_ci+ if (!nr_to_scan) 148622851890Sopenharmony_ci+ only_scan = 1; 148722851890Sopenharmony_ci+ 148822851890Sopenharmony_ci+ mutex_lock(&pool_list_lock); 148922851890Sopenharmony_ci+ list_for_each_entry(pool, &pool_list, list) { 149022851890Sopenharmony_ci+ if (only_scan) { 149122851890Sopenharmony_ci+ nr_total += dmabuf_page_pool_do_shrink(pool, 149222851890Sopenharmony_ci+ gfp_mask, 149322851890Sopenharmony_ci+ nr_to_scan); 149422851890Sopenharmony_ci+ } else { 149522851890Sopenharmony_ci+ nr_freed = dmabuf_page_pool_do_shrink(pool, 149622851890Sopenharmony_ci+ gfp_mask, 149722851890Sopenharmony_ci+ nr_to_scan); 149822851890Sopenharmony_ci+ nr_to_scan -= nr_freed; 149922851890Sopenharmony_ci+ nr_total += nr_freed; 150022851890Sopenharmony_ci+ if (nr_to_scan <= 0) 150122851890Sopenharmony_ci+ break; 150222851890Sopenharmony_ci+ } 150322851890Sopenharmony_ci+ } 150422851890Sopenharmony_ci+ mutex_unlock(&pool_list_lock); 150522851890Sopenharmony_ci+ 150622851890Sopenharmony_ci+ return nr_total; 150722851890Sopenharmony_ci+} 150822851890Sopenharmony_ci+ 150922851890Sopenharmony_ci+static unsigned long dmabuf_page_pool_shrink_count(struct shrinker *shrinker, 151022851890Sopenharmony_ci+ struct shrink_control *sc) 151122851890Sopenharmony_ci+{ 151222851890Sopenharmony_ci+ return dmabuf_page_pool_shrink(sc->gfp_mask, 0); 151322851890Sopenharmony_ci+} 151422851890Sopenharmony_ci+ 151522851890Sopenharmony_ci+static unsigned long dmabuf_page_pool_shrink_scan(struct shrinker *shrinker, 151622851890Sopenharmony_ci+ struct shrink_control *sc) 151722851890Sopenharmony_ci+{ 151822851890Sopenharmony_ci+ if (sc->nr_to_scan == 0) 151922851890Sopenharmony_ci+ return 0; 152022851890Sopenharmony_ci+ return dmabuf_page_pool_shrink(sc->gfp_mask, sc->nr_to_scan); 152122851890Sopenharmony_ci+} 152222851890Sopenharmony_ci+ 152322851890Sopenharmony_ci+struct shrinker pool_shrinker = { 152422851890Sopenharmony_ci+ .count_objects = dmabuf_page_pool_shrink_count, 152522851890Sopenharmony_ci+ .scan_objects = dmabuf_page_pool_shrink_scan, 152622851890Sopenharmony_ci+ .seeks = DEFAULT_SEEKS, 152722851890Sopenharmony_ci+ .batch = 0, 152822851890Sopenharmony_ci+}; 152922851890Sopenharmony_ci+ 153022851890Sopenharmony_ci+static int dmabuf_page_pool_init_shrinker(void) 153122851890Sopenharmony_ci+{ 153222851890Sopenharmony_ci+ return register_shrinker(&pool_shrinker); 153322851890Sopenharmony_ci+} 153422851890Sopenharmony_ci+module_init(dmabuf_page_pool_init_shrinker); 153522851890Sopenharmony_ci+MODULE_LICENSE("GPL v2"); 153622851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/page_pool.h b/drivers/dma-buf/heaps/page_pool.h 153722851890Sopenharmony_cinew file mode 100755 153822851890Sopenharmony_ciindex 000000000..6b083b04f 153922851890Sopenharmony_ci--- /dev/null 154022851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/page_pool.h 154122851890Sopenharmony_ci@@ -0,0 +1,55 @@ 154222851890Sopenharmony_ci+/* SPDX-License-Identifier: GPL-2.0 */ 154322851890Sopenharmony_ci+/* 154422851890Sopenharmony_ci+ * DMA BUF PagePool implementation 154522851890Sopenharmony_ci+ * Based on earlier ION code by Google 154622851890Sopenharmony_ci+ * 154722851890Sopenharmony_ci+ * Copyright (C) 2011 Google, Inc. 154822851890Sopenharmony_ci+ * Copyright (C) 2020 Linaro Ltd. 154922851890Sopenharmony_ci+ */ 155022851890Sopenharmony_ci+ 155122851890Sopenharmony_ci+#ifndef _DMABUF_PAGE_POOL_H 155222851890Sopenharmony_ci+#define _DMABUF_PAGE_POOL_H 155322851890Sopenharmony_ci+ 155422851890Sopenharmony_ci+#include <linux/device.h> 155522851890Sopenharmony_ci+#include <linux/kref.h> 155622851890Sopenharmony_ci+#include <linux/mm_types.h> 155722851890Sopenharmony_ci+#include <linux/mutex.h> 155822851890Sopenharmony_ci+#include <linux/shrinker.h> 155922851890Sopenharmony_ci+#include <linux/types.h> 156022851890Sopenharmony_ci+ 156122851890Sopenharmony_ci+/* page types we track in the pool */ 156222851890Sopenharmony_ci+enum { 156322851890Sopenharmony_ci+ POOL_LOWPAGE, /* Clean lowmem pages */ 156422851890Sopenharmony_ci+ POOL_HIGHPAGE, /* Clean highmem pages */ 156522851890Sopenharmony_ci+ 156622851890Sopenharmony_ci+ POOL_TYPE_SIZE, 156722851890Sopenharmony_ci+}; 156822851890Sopenharmony_ci+ 156922851890Sopenharmony_ci+/** 157022851890Sopenharmony_ci+ * struct dmabuf_page_pool - pagepool struct 157122851890Sopenharmony_ci+ * @count[]: array of number of pages of that type in the pool 157222851890Sopenharmony_ci+ * @items[]: array of list of pages of the specific type 157322851890Sopenharmony_ci+ * @mutex: lock protecting this struct and especially the count 157422851890Sopenharmony_ci+ * item list 157522851890Sopenharmony_ci+ * @gfp_mask: gfp_mask to use from alloc 157622851890Sopenharmony_ci+ * @order: order of pages in the pool 157722851890Sopenharmony_ci+ * @list: list node for list of pools 157822851890Sopenharmony_ci+ * 157922851890Sopenharmony_ci+ * Allows you to keep a pool of pre allocated pages to use 158022851890Sopenharmony_ci+ */ 158122851890Sopenharmony_ci+struct dmabuf_page_pool { 158222851890Sopenharmony_ci+ int count[POOL_TYPE_SIZE]; 158322851890Sopenharmony_ci+ struct list_head items[POOL_TYPE_SIZE]; 158422851890Sopenharmony_ci+ struct mutex mutex; 158522851890Sopenharmony_ci+ gfp_t gfp_mask; 158622851890Sopenharmony_ci+ unsigned int order; 158722851890Sopenharmony_ci+ struct list_head list; 158822851890Sopenharmony_ci+}; 158922851890Sopenharmony_ci+ 159022851890Sopenharmony_ci+struct dmabuf_page_pool *dmabuf_page_pool_create(gfp_t gfp_mask, 159122851890Sopenharmony_ci+ unsigned int order); 159222851890Sopenharmony_ci+void dmabuf_page_pool_destroy(struct dmabuf_page_pool *pool); 159322851890Sopenharmony_ci+struct page *dmabuf_page_pool_alloc(struct dmabuf_page_pool *pool); 159422851890Sopenharmony_ci+void dmabuf_page_pool_free(struct dmabuf_page_pool *pool, struct page *page); 159522851890Sopenharmony_ci+ 159622851890Sopenharmony_ci+#endif /* _DMABUF_PAGE_POOL_H */ 159722851890Sopenharmony_cidiff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c 159822851890Sopenharmony_ciindex 0bf688e3c..bbca2e195 100644 159922851890Sopenharmony_ci--- a/drivers/dma-buf/heaps/system_heap.c 160022851890Sopenharmony_ci+++ b/drivers/dma-buf/heaps/system_heap.c 160122851890Sopenharmony_ci@@ -3,7 +3,11 @@ 160222851890Sopenharmony_ci * DMABUF System heap exporter 160322851890Sopenharmony_ci * 160422851890Sopenharmony_ci * Copyright (C) 2011 Google, Inc. 160522851890Sopenharmony_ci- * Copyright (C) 2019 Linaro Ltd. 160622851890Sopenharmony_ci+ * Copyright (C) 2019, 2020 Linaro Ltd. 160722851890Sopenharmony_ci+ * 160822851890Sopenharmony_ci+ * Portions based off of Andrew Davis' SRAM heap: 160922851890Sopenharmony_ci+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 161022851890Sopenharmony_ci+ * Andrew F. Davis <afd@ti.com> 161122851890Sopenharmony_ci */ 161222851890Sopenharmony_ci 161322851890Sopenharmony_ci #include <linux/dma-buf.h> 161422851890Sopenharmony_ci@@ -15,99 +19,547 @@ 161522851890Sopenharmony_ci #include <linux/module.h> 161622851890Sopenharmony_ci #include <linux/scatterlist.h> 161722851890Sopenharmony_ci #include <linux/slab.h> 161822851890Sopenharmony_ci-#include <linux/sched/signal.h> 161922851890Sopenharmony_ci-#include <asm/page.h> 162022851890Sopenharmony_ci+#include <linux/vmalloc.h> 162122851890Sopenharmony_ci+ 162222851890Sopenharmony_ci+#include "page_pool.h" 162322851890Sopenharmony_ci+#include "deferred-free-helper.h" 162422851890Sopenharmony_ci+ 162522851890Sopenharmony_ci+static struct dma_heap *sys_heap; 162622851890Sopenharmony_ci+static struct dma_heap *sys_uncached_heap; 162722851890Sopenharmony_ci+ 162822851890Sopenharmony_ci+struct system_heap_buffer { 162922851890Sopenharmony_ci+ struct dma_heap *heap; 163022851890Sopenharmony_ci+ struct list_head attachments; 163122851890Sopenharmony_ci+ struct mutex lock; 163222851890Sopenharmony_ci+ unsigned long len; 163322851890Sopenharmony_ci+ struct sg_table sg_table; 163422851890Sopenharmony_ci+ int vmap_cnt; 163522851890Sopenharmony_ci+ void *vaddr; 163622851890Sopenharmony_ci+ struct deferred_freelist_item deferred_free; 163722851890Sopenharmony_ci+ 163822851890Sopenharmony_ci+ bool uncached; 163922851890Sopenharmony_ci+}; 164022851890Sopenharmony_ci+ 164122851890Sopenharmony_ci+struct dma_heap_attachment { 164222851890Sopenharmony_ci+ struct device *dev; 164322851890Sopenharmony_ci+ struct sg_table *table; 164422851890Sopenharmony_ci+ struct list_head list; 164522851890Sopenharmony_ci+ bool mapped; 164622851890Sopenharmony_ci 164722851890Sopenharmony_ci-#include "heap-helpers.h" 164822851890Sopenharmony_ci+ bool uncached; 164922851890Sopenharmony_ci+}; 165022851890Sopenharmony_ci 165122851890Sopenharmony_ci-struct dma_heap *sys_heap; 165222851890Sopenharmony_ci+#define LOW_ORDER_GFP (GFP_HIGHUSER | __GFP_ZERO | __GFP_COMP) 165322851890Sopenharmony_ci+#define MID_ORDER_GFP (LOW_ORDER_GFP | __GFP_NOWARN) 165422851890Sopenharmony_ci+#define HIGH_ORDER_GFP (((GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN \ 165522851890Sopenharmony_ci+ | __GFP_NORETRY) & ~__GFP_RECLAIM) \ 165622851890Sopenharmony_ci+ | __GFP_COMP) 165722851890Sopenharmony_ci+static gfp_t order_flags[] = {HIGH_ORDER_GFP, MID_ORDER_GFP, LOW_ORDER_GFP}; 165822851890Sopenharmony_ci+/* 165922851890Sopenharmony_ci+ * The selection of the orders used for allocation (1MB, 64K, 4K) is designed 166022851890Sopenharmony_ci+ * to match with the sizes often found in IOMMUs. Using order 4 pages instead 166122851890Sopenharmony_ci+ * of order 0 pages can significantly improve the performance of many IOMMUs 166222851890Sopenharmony_ci+ * by reducing TLB pressure and time spent updating page tables. 166322851890Sopenharmony_ci+ */ 166422851890Sopenharmony_ci+static const unsigned int orders[] = {8, 4, 0}; 166522851890Sopenharmony_ci+#define NUM_ORDERS ARRAY_SIZE(orders) 166622851890Sopenharmony_ci+struct dmabuf_page_pool *pools[NUM_ORDERS]; 166722851890Sopenharmony_ci 166822851890Sopenharmony_ci-static void system_heap_free(struct heap_helper_buffer *buffer) 166922851890Sopenharmony_ci+static struct sg_table *dup_sg_table(struct sg_table *table) 167022851890Sopenharmony_ci { 167122851890Sopenharmony_ci- pgoff_t pg; 167222851890Sopenharmony_ci+ struct sg_table *new_table; 167322851890Sopenharmony_ci+ int ret, i; 167422851890Sopenharmony_ci+ struct scatterlist *sg, *new_sg; 167522851890Sopenharmony_ci 167622851890Sopenharmony_ci- for (pg = 0; pg < buffer->pagecount; pg++) 167722851890Sopenharmony_ci- __free_page(buffer->pages[pg]); 167822851890Sopenharmony_ci- kfree(buffer->pages); 167922851890Sopenharmony_ci- kfree(buffer); 168022851890Sopenharmony_ci+ new_table = kzalloc(sizeof(*new_table), GFP_KERNEL); 168122851890Sopenharmony_ci+ if (!new_table) 168222851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 168322851890Sopenharmony_ci+ 168422851890Sopenharmony_ci+ ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL); 168522851890Sopenharmony_ci+ if (ret) { 168622851890Sopenharmony_ci+ kfree(new_table); 168722851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 168822851890Sopenharmony_ci+ } 168922851890Sopenharmony_ci+ 169022851890Sopenharmony_ci+ new_sg = new_table->sgl; 169122851890Sopenharmony_ci+ for_each_sgtable_sg(table, sg, i) { 169222851890Sopenharmony_ci+ sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset); 169322851890Sopenharmony_ci+ new_sg = sg_next(new_sg); 169422851890Sopenharmony_ci+ } 169522851890Sopenharmony_ci+ 169622851890Sopenharmony_ci+ return new_table; 169722851890Sopenharmony_ci } 169822851890Sopenharmony_ci 169922851890Sopenharmony_ci-static int system_heap_allocate(struct dma_heap *heap, 170022851890Sopenharmony_ci- unsigned long len, 170122851890Sopenharmony_ci- unsigned long fd_flags, 170222851890Sopenharmony_ci- unsigned long heap_flags) 170322851890Sopenharmony_ci+static int system_heap_attach(struct dma_buf *dmabuf, 170422851890Sopenharmony_ci+ struct dma_buf_attachment *attachment) 170522851890Sopenharmony_ci { 170622851890Sopenharmony_ci- struct heap_helper_buffer *helper_buffer; 170722851890Sopenharmony_ci- struct dma_buf *dmabuf; 170822851890Sopenharmony_ci- int ret = -ENOMEM; 170922851890Sopenharmony_ci- pgoff_t pg; 171022851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 171122851890Sopenharmony_ci+ struct dma_heap_attachment *a; 171222851890Sopenharmony_ci+ struct sg_table *table; 171322851890Sopenharmony_ci+ 171422851890Sopenharmony_ci+ a = kzalloc(sizeof(*a), GFP_KERNEL); 171522851890Sopenharmony_ci+ if (!a) 171622851890Sopenharmony_ci+ return -ENOMEM; 171722851890Sopenharmony_ci 171822851890Sopenharmony_ci- helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL); 171922851890Sopenharmony_ci- if (!helper_buffer) 172022851890Sopenharmony_ci+ table = dup_sg_table(&buffer->sg_table); 172122851890Sopenharmony_ci+ if (IS_ERR(table)) { 172222851890Sopenharmony_ci+ kfree(a); 172322851890Sopenharmony_ci return -ENOMEM; 172422851890Sopenharmony_ci+ } 172522851890Sopenharmony_ci+ 172622851890Sopenharmony_ci+ a->table = table; 172722851890Sopenharmony_ci+ a->dev = attachment->dev; 172822851890Sopenharmony_ci+ INIT_LIST_HEAD(&a->list); 172922851890Sopenharmony_ci+ a->mapped = false; 173022851890Sopenharmony_ci+ a->uncached = buffer->uncached; 173122851890Sopenharmony_ci+ attachment->priv = a; 173222851890Sopenharmony_ci+ 173322851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 173422851890Sopenharmony_ci+ list_add(&a->list, &buffer->attachments); 173522851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 173622851890Sopenharmony_ci+ 173722851890Sopenharmony_ci+ return 0; 173822851890Sopenharmony_ci+} 173922851890Sopenharmony_ci+ 174022851890Sopenharmony_ci+static void system_heap_detach(struct dma_buf *dmabuf, 174122851890Sopenharmony_ci+ struct dma_buf_attachment *attachment) 174222851890Sopenharmony_ci+{ 174322851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 174422851890Sopenharmony_ci+ struct dma_heap_attachment *a = attachment->priv; 174522851890Sopenharmony_ci+ 174622851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 174722851890Sopenharmony_ci+ list_del(&a->list); 174822851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 174922851890Sopenharmony_ci+ 175022851890Sopenharmony_ci+ sg_free_table(a->table); 175122851890Sopenharmony_ci+ kfree(a->table); 175222851890Sopenharmony_ci+ kfree(a); 175322851890Sopenharmony_ci+} 175422851890Sopenharmony_ci 175522851890Sopenharmony_ci- init_heap_helper_buffer(helper_buffer, system_heap_free); 175622851890Sopenharmony_ci- helper_buffer->heap = heap; 175722851890Sopenharmony_ci- helper_buffer->size = len; 175822851890Sopenharmony_ci+static struct sg_table *system_heap_map_dma_buf(struct dma_buf_attachment *attachment, 175922851890Sopenharmony_ci+ enum dma_data_direction direction) 176022851890Sopenharmony_ci+{ 176122851890Sopenharmony_ci+ struct dma_heap_attachment *a = attachment->priv; 176222851890Sopenharmony_ci+ struct sg_table *table = a->table; 176322851890Sopenharmony_ci+ int attr = attachment->dma_map_attrs; 176422851890Sopenharmony_ci+ int ret; 176522851890Sopenharmony_ci+ 176622851890Sopenharmony_ci+ if (a->uncached) 176722851890Sopenharmony_ci+ attr |= DMA_ATTR_SKIP_CPU_SYNC; 176822851890Sopenharmony_ci+ 176922851890Sopenharmony_ci+ ret = dma_map_sgtable(attachment->dev, table, direction, attr); 177022851890Sopenharmony_ci+ if (ret) 177122851890Sopenharmony_ci+ return ERR_PTR(ret); 177222851890Sopenharmony_ci+ 177322851890Sopenharmony_ci+ a->mapped = true; 177422851890Sopenharmony_ci+ return table; 177522851890Sopenharmony_ci+} 177622851890Sopenharmony_ci+ 177722851890Sopenharmony_ci+static void system_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, 177822851890Sopenharmony_ci+ struct sg_table *table, 177922851890Sopenharmony_ci+ enum dma_data_direction direction) 178022851890Sopenharmony_ci+{ 178122851890Sopenharmony_ci+ struct dma_heap_attachment *a = attachment->priv; 178222851890Sopenharmony_ci+ int attr = attachment->dma_map_attrs; 178322851890Sopenharmony_ci+ 178422851890Sopenharmony_ci+ if (a->uncached) 178522851890Sopenharmony_ci+ attr |= DMA_ATTR_SKIP_CPU_SYNC; 178622851890Sopenharmony_ci+ a->mapped = false; 178722851890Sopenharmony_ci+ dma_unmap_sgtable(attachment->dev, table, direction, attr); 178822851890Sopenharmony_ci+} 178922851890Sopenharmony_ci 179022851890Sopenharmony_ci- helper_buffer->pagecount = len / PAGE_SIZE; 179122851890Sopenharmony_ci- helper_buffer->pages = kmalloc_array(helper_buffer->pagecount, 179222851890Sopenharmony_ci- sizeof(*helper_buffer->pages), 179322851890Sopenharmony_ci- GFP_KERNEL); 179422851890Sopenharmony_ci- if (!helper_buffer->pages) { 179522851890Sopenharmony_ci- ret = -ENOMEM; 179622851890Sopenharmony_ci- goto err0; 179722851890Sopenharmony_ci+static int system_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, 179822851890Sopenharmony_ci+ enum dma_data_direction direction) 179922851890Sopenharmony_ci+{ 180022851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 180122851890Sopenharmony_ci+ struct dma_heap_attachment *a; 180222851890Sopenharmony_ci+ 180322851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 180422851890Sopenharmony_ci+ 180522851890Sopenharmony_ci+ if (buffer->vmap_cnt) 180622851890Sopenharmony_ci+ invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); 180722851890Sopenharmony_ci+ 180822851890Sopenharmony_ci+ if (!buffer->uncached) { 180922851890Sopenharmony_ci+ list_for_each_entry(a, &buffer->attachments, list) { 181022851890Sopenharmony_ci+ if (!a->mapped) 181122851890Sopenharmony_ci+ continue; 181222851890Sopenharmony_ci+ dma_sync_sgtable_for_cpu(a->dev, a->table, direction); 181322851890Sopenharmony_ci+ } 181422851890Sopenharmony_ci } 181522851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 181622851890Sopenharmony_ci+ 181722851890Sopenharmony_ci+ return 0; 181822851890Sopenharmony_ci+} 181922851890Sopenharmony_ci+ 182022851890Sopenharmony_ci+static int system_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, 182122851890Sopenharmony_ci+ enum dma_data_direction direction) 182222851890Sopenharmony_ci+{ 182322851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 182422851890Sopenharmony_ci+ struct dma_heap_attachment *a; 182522851890Sopenharmony_ci+ 182622851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 182722851890Sopenharmony_ci+ 182822851890Sopenharmony_ci+ if (buffer->vmap_cnt) 182922851890Sopenharmony_ci+ flush_kernel_vmap_range(buffer->vaddr, buffer->len); 183022851890Sopenharmony_ci+ 183122851890Sopenharmony_ci+ if (!buffer->uncached) { 183222851890Sopenharmony_ci+ list_for_each_entry(a, &buffer->attachments, list) { 183322851890Sopenharmony_ci+ if (!a->mapped) 183422851890Sopenharmony_ci+ continue; 183522851890Sopenharmony_ci+ dma_sync_sgtable_for_device(a->dev, a->table, direction); 183622851890Sopenharmony_ci+ } 183722851890Sopenharmony_ci+ } 183822851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 183922851890Sopenharmony_ci+ 184022851890Sopenharmony_ci+ return 0; 184122851890Sopenharmony_ci+} 184222851890Sopenharmony_ci+ 184322851890Sopenharmony_ci+static int system_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) 184422851890Sopenharmony_ci+{ 184522851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 184622851890Sopenharmony_ci+ struct sg_table *table = &buffer->sg_table; 184722851890Sopenharmony_ci+ unsigned long addr = vma->vm_start; 184822851890Sopenharmony_ci+ struct sg_page_iter piter; 184922851890Sopenharmony_ci+ int ret; 185022851890Sopenharmony_ci+ 185122851890Sopenharmony_ci+ if (buffer->uncached) 185222851890Sopenharmony_ci+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 185322851890Sopenharmony_ci+ 185422851890Sopenharmony_ci+ for_each_sgtable_page(table, &piter, vma->vm_pgoff) { 185522851890Sopenharmony_ci+ struct page *page = sg_page_iter_page(&piter); 185622851890Sopenharmony_ci+ 185722851890Sopenharmony_ci+ ret = remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE, 185822851890Sopenharmony_ci+ vma->vm_page_prot); 185922851890Sopenharmony_ci+ if (ret) 186022851890Sopenharmony_ci+ return ret; 186122851890Sopenharmony_ci+ addr += PAGE_SIZE; 186222851890Sopenharmony_ci+ if (addr >= vma->vm_end) 186322851890Sopenharmony_ci+ return 0; 186422851890Sopenharmony_ci+ } 186522851890Sopenharmony_ci+ return 0; 186622851890Sopenharmony_ci+} 186722851890Sopenharmony_ci+ 186822851890Sopenharmony_ci+static void *system_heap_do_vmap(struct system_heap_buffer *buffer) 186922851890Sopenharmony_ci+{ 187022851890Sopenharmony_ci+ struct sg_table *table = &buffer->sg_table; 187122851890Sopenharmony_ci+ int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE; 187222851890Sopenharmony_ci+ struct page **pages = vmalloc(sizeof(struct page *) * npages); 187322851890Sopenharmony_ci+ struct page **tmp = pages; 187422851890Sopenharmony_ci+ struct sg_page_iter piter; 187522851890Sopenharmony_ci+ pgprot_t pgprot = PAGE_KERNEL; 187622851890Sopenharmony_ci+ void *vaddr; 187722851890Sopenharmony_ci+ 187822851890Sopenharmony_ci+ if (!pages) 187922851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 188022851890Sopenharmony_ci+ 188122851890Sopenharmony_ci+ if (buffer->uncached) 188222851890Sopenharmony_ci+ pgprot = pgprot_writecombine(PAGE_KERNEL); 188322851890Sopenharmony_ci+ 188422851890Sopenharmony_ci+ for_each_sgtable_page(table, &piter, 0) { 188522851890Sopenharmony_ci+ WARN_ON(tmp - pages >= npages); 188622851890Sopenharmony_ci+ *tmp++ = sg_page_iter_page(&piter); 188722851890Sopenharmony_ci+ } 188822851890Sopenharmony_ci+ 188922851890Sopenharmony_ci+ vaddr = vmap(pages, npages, VM_MAP, pgprot); 189022851890Sopenharmony_ci+ vfree(pages); 189122851890Sopenharmony_ci+ 189222851890Sopenharmony_ci+ if (!vaddr) 189322851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 189422851890Sopenharmony_ci+ 189522851890Sopenharmony_ci+ return vaddr; 189622851890Sopenharmony_ci+} 189722851890Sopenharmony_ci+ 189822851890Sopenharmony_ci+static void *system_heap_vmap(struct dma_buf *dmabuf) 189922851890Sopenharmony_ci+{ 190022851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 190122851890Sopenharmony_ci+ void *vaddr; 190222851890Sopenharmony_ci+ 190322851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 190422851890Sopenharmony_ci+ if (buffer->vmap_cnt) { 190522851890Sopenharmony_ci+ buffer->vmap_cnt++; 190622851890Sopenharmony_ci+ vaddr = buffer->vaddr; 190722851890Sopenharmony_ci+ goto out; 190822851890Sopenharmony_ci+ } 190922851890Sopenharmony_ci+ 191022851890Sopenharmony_ci+ vaddr = system_heap_do_vmap(buffer); 191122851890Sopenharmony_ci+ if (IS_ERR(vaddr)) 191222851890Sopenharmony_ci+ goto out; 191322851890Sopenharmony_ci+ 191422851890Sopenharmony_ci+ buffer->vaddr = vaddr; 191522851890Sopenharmony_ci+ buffer->vmap_cnt++; 191622851890Sopenharmony_ci+out: 191722851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 191822851890Sopenharmony_ci 191922851890Sopenharmony_ci- for (pg = 0; pg < helper_buffer->pagecount; pg++) { 192022851890Sopenharmony_ci+ return vaddr; 192122851890Sopenharmony_ci+} 192222851890Sopenharmony_ci+ 192322851890Sopenharmony_ci+static void system_heap_vunmap(struct dma_buf *dmabuf, void *vaddr) 192422851890Sopenharmony_ci+{ 192522851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 192622851890Sopenharmony_ci+ 192722851890Sopenharmony_ci+ mutex_lock(&buffer->lock); 192822851890Sopenharmony_ci+ if (!--buffer->vmap_cnt) { 192922851890Sopenharmony_ci+ vunmap(buffer->vaddr); 193022851890Sopenharmony_ci+ buffer->vaddr = NULL; 193122851890Sopenharmony_ci+ } 193222851890Sopenharmony_ci+ mutex_unlock(&buffer->lock); 193322851890Sopenharmony_ci+} 193422851890Sopenharmony_ci+ 193522851890Sopenharmony_ci+static int system_heap_zero_buffer(struct system_heap_buffer *buffer) 193622851890Sopenharmony_ci+{ 193722851890Sopenharmony_ci+ struct sg_table *sgt = &buffer->sg_table; 193822851890Sopenharmony_ci+ struct sg_page_iter piter; 193922851890Sopenharmony_ci+ struct page *p; 194022851890Sopenharmony_ci+ void *vaddr; 194122851890Sopenharmony_ci+ int ret = 0; 194222851890Sopenharmony_ci+ 194322851890Sopenharmony_ci+ for_each_sgtable_page(sgt, &piter, 0) { 194422851890Sopenharmony_ci+ p = sg_page_iter_page(&piter); 194522851890Sopenharmony_ci+ vaddr = kmap_atomic(p); 194622851890Sopenharmony_ci+ memset(vaddr, 0, PAGE_SIZE); 194722851890Sopenharmony_ci+ kunmap_atomic(vaddr); 194822851890Sopenharmony_ci+ } 194922851890Sopenharmony_ci+ 195022851890Sopenharmony_ci+ return ret; 195122851890Sopenharmony_ci+} 195222851890Sopenharmony_ci+ 195322851890Sopenharmony_ci+static void system_heap_buf_free(struct deferred_freelist_item *item, 195422851890Sopenharmony_ci+ enum df_reason reason) 195522851890Sopenharmony_ci+{ 195622851890Sopenharmony_ci+ struct system_heap_buffer *buffer; 195722851890Sopenharmony_ci+ struct sg_table *table; 195822851890Sopenharmony_ci+ struct scatterlist *sg; 195922851890Sopenharmony_ci+ int i, j; 196022851890Sopenharmony_ci+ 196122851890Sopenharmony_ci+ buffer = container_of(item, struct system_heap_buffer, deferred_free); 196222851890Sopenharmony_ci+ /* Zero the buffer pages before adding back to the pool */ 196322851890Sopenharmony_ci+ if (reason == DF_NORMAL) 196422851890Sopenharmony_ci+ if (system_heap_zero_buffer(buffer)) 196522851890Sopenharmony_ci+ reason = DF_UNDER_PRESSURE; // On failure, just free 196622851890Sopenharmony_ci+ 196722851890Sopenharmony_ci+ table = &buffer->sg_table; 196822851890Sopenharmony_ci+ for_each_sgtable_sg(table, sg, i) { 196922851890Sopenharmony_ci+ struct page *page = sg_page(sg); 197022851890Sopenharmony_ci+ 197122851890Sopenharmony_ci+ if (reason == DF_UNDER_PRESSURE) { 197222851890Sopenharmony_ci+ __free_pages(page, compound_order(page)); 197322851890Sopenharmony_ci+ } else { 197422851890Sopenharmony_ci+ for (j = 0; j < NUM_ORDERS; j++) { 197522851890Sopenharmony_ci+ if (compound_order(page) == orders[j]) 197622851890Sopenharmony_ci+ break; 197722851890Sopenharmony_ci+ } 197822851890Sopenharmony_ci+ dmabuf_page_pool_free(pools[j], page); 197922851890Sopenharmony_ci+ } 198022851890Sopenharmony_ci+ } 198122851890Sopenharmony_ci+ sg_free_table(table); 198222851890Sopenharmony_ci+ kfree(buffer); 198322851890Sopenharmony_ci+} 198422851890Sopenharmony_ci+ 198522851890Sopenharmony_ci+static void system_heap_dma_buf_release(struct dma_buf *dmabuf) 198622851890Sopenharmony_ci+{ 198722851890Sopenharmony_ci+ struct system_heap_buffer *buffer = dmabuf->priv; 198822851890Sopenharmony_ci+ int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE; 198922851890Sopenharmony_ci+ 199022851890Sopenharmony_ci+ deferred_free(&buffer->deferred_free, system_heap_buf_free, npages); 199122851890Sopenharmony_ci+} 199222851890Sopenharmony_ci+ 199322851890Sopenharmony_ci+static const struct dma_buf_ops system_heap_buf_ops = { 199422851890Sopenharmony_ci+ .attach = system_heap_attach, 199522851890Sopenharmony_ci+ .detach = system_heap_detach, 199622851890Sopenharmony_ci+ .map_dma_buf = system_heap_map_dma_buf, 199722851890Sopenharmony_ci+ .unmap_dma_buf = system_heap_unmap_dma_buf, 199822851890Sopenharmony_ci+ .begin_cpu_access = system_heap_dma_buf_begin_cpu_access, 199922851890Sopenharmony_ci+ .end_cpu_access = system_heap_dma_buf_end_cpu_access, 200022851890Sopenharmony_ci+ .mmap = system_heap_mmap, 200122851890Sopenharmony_ci+ .vmap = system_heap_vmap, 200222851890Sopenharmony_ci+ .vunmap = system_heap_vunmap, 200322851890Sopenharmony_ci+ .release = system_heap_dma_buf_release, 200422851890Sopenharmony_ci+}; 200522851890Sopenharmony_ci+ 200622851890Sopenharmony_ci+static struct page *alloc_largest_available(unsigned long size, 200722851890Sopenharmony_ci+ unsigned int max_order) 200822851890Sopenharmony_ci+{ 200922851890Sopenharmony_ci+ struct page *page; 201022851890Sopenharmony_ci+ int i; 201122851890Sopenharmony_ci+ 201222851890Sopenharmony_ci+ for (i = 0; i < NUM_ORDERS; i++) { 201322851890Sopenharmony_ci+ if (size < (PAGE_SIZE << orders[i])) 201422851890Sopenharmony_ci+ continue; 201522851890Sopenharmony_ci+ if (max_order < orders[i]) 201622851890Sopenharmony_ci+ continue; 201722851890Sopenharmony_ci+ page = dmabuf_page_pool_alloc(pools[i]); 201822851890Sopenharmony_ci+ if (!page) 201922851890Sopenharmony_ci+ continue; 202022851890Sopenharmony_ci+ return page; 202122851890Sopenharmony_ci+ } 202222851890Sopenharmony_ci+ return NULL; 202322851890Sopenharmony_ci+} 202422851890Sopenharmony_ci+ 202522851890Sopenharmony_ci+static struct dma_buf *system_heap_do_allocate(struct dma_heap *heap, 202622851890Sopenharmony_ci+ unsigned long len, 202722851890Sopenharmony_ci+ unsigned long fd_flags, 202822851890Sopenharmony_ci+ unsigned long heap_flags, 202922851890Sopenharmony_ci+ bool uncached) 203022851890Sopenharmony_ci+{ 203122851890Sopenharmony_ci+ struct system_heap_buffer *buffer; 203222851890Sopenharmony_ci+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 203322851890Sopenharmony_ci+ unsigned long size_remaining = len; 203422851890Sopenharmony_ci+ unsigned int max_order = orders[0]; 203522851890Sopenharmony_ci+ struct dma_buf *dmabuf; 203622851890Sopenharmony_ci+ struct sg_table *table; 203722851890Sopenharmony_ci+ struct scatterlist *sg; 203822851890Sopenharmony_ci+ struct list_head pages; 203922851890Sopenharmony_ci+ struct page *page, *tmp_page; 204022851890Sopenharmony_ci+ int i, ret = -ENOMEM; 204122851890Sopenharmony_ci+ 204222851890Sopenharmony_ci+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 204322851890Sopenharmony_ci+ if (!buffer) 204422851890Sopenharmony_ci+ return ERR_PTR(-ENOMEM); 204522851890Sopenharmony_ci+ 204622851890Sopenharmony_ci+ INIT_LIST_HEAD(&buffer->attachments); 204722851890Sopenharmony_ci+ mutex_init(&buffer->lock); 204822851890Sopenharmony_ci+ buffer->heap = heap; 204922851890Sopenharmony_ci+ buffer->len = len; 205022851890Sopenharmony_ci+ buffer->uncached = uncached; 205122851890Sopenharmony_ci+ 205222851890Sopenharmony_ci+ INIT_LIST_HEAD(&pages); 205322851890Sopenharmony_ci+ i = 0; 205422851890Sopenharmony_ci+ while (size_remaining > 0) { 205522851890Sopenharmony_ci /* 205622851890Sopenharmony_ci * Avoid trying to allocate memory if the process 205722851890Sopenharmony_ci- * has been killed by by SIGKILL 205822851890Sopenharmony_ci+ * has been killed by SIGKILL 205922851890Sopenharmony_ci */ 206022851890Sopenharmony_ci if (fatal_signal_pending(current)) 206122851890Sopenharmony_ci- goto err1; 206222851890Sopenharmony_ci+ goto free_buffer; 206322851890Sopenharmony_ci+ 206422851890Sopenharmony_ci+ page = alloc_largest_available(size_remaining, max_order); 206522851890Sopenharmony_ci+ if (!page) 206622851890Sopenharmony_ci+ goto free_buffer; 206722851890Sopenharmony_ci+ 206822851890Sopenharmony_ci+ list_add_tail(&page->lru, &pages); 206922851890Sopenharmony_ci+ size_remaining -= page_size(page); 207022851890Sopenharmony_ci+ max_order = compound_order(page); 207122851890Sopenharmony_ci+ i++; 207222851890Sopenharmony_ci+ } 207322851890Sopenharmony_ci 207422851890Sopenharmony_ci- helper_buffer->pages[pg] = alloc_page(GFP_KERNEL | __GFP_ZERO); 207522851890Sopenharmony_ci- if (!helper_buffer->pages[pg]) 207622851890Sopenharmony_ci- goto err1; 207722851890Sopenharmony_ci+ table = &buffer->sg_table; 207822851890Sopenharmony_ci+ if (sg_alloc_table(table, i, GFP_KERNEL)) 207922851890Sopenharmony_ci+ goto free_buffer; 208022851890Sopenharmony_ci+ 208122851890Sopenharmony_ci+ sg = table->sgl; 208222851890Sopenharmony_ci+ list_for_each_entry_safe(page, tmp_page, &pages, lru) { 208322851890Sopenharmony_ci+ sg_set_page(sg, page, page_size(page), 0); 208422851890Sopenharmony_ci+ sg = sg_next(sg); 208522851890Sopenharmony_ci+ list_del(&page->lru); 208622851890Sopenharmony_ci } 208722851890Sopenharmony_ci 208822851890Sopenharmony_ci /* create the dmabuf */ 208922851890Sopenharmony_ci- dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags); 209022851890Sopenharmony_ci+ exp_info.exp_name = dma_heap_get_name(heap); 209122851890Sopenharmony_ci+ exp_info.ops = &system_heap_buf_ops; 209222851890Sopenharmony_ci+ exp_info.size = buffer->len; 209322851890Sopenharmony_ci+ exp_info.flags = fd_flags; 209422851890Sopenharmony_ci+ exp_info.priv = buffer; 209522851890Sopenharmony_ci+ dmabuf = dma_buf_export(&exp_info); 209622851890Sopenharmony_ci if (IS_ERR(dmabuf)) { 209722851890Sopenharmony_ci ret = PTR_ERR(dmabuf); 209822851890Sopenharmony_ci- goto err1; 209922851890Sopenharmony_ci+ goto free_pages; 210022851890Sopenharmony_ci+ } 210122851890Sopenharmony_ci+ 210222851890Sopenharmony_ci+ /* 210322851890Sopenharmony_ci+ * For uncached buffers, we need to initially flush cpu cache, since 210422851890Sopenharmony_ci+ * the __GFP_ZERO on the allocation means the zeroing was done by the 210522851890Sopenharmony_ci+ * cpu and thus it is likely cached. Map (and implicitly flush) and 210622851890Sopenharmony_ci+ * unmap it now so we don't get corruption later on. 210722851890Sopenharmony_ci+ */ 210822851890Sopenharmony_ci+ if (buffer->uncached) { 210922851890Sopenharmony_ci+ dma_map_sgtable(dma_heap_get_dev(heap), table, DMA_BIDIRECTIONAL, 0); 211022851890Sopenharmony_ci+ dma_unmap_sgtable(dma_heap_get_dev(heap), table, DMA_BIDIRECTIONAL, 0); 211122851890Sopenharmony_ci } 211222851890Sopenharmony_ci 211322851890Sopenharmony_ci- helper_buffer->dmabuf = dmabuf; 211422851890Sopenharmony_ci+ return dmabuf; 211522851890Sopenharmony_ci 211622851890Sopenharmony_ci- ret = dma_buf_fd(dmabuf, fd_flags); 211722851890Sopenharmony_ci- if (ret < 0) { 211822851890Sopenharmony_ci- dma_buf_put(dmabuf); 211922851890Sopenharmony_ci- /* just return, as put will call release and that will free */ 212022851890Sopenharmony_ci- return ret; 212122851890Sopenharmony_ci+free_pages: 212222851890Sopenharmony_ci+ for_each_sgtable_sg(table, sg, i) { 212322851890Sopenharmony_ci+ struct page *p = sg_page(sg); 212422851890Sopenharmony_ci+ 212522851890Sopenharmony_ci+ __free_pages(p, compound_order(p)); 212622851890Sopenharmony_ci } 212722851890Sopenharmony_ci+ sg_free_table(table); 212822851890Sopenharmony_ci+free_buffer: 212922851890Sopenharmony_ci+ list_for_each_entry_safe(page, tmp_page, &pages, lru) 213022851890Sopenharmony_ci+ __free_pages(page, compound_order(page)); 213122851890Sopenharmony_ci+ kfree(buffer); 213222851890Sopenharmony_ci 213322851890Sopenharmony_ci- return ret; 213422851890Sopenharmony_ci+ return ERR_PTR(ret); 213522851890Sopenharmony_ci+} 213622851890Sopenharmony_ci 213722851890Sopenharmony_ci-err1: 213822851890Sopenharmony_ci- while (pg > 0) 213922851890Sopenharmony_ci- __free_page(helper_buffer->pages[--pg]); 214022851890Sopenharmony_ci- kfree(helper_buffer->pages); 214122851890Sopenharmony_ci-err0: 214222851890Sopenharmony_ci- kfree(helper_buffer); 214322851890Sopenharmony_ci+static struct dma_buf *system_heap_allocate(struct dma_heap *heap, 214422851890Sopenharmony_ci+ unsigned long len, 214522851890Sopenharmony_ci+ unsigned long fd_flags, 214622851890Sopenharmony_ci+ unsigned long heap_flags) 214722851890Sopenharmony_ci+{ 214822851890Sopenharmony_ci+ return system_heap_do_allocate(heap, len, fd_flags, heap_flags, false); 214922851890Sopenharmony_ci+} 215022851890Sopenharmony_ci 215122851890Sopenharmony_ci- return ret; 215222851890Sopenharmony_ci+static long system_get_pool_size(struct dma_heap *heap) 215322851890Sopenharmony_ci+{ 215422851890Sopenharmony_ci+ int i; 215522851890Sopenharmony_ci+ long num_pages = 0; 215622851890Sopenharmony_ci+ struct dmabuf_page_pool **pool; 215722851890Sopenharmony_ci+ 215822851890Sopenharmony_ci+ pool = pools; 215922851890Sopenharmony_ci+ for (i = 0; i < NUM_ORDERS; i++, pool++) { 216022851890Sopenharmony_ci+ num_pages += ((*pool)->count[POOL_LOWPAGE] + 216122851890Sopenharmony_ci+ (*pool)->count[POOL_HIGHPAGE]) << (*pool)->order; 216222851890Sopenharmony_ci+ } 216322851890Sopenharmony_ci+ 216422851890Sopenharmony_ci+ return num_pages << PAGE_SHIFT; 216522851890Sopenharmony_ci } 216622851890Sopenharmony_ci 216722851890Sopenharmony_ci static const struct dma_heap_ops system_heap_ops = { 216822851890Sopenharmony_ci .allocate = system_heap_allocate, 216922851890Sopenharmony_ci+ .get_pool_size = system_get_pool_size, 217022851890Sopenharmony_ci+}; 217122851890Sopenharmony_ci+ 217222851890Sopenharmony_ci+static struct dma_buf *system_uncached_heap_allocate(struct dma_heap *heap, 217322851890Sopenharmony_ci+ unsigned long len, 217422851890Sopenharmony_ci+ unsigned long fd_flags, 217522851890Sopenharmony_ci+ unsigned long heap_flags) 217622851890Sopenharmony_ci+{ 217722851890Sopenharmony_ci+ return system_heap_do_allocate(heap, len, fd_flags, heap_flags, true); 217822851890Sopenharmony_ci+} 217922851890Sopenharmony_ci+ 218022851890Sopenharmony_ci+/* Dummy function to be used until we can call coerce_mask_and_coherent */ 218122851890Sopenharmony_ci+static struct dma_buf *system_uncached_heap_not_initialized(struct dma_heap *heap, 218222851890Sopenharmony_ci+ unsigned long len, 218322851890Sopenharmony_ci+ unsigned long fd_flags, 218422851890Sopenharmony_ci+ unsigned long heap_flags) 218522851890Sopenharmony_ci+{ 218622851890Sopenharmony_ci+ return ERR_PTR(-EBUSY); 218722851890Sopenharmony_ci+} 218822851890Sopenharmony_ci+ 218922851890Sopenharmony_ci+static struct dma_heap_ops system_uncached_heap_ops = { 219022851890Sopenharmony_ci+ /* After system_heap_create is complete, we will swap this */ 219122851890Sopenharmony_ci+ .allocate = system_uncached_heap_not_initialized, 219222851890Sopenharmony_ci }; 219322851890Sopenharmony_ci 219422851890Sopenharmony_ci static int system_heap_create(void) 219522851890Sopenharmony_ci { 219622851890Sopenharmony_ci struct dma_heap_export_info exp_info; 219722851890Sopenharmony_ci- int ret = 0; 219822851890Sopenharmony_ci+ int i; 219922851890Sopenharmony_ci+ 220022851890Sopenharmony_ci+ for (i = 0; i < NUM_ORDERS; i++) { 220122851890Sopenharmony_ci+ pools[i] = dmabuf_page_pool_create(order_flags[i], orders[i]); 220222851890Sopenharmony_ci+ 220322851890Sopenharmony_ci+ if (!pools[i]) { 220422851890Sopenharmony_ci+ int j; 220522851890Sopenharmony_ci+ 220622851890Sopenharmony_ci+ pr_err("%s: page pool creation failed!\n", __func__); 220722851890Sopenharmony_ci+ for (j = 0; j < i; j++) 220822851890Sopenharmony_ci+ dmabuf_page_pool_destroy(pools[j]); 220922851890Sopenharmony_ci+ return -ENOMEM; 221022851890Sopenharmony_ci+ } 221122851890Sopenharmony_ci+ } 221222851890Sopenharmony_ci 221322851890Sopenharmony_ci exp_info.name = "system"; 221422851890Sopenharmony_ci exp_info.ops = &system_heap_ops; 221522851890Sopenharmony_ci@@ -115,9 +567,21 @@ static int system_heap_create(void) 221622851890Sopenharmony_ci 221722851890Sopenharmony_ci sys_heap = dma_heap_add(&exp_info); 221822851890Sopenharmony_ci if (IS_ERR(sys_heap)) 221922851890Sopenharmony_ci- ret = PTR_ERR(sys_heap); 222022851890Sopenharmony_ci+ return PTR_ERR(sys_heap); 222122851890Sopenharmony_ci 222222851890Sopenharmony_ci- return ret; 222322851890Sopenharmony_ci+ exp_info.name = "system-uncached"; 222422851890Sopenharmony_ci+ exp_info.ops = &system_uncached_heap_ops; 222522851890Sopenharmony_ci+ exp_info.priv = NULL; 222622851890Sopenharmony_ci+ 222722851890Sopenharmony_ci+ sys_uncached_heap = dma_heap_add(&exp_info); 222822851890Sopenharmony_ci+ if (IS_ERR(sys_uncached_heap)) 222922851890Sopenharmony_ci+ return PTR_ERR(sys_uncached_heap); 223022851890Sopenharmony_ci+ 223122851890Sopenharmony_ci+ dma_coerce_mask_and_coherent(dma_heap_get_dev(sys_uncached_heap), DMA_BIT_MASK(64)); 223222851890Sopenharmony_ci+ mb(); /* make sure we only set allocate after dma_mask is set */ 223322851890Sopenharmony_ci+ system_uncached_heap_ops.allocate = system_uncached_heap_allocate; 223422851890Sopenharmony_ci+ 223522851890Sopenharmony_ci+ return 0; 223622851890Sopenharmony_ci } 223722851890Sopenharmony_ci module_init(system_heap_create); 223822851890Sopenharmony_ci MODULE_LICENSE("GPL v2"); 223922851890Sopenharmony_cidiff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c 224022851890Sopenharmony_ciindex 109d11fb4..4aac2ec86 100644 224122851890Sopenharmony_ci--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c 224222851890Sopenharmony_ci+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c 224322851890Sopenharmony_ci@@ -461,9 +461,10 @@ int drm_gem_fb_prepare_fb(struct drm_plane *plane, 224422851890Sopenharmony_ci return 0; 224522851890Sopenharmony_ci 224622851890Sopenharmony_ci obj = drm_gem_fb_get_obj(state->fb, 0); 224722851890Sopenharmony_ci- fence = dma_resv_get_excl_rcu(obj->resv); 224822851890Sopenharmony_ci- drm_atomic_set_fence_for_plane(state, fence); 224922851890Sopenharmony_ci- 225022851890Sopenharmony_ci+ if (obj) { 225122851890Sopenharmony_ci+ fence = dma_resv_get_excl_rcu(obj->resv); 225222851890Sopenharmony_ci+ drm_atomic_set_fence_for_plane(state, fence); 225322851890Sopenharmony_ci+ } 225422851890Sopenharmony_ci return 0; 225522851890Sopenharmony_ci } 225622851890Sopenharmony_ci EXPORT_SYMBOL_GPL(drm_gem_fb_prepare_fb); 225722851890Sopenharmony_cidiff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c 225822851890Sopenharmony_ciindex f135b7959..fc9c53e3e 100644 225922851890Sopenharmony_ci--- a/drivers/gpu/drm/drm_vblank.c 226022851890Sopenharmony_ci+++ b/drivers/gpu/drm/drm_vblank.c 226122851890Sopenharmony_ci@@ -1100,7 +1100,7 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe) 226222851890Sopenharmony_ci return dev->driver->enable_vblank(dev, pipe); 226322851890Sopenharmony_ci } 226422851890Sopenharmony_ci 226522851890Sopenharmony_ci- return -EINVAL; 226622851890Sopenharmony_ci+ return 0; 226722851890Sopenharmony_ci } 226822851890Sopenharmony_ci 226922851890Sopenharmony_ci static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) 227022851890Sopenharmony_cidiff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h 227122851890Sopenharmony_ciindex 0c5706abb..528cd83d3 100644 227222851890Sopenharmony_ci--- a/include/linux/dma-buf.h 227322851890Sopenharmony_ci+++ b/include/linux/dma-buf.h 227422851890Sopenharmony_ci@@ -289,14 +289,9 @@ struct dma_buf_ops { 227522851890Sopenharmony_ci * @list_node: node for dma_buf accounting and debugging. 227622851890Sopenharmony_ci * @priv: exporter specific private data for this buffer object. 227722851890Sopenharmony_ci * @resv: reservation object linked to this dma-buf 227822851890Sopenharmony_ci- * @exp_pid: pid of exporter task which created this obj 227922851890Sopenharmony_ci- * @exp_task_comm: process name of exporter task which created this obj 228022851890Sopenharmony_ci * @poll: for userspace poll support 228122851890Sopenharmony_ci * @cb_excl: for userspace poll support 228222851890Sopenharmony_ci * @cb_shared: for userspace poll support 228322851890Sopenharmony_ci- * @sysfs_entry: for exposing information about this buffer in sysfs. 228422851890Sopenharmony_ci- * The attachment_uid member of @sysfs_entry is protected by dma_resv lock 228522851890Sopenharmony_ci- * and is incremented on each attach. 228622851890Sopenharmony_ci * 228722851890Sopenharmony_ci * This represents a shared buffer, created by calling dma_buf_export(). The 228822851890Sopenharmony_ci * userspace representation is a normal file descriptor, which can be created by 228922851890Sopenharmony_ci@@ -322,10 +317,6 @@ struct dma_buf { 229022851890Sopenharmony_ci struct list_head list_node; 229122851890Sopenharmony_ci void *priv; 229222851890Sopenharmony_ci struct dma_resv *resv; 229322851890Sopenharmony_ci-#ifdef CONFIG_DMABUF_PROCESS_INFO 229422851890Sopenharmony_ci- pid_t exp_pid; 229522851890Sopenharmony_ci- char exp_task_comm[TASK_COMM_LEN]; 229622851890Sopenharmony_ci-#endif 229722851890Sopenharmony_ci 229822851890Sopenharmony_ci /* poll support */ 229922851890Sopenharmony_ci wait_queue_head_t poll; 230022851890Sopenharmony_ci@@ -336,13 +327,6 @@ struct dma_buf { 230122851890Sopenharmony_ci 230222851890Sopenharmony_ci __poll_t active; 230322851890Sopenharmony_ci } cb_excl, cb_shared; 230422851890Sopenharmony_ci-#ifdef CONFIG_DMABUF_SYSFS_STATS 230522851890Sopenharmony_ci- /* for sysfs stats */ 230622851890Sopenharmony_ci- struct dma_buf_sysfs_entry { 230722851890Sopenharmony_ci- struct kobject kobj; 230822851890Sopenharmony_ci- struct dma_buf *dmabuf; 230922851890Sopenharmony_ci- } *sysfs_entry; 231022851890Sopenharmony_ci-#endif 231122851890Sopenharmony_ci }; 231222851890Sopenharmony_ci 231322851890Sopenharmony_ci /** 231422851890Sopenharmony_ci@@ -412,6 +396,7 @@ struct dma_buf_attachment { 231522851890Sopenharmony_ci const struct dma_buf_attach_ops *importer_ops; 231622851890Sopenharmony_ci void *importer_priv; 231722851890Sopenharmony_ci void *priv; 231822851890Sopenharmony_ci+ unsigned long dma_map_attrs; 231922851890Sopenharmony_ci }; 232022851890Sopenharmony_ci 232122851890Sopenharmony_ci /** 232222851890Sopenharmony_ci@@ -520,16 +505,4 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, 232322851890Sopenharmony_ci unsigned long); 232422851890Sopenharmony_ci void *dma_buf_vmap(struct dma_buf *); 232522851890Sopenharmony_ci void dma_buf_vunmap(struct dma_buf *, void *vaddr); 232622851890Sopenharmony_ci- 232722851890Sopenharmony_ci-#ifdef CONFIG_DMABUF_PROCESS_INFO 232822851890Sopenharmony_ci-/** 232922851890Sopenharmony_ci- * get_dma_buf_from_file - Get struct dma_buf* from struct file* 233022851890Sopenharmony_ci- * @f: [in] pointer to struct file, which is associated with a 233122851890Sopenharmony_ci- * dma_buf object. 233222851890Sopenharmony_ci- * 233322851890Sopenharmony_ci- * If @f IS_ERR_OR_NULL, return NULL. 233422851890Sopenharmony_ci- * If @f is not a file associated with dma_buf, return NULL. 233522851890Sopenharmony_ci- */ 233622851890Sopenharmony_ci-struct dma_buf *get_dma_buf_from_file(struct file *f); 233722851890Sopenharmony_ci-#endif /* CONFIG_DMABUF_PROCESS_INFO */ 233822851890Sopenharmony_ci #endif /* __DMA_BUF_H__ */ 233922851890Sopenharmony_cidiff --git a/include/linux/dma-heap.h b/include/linux/dma-heap.h 234022851890Sopenharmony_ciindex 83b8cfb2d..e8f0e92c2 100644 234122851890Sopenharmony_ci--- a/include/linux/dma-heap.h 234222851890Sopenharmony_ci+++ b/include/linux/dma-heap.h 234322851890Sopenharmony_ci@@ -16,15 +16,17 @@ struct dma_heap; 234422851890Sopenharmony_ci 234522851890Sopenharmony_ci /** 234622851890Sopenharmony_ci * struct dma_heap_ops - ops to operate on a given heap 234722851890Sopenharmony_ci- * @allocate: allocate dmabuf and return fd 234822851890Sopenharmony_ci+ * @allocate: allocate dmabuf and return struct dma_buf ptr 234922851890Sopenharmony_ci+ * @get_pool_size: if heap maintains memory pools, get pool size in bytes 235022851890Sopenharmony_ci * 235122851890Sopenharmony_ci- * allocate returns dmabuf fd on success, -errno on error. 235222851890Sopenharmony_ci+ * allocate returns dmabuf on success, ERR_PTR(-errno) on error. 235322851890Sopenharmony_ci */ 235422851890Sopenharmony_ci struct dma_heap_ops { 235522851890Sopenharmony_ci- int (*allocate)(struct dma_heap *heap, 235622851890Sopenharmony_ci+ struct dma_buf *(*allocate)(struct dma_heap *heap, 235722851890Sopenharmony_ci unsigned long len, 235822851890Sopenharmony_ci unsigned long fd_flags, 235922851890Sopenharmony_ci unsigned long heap_flags); 236022851890Sopenharmony_ci+ long (*get_pool_size)(struct dma_heap *heap); 236122851890Sopenharmony_ci }; 236222851890Sopenharmony_ci 236322851890Sopenharmony_ci /** 236422851890Sopenharmony_ci@@ -50,6 +52,15 @@ struct dma_heap_export_info { 236522851890Sopenharmony_ci */ 236622851890Sopenharmony_ci void *dma_heap_get_drvdata(struct dma_heap *heap); 236722851890Sopenharmony_ci 236822851890Sopenharmony_ci+/** 236922851890Sopenharmony_ci+ * dma_heap_get_dev() - get device struct for the heap 237022851890Sopenharmony_ci+ * @heap: DMA-Heap to retrieve device struct from 237122851890Sopenharmony_ci+ * 237222851890Sopenharmony_ci+ * Returns: 237322851890Sopenharmony_ci+ * The device struct for the heap. 237422851890Sopenharmony_ci+ */ 237522851890Sopenharmony_ci+struct device *dma_heap_get_dev(struct dma_heap *heap); 237622851890Sopenharmony_ci+ 237722851890Sopenharmony_ci /** 237822851890Sopenharmony_ci * dma_heap_get_name() - get heap name 237922851890Sopenharmony_ci * @heap: DMA-Heap to retrieve private data for 238022851890Sopenharmony_ci@@ -65,4 +76,49 @@ const char *dma_heap_get_name(struct dma_heap *heap); 238122851890Sopenharmony_ci */ 238222851890Sopenharmony_ci struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info); 238322851890Sopenharmony_ci 238422851890Sopenharmony_ci+/** 238522851890Sopenharmony_ci+ * dma_heap_put - drops a reference to a dmabuf heaps, potentially freeing it 238622851890Sopenharmony_ci+ * @heap: heap pointer 238722851890Sopenharmony_ci+ */ 238822851890Sopenharmony_ci+void dma_heap_put(struct dma_heap *heap); 238922851890Sopenharmony_ci+ 239022851890Sopenharmony_ci+/** 239122851890Sopenharmony_ci+ * dma_heap_find - Returns the registered dma_heap with the specified name 239222851890Sopenharmony_ci+ * @name: Name of the heap to find 239322851890Sopenharmony_ci+ * 239422851890Sopenharmony_ci+ * NOTE: dma_heaps returned from this function MUST be released 239522851890Sopenharmony_ci+ * using dma_heap_put() when the user is done. 239622851890Sopenharmony_ci+ */ 239722851890Sopenharmony_ci+struct dma_heap *dma_heap_find(const char *name); 239822851890Sopenharmony_ci+ 239922851890Sopenharmony_ci+/** 240022851890Sopenharmony_ci+ * dma_heap_buffer_alloc - Allocate dma-buf from a dma_heap 240122851890Sopenharmony_ci+ * @heap: dma_heap to allocate from 240222851890Sopenharmony_ci+ * @len: size to allocate 240322851890Sopenharmony_ci+ * @fd_flags: flags to set on returned dma-buf fd 240422851890Sopenharmony_ci+ * @heap_flags: flags to pass to the dma heap 240522851890Sopenharmony_ci+ * 240622851890Sopenharmony_ci+ * This is for internal dma-buf allocations only. 240722851890Sopenharmony_ci+ */ 240822851890Sopenharmony_ci+struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, 240922851890Sopenharmony_ci+ unsigned int fd_flags, 241022851890Sopenharmony_ci+ unsigned int heap_flags); 241122851890Sopenharmony_ci+ 241222851890Sopenharmony_ci+/** dma_heap_buffer_free - Free dma_buf allocated by dma_heap_buffer_alloc 241322851890Sopenharmony_ci+ * @dma_buf: dma_buf to free 241422851890Sopenharmony_ci+ * 241522851890Sopenharmony_ci+ * This is really only a simple wrapper to dma_buf_put() 241622851890Sopenharmony_ci+ */ 241722851890Sopenharmony_ci+void dma_heap_buffer_free(struct dma_buf *); 241822851890Sopenharmony_ci+ 241922851890Sopenharmony_ci+/** 242022851890Sopenharmony_ci+ * dma_heap_bufferfd_alloc - Allocate dma-buf fd from a dma_heap 242122851890Sopenharmony_ci+ * @heap: dma_heap to allocate from 242222851890Sopenharmony_ci+ * @len: size to allocate 242322851890Sopenharmony_ci+ * @fd_flags: flags to set on returned dma-buf fd 242422851890Sopenharmony_ci+ * @heap_flags: flags to pass to the dma heap 242522851890Sopenharmony_ci+ */ 242622851890Sopenharmony_ci+int dma_heap_bufferfd_alloc(struct dma_heap *heap, size_t len, 242722851890Sopenharmony_ci+ unsigned int fd_flags, 242822851890Sopenharmony_ci+ unsigned int heap_flags); 242922851890Sopenharmony_ci #endif /* _DMA_HEAPS_H */ 243022851890Sopenharmony_cidiff --git a/kernel/sched/core.c b/kernel/sched/core.c 243122851890Sopenharmony_ciindex 46a0df7d1..2909709f4 100644 243222851890Sopenharmony_ci--- a/kernel/sched/core.c 243322851890Sopenharmony_ci+++ b/kernel/sched/core.c 243422851890Sopenharmony_ci@@ -5636,16 +5636,19 @@ int sched_setscheduler(struct task_struct *p, int policy, 243522851890Sopenharmony_ci { 243622851890Sopenharmony_ci return _sched_setscheduler(p, policy, param, true); 243722851890Sopenharmony_ci } 243822851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(sched_setscheduler); 243922851890Sopenharmony_ci 244022851890Sopenharmony_ci int sched_setattr(struct task_struct *p, const struct sched_attr *attr) 244122851890Sopenharmony_ci { 244222851890Sopenharmony_ci return __sched_setscheduler(p, attr, true, true); 244322851890Sopenharmony_ci } 244422851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(sched_setattr); 244522851890Sopenharmony_ci 244622851890Sopenharmony_ci int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr) 244722851890Sopenharmony_ci { 244822851890Sopenharmony_ci return __sched_setscheduler(p, attr, false, true); 244922851890Sopenharmony_ci } 245022851890Sopenharmony_ci+EXPORT_SYMBOL_GPL(sched_setscheduler_nocheck); 245122851890Sopenharmony_ci 245222851890Sopenharmony_ci /** 245322851890Sopenharmony_ci * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace. 245422851890Sopenharmony_ci-- 245522851890Sopenharmony_ci2.25.1 245622851890Sopenharmony_ci 2457