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