11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds * for more details.
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Copyright (C) 1995 Linus Torvalds
71da177e4SLinus Torvalds * Copyright (C) 1995 Waldorf Electronics
81da177e4SLinus Torvalds * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Ralf Baechle
91da177e4SLinus Torvalds * Copyright (C) 1996 Stoned Elipot
101da177e4SLinus Torvalds * Copyright (C) 1999 Silicon Graphics, Inc.
1120d60d99SMaciej W. Rozycki * Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki
121da177e4SLinus Torvalds */
131da177e4SLinus Torvalds #include <linux/init.h>
147f066a22SThomas Gleixner #include <linux/cpu.h>
157f066a22SThomas Gleixner #include <linux/delay.h>
161da177e4SLinus Torvalds #include <linux/ioport.h>
1773bc256dSPaul Gortmaker #include <linux/export.h>
18894673eeSJon Smirl #include <linux/screen_info.h>
199d15ffc8STejun Heo #include <linux/memblock.h>
201da177e4SLinus Torvalds #include <linux/initrd.h>
211da177e4SLinus Torvalds #include <linux/root_dev.h>
221da177e4SLinus Torvalds #include <linux/highmem.h>
231da177e4SLinus Torvalds #include <linux/console.h>
2422a9835cSDave Hansen #include <linux/pfn.h>
256312e0eeSAtsushi Nemoto #include <linux/debugfs.h>
267aa1c8f4SRalf Baechle #include <linux/kexec.h>
274d9f77d2SJohn Crispin #include <linux/sizes.h>
28f4649382SZubair Lutfullah Kakakhel #include <linux/device.h>
290b1abd1fSChristoph Hellwig #include <linux/dma-map-ops.h>
308f4703aaSAurelien Jarno #include <linux/decompress/generic.h>
3173346081SMarcin Nowakowski #include <linux/of_fdt.h>
32be8fa1cbSTiezhu Yang #include <linux/dmi.h>
33b306c5f5SJinyang He #include <linux/crash_dump.h>
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds #include <asm/addrspace.h>
361da177e4SLinus Torvalds #include <asm/bootinfo.h>
3720d60d99SMaciej W. Rozycki #include <asm/bugs.h>
38ec74e361SRalf Baechle #include <asm/cache.h>
39e934945dSJames Hogan #include <asm/cdmm.h>
401da177e4SLinus Torvalds #include <asm/cpu.h>
4175dcfc1dSPaul Burton #include <asm/debug.h>
42795d82edSTiezhu Yang #include <asm/mmzone.h>
431da177e4SLinus Torvalds #include <asm/sections.h>
441da177e4SLinus Torvalds #include <asm/setup.h>
4587353d8aSRalf Baechle #include <asm/smp-ops.h>
46f2ffa5abSDezhong Diao #include <asm/prom.h>
47056a68ceSJason A. Donenfeld #include <asm/fw/fw.h>
481da177e4SLinus Torvalds
4987db537dSAaro Koskinen #ifdef CONFIG_MIPS_ELF_APPENDED_DTB
509ae31e2aSMauri Sandberg char __section(".appended_dtb") __appended_dtb[0x100000];
5187db537dSAaro Koskinen #endif /* CONFIG_MIPS_ELF_APPENDED_DTB */
5287db537dSAaro Koskinen
53ec74e361SRalf Baechle struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds EXPORT_SYMBOL(cpu_data);
561da177e4SLinus Torvalds
57*d9a5d5c4SArnd Bergmann #ifdef CONFIG_VGA_CONSOLE
581da177e4SLinus Torvalds struct screen_info screen_info;
591da177e4SLinus Torvalds #endif
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds * Setup information
631da177e4SLinus Torvalds *
641da177e4SLinus Torvalds * These are initialized so they are in the .data section
651da177e4SLinus Torvalds */
66ec74e361SRalf Baechle unsigned long mips_machtype __read_mostly = MACH_UNKNOWN;
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds EXPORT_SYMBOL(mips_machtype);
691da177e4SLinus Torvalds
706acc7d48SDmitri Vorobiev static char __initdata command_line[COMMAND_LINE_SIZE];
716acc7d48SDmitri Vorobiev char __initdata arcs_cmdline[COMMAND_LINE_SIZE];
726acc7d48SDmitri Vorobiev
736acc7d48SDmitri Vorobiev #ifdef CONFIG_CMDLINE_BOOL
749dd422f6SPaul Burton static const char builtin_cmdline[] __initconst = CONFIG_CMDLINE;
75b7340422SPaul Burton #else
76b7340422SPaul Burton static const char builtin_cmdline[] __initconst = "";
776acc7d48SDmitri Vorobiev #endif
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds /*
801da177e4SLinus Torvalds * mips_io_port_base is the begin of the address space to which x86 style
811da177e4SLinus Torvalds * I/O ports are mapped.
821da177e4SLinus Torvalds */
8312051b31SNick Desaulniers unsigned long mips_io_port_base = -1;
841da177e4SLinus Torvalds EXPORT_SYMBOL(mips_io_port_base);
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds static struct resource code_resource = { .name = "Kernel code", };
871da177e4SLinus Torvalds static struct resource data_resource = { .name = "Kernel data", };
88e0c5f36bSDavid Daney static struct resource bss_resource = { .name = "Kernel bss", };
891da177e4SLinus Torvalds
90d4d3ef8bSJinyang He unsigned long __kaslr_offset __ro_after_init;
91d4d3ef8bSJinyang He EXPORT_SYMBOL(__kaslr_offset);
92d4d3ef8bSJinyang He
934d9f77d2SJohn Crispin static void *detect_magic __initdata = detect_memory_region;
944d9f77d2SJohn Crispin
956c359eb1SPaul Burton #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
966c359eb1SPaul Burton unsigned long ARCH_PFN_OFFSET;
976c359eb1SPaul Burton EXPORT_SYMBOL(ARCH_PFN_OFFSET);
986c359eb1SPaul Burton #endif
996c359eb1SPaul Burton
detect_memory_region(phys_addr_t start,phys_addr_t sz_min,phys_addr_t sz_max)10015d45cceSRalf Baechle void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max)
1014d9f77d2SJohn Crispin {
1024d9f77d2SJohn Crispin void *dm = &detect_magic;
10315d45cceSRalf Baechle phys_addr_t size;
1044d9f77d2SJohn Crispin
1054d9f77d2SJohn Crispin for (size = sz_min; size < sz_max; size <<= 1) {
1064d9f77d2SJohn Crispin if (!memcmp(dm, dm + size, sizeof(detect_magic)))
1074d9f77d2SJohn Crispin break;
1084d9f77d2SJohn Crispin }
1094d9f77d2SJohn Crispin
1104d9f77d2SJohn Crispin pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n",
1114d9f77d2SJohn Crispin ((unsigned long long) size) / SZ_1M,
1124d9f77d2SJohn Crispin (unsigned long long) start,
1134d9f77d2SJohn Crispin ((unsigned long long) sz_min) / SZ_1M,
1144d9f77d2SJohn Crispin ((unsigned long long) sz_max) / SZ_1M);
1154d9f77d2SJohn Crispin
116e7ae8d17SThomas Bogendoerfer memblock_add(start, size);
1174d9f77d2SJohn Crispin }
1184d9f77d2SJohn Crispin
119d2043ca8SFranck Bui-Huu /*
120d2043ca8SFranck Bui-Huu * Manage initrd
121d2043ca8SFranck Bui-Huu */
122d2043ca8SFranck Bui-Huu #ifdef CONFIG_BLK_DEV_INITRD
123d2043ca8SFranck Bui-Huu
rd_start_early(char * p)124a09fc446SFranck Bui-Huu static int __init rd_start_early(char *p)
1251da177e4SLinus Torvalds {
126a09fc446SFranck Bui-Huu unsigned long start = memparse(p, &p);
1271da177e4SLinus Torvalds
128875d43e7SRalf Baechle #ifdef CONFIG_64BIT
129a7837b76SFranck Bui-Huu /* Guess if the sign extension was forgotten by bootloader */
130a7837b76SFranck Bui-Huu if (start < XKPHYS)
131a7837b76SFranck Bui-Huu start = (int)start;
1321da177e4SLinus Torvalds #endif
133a09fc446SFranck Bui-Huu initrd_start = start;
134a09fc446SFranck Bui-Huu initrd_end += start;
1351da177e4SLinus Torvalds return 0;
1361da177e4SLinus Torvalds }
137a09fc446SFranck Bui-Huu early_param("rd_start", rd_start_early);
138a09fc446SFranck Bui-Huu
rd_size_early(char * p)139a09fc446SFranck Bui-Huu static int __init rd_size_early(char *p)
140a09fc446SFranck Bui-Huu {
141a09fc446SFranck Bui-Huu initrd_end += memparse(p, &p);
142a09fc446SFranck Bui-Huu return 0;
143a09fc446SFranck Bui-Huu }
144a09fc446SFranck Bui-Huu early_param("rd_size", rd_size_early);
1451da177e4SLinus Torvalds
146a7837b76SFranck Bui-Huu /* it returns the next free pfn after initrd */
init_initrd(void)147d2043ca8SFranck Bui-Huu static unsigned long __init init_initrd(void)
1481da177e4SLinus Torvalds {
149a7837b76SFranck Bui-Huu unsigned long end;
1501da177e4SLinus Torvalds
151d2043ca8SFranck Bui-Huu /*
152a09fc446SFranck Bui-Huu * Board specific code or command line parser should have
153a09fc446SFranck Bui-Huu * already set up initrd_start and initrd_end. In these cases
154a09fc446SFranck Bui-Huu * perfom sanity checks and use them if all looks good.
155d2043ca8SFranck Bui-Huu */
15632028f1fSRalf Baechle if (!initrd_start || initrd_end <= initrd_start)
157a7837b76SFranck Bui-Huu goto disable;
158a7837b76SFranck Bui-Huu
159a7837b76SFranck Bui-Huu if (initrd_start & ~PAGE_MASK) {
160a64ae7a2SMike Crowe pr_err("initrd start must be page aligned\n");
161a7837b76SFranck Bui-Huu goto disable;
162a7837b76SFranck Bui-Huu }
163a7837b76SFranck Bui-Huu
164a7837b76SFranck Bui-Huu /*
165a7837b76SFranck Bui-Huu * Sanitize initrd addresses. For example firmware
166a7837b76SFranck Bui-Huu * can't guess if they need to pass them through
167a7837b76SFranck Bui-Huu * 64-bits values if the kernel has been built in pure
168a7837b76SFranck Bui-Huu * 32-bit. We need also to switch from KSEG0 to XKPHYS
169a7837b76SFranck Bui-Huu * addresses now, so the code can now safely use __pa().
170a7837b76SFranck Bui-Huu */
171a7837b76SFranck Bui-Huu end = __pa(initrd_end);
172a7837b76SFranck Bui-Huu initrd_end = (unsigned long)__va(end);
173a7837b76SFranck Bui-Huu initrd_start = (unsigned long)__va(__pa(initrd_start));
174a7837b76SFranck Bui-Huu
1754897a898SLiviu Dudau if (initrd_start < PAGE_OFFSET) {
1764897a898SLiviu Dudau pr_err("initrd start < PAGE_OFFSET\n");
1774897a898SLiviu Dudau goto disable;
1784897a898SLiviu Dudau }
1794897a898SLiviu Dudau
180a7837b76SFranck Bui-Huu ROOT_DEV = Root_RAM0;
181a7837b76SFranck Bui-Huu return PFN_UP(end);
182a7837b76SFranck Bui-Huu disable:
183a09fc446SFranck Bui-Huu initrd_start = 0;
184a09fc446SFranck Bui-Huu initrd_end = 0;
185a7837b76SFranck Bui-Huu return 0;
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds
1888f4703aaSAurelien Jarno /* In some conditions (e.g. big endian bootloader with a little endian
1898f4703aaSAurelien Jarno kernel), the initrd might appear byte swapped. Try to detect this and
1908f4703aaSAurelien Jarno byte swap it if needed. */
maybe_bswap_initrd(void)1918f4703aaSAurelien Jarno static void __init maybe_bswap_initrd(void)
1928f4703aaSAurelien Jarno {
1938f4703aaSAurelien Jarno #if defined(CONFIG_CPU_CAVIUM_OCTEON)
1948f4703aaSAurelien Jarno u64 buf;
1958f4703aaSAurelien Jarno
1968f4703aaSAurelien Jarno /* Check for CPIO signature */
1978f4703aaSAurelien Jarno if (!memcmp((void *)initrd_start, "070701", 6))
1988f4703aaSAurelien Jarno return;
1998f4703aaSAurelien Jarno
2008f4703aaSAurelien Jarno /* Check for compressed initrd */
2018f4703aaSAurelien Jarno if (decompress_method((unsigned char *)initrd_start, 8, NULL))
2028f4703aaSAurelien Jarno return;
2038f4703aaSAurelien Jarno
2048f4703aaSAurelien Jarno /* Try again with a byte swapped header */
2058f4703aaSAurelien Jarno buf = swab64p((u64 *)initrd_start);
2068f4703aaSAurelien Jarno if (!memcmp(&buf, "070701", 6) ||
2078f4703aaSAurelien Jarno decompress_method((unsigned char *)(&buf), 8, NULL)) {
2088f4703aaSAurelien Jarno unsigned long i;
2098f4703aaSAurelien Jarno
2108f4703aaSAurelien Jarno pr_info("Byteswapped initrd detected\n");
2118f4703aaSAurelien Jarno for (i = initrd_start; i < ALIGN(initrd_end, 8); i += 8)
2128f4703aaSAurelien Jarno swab64s((u64 *)i);
2138f4703aaSAurelien Jarno }
2148f4703aaSAurelien Jarno #endif
2158f4703aaSAurelien Jarno }
2168f4703aaSAurelien Jarno
finalize_initrd(void)217d2043ca8SFranck Bui-Huu static void __init finalize_initrd(void)
218d2043ca8SFranck Bui-Huu {
219d2043ca8SFranck Bui-Huu unsigned long size = initrd_end - initrd_start;
220d2043ca8SFranck Bui-Huu
221d2043ca8SFranck Bui-Huu if (size == 0) {
222d2043ca8SFranck Bui-Huu printk(KERN_INFO "Initrd not found or empty");
223d2043ca8SFranck Bui-Huu goto disable;
224d2043ca8SFranck Bui-Huu }
225d4df6d4eSFranck Bui-Huu if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
226a64ae7a2SMike Crowe printk(KERN_ERR "Initrd extends beyond end of memory");
227d2043ca8SFranck Bui-Huu goto disable;
228d2043ca8SFranck Bui-Huu }
229d2043ca8SFranck Bui-Huu
2308f4703aaSAurelien Jarno maybe_bswap_initrd();
2318f4703aaSAurelien Jarno
232bcec54bfSMike Rapoport memblock_reserve(__pa(initrd_start), size);
233d2043ca8SFranck Bui-Huu initrd_below_start_ok = 1;
234d2043ca8SFranck Bui-Huu
235a64ae7a2SMike Crowe pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
236d2043ca8SFranck Bui-Huu initrd_start, size);
237d2043ca8SFranck Bui-Huu return;
238d2043ca8SFranck Bui-Huu disable:
239a64ae7a2SMike Crowe printk(KERN_CONT " - disabling initrd\n");
240d2043ca8SFranck Bui-Huu initrd_start = 0;
241d2043ca8SFranck Bui-Huu initrd_end = 0;
242d2043ca8SFranck Bui-Huu }
243d2043ca8SFranck Bui-Huu
244d2043ca8SFranck Bui-Huu #else /* !CONFIG_BLK_DEV_INITRD */
245d2043ca8SFranck Bui-Huu
init_initrd(void)2469ba126cfSRalf Baechle static unsigned long __init init_initrd(void)
2479ba126cfSRalf Baechle {
2489ba126cfSRalf Baechle return 0;
2499ba126cfSRalf Baechle }
2509ba126cfSRalf Baechle
251d2043ca8SFranck Bui-Huu #define finalize_initrd() do {} while (0)
252d2043ca8SFranck Bui-Huu
253d2043ca8SFranck Bui-Huu #endif
254d2043ca8SFranck Bui-Huu
255b6f1f0deSFranck Bui-Huu /*
256d2043ca8SFranck Bui-Huu * Initialize the bootmem allocator. It also setup initrd related data
257d2043ca8SFranck Bui-Huu * if needed.
258b6f1f0deSFranck Bui-Huu */
259268a2d60SJiaxun Yang #if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON64) && defined(CONFIG_NUMA))
260d2043ca8SFranck Bui-Huu
bootmem_init(void)261d2043ca8SFranck Bui-Huu static void __init bootmem_init(void)
262d2043ca8SFranck Bui-Huu {
263d2043ca8SFranck Bui-Huu init_initrd();
264d2043ca8SFranck Bui-Huu finalize_initrd();
265d2043ca8SFranck Bui-Huu }
266d2043ca8SFranck Bui-Huu
267d2043ca8SFranck Bui-Huu #else /* !CONFIG_SGI_IP27 */
268d2043ca8SFranck Bui-Huu
bootmem_init(void)269d2043ca8SFranck Bui-Huu static void __init bootmem_init(void)
270d2043ca8SFranck Bui-Huu {
271a94e4f24SJiaxun Yang phys_addr_t ramstart, ramend;
27261a2f1aeSThomas Bogendoerfer unsigned long start, end;
27361a2f1aeSThomas Bogendoerfer int i;
274a94e4f24SJiaxun Yang
275a94e4f24SJiaxun Yang ramstart = memblock_start_of_DRAM();
276a94e4f24SJiaxun Yang ramend = memblock_end_of_DRAM();
277d2043ca8SFranck Bui-Huu
278d2043ca8SFranck Bui-Huu /*
279f9a7febdSGreg Ungerer * Sanity check any INITRD first. We don't take it into account
280f9a7febdSGreg Ungerer * for bootmem setup initially, rely on the end-of-kernel-code
281f9a7febdSGreg Ungerer * as our memory range starting point. Once bootmem is inited we
282f9a7febdSGreg Ungerer * will reserve the area used for the initrd.
283d2043ca8SFranck Bui-Huu */
284f9a7febdSGreg Ungerer init_initrd();
285b6f1f0deSFranck Bui-Huu
286b93ddc4fSSerge Semin /* Reserve memory occupied by kernel. */
287b93ddc4fSSerge Semin memblock_reserve(__pa_symbol(&_text),
288b93ddc4fSSerge Semin __pa_symbol(&_end) - __pa_symbol(&_text));
289bcec54bfSMike Rapoport
290a94e4f24SJiaxun Yang /* max_low_pfn is not a number of pages but the end pfn of low mem */
2916c359eb1SPaul Burton
2926c359eb1SPaul Burton #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
2936c359eb1SPaul Burton ARCH_PFN_OFFSET = PFN_UP(ramstart);
2946c359eb1SPaul Burton #else
29567a3ba25SMarcin Nowakowski /*
29667a3ba25SMarcin Nowakowski * Reserve any memory between the start of RAM and PHYS_OFFSET
29767a3ba25SMarcin Nowakowski */
298a94e4f24SJiaxun Yang if (ramstart > PHYS_OFFSET)
29966b416eeSThomas Bogendoerfer memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
30067a3ba25SMarcin Nowakowski
301a94e4f24SJiaxun Yang if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
302a64ae7a2SMike Crowe pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
303a94e4f24SJiaxun Yang (unsigned long)((PFN_UP(ramstart) - ARCH_PFN_OFFSET) * sizeof(struct page)),
304a94e4f24SJiaxun Yang (unsigned long)(PFN_UP(ramstart) - ARCH_PFN_OFFSET));
305db84dc61SFranck Bui-Huu }
3066c359eb1SPaul Burton #endif
307db84dc61SFranck Bui-Huu
308a94e4f24SJiaxun Yang min_low_pfn = ARCH_PFN_OFFSET;
309a94e4f24SJiaxun Yang max_pfn = PFN_DOWN(ramend);
31061a2f1aeSThomas Bogendoerfer for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {
3111da177e4SLinus Torvalds /*
312a94e4f24SJiaxun Yang * Skip highmem here so we get an accurate max_low_pfn if low
313a94e4f24SJiaxun Yang * memory stops short of high memory.
314a94e4f24SJiaxun Yang * If the region overlaps HIGHMEM_START, end is clipped so
315a94e4f24SJiaxun Yang * max_pfn excludes the highmem portion.
3161da177e4SLinus Torvalds */
317a94e4f24SJiaxun Yang if (start >= PFN_DOWN(HIGHMEM_START))
318a94e4f24SJiaxun Yang continue;
319a94e4f24SJiaxun Yang if (end > PFN_DOWN(HIGHMEM_START))
320a94e4f24SJiaxun Yang end = PFN_DOWN(HIGHMEM_START);
321a94e4f24SJiaxun Yang if (end > max_low_pfn)
322a94e4f24SJiaxun Yang max_low_pfn = end;
323a94e4f24SJiaxun Yang }
324a94e4f24SJiaxun Yang
325a94e4f24SJiaxun Yang if (min_low_pfn >= max_low_pfn)
326a94e4f24SJiaxun Yang panic("Incorrect memory mapping !!!");
327a94e4f24SJiaxun Yang
328a94e4f24SJiaxun Yang if (max_pfn > PFN_DOWN(HIGHMEM_START)) {
32966c8b147SSerge Semin max_low_pfn = PFN_DOWN(HIGHMEM_START);
3301da177e4SLinus Torvalds #ifdef CONFIG_HIGHMEM
33166c8b147SSerge Semin highstart_pfn = max_low_pfn;
332a94e4f24SJiaxun Yang highend_pfn = max_pfn;
333a94e4f24SJiaxun Yang #else
334a94e4f24SJiaxun Yang max_pfn = max_low_pfn;
3356ea3ba6fSSerge Semin #endif
33643064c0cSDavid Daney }
33743064c0cSDavid Daney
338d2043ca8SFranck Bui-Huu /*
339d2043ca8SFranck Bui-Huu * Reserve initrd memory if needed.
340d2043ca8SFranck Bui-Huu */
341d2043ca8SFranck Bui-Huu finalize_initrd();
342d2043ca8SFranck Bui-Huu }
343d2043ca8SFranck Bui-Huu
3441da177e4SLinus Torvalds #endif /* CONFIG_SGI_IP27 */
3451da177e4SLinus Torvalds
346982f6ffeSRalf Baechle static int usermem __initdata;
347a09fc446SFranck Bui-Huu
early_parse_mem(char * p)348a09fc446SFranck Bui-Huu static int __init early_parse_mem(char *p)
349a09fc446SFranck Bui-Huu {
350ad8f723aSJaedon Shin phys_addr_t start, size;
351a09fc446SFranck Bui-Huu
352fb3d6967STiezhu Yang if (!p) {
353fb3d6967STiezhu Yang pr_err("mem parameter is empty, do nothing\n");
354fb3d6967STiezhu Yang return -EINVAL;
355fb3d6967STiezhu Yang }
356fb3d6967STiezhu Yang
357a09fc446SFranck Bui-Huu /*
358a09fc446SFranck Bui-Huu * If a user specifies memory size, we
359a09fc446SFranck Bui-Huu * blow away any automatically generated
360a09fc446SFranck Bui-Huu * size.
361a09fc446SFranck Bui-Huu */
362a09fc446SFranck Bui-Huu if (usermem == 0) {
363a09fc446SFranck Bui-Huu usermem = 1;
364a94e4f24SJiaxun Yang memblock_remove(memblock_start_of_DRAM(),
365a94e4f24SJiaxun Yang memblock_end_of_DRAM() - memblock_start_of_DRAM());
366a09fc446SFranck Bui-Huu }
367a09fc446SFranck Bui-Huu start = 0;
368a09fc446SFranck Bui-Huu size = memparse(p, &p);
369a09fc446SFranck Bui-Huu if (*p == '@')
370a09fc446SFranck Bui-Huu start = memparse(p + 1, &p);
371a09fc446SFranck Bui-Huu
372795d82edSTiezhu Yang if (IS_ENABLED(CONFIG_NUMA))
373795d82edSTiezhu Yang memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE);
374795d82edSTiezhu Yang else
375e7ae8d17SThomas Bogendoerfer memblock_add(start, size);
37673fbc1ebSMarcin Nowakowski
377a09fc446SFranck Bui-Huu return 0;
378a09fc446SFranck Bui-Huu }
379a09fc446SFranck Bui-Huu early_param("mem", early_parse_mem);
3802925aba4SRalf Baechle
early_parse_memmap(char * p)381296a7624SMiodrag Dinic static int __init early_parse_memmap(char *p)
382296a7624SMiodrag Dinic {
383296a7624SMiodrag Dinic char *oldp;
384296a7624SMiodrag Dinic u64 start_at, mem_size;
385296a7624SMiodrag Dinic
386296a7624SMiodrag Dinic if (!p)
387296a7624SMiodrag Dinic return -EINVAL;
388296a7624SMiodrag Dinic
389296a7624SMiodrag Dinic if (!strncmp(p, "exactmap", 8)) {
390296a7624SMiodrag Dinic pr_err("\"memmap=exactmap\" invalid on MIPS\n");
391296a7624SMiodrag Dinic return 0;
392296a7624SMiodrag Dinic }
393296a7624SMiodrag Dinic
394296a7624SMiodrag Dinic oldp = p;
395296a7624SMiodrag Dinic mem_size = memparse(p, &p);
396296a7624SMiodrag Dinic if (p == oldp)
397296a7624SMiodrag Dinic return -EINVAL;
398296a7624SMiodrag Dinic
399296a7624SMiodrag Dinic if (*p == '@') {
400296a7624SMiodrag Dinic start_at = memparse(p+1, &p);
401e7ae8d17SThomas Bogendoerfer memblock_add(start_at, mem_size);
402296a7624SMiodrag Dinic } else if (*p == '#') {
403296a7624SMiodrag Dinic pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n");
404296a7624SMiodrag Dinic return -EINVAL;
405296a7624SMiodrag Dinic } else if (*p == '$') {
406296a7624SMiodrag Dinic start_at = memparse(p+1, &p);
407e7ae8d17SThomas Bogendoerfer memblock_add(start_at, mem_size);
408e7ae8d17SThomas Bogendoerfer memblock_reserve(start_at, mem_size);
409296a7624SMiodrag Dinic } else {
410296a7624SMiodrag Dinic pr_err("\"memmap\" invalid format!\n");
411296a7624SMiodrag Dinic return -EINVAL;
412296a7624SMiodrag Dinic }
413296a7624SMiodrag Dinic
414296a7624SMiodrag Dinic if (*p == '\0') {
415296a7624SMiodrag Dinic usermem = 1;
416296a7624SMiodrag Dinic return 0;
417296a7624SMiodrag Dinic } else
418296a7624SMiodrag Dinic return -EINVAL;
419296a7624SMiodrag Dinic }
420296a7624SMiodrag Dinic early_param("memmap", early_parse_memmap);
421296a7624SMiodrag Dinic
mips_reserve_vmcore(void)422b306c5f5SJinyang He static void __init mips_reserve_vmcore(void)
4234893fc88SCorey Minyard {
424b306c5f5SJinyang He #ifdef CONFIG_PROC_VMCORE
425b10d6bcaSMike Rapoport phys_addr_t start, end;
426b10d6bcaSMike Rapoport u64 i;
4274893fc88SCorey Minyard
428b306c5f5SJinyang He if (!elfcorehdr_size) {
429b10d6bcaSMike Rapoport for_each_mem_range(i, &start, &end) {
430b306c5f5SJinyang He if (elfcorehdr_addr >= start && elfcorehdr_addr < end) {
4314893fc88SCorey Minyard /*
4324893fc88SCorey Minyard * Reserve from the elf core header to the end of
4334893fc88SCorey Minyard * the memory segment, that should all be kdump
4344893fc88SCorey Minyard * reserved memory.
4354893fc88SCorey Minyard */
436b306c5f5SJinyang He elfcorehdr_size = end - elfcorehdr_addr;
4374893fc88SCorey Minyard break;
4384893fc88SCorey Minyard }
4394893fc88SCorey Minyard }
4404893fc88SCorey Minyard }
441b306c5f5SJinyang He
442b306c5f5SJinyang He pr_info("Reserving %ldKB of memory at %ldKB for kdump\n",
443b306c5f5SJinyang He (unsigned long)elfcorehdr_size >> 10, (unsigned long)elfcorehdr_addr >> 10);
444b306c5f5SJinyang He
445b306c5f5SJinyang He memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
4464893fc88SCorey Minyard #endif
447b306c5f5SJinyang He }
4484893fc88SCorey Minyard
449c2882b7fSPrem Mallappa #ifdef CONFIG_KEXEC
45026262396SYouling Tang
45126262396SYouling Tang /* 64M alignment for crash kernel regions */
45226262396SYouling Tang #define CRASH_ALIGN SZ_64M
45326262396SYouling Tang #define CRASH_ADDR_MAX SZ_512M
45426262396SYouling Tang
mips_parse_crashkernel(void)455c2882b7fSPrem Mallappa static void __init mips_parse_crashkernel(void)
456c2882b7fSPrem Mallappa {
457c2882b7fSPrem Mallappa unsigned long long total_mem;
458c2882b7fSPrem Mallappa unsigned long long crash_size, crash_base;
459c2882b7fSPrem Mallappa int ret;
460c2882b7fSPrem Mallappa
461a94e4f24SJiaxun Yang total_mem = memblock_phys_mem_size();
462c2882b7fSPrem Mallappa ret = parse_crashkernel(boot_command_line, total_mem,
463c2882b7fSPrem Mallappa &crash_size, &crash_base);
464c2882b7fSPrem Mallappa if (ret != 0 || crash_size <= 0)
465c2882b7fSPrem Mallappa return;
466c2882b7fSPrem Mallappa
46726262396SYouling Tang if (crash_base <= 0) {
468a7259df7SMike Rapoport crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
469a7259df7SMike Rapoport CRASH_ALIGN,
470a7259df7SMike Rapoport CRASH_ADDR_MAX);
47126262396SYouling Tang if (!crash_base) {
47226262396SYouling Tang pr_warn("crashkernel reservation failed - No suitable area found.\n");
47326262396SYouling Tang return;
47426262396SYouling Tang }
47526262396SYouling Tang } else {
47626262396SYouling Tang unsigned long long start;
47726262396SYouling Tang
478a7259df7SMike Rapoport start = memblock_phys_alloc_range(crash_size, 1,
479a7259df7SMike Rapoport crash_base,
480a7259df7SMike Rapoport crash_base + crash_size);
48126262396SYouling Tang if (start != crash_base) {
482a8f108d7SMarcin Nowakowski pr_warn("Invalid memory region reserved for crash kernel\n");
483a8f108d7SMarcin Nowakowski return;
484a8f108d7SMarcin Nowakowski }
48526262396SYouling Tang }
486a8f108d7SMarcin Nowakowski
487c2882b7fSPrem Mallappa crashk_res.start = crash_base;
488c2882b7fSPrem Mallappa crashk_res.end = crash_base + crash_size - 1;
489c2882b7fSPrem Mallappa }
490c2882b7fSPrem Mallappa
request_crashkernel(struct resource * res)491c2882b7fSPrem Mallappa static void __init request_crashkernel(struct resource *res)
492c2882b7fSPrem Mallappa {
493c2882b7fSPrem Mallappa int ret;
494c2882b7fSPrem Mallappa
495269aa43aSMarcin Nowakowski if (crashk_res.start == crashk_res.end)
496269aa43aSMarcin Nowakowski return;
497269aa43aSMarcin Nowakowski
498c2882b7fSPrem Mallappa ret = request_resource(res, &crashk_res);
499c2882b7fSPrem Mallappa if (!ret)
500c2882b7fSPrem Mallappa pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
501ecb98379SJulia Lawall (unsigned long)(resource_size(&crashk_res) >> 20),
502c2882b7fSPrem Mallappa (unsigned long)(crashk_res.start >> 20));
503c2882b7fSPrem Mallappa }
504c2882b7fSPrem Mallappa #else /* !defined(CONFIG_KEXEC) */
mips_parse_crashkernel(void)505c2882b7fSPrem Mallappa static void __init mips_parse_crashkernel(void)
506c2882b7fSPrem Mallappa {
507c2882b7fSPrem Mallappa }
508c2882b7fSPrem Mallappa
request_crashkernel(struct resource * res)509c2882b7fSPrem Mallappa static void __init request_crashkernel(struct resource *res)
510c2882b7fSPrem Mallappa {
511c2882b7fSPrem Mallappa }
512c2882b7fSPrem Mallappa #endif /* !defined(CONFIG_KEXEC) */
513c2882b7fSPrem Mallappa
check_kernel_sections_mem(void)514a94e4f24SJiaxun Yang static void __init check_kernel_sections_mem(void)
515a94e4f24SJiaxun Yang {
516d121f125SAlexander Sverdlin phys_addr_t start = __pa_symbol(&_text);
517d121f125SAlexander Sverdlin phys_addr_t size = __pa_symbol(&_end) - start;
518a94e4f24SJiaxun Yang
519a94e4f24SJiaxun Yang if (!memblock_is_region_memory(start, size)) {
520a94e4f24SJiaxun Yang pr_info("Kernel sections are not in the memory maps\n");
521a94e4f24SJiaxun Yang memblock_add(start, size);
522a94e4f24SJiaxun Yang }
523a94e4f24SJiaxun Yang }
524a94e4f24SJiaxun Yang
bootcmdline_append(const char * s,size_t max)5257784cac6SPaul Burton static void __init bootcmdline_append(const char *s, size_t max)
5267784cac6SPaul Burton {
5277784cac6SPaul Burton if (!s[0] || !max)
5287784cac6SPaul Burton return;
5297784cac6SPaul Burton
5307784cac6SPaul Burton if (boot_command_line[0])
5317784cac6SPaul Burton strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
5327784cac6SPaul Burton
5337784cac6SPaul Burton strlcat(boot_command_line, s, max);
5347784cac6SPaul Burton }
5357784cac6SPaul Burton
53697272776SPaul Burton #ifdef CONFIG_OF_EARLY_FLATTREE
53797272776SPaul Burton
bootcmdline_scan_chosen(unsigned long node,const char * uname,int depth,void * data)5387784cac6SPaul Burton static int __init bootcmdline_scan_chosen(unsigned long node, const char *uname,
5397784cac6SPaul Burton int depth, void *data)
5407784cac6SPaul Burton {
5417784cac6SPaul Burton bool *dt_bootargs = data;
5427784cac6SPaul Burton const char *p;
5437784cac6SPaul Burton int l;
5447784cac6SPaul Burton
5457784cac6SPaul Burton if (depth != 1 || !data ||
5467784cac6SPaul Burton (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
5477784cac6SPaul Burton return 0;
5487784cac6SPaul Burton
5497784cac6SPaul Burton p = of_get_flat_dt_prop(node, "bootargs", &l);
5507784cac6SPaul Burton if (p != NULL && l > 0) {
5517784cac6SPaul Burton bootcmdline_append(p, min(l, COMMAND_LINE_SIZE));
5527784cac6SPaul Burton *dt_bootargs = true;
5537784cac6SPaul Burton }
5547784cac6SPaul Burton
5557784cac6SPaul Burton return 1;
5567784cac6SPaul Burton }
5577784cac6SPaul Burton
55897272776SPaul Burton #endif /* CONFIG_OF_EARLY_FLATTREE */
55997272776SPaul Burton
bootcmdline_init(void)560bd6e3898SZhi Li static void __init bootcmdline_init(void)
5617784cac6SPaul Burton {
5627784cac6SPaul Burton bool dt_bootargs = false;
5637784cac6SPaul Burton
5647784cac6SPaul Burton /*
5657784cac6SPaul Burton * If CMDLINE_OVERRIDE is enabled then initializing the command line is
5667784cac6SPaul Burton * trivial - we simply use the built-in command line unconditionally &
5677784cac6SPaul Burton * unmodified.
5687784cac6SPaul Burton */
5697784cac6SPaul Burton if (IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) {
57088ca100cS陈学兵 strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
5717784cac6SPaul Burton return;
5727784cac6SPaul Burton }
5737784cac6SPaul Burton
5747784cac6SPaul Burton /*
5757784cac6SPaul Burton * If the user specified a built-in command line &
5767784cac6SPaul Burton * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
5777784cac6SPaul Burton * prepended to arguments from the bootloader or DT so we'll copy them
5787784cac6SPaul Burton * to the start of boot_command_line here. Otherwise, empty
5797784cac6SPaul Burton * boot_command_line to undo anything early_init_dt_scan_chosen() did.
5807784cac6SPaul Burton */
5817784cac6SPaul Burton if (IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
58288ca100cS陈学兵 strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
5837784cac6SPaul Burton else
5847784cac6SPaul Burton boot_command_line[0] = 0;
5857784cac6SPaul Burton
58697272776SPaul Burton #ifdef CONFIG_OF_EARLY_FLATTREE
5877784cac6SPaul Burton /*
5887784cac6SPaul Burton * If we're configured to take boot arguments from DT, look for those
5897784cac6SPaul Burton * now.
5907784cac6SPaul Burton */
5918e029eb0SPaul Cercueil if (IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) ||
5928e029eb0SPaul Cercueil IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND))
5937784cac6SPaul Burton of_scan_flat_dt(bootcmdline_scan_chosen, &dt_bootargs);
59497272776SPaul Burton #endif
5957784cac6SPaul Burton
5967784cac6SPaul Burton /*
5977784cac6SPaul Burton * If we didn't get any arguments from DT (regardless of whether that's
5987784cac6SPaul Burton * because we weren't configured to look for them, or because we looked
5997784cac6SPaul Burton * & found none) then we'll take arguments from the bootloader.
6007784cac6SPaul Burton * plat_mem_setup() should have filled arcs_cmdline with arguments from
6017784cac6SPaul Burton * the bootloader.
6027784cac6SPaul Burton */
6037784cac6SPaul Burton if (IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) || !dt_bootargs)
6047784cac6SPaul Burton bootcmdline_append(arcs_cmdline, COMMAND_LINE_SIZE);
6057784cac6SPaul Burton
6067784cac6SPaul Burton /*
6077784cac6SPaul Burton * If the user specified a built-in command line & we didn't already
6087784cac6SPaul Burton * prepend it, we append it to boot_command_line here.
6097784cac6SPaul Burton */
6107784cac6SPaul Burton if (IS_ENABLED(CONFIG_CMDLINE_BOOL) &&
6117784cac6SPaul Burton !IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
6127784cac6SPaul Burton bootcmdline_append(builtin_cmdline, COMMAND_LINE_SIZE);
6137784cac6SPaul Burton }
6142024972eSJonas Gorski
61552c985acSPaul Burton /*
61652c985acSPaul Burton * arch_mem_init - initialize memory management subsystem
61752c985acSPaul Burton *
61852c985acSPaul Burton * o plat_mem_setup() detects the memory configuration and will record detected
619e7ae8d17SThomas Bogendoerfer * memory areas using memblock_add.
62052c985acSPaul Burton *
62152c985acSPaul Burton * At this stage the memory configuration of the system is known to the
62252c985acSPaul Burton * kernel but generic memory management system is still entirely uninitialized.
62352c985acSPaul Burton *
62452c985acSPaul Burton * o bootmem_init()
62552c985acSPaul Burton * o sparse_init()
62652c985acSPaul Burton * o paging_init()
62752c985acSPaul Burton * o dma_contiguous_reserve()
62852c985acSPaul Burton *
62952c985acSPaul Burton * At this stage the bootmem allocator is ready to use.
63052c985acSPaul Burton *
63152c985acSPaul Burton * NOTE: historically plat_mem_setup did the entire platform initialization.
63252c985acSPaul Burton * This was rather impractical because it meant plat_mem_setup had to
63352c985acSPaul Burton * get away without any kind of memory allocator. To keep old code from
63452c985acSPaul Burton * breaking plat_setup was just renamed to plat_mem_setup and a second platform
63552c985acSPaul Burton * initialization hook for anything else was introduced.
63652c985acSPaul Burton */
arch_mem_init(char ** cmdline_p)6372925aba4SRalf Baechle static void __init arch_mem_init(char **cmdline_p)
6382925aba4SRalf Baechle {
639951d223cSPaul Burton /* call board setup routine */
640951d223cSPaul Burton plat_mem_setup();
64125517ed4SHuacai Chen memblock_set_bottom_up(true);
642951d223cSPaul Burton
643bd6e3898SZhi Li bootcmdline_init();
64488ca100cS陈学兵 strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
6452925aba4SRalf Baechle *cmdline_p = command_line;
6462925aba4SRalf Baechle
647a09fc446SFranck Bui-Huu parse_early_param();
648a09fc446SFranck Bui-Huu
649a94e4f24SJiaxun Yang if (usermem)
650a94e4f24SJiaxun Yang pr_info("User-defined physical RAM map overwrite\n");
651a94e4f24SJiaxun Yang
652a94e4f24SJiaxun Yang check_kernel_sections_mem();
653a09fc446SFranck Bui-Huu
65473346081SMarcin Nowakowski early_init_fdt_reserve_self();
65573346081SMarcin Nowakowski early_init_fdt_scan_reserved_mem();
65673346081SMarcin Nowakowski
657a94e4f24SJiaxun Yang #ifndef CONFIG_NUMA
658a94e4f24SJiaxun Yang memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
659a94e4f24SJiaxun Yang #endif
6602925aba4SRalf Baechle bootmem_init();
661bcec54bfSMike Rapoport
662bcec54bfSMike Rapoport /*
663bcec54bfSMike Rapoport * Prevent memblock from allocating high memory.
664bcec54bfSMike Rapoport * This cannot be done before max_low_pfn is detected, so up
665bcec54bfSMike Rapoport * to this point is possible to only reserve physical memory
666eb31d559SMike Rapoport * with memblock_reserve; memblock_alloc* can be used
667bcec54bfSMike Rapoport * only after this point
668bcec54bfSMike Rapoport */
669bcec54bfSMike Rapoport memblock_set_current_limit(PFN_PHYS(max_low_pfn));
670bcec54bfSMike Rapoport
671b306c5f5SJinyang He mips_reserve_vmcore();
672c2882b7fSPrem Mallappa
673c2882b7fSPrem Mallappa mips_parse_crashkernel();
674f2ffa5abSDezhong Diao device_tree_init();
675269b3a9aSTiezhu Yang
676269b3a9aSTiezhu Yang /*
677269b3a9aSTiezhu Yang * In order to reduce the possibility of kernel panic when failed to
678269b3a9aSTiezhu Yang * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
679269b3a9aSTiezhu Yang * low memory as small as possible before plat_swiotlb_setup(), so
680269b3a9aSTiezhu Yang * make sparse_init() using top-down allocation.
681269b3a9aSTiezhu Yang */
682269b3a9aSTiezhu Yang memblock_set_bottom_up(false);
6832925aba4SRalf Baechle sparse_init();
684269b3a9aSTiezhu Yang memblock_set_bottom_up(true);
685269b3a9aSTiezhu Yang
686ee71b7d2SDavid Daney plat_swiotlb_setup();
687f4649382SZubair Lutfullah Kakakhel
688f4649382SZubair Lutfullah Kakakhel dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
689a95d0692SHuacai Chen
6904e50a35dSSerge Semin /* Reserve for hibernation. */
6914e50a35dSSerge Semin memblock_reserve(__pa_symbol(&__nosave_begin),
6924e50a35dSSerge Semin __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin));
69330c8f4e4SSerge Semin
694a94e4f24SJiaxun Yang early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
6952925aba4SRalf Baechle }
6962925aba4SRalf Baechle
resource_init(void)6978df32c63SFranck Bui-Huu static void __init resource_init(void)
6981da177e4SLinus Torvalds {
699b10d6bcaSMike Rapoport phys_addr_t start, end;
700b10d6bcaSMike Rapoport u64 i;
7011da177e4SLinus Torvalds
7026adb5fe7SRalf Baechle if (UNCAC_BASE != IO_BASE)
7036adb5fe7SRalf Baechle return;
7046adb5fe7SRalf Baechle
705f5bffe3aSFranck Bui-Huu code_resource.start = __pa_symbol(&_text);
706f5bffe3aSFranck Bui-Huu code_resource.end = __pa_symbol(&_etext) - 1;
707f5bffe3aSFranck Bui-Huu data_resource.start = __pa_symbol(&_etext);
708f5bffe3aSFranck Bui-Huu data_resource.end = __pa_symbol(&_edata) - 1;
709e0c5f36bSDavid Daney bss_resource.start = __pa_symbol(&__bss_start);
710e0c5f36bSDavid Daney bss_resource.end = __pa_symbol(&__bss_stop) - 1;
7111da177e4SLinus Torvalds
712b10d6bcaSMike Rapoport for_each_mem_range(i, &start, &end) {
7131da177e4SLinus Torvalds struct resource *res;
7141da177e4SLinus Torvalds
7157e1c4e27SMike Rapoport res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
7168a7f97b9SMike Rapoport if (!res)
7178a7f97b9SMike Rapoport panic("%s: Failed to allocate %zu bytes\n", __func__,
7188a7f97b9SMike Rapoport sizeof(struct resource));
71935d98e93SToshi Kani
72035d98e93SToshi Kani res->start = start;
721b10d6bcaSMike Rapoport /*
722b10d6bcaSMike Rapoport * In memblock, end points to the first byte after the
723b10d6bcaSMike Rapoport * range while in resourses, end points to the last byte in
724b10d6bcaSMike Rapoport * the range.
725b10d6bcaSMike Rapoport */
726b10d6bcaSMike Rapoport res->end = end - 1;
727a94e4f24SJiaxun Yang res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
7281da177e4SLinus Torvalds res->name = "System RAM";
7291da177e4SLinus Torvalds
7301da177e4SLinus Torvalds request_resource(&iomem_resource, res);
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds /*
7331da177e4SLinus Torvalds * We don't know which RAM region contains kernel data,
7341da177e4SLinus Torvalds * so we try it repeatedly and let the resource manager
7351da177e4SLinus Torvalds * test it.
7361da177e4SLinus Torvalds */
7371da177e4SLinus Torvalds request_resource(res, &code_resource);
7381da177e4SLinus Torvalds request_resource(res, &data_resource);
739e0c5f36bSDavid Daney request_resource(res, &bss_resource);
7407aa1c8f4SRalf Baechle request_crashkernel(res);
7411da177e4SLinus Torvalds }
7421da177e4SLinus Torvalds }
7431da177e4SLinus Torvalds
7440f3f506bSHuacai Chen #ifdef CONFIG_SMP
prefill_possible_map(void)7450f3f506bSHuacai Chen static void __init prefill_possible_map(void)
7460f3f506bSHuacai Chen {
7470f3f506bSHuacai Chen int i, possible = num_possible_cpus();
7480f3f506bSHuacai Chen
7490f3f506bSHuacai Chen if (possible > nr_cpu_ids)
7500f3f506bSHuacai Chen possible = nr_cpu_ids;
7510f3f506bSHuacai Chen
7520f3f506bSHuacai Chen for (i = 0; i < possible; i++)
7530f3f506bSHuacai Chen set_cpu_possible(i, true);
7540f3f506bSHuacai Chen for (; i < NR_CPUS; i++)
7550f3f506bSHuacai Chen set_cpu_possible(i, false);
7560f3f506bSHuacai Chen
75738bef8e5SYury Norov set_nr_cpu_ids(possible);
7580f3f506bSHuacai Chen }
7590f3f506bSHuacai Chen #else
prefill_possible_map(void)7600f3f506bSHuacai Chen static inline void prefill_possible_map(void) {}
7610f3f506bSHuacai Chen #endif
7620f3f506bSHuacai Chen
setup_rng_seed(void)763056a68ceSJason A. Donenfeld static void __init setup_rng_seed(void)
764056a68ceSJason A. Donenfeld {
765056a68ceSJason A. Donenfeld char *rng_seed_hex = fw_getenv("rngseed");
766056a68ceSJason A. Donenfeld u8 rng_seed[512];
767056a68ceSJason A. Donenfeld size_t len;
768056a68ceSJason A. Donenfeld
769056a68ceSJason A. Donenfeld if (!rng_seed_hex)
770056a68ceSJason A. Donenfeld return;
771056a68ceSJason A. Donenfeld
772056a68ceSJason A. Donenfeld len = min(sizeof(rng_seed), strlen(rng_seed_hex) / 2);
773056a68ceSJason A. Donenfeld if (hex2bin(rng_seed, rng_seed_hex, len))
774056a68ceSJason A. Donenfeld return;
775056a68ceSJason A. Donenfeld
776056a68ceSJason A. Donenfeld add_bootloader_randomness(rng_seed, len);
777056a68ceSJason A. Donenfeld memzero_explicit(rng_seed, len);
778056a68ceSJason A. Donenfeld memzero_explicit(rng_seed_hex, len * 2);
779056a68ceSJason A. Donenfeld }
780056a68ceSJason A. Donenfeld
setup_arch(char ** cmdline_p)7811da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
7821da177e4SLinus Torvalds {
7831da177e4SLinus Torvalds cpu_probe();
7843af5a67cSPaul Burton mips_cm_probe();
7851da177e4SLinus Torvalds prom_init();
78636a88530SRalf Baechle
787e934945dSJames Hogan setup_early_fdc_console();
78836a88530SRalf Baechle #ifdef CONFIG_EARLY_PRINTK
78936a88530SRalf Baechle setup_early_printk();
79036a88530SRalf Baechle #endif
7911da177e4SLinus Torvalds cpu_report();
792f4670a1bSNathan Chancellor if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64))
793f4670a1bSNathan Chancellor check_bugs64_early();
7941da177e4SLinus Torvalds
7951da177e4SLinus Torvalds #if defined(CONFIG_VT)
7961da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
7971da177e4SLinus Torvalds conswitchp = &vga_con;
7981da177e4SLinus Torvalds #endif
7991da177e4SLinus Torvalds #endif
8001da177e4SLinus Torvalds
8012925aba4SRalf Baechle arch_mem_init(cmdline_p);
802be8fa1cbSTiezhu Yang dmi_setup();
8031da177e4SLinus Torvalds
8041da177e4SLinus Torvalds resource_init();
8059b6695a8SRalf Baechle plat_smp_setup();
8060f3f506bSHuacai Chen prefill_possible_map();
8076650df3cSDavid Daney
8086650df3cSDavid Daney cpu_cache_init();
809058effe7SPaul Burton paging_init();
8104f1682b8STiezhu Yang
8114f1682b8STiezhu Yang memblock_dump_all();
812056a68ceSJason A. Donenfeld
813056a68ceSJason A. Donenfeld setup_rng_seed();
8141da177e4SLinus Torvalds }
8151da177e4SLinus Torvalds
81669a6c312SAtsushi Nemoto unsigned long kernelsp[NR_CPUS];
81769a6c312SAtsushi Nemoto unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
8186312e0eeSAtsushi Nemoto
8196312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
8206312e0eeSAtsushi Nemoto struct dentry *mips_debugfs_dir;
debugfs_mips(void)8216312e0eeSAtsushi Nemoto static int __init debugfs_mips(void)
8226312e0eeSAtsushi Nemoto {
823d8140426SGreg Kroah-Hartman mips_debugfs_dir = debugfs_create_dir("mips", NULL);
8246312e0eeSAtsushi Nemoto return 0;
8256312e0eeSAtsushi Nemoto }
8266312e0eeSAtsushi Nemoto arch_initcall(debugfs_mips);
8276312e0eeSAtsushi Nemoto #endif
828aa4db775SChristoph Hellwig
829a86497d6SChristoph Hellwig #ifdef CONFIG_DMA_NONCOHERENT
setcoherentio(char * str)830aa4db775SChristoph Hellwig static int __init setcoherentio(char *str)
831aa4db775SChristoph Hellwig {
83214ac09a6SChristoph Hellwig dma_default_coherent = true;
833aa4db775SChristoph Hellwig pr_info("Hardware DMA cache coherency (command line)\n");
834aa4db775SChristoph Hellwig return 0;
835aa4db775SChristoph Hellwig }
836aa4db775SChristoph Hellwig early_param("coherentio", setcoherentio);
837aa4db775SChristoph Hellwig
setnocoherentio(char * str)838aa4db775SChristoph Hellwig static int __init setnocoherentio(char *str)
839aa4db775SChristoph Hellwig {
8401e6ae0e4SRandy Dunlap dma_default_coherent = false;
841aa4db775SChristoph Hellwig pr_info("Software DMA cache coherency (command line)\n");
842aa4db775SChristoph Hellwig return 0;
843aa4db775SChristoph Hellwig }
844aa4db775SChristoph Hellwig early_param("nocoherentio", setnocoherentio);
845aa4db775SChristoph Hellwig #endif
8467f066a22SThomas Gleixner
arch_cpu_finalize_init(void)8477f066a22SThomas Gleixner void __init arch_cpu_finalize_init(void)
8487f066a22SThomas Gleixner {
8497f066a22SThomas Gleixner unsigned int cpu = smp_processor_id();
8507f066a22SThomas Gleixner
8517f066a22SThomas Gleixner cpu_data[cpu].udelay_val = loops_per_jiffy;
8527f066a22SThomas Gleixner check_bugs32();
8537f066a22SThomas Gleixner
8547f066a22SThomas Gleixner if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64))
8557f066a22SThomas Gleixner check_bugs64();
8567f066a22SThomas Gleixner }
857