This is a generic kernel virtual memory mapper, not specific to ioremap.

Signed-off-by: Nicholas Piggin <npig...@gmail.com>
---
 include/linux/vmalloc.h |   3 +
 mm/ioremap.c            | 197 ----------------------------------------
 mm/vmalloc.c            | 196 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 199 insertions(+), 197 deletions(-)

diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 3f6bba4cc9bc..15adb9a14fb6 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -177,6 +177,9 @@ extern struct vm_struct *remove_vm_area(const void *addr);
 extern struct vm_struct *find_vm_area(const void *addr);
 
 #ifdef CONFIG_MMU
+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 c67f91164401..d1dcc7e744ac 100644
--- a/mm/ioremap.c
+++ b/mm/ioremap.c
@@ -28,203 +28,6 @@ early_param("nohugeiomap", set_nohugeiomap);
 static const bool iomap_max_page_shift = PAGE_SHIFT;
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
 
-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;
-}
-
-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)
 {
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 45cd80ec7eeb..256554d598e6 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -70,6 +70,202 @@ 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

Reply via email to