linux/arch/sparc/kernel/setup.c
<<
>>
Prefs
   1/*  $Id: setup.c,v 1.126 2001/11/13 00:49:27 davem Exp $
   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/a.out.h>
  20#include <linux/screen_info.h>
  21#include <linux/delay.h>
  22#include <linux/fs.h>
  23#include <linux/seq_file.h>
  24#include <linux/syscalls.h>
  25#include <linux/kdev_t.h>
  26#include <linux/major.h>
  27#include <linux/string.h>
  28#include <linux/init.h>
  29#include <linux/interrupt.h>
  30#include <linux/console.h>
  31#include <linux/spinlock.h>
  32#include <linux/root_dev.h>
  33#include <linux/cpu.h>
  34#include <linux/kdebug.h>
  35
  36#include <asm/system.h>
  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/machines.h>
  47#include <asm/cpudata.h>
  48#include <asm/setup.h>
  49
  50struct screen_info screen_info = {
  51        0, 0,                   /* orig-x, orig-y */
  52        0,                      /* unused */
  53        0,                      /* orig-video-page */
  54        0,                      /* orig-video-mode */
  55        128,                    /* orig-video-cols */
  56        0,0,0,                  /* ega_ax, ega_bx, ega_cx */
  57        54,                     /* orig-video-lines */
  58        0,                      /* orig-video-isVGA */
  59        16                      /* orig-video-points */
  60};
  61
  62/* Typing sync at the prom prompt calls the function pointed to by
  63 * romvec->pv_synchook which I set to the following function.
  64 * This should sync all filesystems and return, for now it just
  65 * prints out pretty messages and returns.
  66 */
  67
  68extern unsigned long trapbase;
  69void (*prom_palette)(int);
  70
  71/* Pretty sick eh? */
  72void 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        if (prom_palette)
  85                prom_palette(1);
  86        prom_printf("PROM SYNC COMMAND...\n");
  87        show_free_areas();
  88        if(current->pid != 0) {
  89                local_irq_enable();
  90                sys_sync();
  91                local_irq_disable();
  92        }
  93        prom_printf("Returning to prom\n");
  94
  95        __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
  96                             "nop\n\t"
  97                             "nop\n\t"
  98                             "nop\n\t" : : "r" (prom_tbr));
  99        local_irq_restore(flags);
 100
 101        return;
 102}
 103
 104unsigned int boot_flags __initdata = 0;
 105#define BOOTME_DEBUG  0x1
 106
 107/* Exported for mm/init.c:paging_init. */
 108unsigned long cmdline_memory_size __initdata = 0;
 109
 110static void
 111prom_console_write(struct console *con, const char *s, unsigned n)
 112{
 113        prom_write(s, n);
 114}
 115
 116static struct console prom_debug_console = {
 117        .name =         "debug",
 118        .write =        prom_console_write,
 119        .flags =        CON_PRINTBUFFER,
 120        .index =        -1,
 121};
 122
 123/* 
 124 * Process kernel command line switches that are specific to the
 125 * SPARC or that require special low-level processing.
 126 */
 127static void __init process_switch(char c)
 128{
 129        switch (c) {
 130        case 'd':
 131                boot_flags |= BOOTME_DEBUG;
 132                break;
 133        case 's':
 134                break;
 135        case 'h':
 136                prom_printf("boot_flags_init: Halt!\n");
 137                prom_halt();
 138                break;
 139        case 'p':
 140                /* Use PROM debug console. */
 141                register_console(&prom_debug_console);
 142                break;
 143        default:
 144                printk("Unknown boot switch (-%c)\n", c);
 145                break;
 146        }
 147}
 148
 149static void __init process_console(char *commands)
 150{
 151        serial_console = 0;
 152        commands += 8;
 153        /* Linux-style serial */
 154        if (!strncmp(commands, "ttyS", 4))
 155                serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
 156        else if (!strncmp(commands, "tty", 3)) {
 157                char c = *(commands + 3);
 158                /* Solaris-style serial */
 159                if (c == 'a' || c == 'b')
 160                        serial_console = c - 'a' + 1;
 161                /* else Linux-style fbcon, not serial */
 162        }
 163#if defined(CONFIG_PROM_CONSOLE)
 164        if (!strncmp(commands, "prom", 4)) {
 165                char *p;
 166
 167                for (p = commands - 8; *p && *p != ' '; p++)
 168                        *p = ' ';
 169                conswitchp = &prom_con;
 170        }
 171#endif
 172}
 173
 174static void __init boot_flags_init(char *commands)
 175{
 176        while (*commands) {
 177                /* Move to the start of the next "argument". */
 178                while (*commands && *commands == ' ')
 179                        commands++;
 180
 181                /* Process any command switches, otherwise skip it. */
 182                if (*commands == '\0')
 183                        break;
 184                if (*commands == '-') {
 185                        commands++;
 186                        while (*commands && *commands != ' ')
 187                                process_switch(*commands++);
 188                        continue;
 189                }
 190                if (!strncmp(commands, "console=", 8)) {
 191                        process_console(commands);
 192                } else if (!strncmp(commands, "mem=", 4)) {
 193                        /*
 194                         * "mem=XXX[kKmM] overrides the PROM-reported
 195                         * memory size.
 196                         */
 197                        cmdline_memory_size = simple_strtoul(commands + 4,
 198                                                     &commands, 0);
 199                        if (*commands == 'K' || *commands == 'k') {
 200                                cmdline_memory_size <<= 10;
 201                                commands++;
 202                        } else if (*commands=='M' || *commands=='m') {
 203                                cmdline_memory_size <<= 20;
 204                                commands++;
 205                        }
 206                }
 207                while (*commands && *commands != ' ')
 208                        commands++;
 209        }
 210}
 211
 212/* This routine will in the future do all the nasty prom stuff
 213 * to probe for the mmu type and its parameters, etc. This will
 214 * also be where SMP things happen plus the Sparc specific memory
 215 * physical memory probe as on the alpha.
 216 */
 217
 218extern int prom_probe_memory(void);
 219extern void sun4c_probe_vac(void);
 220extern char cputypval;
 221extern unsigned long start, end;
 222extern void panic_setup(char *, int *);
 223
 224extern unsigned short root_flags;
 225extern unsigned short root_dev;
 226extern unsigned short ram_flags;
 227#define RAMDISK_IMAGE_START_MASK        0x07FF
 228#define RAMDISK_PROMPT_FLAG             0x8000
 229#define RAMDISK_LOAD_FLAG               0x4000
 230
 231extern int root_mountflags;
 232
 233char reboot_command[COMMAND_LINE_SIZE];
 234enum sparc_cpu sparc_cpu_model;
 235
 236struct tt_entry *sparc_ttable;
 237
 238struct pt_regs fake_swapper_regs;
 239
 240void __init setup_arch(char **cmdline_p)
 241{
 242        int i;
 243        unsigned long highest_paddr;
 244
 245        sparc_ttable = (struct tt_entry *) &start;
 246
 247        /* Initialize PROM console and command line. */
 248        *cmdline_p = prom_getbootargs();
 249        strcpy(boot_command_line, *cmdline_p);
 250
 251        /* Set sparc_cpu_model */
 252        sparc_cpu_model = sun_unknown;
 253        if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
 254        if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
 255        if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
 256        if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; }  /* CP-1200 with PROM 2.30 -E */
 257        if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
 258        if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
 259        if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
 260
 261#ifdef CONFIG_SUN4
 262        if (sparc_cpu_model != sun4) {
 263                prom_printf("This kernel is for Sun4 architecture only.\n");
 264                prom_halt();
 265        }
 266#endif
 267        printk("ARCH: ");
 268        switch(sparc_cpu_model) {
 269        case sun4:
 270                printk("SUN4\n");
 271                break;
 272        case sun4c:
 273                printk("SUN4C\n");
 274                break;
 275        case sun4m:
 276                printk("SUN4M\n");
 277                break;
 278        case sun4d:
 279                printk("SUN4D\n");
 280                break;
 281        case sun4e:
 282                printk("SUN4E\n");
 283                break;
 284        case sun4u:
 285                printk("SUN4U\n");
 286                break;
 287        default:
 288                printk("UNKNOWN!\n");
 289                break;
 290        };
 291
 292#ifdef CONFIG_DUMMY_CONSOLE
 293        conswitchp = &dummy_con;
 294#elif defined(CONFIG_PROM_CONSOLE)
 295        conswitchp = &prom_con;
 296#endif
 297        boot_flags_init(*cmdline_p);
 298
 299        idprom_init();
 300        if (ARCH_SUN4C_SUN4)
 301                sun4c_probe_vac();
 302        load_mmu();
 303        (void) prom_probe_memory();
 304
 305        phys_base = 0xffffffffUL;
 306        highest_paddr = 0UL;
 307        for (i = 0; sp_banks[i].num_bytes != 0; i++) {
 308                unsigned long top;
 309
 310                if (sp_banks[i].base_addr < phys_base)
 311                        phys_base = sp_banks[i].base_addr;
 312                top = sp_banks[i].base_addr +
 313                        sp_banks[i].num_bytes;
 314                if (highest_paddr < top)
 315                        highest_paddr = top;
 316        }
 317        pfn_base = phys_base >> PAGE_SHIFT;
 318
 319        if (!root_flags)
 320                root_mountflags &= ~MS_RDONLY;
 321        ROOT_DEV = old_decode_dev(root_dev);
 322#ifdef CONFIG_BLK_DEV_RAM
 323        rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
 324        rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
 325        rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
 326#endif
 327
 328        prom_setsync(prom_sync_me);
 329
 330        if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
 331           ((*(short *)linux_dbvec) != -1)) {
 332                printk("Booted under KADB. Syncing trap table.\n");
 333                (*(linux_dbvec->teach_debugger))();
 334        }
 335
 336        init_mm.context = (unsigned long) NO_CONTEXT;
 337        init_task.thread.kregs = &fake_swapper_regs;
 338
 339        paging_init();
 340
 341        smp_setup_cpu_possible_map();
 342}
 343
 344static int __init set_preferred_console(void)
 345{
 346        int idev, odev;
 347
 348        /* The user has requested a console so this is already set up. */
 349        if (serial_console >= 0)
 350                return -EBUSY;
 351
 352        idev = prom_query_input_device();
 353        odev = prom_query_output_device();
 354        if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
 355                serial_console = 0;
 356        } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
 357                serial_console = 1;
 358        } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
 359                serial_console = 2;
 360        } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
 361                prom_printf("MrCoffee ttya\n");
 362                serial_console = 1;
 363        } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
 364                serial_console = 0;
 365                prom_printf("MrCoffee keyboard\n");
 366        } else {
 367                prom_printf("Confusing console (idev %d, odev %d)\n",
 368                    idev, odev);
 369                serial_console = 1;
 370        }
 371
 372        if (serial_console)
 373                return add_preferred_console("ttyS", serial_console - 1, NULL);
 374
 375        return -ENODEV;
 376}
 377console_initcall(set_preferred_console);
 378
 379extern char *sparc_cpu_type;
 380extern char *sparc_fpu_type;
 381
 382static int ncpus_probed;
 383
 384static int show_cpuinfo(struct seq_file *m, void *__unused)
 385{
 386        seq_printf(m,
 387                   "cpu\t\t: %s\n"
 388                   "fpu\t\t: %s\n"
 389                   "promlib\t\t: Version %d Revision %d\n"
 390                   "prom\t\t: %d.%d\n"
 391                   "type\t\t: %s\n"
 392                   "ncpus probed\t: %d\n"
 393                   "ncpus active\t: %d\n"
 394#ifndef CONFIG_SMP
 395                   "CPU0Bogo\t: %lu.%02lu\n"
 396                   "CPU0ClkTck\t: %ld\n"
 397#endif
 398                   ,
 399                   sparc_cpu_type ? sparc_cpu_type : "undetermined",
 400                   sparc_fpu_type ? sparc_fpu_type : "undetermined",
 401                   romvec->pv_romvers,
 402                   prom_rev,
 403                   romvec->pv_printrev >> 16,
 404                   romvec->pv_printrev & 0xffff,
 405                   &cputypval,
 406                   ncpus_probed,
 407                   num_online_cpus()
 408#ifndef CONFIG_SMP
 409                   , cpu_data(0).udelay_val/(500000/HZ),
 410                   (cpu_data(0).udelay_val/(5000/HZ)) % 100,
 411                   cpu_data(0).clock_tick
 412#endif
 413                );
 414
 415#ifdef CONFIG_SMP
 416        smp_bogo(m);
 417#endif
 418        mmu_info(m);
 419#ifdef CONFIG_SMP
 420        smp_info(m);
 421#endif
 422        return 0;
 423}
 424
 425static void *c_start(struct seq_file *m, loff_t *pos)
 426{
 427        /* The pointer we are returning is arbitrary,
 428         * it just has to be non-NULL and not IS_ERR
 429         * in the success case.
 430         */
 431        return *pos == 0 ? &c_start : NULL;
 432}
 433
 434static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 435{
 436        ++*pos;
 437        return c_start(m, pos);
 438}
 439
 440static void c_stop(struct seq_file *m, void *v)
 441{
 442}
 443
 444struct seq_operations cpuinfo_op = {
 445        .start =c_start,
 446        .next = c_next,
 447        .stop = c_stop,
 448        .show = show_cpuinfo,
 449};
 450
 451extern int stop_a_enabled;
 452
 453void sun_do_break(void)
 454{
 455        if (!stop_a_enabled)
 456                return;
 457
 458        printk("\n");
 459        flush_user_windows();
 460
 461        prom_cmdline();
 462}
 463
 464int serial_console = -1;
 465int stop_a_enabled = 1;
 466
 467static int __init topology_init(void)
 468{
 469        int i, ncpus, err;
 470
 471        /* Count the number of physically present processors in
 472         * the machine, even on uniprocessor, so that /proc/cpuinfo
 473         * output is consistent with 2.4.x
 474         */
 475        ncpus = 0;
 476        while (!cpu_find_by_instance(ncpus, NULL, NULL))
 477                ncpus++;
 478        ncpus_probed = ncpus;
 479
 480        err = 0;
 481        for_each_online_cpu(i) {
 482                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
 483                if (!p)
 484                        err = -ENOMEM;
 485                else
 486                        register_cpu(p, i);
 487        }
 488
 489        return err;
 490}
 491
 492subsys_initcall(topology_init);
 493
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.