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