aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Salter <msalter@redhat.com>2014-04-07 18:39:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-07 19:36:15 -0400
commitbf4b558eba920a38f91beb5ee62a8ce2628c92f7 (patch)
tree322210246d72cf0ce2a700709da443022e9dac6b
parent0bf757c73d6612d3d279de3f61b35062aa9c8b1d (diff)
arm64: add early_ioremap support
Add support for early IO or memory mappings which are needed before the normal ioremap() is usable. This also adds fixmap support for permanent fixed mappings such as that used by the earlyprintk device register region. Signed-off-by: Mark Salter <msalter@redhat.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Borislav Petkov <borislav.petkov@amd.com> Cc: Dave Young <dyoung@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/arm64/memory.txt4
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/include/asm/Kbuild1
-rw-r--r--arch/arm64/include/asm/fixmap.h67
-rw-r--r--arch/arm64/include/asm/io.h1
-rw-r--r--arch/arm64/include/asm/memory.h2
-rw-r--r--arch/arm64/kernel/early_printk.c8
-rw-r--r--arch/arm64/kernel/head.S9
-rw-r--r--arch/arm64/kernel/setup.c2
-rw-r--r--arch/arm64/mm/ioremap.c85
-rw-r--r--arch/arm64/mm/mmu.c41
11 files changed, 169 insertions, 52 deletions
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
index 85e24c4f215c..d50fa618371b 100644
--- a/Documentation/arm64/memory.txt
+++ b/Documentation/arm64/memory.txt
@@ -39,7 +39,7 @@ ffffffbffa000000 ffffffbffaffffff 16MB PCI I/O space
39 39
40ffffffbffb000000 ffffffbffbbfffff 12MB [guard] 40ffffffbffb000000 ffffffbffbbfffff 12MB [guard]
41 41
42ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device 42ffffffbffbc00000 ffffffbffbdfffff 2MB fixed mappings
43 43
44ffffffbffbe00000 ffffffbffbffffff 2MB [guard] 44ffffffbffbe00000 ffffffbffbffffff 2MB [guard]
45 45
@@ -66,7 +66,7 @@ fffffdfffa000000 fffffdfffaffffff 16MB PCI I/O space
66 66
67fffffdfffb000000 fffffdfffbbfffff 12MB [guard] 67fffffdfffb000000 fffffdfffbbfffff 12MB [guard]
68 68
69fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk device 69fffffdfffbc00000 fffffdfffbdfffff 2MB fixed mappings
70 70
71fffffdfffbe00000 fffffdfffbffffff 2MB [guard] 71fffffdfffbe00000 fffffdfffbffffff 2MB [guard]
72 72
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8079a23e2701..e6e4d3749a6e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -17,6 +17,7 @@ config ARM64
17 select GENERIC_CLOCKEVENTS 17 select GENERIC_CLOCKEVENTS
18 select GENERIC_CLOCKEVENTS_BROADCAST if SMP 18 select GENERIC_CLOCKEVENTS_BROADCAST if SMP
19 select GENERIC_CPU_AUTOPROBE 19 select GENERIC_CPU_AUTOPROBE
20 select GENERIC_EARLY_IOREMAP
20 select GENERIC_IOMAP 21 select GENERIC_IOMAP
21 select GENERIC_IRQ_PROBE 22 select GENERIC_IRQ_PROBE
22 select GENERIC_IRQ_SHOW 23 select GENERIC_IRQ_SHOW
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 4bca4923fc0b..83f71b3004a8 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -10,6 +10,7 @@ generic-y += delay.h
10generic-y += div64.h 10generic-y += div64.h
11generic-y += dma.h 11generic-y += dma.h
12generic-y += emergency-restart.h 12generic-y += emergency-restart.h
13generic-y += early_ioremap.h
13generic-y += errno.h 14generic-y += errno.h
14generic-y += ftrace.h 15generic-y += ftrace.h
15generic-y += hash.h 16generic-y += hash.h
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
new file mode 100644
index 000000000000..5f7bfe6df723
--- /dev/null
+++ b/arch/arm64/include/asm/fixmap.h
@@ -0,0 +1,67 @@
1/*
2 * fixmap.h: compile-time virtual memory allocation
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 1998 Ingo Molnar
9 * Copyright (C) 2013 Mark Salter <msalter@redhat.com>
10 *
11 * Adapted from arch/x86_64 version.
12 *
13 */
14
15#ifndef _ASM_ARM64_FIXMAP_H
16#define _ASM_ARM64_FIXMAP_H
17
18#ifndef __ASSEMBLY__
19#include <linux/kernel.h>
20#include <asm/page.h>
21
22/*
23 * Here we define all the compile-time 'special' virtual
24 * addresses. The point is to have a constant address at
25 * compile time, but to set the physical address only
26 * in the boot process.
27 *
28 * These 'compile-time allocated' memory buffers are
29 * page-sized. Use set_fixmap(idx,phys) to associate
30 * physical memory with fixmap indices.
31 *
32 */
33enum fixed_addresses {
34 FIX_EARLYCON_MEM_BASE,
35 __end_of_permanent_fixed_addresses,
36
37 /*
38 * Temporary boot-time mappings, used by early_ioremap(),
39 * before ioremap() is functional.
40 */
41#ifdef CONFIG_ARM64_64K_PAGES
42#define NR_FIX_BTMAPS 4
43#else
44#define NR_FIX_BTMAPS 64
45#endif
46#define FIX_BTMAPS_SLOTS 7
47#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
48
49 FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
50 FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
51 __end_of_fixed_addresses
52};
53
54#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
55#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
56
57#define FIXMAP_PAGE_IO __pgprot(PROT_DEVICE_nGnRE)
58
59extern void __early_set_fixmap(enum fixed_addresses idx,
60 phys_addr_t phys, pgprot_t flags);
61
62#define __set_fixmap __early_set_fixmap
63
64#include <asm-generic/fixmap.h>
65
66#endif /* !__ASSEMBLY__ */
67#endif /* _ASM_ARM64_FIXMAP_H */
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 7846a6bb0833..a1bef78f0303 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -27,6 +27,7 @@
27#include <asm/byteorder.h> 27#include <asm/byteorder.h>
28#include <asm/barrier.h> 28#include <asm/barrier.h>
29#include <asm/pgtable.h> 29#include <asm/pgtable.h>
30#include <asm/early_ioremap.h>
30 31
31#include <xen/xen.h> 32#include <xen/xen.h>
32 33
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 9dc5dc39fded..e94f9458aa6f 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -49,7 +49,7 @@
49#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) 49#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
50#define MODULES_END (PAGE_OFFSET) 50#define MODULES_END (PAGE_OFFSET)
51#define MODULES_VADDR (MODULES_END - SZ_64M) 51#define MODULES_VADDR (MODULES_END - SZ_64M)
52#define EARLYCON_IOBASE (MODULES_VADDR - SZ_4M) 52#define FIXADDR_TOP (MODULES_VADDR - SZ_2M - PAGE_SIZE)
53#define TASK_SIZE_64 (UL(1) << VA_BITS) 53#define TASK_SIZE_64 (UL(1) << VA_BITS)
54 54
55#ifdef CONFIG_COMPAT 55#ifdef CONFIG_COMPAT
diff --git a/arch/arm64/kernel/early_printk.c b/arch/arm64/kernel/early_printk.c
index fbb6e1843659..ffbbdde7aba1 100644
--- a/arch/arm64/kernel/early_printk.c
+++ b/arch/arm64/kernel/early_printk.c
@@ -26,6 +26,8 @@
26#include <linux/amba/serial.h> 26#include <linux/amba/serial.h>
27#include <linux/serial_reg.h> 27#include <linux/serial_reg.h>
28 28
29#include <asm/fixmap.h>
30
29static void __iomem *early_base; 31static void __iomem *early_base;
30static void (*printch)(char ch); 32static void (*printch)(char ch);
31 33
@@ -141,8 +143,10 @@ static int __init setup_early_printk(char *buf)
141 } 143 }
142 /* no options parsing yet */ 144 /* no options parsing yet */
143 145
144 if (paddr) 146 if (paddr) {
145 early_base = early_io_map(paddr, EARLYCON_IOBASE); 147 set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr);
148 early_base = (void __iomem *)fix_to_virt(FIX_EARLYCON_MEM_BASE);
149 }
146 150
147 printch = match->printch; 151 printch = match->printch;
148 early_console = &early_console_dev; 152 early_console = &early_console_dev;
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 61035d6814cb..1fe5d8d2bdfd 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -404,7 +404,7 @@ ENDPROC(__calc_phys_offset)
404 * - identity mapping to enable the MMU (low address, TTBR0) 404 * - identity mapping to enable the MMU (low address, TTBR0)
405 * - first few MB of the kernel linear mapping to jump to once the MMU has 405 * - first few MB of the kernel linear mapping to jump to once the MMU has
406 * been enabled, including the FDT blob (TTBR1) 406 * been enabled, including the FDT blob (TTBR1)
407 * - UART mapping if CONFIG_EARLY_PRINTK is enabled (TTBR1) 407 * - pgd entry for fixed mappings (TTBR1)
408 */ 408 */
409__create_page_tables: 409__create_page_tables:
410 pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses 410 pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses
@@ -461,15 +461,12 @@ __create_page_tables:
461 sub x6, x6, #1 // inclusive range 461 sub x6, x6, #1 // inclusive range
462 create_block_map x0, x7, x3, x5, x6 462 create_block_map x0, x7, x3, x5, x6
4631: 4631:
464#ifdef CONFIG_EARLY_PRINTK
465 /* 464 /*
466 * Create the pgd entry for the UART mapping. The full mapping is done 465 * Create the pgd entry for the fixed mappings.
467 * later based earlyprintk kernel parameter.
468 */ 466 */
469 ldr x5, =EARLYCON_IOBASE // UART virtual address 467 ldr x5, =FIXADDR_TOP // Fixed mapping virtual address
470 add x0, x26, #2 * PAGE_SIZE // section table address 468 add x0, x26, #2 * PAGE_SIZE // section table address
471 create_pgd_entry x26, x0, x5, x6, x7 469 create_pgd_entry x26, x0, x5, x6, x7
472#endif
473 ret 470 ret
474ENDPROC(__create_page_tables) 471ENDPROC(__create_page_tables)
475 .ltorg 472 .ltorg
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 20830d1afbb6..720853f70b6b 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -42,6 +42,7 @@
42#include <linux/of_fdt.h> 42#include <linux/of_fdt.h>
43#include <linux/of_platform.h> 43#include <linux/of_platform.h>
44 44
45#include <asm/fixmap.h>
45#include <asm/cputype.h> 46#include <asm/cputype.h>
46#include <asm/elf.h> 47#include <asm/elf.h>
47#include <asm/cputable.h> 48#include <asm/cputable.h>
@@ -361,6 +362,7 @@ void __init setup_arch(char **cmdline_p)
361 *cmdline_p = boot_command_line; 362 *cmdline_p = boot_command_line;
362 363
363 init_mem_pgprot(); 364 init_mem_pgprot();
365 early_ioremap_init();
364 366
365 parse_early_param(); 367 parse_early_param();
366 368
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
index 2bb1d586664c..7ec328392ae0 100644
--- a/arch/arm64/mm/ioremap.c
+++ b/arch/arm64/mm/ioremap.c
@@ -25,6 +25,10 @@
25#include <linux/vmalloc.h> 25#include <linux/vmalloc.h>
26#include <linux/io.h> 26#include <linux/io.h>
27 27
28#include <asm/fixmap.h>
29#include <asm/tlbflush.h>
30#include <asm/pgalloc.h>
31
28static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, 32static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
29 pgprot_t prot, void *caller) 33 pgprot_t prot, void *caller)
30{ 34{
@@ -98,3 +102,84 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
98 __builtin_return_address(0)); 102 __builtin_return_address(0));
99} 103}
100EXPORT_SYMBOL(ioremap_cache); 104EXPORT_SYMBOL(ioremap_cache);
105
106#ifndef CONFIG_ARM64_64K_PAGES
107static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
108#endif
109
110static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
111{
112 pgd_t *pgd;
113 pud_t *pud;
114
115 pgd = pgd_offset_k(addr);
116 BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
117
118 pud = pud_offset(pgd, addr);
119 BUG_ON(pud_none(*pud) || pud_bad(*pud));
120
121 return pmd_offset(pud, addr);
122}
123
124static inline pte_t * __init early_ioremap_pte(unsigned long addr)
125{
126 pmd_t *pmd = early_ioremap_pmd(addr);
127
128 BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
129
130 return pte_offset_kernel(pmd, addr);
131}
132
133void __init early_ioremap_init(void)
134{
135 pmd_t *pmd;
136
137 pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
138#ifndef CONFIG_ARM64_64K_PAGES
139 /* need to populate pmd for 4k pagesize only */
140 pmd_populate_kernel(&init_mm, pmd, bm_pte);
141#endif
142 /*
143 * The boot-ioremap range spans multiple pmds, for which
144 * we are not prepared:
145 */
146 BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
147 != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
148
149 if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) {
150 WARN_ON(1);
151 pr_warn("pmd %p != %p\n",
152 pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END)));
153 pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
154 fix_to_virt(FIX_BTMAP_BEGIN));
155 pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
156 fix_to_virt(FIX_BTMAP_END));
157
158 pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
159 pr_warn("FIX_BTMAP_BEGIN: %d\n",
160 FIX_BTMAP_BEGIN);
161 }
162
163 early_ioremap_setup();
164}
165
166void __init __early_set_fixmap(enum fixed_addresses idx,
167 phys_addr_t phys, pgprot_t flags)
168{
169 unsigned long addr = __fix_to_virt(idx);
170 pte_t *pte;
171
172 if (idx >= __end_of_fixed_addresses) {
173 BUG();
174 return;
175 }
176
177 pte = early_ioremap_pte(addr);
178
179 if (pgprot_val(flags))
180 set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
181 else {
182 pte_clear(&init_mm, addr, pte);
183 flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
184 }
185}
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index ba259a0e385e..6b7e89569a3a 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -260,47 +260,6 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
260 } while (pgd++, addr = next, addr != end); 260 } while (pgd++, addr = next, addr != end);
261} 261}
262 262
263#ifdef CONFIG_EARLY_PRINTK
264/*
265 * Create an early I/O mapping using the pgd/pmd entries already populated
266 * in head.S as this function is called too early to allocated any memory. The
267 * mapping size is 2MB with 4KB pages or 64KB or 64KB pages.
268 */
269void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
270{
271 unsigned long size, mask;
272 bool page64k = IS_ENABLED(CONFIG_ARM64_64K_PAGES);
273 pgd_t *pgd;
274 pud_t *pud;
275 pmd_t *pmd;
276 pte_t *pte;
277
278 /*
279 * No early pte entries with !ARM64_64K_PAGES configuration, so using
280 * sections (pmd).
281 */
282 size = page64k ? PAGE_SIZE : SECTION_SIZE;
283 mask = ~(size - 1);
284
285 pgd = pgd_offset_k(virt);
286 pud = pud_offset(pgd, virt);
287 if (pud_none(*pud))
288 return NULL;
289 pmd = pmd_offset(pud, virt);
290
291 if (page64k) {
292 if (pmd_none(*pmd))
293 return NULL;
294 pte = pte_offset_kernel(pmd, virt);
295 set_pte(pte, __pte((phys & mask) | PROT_DEVICE_nGnRE));
296 } else {
297 set_pmd(pmd, __pmd((phys & mask) | PROT_SECT_DEVICE_nGnRE));
298 }
299
300 return (void __iomem *)((virt & mask) + (phys & ~mask));
301}
302#endif
303
304static void __init map_mem(void) 263static void __init map_mem(void)
305{ 264{
306 struct memblock_region *reg; 265 struct memblock_region *reg;