diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-05-14 02:59:09 -0400 |
---|---|---|
committer | Paul Mundt <lethal@hera.kernel.org> | 2007-06-07 22:43:37 -0400 |
commit | 9655ad03af2d232c3b26e7562ab4f8c29b107e49 (patch) | |
tree | 6a76057e969ca072e7ca9bdf253219e759054d3f /arch/sh | |
parent | e08f457c7c0cc7720f28349f8780ea752c063441 (diff) |
sh: Fixup machvec support.
This fixes up much of the machvec handling, allowing for it to be
overloaded on boot. Making practical use of this still requires
some Kconfig munging, however.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/kernel/machvec.c | 105 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 162 | ||||
-rw-r--r-- | arch/sh/kernel/vmlinux.lds.S | 3 |
4 files changed, 122 insertions, 150 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index fb623e5d1857..1f141a8ba17c 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | extra-y := head.o init_task.o vmlinux.lds | 5 | extra-y := head.o init_task.o vmlinux.lds |
6 | 6 | ||
7 | obj-y := debugtraps.o io.o io_generic.o irq.o process.o ptrace.o \ | 7 | obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process.o ptrace.o \ |
8 | semaphore.o setup.o signal.o sys_sh.o syscalls.o \ | 8 | semaphore.o setup.o signal.o sys_sh.o syscalls.o \ |
9 | time.o topology.o traps.o | 9 | time.o topology.o traps.o |
10 | 10 | ||
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c new file mode 100644 index 000000000000..1e78191154e3 --- /dev/null +++ b/arch/sh/kernel/machvec.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/machvec.c | ||
3 | * | ||
4 | * The SuperH machine vector setup handlers, yanked from setup.c | ||
5 | * | ||
6 | * Copyright (C) 1999 Niibe Yutaka | ||
7 | * Copyright (C) 2002 - 2007 Paul Mundt | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <asm/machvec.h> | ||
16 | #include <asm/sections.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/irq.h> | ||
19 | |||
20 | #define MV_NAME_SIZE 32 | ||
21 | |||
22 | #define for_each_mv(mv) \ | ||
23 | for ((mv) = (struct sh_machine_vector *)&__machvec_start; \ | ||
24 | (mv) && (unsigned long)(mv) < (unsigned long)&__machvec_end; \ | ||
25 | (mv)++) | ||
26 | |||
27 | static struct sh_machine_vector * __init get_mv_byname(const char *name) | ||
28 | { | ||
29 | struct sh_machine_vector *mv; | ||
30 | |||
31 | for_each_mv(mv) | ||
32 | if (strcasecmp(name, get_system_type()) == 0) | ||
33 | return mv; | ||
34 | |||
35 | return NULL; | ||
36 | } | ||
37 | |||
38 | static int __init early_parse_mv(char *from) | ||
39 | { | ||
40 | char mv_name[MV_NAME_SIZE] = ""; | ||
41 | char *mv_end; | ||
42 | char *mv_comma; | ||
43 | int mv_len; | ||
44 | struct sh_machine_vector *mvp; | ||
45 | |||
46 | mv_end = strchr(from, ' '); | ||
47 | if (mv_end == NULL) | ||
48 | mv_end = from + strlen(from); | ||
49 | |||
50 | mv_comma = strchr(from, ','); | ||
51 | mv_len = mv_end - from; | ||
52 | if (mv_len > (MV_NAME_SIZE-1)) | ||
53 | mv_len = MV_NAME_SIZE-1; | ||
54 | memcpy(mv_name, from, mv_len); | ||
55 | mv_name[mv_len] = '\0'; | ||
56 | from = mv_end; | ||
57 | |||
58 | if (strcmp(sh_mv.mv_name, mv_name) != 0) { | ||
59 | mvp = get_mv_byname(mv_name); | ||
60 | if (unlikely(!mvp)) { | ||
61 | printk("Available vectors:\n\n\t"); | ||
62 | for_each_mv(mvp) | ||
63 | printk("'%s', ", mvp->mv_name); | ||
64 | printk("\n\n"); | ||
65 | panic("Failed to select machvec '%s' -- halting.\n", | ||
66 | mv_name); | ||
67 | } else | ||
68 | sh_mv = *mvp; | ||
69 | } | ||
70 | |||
71 | printk(KERN_NOTICE "Booting machvec: %s\n", sh_mv.mv_name); | ||
72 | return 0; | ||
73 | } | ||
74 | early_param("sh_mv", early_parse_mv); | ||
75 | |||
76 | void __init sh_mv_setup(void) | ||
77 | { | ||
78 | /* | ||
79 | * Manually walk the vec, fill in anything that the board hasn't yet | ||
80 | * by hand, wrapping to the generic implementation. | ||
81 | */ | ||
82 | #define mv_set(elem) do { \ | ||
83 | if (!sh_mv.mv_##elem) \ | ||
84 | sh_mv.mv_##elem = generic_##elem; \ | ||
85 | } while (0) | ||
86 | |||
87 | mv_set(inb); mv_set(inw); mv_set(inl); | ||
88 | mv_set(outb); mv_set(outw); mv_set(outl); | ||
89 | |||
90 | mv_set(inb_p); mv_set(inw_p); mv_set(inl_p); | ||
91 | mv_set(outb_p); mv_set(outw_p); mv_set(outl_p); | ||
92 | |||
93 | mv_set(insb); mv_set(insw); mv_set(insl); | ||
94 | mv_set(outsb); mv_set(outsw); mv_set(outsl); | ||
95 | |||
96 | mv_set(readb); mv_set(readw); mv_set(readl); | ||
97 | mv_set(writeb); mv_set(writew); mv_set(writel); | ||
98 | |||
99 | mv_set(ioport_map); | ||
100 | mv_set(ioport_unmap); | ||
101 | mv_set(irq_demux); | ||
102 | |||
103 | if (!sh_mv.mv_nr_irqs) | ||
104 | sh_mv.mv_nr_irqs = NR_IRQS; | ||
105 | } | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 61152b438325..0ad715833990 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -46,16 +46,8 @@ struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, }; | |||
46 | struct screen_info screen_info; | 46 | struct screen_info screen_info; |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #if defined(CONFIG_SH_UNKNOWN) | ||
50 | struct sh_machine_vector sh_mv; | ||
51 | #endif | ||
52 | |||
53 | extern int root_mountflags; | 49 | extern int root_mountflags; |
54 | 50 | ||
55 | #define MV_NAME_SIZE 32 | ||
56 | |||
57 | static struct sh_machine_vector* __init get_mv_byname(const char* name); | ||
58 | |||
59 | /* | 51 | /* |
60 | * This is set up by the setup-routine at boot-time | 52 | * This is set up by the setup-routine at boot-time |
61 | */ | 53 | */ |
@@ -81,131 +73,17 @@ static struct resource data_resource = { .name = "Kernel data", }; | |||
81 | 73 | ||
82 | unsigned long memory_start, memory_end; | 74 | unsigned long memory_start, memory_end; |
83 | 75 | ||
84 | static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], | 76 | static int __init early_parse_mem(char *p) |
85 | struct sh_machine_vector** mvp, | ||
86 | unsigned long *mv_io_base) | ||
87 | { | 77 | { |
88 | char c = ' ', *to = command_line, *from = COMMAND_LINE; | 78 | unsigned long size; |
89 | int len = 0; | ||
90 | |||
91 | /* Save unparsed command line copy for /proc/cmdline */ | ||
92 | memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); | ||
93 | boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; | ||
94 | 79 | ||
95 | memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START; | 80 | memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START; |
96 | memory_end = memory_start + __MEMORY_SIZE; | 81 | size = memparse(p, &p); |
97 | 82 | memory_end = memory_start + size; | |
98 | for (;;) { | ||
99 | /* | ||
100 | * "mem=XXX[kKmM]" defines a size of memory. | ||
101 | */ | ||
102 | if (c == ' ' && !memcmp(from, "mem=", 4)) { | ||
103 | if (to != command_line) | ||
104 | to--; | ||
105 | { | ||
106 | unsigned long mem_size; | ||
107 | |||
108 | mem_size = memparse(from+4, &from); | ||
109 | memory_end = memory_start + mem_size; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | if (c == ' ' && !memcmp(from, "sh_mv=", 6)) { | ||
114 | char* mv_end; | ||
115 | char* mv_comma; | ||
116 | int mv_len; | ||
117 | if (to != command_line) | ||
118 | to--; | ||
119 | from += 6; | ||
120 | mv_end = strchr(from, ' '); | ||
121 | if (mv_end == NULL) | ||
122 | mv_end = from + strlen(from); | ||
123 | |||
124 | mv_comma = strchr(from, ','); | ||
125 | if ((mv_comma != NULL) && (mv_comma < mv_end)) { | ||
126 | int ints[3]; | ||
127 | get_options(mv_comma+1, ARRAY_SIZE(ints), ints); | ||
128 | *mv_io_base = ints[1]; | ||
129 | mv_len = mv_comma - from; | ||
130 | } else { | ||
131 | mv_len = mv_end - from; | ||
132 | } | ||
133 | if (mv_len > (MV_NAME_SIZE-1)) | ||
134 | mv_len = MV_NAME_SIZE-1; | ||
135 | memcpy(mv_name, from, mv_len); | ||
136 | mv_name[mv_len] = '\0'; | ||
137 | from = mv_end; | ||
138 | |||
139 | *mvp = get_mv_byname(mv_name); | ||
140 | } | ||
141 | |||
142 | c = *(from++); | ||
143 | if (!c) | ||
144 | break; | ||
145 | if (COMMAND_LINE_SIZE <= ++len) | ||
146 | break; | ||
147 | *(to++) = c; | ||
148 | } | ||
149 | *to = '\0'; | ||
150 | *cmdline_p = command_line; | ||
151 | } | ||
152 | |||
153 | static int __init sh_mv_setup(char **cmdline_p) | ||
154 | { | ||
155 | #ifdef CONFIG_SH_UNKNOWN | ||
156 | extern struct sh_machine_vector mv_unknown; | ||
157 | #endif | ||
158 | struct sh_machine_vector *mv = NULL; | ||
159 | char mv_name[MV_NAME_SIZE] = ""; | ||
160 | unsigned long mv_io_base = 0; | ||
161 | |||
162 | parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base); | ||
163 | |||
164 | #ifdef CONFIG_SH_UNKNOWN | ||
165 | if (mv == NULL) { | ||
166 | mv = &mv_unknown; | ||
167 | if (*mv_name != '\0') { | ||
168 | printk("Warning: Unsupported machine %s, using unknown\n", | ||
169 | mv_name); | ||
170 | } | ||
171 | } | ||
172 | sh_mv = *mv; | ||
173 | #endif | ||
174 | |||
175 | /* | ||
176 | * Manually walk the vec, fill in anything that the board hasn't yet | ||
177 | * by hand, wrapping to the generic implementation. | ||
178 | */ | ||
179 | #define mv_set(elem) do { \ | ||
180 | if (!sh_mv.mv_##elem) \ | ||
181 | sh_mv.mv_##elem = generic_##elem; \ | ||
182 | } while (0) | ||
183 | |||
184 | mv_set(inb); mv_set(inw); mv_set(inl); | ||
185 | mv_set(outb); mv_set(outw); mv_set(outl); | ||
186 | |||
187 | mv_set(inb_p); mv_set(inw_p); mv_set(inl_p); | ||
188 | mv_set(outb_p); mv_set(outw_p); mv_set(outl_p); | ||
189 | |||
190 | mv_set(insb); mv_set(insw); mv_set(insl); | ||
191 | mv_set(outsb); mv_set(outsw); mv_set(outsl); | ||
192 | |||
193 | mv_set(readb); mv_set(readw); mv_set(readl); | ||
194 | mv_set(writeb); mv_set(writew); mv_set(writel); | ||
195 | |||
196 | mv_set(ioport_map); | ||
197 | mv_set(ioport_unmap); | ||
198 | mv_set(irq_demux); | ||
199 | |||
200 | #ifdef CONFIG_SH_UNKNOWN | ||
201 | __set_io_port_base(mv_io_base); | ||
202 | #endif | ||
203 | |||
204 | if (!sh_mv.mv_nr_irqs) | ||
205 | sh_mv.mv_nr_irqs = NR_IRQS; | ||
206 | 83 | ||
207 | return 0; | 84 | return 0; |
208 | } | 85 | } |
86 | early_param("mem", early_parse_mem); | ||
209 | 87 | ||
210 | /* | 88 | /* |
211 | * Register fully available low RAM pages with the bootmem allocator. | 89 | * Register fully available low RAM pages with the bootmem allocator. |
@@ -340,9 +218,17 @@ void __init setup_arch(char **cmdline_p) | |||
340 | data_resource.start = virt_to_phys(_etext); | 218 | data_resource.start = virt_to_phys(_etext); |
341 | data_resource.end = virt_to_phys(_edata)-1; | 219 | data_resource.end = virt_to_phys(_edata)-1; |
342 | 220 | ||
221 | memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START; | ||
222 | memory_end = memory_start + __MEMORY_SIZE; | ||
223 | |||
224 | /* Save unparsed command line copy for /proc/cmdline */ | ||
225 | strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); | ||
226 | |||
227 | *cmdline_p = command_line; | ||
228 | |||
343 | parse_early_param(); | 229 | parse_early_param(); |
344 | 230 | ||
345 | sh_mv_setup(cmdline_p); | 231 | sh_mv_setup(); |
346 | 232 | ||
347 | /* | 233 | /* |
348 | * Find the highest page frame number we have available | 234 | * Find the highest page frame number we have available |
@@ -369,26 +255,6 @@ void __init setup_arch(char **cmdline_p) | |||
369 | sh_mv.mv_setup(cmdline_p); | 255 | sh_mv.mv_setup(cmdline_p); |
370 | } | 256 | } |
371 | 257 | ||
372 | struct sh_machine_vector* __init get_mv_byname(const char* name) | ||
373 | { | ||
374 | extern long __machvec_start, __machvec_end; | ||
375 | struct sh_machine_vector *all_vecs = | ||
376 | (struct sh_machine_vector *)&__machvec_start; | ||
377 | |||
378 | int i, n = ((unsigned long)&__machvec_end | ||
379 | - (unsigned long)&__machvec_start)/ | ||
380 | sizeof(struct sh_machine_vector); | ||
381 | |||
382 | for (i = 0; i < n; ++i) { | ||
383 | struct sh_machine_vector *mv = &all_vecs[i]; | ||
384 | if (mv == NULL) | ||
385 | continue; | ||
386 | if (strcasecmp(name, get_system_type()) == 0) { | ||
387 | return mv; | ||
388 | } | ||
389 | } | ||
390 | return NULL; | ||
391 | } | ||
392 | 258 | ||
393 | static const char *cpu_name[] = { | 259 | static const char *cpu_name[] = { |
394 | [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", | 260 | [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", |
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 4c5b57e9c3c1..f437a4f06da4 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S | |||
@@ -98,8 +98,9 @@ SECTIONS | |||
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | __machvec_start = .; | 100 | __machvec_start = .; |
101 | .init.machvec : { *(.init.machvec) } | 101 | .machvec.init : { *(.machvec.init) } |
102 | __machvec_end = .; | 102 | __machvec_end = .; |
103 | |||
103 | . = ALIGN(PAGE_SIZE); | 104 | . = ALIGN(PAGE_SIZE); |
104 | __init_end = .; | 105 | __init_end = .; |
105 | 106 | ||