2019-08-13 20:12:31

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 01/10] powerpc/mm: drop ppc_md.iounmap()

ppc_md.iounmap() is never set, drop it.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/include/asm/machdep.h | 2 --
arch/powerpc/mm/pgtable_64.c | 5 +----
2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index c43d6eca9edd..3370df4bdaa0 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -33,8 +33,6 @@ struct machdep_calls {
#ifdef CONFIG_PPC64
void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
pgprot_t prot, void *caller);
- void (*iounmap)(volatile void __iomem *token);
-
#ifdef CONFIG_PM
void (*iommu_save)(void);
void (*iommu_restore)(void);
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 9ad59b733984..11eb90ea2d4f 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -285,10 +285,7 @@ void __iounmap(volatile void __iomem *token)

void iounmap(volatile void __iomem *token)
{
- if (ppc_md.iounmap)
- ppc_md.iounmap(token);
- else
- __iounmap(token);
+ __iounmap(token);
}

EXPORT_SYMBOL(ioremap);
--
2.13.3


2019-08-13 20:12:48

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 07/10] powerpc/mm: move iounmap() into ioremap.c and drop __iounmap()

On PPC64 iounmap() does nothing else than calling __iounmap()
and is the only user of __iounmap().
__iounmap() is almost similar to PPC32 iounmap().

Lets define a common iounmap() and drop __iounmap().

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/include/asm/book3s/32/pgtable.h | 2 ++
arch/powerpc/include/asm/io.h | 5 -----
arch/powerpc/include/asm/nohash/32/pgtable.h | 2 ++
arch/powerpc/mm/ioremap.c | 31 ++++++++++++++++++++++++++++
arch/powerpc/mm/pgtable_32.c | 14 -------------
arch/powerpc/mm/pgtable_64.c | 28 -------------------------
6 files changed, 35 insertions(+), 47 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index aa1bc5f8da90..af34554d19e8 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -165,6 +165,8 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
#define IOREMAP_TOP KVIRT_TOP
#endif

+#define IOREMAP_BASE VMALLOC_START
+
/*
* 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
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 23e5d5d16c7e..02d6256fe1ea 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -712,9 +712,6 @@ static inline void iosync(void)
* * __ioremap_caller is the same as above but takes an explicit caller
* reference rather than using __builtin_return_address(0)
*
- * * __iounmap, is the low level implementation used by iounmap and cannot
- * be hooked (but can be used by a hook on iounmap)
- *
*/
extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
extern void __iomem *ioremap_prot(phys_addr_t address, unsigned long size,
@@ -734,8 +731,6 @@ extern void __iomem *__ioremap(phys_addr_t, unsigned long size,
extern void __iomem *__ioremap_caller(phys_addr_t, unsigned long size,
pgprot_t prot, void *caller);

-extern void __iounmap(volatile void __iomem *addr);
-
extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea,
unsigned long size, pgprot_t prot);
extern void __iounmap_at(void *ea, unsigned long size);
diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 7ce2a7c9fade..09f2739ab556 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -93,6 +93,8 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
#define IOREMAP_TOP KVIRT_TOP
#endif

+#define IOREMAP_BASE VMALLOC_START
+
/*
* 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
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 0c23660522ca..57d742509cec 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -1,7 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <asm/io-workarounds.h>
+#include <mm/mmu_decl.h>

unsigned long ioremap_bot;
EXPORT_SYMBOL(ioremap_bot);
@@ -72,3 +75,31 @@ void __iomem *ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long f
return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
}
EXPORT_SYMBOL(ioremap_prot);
+
+/*
+ * Unmap an IO region and remove it from vmalloc'd list.
+ * Access to IO memory should be serialized by driver.
+ */
+void iounmap(volatile void __iomem *token)
+{
+ void *addr;
+
+ /*
+ * If mapped by BATs then there is nothing to do.
+ */
+ if (v_block_mapped((unsigned long)token))
+ return;
+
+ if (!slab_is_available())
+ return;
+
+ addr = (void *)((unsigned long __force)PCI_FIX_ADDR(token) & PAGE_MASK);
+ if (WARN_ON((unsigned long)addr < IOREMAP_BASE))
+ return;
+ if ((unsigned long)addr >= ioremap_bot) {
+ pr_warn("Attempt to %s early bolted mapping at 0x%p\n", __func__, addr);
+ return;
+ }
+ vunmap(addr);
+}
+EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 7efdb1dee19b..4597f45e4dc6 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -110,20 +110,6 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *call
return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
}

-void iounmap(volatile void __iomem *addr)
-{
- /*
- * If mapped by BATs then there is nothing to do.
- * Calling vfree() generates a benign warning.
- */
- if (v_block_mapped((unsigned long)addr))
- return;
-
- if (addr > high_memory && (unsigned long) addr < ioremap_bot)
- vunmap((void *) (PAGE_MASK & (unsigned long)addr));
-}
-EXPORT_SYMBOL(iounmap);
-
static void __init *early_alloc_pgtable(unsigned long size)
{
void *ptr = memblock_alloc(size, size);
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index d631659c8859..b50a53a0a42b 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -201,35 +201,7 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
return ret;
}

-/*
- * Unmap an IO region and remove it from imalloc'd list.
- * Access to IO memory should be serialized by driver.
- */
-void __iounmap(volatile void __iomem *token)
-{
- void *addr;
-
- if (!slab_is_available())
- return;
-
- addr = (void *) ((unsigned long __force)
- PCI_FIX_ADDR(token) & PAGE_MASK);
- if ((unsigned long)addr >= ioremap_bot) {
- printk(KERN_WARNING "Attempt to iounmap early bolted mapping"
- " at 0x%p\n", addr);
- return;
- }
- vunmap(addr);
-}
-
-void iounmap(volatile void __iomem *token)
-{
- __iounmap(token);
-}
-
EXPORT_SYMBOL(__ioremap_at);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(__iounmap);
EXPORT_SYMBOL(__iounmap_at);

#ifndef __PAGETABLE_PUD_FOLDED
--
2.13.3

2019-08-13 20:12:52

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 06/10] powerpc/mm: make ioremap_bot common to all

Drop multiple definitions of ioremap_bot and make one common to
all subarches.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/include/asm/book3s/32/pgtable.h | 2 --
arch/powerpc/include/asm/book3s/64/pgtable.h | 1 -
arch/powerpc/include/asm/nohash/32/pgtable.h | 2 --
arch/powerpc/include/asm/pgtable.h | 2 ++
arch/powerpc/mm/ioremap.c | 3 +++
arch/powerpc/mm/mmu_decl.h | 1 -
arch/powerpc/mm/nohash/tlb.c | 2 ++
arch/powerpc/mm/pgtable_32.c | 3 ---
arch/powerpc/mm/pgtable_64.c | 3 ---
9 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 838de59f6754..aa1bc5f8da90 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -201,8 +201,6 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
#include <linux/sched.h>
#include <linux/threads.h>

-extern unsigned long ioremap_bot;
-
/* Bits to mask out from a PGD to get to the PUD page */
#define PGD_MASKED_BITS 0

diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 8308f32e9782..11819e3c755e 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -289,7 +289,6 @@ extern unsigned long __kernel_io_end;
#define KERN_IO_END __kernel_io_end

extern struct page *vmemmap;
-extern unsigned long ioremap_bot;
extern unsigned long pci_io_base;
#endif /* __ASSEMBLY__ */

diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 0284f8f5305f..7ce2a7c9fade 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -11,8 +11,6 @@
#include <asm/mmu.h> /* For sub-arch specific PPC_PIN_SIZE */
#include <asm/asm-405.h>

-extern unsigned long ioremap_bot;
-
#ifdef CONFIG_44x
extern int icache_44x_need_flush;
#endif
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index c58ba7963688..c54bb68c1354 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -68,6 +68,8 @@ extern pgd_t swapper_pg_dir[];

extern void paging_init(void);

+extern unsigned long ioremap_bot;
+
/*
* kern_addr_valid is intended to indicate whether an address is a valid
* kernel address. Most 32-bit archs define it as always true (like this)
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index a44d9e4c948a..0c23660522ca 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -3,6 +3,9 @@
#include <linux/io.h>
#include <asm/io-workarounds.h>

+unsigned long ioremap_bot;
+EXPORT_SYMBOL(ioremap_bot);
+
void __iomem *__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
{
return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0));
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index 32c1a191c28a..6ee64d5e2824 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -108,7 +108,6 @@ extern u8 early_hash[];

#endif /* CONFIG_PPC32 */

-extern unsigned long ioremap_bot;
extern unsigned long __max_low_memory;
extern phys_addr_t __initial_memory_limit_addr;
extern phys_addr_t total_memory;
diff --git a/arch/powerpc/mm/nohash/tlb.c b/arch/powerpc/mm/nohash/tlb.c
index d4acf6fa0596..350a54f70a37 100644
--- a/arch/powerpc/mm/nohash/tlb.c
+++ b/arch/powerpc/mm/nohash/tlb.c
@@ -704,6 +704,8 @@ static void __init early_init_mmu_global(void)
* for use by the TLB miss code
*/
linear_map_top = memblock_end_of_DRAM();
+
+ ioremap_bot = IOREMAP_END;
}

static void __init early_mmu_set_memory_limit(void)
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 8126c2d1afbf..7efdb1dee19b 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -33,9 +33,6 @@

#include <mm/mmu_decl.h>

-unsigned long ioremap_bot;
-EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */
-
extern char etext[], _stext[], _sinittext[], _einittext[];

void __iomem *
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 0f0b1e1ea5ab..d631659c8859 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -99,9 +99,6 @@ unsigned long __pte_frag_nr;
EXPORT_SYMBOL(__pte_frag_nr);
unsigned long __pte_frag_size_shift;
EXPORT_SYMBOL(__pte_frag_size_shift);
-unsigned long ioremap_bot;
-#else /* !CONFIG_PPC_BOOK3S_64 */
-unsigned long ioremap_bot = IOREMAP_END;
#endif

int __weak ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t prot, int nid)
--
2.13.3

2019-08-13 20:12:54

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 10/10] powerpc/mm: refactor ioremap_range() and use ioremap_page_range()

book3s64's ioremap_range() is almost same as fallback ioremap_range(),
except that it calls radix__ioremap_range() when radix is enabled.

radix__ioremap_range() is also very similar to the other ones, expect
that it calls ioremap_page_range when slab is available.

Lets keep only one version of ioremap_range() which calls
ioremap_page_range() on all platforms when slab is available.

At the same time, drop the nid parameter which is not used.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/include/asm/book3s/64/radix.h | 3 ---
arch/powerpc/mm/book3s64/pgtable.c | 21 ---------------------
arch/powerpc/mm/book3s64/radix_pgtable.c | 20 --------------------
arch/powerpc/mm/ioremap.c | 23 +++++++++++++----------
4 files changed, 13 insertions(+), 54 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h
index e04a839cb5b9..574eca33f893 100644
--- a/arch/powerpc/include/asm/book3s/64/radix.h
+++ b/arch/powerpc/include/asm/book3s/64/radix.h
@@ -266,9 +266,6 @@ extern void radix__vmemmap_remove_mapping(unsigned long start,
extern int radix__map_kernel_page(unsigned long ea, unsigned long pa,
pgprot_t flags, unsigned int psz);

-extern int radix__ioremap_range(unsigned long ea, phys_addr_t pa,
- unsigned long size, pgprot_t prot, int nid);
-
static inline unsigned long radix__get_tree_size(void)
{
unsigned long rts_field;
diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
index 7d0e0d0d22c4..4c8bed856533 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -446,24 +446,3 @@ int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,

return true;
}
-
-int ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t prot, int nid)
-{
- unsigned long i;
-
- if (radix_enabled())
- return radix__ioremap_range(ea, pa, size, prot, nid);
-
- for (i = 0; i < size; i += PAGE_SIZE) {
- int err = map_kernel_page(ea + i, pa + i, prot);
- if (err) {
- if (slab_is_available())
- unmap_kernel_range(ea, size);
- else
- WARN_ON_ONCE(1); /* Should clean up */
- return err;
- }
- }
-
- return 0;
-}
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index 11303e2fffb1..d39edbb07bd1 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -1218,26 +1218,6 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
return 1;
}

-int radix__ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size,
- pgprot_t prot, int nid)
-{
- if (likely(slab_is_available())) {
- int err = ioremap_page_range(ea, ea + size, pa, prot);
- if (err)
- unmap_kernel_range(ea, size);
- return err;
- } else {
- unsigned long i;
-
- for (i = 0; i < size; i += PAGE_SIZE) {
- int err = map_kernel_page(ea + i, pa + i, prot);
- if (WARN_ON_ONCE(err)) /* Should clean up */
- return err;
- }
- return 0;
- }
-}
-
int __init arch_ioremap_p4d_supported(void)
{
return 0;
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 537c9148cea1..dc538d7f2467 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -76,21 +76,24 @@ void __iomem *ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long f
}
EXPORT_SYMBOL(ioremap_prot);

-int __weak ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size,
- pgprot_t prot, int nid)
+static int ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size,
+ pgprot_t prot)
{
unsigned long i;

+ if (slab_is_available()) {
+ int err = ioremap_page_range(ea, ea + size, pa, prot);
+
+ if (err)
+ unmap_kernel_range(ea, size);
+ return err;
+ }
+
for (i = 0; i < size; i += PAGE_SIZE) {
int err = map_kernel_page(ea + i, pa + i, prot);

- if (err) {
- if (slab_is_available())
- unmap_kernel_range(ea, size);
- else
- WARN_ON_ONCE(1); /* Should clean up */
+ if (WARN_ON_ONCE(err)) /* Should clean up */
return err;
- }
}

return 0;
@@ -165,7 +168,7 @@ void __iomem *__ioremap_caller(phys_addr_t addr, unsigned long size,
ioremap_bot -= size;
va = ioremap_bot;
}
- ret = ioremap_range(va, pa, size, prot, NUMA_NO_NODE);
+ ret = ioremap_range(va, pa, size, prot);
if (!ret)
return (void __iomem *)va + (addr & ~PAGE_MASK);

@@ -223,7 +226,7 @@ void __iomem *__ioremap_at(phys_addr_t pa, void *ea, unsigned long size, pgprot_
WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
WARN_ON(size & ~PAGE_MASK);

- if (ioremap_range((unsigned long)ea, pa, size, prot, NUMA_NO_NODE))
+ if (ioremap_range((unsigned long)ea, pa, size, prot))
return NULL;

return (void __iomem *)ea;
--
2.13.3

2019-08-13 20:13:06

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 09/10] powerpc/mm: make __ioremap_caller() common to PPC32 and PPC64

__ioremap_caller() do the same thing. Define a common one.

__ioremap() is not reused because most of the tests included in
it are unnecessary when coming from __ioremap_caller()

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/mm/ioremap.c | 99 ++++++++++++++++++++++++++++++++++++++++++++
arch/powerpc/mm/pgtable_32.c | 75 ---------------------------------
arch/powerpc/mm/pgtable_64.c | 61 ---------------------------
3 files changed, 99 insertions(+), 136 deletions(-)

diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 889ee656cf64..537c9148cea1 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -76,6 +76,105 @@ void __iomem *ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long f
}
EXPORT_SYMBOL(ioremap_prot);

+int __weak ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size,
+ pgprot_t prot, int nid)
+{
+ unsigned long i;
+
+ for (i = 0; i < size; i += PAGE_SIZE) {
+ int err = map_kernel_page(ea + i, pa + i, prot);
+
+ if (err) {
+ if (slab_is_available())
+ unmap_kernel_range(ea, size);
+ else
+ WARN_ON_ONCE(1); /* Should clean up */
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+void __iomem *__ioremap_caller(phys_addr_t addr, unsigned long size,
+ pgprot_t prot, void *caller)
+{
+ phys_addr_t pa = addr & PAGE_MASK;
+ int ret;
+ unsigned long va;
+
+ size = PAGE_ALIGN(addr + size) - pa;
+
+#ifdef CONFIG_PPC64
+ /* We don't support the 4K PFN hack with ioremap */
+ if (pgprot_val(prot) & H_PAGE_4K_PFN)
+ return NULL;
+#else
+ /*
+ * If the address lies within the first 16 MB, assume it's in ISA
+ * memory space
+ */
+ if (pa < SZ_16M)
+ pa += _ISA_MEM_BASE;
+
+#ifndef CONFIG_CRASH_DUMP
+ /*
+ * Don't allow anybody to remap normal RAM that we're using.
+ * mem_init() sets high_memory so only do the check after that.
+ */
+ if (slab_is_available() && pa <= virt_to_phys(high_memory - 1) &&
+ page_is_ram(__phys_to_pfn(pa))) {
+ pr_err("%s(): phys addr 0x%llx is RAM lr %ps\n", __func__,
+ (unsigned long long)pa, __builtin_return_address(0));
+ return NULL;
+ }
+#endif
+#endif /* CONFIG_PPC64 */
+
+ if (size == 0 || pa == 0)
+ return NULL;
+
+ /*
+ * Is it already mapped? Perhaps overlapped by a previous
+ * mapping.
+ */
+ va = p_block_mapped(pa);
+ if (va)
+ return (void __iomem *)va + (addr & ~PAGE_MASK);
+
+ /*
+ * Choose an address to map it to.
+ * Once the vmalloc system is running, we use it.
+ * Before that, we map using addresses going
+ * down from ioremap_bot. vmalloc will use
+ * the addresses from IOREMAP_BASE through
+ * ioremap_bot
+ *
+ */
+ if (slab_is_available()) {
+ struct vm_struct *area;
+
+ area = __get_vm_area_caller(size, VM_IOREMAP, IOREMAP_BASE,
+ ioremap_bot, caller);
+ if (area == NULL)
+ return NULL;
+
+ area->phys_addr = pa;
+ va = (unsigned long)area->addr;
+ } else {
+ ioremap_bot -= size;
+ va = ioremap_bot;
+ }
+ ret = ioremap_range(va, pa, size, prot, NUMA_NO_NODE);
+ if (!ret)
+ return (void __iomem *)va + (addr & ~PAGE_MASK);
+
+ if (!slab_is_available())
+ ioremap_bot += size;
+
+ return NULL;
+}
+
/*
* Unmap an IO region and remove it from vmalloc'd list.
* Access to IO memory should be serialized by driver.
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 4597f45e4dc6..bacf3b85191c 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -35,81 +35,6 @@

extern char etext[], _stext[], _sinittext[], _einittext[];

-void __iomem *
-__ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *caller)
-{
- unsigned long v, i;
- phys_addr_t p;
- int err;
-
- /*
- * Choose an address to map it to.
- * Once the vmalloc system is running, we use it.
- * Before then, we use space going down from IOREMAP_TOP
- * (ioremap_bot records where we're up to).
- */
- p = addr & PAGE_MASK;
- size = PAGE_ALIGN(addr + size) - p;
-
- /*
- * If the address lies within the first 16 MB, assume it's in ISA
- * memory space
- */
- if (p < 16*1024*1024)
- p += _ISA_MEM_BASE;
-
-#ifndef CONFIG_CRASH_DUMP
- /*
- * Don't allow anybody to remap normal RAM that we're using.
- * mem_init() sets high_memory so only do the check after that.
- */
- if (slab_is_available() && p <= virt_to_phys(high_memory - 1) &&
- page_is_ram(__phys_to_pfn(p))) {
- printk("__ioremap(): phys addr 0x%llx is RAM lr %ps\n",
- (unsigned long long)p, __builtin_return_address(0));
- return NULL;
- }
-#endif
-
- if (size == 0)
- return NULL;
-
- /*
- * Is it already mapped? Perhaps overlapped by a previous
- * mapping.
- */
- v = p_block_mapped(p);
- if (v)
- 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;
- } else {
- v = (ioremap_bot -= size);
- }
-
- /*
- * Should check if it is a candidate for a BAT mapping
- */
-
- err = 0;
- for (i = 0; i < size && err == 0; i += PAGE_SIZE)
- err = map_kernel_page(v + i, p + i, prot);
- if (err) {
- if (slab_is_available())
- vunmap((void *)v);
- return NULL;
- }
-
-out:
- return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
-}
-
static void __init *early_alloc_pgtable(unsigned long size)
{
void *ptr = memblock_alloc(size, size);
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 32220f7381d7..781263df9f5e 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -101,67 +101,6 @@ unsigned long __pte_frag_size_shift;
EXPORT_SYMBOL(__pte_frag_size_shift);
#endif

-int __weak ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t prot, int nid)
-{
- unsigned long i;
-
- for (i = 0; i < size; i += PAGE_SIZE) {
- int err = map_kernel_page(ea + i, pa + i, prot);
- if (err) {
- if (slab_is_available())
- unmap_kernel_range(ea, size);
- else
- WARN_ON_ONCE(1); /* Should clean up */
- return err;
- }
- }
-
- return 0;
-}
-
-void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
- pgprot_t prot, void *caller)
-{
- phys_addr_t paligned;
- void __iomem *ret;
-
- /*
- * Choose an address to map it to.
- * Once the vmalloc system is running, we use it.
- * Before that, we map using addresses going
- * down from ioremap_bot. vmalloc will use
- * the addresses from IOREMAP_BASE through
- * ioremap_bot
- *
- */
- paligned = 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_BASE, ioremap_bot,
- caller);
- if (area == NULL)
- return NULL;
-
- area->phys_addr = paligned;
- ret = __ioremap_at(paligned, area->addr, size, prot);
- } else {
- ret = __ioremap_at(paligned, (void *)ioremap_bot - size, size, prot);
- if (ret)
- ioremap_bot -= size;
- }
-
- if (ret)
- ret += addr & ~PAGE_MASK;
- return ret;
-}
-
#ifndef __PAGETABLE_PUD_FOLDED
/* 4 level page table */
struct page *pgd_page(pgd_t pgd)
--
2.13.3

2019-08-13 20:13:45

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 04/10] powerpc/mm: move ioremap_prot() into ioremap.c

Both ioremap_prot() are idenfical, move them into ioremap.c

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/mm/ioremap.c | 19 +++++++++++++++++++
arch/powerpc/mm/pgtable_32.c | 17 -----------------
arch/powerpc/mm/pgtable_64.c | 24 ------------------------
3 files changed, 19 insertions(+), 41 deletions(-)

diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 89479ee88344..a44d9e4c948a 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -50,3 +50,22 @@ void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size)
return iowa_ioremap(addr, size, prot, caller);
return __ioremap_caller(addr, size, prot, caller);
}
+
+void __iomem *ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
+{
+ pte_t pte = __pte(flags);
+ void *caller = __builtin_return_address(0);
+
+ /* writeable implies dirty for kernel addresses */
+ if (pte_write(pte))
+ pte = pte_mkdirty(pte);
+
+ /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
+ pte = pte_exprotect(pte);
+ pte = pte_mkprivileged(pte);
+
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
+ return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
+}
+EXPORT_SYMBOL(ioremap_prot);
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 1999ec11706d..8126c2d1afbf 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -39,23 +39,6 @@ EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */
extern char etext[], _stext[], _sinittext[], _einittext[];

void __iomem *
-ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
-{
- pte_t pte = __pte(flags);
-
- /* writeable implies dirty for kernel addresses */
- if (pte_write(pte))
- pte = pte_mkdirty(pte);
-
- /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
- pte = pte_exprotect(pte);
- pte = pte_mkprivileged(pte);
-
- return __ioremap_caller(addr, size, pte_pgprot(pte), __builtin_return_address(0));
-}
-EXPORT_SYMBOL(ioremap_prot);
-
-void __iomem *
__ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *caller)
{
unsigned long v, i;
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 3ad921ac4862..6fa2e969bf0e 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -204,29 +204,6 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
return ret;
}

-void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size,
- unsigned long flags)
-{
- pte_t pte = __pte(flags);
- void *caller = __builtin_return_address(0);
-
- /* writeable implies dirty for kernel addresses */
- if (pte_write(pte))
- pte = pte_mkdirty(pte);
-
- /* we don't want to let _PAGE_EXEC leak out */
- pte = pte_exprotect(pte);
- /*
- * Force kernel mapping.
- */
- pte = pte_mkprivileged(pte);
-
- if (iowa_is_active())
- return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
- return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
-}
-
-
/*
* Unmap an IO region and remove it from imalloc'd list.
* Access to IO memory should be serialized by driver.
@@ -253,7 +230,6 @@ void iounmap(volatile void __iomem *token)
__iounmap(token);
}

-EXPORT_SYMBOL(ioremap_prot);
EXPORT_SYMBOL(__ioremap_at);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(__iounmap);
--
2.13.3

2019-08-13 20:13:45

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.

Until vmalloc system is up and running, ioremap basically
allocates addresses at the border of the IOREMAP area.

On PPC32, addresses are allocated down from the top of the area
while on PPC64, addresses are allocated up from the base of the
area.

On PPC32, the base of vmalloc area is not known yet when ioremap()
starts to be used, while the end of it is fixed. On PPC64, both the
start and the end are already fixed when ioremap() starts to being
used.

Changing PPC64 behaviour is the lighest change, so change PPC64
ioremap() to allocate addresses from the top as PPC32 does.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/mm/book3s64/hash_utils.c | 2 +-
arch/powerpc/mm/book3s64/radix_pgtable.c | 2 +-
arch/powerpc/mm/pgtable_64.c | 18 +++++++++---------
3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c
index e6d471058597..0f954dc40346 100644
--- a/arch/powerpc/mm/book3s64/hash_utils.c
+++ b/arch/powerpc/mm/book3s64/hash_utils.c
@@ -1030,7 +1030,7 @@ void __init hash__early_init_mmu(void)
__kernel_io_start = H_KERN_IO_START;
__kernel_io_end = H_KERN_IO_END;
vmemmap = (struct page *)H_VMEMMAP_START;
- ioremap_bot = IOREMAP_BASE;
+ ioremap_bot = IOREMAP_END;

#ifdef CONFIG_PCI
pci_io_base = ISA_IO_BASE;
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index b4ca9e95e678..11303e2fffb1 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -611,7 +611,7 @@ void __init radix__early_init_mmu(void)
__kernel_io_start = RADIX_KERN_IO_START;
__kernel_io_end = RADIX_KERN_IO_END;
vmemmap = (struct page *)RADIX_VMEMMAP_START;
- ioremap_bot = IOREMAP_BASE;
+ ioremap_bot = IOREMAP_END;

#ifdef CONFIG_PCI
pci_io_base = ISA_IO_BASE;
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 6fa2e969bf0e..0f0b1e1ea5ab 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -101,7 +101,7 @@ unsigned long __pte_frag_size_shift;
EXPORT_SYMBOL(__pte_frag_size_shift);
unsigned long ioremap_bot;
#else /* !CONFIG_PPC_BOOK3S_64 */
-unsigned long ioremap_bot = IOREMAP_BASE;
+unsigned long ioremap_bot = IOREMAP_END;
#endif

int __weak ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t prot, int nid)
@@ -169,11 +169,11 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,

/*
* Choose an address to map it to.
- * Once the imalloc system is running, we use it.
+ * Once the vmalloc system is running, we use it.
* Before that, we map using addresses going
- * up from ioremap_bot. imalloc will use
- * the addresses from ioremap_bot through
- * IMALLOC_END
+ * down from ioremap_bot. vmalloc will use
+ * the addresses from IOREMAP_BASE through
+ * ioremap_bot
*
*/
paligned = addr & PAGE_MASK;
@@ -186,7 +186,7 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
struct vm_struct *area;

area = __get_vm_area_caller(size, VM_IOREMAP,
- ioremap_bot, IOREMAP_END,
+ IOREMAP_BASE, ioremap_bot,
caller);
if (area == NULL)
return NULL;
@@ -194,9 +194,9 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
area->phys_addr = paligned;
ret = __ioremap_at(paligned, area->addr, size, prot);
} else {
- ret = __ioremap_at(paligned, (void *)ioremap_bot, size, prot);
+ ret = __ioremap_at(paligned, (void *)ioremap_bot - size, size, prot);
if (ret)
- ioremap_bot += size;
+ ioremap_bot -= size;
}

if (ret)
@@ -217,7 +217,7 @@ void __iounmap(volatile void __iomem *token)

addr = (void *) ((unsigned long __force)
PCI_FIX_ADDR(token) & PAGE_MASK);
- if ((unsigned long)addr < ioremap_bot) {
+ if ((unsigned long)addr >= ioremap_bot) {
printk(KERN_WARNING "Attempt to iounmap early bolted mapping"
" at 0x%p\n", addr);
return;
--
2.13.3

2019-08-13 20:14:46

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 03/10] powerpc/mm: move common 32/64 bits ioremap functions into ioremap.c

ioremap(), __ioremap(), ioremap_wc() and ioremap_coherent() are
now identical on PPC32 and PPC64 as iowa_is_active() will always
return false on PPC32. Move them into a new common location called
ioremap.c

Allthough ioremap_wt() only exists on PPC32, move it into ioremap.c
as well. As it is the only one specific to PPC32, it is not worth
creating an ioremap_32.c file and leaving it in pgtable_32.c would
make it the only ioremap function in that file at the end of the
series.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/ioremap.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
arch/powerpc/mm/pgtable_32.c | 43 ------------------------------------
arch/powerpc/mm/pgtable_64.c | 39 ---------------------------------
4 files changed, 53 insertions(+), 83 deletions(-)
create mode 100644 arch/powerpc/mm/ioremap.c

diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 0f499db315d6..29c682fe9144 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -7,7 +7,7 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)

obj-y := fault.o mem.o pgtable.o mmap.o \
init_$(BITS).o pgtable_$(BITS).o \
- pgtable-frag.o \
+ pgtable-frag.o ioremap.o \
init-common.o mmu_context.o drmem.o
obj-$(CONFIG_PPC_MMU_NOHASH) += nohash/
obj-$(CONFIG_PPC_BOOK3S_32) += book3s32/
diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
new file mode 100644
index 000000000000..89479ee88344
--- /dev/null
+++ b/arch/powerpc/mm/ioremap.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/io.h>
+#include <asm/io-workarounds.h>
+
+void __iomem *__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
+{
+ return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0));
+}
+EXPORT_SYMBOL(__ioremap);
+
+void __iomem *ioremap(phys_addr_t addr, unsigned long size)
+{
+ pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
+ void *caller = __builtin_return_address(0);
+
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, prot, caller);
+ return __ioremap_caller(addr, size, prot, caller);
+}
+EXPORT_SYMBOL(ioremap);
+
+void __iomem *ioremap_wc(phys_addr_t addr, unsigned long size)
+{
+ pgprot_t prot = pgprot_noncached_wc(PAGE_KERNEL);
+ void *caller = __builtin_return_address(0);
+
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, prot, caller);
+ return __ioremap_caller(addr, size, prot, caller);
+}
+EXPORT_SYMBOL(ioremap_wc);
+
+#ifdef CONFIG_PPC32
+void __iomem *ioremap_wt(phys_addr_t addr, unsigned long size)
+{
+ pgprot_t prot = pgprot_cached_wthru(PAGE_KERNEL);
+
+ return __ioremap_caller(addr, size, prot, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_wt);
+#endif
+
+void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size)
+{
+ pgprot_t prot = pgprot_cached(PAGE_KERNEL);
+ void *caller = __builtin_return_address(0);
+
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, prot, caller);
+ return __ioremap_caller(addr, size, prot, caller);
+}
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 35cb96cfc258..1999ec11706d 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -39,42 +39,6 @@ EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */
extern char etext[], _stext[], _sinittext[], _einittext[];

void __iomem *
-ioremap(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
-
- return __ioremap_caller(addr, size, prot, __builtin_return_address(0));
-}
-EXPORT_SYMBOL(ioremap);
-
-void __iomem *
-ioremap_wc(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_noncached_wc(PAGE_KERNEL);
-
- return __ioremap_caller(addr, size, prot, __builtin_return_address(0));
-}
-EXPORT_SYMBOL(ioremap_wc);
-
-void __iomem *
-ioremap_wt(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_cached_wthru(PAGE_KERNEL);
-
- return __ioremap_caller(addr, size, prot, __builtin_return_address(0));
-}
-EXPORT_SYMBOL(ioremap_wt);
-
-void __iomem *
-ioremap_coherent(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_cached(PAGE_KERNEL);
-
- return __ioremap_caller(addr, size, prot, __builtin_return_address(0));
-}
-EXPORT_SYMBOL(ioremap_coherent);
-
-void __iomem *
ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
{
pte_t pte = __pte(flags);
@@ -92,12 +56,6 @@ ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
EXPORT_SYMBOL(ioremap_prot);

void __iomem *
-__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
-{
- return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0));
-}
-
-void __iomem *
__ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *caller)
{
unsigned long v, i;
@@ -171,7 +129,6 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *call
out:
return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
}
-EXPORT_SYMBOL(__ioremap);

void iounmap(volatile void __iomem *addr)
{
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 194efc6f39fb..3ad921ac4862 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -204,42 +204,6 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
return ret;
}

-void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
- unsigned long flags)
-{
- return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0));
-}
-
-void __iomem * ioremap(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
- void *caller = __builtin_return_address(0);
-
- if (iowa_is_active())
- return iowa_ioremap(addr, size, prot, caller);
- return __ioremap_caller(addr, size, prot, caller);
-}
-
-void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_noncached_wc(PAGE_KERNEL);
- void *caller = __builtin_return_address(0);
-
- if (iowa_is_active())
- return iowa_ioremap(addr, size, prot, caller);
- return __ioremap_caller(addr, size, prot, caller);
-}
-
-void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size)
-{
- pgprot_t prot = pgprot_cached(PAGE_KERNEL);
- void *caller = __builtin_return_address(0);
-
- if (iowa_is_active())
- return iowa_ioremap(addr, size, prot, caller);
- return __ioremap_caller(addr, size, prot, caller);
-}
-
void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size,
unsigned long flags)
{
@@ -289,10 +253,7 @@ void iounmap(volatile void __iomem *token)
__iounmap(token);
}

-EXPORT_SYMBOL(ioremap);
-EXPORT_SYMBOL(ioremap_wc);
EXPORT_SYMBOL(ioremap_prot);
-EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(__ioremap_at);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(__iounmap);
--
2.13.3

2019-08-13 20:14:50

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 08/10] powerpc/mm: move __ioremap_at() and __iounmap_at() into ioremap.c

Allthough __ioremap_at() and __iounmap_at() are specific to PPC64,
lets move them into ioremap.c as it wouldn't be worth creating an
ioremap_64.c only for those functions.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/mm/ioremap.c | 43 +++++++++++++++++++++++++++++++++++++++++++
arch/powerpc/mm/pgtable_64.c | 42 ------------------------------------------
2 files changed, 43 insertions(+), 42 deletions(-)

diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
index 57d742509cec..889ee656cf64 100644
--- a/arch/powerpc/mm/ioremap.c
+++ b/arch/powerpc/mm/ioremap.c
@@ -103,3 +103,46 @@ void iounmap(volatile void __iomem *token)
vunmap(addr);
}
EXPORT_SYMBOL(iounmap);
+
+#ifdef CONFIG_PPC64
+/**
+ * __ioremap_at - Low level function to establish the page tables
+ * for an IO mapping
+ */
+void __iomem *__ioremap_at(phys_addr_t pa, void *ea, unsigned long size, pgprot_t prot)
+{
+ /* We don't support the 4K PFN hack with ioremap */
+ if (pgprot_val(prot) & H_PAGE_4K_PFN)
+ return NULL;
+
+ if ((ea + size) >= (void *)IOREMAP_END) {
+ pr_warn("Outside the supported range\n");
+ return NULL;
+ }
+
+ WARN_ON(pa & ~PAGE_MASK);
+ WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
+ WARN_ON(size & ~PAGE_MASK);
+
+ if (ioremap_range((unsigned long)ea, pa, size, prot, NUMA_NO_NODE))
+ return NULL;
+
+ return (void __iomem *)ea;
+}
+EXPORT_SYMBOL(__ioremap_at);
+
+/**
+ * __iounmap_from - Low level function to tear down the page tables
+ * for an IO mapping. This is used for mappings that
+ * are manipulated manually, like partial unmapping of
+ * PCI IOs or ISA space.
+ */
+void __iounmap_at(void *ea, unsigned long size)
+{
+ WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
+ WARN_ON(size & ~PAGE_MASK);
+
+ unmap_kernel_range((unsigned long)ea, size);
+}
+EXPORT_SYMBOL(__iounmap_at);
+#endif
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index b50a53a0a42b..32220f7381d7 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -119,45 +119,6 @@ int __weak ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, p
return 0;
}

-/**
- * __ioremap_at - Low level function to establish the page tables
- * for an IO mapping
- */
-void __iomem *__ioremap_at(phys_addr_t pa, void *ea, unsigned long size, pgprot_t prot)
-{
- /* We don't support the 4K PFN hack with ioremap */
- if (pgprot_val(prot) & H_PAGE_4K_PFN)
- return NULL;
-
- if ((ea + size) >= (void *)IOREMAP_END) {
- pr_warn("Outside the supported range\n");
- return NULL;
- }
-
- WARN_ON(pa & ~PAGE_MASK);
- WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
- WARN_ON(size & ~PAGE_MASK);
-
- if (ioremap_range((unsigned long)ea, pa, size, prot, NUMA_NO_NODE))
- return NULL;
-
- return (void __iomem *)ea;
-}
-
-/**
- * __iounmap_from - Low level function to tear down the page tables
- * for an IO mapping. This is used for mappings that
- * are manipulated manually, like partial unmapping of
- * PCI IOs or ISA space.
- */
-void __iounmap_at(void *ea, unsigned long size)
-{
- WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
- WARN_ON(size & ~PAGE_MASK);
-
- unmap_kernel_range((unsigned long)ea, size);
-}
-
void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
pgprot_t prot, void *caller)
{
@@ -201,9 +162,6 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size,
return ret;
}

-EXPORT_SYMBOL(__ioremap_at);
-EXPORT_SYMBOL(__iounmap_at);
-
#ifndef __PAGETABLE_PUD_FOLDED
/* 4 level page table */
struct page *pgd_page(pgd_t pgd)
--
2.13.3

2019-08-13 20:15:39

by Christophe Leroy

[permalink] [raw]
Subject: [PATCH v1 02/10] powerpc/mm: rework io-workaround invocation.

ppc_md.ioremap() is only used for I/O workaround on CELL platform,
so indirect function call can be avoided.

This patch reworks the io-workaround and ioremap() functions to
use static keys for the activation of io-workaround.

When CONFIG_PPC_IO_WORKAROUNDS or CONFIG_PPC_INDIRECT_MMIO are not
selected, the I/O workaround ioremap() voids and the static key is
not used at all.

Signed-off-by: Christophe Leroy <[email protected]>
---
arch/powerpc/include/asm/io-workarounds.h | 19 +++++++++++++++++++
arch/powerpc/include/asm/machdep.h | 2 --
arch/powerpc/kernel/io-workarounds.c | 11 ++++++-----
arch/powerpc/mm/pgtable_64.c | 17 +++++++++--------
4 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/include/asm/io-workarounds.h b/arch/powerpc/include/asm/io-workarounds.h
index 01567ea4ceaf..ce337d17ac40 100644
--- a/arch/powerpc/include/asm/io-workarounds.h
+++ b/arch/powerpc/include/asm/io-workarounds.h
@@ -8,6 +8,7 @@
#ifndef _IO_WORKAROUNDS_H
#define _IO_WORKAROUNDS_H

+#ifdef CONFIG_PPC_IO_WORKAROUNDS
#include <linux/io.h>
#include <asm/pci-bridge.h>

@@ -32,4 +33,22 @@ extern int spiderpci_iowa_init(struct iowa_bus *, void *);
#define SPIDER_PCI_DUMMY_READ 0x0810
#define SPIDER_PCI_DUMMY_READ_BASE 0x0814

+#endif
+
+#if defined(CONFIG_PPC_IO_WORKAROUNDS) && defined(CONFIG_PPC_INDIRECT_MMIO)
+DECLARE_STATIC_KEY_FALSE(iowa_key);
+static inline bool iowa_is_active(void)
+{
+ return static_branch_unlikely(&iowa_key);
+}
+#else
+static inline bool iowa_is_active(void)
+{
+ return false;
+}
+#endif
+
+void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
+ pgprot_t prot, void *caller);
+
#endif /* _IO_WORKAROUNDS_H */
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 3370df4bdaa0..657ec893bdcb 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -31,8 +31,6 @@ struct pci_host_bridge;
struct machdep_calls {
char *name;
#ifdef CONFIG_PPC64
- void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
- pgprot_t prot, void *caller);
#ifdef CONFIG_PM
void (*iommu_save)(void);
void (*iommu_restore)(void);
diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c
index fbd2d0007c52..8b5b2aa70840 100644
--- a/arch/powerpc/kernel/io-workarounds.c
+++ b/arch/powerpc/kernel/io-workarounds.c
@@ -18,6 +18,7 @@
#include <asm/io-workarounds.h>
#include <asm/pte-walk.h>

+DEFINE_STATIC_KEY_FALSE(iowa_key);

#define IOWA_MAX_BUS 8

@@ -149,8 +150,8 @@ static const struct ppc_pci_io iowa_pci_io = {
};

#ifdef CONFIG_PPC_INDIRECT_MMIO
-static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
- pgprot_t prot, void *caller)
+void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
+ pgprot_t prot, void *caller)
{
struct iowa_bus *bus;
void __iomem *res = __ioremap_caller(addr, size, prot, caller);
@@ -163,8 +164,6 @@ static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
}
return res;
}
-#else /* CONFIG_PPC_INDIRECT_MMIO */
-#define iowa_ioremap NULL
#endif /* !CONFIG_PPC_INDIRECT_MMIO */

/* Enable IO workaround */
@@ -175,7 +174,9 @@ static void io_workaround_init(void)
if (io_workaround_inited)
return;
ppc_pci_io = iowa_pci_io;
- ppc_md.ioremap = iowa_ioremap;
+#ifdef CONFIG_PPC_INDIRECT_MMIO
+ static_branch_enable(&iowa_key);
+#endif
io_workaround_inited = 1;
}

diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 11eb90ea2d4f..194efc6f39fb 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -35,6 +35,7 @@
#include <asm/page.h>
#include <asm/prom.h>
#include <asm/io.h>
+#include <asm/io-workarounds.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
@@ -214,8 +215,8 @@ void __iomem * ioremap(phys_addr_t addr, unsigned long size)
pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
void *caller = __builtin_return_address(0);

- if (ppc_md.ioremap)
- return ppc_md.ioremap(addr, size, prot, caller);
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, prot, caller);
return __ioremap_caller(addr, size, prot, caller);
}

@@ -224,8 +225,8 @@ void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size)
pgprot_t prot = pgprot_noncached_wc(PAGE_KERNEL);
void *caller = __builtin_return_address(0);

- if (ppc_md.ioremap)
- return ppc_md.ioremap(addr, size, prot, caller);
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, prot, caller);
return __ioremap_caller(addr, size, prot, caller);
}

@@ -234,8 +235,8 @@ void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size)
pgprot_t prot = pgprot_cached(PAGE_KERNEL);
void *caller = __builtin_return_address(0);

- if (ppc_md.ioremap)
- return ppc_md.ioremap(addr, size, prot, caller);
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, prot, caller);
return __ioremap_caller(addr, size, prot, caller);
}

@@ -256,8 +257,8 @@ void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size,
*/
pte = pte_mkprivileged(pte);

- if (ppc_md.ioremap)
- return ppc_md.ioremap(addr, size, pte_pgprot(pte), caller);
+ if (iowa_is_active())
+ return iowa_ioremap(addr, size, pte_pgprot(pte), caller);
return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
}

--
2.13.3

2019-08-14 05:21:14

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 01/10] powerpc/mm: drop ppc_md.iounmap()

On Tue, Aug 13, 2019 at 08:11:33PM +0000, Christophe Leroy wrote:
> ppc_md.iounmap() is never set, drop it.
>
> Signed-off-by: Christophe Leroy <[email protected]>

Hah, I was just going to send the same patch as part of an tree-wide
ioremap related series..

Reviewed-by: Christoph Hellwig <[email protected]>

2019-08-14 05:25:22

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 08/10] powerpc/mm: move __ioremap_at() and __iounmap_at() into ioremap.c

> +/**
> + * __iounmap_from - Low level function to tear down the page tables
> + * for an IO mapping. This is used for mappings that
> + * are manipulated manually, like partial unmapping of
> + * PCI IOs or ISA space.
> + */
> +void __iounmap_at(void *ea, unsigned long size)

The comment doesn't mention the function name. That's why I ususally
don't even add the function name so that it doesn't get out of sync.

2019-08-14 05:40:11

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 02/10] powerpc/mm: rework io-workaround invocation.

On Tue, Aug 13, 2019 at 08:11:34PM +0000, Christophe Leroy wrote:
> ppc_md.ioremap() is only used for I/O workaround on CELL platform,
> so indirect function call can be avoided.
>
> This patch reworks the io-workaround and ioremap() functions to
> use static keys for the activation of io-workaround.
>
> When CONFIG_PPC_IO_WORKAROUNDS or CONFIG_PPC_INDIRECT_MMIO are not
> selected, the I/O workaround ioremap() voids and the static key is
> not used at all.

Why bother with the complex static key? ioremap isn't exactly a fast
path. Just make it a normal branch if enabled, with the option to
compile it out entirely as in your patch.

2019-08-14 05:52:13

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 10/10] powerpc/mm: refactor ioremap_range() and use ioremap_page_range()

Somehow this series is missing a cover letter.

While you are touching all this "fun" can you also look into killing
__ioremap? It seems to be a weird non-standard version of ioremap_prot
(probably predating ioremap_prot) that is missing a few lines of code
setting attributes that might not even be applicable for the two drivers
calling it.

2019-08-14 05:56:23

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.

On Tue, Aug 13, 2019 at 08:11:38PM +0000, Christophe Leroy wrote:
> Until vmalloc system is up and running, ioremap basically
> allocates addresses at the border of the IOREMAP area.

Note that while a few other architectures have a magic hack like powerpc
to make ioremap work before vmalloc, the normal practice would be
to explicitly use early_ioremap. I guess your change is fine for now,
but it might make sense convert powerpc to the explicit early_ioremap
scheme as well.

2019-08-14 06:12:10

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.



Le 14/08/2019 à 07:55, Christoph Hellwig a écrit :
> On Tue, Aug 13, 2019 at 08:11:38PM +0000, Christophe Leroy wrote:
>> Until vmalloc system is up and running, ioremap basically
>> allocates addresses at the border of the IOREMAP area.
>
> Note that while a few other architectures have a magic hack like powerpc
> to make ioremap work before vmalloc, the normal practice would be
> to explicitly use early_ioremap. I guess your change is fine for now,
> but it might make sense convert powerpc to the explicit early_ioremap
> scheme as well.
>

I've been looking into early_ioremap(), but IIUC early_ioremap() is for
ephemeral mappings only, it expects all early mappings to be gone at the
end of init.

PPC installs definitive early mappings (for instance for PCI). How does
that have to be handled ?

Christophe

2019-08-14 06:15:12

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.

On Wed, Aug 14, 2019 at 08:10:59AM +0200, Christophe Leroy wrote:
> > Note that while a few other architectures have a magic hack like powerpc
> > to make ioremap work before vmalloc, the normal practice would be
> > to explicitly use early_ioremap. I guess your change is fine for now,
> > but it might make sense convert powerpc to the explicit early_ioremap
> > scheme as well.
> >
>
> I've been looking into early_ioremap(), but IIUC early_ioremap() is for
> ephemeral mappings only, it expects all early mappings to be gone at the end
> of init.

Yes.

> PPC installs definitive early mappings (for instance for PCI). How does that
> have to be handled ?

Good question, and no good answer. I've just been looking at a generic
ioremap for simple architectures, and been finding all kinds of crap
and inconsistencies, and this is one of the things I noticed.

2019-08-14 06:24:46

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v1 10/10] powerpc/mm: refactor ioremap_range() and use ioremap_page_range()



Le 14/08/2019 à 07:49, Christoph Hellwig a écrit :
> Somehow this series is missing a cover letter.
>
> While you are touching all this "fun" can you also look into killing
> __ioremap? It seems to be a weird non-standard version of ioremap_prot
> (probably predating ioremap_prot) that is missing a few lines of code
> setting attributes that might not even be applicable for the two drivers
> calling it.
>

ocm_init_node() [arch/powerpc/platforms/4xx/ocm.c] calls __ioremap()
with _PAGE_EXEC set while ioremap_prot() clears _PAGE_EXEC

Christophe

2019-08-14 06:33:06

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v1 10/10] powerpc/mm: refactor ioremap_range() and use ioremap_page_range()

On Wed, Aug 14, 2019 at 08:23:54AM +0200, Christophe Leroy wrote:
> Le 14/08/2019 ? 07:49, Christoph Hellwig a ?crit?:
> > Somehow this series is missing a cover letter.
> >
> > While you are touching all this "fun" can you also look into killing
> > __ioremap? It seems to be a weird non-standard version of ioremap_prot
> > (probably predating ioremap_prot) that is missing a few lines of code
> > setting attributes that might not even be applicable for the two drivers
> > calling it.
> >
>
> ocm_init_node() [arch/powerpc/platforms/4xx/ocm.c] calls __ioremap() with
> _PAGE_EXEC set while ioremap_prot() clears _PAGE_EXEC

Indeed. But I don't see anything marking this intentional. Then again
the driver is entirely unused, so we might as well kill it off now.

2019-08-19 12:58:23

by Michael Ellerman

[permalink] [raw]
Subject: Re: [PATCH v1 07/10] powerpc/mm: move iounmap() into ioremap.c and drop __iounmap()

Christophe Leroy <[email protected]> writes:
> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
> index 0c23660522ca..57d742509cec 100644
> --- a/arch/powerpc/mm/ioremap.c
> +++ b/arch/powerpc/mm/ioremap.c
> @@ -72,3 +75,31 @@ void __iomem *ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long f
> return __ioremap_caller(addr, size, pte_pgprot(pte), caller);
> }
> EXPORT_SYMBOL(ioremap_prot);
> +
> +/*
> + * Unmap an IO region and remove it from vmalloc'd list.
> + * Access to IO memory should be serialized by driver.
> + */
> +void iounmap(volatile void __iomem *token)
> +{
> + void *addr;
> +
> + /*
> + * If mapped by BATs then there is nothing to do.
> + */
> + if (v_block_mapped((unsigned long)token))
> + return;
> +
> + if (!slab_is_available())
> + return;
> +
> + addr = (void *)((unsigned long __force)PCI_FIX_ADDR(token) & PAGE_MASK);
> + if (WARN_ON((unsigned long)addr < IOREMAP_BASE))
> + return;

This pops a bunch, as we seem to have various places that want to call
iounmap(NULL) in error paths, much like kfree().

One example:

[ 85.062269] WARNING: CPU: 6 PID: 3643 at arch/powerpc/mm/ioremap.c:97 .iounmap+0x58/0xb0
[ 85.062276] Modules linked in: snd_powermac(+) snd_pcm snd_timer snd soundcore
[ 85.062314] CPU: 6 PID: 3643 Comm: modprobe Tainted: G W 5.3.0-rc2-gcc-8.2.0-00051-ga8e8d67f314c #655
[ 85.062325] NIP: c000000000078e08 LR: c000000000078dd0 CTR: c000000000078db0
[ 85.062335] REGS: c0000000f44f6e40 TRAP: 0700 Tainted: G W (5.3.0-rc2-gcc-8.2.0-00051-ga8e8d67f314c)
[ 85.062342] MSR: 8000000002029032 <SF,VEC,EE,ME,IR,DR,RI> CR: 24228884 XER: 00000000
[ 85.062377] CFAR: c000000000339650 IRQMASK: 0
GPR00: c000000000078dd0 c0000000f44f70d0 c000000001a2ff00 0000000000000000
GPR04: c008000000336518 0000000000000000 c000000001a66b80 0000000000000001
GPR08: c0000000013296c8 c00a000080000000 0000000000000001 c00800000032ba08
GPR12: c000000000078db0 c00000003fff8e80 0000000000000004 c008000000350000
GPR16: c000000002637730 c000000000d69868 0000000000000000 c000000002637740
GPR20: c00000000197ad08 0000000000000000 0000000000000100 0000000000000028
GPR24: c0000000f736eac0 c0000000f44f7370 c0000000f5065000 c008000000336510
GPR28: c0000000026aafc8 ffffffffffffffed 0000000000000000 0000000000000000
[ 85.062554] NIP [c000000000078e08] .iounmap+0x58/0xb0
[ 85.062564] LR [c000000000078dd0] .iounmap+0x20/0xb0
[ 85.062572] Call Trace:
[ 85.062591] [c0000000f44f70d0] [c000000000078dd0] .iounmap+0x20/0xb0 (unreliable)
[ 85.062623] [c0000000f44f7150] [c008000000321e24] .snd_pmac_free+0x164/0x270 [snd_powermac]
[ 85.062709] [c0000000f44f71e0] [c008000000322fa4] .snd_pmac_new+0x884/0xf30 [snd_powermac]
[ 85.062798] [c0000000f44f72f0] [c00800000032015c] .snd_pmac_probe+0x7c/0x450 [snd_powermac]
[ 85.062849] [c0000000f44f73a0] [c0000000007b0628] .platform_drv_probe+0x68/0x100
[ 85.062863] [c0000000f44f7430] [c0000000007aca94] .really_probe+0x144/0x3c0
[ 85.062880] [c0000000f44f74d0] [c0000000007acfe0] .driver_probe_device+0x80/0x170
[ 85.062899] [c0000000f44f7560] [c0000000007a9be4] .bus_for_each_drv+0xb4/0x130
[ 85.062922] [c0000000f44f7610] [c0000000007ac89c] .__device_attach+0x11c/0x1a0
[ 85.062941] [c0000000f44f76c0] [c0000000007ab3d8] .bus_probe_device+0xe8/0x100
[ 85.062961] [c0000000f44f7750] [c0000000007a6164] .device_add+0x504/0x7d0
[ 85.062978] [c0000000f44f7820] [c0000000007b02fc] .platform_device_add+0x14c/0x310
[ 85.062994] [c0000000f44f78c0] [c0000000007b14c0] .platform_device_register_full+0x130/0x210
[ 85.063084] [c0000000f44f7940] [c00800000032b850] .alsa_card_pmac_init+0x80/0xc4 [snd_powermac]
[ 85.063106] [c0000000f44f7a10] [c000000000010e58] .do_one_initcall+0x88/0x448
[ 85.063158] [c0000000f44f7b00] [c0000000002416e4] .do_init_module+0x74/0x2e0
[ 85.063203] [c0000000f44f7ba0] [c000000000243bd4] .load_module+0x20b4/0x26d0
[ 85.063219] [c0000000f44f7cf0] [c000000000244470] .__se_sys_finit_module+0xe0/0x140
[ 85.063237] [c0000000f44f7e20] [c00000000000c46c] system_call+0x5c/0x70



I think we can just do:

void iounmap(volatile void __iomem *token)
{
void *addr;

if (!addr)
return;

...

??

cheers

2019-08-19 13:44:19

by Nicholas Piggin

[permalink] [raw]
Subject: Re: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.

Christophe Leroy's on August 14, 2019 6:11 am:
> Until vmalloc system is up and running, ioremap basically
> allocates addresses at the border of the IOREMAP area.
>
> On PPC32, addresses are allocated down from the top of the area
> while on PPC64, addresses are allocated up from the base of the
> area.

This series looks pretty good to me, but I'm not sure about this patch.

It seems like quite a small divergence in terms of code, and it looks
like the final result still has some ifdefs in these functions. Maybe
you could just keep existing behaviour for this cleanup series so it
does not risk triggering some obscure regression? Merging behaviour
could be proposed at the end.

Thanks,
Nick

2019-08-20 00:19:12

by Michael Ellerman

[permalink] [raw]
Subject: Re: [PATCH v1 08/10] powerpc/mm: move __ioremap_at() and __iounmap_at() into ioremap.c

Christophe Leroy <[email protected]> writes:

> diff --git a/arch/powerpc/mm/ioremap.c b/arch/powerpc/mm/ioremap.c
> index 57d742509cec..889ee656cf64 100644
> --- a/arch/powerpc/mm/ioremap.c
> +++ b/arch/powerpc/mm/ioremap.c
> @@ -103,3 +103,46 @@ void iounmap(volatile void __iomem *token)
> vunmap(addr);
> }
> EXPORT_SYMBOL(iounmap);
> +
> +#ifdef CONFIG_PPC64
> +/**
> + * __ioremap_at - Low level function to establish the page tables
> + * for an IO mapping
> + */
> +void __iomem *__ioremap_at(phys_addr_t pa, void *ea, unsigned long size, pgprot_t prot)
> +{
> + /* We don't support the 4K PFN hack with ioremap */
> + if (pgprot_val(prot) & H_PAGE_4K_PFN)
> + return NULL;
> +
> + if ((ea + size) >= (void *)IOREMAP_END) {
> + pr_warn("Outside the supported range\n");
> + return NULL;
> + }
> +
> + WARN_ON(pa & ~PAGE_MASK);
> + WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
> + WARN_ON(size & ~PAGE_MASK);
> +
> + if (ioremap_range((unsigned long)ea, pa, size, prot, NUMA_NO_NODE))

This doesn't build.

Adding ...

extern int ioremap_range(unsigned long ea, phys_addr_t pa, unsigned long size, pgprot_t prot, int nid);

... above, until the next patch, fixes it.

cheers

2019-08-20 00:23:34

by Michael Ellerman

[permalink] [raw]
Subject: Re: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.

Nicholas Piggin <[email protected]> writes:
> Christophe Leroy's on August 14, 2019 6:11 am:
>> Until vmalloc system is up and running, ioremap basically
>> allocates addresses at the border of the IOREMAP area.
>>
>> On PPC32, addresses are allocated down from the top of the area
>> while on PPC64, addresses are allocated up from the base of the
>> area.
>
> This series looks pretty good to me, but I'm not sure about this patch.
>
> It seems like quite a small divergence in terms of code, and it looks
> like the final result still has some ifdefs in these functions. Maybe
> you could just keep existing behaviour for this cleanup series so it
> does not risk triggering some obscure regression?

Yeah that is also my feeling. Changing it *should* work, and I haven't
found anything that breaks yet, but it's one of those things that's
bound to break something for some obscure reason.

Christophe do you think you can rework it to retain the different
allocation directions at least for now?

cheers

2019-08-20 05:11:09

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v1 05/10] powerpc/mm: Do early ioremaps from top to bottom on PPC64 too.



Le 20/08/2019 à 02:20, Michael Ellerman a écrit :
> Nicholas Piggin <[email protected]> writes:
>> Christophe Leroy's on August 14, 2019 6:11 am:
>>> Until vmalloc system is up and running, ioremap basically
>>> allocates addresses at the border of the IOREMAP area.
>>>
>>> On PPC32, addresses are allocated down from the top of the area
>>> while on PPC64, addresses are allocated up from the base of the
>>> area.
>>
>> This series looks pretty good to me, but I'm not sure about this patch.
>>
>> It seems like quite a small divergence in terms of code, and it looks
>> like the final result still has some ifdefs in these functions. Maybe
>> you could just keep existing behaviour for this cleanup series so it
>> does not risk triggering some obscure regression?
>
> Yeah that is also my feeling. Changing it *should* work, and I haven't
> found anything that breaks yet, but it's one of those things that's
> bound to break something for some obscure reason.
>
> Christophe do you think you can rework it to retain the different
> allocation directions at least for now?
>

Yes I have started addressing the comments I received, and I think for
now I'll keep all the machinery aside from the merge. Not sure yet if
I'll leave it in pgtables_32/64.c or if I'll add ioremap_32/64.c

Christophe