[PATCH] openrisc: Implement fixmap to fix eralycon

Stafford Horne posted 1 patch 2 months ago
arch/openrisc/Kconfig              |  3 +++
arch/openrisc/include/asm/fixmap.h | 21 +++++-------------
arch/openrisc/mm/init.c            | 34 ++++++++++++++++++++++++++++++
3 files changed, 42 insertions(+), 16 deletions(-)
[PATCH] openrisc: Implement fixmap to fix eralycon
Posted by Stafford Horne 2 months ago
With commit 53c98e35dcbc ("openrisc: mm: remove unneeded early ioremap
code") it was commented that early ioremap was not used in OpenRISC.  I
acked this but was wrong.  Earlycon now fails with the below trace:

    Kernel command line: earlycon
    ------------[ cut here ]------------
    WARNING: CPU: 0 PID: 0 at mm/ioremap.c:23
    generic_ioremap_prot+0x118/0x130
    Modules linked in:
    CPU: 0 UID: 0 PID: 0 Comm: swapper Not tainted
    6.11.0-rc5-00001-gce02fd891c38-dirty #141
    Call trace:
    [<(ptrval)>] dump_stack_lvl+0x7c/0x9c
    [<(ptrval)>] dump_stack+0x1c/0x2c
    [<(ptrval)>] __warn+0xb4/0x108
    [<(ptrval)>] ? generic_ioremap_prot+0x118/0x130
    [<(ptrval)>] warn_slowpath_fmt+0x60/0x98
    [<(ptrval)>] generic_ioremap_prot+0x118/0x130
    [<(ptrval)>] ioremap_prot+0x20/0x30
    [<(ptrval)>] of_setup_earlycon+0xd4/0x2e0
    [<(ptrval)>] early_init_dt_scan_chosen_stdout+0x18c/0x1c8
    [<(ptrval)>] param_setup_earlycon+0x3c/0x60
    [<(ptrval)>] do_early_param+0xb0/0x118
    [<(ptrval)>] parse_args+0x184/0x4b8
    [<(ptrval)>] ? start_kernel+0x0/0x78c
    [<(ptrval)>] parse_early_options+0x40/0x50
    [<(ptrval)>] ? do_early_param+0x0/0x118
    [<(ptrval)>] parse_early_param+0x48/0x68
    [<(ptrval)>] ? start_kernel+0x318/0x78c
    [<(ptrval)>] ? start_kernel+0x0/0x78c
    ---[ end trace 0000000000000000 ]---

To fix this we could either implement early_ioremap or implement fixmap.
In this patch we choose the later option of implementing basic fixmap
support.

While fixing this we also remove the old FIX_IOREMAP slots that were
used by early ioremap code.  That code was also removed by commit
53c98e35dcbc ("openrisc: mm: remove unneeded early ioremap code") but
these definitions were not cleaned up.

Fixes: 53c98e35dcbc ("openrisc: mm: remove unneeded early ioremap code")
Signed-off-by: Stafford Horne <shorne@gmail.com>
---
 arch/openrisc/Kconfig              |  3 +++
 arch/openrisc/include/asm/fixmap.h | 21 +++++-------------
 arch/openrisc/mm/init.c            | 34 ++++++++++++++++++++++++++++++
 3 files changed, 42 insertions(+), 16 deletions(-)

diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 69c0258700b2..3279ef457c57 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -65,6 +65,9 @@ config STACKTRACE_SUPPORT
 config LOCKDEP_SUPPORT
 	def_bool  y
 
+config FIX_EARLYCON_MEM
+	def_bool y
+
 menu "Processor type and features"
 
 choice
diff --git a/arch/openrisc/include/asm/fixmap.h b/arch/openrisc/include/asm/fixmap.h
index ecdb98a5839f..aaa6a26a3e92 100644
--- a/arch/openrisc/include/asm/fixmap.h
+++ b/arch/openrisc/include/asm/fixmap.h
@@ -26,29 +26,18 @@
 #include <linux/bug.h>
 #include <asm/page.h>
 
-/*
- * On OpenRISC we use these special fixed_addresses for doing ioremap
- * early in the boot process before memory initialization is complete.
- * This is used, in particular, by the early serial console code.
- *
- * It's not really 'fixmap', per se, but fits loosely into the same
- * paradigm.
- */
 enum fixed_addresses {
-	/*
-	 * FIX_IOREMAP entries are useful for mapping physical address
-	 * space before ioremap() is useable, e.g. really early in boot
-	 * before kmalloc() is working.
-	 */
-#define FIX_N_IOREMAPS  32
-	FIX_IOREMAP_BEGIN,
-	FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1,
+	FIX_EARLYCON_MEM_BASE,
 	__end_of_fixed_addresses
 };
 
 #define FIXADDR_SIZE		(__end_of_fixed_addresses << PAGE_SHIFT)
 /* FIXADDR_BOTTOM might be a better name here... */
 #define FIXADDR_START		(FIXADDR_TOP - FIXADDR_SIZE)
+#define FIXMAP_PAGE_IO		PAGE_KERNEL_NOCACHE
+
+extern void __set_fixmap(enum fixed_addresses idx,
+			 phys_addr_t phys, pgprot_t flags);
 
 #include <asm-generic/fixmap.h>
 
diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c
index 1dcd78c8f0e9..7397d18c95d7 100644
--- a/arch/openrisc/mm/init.c
+++ b/arch/openrisc/mm/init.c
@@ -207,6 +207,40 @@ void __init mem_init(void)
 	return;
 }
 
+static int __init map_page(unsigned long va, phys_addr_t pa, int flags)
+{
+	p4d_t *p4d;
+	pud_t *pud;
+	pmd_t *pd;
+	pte_t *pg;
+	int err = -ENOMEM;
+
+	p4d = p4d_offset(pgd_offset_k(va), va);
+	pud = pud_offset(p4d, va);
+	pd = pmd_offset(pud, va);
+	pg = pte_alloc_kernel(pd, va);
+
+	if (pg != NULL) {
+		err = 0;
+		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
+				__pgprot(flags)));
+	}
+	return err;
+}
+
+void __init __set_fixmap(enum fixed_addresses idx,
+			 phys_addr_t phys, pgprot_t prot)
+{
+	unsigned long address = __fix_to_virt(idx);
+
+	if (idx >= __end_of_fixed_addresses) {
+		BUG();
+		return;
+	}
+
+	map_page(address, phys, pgprot_val(prot));
+}
+
 static const pgprot_t protection_map[16] = {
 	[VM_NONE]					= PAGE_NONE,
 	[VM_READ]					= PAGE_READONLY_X,
-- 
2.44.0
Re: [PATCH] openrisc: Implement fixmap to fix eralycon
Posted by Stafford Horne 2 months ago
Review from myself, I sent this one out pretty quickly just to get some
conversation started.

In the subject if should be 'earlycon' no 'eralycon'.

On Fri, Sep 27, 2024 at 03:56:56PM +0100, Stafford Horne wrote:
> With commit 53c98e35dcbc ("openrisc: mm: remove unneeded early ioremap
> code") it was commented that early ioremap was not used in OpenRISC.  I
> acked this but was wrong.  Earlycon now fails with the below trace:
..
>
> To fix this we could either implement early_ioremap or implement fixmap.
> In this patch we choose the later option of implementing basic fixmap
> support.
> 
> While fixing this we also remove the old FIX_IOREMAP slots that were
> used by early ioremap code.  That code was also removed by commit
> 53c98e35dcbc ("openrisc: mm: remove unneeded early ioremap code") but
> these definitions were not cleaned up.
> 
> Fixes: 53c98e35dcbc ("openrisc: mm: remove unneeded early ioremap code")
> Signed-off-by: Stafford Horne <shorne@gmail.com>
> ---
>  arch/openrisc/Kconfig              |  3 +++
>  arch/openrisc/include/asm/fixmap.h | 21 +++++-------------
>  arch/openrisc/mm/init.c            | 34 ++++++++++++++++++++++++++++++
>  3 files changed, 42 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
> index 69c0258700b2..3279ef457c57 100644
> --- a/arch/openrisc/Kconfig
> +++ b/arch/openrisc/Kconfig
> @@ -65,6 +65,9 @@ config STACKTRACE_SUPPORT
>  config LOCKDEP_SUPPORT
>  	def_bool  y
>  
> +config FIX_EARLYCON_MEM
> +	def_bool y
> +
>  menu "Processor type and features"
>  
>  choice
> diff --git a/arch/openrisc/include/asm/fixmap.h b/arch/openrisc/include/asm/fixmap.h
> index ecdb98a5839f..aaa6a26a3e92 100644
> --- a/arch/openrisc/include/asm/fixmap.h
> +++ b/arch/openrisc/include/asm/fixmap.h
> @@ -26,29 +26,18 @@
>  #include <linux/bug.h>
>  #include <asm/page.h>
>  
> -/*
> - * On OpenRISC we use these special fixed_addresses for doing ioremap
> - * early in the boot process before memory initialization is complete.
> - * This is used, in particular, by the early serial console code.
> - *
> - * It's not really 'fixmap', per se, but fits loosely into the same
> - * paradigm.
> - */
>  enum fixed_addresses {
> -	/*
> -	 * FIX_IOREMAP entries are useful for mapping physical address
> -	 * space before ioremap() is useable, e.g. really early in boot
> -	 * before kmalloc() is working.
> -	 */
> -#define FIX_N_IOREMAPS  32
> -	FIX_IOREMAP_BEGIN,
> -	FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1,
> +	FIX_EARLYCON_MEM_BASE,
>  	__end_of_fixed_addresses
>  };
>  
>  #define FIXADDR_SIZE		(__end_of_fixed_addresses << PAGE_SHIFT)
>  /* FIXADDR_BOTTOM might be a better name here... */
>  #define FIXADDR_START		(FIXADDR_TOP - FIXADDR_SIZE)
> +#define FIXMAP_PAGE_IO		PAGE_KERNEL_NOCACHE
> +
> +extern void __set_fixmap(enum fixed_addresses idx,
> +			 phys_addr_t phys, pgprot_t flags);
>  
>  #include <asm-generic/fixmap.h>
>  
> diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c
> index 1dcd78c8f0e9..7397d18c95d7 100644
> --- a/arch/openrisc/mm/init.c
> +++ b/arch/openrisc/mm/init.c
> @@ -207,6 +207,40 @@ void __init mem_init(void)
>  	return;
>  }
>  
> +static int __init map_page(unsigned long va, phys_addr_t pa, int flags)
> +{
> +	p4d_t *p4d;
> +	pud_t *pud;
> +	pmd_t *pd;
> +	pte_t *pg;
> +	int err = -ENOMEM;
> +
> +	p4d = p4d_offset(pgd_offset_k(va), va);
> +	pud = pud_offset(p4d, va);
> +	pd = pmd_offset(pud, va);
> +	pg = pte_alloc_kernel(pd, va);
> +
> +	if (pg != NULL) {
> +		err = 0;
> +		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
> +				__pgprot(flags)));

We maybe need to do something like flush tlb here, but since this is only used
by earlycon and before any io access is made it may be ok.

> +	}
> +	return err;
> +}
> +
> +void __init __set_fixmap(enum fixed_addresses idx,
> +			 phys_addr_t phys, pgprot_t prot)
> +{
> +	unsigned long address = __fix_to_virt(idx);
> +
> +	if (idx >= __end_of_fixed_addresses) {
> +		BUG();
> +		return;
> +	}
> +
> +	map_page(address, phys, pgprot_val(prot));
> +}
> +
>  static const pgprot_t protection_map[16] = {
>  	[VM_NONE]					= PAGE_NONE,
>  	[VM_READ]					= PAGE_READONLY_X,
> -- 
> 2.44.0
>