Radix vmemmap mapping can map things correctly at the PMD level or PTE level based on different device boundary checks. We also use altmap.reserve feature to align things correctly at pageblock granularity. We can end up loosing some pages in memory with this. For ex: with 256MB memory block size, we require 4 pages to map vmemmap pages, In order to align things correctly we end up adding a reserve of 28 pages. ie, for every 4096 pages 28 pages get reserved. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@xxxxxxxxxxxxx> --- arch/powerpc/Kconfig | 1 + arch/powerpc/mm/book3s64/radix_pgtable.c | 28 +++++++++++++++++++ .../platforms/pseries/hotplug-memory.c | 4 ++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6bd9ca6f2448..1b0954854a12 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -158,6 +158,7 @@ config PPC select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_KEEP_MEMBLOCK + select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE if PPC_RADIX_MMU select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index afbae37612ad..e0e292b87b4b 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -1692,3 +1692,31 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) return 1; } + +/* + * mm/memory_hotplug.c:mhp_supports_memmap_on_memory goes into details + * some of the restrictions. We don't check for PMD_SIZE because our + * vmemmap allocation code can fallback correctly. The pageblock + * alignment requirement is met using altmap->reserve blocks. + */ +bool mhp_supports_memmap_on_memory(unsigned long size) +{ + if (!radix_enabled()) + return false; + /* + * The pageblock alignment requirement is met by using + * reserve blocks in altmap. + */ + return size == memory_block_size_bytes(); +} + +unsigned long memory_block_align_base(struct resource *res) +{ + unsigned long base_pfn = PHYS_PFN(res->start); + unsigned long align, size = resource_size(res); + unsigned long nr_vmemmap_pages = size / PAGE_SIZE; + unsigned long vmemmap_size = (nr_vmemmap_pages * sizeof(struct page))/PAGE_SIZE; + + align = pageblock_align(base_pfn + vmemmap_size) - (base_pfn + vmemmap_size); + return align; +} diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 9c62c2c3b3d0..326db26d773e 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -617,6 +617,7 @@ static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index) static int dlpar_add_lmb(struct drmem_lmb *lmb) { + mhp_t mhp_flags = MHP_NONE; unsigned long block_sz; int nid, rc; @@ -637,7 +638,8 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb) nid = first_online_node; /* Add the memory */ - rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_NONE); + mhp_flags |= get_memmap_on_memory_flags(); + rc = __add_memory(nid, lmb->base_addr, block_sz, mhp_flags); if (rc) { invalidate_lmb_associativity_index(lmb); return rc; -- 2.41.0