linux/arch/sparc/kernel/setup_32.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/sparc/kernel/setup.c
   3 *
   4 *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
   5 *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
   6 */
   7
   8#include <linux/errno.h>
   9#include <linux/sched.h>
  10#include <linux/kernel.h>
  11#include <linux/mm.h>
  12#include <linux/stddef.h>
  13#include <linux/unistd.h>
  14#include <linux/ptrace.h>
  15#include <linux/slab.h>
  16#include <linux/initrd.h>
  17#include <asm/smp.h>
  18#include <linux/user.h>
  19#include <linux/screen_info.h>
  20#include <linux/delay.h>
  21#include <linux/fs.h>
  22#include <linux/seq_file.h>
  23#include <linux/syscalls.h>
  24#include <linux/kdev_t.h>
  25#include <linux/major.h>
  26#include <linux/string.h>
  27#include <linux/init.h>
  28#include <linux/interrupt.h>
  29#include <linux/console.h>
  30#include <linux/spinlock.h>
  31#include <linux/root_dev.h>
  32#include <linux/cpu.h>
  33#include <linux/kdebug.h>
  34#include <linux/export.h>
  35#include <linux/start_kernel.h>
  36
  37#include <asm/io.h>
  38#include <asm/processor.h>
  39#include <asm/oplib.h>
  40#include <asm/page.h>
  41#include <asm/pgtable.h>
  42#include <asm/traps.h>
  43#include <asm/vaddrs.h>
  44#include <asm/mbus.h>
  45#include <asm/idprom.h>
  46#include <asm/cpudata.h>
  47#include <asm/setup.h>
  48#include <asm/cacheflush.h>
  49#include <asm/sections.h>
  50
  51#include "kernel.h"
  52
  53struct screen_info screen_info = {
  54        0, 0,                   /* orig-x, orig-y */
  55        0,                      /* unused */
  56        0,                      /* orig-video-page */
  57        0,                      /* orig-video-mode */
  58        128,                    /* orig-video-cols */
  59        0,0,0,                  /* ega_ax, ega_bx, ega_cx */
  60        54,                     /* orig-video-lines */
  61        0,                      /* orig-video-isVGA */
  62        16                      /* orig-video-points */
  63};
  64
  65/* Typing sync at the prom prompt calls the function pointed to by
  66 * romvec->pv_synchook which I set to the following function.
  67 * This should sync all filesystems and return, for now it just
  68 * prints out pretty messages and returns.
  69 */
  70
  71/* Pretty sick eh? */
  72static void prom_sync_me(void)
  73{
  74        unsigned long prom_tbr, flags;
  75
  76        /* XXX Badly broken. FIX! - Anton */
  77        local_irq_save(flags);
  78        __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
  79        __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
  80                             "nop\n\t"
  81                             "nop\n\t"
  82                             "nop\n\t" : : "r" (&trapbase));
  83
  84        prom_printf("PROM SYNC COMMAND...\n");
  85        show_free_areas(0, NULL);
  86        if (!is_idle_task(current)) {
  87                local_irq_enable();
  88                sys_sync();
  89                local_irq_disable();
  90        }
  91        prom_printf("Returning to prom\n");
  92
  93        __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
  94                             "nop\n\t"
  95                             "nop\n\t"
  96                             "nop\n\t" : : "r" (prom_tbr));
  97        local_irq_restore(flags);
  98}
  99
 100static unsigned int boot_flags __initdata = 0;
 101#define BOOTME_DEBUG  0x1
 102
 103/* Exported for mm/init.c:paging_init. */
 104unsigned long cmdline_memory_size __initdata = 0;
 105
 106/* which CPU booted us (0xff = not set) */
 107unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */
 108
 109static void
 110prom_console_write(struct console *con, const char *s, unsigned int n)
 111{
 112        prom_write(s, n);
 113}
 114
 115static struct console prom_early_console = {
 116        .name =         "earlyprom",
 117        .write =        prom_console_write,
 118        .flags =        CON_PRINTBUFFER | CON_BOOT,
 119        .index =        -1,
 120};
 121
 122/* 
 123 * Process kernel command line switches that are specific to the
 124 * SPARC or that require special low-level processing.
 125 */
 126static void __init process_switch(char c)
 127{
 128        switch (c) {
 129        case 'd':
 130                boot_flags |= BOOTME_DEBUG;
 131                break;
 132        case 's':
 133                break;
 134        case 'h':
 135                prom_printf("boot_flags_init: Halt!\n");
 136                prom_halt();
 137                break;
 138        case 'p':
 139                prom_early_console.flags &= ~CON_BOOT;
 140                break;
 141        default:
 142                printk("Unknown boot switch (-%c)\n", c);
 143                break;
 144        }
 145}
 146
 147static void __init boot_flags_init(char *commands)
 148{
 149        while (*commands) {
 150                /* Move to the start of the next "argument". */
 151                while (*commands == ' ')
 152                        commands++;
 153
 154                /* Process any command switches, otherwise skip it. */
 155                if (*commands == '\0')
 156                        break;
 157                if (*commands == '-') {
 158                        commands++;
 159                        while (*commands && *commands != ' ')
 160                                process_switch(*commands++);
 161                        continue;
 162                }
 163                if (!strncmp(commands, "mem=", 4)) {
 164                        /*
 165                         * "mem=XXX[kKmM] overrides the PROM-reported
 166                         * memory size.
 167                         */
 168                        cmdline_memory_size = simple_strtoul(commands + 4,
 169                                                     &commands, 0);
 170                        if (*commands == 'K' || *commands == 'k') {
 171                                cmdline_memory_size <<= 10;
 172                                commands++;
 173                        } else if (*commands=='M' || *commands=='m') {
 174                                cmdline_memory_size <<= 20;
 175                                commands++;
 176                        }
 177                }
 178                while (*commands && *commands != ' ')
 179                        commands++;
 180        }
 181}
 182
 183extern unsigned short root_flags;
 184extern unsigned short root_dev;
 185extern unsigned short ram_flags;
 186#define RAMDISK_IMAGE_START_MASK        0x07FF
 187#define RAMDISK_PROMPT_FLAG             0x8000
 188#define RAMDISK_LOAD_FLAG               0x4000
 189
 190extern int root_mountflags;
 191
 192char reboot_command[COMMAND_LINE_SIZE];
 193
 194struct cpuid_patch_entry {
 195        unsigned int    addr;
 196        unsigned int    sun4d[3];
 197        unsigned int    leon[3];
 198};
 199extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
 200
 201static void __init per_cpu_patch(void)
 202{
 203        struct cpuid_patch_entry *p;
 204
 205        if (sparc_cpu_model == sun4m) {
 206                /* Nothing to do, this is what the unpatched code
 207                 * targets.
 208                 */
 209                return;
 210        }
 211
 212        p = &__cpuid_patch;
 213        while (p < &__cpuid_patch_end) {
 214                unsigned long addr = p->addr;
 215                unsigned int *insns;
 216
 217                switch (sparc_cpu_model) {
 218                case sun4d:
 219                        insns = &p->sun4d[0];
 220                        break;
 221
 222                case sparc_leon:
 223                        insns = &p->leon[0];
 224                        break;
 225                default:
 226                        prom_printf("Unknown cpu type, halting.\n");
 227                        prom_halt();
 228                }
 229                *(unsigned int *) (addr + 0) = insns[0];
 230                flushi(addr + 0);
 231                *(unsigned int *) (addr + 4) = insns[1];
 232                flushi(addr + 4);
 233                *(unsigned int *) (addr + 8) = insns[2];
 234                flushi(addr + 8);
 235
 236                p++;
 237        }
 238}
 239
 240struct leon_1insn_patch_entry {
 241        unsigned int addr;
 242        unsigned int insn;
 243};
 244
 245enum sparc_cpu sparc_cpu_model;
 246EXPORT_SYMBOL(sparc_cpu_model);
 247
 248static __init void leon_patch(void)
 249{
 250        struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch;
 251        struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end;
 252
 253        /* Default instruction is leon - no patching */
 254        if (sparc_cpu_model == sparc_leon)
 255                return;
 256
 257        while (start < end) {
 258                unsigned long addr = start->addr;
 259
 260                *(unsigned int *)(addr) = start->insn;
 261                flushi(addr);
 262
 263                start++;
 264        }
 265}
 266
 267struct tt_entry *sparc_ttable;
 268static struct pt_regs fake_swapper_regs;
 269
 270/* Called from head_32.S - before we have setup anything
 271 * in the kernel. Be very careful with what you do here.
 272 */
 273void __init sparc32_start_kernel(struct linux_romvec *rp)
 274{
 275        prom_init(rp);
 276
 277        /* Set sparc_cpu_model */
 278        sparc_cpu_model = sun_unknown;
 279        if (!strcmp(&cputypval[0], "sun4m"))
 280                sparc_cpu_model = sun4m;
 281        if (!strcmp(&cputypval[0], "sun4s"))
 282                sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
 283        if (!strcmp(&cputypval[0], "sun4d"))
 284                sparc_cpu_model = sun4d;
 285        if (!strcmp(&cputypval[0], "sun4e"))
 286                sparc_cpu_model = sun4e;
 287        if (!strcmp(&cputypval[0], "sun4u"))
 288                sparc_cpu_model = sun4u;
 289        if (!strncmp(&cputypval[0], "leon" , 4))
 290                sparc_cpu_model = sparc_leon;
 291
 292        leon_patch();
 293        start_kernel();
 294}
 295
 296void __init setup_arch(char **cmdline_p)
 297{
 298        int i;
 299        unsigned long highest_paddr;
 300
 301        sparc_ttable = &trapbase;
 302
 303        /* Initialize PROM console and command line. */
 304        *cmdline_p = prom_getbootargs();
 305        strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
 306        parse_early_param();
 307
 308        boot_flags_init(*cmdline_p);
 309
 310        register_console(&prom_early_console);
 311
 312        printk("ARCH: ");
 313        switch(sparc_cpu_model) {
 314        case sun4m:
 315                printk("SUN4M\n");
 316                break;
 317        case sun4d:
 318                printk("SUN4D\n");
 319                break;
 320        case sun4e:
 321                printk("SUN4E\n");
 322                break;
 323        case sun4u:
 324                printk("SUN4U\n");
 325                break;
 326        case sparc_leon:
 327                printk("LEON\n");
 328                break;
 329        default:
 330                printk("UNKNOWN!\n");
 331                break;
 332        }
 333
 334#ifdef CONFIG_DUMMY_CONSOLE
 335        conswitchp = &dummy_con;
 336#endif
 337
 338        idprom_init();
 339        load_mmu();
 340
 341        phys_base = 0xffffffffUL;
 342        highest_paddr = 0UL;
 343        for (i = 0; sp_banks[i].num_bytes != 0; i++) {
 344                unsigned long top;
 345
 346                if (sp_banks[i].base_addr < phys_base)
 347                        phys_base = sp_banks[i].base_addr;
 348                top = sp_banks[i].base_addr +
 349                        sp_banks[i].num_bytes;
 350                if (highest_paddr < top)
 351                        highest_paddr = top;
 352        }
 353        pfn_base = phys_base >> PAGE_SHIFT;
 354
 355        if (!root_flags)
 356                root_mountflags &= ~MS_RDONLY;
 357        ROOT_DEV = old_decode_dev(root_dev);
 358#ifdef CONFIG_BLK_DEV_RAM
 359        rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
 360        rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
 361        rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
 362#endif
 363
 364        prom_setsync(prom_sync_me);
 365
 366        if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) &&
 367           ((*(short *)linux_dbvec) != -1)) {
 368                printk("Booted under KADB. Syncing trap table.\n");
 369                (*(linux_dbvec->teach_debugger))();
 370        }
 371
 372        init_task.thread.kregs = &fake_swapper_regs;
 373
 374        /* Run-time patch instructions to match the cpu model */
 375        per_cpu_patch();
 376
 377        paging_init();
 378
 379        smp_setup_cpu_possible_map();
 380}
 381
 382extern int stop_a_enabled;
 383
 384void sun_do_break(void)
 385{
 386        if (!stop_a_enabled)
 387                return;
 388
 389        printk("\n");
 390        flush_user_windows();
 391
 392        prom_cmdline();
 393}
 394EXPORT_SYMBOL(sun_do_break);
 395
 396int stop_a_enabled = 1;
 397
 398static int __init topology_init(void)
 399{
 400        int i, ncpus, err;
 401
 402        /* Count the number of physically present processors in
 403         * the machine, even on uniprocessor, so that /proc/cpuinfo
 404         * output is consistent with 2.4.x
 405         */
 406        ncpus = 0;
 407        while (!cpu_find_by_instance(ncpus, NULL, NULL))
 408                ncpus++;
 409        ncpus_probed = ncpus;
 410
 411        err = 0;
 412        for_each_online_cpu(i) {
 413                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
 414                if (!p)
 415                        err = -ENOMEM;
 416                else
 417                        register_cpu(p, i);
 418        }
 419
 420        return err;
 421}
 422
 423subsys_initcall(topology_init);
 424