Skip to contentSkip to conversation

ARM: early ioremap and permanent fixmap

PATCH New Rob Herring 1 participant 4 messages May 6, 2014 Arm (32-bit)

lore
Share & tools
lore
#0 lore raw

cover ARM: early ioremap and permanent fixmap

From: Rob Herring <[email protected]>

This is an updated series based on previous work by Mark Salter and Leif Lindholm. The last version with the ARM bits is here[1]. I've added fixmap permanent mappings support to this series in order to support generic earlycon on ARM. This enables early console output before any machine hooks run and is configurable on the command line unlike earlyprintk.

This is based on the tty-next tree which has the generic earlycon support for 3.16. A git tree is available here[2].

Rob

[1] https://lkml.org/lkml/2014/2/12/608
[2] git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git arm-fixmap

Mark Salter (2):
arm: use generic fixmap.h
arm: add early_ioremap support

Rob Herring (1):
ARM: fixmap early permanent mapping support

 arch/arm/Kconfig                |  14 +++++
 arch/arm/include/asm/Kbuild     |   1 +
 arch/arm/include/asm/fixmap.h   |  51 +++++++++++-------
 arch/arm/include/asm/io.h       |   1 +
 arch/arm/include/asm/mach/map.h |   1 +
 arch/arm/kernel/setup.c         |   2 +
 arch/arm/mm/Makefile            |   2 +
 arch/arm/mm/early_ioremap.c     | 112 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/init.c              |   2 +-
 arch/arm/mm/mmu.c               |   8 +--
 10 files changed, 172 insertions(+), 22 deletions(-)
 create mode 100644 arch/arm/mm/early_ioremap.c
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/3 arm: use generic fixmap.h

From: Mark Salter <[email protected]>

ARM is different from other architectures in that fixmap pages are indexed with a positive offset from FIXADDR_START. Other architectures index with a negative offset from FIXADDR_TOP. In order to use the generic fixmap.h definitions, this patch redefines FIXADDR_TOP to be inclusive of the useable range. That is, FIXADDR_TOP is the virtual address of the topmost fixed page. The newly defined FIXADDR_END is the first virtual address past the fixed mappings.

---
 arch/arm/include/asm/fixmap.h | 29 ++++++++---------------------
 arch/arm/mm/init.c            |  2 +-
 2 files changed, 9 insertions(+), 22 deletions(-)
arch/arm/include/asm/fixmap.h +8 -21
index bbae919..68ea615 100644
@@ -14,28 +14,15 @@
  */
 
 #define FIXADDR_START		0xfff00000UL
-#define FIXADDR_TOP		0xfffe0000UL
-#define FIXADDR_SIZE		(FIXADDR_TOP - FIXADDR_START)
+#define FIXADDR_END		0xfffe0000UL
+#define FIXADDR_TOP		(FIXADDR_END - PAGE_SIZE)
 
-#define FIX_KMAP_BEGIN		0
-#define FIX_KMAP_END		(FIXADDR_SIZE >> PAGE_SHIFT)
+enum fixed_addresses {
+	FIX_KMAP_BEGIN,
+	FIX_KMAP_END = (FIXADDR_TOP - FIXADDR_START) >> PAGE_SHIFT,
+	__end_of_fixed_addresses
+};
 
-#define __fix_to_virt(x)	(FIXADDR_START + ((x) << PAGE_SHIFT))
-#define __virt_to_fix(x)	(((x) - FIXADDR_START) >> PAGE_SHIFT)
-
-extern void __this_fixmap_does_not_exist(void);
-
-static inline unsigned long fix_to_virt(const unsigned int idx)
-{
-	if (idx >= FIX_KMAP_END)
-		__this_fixmap_does_not_exist();
-	return __fix_to_virt(idx);
-}
-
-static inline unsigned int virt_to_fix(const unsigned long vaddr)
-{
-	BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
-	return __virt_to_fix(vaddr);
-}
+#include <asm-generic/fixmap.h>
 
 #endif
arch/arm/mm/init.c +1 -1
index 2a77ba8..91a4682 100644
@@ -578,7 +578,7 @@ void __init mem_init(void)
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 #endif
-			MLK(FIXADDR_START, FIXADDR_TOP),
+			MLK(FIXADDR_START, FIXADDR_END),
 			MLM(VMALLOC_START, VMALLOC_END),
 			MLM(PAGE_OFFSET, (unsigned long)high_memory),
 #ifdef CONFIG_HIGHMEM
Signature · 1 line
1.9.1
#2 lore raw

PATCH 2/3 arm: add early_ioremap support

In reply to Rob Herring

From: Mark Salter <[email protected]>

This patch uses the generic early_ioremap code to implement early_ioremap for ARM. The ARM-specific bits come mostly from an earlier patch from Leif Lindholm <[email protected]> here:

https://lkml.org/lkml/2013/10/3/279

[robh: minor re-work in prep for permanent mappings. Fix bug in page table allocation size. Rework CONFIG_MMU dependency.]

---
 arch/arm/Kconfig              | 11 ++++++
 arch/arm/include/asm/Kbuild   |  1 +
 arch/arm/include/asm/fixmap.h | 21 ++++++++++
 arch/arm/include/asm/io.h     |  1 +
 arch/arm/kernel/setup.c       |  2 +
 arch/arm/mm/Makefile          |  2 +
 arch/arm/mm/early_ioremap.c   | 90 +++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/mmu.c             |  2 +
 8 files changed, 130 insertions(+)
 create mode 100644 arch/arm/mm/early_ioremap.c
arch/arm/Kconfig +11 -0
index db3c541..b33c68b 100644
@@ -1891,6 +1891,17 @@ config UACCESS_WITH_MEMCPY
 	  However, if the CPU data cache is using a write-allocate mode,
 	  this option is unlikely to provide any performance gain.
 
+config EARLY_IOREMAP
+	bool "Provide early_ioremap() support for kernel initialization"
+	depends on MMU
+	select GENERIC_EARLY_IOREMAP
+	help
+	  Provide a mechanism for kernel initialisation code to temporarily
+	  map, in a highmem-agnostic way, memory pages in before ioremap()
+	  and friends are available (before paging_init() has run). It uses
+	  the same virtual memory range as kmap so all early mappings must
+	  be unmapped before paging_init() is called.
+
 config SECCOMP
 	bool
 	prompt "Enable seccomp to safely compute untrusted bytecode"
arch/arm/include/asm/Kbuild +1 -0
index 23e728e..ec64b55 100644
@@ -4,6 +4,7 @@ generic-y += auxvec.h
 generic-y += bitsperlong.h
 generic-y += cputime.h
 generic-y += current.h
+generic-y += early_ioremap.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
arch/arm/include/asm/fixmap.h +21 -0
index 68ea615..e36020c 100644
@@ -21,8 +21,29 @@ enum fixed_addresses {
 	FIX_KMAP_BEGIN,
 	FIX_KMAP_END = (FIXADDR_TOP - FIXADDR_START) >> PAGE_SHIFT,
 	__end_of_fixed_addresses
+/*
+ * 224 temporary boot-time mappings, used by early_ioremap(),
+ * before ioremap() is functional.
+ *
+ * (P)re-using the FIXADDR region, which is used for highmem
+ * later on, and statically aligned to 1MB.
+ */
+#define NR_FIX_BTMAPS		32
+#define FIX_BTMAPS_SLOTS	7
+#define TOTAL_FIX_BTMAPS	(NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS - FIX_KMAP_BEGIN)
+#define FIX_BTMAP_END		FIX_KMAP_BEGIN
+#define FIX_BTMAP_BEGIN		(FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1)
 };
 
+#define FIXMAP_PAGE_COMMON (L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN)
+
+#define FIXMAP_PAGE_NORMAL (FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK)
+#define FIXMAP_PAGE_IO	   (FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED | L_PTE_DIRTY)
+#define FIXMAP_PAGE_NOCACHE FIXMAP_PAGE_IO
+
+extern void __early_set_fixmap(enum fixed_addresses idx,
+			       phys_addr_t phys, pgprot_t flags);
+
 #include <asm-generic/fixmap.h>
 
 #endif
arch/arm/include/asm/io.h +1 -0
index 8aa4cca..637e0cd 100644
@@ -28,6 +28,7 @@
 #include <asm/byteorder.h>
 #include <asm/memory.h>
 #include <asm-generic/pci_iomap.h>
+#include <asm/early_ioremap.h>
 #include <xen/xen.h>
 
 /*
arch/arm/kernel/setup.c +2 -0
index 50e198c..7882f04 100644
@@ -30,6 +30,7 @@
 #include <linux/bug.h>
 #include <linux/compiler.h>
 #include <linux/sort.h>
+#include <linux/io.h>
 
 #include <asm/unified.h>
 #include <asm/cp15.h>
@@ -883,6 +884,7 @@ void __init setup_arch(char **cmdline_p)
 	const struct machine_desc *mdesc;
 
 	setup_processor();
+	early_ioremap_init();
 	mdesc = setup_machine_fdt(__atags_pointer);
 	if (!mdesc)
 		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
arch/arm/mm/Makefile +2 -0
index 7f39ce2..c6b7b5e 100644
@@ -12,6 +12,8 @@ ifneq ($(CONFIG_MMU),y)
 obj-y				+= nommu.o
 endif
 
+obj-$(CONFIG_EARLY_IOREMAP)	+= early_ioremap.o
+
 obj-$(CONFIG_ARM_PTDUMP)	+= dump.o
 obj-$(CONFIG_MODULES)		+= proc-syms.o
 
arch/arm/mm/early_ioremap.c new file +90 -0

90 lines not on this page · raw message

arch/arm/mm/mmu.c +2 -0
index b68c6b2..9576f87 100644
@@ -35,6 +35,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/pci.h>
+#include <asm/early_ioremap.h>
 
 #include "mm.h"
 #include "tcm.h"
@@ -1508,6 +1509,7 @@ void __init paging_init(const struct machine_desc *mdesc)
 	prepare_page_table();
 	map_lowmem();
 	dma_contiguous_remap();
+	early_ioremap_reset();
 	devicemaps_init(mdesc);
 	kmap_init();
 	tcm_init();
Signature · 1 line
1.9.1
#3 lore raw

PATCH 3/3 ARM: fixmap early permanent mapping support

In reply to Rob Herring

From: Rob Herring <[email protected]>

This adds early permanent mapping support to fixmap early mappings. Unlike early_ioremap mappings, permanent mappings are kept after paging_init. Each permament mapping must be explicitly added. Initially, the only permanent mapping is for early console.

The early pmd and ptes are still destroyed and recreated since the attributes may change as the memory types are initialized.

Cc Mark Salter <[email protected]>
Cc Russell King <[email protected]>
---
 arch/arm/Kconfig                |  3 +++
 arch/arm/include/asm/fixmap.h   |  7 +++++++
 arch/arm/include/asm/mach/map.h |  1 +
 arch/arm/mm/early_ioremap.c     | 22 ++++++++++++++++++++++
 arch/arm/mm/mmu.c               |  6 +++---
 5 files changed, 36 insertions(+), 3 deletions(-)
arch/arm/Kconfig +3 -0
index b33c68b..f15a096 100644
@@ -188,6 +188,9 @@ config ARCH_HAS_CPUFREQ
 config ARCH_HAS_BANDGAP
 	bool
 
+config FIX_EARLYCON_MEM
+	def_bool EARLY_IOREMAP
+
 config GENERIC_HWEIGHT
 	bool
 	default y
arch/arm/include/asm/fixmap.h +7 -0
index e36020c..3324599 100644
@@ -1,6 +1,9 @@
 #ifndef _ASM_FIXMAP_H
 #define _ASM_FIXMAP_H
 
+#include <linux/kernel.h>
+#include <asm/pgtable.h>
+
 /*
  * Nothing too fancy for now.
  *
@@ -18,6 +21,8 @@
 #define FIXADDR_TOP		(FIXADDR_END - PAGE_SIZE)
 
 enum fixed_addresses {
+	FIX_EARLYCON_MEM_BASE,
+	__end_of_permanent_fixed_addresses,
 	FIX_KMAP_BEGIN,
 	FIX_KMAP_END = (FIXADDR_TOP - FIXADDR_START) >> PAGE_SHIFT,
 	__end_of_fixed_addresses
@@ -44,6 +49,8 @@ enum fixed_addresses {
 extern void __early_set_fixmap(enum fixed_addresses idx,
 			       phys_addr_t phys, pgprot_t flags);
 
+#define __set_fixmap __early_set_fixmap
+
 #include <asm-generic/fixmap.h>
 
 #endif
arch/arm/include/asm/mach/map.h +1 -0
index f98c7f3..cc5ed24 100644
@@ -39,6 +39,7 @@ enum {
 };
 
 #ifdef CONFIG_MMU
+extern void create_mapping(struct map_desc *);
 extern void iotable_init(struct map_desc *, int);
 extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
 				  void *caller);
arch/arm/mm/early_ioremap.c +22 -0
index 0258a20..cf143115 100644
@@ -86,5 +86,27 @@ void __init __early_set_fixmap(enum fixed_addresses idx,
 
 void __init early_ioremap_shutdown(void)
 {
+	int i;
+
 	pmd_clear(early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)));
+
+	/* Create new entries for permanent mappings */
+	for (i = 0; i < __end_of_permanent_fixed_addresses; i++) {
+		pte_t *pte;
+		struct map_desc map;
+
+		map.virtual = fix_to_virt(i);
+		pte = early_ioremap_pte(map.virtual);
+
+		/* Only i/o device mappings are supported ATM */
+		if (pte_none(*pte) ||
+		    (pte_val(*pte) & L_PTE_MT_MASK) != L_PTE_MT_DEV_SHARED)
+			continue;
+
+		map.pfn = pte_pfn(*pte);
+		map.type = MT_DEVICE;
+		map.length = PAGE_SIZE;
+
+		create_mapping(&map);
+	}
 }
arch/arm/mm/mmu.c +3 -3
index 9576f87..b2187f1 100644
@@ -829,7 +829,7 @@ static void __init create_36bit_mapping(struct map_desc *md,
  * offsets, and we take full advantage of sections and
  * supersections.
  */
-static void __init create_mapping(struct map_desc *md)
+void __init create_mapping(struct map_desc *md)
 {
 	unsigned long addr, length, end;
 	phys_addr_t phys;
@@ -844,7 +844,7 @@ static void __init create_mapping(struct map_desc *md)
 	}
 
 	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
-	    md->virtual >= PAGE_OFFSET &&
+	    md->virtual >= PAGE_OFFSET && md->virtual < 0xffe00000 &&
 	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
 		printk(KERN_WARNING "BUG: mapping for 0x%08llx"
 		       " at 0x%08lx out of vmalloc space\n",
@@ -1271,7 +1271,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
 
 	early_trap_init(vectors);
 
-	for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
+	for (addr = VMALLOC_START; addr < 0xffe00000; addr += PMD_SIZE)
 		pmd_clear(pmd_off_k(addr));
 
 	/*
Signature · 1 line
1.9.1