[RFC PATCH 2/2] mm/pmem: Add memblock based e820 platform driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch steal system RAM and use that to emulate pmem device using the
e820 platform driver.

This adds a new kernel command line 'pmemmap' which takes the format <size[KMG]>
to allocate memory early in the boot. This memory is later registered as
persistent memory range.

Based on original patch from Oliver OHalloran <oliveroh@xxxxxxxxxxx>

Not-Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@xxxxxxxxxxxxx>
---
 drivers/nvdimm/Kconfig        |  13 ++++
 drivers/nvdimm/Makefile       |   1 +
 drivers/nvdimm/memblockpmem.c | 115 ++++++++++++++++++++++++++++++++++
 3 files changed, 129 insertions(+)
 create mode 100644 drivers/nvdimm/memblockpmem.c

diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig
index 50d2a33de441..cbbbcbd4506b 100644
--- a/drivers/nvdimm/Kconfig
+++ b/drivers/nvdimm/Kconfig
@@ -115,4 +115,17 @@ config OF_PMEM
 config PMEM_PLATFORM_DEVICE
        bool
 
+config MEMBLOCK_PMEM
+	bool "pmemmap= parameter support"
+	default y
+	depends on HAVE_MEMBLOCK
+	select PMEM_PLATFORM_DEVICE
+	help
+	  Add support for the pmemmap= kernel command line parameter. This is similar
+	  to the memmap= parameter available on ACPI platforms, but it uses generic
+	  kernel facilities (the memblock allocator) to reserve memory rather than adding
+	  to the e820 table.
+
+	  Select Y if unsure.
+
 endif
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index 94f7f29146ce..0215ce0182e9 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o
 obj-$(CONFIG_ND_BLK) += nd_blk.o
 obj-$(CONFIG_PMEM_PLATFORM_DEVICE) += nd_e820.o
 obj-$(CONFIG_OF_PMEM) += of_pmem.o
+obj-$(CONFIG_MEMBLOCK_PMEM) += memblockpmem.o
 
 nd_pmem-y := pmem.o
 
diff --git a/drivers/nvdimm/memblockpmem.c b/drivers/nvdimm/memblockpmem.c
new file mode 100644
index 000000000000..d39772b75fcd
--- /dev/null
+++ b/drivers/nvdimm/memblockpmem.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 IBM Corporation
+ */
+
+#define pr_fmt(fmt) "memblock pmem: " fmt
+
+#include <linux/libnvdimm.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
+#include <linux/mmzone.h>
+#include <linux/cpu.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+/*
+ * Align pmem reservations to the section size so we don't have issues with
+ * memory hotplug
+ */
+#ifdef CONFIG_SPARSEMEM
+#define BOOTPMEM_ALIGN (1UL << SECTION_SIZE_BITS)
+#else
+#define BOOTPMEM_ALIGN PFN_DEFAULT_ALIGNMENT
+#endif
+
+static __initdata u64 pmem_size;
+static __initdata phys_addr_t pmem_stolen_memory;
+
+static void alloc_pmem_from_memblock(void)
+{
+
+	pmem_stolen_memory = memblock_alloc_base(pmem_size,
+						 BOOTPMEM_ALIGN,
+						 MEMBLOCK_ALLOC_ACCESSIBLE);
+	if (!pmem_stolen_memory) {
+		pr_err("Failed to allocate memory for PMEM from memblock\n");
+		return;
+	}
+
+	/*
+	 * Remove from the memblock reserved range
+	 */
+	memblock_free(pmem_stolen_memory, pmem_size);
+
+	/*
+	 * Remove from the memblock memory range.
+	 */
+	memblock_remove(pmem_stolen_memory, pmem_size);
+	pr_info("Allocated %ld memory at 0x%lx\n", (unsigned long)pmem_size,
+		(unsigned long)pmem_stolen_memory);
+	return;
+}
+
+/*
+ * pmemmap=ss[KMG]
+ *
+ * This is similar to the memremap=offset[KMG]!size[KMG] paramater
+ * for adding a legacy pmem range to the e820 map on x86, but it's
+ * platform agnostic.
+ *
+ * e.g. pmemmap=16G allocates 16G pmem region
+ */
+static int __init parse_pmemmap(char *p)
+{
+	char *old_p = p;
+
+	if (!p)
+		return -EINVAL;
+
+	pmem_size = memparse(p, &p);
+	if (p == old_p)
+		return -EINVAL;
+
+	alloc_pmem_from_memblock();
+	return 0;
+}
+early_param("pmemmap", parse_pmemmap);
+
+static __init int register_e820_pmem(void)
+{
+	struct resource *res, *conflict;
+        struct platform_device *pdev;
+
+	if (!pmem_stolen_memory)
+		return 0;
+
+	res = kzalloc(sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return -1;
+
+	memset(res, 0, sizeof(*res));
+	res->start = pmem_stolen_memory;
+	res->end = pmem_stolen_memory + pmem_size - 1;
+	res->name = "Persistent Memory (legacy)";
+	res->desc = IORES_DESC_PERSISTENT_MEMORY_LEGACY;
+	res->flags = IORESOURCE_MEM;
+
+	conflict = insert_resource_conflict(&iomem_resource, res);
+	if (conflict) {
+		pr_err("%pR conflicts, try insert below %pR\n", res, conflict);
+		kfree(res);
+		return -1;
+	}
+	/*
+	 * See drivers/nvdimm/e820.c for the implementation, this is
+	 * simply here to trigger the module to load on demand.
+	 */
+	pdev = platform_device_alloc("e820_pmem", -1);
+
+	return platform_device_add(pdev);
+}
+device_initcall(register_e820_pmem);
-- 
2.17.1




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux