[PATCH] mm: free reserved area's memmap if possiable

From: zhouxianrong
Date: Mon Feb 13 2017 - 07:08:15 EST


From: zhouxianrong <zhouxianrong@xxxxxxxxxx>

just like freeing no-map area's memmap we could free reserved
area's memmap as well only when user of reserved area indicate
that we can do this in dts or drivers. that is, user of reserved
area know how to use the reserved area who could not memblock_free
or free_reserved_xxx the reserved area and regard the area as raw
pfn usage. the patch supply a way to users who want to utilize the
memmap memory corresponding to raw pfn reserved areas as many as
possible.

Signed-off-by: zhouxianrong <zhouxianrong@xxxxxxxxxx>
---
arch/arm64/mm/init.c | 14 +++++++++++++-
drivers/of/fdt.c | 31 +++++++++++++++++++++++--------
drivers/of/of_reserved_mem.c | 21 ++++++++++++++-------
include/linux/memblock.h | 3 +++
include/linux/of_fdt.h | 2 +-
mm/memblock.c | 24 ++++++++++++++++++++++++
6 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 380ebe7..7e62ef8 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -358,7 +358,7 @@ static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn)
*/
static void __init free_unused_memmap(void)
{
- unsigned long start, prev_end = 0;
+ unsigned long start, end, prev_end = 0;
struct memblock_region *reg;

for_each_memblock(memory, reg) {
@@ -391,6 +391,18 @@ static void __init free_unused_memmap(void)
if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION));
#endif
+
+ for_each_memblock(reserved, reg) {
+ if (!(reg->flags & MEMBLOCK_RAW_PFN))
+ continue;
+
+ start = memblock_region_memory_base_pfn(reg);
+ end = round_down(memblock_region_memory_end_pfn(reg),
+ MAX_ORDER_NR_PAGES);
+
+ if (start < end)
+ free_memmap(start, end);
+ }
}
#endif /* !CONFIG_SPARSEMEM_VMEMMAP */

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c9b5cac..39e7474 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -582,7 +582,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
phys_addr_t base, size;
int len;
const __be32 *prop;
- int nomap, first = 1;
+ int nomap, raw_pfn, first = 1;

prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
@@ -595,13 +595,15 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
}

nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+ raw_pfn = of_get_flat_dt_prop(node, "raw-pfn", NULL) != NULL;

while (len >= t_len) {
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
size = dt_mem_next_cell(dt_root_size_cells, &prop);

if (size &&
- early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
+ early_init_dt_reserve_memory_arch(base, size, nomap,
+ raw_pfn) == 0)
pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
else
@@ -699,7 +701,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
if (!size)
break;
- early_init_dt_reserve_memory_arch(base, size, 0);
+ early_init_dt_reserve_memory_arch(base, size, 0, 0);
}

of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
@@ -717,6 +719,7 @@ void __init early_init_fdt_reserve_self(void)
/* Reserve the dtb region */
early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
fdt_totalsize(initial_boot_params),
+ 0,
0);
}

@@ -1161,11 +1164,21 @@ int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size)
}

int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
- phys_addr_t size, bool nomap)
+ phys_addr_t size, bool nomap,
+ bool raw_pfn)
{
+ int err;
+
if (nomap)
return memblock_remove(base, size);
- return memblock_reserve(base, size);
+
+ err = memblock_reserve(base, size);
+ if (err == 0) {
+ if (raw_pfn)
+ memblock_mark_raw_pfn(base, size);
+ }
+
+ return err;
}

/*
@@ -1188,10 +1201,12 @@ int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size)
}

int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
- phys_addr_t size, bool nomap)
+ phys_addr_t size, bool nomap,
+ bool raw_pfn)
{
- pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n",
- &base, &size, nomap ? " (nomap)" : "");
+ pr_err("Reserved memory not supported, ignoring range %pa - %pa%s - %pa%s\n",
+ &base, &size, nomap ? " (nomap)" : "",
+ raw_pfn ? " (raw-pfn)" : "");
return -ENOSYS;
}

diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 366d8c3..d7d9255 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -33,7 +33,7 @@
#include <linux/memblock.h>
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
+ bool raw_pfn, phys_addr_t *res_base)
{
phys_addr_t base;
/*
@@ -56,15 +56,19 @@ int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
*res_base = base;
if (nomap)
return memblock_remove(base, size);
+
+ if (raw_pfn)
+ memblock_mark_raw_pfn(base, size);
+
return 0;
}
#else
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
+ bool raw_pfn, phys_addr_t *res_base)
{
- pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
- size, nomap ? " (nomap)" : "");
+ pr_err("Reserved memory not supported, ignoring region 0x%llx%s 0x%llx%s\n",
+ size, nomap ? " (nomap)" : "", raw_pfn ? " (raw-pfn)" : "");
return -ENOSYS;
}
#endif
@@ -103,7 +107,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
phys_addr_t base = 0, align = 0, size;
int len;
const __be32 *prop;
- int nomap;
+ int nomap, raw_pfn;
int ret;

prop = of_get_flat_dt_prop(node, "size", &len);
@@ -117,6 +121,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
size = dt_mem_next_cell(dt_root_size_cells, &prop);

nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+ raw_pfn = of_get_flat_dt_prop(node, "raw-pfn", NULL) != NULL;

prop = of_get_flat_dt_prop(node, "alignment", &len);
if (prop) {
@@ -156,7 +161,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
&prop);

ret = early_init_dt_alloc_reserved_memory_arch(size,
- align, start, end, nomap, &base);
+ align, start, end, nomap,
+ raw_pfn, &base);
if (ret == 0) {
pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base,
@@ -168,7 +174,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,

} else {
ret = early_init_dt_alloc_reserved_memory_arch(size, align,
- 0, 0, nomap, &base);
+ 0, 0, nomap,
+ raw_pfn, &base);
if (ret == 0)
pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 5b759c9..7266be1 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -26,6 +26,7 @@ enum {
MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
MEMBLOCK_MIRROR = 0x2, /* mirrored region */
MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */
+ MEMBLOCK_RAW_PFN = 0x8, /* raw pfn region's memmap never used */
};

struct memblock_region {
@@ -92,6 +93,8 @@ bool memblock_overlaps_region(struct memblock_type *type,
int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
+int memblock_mark_raw_pfn(phys_addr_t base, phys_addr_t size);
+int memblock_clear_raw_pfn(phys_addr_t base, phys_addr_t size);
ulong choose_memblock_flags(void);

/* Low level functions */
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 271b3fd..29284d7 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -73,7 +73,7 @@ extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
extern void early_init_dt_add_memory_arch(u64 base, u64 size);
extern int early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size);
extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
- bool no_map);
+ bool no_map, bool raw_pfn);
extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
extern u64 dt_mem_next_cell(int s, const __be32 **cellp);

diff --git a/mm/memblock.c b/mm/memblock.c
index 7608bc3..c103b94 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -814,6 +814,30 @@ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
}

/**
+ * memblock_mark_raw_pfn - Mark raw pfn memory with flag MEMBLOCK_RAW_PFN.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Return 0 on succees, -errno on failure.
+ */
+int __init_memblock memblock_mark_raw_pfn(phys_addr_t base, phys_addr_t size)
+{
+ return memblock_setclr_flag(base, size, 1, MEMBLOCK_RAW_PFN);
+}
+
+/**
+ * memblock_clear_raw_pfn - Clear flag MEMBLOCK_RAW_PFN for a specified region.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Return 0 on succees, -errno on failure.
+ */
+int __init_memblock memblock_clear_raw_pfn(phys_addr_t base, phys_addr_t size)
+{
+ return memblock_setclr_flag(base, size, 0, MEMBLOCK_RAW_PFN);
+}
+
+/**
* __next_reserved_mem_region - next function for for_each_reserved_region()
* @idx: pointer to u64 loop variable
* @out_start: ptr to phys_addr_t for start address of the region, can be %NULL
--
1.7.9.5