Skip to content

Commit 4b5d62c

Browse files
rarbabmpe
authored andcommitted
powerpc/mm: add radix__remove_section_mapping()
Tear down and free the four-level page tables of physical mappings during memory hotremove. Borrow the basic structure of remove_pagetable() and friends from the identically-named x86 functions. Reduce the frequency of tlb flushes and page_table_lock spinlocks by only doing them in the outermost function. There was some question as to whether the locking is needed at all. Leave it for now, but we could consider dropping it. Memory must be offline to be removed, thus not in use. So there shouldn't be the sort of concurrent page walking activity here that might prompt us to use RCU. Signed-off-by: Reza Arbab <arbab@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent 6cc2734 commit 4b5d62c

File tree

3 files changed

+135
-1
lines changed

3 files changed

+135
-1
lines changed

arch/powerpc/include/asm/book3s/64/radix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ static inline unsigned long radix__get_tree_size(void)
294294

295295
#ifdef CONFIG_MEMORY_HOTPLUG
296296
int radix__create_section_mapping(unsigned long start, unsigned long end);
297+
int radix__remove_section_mapping(unsigned long start, unsigned long end);
297298
#endif /* CONFIG_MEMORY_HOTPLUG */
298299
#endif /* __ASSEMBLY__ */
299300
#endif

arch/powerpc/mm/pgtable-book3s64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ int create_section_mapping(unsigned long start, unsigned long end)
139139
int remove_section_mapping(unsigned long start, unsigned long end)
140140
{
141141
if (radix_enabled())
142-
return -ENODEV;
142+
return radix__remove_section_mapping(start, end);
143143

144144
return hash__remove_section_mapping(start, end);
145145
}

arch/powerpc/mm/pgtable-radix.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,143 @@ void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
482482
}
483483

484484
#ifdef CONFIG_MEMORY_HOTPLUG
485+
static void free_pte_table(pte_t *pte_start, pmd_t *pmd)
486+
{
487+
pte_t *pte;
488+
int i;
489+
490+
for (i = 0; i < PTRS_PER_PTE; i++) {
491+
pte = pte_start + i;
492+
if (!pte_none(*pte))
493+
return;
494+
}
495+
496+
pte_free_kernel(&init_mm, pte_start);
497+
pmd_clear(pmd);
498+
}
499+
500+
static void free_pmd_table(pmd_t *pmd_start, pud_t *pud)
501+
{
502+
pmd_t *pmd;
503+
int i;
504+
505+
for (i = 0; i < PTRS_PER_PMD; i++) {
506+
pmd = pmd_start + i;
507+
if (!pmd_none(*pmd))
508+
return;
509+
}
510+
511+
pmd_free(&init_mm, pmd_start);
512+
pud_clear(pud);
513+
}
514+
515+
static void remove_pte_table(pte_t *pte_start, unsigned long addr,
516+
unsigned long end)
517+
{
518+
unsigned long next;
519+
pte_t *pte;
520+
521+
pte = pte_start + pte_index(addr);
522+
for (; addr < end; addr = next, pte++) {
523+
next = (addr + PAGE_SIZE) & PAGE_MASK;
524+
if (next > end)
525+
next = end;
526+
527+
if (!pte_present(*pte))
528+
continue;
529+
530+
pte_clear(&init_mm, addr, pte);
531+
}
532+
}
533+
534+
static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,
535+
unsigned long end)
536+
{
537+
unsigned long next;
538+
pte_t *pte_base;
539+
pmd_t *pmd;
540+
541+
pmd = pmd_start + pmd_index(addr);
542+
for (; addr < end; addr = next, pmd++) {
543+
next = pmd_addr_end(addr, end);
544+
545+
if (!pmd_present(*pmd))
546+
continue;
547+
548+
if (pmd_huge(*pmd)) {
549+
pte_clear(&init_mm, addr, (pte_t *)pmd);
550+
continue;
551+
}
552+
553+
pte_base = (pte_t *)pmd_page_vaddr(*pmd);
554+
remove_pte_table(pte_base, addr, next);
555+
free_pte_table(pte_base, pmd);
556+
}
557+
}
558+
559+
static void remove_pud_table(pud_t *pud_start, unsigned long addr,
560+
unsigned long end)
561+
{
562+
unsigned long next;
563+
pmd_t *pmd_base;
564+
pud_t *pud;
565+
566+
pud = pud_start + pud_index(addr);
567+
for (; addr < end; addr = next, pud++) {
568+
next = pud_addr_end(addr, end);
569+
570+
if (!pud_present(*pud))
571+
continue;
572+
573+
if (pud_huge(*pud)) {
574+
pte_clear(&init_mm, addr, (pte_t *)pud);
575+
continue;
576+
}
577+
578+
pmd_base = (pmd_t *)pud_page_vaddr(*pud);
579+
remove_pmd_table(pmd_base, addr, next);
580+
free_pmd_table(pmd_base, pud);
581+
}
582+
}
583+
584+
static void remove_pagetable(unsigned long start, unsigned long end)
585+
{
586+
unsigned long addr, next;
587+
pud_t *pud_base;
588+
pgd_t *pgd;
589+
590+
spin_lock(&init_mm.page_table_lock);
591+
592+
for (addr = start; addr < end; addr = next) {
593+
next = pgd_addr_end(addr, end);
594+
595+
pgd = pgd_offset_k(addr);
596+
if (!pgd_present(*pgd))
597+
continue;
598+
599+
if (pgd_huge(*pgd)) {
600+
pte_clear(&init_mm, addr, (pte_t *)pgd);
601+
continue;
602+
}
603+
604+
pud_base = (pud_t *)pgd_page_vaddr(*pgd);
605+
remove_pud_table(pud_base, addr, next);
606+
}
607+
608+
spin_unlock(&init_mm.page_table_lock);
609+
radix__flush_tlb_kernel_range(start, end);
610+
}
611+
485612
int __ref radix__create_section_mapping(unsigned long start, unsigned long end)
486613
{
487614
return create_physical_mapping(start, end);
488615
}
616+
617+
int radix__remove_section_mapping(unsigned long start, unsigned long end)
618+
{
619+
remove_pagetable(start, end);
620+
return 0;
621+
}
489622
#endif /* CONFIG_MEMORY_HOTPLUG */
490623

491624
#ifdef CONFIG_SPARSEMEM_VMEMMAP

0 commit comments

Comments
 (0)