xref: /openbmc/linux/arch/mips/kernel/setup.c (revision 57904291176fa16a981cefca5cbe1a0b50196792)
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