diff mbox series

[4/4] sample/reserved_mem: Introduce a sample of struct page and dio support to no-map rmem

Message ID 20220711122459.13773-5-me@linux.beauty
State New
Headers show
Series [1/4] of: add struct page support to rmem | expand

Commit Message

Li Chen July 11, 2022, 12:24 p.m. UTC
From: Li Chen <lchen@ambarella.com>

This sample driver shows how to build struct pages support to no-map rmem.

Signed-off-by: Li Chen <lchen@ambarella.com>
Change-Id: Ie78494fa86fda40ceb73eab3b8ba505d0ad851a1
---
 samples/Kconfig                 |   7 ++
 samples/Makefile                |   1 +
 samples/reserved_mem/Makefile   |   2 +
 samples/reserved_mem/rmem_dio.c | 116 ++++++++++++++++++++++++++++++++
 4 files changed, 126 insertions(+)
 create mode 100755 samples/reserved_mem/Makefile
 create mode 100755 samples/reserved_mem/rmem_dio.c

Comments

Arnd Bergmann Aug. 5, 2022, 2:09 p.m. UTC | #1
On Thu, Aug 4, 2022 at 12:07 PM Li Chen <me@linux.beauty> wrote:

> Apart from our cases, I heard there are some other cases where cma_alloc
>  failed even non-cma system memory has enough memory because pages in
> CMA memory are pinned and cannot move out of CMA. There are some fixes like
> 1. move these memory out of CMA before pinned
> 2. only allow non-long-time pinned memory allocation from CMA.
>
> But these two solutions are not merged into the mainline yet.

Right, I think this has come up before, not sure why it wasn't implemented.
My feeling is that 2. cannot work because you don't know if memory will be
pinned in the future at the time of allocation, but 1. should be doable.

A possible alternative here would be to avoid the pinning. In most workloads
it should not be possible to pin a large number of pages, but I assume there
is a good reason to do so here.

        Arnd
David Hildenbrand Aug. 5, 2022, 3:28 p.m. UTC | #2
On 05.08.22 16:09, Arnd Bergmann wrote:
> On Thu, Aug 4, 2022 at 12:07 PM Li Chen <me@linux.beauty> wrote:
> 
>> Apart from our cases, I heard there are some other cases where cma_alloc
>>  failed even non-cma system memory has enough memory because pages in
>> CMA memory are pinned and cannot move out of CMA. There are some fixes like
>> 1. move these memory out of CMA before pinned
>> 2. only allow non-long-time pinned memory allocation from CMA.
>>
>> But these two solutions are not merged into the mainline yet.
> 
> Right, I think this has come up before, not sure why it wasn't implemented.
> My feeling is that 2. cannot work because you don't know if memory will be
> pinned in the future at the time of allocation, but 1. should be doable.

We disallow longterm pinning of CMA memory already and migrate it out of
the CMA region. If migration fails, we reject pinning.

See

9a4e9f3b2d73 ("mm: update get_user_pages_longterm to migrate pages
allocated from CMA region")

and recent

1c563432588d ("mm: fix is_pinnable_page against a cma page")


It's worth nothing that is_pinnable_page() will be renamed to
is_longterm_pinnable_page() soon to express what it actually means.

Note that some FOLL_GET users (vmsplice, O_DIRECT) still have to be
converted to FOLL_PIN, and especially also set FOLL_LONGTERM (vmsplice).
diff mbox series

Patch

diff --git a/samples/Kconfig b/samples/Kconfig
index b0503ef058d3..d83ba02ec215 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -6,6 +6,13 @@  menuconfig SAMPLES
 
 if SAMPLES
 
+config RESERVED_MEM_DIO
+	tristate "Build example reserved mem dio support"
+	depends on OF_RESERVED_MEM_DIO_SUPPORT
+	help
+	   Build kernel space sample module to show how to add struct
+		 page and dio support to reserved memory.
+
 config SAMPLE_AUXDISPLAY
 	bool "auxdisplay sample"
 	depends on CC_CAN_LINK
diff --git a/samples/Makefile b/samples/Makefile
index 087e0988ccc5..106a386869eb 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -1,6 +1,7 @@ 
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for Linux samples code
 
+obj-$(CONFIG_RESERVED_MEM_DIO)		+= reserved_mem/
 subdir-$(CONFIG_SAMPLE_AUXDISPLAY)	+= auxdisplay
 subdir-$(CONFIG_SAMPLE_ANDROID_BINDERFS) += binderfs
 obj-$(CONFIG_SAMPLE_CONFIGFS)		+= configfs/
diff --git a/samples/reserved_mem/Makefile b/samples/reserved_mem/Makefile
new file mode 100755
index 000000000000..a4f5c8bc08dc
--- /dev/null
+++ b/samples/reserved_mem/Makefile
@@ -0,0 +1,2 @@ 
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_RESERVED_MEM_DIO) += rmem_dio.o
diff --git a/samples/reserved_mem/rmem_dio.c b/samples/reserved_mem/rmem_dio.c
new file mode 100755
index 000000000000..ffb3395de63c
--- /dev/null
+++ b/samples/reserved_mem/rmem_dio.c
@@ -0,0 +1,116 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sample driver for reserved memory with struct page and dio support.
+ *
+ * wsps is abbr for with struct page support
+ *
+ * Copyright (C) 2022 Li Chen <lchen@ambarella.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/cdev.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+
+/*
+ * dts example
+ * rmem: rmem@1 {
+ *			compatible = "shared-dma-pool";
+ *			no-map;
+ *			size = <0x0 0x20000000>;
+ *		};
+ * perf {
+ *		compatible = "example,rmem";
+ *		memory-region = <&rmem>;
+ *	};
+ */
+
+static struct reserved_mem *rmem;
+
+static int rmem_wsps_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static int rmem_wsps_release(struct inode *inode,
+					  struct file *filp)
+{
+	return 0;
+}
+
+static int rmem_wsps_mmap(struct file *file,
+					     struct vm_area_struct *vma)
+{
+	return reserved_mem_dio_mmap(file, vma, rmem);
+}
+
+static const struct file_operations rmem_wsps_remap_ops = {
+	.owner = THIS_MODULE,
+	.open = rmem_wsps_open,
+	.release = rmem_wsps_release,
+	.mmap = rmem_wsps_mmap,
+};
+
+static struct miscdevice rmem_wsps_miscdev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "rmem_wsps",
+	.fops = &rmem_wsps_remap_ops,
+};
+
+static int rmem_wsps_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	void *vaddr;
+	int ret;
+
+	ret = misc_register(&rmem_wsps_miscdev);
+	if (ret) {
+		dev_err(dev, "%s: misc_register failed, %d\n", __func__, ret);
+		return -ENODEV;
+	}
+
+	rmem = get_reserved_mem_from_dev(dev);
+	if (!rmem) {
+		dev_err(dev, "%s: failed to find reserved\n", __func__);
+		return -ENODEV;
+	}
+
+	vaddr = reserved_mem_memremap_pages(dev, rmem);
+	if (IS_ERR_OR_NULL(vaddr))
+		return PTR_ERR(vaddr);
+
+	return 0;
+}
+
+static const struct of_device_id rmem_dio_match[] = {
+	{
+		.compatible = "example,rmem",
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, rmem_dio_match);
+
+static struct platform_driver rmem_wsps_driver = {
+	.probe = rmem_wsps_probe,
+	.driver = {
+		.name = "rmem_wsps",
+		.of_match_table = rmem_dio_match,
+	},
+};
+
+static int __init rmem_wsps_init(void)
+{
+	return platform_driver_register(&rmem_wsps_driver);
+}
+
+module_init(rmem_wsps_init);
+MODULE_LICENSE("GPL");