root/arch/mips/sibyte/common/cfe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cfe_linux_exit
  2. cfe_linux_restart
  3. cfe_linux_halt
  4. prom_meminit
  5. initrd_setup
  6. prom_init
  7. prom_free_prom_memory
  8. prom_putchar

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
   4  */
   5 
   6 #include <linux/init.h>
   7 #include <linux/kernel.h>
   8 #include <linux/linkage.h>
   9 #include <linux/mm.h>
  10 #include <linux/blkdev.h>
  11 #include <linux/memblock.h>
  12 #include <linux/pm.h>
  13 #include <linux/smp.h>
  14 
  15 #include <asm/bootinfo.h>
  16 #include <asm/reboot.h>
  17 #include <asm/setup.h>
  18 #include <asm/sibyte/board.h>
  19 #include <asm/smp-ops.h>
  20 
  21 #include <asm/fw/cfe/cfe_api.h>
  22 #include <asm/fw/cfe/cfe_error.h>
  23 
  24 /* Max ram addressable in 32-bit segments */
  25 #ifdef CONFIG_64BIT
  26 #define MAX_RAM_SIZE (~0ULL)
  27 #else
  28 #ifdef CONFIG_HIGHMEM
  29 #ifdef CONFIG_PHYS_ADDR_T_64BIT
  30 #define MAX_RAM_SIZE (~0ULL)
  31 #else
  32 #define MAX_RAM_SIZE (0xffffffffULL)
  33 #endif
  34 #else
  35 #define MAX_RAM_SIZE (0x1fffffffULL)
  36 #endif
  37 #endif
  38 
  39 #define SIBYTE_MAX_MEM_REGIONS 8
  40 phys_addr_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS];
  41 phys_addr_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS];
  42 unsigned int board_mem_region_count;
  43 
  44 int cfe_cons_handle;
  45 
  46 #ifdef CONFIG_BLK_DEV_INITRD
  47 extern unsigned long initrd_start, initrd_end;
  48 #endif
  49 
  50 static void __noreturn cfe_linux_exit(void *arg)
  51 {
  52         int warm = *(int *)arg;
  53 
  54         if (smp_processor_id()) {
  55                 static int reboot_smp;
  56 
  57                 /* Don't repeat the process from another CPU */
  58                 if (!reboot_smp) {
  59                         /* Get CPU 0 to do the cfe_exit */
  60                         reboot_smp = 1;
  61                         smp_call_function(cfe_linux_exit, arg, 0);
  62                 }
  63         } else {
  64                 printk("Passing control back to CFE...\n");
  65                 cfe_exit(warm, 0);
  66                 printk("cfe_exit returned??\n");
  67         }
  68         while (1);
  69 }
  70 
  71 static void __noreturn cfe_linux_restart(char *command)
  72 {
  73         static const int zero;
  74 
  75         cfe_linux_exit((void *)&zero);
  76 }
  77 
  78 static void __noreturn cfe_linux_halt(void)
  79 {
  80         static const int one = 1;
  81 
  82         cfe_linux_exit((void *)&one);
  83 }
  84 
  85 static __init void prom_meminit(void)
  86 {
  87         u64 addr, size, type; /* regardless of PHYS_ADDR_T_64BIT */
  88         int mem_flags = 0;
  89         unsigned int idx;
  90         int rd_flag;
  91 #ifdef CONFIG_BLK_DEV_INITRD
  92         unsigned long initrd_pstart;
  93         unsigned long initrd_pend;
  94 
  95         initrd_pstart = CPHYSADDR(initrd_start);
  96         initrd_pend = CPHYSADDR(initrd_end);
  97         if (initrd_start &&
  98             ((initrd_pstart > MAX_RAM_SIZE)
  99              || (initrd_pend > MAX_RAM_SIZE))) {
 100                 panic("initrd out of addressable memory");
 101         }
 102 
 103 #endif /* INITRD */
 104 
 105         for (idx = 0; cfe_enummem(idx, mem_flags, &addr, &size, &type) != CFE_ERR_NOMORE;
 106              idx++) {
 107                 rd_flag = 0;
 108                 if (type == CFE_MI_AVAILABLE) {
 109                         /*
 110                          * See if this block contains (any portion of) the
 111                          * ramdisk
 112                          */
 113 #ifdef CONFIG_BLK_DEV_INITRD
 114                         if (initrd_start) {
 115                                 if ((initrd_pstart > addr) &&
 116                                     (initrd_pstart < (addr + size))) {
 117                                         add_memory_region(addr,
 118                                                           initrd_pstart - addr,
 119                                                           BOOT_MEM_RAM);
 120                                         rd_flag = 1;
 121                                 }
 122                                 if ((initrd_pend > addr) &&
 123                                     (initrd_pend < (addr + size))) {
 124                                         add_memory_region(initrd_pend,
 125                                                 (addr + size) - initrd_pend,
 126                                                  BOOT_MEM_RAM);
 127                                         rd_flag = 1;
 128                                 }
 129                         }
 130 #endif
 131                         if (!rd_flag) {
 132                                 if (addr > MAX_RAM_SIZE)
 133                                         continue;
 134                                 if (addr+size > MAX_RAM_SIZE)
 135                                         size = MAX_RAM_SIZE - (addr+size) + 1;
 136                                 /*
 137                                  * memcpy/__copy_user prefetch, which
 138                                  * will cause a bus error for
 139                                  * KSEG/KUSEG addrs not backed by RAM.
 140                                  * Hence, reserve some padding for the
 141                                  * prefetch distance.
 142                                  */
 143                                 if (size > 512)
 144                                         size -= 512;
 145                                 add_memory_region(addr, size, BOOT_MEM_RAM);
 146                         }
 147                         board_mem_region_addrs[board_mem_region_count] = addr;
 148                         board_mem_region_sizes[board_mem_region_count] = size;
 149                         board_mem_region_count++;
 150                         if (board_mem_region_count ==
 151                             SIBYTE_MAX_MEM_REGIONS) {
 152                                 /*
 153                                  * Too many regions.  Need to configure more
 154                                  */
 155                                 while(1);
 156                         }
 157                 }
 158         }
 159 #ifdef CONFIG_BLK_DEV_INITRD
 160         if (initrd_start) {
 161                 add_memory_region(initrd_pstart, initrd_pend - initrd_pstart,
 162                                   BOOT_MEM_RESERVED);
 163         }
 164 #endif
 165 }
 166 
 167 #ifdef CONFIG_BLK_DEV_INITRD
 168 static int __init initrd_setup(char *str)
 169 {
 170         char rdarg[64];
 171         int idx;
 172         char *tmp, *endptr;
 173         unsigned long initrd_size;
 174 
 175         /* Make a copy of the initrd argument so we can smash it up here */
 176         for (idx = 0; idx < sizeof(rdarg)-1; idx++) {
 177                 if (!str[idx] || (str[idx] == ' ')) break;
 178                 rdarg[idx] = str[idx];
 179         }
 180 
 181         rdarg[idx] = 0;
 182         str = rdarg;
 183 
 184         /*
 185          *Initrd location comes in the form "<hex size of ramdisk in bytes>@<location in memory>"
 186          *  e.g. initrd=3abfd@80010000.  This is set up by the loader.
 187          */
 188         for (tmp = str; *tmp != '@'; tmp++) {
 189                 if (!*tmp) {
 190                         goto fail;
 191                 }
 192         }
 193         *tmp = 0;
 194         tmp++;
 195         if (!*tmp) {
 196                 goto fail;
 197         }
 198         initrd_size = simple_strtoul(str, &endptr, 16);
 199         if (*endptr) {
 200                 *(tmp-1) = '@';
 201                 goto fail;
 202         }
 203         *(tmp-1) = '@';
 204         initrd_start = simple_strtoul(tmp, &endptr, 16);
 205         if (*endptr) {
 206                 goto fail;
 207         }
 208         initrd_end = initrd_start + initrd_size;
 209         printk("Found initrd of %lx@%lx\n", initrd_size, initrd_start);
 210         return 1;
 211  fail:
 212         printk("Bad initrd argument.  Disabling initrd\n");
 213         initrd_start = 0;
 214         initrd_end = 0;
 215         return 1;
 216 }
 217 
 218 #endif
 219 
 220 extern const struct plat_smp_ops sb_smp_ops;
 221 extern const struct plat_smp_ops bcm1480_smp_ops;
 222 
 223 /*
 224  * prom_init is called just after the cpu type is determined, from setup_arch()
 225  */
 226 void __init prom_init(void)
 227 {
 228         uint64_t cfe_ept, cfe_handle;
 229         unsigned int cfe_eptseal;
 230         int argc = fw_arg0;
 231         char **envp = (char **) fw_arg2;
 232         int *prom_vec = (int *) fw_arg3;
 233 
 234         _machine_restart   = cfe_linux_restart;
 235         _machine_halt      = cfe_linux_halt;
 236         pm_power_off = cfe_linux_halt;
 237 
 238         /*
 239          * Check if a loader was used; if NOT, the 4 arguments are
 240          * what CFE gives us (handle, 0, EPT and EPTSEAL)
 241          */
 242         if (argc < 0) {
 243                 cfe_handle = (uint64_t)(long)argc;
 244                 cfe_ept = (long)envp;
 245                 cfe_eptseal = (uint32_t)(unsigned long)prom_vec;
 246         } else {
 247                 if ((int32_t)(long)prom_vec < 0) {
 248                         /*
 249                          * Old loader; all it gives us is the handle,
 250                          * so use the "known" entrypoint and assume
 251                          * the seal.
 252                          */
 253                         cfe_handle = (uint64_t)(long)prom_vec;
 254                         cfe_ept = (uint64_t)((int32_t)0x9fc00500);
 255                         cfe_eptseal = CFE_EPTSEAL;
 256                 } else {
 257                         /*
 258                          * Newer loaders bundle the handle/ept/eptseal
 259                          * Note: prom_vec is in the loader's useg
 260                          * which is still alive in the TLB.
 261                          */
 262                         cfe_handle = (uint64_t)((int32_t *)prom_vec)[0];
 263                         cfe_ept = (uint64_t)((int32_t *)prom_vec)[2];
 264                         cfe_eptseal = (unsigned int)((uint32_t *)prom_vec)[3];
 265                 }
 266         }
 267         if (cfe_eptseal != CFE_EPTSEAL) {
 268                 /* too early for panic to do any good */
 269                 printk("CFE's entrypoint seal doesn't match. Spinning.");
 270                 while (1) ;
 271         }
 272         cfe_init(cfe_handle, cfe_ept);
 273         /*
 274          * Get the handle for (at least) prom_putchar, possibly for
 275          * boot console
 276          */
 277         cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
 278         if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, COMMAND_LINE_SIZE) < 0) {
 279                 if (argc >= 0) {
 280                         /* The loader should have set the command line */
 281                         /* too early for panic to do any good */
 282                         printk("LINUX_CMDLINE not defined in cfe.");
 283                         while (1) ;
 284                 }
 285         }
 286 
 287 #ifdef CONFIG_BLK_DEV_INITRD
 288         {
 289                 char *ptr;
 290                 /* Need to find out early whether we've got an initrd.  So scan
 291                    the list looking now */
 292                 for (ptr = arcs_cmdline; *ptr; ptr++) {
 293                         while (*ptr == ' ') {
 294                                 ptr++;
 295                         }
 296                         if (!strncmp(ptr, "initrd=", 7)) {
 297                                 initrd_setup(ptr+7);
 298                                 break;
 299                         } else {
 300                                 while (*ptr && (*ptr != ' ')) {
 301                                         ptr++;
 302                                 }
 303                         }
 304                 }
 305         }
 306 #endif /* CONFIG_BLK_DEV_INITRD */
 307 
 308         /* Not sure this is needed, but it's the safe way. */
 309         arcs_cmdline[COMMAND_LINE_SIZE-1] = 0;
 310 
 311         prom_meminit();
 312 
 313 #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
 314         register_smp_ops(&sb_smp_ops);
 315 #endif
 316 #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
 317         register_smp_ops(&bcm1480_smp_ops);
 318 #endif
 319 }
 320 
 321 void __init prom_free_prom_memory(void)
 322 {
 323         /* Not sure what I'm supposed to do here.  Nothing, I think */
 324 }
 325 
 326 void prom_putchar(char c)
 327 {
 328         int ret;
 329 
 330         while ((ret = cfe_write(cfe_cons_handle, &c, 1)) == 0)
 331                 ;
 332 }

/* [<][>][^][v][top][bottom][index][help] */