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;
 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        switch(sparc_cpu_model) {
 313        case sun4m:
 314                pr_info("ARCH: SUN4M\n");
 315                break;
 316        case sun4d:
 317                pr_info("ARCH: SUN4D\n");
 318                break;
 319        case sun4e:
 320                pr_info("ARCH: SUN4E\n");
 321                break;
 322        case sun4u:
 323                pr_info("ARCH: SUN4U\n");
 324                break;
 325        case sparc_leon:
 326                pr_info("ARCH: LEON\n");
 327                break;
 328        default:
 329                pr_info("ARCH: UNKNOWN!\n");
 330                break;
 331        }
 332
 333        idprom_init();
 334        load_mmu();
 335
 336        phys_base = 0xffffffffUL;
 337        highest_paddr = 0UL;
 338        for (i = 0; sp_banks[i].num_bytes != 0; i++) {
 339                unsigned long top;
 340
 341                if (sp_banks[i].base_addr < phys_base)
 342                        phys_base = sp_banks[i].base_addr;
 343                top = sp_banks[i].base_addr +
 344                        sp_banks[i].num_bytes;
 345                if (highest_paddr < top)
 346                        highest_paddr = top;
 347        }
 348        pfn_base = phys_base >> PAGE_SHIFT;
 349
 350        if (!root_flags)
 351                root_mountflags &= ~MS_RDONLY;
 352        ROOT_DEV = old_decode_dev(root_dev);
 353#ifdef CONFIG_BLK_DEV_RAM
 354        rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
 355#endif
 356
 357        prom_setsync(prom_sync_me);
 358
 359        if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) &&
 360           ((*(short *)linux_dbvec) != -1)) {
 361                printk("Booted under KADB. Syncing trap table.\n");
 362                (*(linux_dbvec->teach_debugger))();
 363        }
 364
 365        /* Run-time patch instructions to match the cpu model */
 366        per_cpu_patch();
 367
 368        paging_init();
 369
 370        smp_setup_cpu_possible_map();
 371}
 372
 373extern int stop_a_enabled;
 374
 375void sun_do_break(void)
 376{
 377        if (!stop_a_enabled)
 378                return;
 379
 380        printk("\n");
 381        flush_user_windows();
 382
 383        prom_cmdline();
 384}
 385EXPORT_SYMBOL(sun_do_break);
 386
 387int stop_a_enabled = 1;
 388
 389static int __init topology_init(void)
 390{
 391        int i, ncpus, err;
 392
 393        /* Count the number of physically present processors in
 394         * the machine, even on uniprocessor, so that /proc/cpuinfo
 395         * output is consistent with 2.4.x
 396         */
 397        ncpus = 0;
 398        while (!cpu_find_by_instance(ncpus, NULL, NULL))
 399                ncpus++;
 400        ncpus_probed = ncpus;
 401
 402        err = 0;
 403        for_each_online_cpu(i) {
 404                struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
 405                if (!p)
 406                        err = -ENOMEM;
 407                else
 408                        register_cpu(p, i);
 409        }
 410
 411        return err;
 412}
 413
 414subsys_initcall(topology_init);
 415