diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 5a0a68b35bb11cb3ca5b984b232f16a1eec70e3d..4b38e33741e4db472bd92034963db73985be2382 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2831,10 +2831,13 @@ will be eaten. memmap=nn[KMG]!ss[KMG] - [KNL,X86] Mark specific memory as protected. + [KNL,X86,ARM64] Mark specific memory as protected. Region of memory to be used, from ss to ss+nn. - The memory region may be marked as e820 type 12 (0xc) + [X86] The memory region may be marked as e820 type 12 (0xc) and is NVDIMM or ADR memory. + [ARM64] The maximum memory regions supported is 8. + Example: + memmap=100K!0x1a0000000 memmap=%-+ [KNL,ACPI] Convert memory within the specified region diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 2cab963563d993d27864fad6724d4b0fdf87663e..e0c2f9a1a256de0e1af5ffef8f2a1b0ab312de88 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1325,6 +1325,24 @@ config RODATA_FULL_DEFAULT_ENABLED This requires the linear region to be mapped down to pages, which may adversely affect performance in some cases. +config ARM64_PMEM_RESERVE + bool + +config ARM64_PMEM_LEGACY + tristate "Support Persistent Memory (legacy) register via protected memory" + depends on BLK_DEV + select ARM64_PMEM_RESERVE + select PMEM_LEGACY + select PMEM_LEGACY_DEVICE + select LIBNVDIMM + help + Protected memory ranges for persistent memory are described by the + 'memmap=nn[KMG]!ss[KMG]' kernel parameter". + The kernel will offer those memory regions to the 'pmem' driver so + they can be used for persistent storage. + + Say Y if unsure. + config ARM64_SW_TTBR0_PAN bool "Emulate Privileged Access Never using TTBR0_EL1 switching" help diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 58d69e2e7538a2074c11a29f42b5fa358913b318..5e0713f5120e6899f4d0b7f5915bbb6e17e69b8f 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -52,6 +52,8 @@ #include #include +#include "../mm/pmem_reserve.h" + static int num_standard_resources; static struct resource *standard_resources; @@ -297,6 +299,8 @@ static void __init request_standard_resources(void) request_pin_mem_res(res); } + + request_pmem_res_resource(); } static int __init reserve_memblock_reserved_regions(void) diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile index 5ead3c3de3b6115deab05a1255d5bf3644871308..42e107d6da4f78b7cfe01077af60d148f4e38af7 100644 --- a/arch/arm64/mm/Makefile +++ b/arch/arm64/mm/Makefile @@ -13,3 +13,5 @@ KASAN_SANITIZE_physaddr.o += n obj-$(CONFIG_KASAN) += kasan_init.o KASAN_SANITIZE_kasan_init.o := n + +obj-$(CONFIG_ARM64_PMEM_RESERVE) += pmem_reserve.o diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 1364d52cbaa8c48c2d6087cbbaf0d5478de143ff..5ab9dd7d55d94977d8eff11e0072e8c0e9a5d270 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -45,6 +45,8 @@ #include #include +#include "pmem_reserve.h" + /* * We need to be able to catch inadvertent references to memstart_addr * that occur (potentially in generic code) before arm64_memblock_init() @@ -394,6 +396,9 @@ static int __init parse_memmap_one(char *p) start_at = memparse(p + 1, &p); memblock_reserve(start_at, mem_size); memblock_mark_memmap(start_at, mem_size); + } else if (*p == '!') { + start_at = memparse(p + 1, &p); + setup_reserve_pmem(start_at, mem_size); } else pr_info("Unrecognized memmap option, please check the parameter.\n"); @@ -590,6 +595,8 @@ void __init bootmem_init(void) reserve_quick_kexec(); #endif + reserve_pmem(); + reserve_pin_memory_res(); memblock_dump_all(); diff --git a/arch/arm64/mm/pmem_reserve.c b/arch/arm64/mm/pmem_reserve.c new file mode 100644 index 0000000000000000000000000000000000000000..70fec28409ad29654f0513335fdf41f2da85d344 --- /dev/null +++ b/arch/arm64/mm/pmem_reserve.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) "pmem_reserve: " fmt + +#include +#include +#include + +#define MAX_REGIONS 8 +static int pmem_res_cnt; +struct resource pmem_res[MAX_REGIONS]; + +void __init setup_reserve_pmem(u64 start, u64 size) +{ + if (pmem_res_cnt >= MAX_REGIONS) { + pr_err("protected memory regions above upper limit %d\n", MAX_REGIONS); + return; + } + + pmem_res[pmem_res_cnt].start = start; + pmem_res[pmem_res_cnt].end = start + size - 1; + pmem_res_cnt++; +} + +void __init request_pmem_res_resource(void) +{ + struct resource *res; + int i; + + for (i = 0; i < pmem_res_cnt; i++) { + res = &pmem_res[i]; + res->name = "Persistent Memory (legacy)"; + res->flags = IORESOURCE_MEM; + res->desc = IORES_DESC_PERSISTENT_MEMORY_LEGACY; + if (res->start && res->end) + request_resource(&iomem_resource, res); + } +} + +void __init reserve_pmem(void) +{ + struct resource *res; + phys_addr_t size; + int i; + + for (i = 0; i < pmem_res_cnt; i++) { + res = &pmem_res[i]; + size = res->end - res->start; + if (!memblock_is_region_memory(res->start, size)) { + pr_warn("region[%pa-%pa] is not in memory\n", + &res->start, &res->end); + res->start = res->end = 0; + continue; + } + + if (memblock_is_region_reserved(res->start, size)) { + pr_warn("region[%pa-%pa] overlaps reserved memory\n", + &res->start, &res->end); + res->start = res->end = 0; + continue; + } + + memblock_remove(res->start, size); + pr_info("region %d: [%pa-%pa] (%lluMB)\n", i, &res->start, &res->end, size >> 20); + } +} diff --git a/arch/arm64/mm/pmem_reserve.h b/arch/arm64/mm/pmem_reserve.h new file mode 100644 index 0000000000000000000000000000000000000000..d143198c9696e6b22d10ad65af9c0cf87a5411ae --- /dev/null +++ b/arch/arm64/mm/pmem_reserve.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include + +#ifdef CONFIG_ARM64_PMEM_RESERVE +void __init setup_reserve_pmem(u64 start, u64 size); +void __init reserve_pmem(void); +void __init request_pmem_res_resource(void); +#else +static inline void __init setup_reserve_pmem(u64 start, u64 size) {} +static inline void __init reserve_pmem(void) {} +static inline void __init request_pmem_res_resource(void) {} +#endif