aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-11-05 02:54:17 -0500
committerMatt Fleming <matt@console-pimps.org>2010-01-16 09:31:36 -0500
commit4d35b93a66e9b87df20784fcf130d2e8760be53f (patch)
treeaf0b82ab28a0e4142130c6510cc06cca3d4a67aa
parent07cad4dc1bfdaefd20c6329e9d8179ad1c600e92 (diff)
sh: Add fixed ioremap support
Some devices need to be ioremap'd and accessed very early in the boot process. It is not possible to use the standard ioremap() function in this case because that requires kmalloc()'ing some virtual address space and kmalloc() may not be available so early in boot. This patch provides fixmap mappings that allow physical address ranges to be remapped into the kernel address space during the early boot stages. Signed-off-by: Matt Fleming <matt@console-pimps.org>
-rw-r--r--arch/sh/include/asm/fixmap.h8
-rw-r--r--arch/sh/include/asm/io.h6
-rw-r--r--arch/sh/kernel/setup.c7
-rw-r--r--arch/sh/mm/Kconfig4
-rw-r--r--arch/sh/mm/Makefile1
-rw-r--r--arch/sh/mm/ioremap_fixed.c144
6 files changed, 167 insertions, 3 deletions
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 1566d3361ca4..38a1de866873 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -60,6 +60,14 @@ enum fixed_addresses {
60 FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ 60 FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
61 FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, 61 FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
62#endif 62#endif
63 /*
64 * FIX_IOREMAP entries are useful for mapping physical address
65 * space before ioremap() is useable, e.g. really early in boot
66 * before kmalloc() is working.
67 */
68#define FIX_N_IOREMAPS 32
69 FIX_IOREMAP_BEGIN,
70 FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS,
63 __end_of_fixed_addresses 71 __end_of_fixed_addresses
64}; 72};
65 73
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index f4314d8b05b8..bee5965e0a82 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -237,6 +237,12 @@ void __iomem *__ioremap_caller(unsigned long offset, unsigned long size,
237 unsigned long flags, void *caller); 237 unsigned long flags, void *caller);
238void __iounmap(void __iomem *addr); 238void __iounmap(void __iomem *addr);
239 239
240#ifdef CONFIG_IOREMAP_FIXED
241extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, pgprot_t);
242extern void iounmap_fixed(void __iomem *);
243extern void ioremap_fixed_init(void);
244#endif
245
240static inline void __iomem * 246static inline void __iomem *
241__ioremap(unsigned long offset, unsigned long size, unsigned long flags) 247__ioremap(unsigned long offset, unsigned long size, unsigned long flags)
242{ 248{
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index f79ebe32a24a..e187750dd319 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -449,14 +449,15 @@ void __init setup_arch(char **cmdline_p)
449#ifdef CONFIG_DUMMY_CONSOLE 449#ifdef CONFIG_DUMMY_CONSOLE
450 conswitchp = &dummy_con; 450 conswitchp = &dummy_con;
451#endif 451#endif
452 paging_init();
453 pmb_init();
454
455 ioremap_fixed_init();
452 456
453 /* Perform the machine specific initialisation */ 457 /* Perform the machine specific initialisation */
454 if (likely(sh_mv.mv_setup)) 458 if (likely(sh_mv.mv_setup))
455 sh_mv.mv_setup(cmdline_p); 459 sh_mv.mv_setup(cmdline_p);
456 460
457 paging_init();
458 pmb_init();
459
460#ifdef CONFIG_SMP 461#ifdef CONFIG_SMP
461 plat_smp_setup(); 462 plat_smp_setup();
462#endif 463#endif
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 7a4ebc8cbadd..b89075256b70 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -169,6 +169,10 @@ config ARCH_MEMORY_PROBE
169 def_bool y 169 def_bool y
170 depends on MEMORY_HOTPLUG 170 depends on MEMORY_HOTPLUG
171 171
172config IOREMAP_FIXED
173 def_bool y
174 depends on X2TLB || SUPERH64
175
172choice 176choice
173 prompt "Kernel page size" 177 prompt "Kernel page size"
174 default PAGE_SIZE_4KB 178 default PAGE_SIZE_4KB
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index edde8bdd681d..89ba56c20ade 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -35,6 +35,7 @@ endif
35obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 35obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
36obj-$(CONFIG_PMB) += pmb.o 36obj-$(CONFIG_PMB) += pmb.o
37obj-$(CONFIG_NUMA) += numa.o 37obj-$(CONFIG_NUMA) += numa.o
38obj-$(CONFIG_IOREMAP_FIXED) += ioremap_fixed.o
38 39
39# Special flags for fault_64.o. This puts restrictions on the number of 40# Special flags for fault_64.o. This puts restrictions on the number of
40# caller-save registers that the compiler can target when building this file. 41# caller-save registers that the compiler can target when building this file.
diff --git a/arch/sh/mm/ioremap_fixed.c b/arch/sh/mm/ioremap_fixed.c
new file mode 100644
index 000000000000..3a9d3d88fe8d
--- /dev/null
+++ b/arch/sh/mm/ioremap_fixed.c
@@ -0,0 +1,144 @@
1/*
2 * Re-map IO memory to kernel address space so that we can access it.
3 *
4 * These functions should only be used when it is necessary to map a
5 * physical address space into the kernel address space before ioremap()
6 * can be used, e.g. early in boot before paging_init().
7 *
8 * Copyright (C) 2009 Matt Fleming
9 */
10
11#include <linux/vmalloc.h>
12#include <linux/ioport.h>
13#include <linux/module.h>
14#include <linux/mm.h>
15#include <linux/io.h>
16#include <linux/bootmem.h>
17#include <linux/proc_fs.h>
18#include <linux/slab.h>
19#include <asm/fixmap.h>
20#include <asm/page.h>
21#include <asm/pgalloc.h>
22#include <asm/addrspace.h>
23#include <asm/cacheflush.h>
24#include <asm/tlbflush.h>
25#include <asm/mmu.h>
26#include <asm/mmu_context.h>
27
28struct ioremap_map {
29 void __iomem *addr;
30 unsigned long size;
31 unsigned long fixmap_addr;
32};
33
34static struct ioremap_map ioremap_maps[FIX_N_IOREMAPS];
35
36void __init ioremap_fixed_init(void)
37{
38 struct ioremap_map *map;
39 int i;
40
41 for (i = 0; i < FIX_N_IOREMAPS; i++) {
42 map = &ioremap_maps[i];
43 map->fixmap_addr = __fix_to_virt(FIX_IOREMAP_BEGIN + i);
44 }
45}
46
47void __init __iomem *
48ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
49{
50 enum fixed_addresses idx0, idx;
51 resource_size_t last_addr;
52 struct ioremap_map *map;
53 unsigned long offset;
54 unsigned int nrpages;
55 int i, slot;
56
57 slot = -1;
58 for (i = 0; i < FIX_N_IOREMAPS; i++) {
59 map = &ioremap_maps[i];
60 if (!map->addr) {
61 map->size = size;
62 slot = i;
63 break;
64 }
65 }
66
67 if (slot < 0)
68 return NULL;
69
70 /* Don't allow wraparound or zero size */
71 last_addr = phys_addr + size - 1;
72 if (!size || last_addr < phys_addr)
73 return NULL;
74
75 /*
76 * Fixmap mappings have to be page-aligned
77 */
78 offset = phys_addr & ~PAGE_MASK;
79 phys_addr &= PAGE_MASK;
80 size = PAGE_ALIGN(last_addr + 1) - phys_addr;
81
82 /*
83 * Mappings have to fit in the FIX_IOREMAP area.
84 */
85 nrpages = size >> PAGE_SHIFT;
86 if (nrpages > FIX_N_IOREMAPS)
87 return NULL;
88
89 /*
90 * Ok, go for it..
91 */
92 idx0 = FIX_IOREMAP_BEGIN + slot;
93 idx = idx0;
94 while (nrpages > 0) {
95 pgprot_val(prot) |= _PAGE_WIRED;
96 __set_fixmap(idx, phys_addr, prot);
97 phys_addr += PAGE_SIZE;
98 idx++;
99 --nrpages;
100 }
101
102 map->addr = (void __iomem *)(offset + map->fixmap_addr);
103 return map->addr;
104}
105
106void __init iounmap_fixed(void __iomem *addr)
107{
108 enum fixed_addresses idx;
109 unsigned long virt_addr;
110 struct ioremap_map *map;
111 unsigned long offset;
112 unsigned int nrpages;
113 int i, slot;
114 pgprot_t prot;
115
116 slot = -1;
117 for (i = 0; i < FIX_N_IOREMAPS; i++) {
118 map = &ioremap_maps[i];
119 if (map->addr == addr) {
120 slot = i;
121 break;
122 }
123 }
124
125 if (slot < 0)
126 return;
127
128 virt_addr = (unsigned long)addr;
129
130 offset = virt_addr & ~PAGE_MASK;
131 nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT;
132
133 pgprot_val(prot) = _PAGE_WIRED;
134
135 idx = FIX_IOREMAP_BEGIN + slot + nrpages;
136 while (nrpages > 0) {
137 __clear_fixmap(idx, prot);
138 --idx;
139 --nrpages;
140 }
141
142 map->size = 0;
143 map->addr = NULL;
144}