Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/arch/sparc/kernel/setup.c
0004  *
0005  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
0006  *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
0007  */
0008 
0009 #include <linux/errno.h>
0010 #include <linux/sched.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mm.h>
0013 #include <linux/stddef.h>
0014 #include <linux/unistd.h>
0015 #include <linux/ptrace.h>
0016 #include <linux/slab.h>
0017 #include <linux/initrd.h>
0018 #include <asm/smp.h>
0019 #include <linux/user.h>
0020 #include <linux/screen_info.h>
0021 #include <linux/delay.h>
0022 #include <linux/fs.h>
0023 #include <linux/seq_file.h>
0024 #include <linux/syscalls.h>
0025 #include <linux/kdev_t.h>
0026 #include <linux/major.h>
0027 #include <linux/string.h>
0028 #include <linux/init.h>
0029 #include <linux/interrupt.h>
0030 #include <linux/console.h>
0031 #include <linux/spinlock.h>
0032 #include <linux/root_dev.h>
0033 #include <linux/cpu.h>
0034 #include <linux/kdebug.h>
0035 #include <linux/export.h>
0036 #include <linux/start_kernel.h>
0037 #include <uapi/linux/mount.h>
0038 
0039 #include <asm/io.h>
0040 #include <asm/processor.h>
0041 #include <asm/oplib.h>
0042 #include <asm/page.h>
0043 #include <asm/traps.h>
0044 #include <asm/vaddrs.h>
0045 #include <asm/mbus.h>
0046 #include <asm/idprom.h>
0047 #include <asm/cpudata.h>
0048 #include <asm/setup.h>
0049 #include <asm/cacheflush.h>
0050 #include <asm/sections.h>
0051 
0052 #include "kernel.h"
0053 
0054 struct screen_info screen_info = {
0055     0, 0,           /* orig-x, orig-y */
0056     0,          /* unused */
0057     0,          /* orig-video-page */
0058     0,          /* orig-video-mode */
0059     128,            /* orig-video-cols */
0060     0,0,0,          /* ega_ax, ega_bx, ega_cx */
0061     54,         /* orig-video-lines */
0062     0,                      /* orig-video-isVGA */
0063     16                      /* orig-video-points */
0064 };
0065 
0066 /* Typing sync at the prom prompt calls the function pointed to by
0067  * romvec->pv_synchook which I set to the following function.
0068  * This should sync all filesystems and return, for now it just
0069  * prints out pretty messages and returns.
0070  */
0071 
0072 /* Pretty sick eh? */
0073 static void prom_sync_me(void)
0074 {
0075     unsigned long prom_tbr, flags;
0076 
0077     /* XXX Badly broken. FIX! - Anton */
0078     local_irq_save(flags);
0079     __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
0080     __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
0081                  "nop\n\t"
0082                  "nop\n\t"
0083                  "nop\n\t" : : "r" (&trapbase));
0084 
0085     prom_printf("PROM SYNC COMMAND...\n");
0086     show_free_areas(0, NULL);
0087     if (!is_idle_task(current)) {
0088         local_irq_enable();
0089         ksys_sync();
0090         local_irq_disable();
0091     }
0092     prom_printf("Returning to prom\n");
0093 
0094     __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
0095                  "nop\n\t"
0096                  "nop\n\t"
0097                  "nop\n\t" : : "r" (prom_tbr));
0098     local_irq_restore(flags);
0099 }
0100 
0101 static unsigned int boot_flags __initdata = 0;
0102 #define BOOTME_DEBUG  0x1
0103 
0104 /* Exported for mm/init.c:paging_init. */
0105 unsigned long cmdline_memory_size __initdata = 0;
0106 
0107 /* which CPU booted us (0xff = not set) */
0108 unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */
0109 
0110 static void
0111 prom_console_write(struct console *con, const char *s, unsigned int n)
0112 {
0113     prom_write(s, n);
0114 }
0115 
0116 static struct console prom_early_console = {
0117     .name =     "earlyprom",
0118     .write =    prom_console_write,
0119     .flags =    CON_PRINTBUFFER | CON_BOOT,
0120     .index =    -1,
0121 };
0122 
0123 /* 
0124  * Process kernel command line switches that are specific to the
0125  * SPARC or that require special low-level processing.
0126  */
0127 static void __init process_switch(char c)
0128 {
0129     switch (c) {
0130     case 'd':
0131         boot_flags |= BOOTME_DEBUG;
0132         break;
0133     case 's':
0134         break;
0135     case 'h':
0136         prom_printf("boot_flags_init: Halt!\n");
0137         prom_halt();
0138         break;
0139     case 'p':
0140         prom_early_console.flags &= ~CON_BOOT;
0141         break;
0142     default:
0143         printk("Unknown boot switch (-%c)\n", c);
0144         break;
0145     }
0146 }
0147 
0148 static void __init boot_flags_init(char *commands)
0149 {
0150     while (*commands) {
0151         /* Move to the start of the next "argument". */
0152         while (*commands == ' ')
0153             commands++;
0154 
0155         /* Process any command switches, otherwise skip it. */
0156         if (*commands == '\0')
0157             break;
0158         if (*commands == '-') {
0159             commands++;
0160             while (*commands && *commands != ' ')
0161                 process_switch(*commands++);
0162             continue;
0163         }
0164         if (!strncmp(commands, "mem=", 4)) {
0165             /*
0166              * "mem=XXX[kKmM] overrides the PROM-reported
0167              * memory size.
0168              */
0169             cmdline_memory_size = simple_strtoul(commands + 4,
0170                              &commands, 0);
0171             if (*commands == 'K' || *commands == 'k') {
0172                 cmdline_memory_size <<= 10;
0173                 commands++;
0174             } else if (*commands=='M' || *commands=='m') {
0175                 cmdline_memory_size <<= 20;
0176                 commands++;
0177             }
0178         }
0179         while (*commands && *commands != ' ')
0180             commands++;
0181     }
0182 }
0183 
0184 extern unsigned short root_flags;
0185 extern unsigned short root_dev;
0186 extern unsigned short ram_flags;
0187 #define RAMDISK_IMAGE_START_MASK    0x07FF
0188 #define RAMDISK_PROMPT_FLAG     0x8000
0189 #define RAMDISK_LOAD_FLAG       0x4000
0190 
0191 extern int root_mountflags;
0192 
0193 char reboot_command[COMMAND_LINE_SIZE];
0194 
0195 struct cpuid_patch_entry {
0196     unsigned int    addr;
0197     unsigned int    sun4d[3];
0198     unsigned int    leon[3];
0199 };
0200 extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
0201 
0202 static void __init per_cpu_patch(void)
0203 {
0204     struct cpuid_patch_entry *p;
0205 
0206     if (sparc_cpu_model == sun4m) {
0207         /* Nothing to do, this is what the unpatched code
0208          * targets.
0209          */
0210         return;
0211     }
0212 
0213     p = &__cpuid_patch;
0214     while (p < &__cpuid_patch_end) {
0215         unsigned long addr = p->addr;
0216         unsigned int *insns;
0217 
0218         switch (sparc_cpu_model) {
0219         case sun4d:
0220             insns = &p->sun4d[0];
0221             break;
0222 
0223         case sparc_leon:
0224             insns = &p->leon[0];
0225             break;
0226         default:
0227             prom_printf("Unknown cpu type, halting.\n");
0228             prom_halt();
0229         }
0230         *(unsigned int *) (addr + 0) = insns[0];
0231         flushi(addr + 0);
0232         *(unsigned int *) (addr + 4) = insns[1];
0233         flushi(addr + 4);
0234         *(unsigned int *) (addr + 8) = insns[2];
0235         flushi(addr + 8);
0236 
0237         p++;
0238     }
0239 }
0240 
0241 struct leon_1insn_patch_entry {
0242     unsigned int addr;
0243     unsigned int insn;
0244 };
0245 
0246 enum sparc_cpu sparc_cpu_model;
0247 EXPORT_SYMBOL(sparc_cpu_model);
0248 
0249 static __init void leon_patch(void)
0250 {
0251     struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch;
0252     struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end;
0253 
0254     /* Default instruction is leon - no patching */
0255     if (sparc_cpu_model == sparc_leon)
0256         return;
0257 
0258     while (start < end) {
0259         unsigned long addr = start->addr;
0260 
0261         *(unsigned int *)(addr) = start->insn;
0262         flushi(addr);
0263 
0264         start++;
0265     }
0266 }
0267 
0268 struct tt_entry *sparc_ttable;
0269 
0270 /* Called from head_32.S - before we have setup anything
0271  * in the kernel. Be very careful with what you do here.
0272  */
0273 void __init sparc32_start_kernel(struct linux_romvec *rp)
0274 {
0275     prom_init(rp);
0276 
0277     /* Set sparc_cpu_model */
0278     sparc_cpu_model = sun_unknown;
0279     if (!strcmp(&cputypval[0], "sun4m"))
0280         sparc_cpu_model = sun4m;
0281     if (!strcmp(&cputypval[0], "sun4s"))
0282         sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
0283     if (!strcmp(&cputypval[0], "sun4d"))
0284         sparc_cpu_model = sun4d;
0285     if (!strcmp(&cputypval[0], "sun4e"))
0286         sparc_cpu_model = sun4e;
0287     if (!strcmp(&cputypval[0], "sun4u"))
0288         sparc_cpu_model = sun4u;
0289     if (!strncmp(&cputypval[0], "leon" , 4))
0290         sparc_cpu_model = sparc_leon;
0291 
0292     leon_patch();
0293     start_kernel();
0294 }
0295 
0296 void __init setup_arch(char **cmdline_p)
0297 {
0298     int i;
0299     unsigned long highest_paddr;
0300 
0301     sparc_ttable = &trapbase;
0302 
0303     /* Initialize PROM console and command line. */
0304     *cmdline_p = prom_getbootargs();
0305     strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
0306     parse_early_param();
0307 
0308     boot_flags_init(*cmdline_p);
0309 
0310     register_console(&prom_early_console);
0311 
0312     switch(sparc_cpu_model) {
0313     case sun4m:
0314         pr_info("ARCH: SUN4M\n");
0315         break;
0316     case sun4d:
0317         pr_info("ARCH: SUN4D\n");
0318         break;
0319     case sun4e:
0320         pr_info("ARCH: SUN4E\n");
0321         break;
0322     case sun4u:
0323         pr_info("ARCH: SUN4U\n");
0324         break;
0325     case sparc_leon:
0326         pr_info("ARCH: LEON\n");
0327         break;
0328     default:
0329         pr_info("ARCH: UNKNOWN!\n");
0330         break;
0331     }
0332 
0333     idprom_init();
0334     load_mmu();
0335 
0336     phys_base = 0xffffffffUL;
0337     highest_paddr = 0UL;
0338     for (i = 0; sp_banks[i].num_bytes != 0; i++) {
0339         unsigned long top;
0340 
0341         if (sp_banks[i].base_addr < phys_base)
0342             phys_base = sp_banks[i].base_addr;
0343         top = sp_banks[i].base_addr +
0344             sp_banks[i].num_bytes;
0345         if (highest_paddr < top)
0346             highest_paddr = top;
0347     }
0348     pfn_base = phys_base >> PAGE_SHIFT;
0349 
0350     if (!root_flags)
0351         root_mountflags &= ~MS_RDONLY;
0352     ROOT_DEV = old_decode_dev(root_dev);
0353 #ifdef CONFIG_BLK_DEV_RAM
0354     rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
0355 #endif
0356 
0357     prom_setsync(prom_sync_me);
0358 
0359     if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) &&
0360        ((*(short *)linux_dbvec) != -1)) {
0361         printk("Booted under KADB. Syncing trap table.\n");
0362         (*(linux_dbvec->teach_debugger))();
0363     }
0364 
0365     /* Run-time patch instructions to match the cpu model */
0366     per_cpu_patch();
0367 
0368     paging_init();
0369 
0370     smp_setup_cpu_possible_map();
0371 }
0372 
0373 extern int stop_a_enabled;
0374 
0375 void sun_do_break(void)
0376 {
0377     if (!stop_a_enabled)
0378         return;
0379 
0380     printk("\n");
0381     flush_user_windows();
0382 
0383     prom_cmdline();
0384 }
0385 EXPORT_SYMBOL(sun_do_break);
0386 
0387 int stop_a_enabled = 1;
0388 
0389 static int __init topology_init(void)
0390 {
0391     int i, ncpus, err;
0392 
0393     /* Count the number of physically present processors in
0394      * the machine, even on uniprocessor, so that /proc/cpuinfo
0395      * output is consistent with 2.4.x
0396      */
0397     ncpus = 0;
0398     while (!cpu_find_by_instance(ncpus, NULL, NULL))
0399         ncpus++;
0400     ncpus_probed = ncpus;
0401 
0402     err = 0;
0403     for_each_online_cpu(i) {
0404         struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
0405         if (!p)
0406             err = -ENOMEM;
0407         else
0408             register_cpu(p, i);
0409     }
0410 
0411     return err;
0412 }
0413 
0414 subsys_initcall(topology_init);