--- v5
+++ v10
@@ -1,430 +1,83 @@
-This is a generic kernel virtual memory mapper, not specific to ioremap.
+This allows unsupported levels to be constant folded away, and so
+p4d_free_pud_page can be removed because it's no longer linked to.
+Cc: linuxppc-dev@lists.ozlabs.org
+Acked-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
- include/linux/vmalloc.h | 2 +
- mm/ioremap.c | 192 ----------------------------------------
- mm/vmalloc.c | 191 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 193 insertions(+), 192 deletions(-)
+ arch/powerpc/include/asm/vmalloc.h | 19 ++++++++++++++++---
+ arch/powerpc/mm/book3s64/radix_pgtable.c | 21 ---------------------
+ 2 files changed, 16 insertions(+), 24 deletions(-)
-diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
-index 787d77ad7536..e3590e93bfff 100644
---- a/include/linux/vmalloc.h
-+++ b/include/linux/vmalloc.h
-@@ -181,6 +181,8 @@ extern struct vm_struct *remove_vm_area(const void *addr);
- extern struct vm_struct *find_vm_area(const void *addr);
+diff --git a/arch/powerpc/include/asm/vmalloc.h b/arch/powerpc/include/asm/vmalloc.h
+index 105abb73f075..3f0c153befb0 100644
+--- a/arch/powerpc/include/asm/vmalloc.h
++++ b/arch/powerpc/include/asm/vmalloc.h
+@@ -1,12 +1,25 @@
+ #ifndef _ASM_POWERPC_VMALLOC_H
+ #define _ASM_POWERPC_VMALLOC_H
- #ifdef CONFIG_MMU
-+extern int vmap_range(unsigned long addr, unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
-+ unsigned int max_page_shift);
- extern int map_kernel_range_noflush(unsigned long start, unsigned long size,
- pgprot_t prot, struct page **pages);
- int map_kernel_range(unsigned long start, unsigned long size, pgprot_t prot,
-diff --git a/mm/ioremap.c b/mm/ioremap.c
-index b0032dbadaf7..cdda0e022740 100644
---- a/mm/ioremap.c
-+++ b/mm/ioremap.c
-@@ -28,198 +28,6 @@ early_param("nohugeiomap", set_nohugeiomap);
- static const bool iomap_allow_huge = false;
- #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
++#include <asm/mmu.h>
+ #include <asm/page.h>
--static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, pgtbl_mod_mask *mask)
+ #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
+-bool arch_vmap_p4d_supported(pgprot_t prot);
+-bool arch_vmap_pud_supported(pgprot_t prot);
+-bool arch_vmap_pmd_supported(pgprot_t prot);
++static inline bool arch_vmap_p4d_supported(pgprot_t prot)
++{
++ return false;
++}
++
++static inline bool arch_vmap_pud_supported(pgprot_t prot)
++{
++ /* HPT does not cope with large pages in the vmalloc area */
++ return radix_enabled();
++}
++
++static inline bool arch_vmap_pmd_supported(pgprot_t prot)
++{
++ return radix_enabled();
++}
+ #endif
+
+ #endif /* _ASM_POWERPC_VMALLOC_H */
+diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
+index 743807fc210f..8da62afccee5 100644
+--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
++++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
+@@ -1082,22 +1082,6 @@ void radix__ptep_modify_prot_commit(struct vm_area_struct *vma,
+ set_pte_at(mm, addr, ptep, pte);
+ }
+
+-bool arch_vmap_pud_supported(pgprot_t prot)
-{
-- pte_t *pte;
-- u64 pfn;
+- /* HPT does not cope with large pages in the vmalloc area */
+- return radix_enabled();
+-}
-
-- pfn = phys_addr >> PAGE_SHIFT;
-- pte = pte_alloc_kernel_track(pmd, addr, mask);
-- if (!pte)
-- return -ENOMEM;
-- do {
-- BUG_ON(!pte_none(*pte));
-- set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
-- pfn++;
-- } while (pte++, addr += PAGE_SIZE, addr != end);
-- *mask |= PGTBL_PTE_MODIFIED;
+-bool arch_vmap_pmd_supported(pgprot_t prot)
+-{
+- return radix_enabled();
+-}
+-
+-int p4d_free_pud_page(p4d_t *p4d, unsigned long addr)
+-{
- return 0;
-}
-
--static int vmap_try_huge_pmd(pmd_t *pmd, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift)
+ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
+ {
+ pte_t *ptep = (pte_t *)pud;
+@@ -1181,8 +1165,3 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
+
+ return 1;
+ }
+-
+-bool arch_vmap_p4d_supported(pgprot_t prot)
-{
-- if (max_page_shift < PMD_SHIFT)
-- return 0;
--
-- if (!arch_vmap_pmd_supported(prot))
-- return 0;
--
-- if ((end - addr) != PMD_SIZE)
-- return 0;
--
-- if (!IS_ALIGNED(addr, PMD_SIZE))
-- return 0;
--
-- if (!IS_ALIGNED(phys_addr, PMD_SIZE))
-- return 0;
--
-- if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr))
-- return 0;
--
-- return pmd_set_huge(pmd, phys_addr, prot);
+- return false;
-}
--
--static int vmap_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift,
-- pgtbl_mod_mask *mask)
--{
-- pmd_t *pmd;
-- unsigned long next;
--
-- pmd = pmd_alloc_track(&init_mm, pud, addr, mask);
-- if (!pmd)
-- return -ENOMEM;
-- do {
-- next = pmd_addr_end(addr, end);
--
-- if (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot, max_page_shift)) {
-- *mask |= PGTBL_PMD_MODIFIED;
-- continue;
-- }
--
-- if (vmap_pte_range(pmd, addr, next, phys_addr, prot, mask))
-- return -ENOMEM;
-- } while (pmd++, phys_addr += (next - addr), addr = next, addr != end);
-- return 0;
--}
--
--static int vmap_try_huge_pud(pud_t *pud, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift)
--{
-- if (max_page_shift < PUD_SHIFT)
-- return 0;
--
-- if (!arch_vmap_pud_supported(prot))
-- return 0;
--
-- if ((end - addr) != PUD_SIZE)
-- return 0;
--
-- if (!IS_ALIGNED(addr, PUD_SIZE))
-- return 0;
--
-- if (!IS_ALIGNED(phys_addr, PUD_SIZE))
-- return 0;
--
-- if (pud_present(*pud) && !pud_free_pmd_page(pud, addr))
-- return 0;
--
-- return pud_set_huge(pud, phys_addr, prot);
--}
--
--static int vmap_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift,
-- pgtbl_mod_mask *mask)
--{
-- pud_t *pud;
-- unsigned long next;
--
-- pud = pud_alloc_track(&init_mm, p4d, addr, mask);
-- if (!pud)
-- return -ENOMEM;
-- do {
-- next = pud_addr_end(addr, end);
--
-- if (vmap_try_huge_pud(pud, addr, next, phys_addr, prot, max_page_shift)) {
-- *mask |= PGTBL_PUD_MODIFIED;
-- continue;
-- }
--
-- if (vmap_pmd_range(pud, addr, next, phys_addr, prot, max_page_shift, mask))
-- return -ENOMEM;
-- } while (pud++, phys_addr += (next - addr), addr = next, addr != end);
-- return 0;
--}
--
--static int vmap_try_huge_p4d(p4d_t *p4d, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift)
--{
-- if (max_page_shift < P4D_SHIFT)
-- return 0;
--
-- if (!arch_vmap_p4d_supported(prot))
-- return 0;
--
-- if ((end - addr) != P4D_SIZE)
-- return 0;
--
-- if (!IS_ALIGNED(addr, P4D_SIZE))
-- return 0;
--
-- if (!IS_ALIGNED(phys_addr, P4D_SIZE))
-- return 0;
--
-- if (p4d_present(*p4d) && !p4d_free_pud_page(p4d, addr))
-- return 0;
--
-- return p4d_set_huge(p4d, phys_addr, prot);
--}
--
--static int vmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end,
-- phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift,
-- pgtbl_mod_mask *mask)
--{
-- p4d_t *p4d;
-- unsigned long next;
--
-- p4d = p4d_alloc_track(&init_mm, pgd, addr, mask);
-- if (!p4d)
-- return -ENOMEM;
-- do {
-- next = p4d_addr_end(addr, end);
--
-- if (vmap_try_huge_p4d(p4d, addr, next, phys_addr, prot, max_page_shift)) {
-- *mask |= PGTBL_P4D_MODIFIED;
-- continue;
-- }
--
-- if (vmap_pud_range(p4d, addr, next, phys_addr, prot, max_page_shift, mask))
-- return -ENOMEM;
-- } while (p4d++, phys_addr += (next - addr), addr = next, addr != end);
-- return 0;
--}
--
--static int vmap_range(unsigned long addr, unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
-- unsigned int max_page_shift)
--{
-- pgd_t *pgd;
-- unsigned long start;
-- unsigned long next;
-- int err;
-- pgtbl_mod_mask mask = 0;
--
-- might_sleep();
-- BUG_ON(addr >= end);
--
-- start = addr;
-- pgd = pgd_offset_k(addr);
-- do {
-- next = pgd_addr_end(addr, end);
-- err = vmap_p4d_range(pgd, addr, next, phys_addr, prot, max_page_shift, &mask);
-- if (err)
-- break;
-- } while (pgd++, phys_addr += (next - addr), addr = next, addr != end);
--
-- flush_cache_vmap(start, end);
--
-- if (mask & ARCH_PAGE_TABLE_SYNC_MASK)
-- arch_sync_kernel_mappings(start, end);
--
-- return err;
--}
--
- int ioremap_page_range(unsigned long addr, unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
- {
- unsigned int max_page_shift = PAGE_SHIFT;
-diff --git a/mm/vmalloc.c b/mm/vmalloc.c
-index 3a1e45fd1626..129f10545bb1 100644
---- a/mm/vmalloc.c
-+++ b/mm/vmalloc.c
-@@ -71,6 +71,197 @@ static void free_work(struct work_struct *w)
- }
-
- /*** Page table manipulation functions ***/
-+static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, pgtbl_mod_mask *mask)
-+{
-+ pte_t *pte;
-+ u64 pfn;
-+
-+ pfn = phys_addr >> PAGE_SHIFT;
-+ pte = pte_alloc_kernel_track(pmd, addr, mask);
-+ if (!pte)
-+ return -ENOMEM;
-+ do {
-+ BUG_ON(!pte_none(*pte));
-+ set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
-+ pfn++;
-+ } while (pte++, addr += PAGE_SIZE, addr != end);
-+ *mask |= PGTBL_PTE_MODIFIED;
-+ return 0;
-+}
-+
-+static int vmap_try_huge_pmd(pmd_t *pmd, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift)
-+{
-+ if (max_page_shift < PMD_SHIFT)
-+ return 0;
-+
-+ if (!arch_vmap_pmd_supported(prot))
-+ return 0;
-+
-+ if ((end - addr) != PMD_SIZE)
-+ return 0;
-+
-+ if (!IS_ALIGNED(addr, PMD_SIZE))
-+ return 0;
-+
-+ if (!IS_ALIGNED(phys_addr, PMD_SIZE))
-+ return 0;
-+
-+ if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr))
-+ return 0;
-+
-+ return pmd_set_huge(pmd, phys_addr, prot);
-+}
-+
-+static int vmap_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift,
-+ pgtbl_mod_mask *mask)
-+{
-+ pmd_t *pmd;
-+ unsigned long next;
-+
-+ pmd = pmd_alloc_track(&init_mm, pud, addr, mask);
-+ if (!pmd)
-+ return -ENOMEM;
-+ do {
-+ next = pmd_addr_end(addr, end);
-+
-+ if (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot, max_page_shift)) {
-+ *mask |= PGTBL_PMD_MODIFIED;
-+ continue;
-+ }
-+
-+ if (vmap_pte_range(pmd, addr, next, phys_addr, prot, mask))
-+ return -ENOMEM;
-+ } while (pmd++, phys_addr += (next - addr), addr = next, addr != end);
-+ return 0;
-+}
-+
-+static int vmap_try_huge_pud(pud_t *pud, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift)
-+{
-+ if (max_page_shift < PUD_SHIFT)
-+ return 0;
-+
-+ if (!arch_vmap_pud_supported(prot))
-+ return 0;
-+
-+ if ((end - addr) != PUD_SIZE)
-+ return 0;
-+
-+ if (!IS_ALIGNED(addr, PUD_SIZE))
-+ return 0;
-+
-+ if (!IS_ALIGNED(phys_addr, PUD_SIZE))
-+ return 0;
-+
-+ if (pud_present(*pud) && !pud_free_pmd_page(pud, addr))
-+ return 0;
-+
-+ return pud_set_huge(pud, phys_addr, prot);
-+}
-+
-+static int vmap_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift,
-+ pgtbl_mod_mask *mask)
-+{
-+ pud_t *pud;
-+ unsigned long next;
-+
-+ pud = pud_alloc_track(&init_mm, p4d, addr, mask);
-+ if (!pud)
-+ return -ENOMEM;
-+ do {
-+ next = pud_addr_end(addr, end);
-+
-+ if (vmap_try_huge_pud(pud, addr, next, phys_addr, prot, max_page_shift)) {
-+ *mask |= PGTBL_PUD_MODIFIED;
-+ continue;
-+ }
-+
-+ if (vmap_pmd_range(pud, addr, next, phys_addr, prot, max_page_shift, mask))
-+ return -ENOMEM;
-+ } while (pud++, phys_addr += (next - addr), addr = next, addr != end);
-+ return 0;
-+}
-+
-+static int vmap_try_huge_p4d(p4d_t *p4d, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift)
-+{
-+ if (max_page_shift < P4D_SHIFT)
-+ return 0;
-+
-+ if (!arch_vmap_p4d_supported(prot))
-+ return 0;
-+
-+ if ((end - addr) != P4D_SIZE)
-+ return 0;
-+
-+ if (!IS_ALIGNED(addr, P4D_SIZE))
-+ return 0;
-+
-+ if (!IS_ALIGNED(phys_addr, P4D_SIZE))
-+ return 0;
-+
-+ if (p4d_present(*p4d) && !p4d_free_pud_page(p4d, addr))
-+ return 0;
-+
-+ return p4d_set_huge(p4d, phys_addr, prot);
-+}
-+
-+static int vmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end,
-+ phys_addr_t phys_addr, pgprot_t prot, unsigned int max_page_shift,
-+ pgtbl_mod_mask *mask)
-+{
-+ p4d_t *p4d;
-+ unsigned long next;
-+
-+ p4d = p4d_alloc_track(&init_mm, pgd, addr, mask);
-+ if (!p4d)
-+ return -ENOMEM;
-+ do {
-+ next = p4d_addr_end(addr, end);
-+
-+ if (vmap_try_huge_p4d(p4d, addr, next, phys_addr, prot, max_page_shift)) {
-+ *mask |= PGTBL_P4D_MODIFIED;
-+ continue;
-+ }
-+
-+ if (vmap_pud_range(p4d, addr, next, phys_addr, prot, max_page_shift, mask))
-+ return -ENOMEM;
-+ } while (p4d++, phys_addr += (next - addr), addr = next, addr != end);
-+ return 0;
-+}
-+
-+int vmap_range(unsigned long addr, unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
-+ unsigned int max_page_shift)
-+{
-+ pgd_t *pgd;
-+ unsigned long start;
-+ unsigned long next;
-+ int err;
-+ pgtbl_mod_mask mask = 0;
-+
-+ might_sleep();
-+ BUG_ON(addr >= end);
-+
-+ start = addr;
-+ pgd = pgd_offset_k(addr);
-+ do {
-+ next = pgd_addr_end(addr, end);
-+ err = vmap_p4d_range(pgd, addr, next, phys_addr, prot, max_page_shift, &mask);
-+ if (err)
-+ break;
-+ } while (pgd++, phys_addr += (next - addr), addr = next, addr != end);
-+
-+ flush_cache_vmap(start, end);
-+
-+ if (mask & ARCH_PAGE_TABLE_SYNC_MASK)
-+ arch_sync_kernel_mappings(start, end);
-+
-+ return err;
-+}
-
- static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
- pgtbl_mod_mask *mask)
--
2.23.0