powerpc/mm: refactor ioremap vm area setup.
authorChristophe Leroy <christophe.leroy@c-s.fr>
Tue, 20 Aug 2019 14:07:19 +0000 (14:07 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 27 Aug 2019 03:03:35 +0000 (13:03 +1000)
PPC32 and PPC64 are doing the same once SLAB is available.
Create a do_ioremap() function that calls get_vm_area and
do the mapping.

For PPC64, we add the 4K PFN hack sanity check to __ioremap_caller()
in order to avoid using __ioremap_at(). Other checks in __ioremap_at()
are irrelevant for __ioremap_caller().

On PPC64, VM area is allocated in the range [ioremap_bot ; IOREMAP_END]
On PPC32, VM area is allocated in the range [VMALLOC_START ; VMALLOC_END]

Lets define IOREMAP_START is ioremap_bot for PPC64, and alias
IOREMAP_START/END to VMALLOC_START/END on PPC32

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/42e7e36ad32e0fdf76692426cc642799c9f689b8.1566309263.git.christophe.leroy@c-s.fr
arch/powerpc/include/asm/book3s/32/pgtable.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/io.h
arch/powerpc/include/asm/nohash/32/pgtable.h
arch/powerpc/include/asm/nohash/64/pgtable.h
arch/powerpc/mm/ioremap.c
arch/powerpc/mm/ioremap_32.c
arch/powerpc/mm/ioremap_64.c

index aa1bc5f8da90890a9ea687978e2427d8020fcc05..331a29a501a1b5447a4580d6564d27743faf14ff 100644 (file)
@@ -165,6 +165,10 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
 #define IOREMAP_TOP    KVIRT_TOP
 #endif
 
+/* PPC32 shares vmalloc area with ioremap */
+#define IOREMAP_START  VMALLOC_START
+#define IOREMAP_END    VMALLOC_END
+
 /*
  * Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 16MB value just means that there will be a 64MB "hole" after the
index 03c9a14dd9023a084a2a6df83c9578835aa2d0be..b01624e5c467142a350db94e8742312f99f0cbd4 100644 (file)
@@ -316,6 +316,7 @@ extern unsigned long pci_io_base;
 #define  PHB_IO_BASE   (ISA_IO_END)
 #define  PHB_IO_END    (KERN_IO_START + FULL_IO_SIZE)
 #define IOREMAP_BASE   (PHB_IO_END)
+#define IOREMAP_START  (ioremap_bot)
 #define IOREMAP_END    (KERN_IO_END)
 
 /* Advertise special mapping type for AGP */
index 8e00d95f96005ff967cb5aacec17c9595ad90dbb..dc529ea0fffa1185ddfee42a01163756f2c4c6f9 100644 (file)
@@ -723,6 +723,8 @@ void __iomem *ioremap_coherent(phys_addr_t address, unsigned long size);
 extern void iounmap(volatile void __iomem *addr);
 
 int ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t prot);
+void __iomem *do_ioremap(phys_addr_t pa, phys_addr_t offset, unsigned long size,
+                        pgprot_t prot, void *caller);
 
 extern void __iomem *__ioremap_caller(phys_addr_t, unsigned long size,
                                      pgprot_t prot, void *caller);
index 7ce2a7c9fade15ab548d31f8d27be2820254a998..3e1a4c1e40f048c553f30d13c5dd5aff4fcee20c 100644 (file)
@@ -93,6 +93,10 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
 #define IOREMAP_TOP    KVIRT_TOP
 #endif
 
+/* PPC32 shares vmalloc area with ioremap */
+#define IOREMAP_START  VMALLOC_START
+#define IOREMAP_END    VMALLOC_END
+
 /*
  * Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 16MB value just means that there will be a 64MB "hole" after the
index b9f66cf15c310a0910316b5e386cf79d3f042de4..9a33b8bd842d97c869bdea390e6aec57062db249 100644 (file)
@@ -53,6 +53,7 @@
 #define  PHB_IO_BASE   (ISA_IO_END)
 #define  PHB_IO_END    (KERN_IO_START + FULL_IO_SIZE)
 #define IOREMAP_BASE   (PHB_IO_END)
+#define IOREMAP_START  (ioremap_bot)
 #define IOREMAP_END    (KERN_VIRT_START + KERN_VIRT_SIZE)
 
 
index 50ee6544d0b7d071bdf4a0502ffa9a56ef0cc2d1..57630325846cd78d2c4a63d63e35c7a59d9686b3 100644 (file)
@@ -80,3 +80,23 @@ int ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t
 
        return 0;
 }
+
+void __iomem *do_ioremap(phys_addr_t pa, phys_addr_t offset, unsigned long size,
+                        pgprot_t prot, void *caller)
+{
+       struct vm_struct *area;
+       int ret;
+
+       area = __get_vm_area_caller(size, VM_IOREMAP, IOREMAP_START, IOREMAP_END, caller);
+       if (area == NULL)
+               return NULL;
+
+       area->phys_addr = pa;
+       ret = ioremap_range((unsigned long)area->addr, pa, size, prot);
+       if (!ret)
+               return (void __iomem *)area->addr + offset;
+
+       free_vm_area(area);
+
+       return NULL;
+}
index 85b90a62e0845a5585ea95ab39a54f824dda012d..fcf343dbf2bf9805c0c8de0ea46183d8a56c7136 100644 (file)
@@ -18,7 +18,7 @@ void __iomem *
 __ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *caller)
 {
        unsigned long v;
-       phys_addr_t p;
+       phys_addr_t p, offset;
        int err;
 
        /*
@@ -28,6 +28,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *call
         * (ioremap_bot records where we're up to).
         */
        p = addr & PAGE_MASK;
+       offset = addr & ~PAGE_MASK;
        size = PAGE_ALIGN(addr + size) - p;
 
        /*
@@ -62,12 +63,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *call
                goto out;
 
        if (slab_is_available()) {
-               struct vm_struct *area;
-               area = get_vm_area_caller(size, VM_IOREMAP, caller);
-               if (area == 0)
-                       return NULL;
-               area->phys_addr = p;
-               v = (unsigned long)area->addr;
+               return do_ioremap(p, offset, size, prot, caller);
        } else {
                v = (ioremap_bot -= size);
        }
@@ -77,11 +73,8 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *call
         */
 
        err = ioremap_range((unsigned long)v, p, size, prot);
-       if (err) {
-               if (slab_is_available())
-                       vunmap((void *)v);
+       if (err)
                return NULL;
-       }
 
 out:
        return (void __iomem *)(v + ((unsigned long)addr & ~PAGE_MASK));
index d132ce1e538d151b98ac33a0a25d60dd3eee2138..e37b68b7f0e86bb277f9aeb607e53a5275e618ea 100644 (file)
@@ -46,9 +46,13 @@ EXPORT_SYMBOL(__iounmap_at);
 void __iomem *__ioremap_caller(phys_addr_t addr, unsigned long size,
                               pgprot_t prot, void *caller)
 {
-       phys_addr_t paligned;
+       phys_addr_t paligned, offset;
        void __iomem *ret;
 
+       /* We don't support the 4K PFN hack with ioremap */
+       if (pgprot_val(prot) & H_PAGE_4K_PFN)
+               return NULL;
+
        /*
         * Choose an address to map it to. Once the vmalloc system is running,
         * we use it. Before that, we map using addresses going up from
@@ -56,21 +60,14 @@ void __iomem *__ioremap_caller(phys_addr_t addr, unsigned long size,
         * through ioremap_bot.
         */
        paligned = addr & PAGE_MASK;
+       offset = addr & ~PAGE_MASK;
        size = PAGE_ALIGN(addr + size) - paligned;
 
        if (size == 0 || paligned == 0)
                return NULL;
 
        if (slab_is_available()) {
-               struct vm_struct *area;
-
-               area = __get_vm_area_caller(size, VM_IOREMAP, ioremap_bot,
-                                           IOREMAP_END, caller);
-               if (area == NULL)
-                       return NULL;
-
-               area->phys_addr = paligned;
-               ret = __ioremap_at(paligned, area->addr, size, prot);
+               return do_ioremap(paligned, offset, size, prot, caller);
        } else {
                ret = __ioremap_at(paligned, (void *)ioremap_bot, size, prot);
                if (ret)