sh: Fixup machvec support.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 14 May 2007 06:59:09 +0000 (15:59 +0900)
committerPaul Mundt <lethal@hera.kernel.org>
Fri, 8 Jun 2007 02:43:37 +0000 (02:43 +0000)
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>
arch/sh/kernel/Makefile
arch/sh/kernel/machvec.c [new file with mode: 0644]
arch/sh/kernel/setup.c
arch/sh/kernel/vmlinux.lds.S
include/asm-sh/machvec_init.h
include/asm-sh/sections.h
include/asm-sh/setup.h

index fb623e5..1f141a8 100644 (file)
@@ -4,7 +4,7 @@
 
 extra-y        := head.o init_task.o vmlinux.lds
 
-obj-y  := debugtraps.o io.o io_generic.o irq.o process.o ptrace.o \
+obj-y  := debugtraps.o io.o io_generic.o irq.o machvec.o process.o ptrace.o \
           semaphore.o setup.o signal.o sys_sh.o syscalls.o \
           time.o topology.o traps.o
 
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
new file mode 100644 (file)
index 0000000..1e78191
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * arch/sh/kernel/machvec.c
+ *
+ * The SuperH machine vector setup handlers, yanked from setup.c
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2002 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/machvec.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define MV_NAME_SIZE 32
+
+#define for_each_mv(mv) \
+       for ((mv) = (struct sh_machine_vector *)&__machvec_start; \
+            (mv) && (unsigned long)(mv) < (unsigned long)&__machvec_end; \
+            (mv)++)
+
+static struct sh_machine_vector * __init get_mv_byname(const char *name)
+{
+       struct sh_machine_vector *mv;
+
+       for_each_mv(mv)
+               if (strcasecmp(name, get_system_type()) == 0)
+                       return mv;
+
+       return NULL;
+}
+
+static int __init early_parse_mv(char *from)
+{
+       char mv_name[MV_NAME_SIZE] = "";
+       char *mv_end;
+       char *mv_comma;
+       int mv_len;
+       struct sh_machine_vector *mvp;
+
+       mv_end = strchr(from, ' ');
+       if (mv_end == NULL)
+               mv_end = from + strlen(from);
+
+       mv_comma = strchr(from, ',');
+       mv_len = mv_end - from;
+       if (mv_len > (MV_NAME_SIZE-1))
+               mv_len = MV_NAME_SIZE-1;
+       memcpy(mv_name, from, mv_len);
+       mv_name[mv_len] = '\0';
+       from = mv_end;
+
+       if (strcmp(sh_mv.mv_name, mv_name) != 0) {
+               mvp = get_mv_byname(mv_name);
+               if (unlikely(!mvp)) {
+                       printk("Available vectors:\n\n\t");
+                       for_each_mv(mvp)
+                               printk("'%s', ", mvp->mv_name);
+                       printk("\n\n");
+                       panic("Failed to select machvec '%s' -- halting.\n",
+                             mv_name);
+               } else
+                       sh_mv = *mvp;
+       }
+
+       printk(KERN_NOTICE "Booting machvec: %s\n", sh_mv.mv_name);
+       return 0;
+}
+early_param("sh_mv", early_parse_mv);
+
+void __init sh_mv_setup(void)
+{
+       /*
+        * Manually walk the vec, fill in anything that the board hasn't yet
+        * by hand, wrapping to the generic implementation.
+        */
+#define mv_set(elem) do { \
+       if (!sh_mv.mv_##elem) \
+               sh_mv.mv_##elem = generic_##elem; \
+} while (0)
+
+       mv_set(inb);    mv_set(inw);    mv_set(inl);
+       mv_set(outb);   mv_set(outw);   mv_set(outl);
+
+       mv_set(inb_p);  mv_set(inw_p);  mv_set(inl_p);
+       mv_set(outb_p); mv_set(outw_p); mv_set(outl_p);
+
+       mv_set(insb);   mv_set(insw);   mv_set(insl);
+       mv_set(outsb);  mv_set(outsw);  mv_set(outsl);
+
+       mv_set(readb);  mv_set(readw);  mv_set(readl);
+       mv_set(writeb); mv_set(writew); mv_set(writel);
+
+       mv_set(ioport_map);
+       mv_set(ioport_unmap);
+       mv_set(irq_demux);
+
+       if (!sh_mv.mv_nr_irqs)
+               sh_mv.mv_nr_irqs = NR_IRQS;
+}
index 61152b4..0ad7158 100644 (file)
@@ -46,16 +46,8 @@ struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
 struct screen_info screen_info;
 #endif
 
-#if defined(CONFIG_SH_UNKNOWN)
-struct sh_machine_vector sh_mv;
-#endif
-
 extern int root_mountflags;
 
-#define MV_NAME_SIZE 32
-
-static struct sh_machine_vector* __init get_mv_byname(const char* name);
-
 /*
  * This is set up by the setup-routine at boot-time
  */
@@ -81,131 +73,17 @@ static struct resource data_resource = { .name = "Kernel data", };
 
 unsigned long memory_start, memory_end;
 
-static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
-                                 struct sh_machine_vector** mvp,
-                                 unsigned long *mv_io_base)
+static int __init early_parse_mem(char *p)
 {
-       char c = ' ', *to = command_line, *from = COMMAND_LINE;
-       int len = 0;
-
-       /* Save unparsed command line copy for /proc/cmdline */
-       memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
-       boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
+       unsigned long size;
 
        memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
-       memory_end = memory_start + __MEMORY_SIZE;
-
-       for (;;) {
-               /*
-                * "mem=XXX[kKmM]" defines a size of memory.
-                */
-               if (c == ' ' && !memcmp(from, "mem=", 4)) {
-                       if (to != command_line)
-                               to--;
-                       {
-                               unsigned long mem_size;
-
-                               mem_size = memparse(from+4, &from);
-                               memory_end = memory_start + mem_size;
-                       }
-               }
-
-               if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
-                       char* mv_end;
-                       char* mv_comma;
-                       int mv_len;
-                       if (to != command_line)
-                               to--;
-                       from += 6;
-                       mv_end = strchr(from, ' ');
-                       if (mv_end == NULL)
-                               mv_end = from + strlen(from);
-
-                       mv_comma = strchr(from, ',');
-                       if ((mv_comma != NULL) && (mv_comma < mv_end)) {
-                               int ints[3];
-                               get_options(mv_comma+1, ARRAY_SIZE(ints), ints);
-                               *mv_io_base = ints[1];
-                               mv_len = mv_comma - from;
-                       } else {
-                               mv_len = mv_end - from;
-                       }
-                       if (mv_len > (MV_NAME_SIZE-1))
-                               mv_len = MV_NAME_SIZE-1;
-                       memcpy(mv_name, from, mv_len);
-                       mv_name[mv_len] = '\0';
-                       from = mv_end;
-
-                       *mvp = get_mv_byname(mv_name);
-               }
-
-               c = *(from++);
-               if (!c)
-                       break;
-               if (COMMAND_LINE_SIZE <= ++len)
-                       break;
-               *(to++) = c;
-       }
-       *to = '\0';
-       *cmdline_p = command_line;
-}
-
-static int __init sh_mv_setup(char **cmdline_p)
-{
-#ifdef CONFIG_SH_UNKNOWN
-       extern struct sh_machine_vector mv_unknown;
-#endif
-       struct sh_machine_vector *mv = NULL;
-       char mv_name[MV_NAME_SIZE] = "";
-       unsigned long mv_io_base = 0;
-
-       parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base);
-
-#ifdef CONFIG_SH_UNKNOWN
-       if (mv == NULL) {
-               mv = &mv_unknown;
-               if (*mv_name != '\0') {
-                       printk("Warning: Unsupported machine %s, using unknown\n",
-                              mv_name);
-               }
-       }
-       sh_mv = *mv;
-#endif
-
-       /*
-        * Manually walk the vec, fill in anything that the board hasn't yet
-        * by hand, wrapping to the generic implementation.
-        */
-#define mv_set(elem) do { \
-       if (!sh_mv.mv_##elem) \
-               sh_mv.mv_##elem = generic_##elem; \
-} while (0)
-
-       mv_set(inb);    mv_set(inw);    mv_set(inl);
-       mv_set(outb);   mv_set(outw);   mv_set(outl);
-
-       mv_set(inb_p);  mv_set(inw_p);  mv_set(inl_p);
-       mv_set(outb_p); mv_set(outw_p); mv_set(outl_p);
-
-       mv_set(insb);   mv_set(insw);   mv_set(insl);
-       mv_set(outsb);  mv_set(outsw);  mv_set(outsl);
-
-       mv_set(readb);  mv_set(readw);  mv_set(readl);
-       mv_set(writeb); mv_set(writew); mv_set(writel);
-
-       mv_set(ioport_map);
-       mv_set(ioport_unmap);
-       mv_set(irq_demux);
-
-#ifdef CONFIG_SH_UNKNOWN
-       __set_io_port_base(mv_io_base);
-#endif
-
-       if (!sh_mv.mv_nr_irqs)
-               sh_mv.mv_nr_irqs = NR_IRQS;
+       size = memparse(p, &p);
+       memory_end = memory_start + size;
 
        return 0;
 }
+early_param("mem", early_parse_mem);
 
 /*
  * Register fully available low RAM pages with the bootmem allocator.
@@ -340,9 +218,17 @@ void __init setup_arch(char **cmdline_p)
        data_resource.start = virt_to_phys(_etext);
        data_resource.end = virt_to_phys(_edata)-1;
 
+       memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
+       memory_end = memory_start + __MEMORY_SIZE;
+
+       /* Save unparsed command line copy for /proc/cmdline */
+       strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+
+       *cmdline_p = command_line;
+
        parse_early_param();
 
-       sh_mv_setup(cmdline_p);
+       sh_mv_setup();
 
        /*
         * Find the highest page frame number we have available
@@ -369,26 +255,6 @@ void __init setup_arch(char **cmdline_p)
                sh_mv.mv_setup(cmdline_p);
 }
 
-struct sh_machine_vector* __init get_mv_byname(const char* name)
-{
-       extern long __machvec_start, __machvec_end;
-       struct sh_machine_vector *all_vecs =
-               (struct sh_machine_vector *)&__machvec_start;
-
-       int i, n = ((unsigned long)&__machvec_end
-                   - (unsigned long)&__machvec_start)/
-               sizeof(struct sh_machine_vector);
-
-       for (i = 0; i < n; ++i) {
-               struct sh_machine_vector *mv = &all_vecs[i];
-               if (mv == NULL)
-                       continue;
-               if (strcasecmp(name, get_system_type()) == 0) {
-                       return mv;
-               }
-       }
-       return NULL;
-}
 
 static const char *cpu_name[] = {
        [CPU_SH7206]    = "SH7206",     [CPU_SH7619]    = "SH7619",
index 4c5b57e..f437a4f 100644 (file)
@@ -98,8 +98,9 @@ SECTIONS
 #endif
 
   __machvec_start = .;
-  .init.machvec : { *(.init.machvec) }
+  .machvec.init : { *(.machvec.init) }
   __machvec_end = .;
+
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
 
index e397798..88a973e 100644 (file)
 #ifndef __SH_MACHVEC_INIT_H
 #define __SH_MACHVEC_INIT_H
 
-
-/*
- * In a GENERIC kernel, we have lots of these vectors floating about,
- * all but one of which we want to go away.  In a non-GENERIC kernel,
- * we want only one, ever.
- *
- * Accomplish this in the GENERIC kernel by puting all of the vectors
- * in the .init.data section where they'll go away.  We'll copy the
- * one we want to the real alpha_mv vector in setup_arch.
- *
- * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but
- * one of the vectors, which will not reside in .init.data.  We then
- * alias this one vector to alpha_mv, so no copy is needed.
- *
- * Upshot: set __initdata to nothing for non-GENERIC kernels.
- *
- * Note we do the same thing for the UNKNOWN kernel, as we need to write
- * to the machine vector while setting it up.
- */
-
-#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_UNKNOWN)
 #define __initmv __attribute__((unused,__section__ (".machvec.init")))
-#define ALIAS_MV(x)
-#else
-#define __initmv
-
-/* GCC actually has a syntax for defining aliases, but is under some
-   delusion that you shouldn't be able to declare it extern somewhere
-   else beforehand.  Fine.  We'll do it ourselves.  */
-#if 0
-#define ALIAS_MV(system) \
-  struct sh_machine_vector sh_mv __attribute__((alias("mv_"#system)));
-#else
 #define ALIAS_MV(system) \
   asm(".global sh_mv\nsh_mv = mv_"#system );
-#endif
-#endif /* GENERIC */
 
 #endif /* __SH_MACHVEC_INIT_H */
index 44c06c0..2a696b8 100644 (file)
@@ -3,5 +3,7 @@
 
 #include <asm-generic/sections.h>
 
+extern long __machvec_start, __machvec_end;
+
 #endif /* __ASM_SH_SECTIONS_H */
 
index 1583c6b..586a971 100644 (file)
@@ -6,6 +6,7 @@
 #ifdef __KERNEL__
 
 int setup_early_printk(char *);
+void sh_mv_setup(void);
 
 #endif /* __KERNEL__ */