aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-05-14 02:59:09 -0400
committerPaul Mundt <lethal@hera.kernel.org>2007-06-07 22:43:37 -0400
commit9655ad03af2d232c3b26e7562ab4f8c29b107e49 (patch)
tree6a76057e969ca072e7ca9bdf253219e759054d3f
parente08f457c7c0cc7720f28349f8780ea752c063441 (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>
-rw-r--r--arch/sh/kernel/Makefile2
-rw-r--r--arch/sh/kernel/machvec.c105
-rw-r--r--arch/sh/kernel/setup.c162
-rw-r--r--arch/sh/kernel/vmlinux.lds.S3
-rw-r--r--include/asm-sh/machvec_init.h34
-rw-r--r--include/asm-sh/sections.h2
-rw-r--r--include/asm-sh/setup.h1
7 files changed, 125 insertions, 184 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
5extra-y := head.o init_task.o vmlinux.lds 5extra-y := head.o init_task.o vmlinux.lds
6 6
7obj-y := debugtraps.o io.o io_generic.o irq.o process.o ptrace.o \ 7obj-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
27static 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
38static 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}
74early_param("sh_mv", early_parse_mv);
75
76void __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, };
46struct screen_info screen_info; 46struct screen_info screen_info;
47#endif 47#endif
48 48
49#if defined(CONFIG_SH_UNKNOWN)
50struct sh_machine_vector sh_mv;
51#endif
52
53extern int root_mountflags; 49extern int root_mountflags;
54 50
55#define MV_NAME_SIZE 32
56
57static 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
82unsigned long memory_start, memory_end; 74unsigned long memory_start, memory_end;
83 75
84static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], 76static 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
153static 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}
86early_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
372struct 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
393static const char *cpu_name[] = { 259static 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
diff --git a/include/asm-sh/machvec_init.h b/include/asm-sh/machvec_init.h
index e397798ebd94..88a973edcf15 100644
--- a/include/asm-sh/machvec_init.h
+++ b/include/asm-sh/machvec_init.h
@@ -12,42 +12,8 @@
12#ifndef __SH_MACHVEC_INIT_H 12#ifndef __SH_MACHVEC_INIT_H
13#define __SH_MACHVEC_INIT_H 13#define __SH_MACHVEC_INIT_H
14 14
15
16/*
17 * In a GENERIC kernel, we have lots of these vectors floating about,
18 * all but one of which we want to go away. In a non-GENERIC kernel,
19 * we want only one, ever.
20 *
21 * Accomplish this in the GENERIC kernel by puting all of the vectors
22 * in the .init.data section where they'll go away. We'll copy the
23 * one we want to the real alpha_mv vector in setup_arch.
24 *
25 * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but
26 * one of the vectors, which will not reside in .init.data. We then
27 * alias this one vector to alpha_mv, so no copy is needed.
28 *
29 * Upshot: set __initdata to nothing for non-GENERIC kernels.
30 *
31 * Note we do the same thing for the UNKNOWN kernel, as we need to write
32 * to the machine vector while setting it up.
33 */
34
35#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_UNKNOWN)
36#define __initmv __attribute__((unused,__section__ (".machvec.init"))) 15#define __initmv __attribute__((unused,__section__ (".machvec.init")))
37#define ALIAS_MV(x)
38#else
39#define __initmv
40
41/* GCC actually has a syntax for defining aliases, but is under some
42 delusion that you shouldn't be able to declare it extern somewhere
43 else beforehand. Fine. We'll do it ourselves. */
44#if 0
45#define ALIAS_MV(system) \
46 struct sh_machine_vector sh_mv __attribute__((alias("mv_"#system)));
47#else
48#define ALIAS_MV(system) \ 16#define ALIAS_MV(system) \
49 asm(".global sh_mv\nsh_mv = mv_"#system ); 17 asm(".global sh_mv\nsh_mv = mv_"#system );
50#endif
51#endif /* GENERIC */
52 18
53#endif /* __SH_MACHVEC_INIT_H */ 19#endif /* __SH_MACHVEC_INIT_H */
diff --git a/include/asm-sh/sections.h b/include/asm-sh/sections.h
index 44c06c09e208..2a696b8ee4f5 100644
--- a/include/asm-sh/sections.h
+++ b/include/asm-sh/sections.h
@@ -3,5 +3,7 @@
3 3
4#include <asm-generic/sections.h> 4#include <asm-generic/sections.h>
5 5
6extern long __machvec_start, __machvec_end;
7
6#endif /* __ASM_SH_SECTIONS_H */ 8#endif /* __ASM_SH_SECTIONS_H */
7 9
diff --git a/include/asm-sh/setup.h b/include/asm-sh/setup.h
index 1583c6b7bdaa..586a9711a75d 100644
--- a/include/asm-sh/setup.h
+++ b/include/asm-sh/setup.h
@@ -6,6 +6,7 @@
6#ifdef __KERNEL__ 6#ifdef __KERNEL__
7 7
8int setup_early_printk(char *); 8int setup_early_printk(char *);
9void sh_mv_setup(void);
9 10
10#endif /* __KERNEL__ */ 11#endif /* __KERNEL__ */
11 12