cfe.c 8.2 KB

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