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>
189d15ffc8STejun Heo #include <linux/memblock.h>
191da177e4SLinus Torvalds #include <linux/initrd.h>
201da177e4SLinus Torvalds #include <linux/root_dev.h>
211da177e4SLinus Torvalds #include <linux/highmem.h>
221da177e4SLinus Torvalds #include <linux/console.h>
2322a9835cSDave Hansen #include <linux/pfn.h>
246312e0eeSAtsushi Nemoto #include <linux/debugfs.h>
257aa1c8f4SRalf Baechle #include <linux/kexec.h>
264d9f77d2SJohn Crispin #include <linux/sizes.h>
27f4649382SZubair Lutfullah Kakakhel #include <linux/device.h>
280b1abd1fSChristoph Hellwig #include <linux/dma-map-ops.h>
298f4703aaSAurelien Jarno #include <linux/decompress/generic.h>
3073346081SMarcin Nowakowski #include <linux/of_fdt.h>
31be8fa1cbSTiezhu Yang #include <linux/dmi.h>
32b306c5f5SJinyang He #include <linux/crash_dump.h>
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds #include <asm/addrspace.h>
351da177e4SLinus Torvalds #include <asm/bootinfo.h>
3620d60d99SMaciej W. Rozycki #include <asm/bugs.h>
37ec74e361SRalf Baechle #include <asm/cache.h>
38e934945dSJames Hogan #include <asm/cdmm.h>
391da177e4SLinus Torvalds #include <asm/cpu.h>
4075dcfc1dSPaul Burton #include <asm/debug.h>
41795d82edSTiezhu Yang #include <asm/mmzone.h>
421da177e4SLinus Torvalds #include <asm/sections.h>
431da177e4SLinus Torvalds #include <asm/setup.h>
4487353d8aSRalf Baechle #include <asm/smp-ops.h>
454bfb53e7SJiaxun Yang #include <asm/mips-cps.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
571da177e4SLinus Torvalds /*
581da177e4SLinus Torvalds * Setup information
591da177e4SLinus Torvalds *
601da177e4SLinus Torvalds * These are initialized so they are in the .data section
611da177e4SLinus Torvalds */
62ec74e361SRalf Baechle unsigned long mips_machtype __read_mostly = MACH_UNKNOWN;
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds EXPORT_SYMBOL(mips_machtype);
651da177e4SLinus Torvalds
666acc7d48SDmitri Vorobiev static char __initdata command_line[COMMAND_LINE_SIZE];
676acc7d48SDmitri Vorobiev char __initdata arcs_cmdline[COMMAND_LINE_SIZE];
686acc7d48SDmitri Vorobiev
696acc7d48SDmitri Vorobiev #ifdef CONFIG_CMDLINE_BOOL
709dd422f6SPaul Burton static const char builtin_cmdline[] __initconst = CONFIG_CMDLINE;
71b7340422SPaul Burton #else
72b7340422SPaul Burton static const char builtin_cmdline[] __initconst = "";
736acc7d48SDmitri Vorobiev #endif
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds /*
761da177e4SLinus Torvalds * mips_io_port_base is the begin of the address space to which x86 style
771da177e4SLinus Torvalds * I/O ports are mapped.
781da177e4SLinus Torvalds */
7912051b31SNick Desaulniers unsigned long mips_io_port_base = -1;
801da177e4SLinus Torvalds EXPORT_SYMBOL(mips_io_port_base);
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds static struct resource code_resource = { .name = "Kernel code", };
831da177e4SLinus Torvalds static struct resource data_resource = { .name = "Kernel data", };
84e0c5f36bSDavid Daney static struct resource bss_resource = { .name = "Kernel bss", };
851da177e4SLinus Torvalds
86d4d3ef8bSJinyang He unsigned long __kaslr_offset __ro_after_init;
87d4d3ef8bSJinyang He EXPORT_SYMBOL(__kaslr_offset);
88d4d3ef8bSJinyang He
894d9f77d2SJohn Crispin static void *detect_magic __initdata = detect_memory_region;
904d9f77d2SJohn Crispin
916c359eb1SPaul Burton #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
926c359eb1SPaul Burton unsigned long ARCH_PFN_OFFSET;
936c359eb1SPaul Burton EXPORT_SYMBOL(ARCH_PFN_OFFSET);
946c359eb1SPaul Burton #endif
956c359eb1SPaul Burton
detect_memory_region(phys_addr_t start,phys_addr_t sz_min,phys_addr_t sz_max)9615d45cceSRalf Baechle void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max)
974d9f77d2SJohn Crispin {
984d9f77d2SJohn Crispin void *dm = &detect_magic;
9915d45cceSRalf Baechle phys_addr_t size;
1004d9f77d2SJohn Crispin
1014d9f77d2SJohn Crispin for (size = sz_min; size < sz_max; size <<= 1) {
1024d9f77d2SJohn Crispin if (!memcmp(dm, dm + size, sizeof(detect_magic)))
1034d9f77d2SJohn Crispin break;
1044d9f77d2SJohn Crispin }
1054d9f77d2SJohn Crispin
1064d9f77d2SJohn Crispin pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n",
1074d9f77d2SJohn Crispin ((unsigned long long) size) / SZ_1M,
1084d9f77d2SJohn Crispin (unsigned long long) start,
1094d9f77d2SJohn Crispin ((unsigned long long) sz_min) / SZ_1M,
1104d9f77d2SJohn Crispin ((unsigned long long) sz_max) / SZ_1M);
1114d9f77d2SJohn Crispin
112e7ae8d17SThomas Bogendoerfer memblock_add(start, size);
1134d9f77d2SJohn Crispin }
1144d9f77d2SJohn Crispin
115d2043ca8SFranck Bui-Huu /*
116d2043ca8SFranck Bui-Huu * Manage initrd
117d2043ca8SFranck Bui-Huu */
118d2043ca8SFranck Bui-Huu #ifdef CONFIG_BLK_DEV_INITRD
119d2043ca8SFranck Bui-Huu
rd_start_early(char * p)120a09fc446SFranck Bui-Huu static int __init rd_start_early(char *p)
1211da177e4SLinus Torvalds {
122a09fc446SFranck Bui-Huu unsigned long start = memparse(p, &p);
1231da177e4SLinus Torvalds
124875d43e7SRalf Baechle #ifdef CONFIG_64BIT
125a7837b76SFranck Bui-Huu /* Guess if the sign extension was forgotten by bootloader */
126a7837b76SFranck Bui-Huu if (start < XKPHYS)
127a7837b76SFranck Bui-Huu start = (int)start;
1281da177e4SLinus Torvalds #endif
129a09fc446SFranck Bui-Huu initrd_start = start;
130a09fc446SFranck Bui-Huu initrd_end += start;
1311da177e4SLinus Torvalds return 0;
1321da177e4SLinus Torvalds }
133a09fc446SFranck Bui-Huu early_param("rd_start", rd_start_early);
134a09fc446SFranck Bui-Huu
rd_size_early(char * p)135a09fc446SFranck Bui-Huu static int __init rd_size_early(char *p)
136a09fc446SFranck Bui-Huu {
137a09fc446SFranck Bui-Huu initrd_end += memparse(p, &p);
138a09fc446SFranck Bui-Huu return 0;
139a09fc446SFranck Bui-Huu }
140a09fc446SFranck Bui-Huu early_param("rd_size", rd_size_early);
1411da177e4SLinus Torvalds
142a7837b76SFranck Bui-Huu /* it returns the next free pfn after initrd */
init_initrd(void)143d2043ca8SFranck Bui-Huu static unsigned long __init init_initrd(void)
1441da177e4SLinus Torvalds {
145a7837b76SFranck Bui-Huu unsigned long end;
1461da177e4SLinus Torvalds
147d2043ca8SFranck Bui-Huu /*
148a09fc446SFranck Bui-Huu * Board specific code or command line parser should have
149a09fc446SFranck Bui-Huu * already set up initrd_start and initrd_end. In these cases
1502f9060b1SBjorn Helgaas * perform sanity checks and use them if all looks good.
151d2043ca8SFranck Bui-Huu */
15232028f1fSRalf Baechle if (!initrd_start || initrd_end <= initrd_start)
153a7837b76SFranck Bui-Huu goto disable;
154a7837b76SFranck Bui-Huu
155a7837b76SFranck Bui-Huu if (initrd_start & ~PAGE_MASK) {
156a64ae7a2SMike Crowe pr_err("initrd start must be page aligned\n");
157a7837b76SFranck Bui-Huu goto disable;
158a7837b76SFranck Bui-Huu }
159a7837b76SFranck Bui-Huu
160a7837b76SFranck Bui-Huu /*
161a7837b76SFranck Bui-Huu * Sanitize initrd addresses. For example firmware
162a7837b76SFranck Bui-Huu * can't guess if they need to pass them through
163a7837b76SFranck Bui-Huu * 64-bits values if the kernel has been built in pure
164a7837b76SFranck Bui-Huu * 32-bit. We need also to switch from KSEG0 to XKPHYS
165a7837b76SFranck Bui-Huu * addresses now, so the code can now safely use __pa().
166a7837b76SFranck Bui-Huu */
167a7837b76SFranck Bui-Huu end = __pa(initrd_end);
168a7837b76SFranck Bui-Huu initrd_end = (unsigned long)__va(end);
169a7837b76SFranck Bui-Huu initrd_start = (unsigned long)__va(__pa(initrd_start));
170a7837b76SFranck Bui-Huu
1714897a898SLiviu Dudau if (initrd_start < PAGE_OFFSET) {
1724897a898SLiviu Dudau pr_err("initrd start < PAGE_OFFSET\n");
1734897a898SLiviu Dudau goto disable;
1744897a898SLiviu Dudau }
1754897a898SLiviu Dudau
176a7837b76SFranck Bui-Huu ROOT_DEV = Root_RAM0;
177a7837b76SFranck Bui-Huu return PFN_UP(end);
178a7837b76SFranck Bui-Huu disable:
179a09fc446SFranck Bui-Huu initrd_start = 0;
180a09fc446SFranck Bui-Huu initrd_end = 0;
181a7837b76SFranck Bui-Huu return 0;
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds
1848f4703aaSAurelien Jarno /* In some conditions (e.g. big endian bootloader with a little endian
1858f4703aaSAurelien Jarno kernel), the initrd might appear byte swapped. Try to detect this and
1868f4703aaSAurelien Jarno byte swap it if needed. */
maybe_bswap_initrd(void)1878f4703aaSAurelien Jarno static void __init maybe_bswap_initrd(void)
1888f4703aaSAurelien Jarno {
1898f4703aaSAurelien Jarno #if defined(CONFIG_CPU_CAVIUM_OCTEON)
1908f4703aaSAurelien Jarno u64 buf;
1918f4703aaSAurelien Jarno
1928f4703aaSAurelien Jarno /* Check for CPIO signature */
1938f4703aaSAurelien Jarno if (!memcmp((void *)initrd_start, "070701", 6))
1948f4703aaSAurelien Jarno return;
1958f4703aaSAurelien Jarno
1968f4703aaSAurelien Jarno /* Check for compressed initrd */
1978f4703aaSAurelien Jarno if (decompress_method((unsigned char *)initrd_start, 8, NULL))
1988f4703aaSAurelien Jarno return;
1998f4703aaSAurelien Jarno
2008f4703aaSAurelien Jarno /* Try again with a byte swapped header */
2018f4703aaSAurelien Jarno buf = swab64p((u64 *)initrd_start);
2028f4703aaSAurelien Jarno if (!memcmp(&buf, "070701", 6) ||
2038f4703aaSAurelien Jarno decompress_method((unsigned char *)(&buf), 8, NULL)) {
2048f4703aaSAurelien Jarno unsigned long i;
2058f4703aaSAurelien Jarno
2068f4703aaSAurelien Jarno pr_info("Byteswapped initrd detected\n");
2078f4703aaSAurelien Jarno for (i = initrd_start; i < ALIGN(initrd_end, 8); i += 8)
2088f4703aaSAurelien Jarno swab64s((u64 *)i);
2098f4703aaSAurelien Jarno }
2108f4703aaSAurelien Jarno #endif
2118f4703aaSAurelien Jarno }
2128f4703aaSAurelien Jarno
finalize_initrd(void)213d2043ca8SFranck Bui-Huu static void __init finalize_initrd(void)
214d2043ca8SFranck Bui-Huu {
215d2043ca8SFranck Bui-Huu unsigned long size = initrd_end - initrd_start;
216d2043ca8SFranck Bui-Huu
217d2043ca8SFranck Bui-Huu if (size == 0) {
218d2043ca8SFranck Bui-Huu printk(KERN_INFO "Initrd not found or empty");
219d2043ca8SFranck Bui-Huu goto disable;
220d2043ca8SFranck Bui-Huu }
221d4df6d4eSFranck Bui-Huu if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
222a64ae7a2SMike Crowe printk(KERN_ERR "Initrd extends beyond end of memory");
223d2043ca8SFranck Bui-Huu goto disable;
224d2043ca8SFranck Bui-Huu }
225d2043ca8SFranck Bui-Huu
2268f4703aaSAurelien Jarno maybe_bswap_initrd();
2278f4703aaSAurelien Jarno
228bcec54bfSMike Rapoport memblock_reserve(__pa(initrd_start), size);
229d2043ca8SFranck Bui-Huu initrd_below_start_ok = 1;
230d2043ca8SFranck Bui-Huu
231a64ae7a2SMike Crowe pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
232d2043ca8SFranck Bui-Huu initrd_start, size);
233d2043ca8SFranck Bui-Huu return;
234d2043ca8SFranck Bui-Huu disable:
235a64ae7a2SMike Crowe printk(KERN_CONT " - disabling initrd\n");
236d2043ca8SFranck Bui-Huu initrd_start = 0;
237d2043ca8SFranck Bui-Huu initrd_end = 0;
238d2043ca8SFranck Bui-Huu }
239d2043ca8SFranck Bui-Huu
240d2043ca8SFranck Bui-Huu #else /* !CONFIG_BLK_DEV_INITRD */
241d2043ca8SFranck Bui-Huu
init_initrd(void)2429ba126cfSRalf Baechle static unsigned long __init init_initrd(void)
2439ba126cfSRalf Baechle {
2449ba126cfSRalf Baechle return 0;
2459ba126cfSRalf Baechle }
2469ba126cfSRalf Baechle
247d2043ca8SFranck Bui-Huu #define finalize_initrd() do {} while (0)
248d2043ca8SFranck Bui-Huu
249d2043ca8SFranck Bui-Huu #endif
250d2043ca8SFranck Bui-Huu
251b6f1f0deSFranck Bui-Huu /*
252d2043ca8SFranck Bui-Huu * Initialize the bootmem allocator. It also setup initrd related data
253d2043ca8SFranck Bui-Huu * if needed.
254b6f1f0deSFranck Bui-Huu */
255268a2d60SJiaxun Yang #if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON64) && defined(CONFIG_NUMA))
256d2043ca8SFranck Bui-Huu
bootmem_init(void)257d2043ca8SFranck Bui-Huu static void __init bootmem_init(void)
258d2043ca8SFranck Bui-Huu {
259d2043ca8SFranck Bui-Huu init_initrd();
260d2043ca8SFranck Bui-Huu finalize_initrd();
261d2043ca8SFranck Bui-Huu }
262d2043ca8SFranck Bui-Huu
263d2043ca8SFranck Bui-Huu #else /* !CONFIG_SGI_IP27 */
264d2043ca8SFranck Bui-Huu
bootmem_init(void)265d2043ca8SFranck Bui-Huu static void __init bootmem_init(void)
266d2043ca8SFranck Bui-Huu {
267a94e4f24SJiaxun Yang phys_addr_t ramstart, ramend;
26861a2f1aeSThomas Bogendoerfer unsigned long start, end;
26961a2f1aeSThomas Bogendoerfer int i;
270a94e4f24SJiaxun Yang
271a94e4f24SJiaxun Yang ramstart = memblock_start_of_DRAM();
272a94e4f24SJiaxun Yang ramend = memblock_end_of_DRAM();
273d2043ca8SFranck Bui-Huu
274d2043ca8SFranck Bui-Huu /*
275f9a7febdSGreg Ungerer * Sanity check any INITRD first. We don't take it into account
276f9a7febdSGreg Ungerer * for bootmem setup initially, rely on the end-of-kernel-code
277f9a7febdSGreg Ungerer * as our memory range starting point. Once bootmem is inited we
278f9a7febdSGreg Ungerer * will reserve the area used for the initrd.
279d2043ca8SFranck Bui-Huu */
280f9a7febdSGreg Ungerer init_initrd();
281b6f1f0deSFranck Bui-Huu
282b93ddc4fSSerge Semin /* Reserve memory occupied by kernel. */
283b93ddc4fSSerge Semin memblock_reserve(__pa_symbol(&_text),
284b93ddc4fSSerge Semin __pa_symbol(&_end) - __pa_symbol(&_text));
285bcec54bfSMike Rapoport
286a94e4f24SJiaxun Yang /* max_low_pfn is not a number of pages but the end pfn of low mem */
2876c359eb1SPaul Burton
2886c359eb1SPaul Burton #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
2896c359eb1SPaul Burton ARCH_PFN_OFFSET = PFN_UP(ramstart);
2906c359eb1SPaul Burton #else
29167a3ba25SMarcin Nowakowski /*
29267a3ba25SMarcin Nowakowski * Reserve any memory between the start of RAM and PHYS_OFFSET
29367a3ba25SMarcin Nowakowski */
294a94e4f24SJiaxun Yang if (ramstart > PHYS_OFFSET)
29566b416eeSThomas Bogendoerfer memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
29667a3ba25SMarcin Nowakowski
297a94e4f24SJiaxun Yang if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
298a64ae7a2SMike Crowe pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
299a94e4f24SJiaxun Yang (unsigned long)((PFN_UP(ramstart) - ARCH_PFN_OFFSET) * sizeof(struct page)),
300a94e4f24SJiaxun Yang (unsigned long)(PFN_UP(ramstart) - ARCH_PFN_OFFSET));
301db84dc61SFranck Bui-Huu }
3026c359eb1SPaul Burton #endif
303db84dc61SFranck Bui-Huu
304a94e4f24SJiaxun Yang min_low_pfn = ARCH_PFN_OFFSET;
305a94e4f24SJiaxun Yang max_pfn = PFN_DOWN(ramend);
30661a2f1aeSThomas Bogendoerfer for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {
3071da177e4SLinus Torvalds /*
308a94e4f24SJiaxun Yang * Skip highmem here so we get an accurate max_low_pfn if low
309a94e4f24SJiaxun Yang * memory stops short of high memory.
310a94e4f24SJiaxun Yang * If the region overlaps HIGHMEM_START, end is clipped so
311a94e4f24SJiaxun Yang * max_pfn excludes the highmem portion.
3121da177e4SLinus Torvalds */
313a94e4f24SJiaxun Yang if (start >= PFN_DOWN(HIGHMEM_START))
314a94e4f24SJiaxun Yang continue;
315a94e4f24SJiaxun Yang if (end > PFN_DOWN(HIGHMEM_START))
316a94e4f24SJiaxun Yang end = PFN_DOWN(HIGHMEM_START);
317a94e4f24SJiaxun Yang if (end > max_low_pfn)
318a94e4f24SJiaxun Yang max_low_pfn = end;
319a94e4f24SJiaxun Yang }
320a94e4f24SJiaxun Yang
321a94e4f24SJiaxun Yang if (min_low_pfn >= max_low_pfn)
322a94e4f24SJiaxun Yang panic("Incorrect memory mapping !!!");
323a94e4f24SJiaxun Yang
324a94e4f24SJiaxun Yang if (max_pfn > PFN_DOWN(HIGHMEM_START)) {
3250f5cc249SSerge Semin max_low_pfn = PFN_DOWN(HIGHMEM_START);
3261da177e4SLinus Torvalds #ifdef CONFIG_HIGHMEM
3270f5cc249SSerge Semin highstart_pfn = max_low_pfn;
328a94e4f24SJiaxun Yang highend_pfn = max_pfn;
329a94e4f24SJiaxun Yang #else
330a94e4f24SJiaxun Yang max_pfn = max_low_pfn;
3316ea3ba6fSSerge Semin #endif
33243064c0cSDavid Daney }
33343064c0cSDavid Daney
334d2043ca8SFranck Bui-Huu /*
335d2043ca8SFranck Bui-Huu * Reserve initrd memory if needed.
336d2043ca8SFranck Bui-Huu */
337d2043ca8SFranck Bui-Huu finalize_initrd();
338d2043ca8SFranck Bui-Huu }
339d2043ca8SFranck Bui-Huu
3401da177e4SLinus Torvalds #endif /* CONFIG_SGI_IP27 */
3411da177e4SLinus Torvalds
342982f6ffeSRalf Baechle static int usermem __initdata;
343a09fc446SFranck Bui-Huu
early_parse_mem(char * p)344a09fc446SFranck Bui-Huu static int __init early_parse_mem(char *p)
345a09fc446SFranck Bui-Huu {
346ad8f723aSJaedon Shin phys_addr_t start, size;
347a09fc446SFranck Bui-Huu
348fb3d6967STiezhu Yang if (!p) {
349fb3d6967STiezhu Yang pr_err("mem parameter is empty, do nothing\n");
350fb3d6967STiezhu Yang return -EINVAL;
351fb3d6967STiezhu Yang }
352fb3d6967STiezhu Yang
353a09fc446SFranck Bui-Huu /*
354a09fc446SFranck Bui-Huu * If a user specifies memory size, we
355a09fc446SFranck Bui-Huu * blow away any automatically generated
356a09fc446SFranck Bui-Huu * size.
357a09fc446SFranck Bui-Huu */
358a09fc446SFranck Bui-Huu if (usermem == 0) {
359a09fc446SFranck Bui-Huu usermem = 1;
360a94e4f24SJiaxun Yang memblock_remove(memblock_start_of_DRAM(),
361a94e4f24SJiaxun Yang memblock_end_of_DRAM() - memblock_start_of_DRAM());
362a09fc446SFranck Bui-Huu }
363a09fc446SFranck Bui-Huu start = 0;
364a09fc446SFranck Bui-Huu size = memparse(p, &p);
365a09fc446SFranck Bui-Huu if (*p == '@')
366a09fc446SFranck Bui-Huu start = memparse(p + 1, &p);
367a09fc446SFranck Bui-Huu
368795d82edSTiezhu Yang if (IS_ENABLED(CONFIG_NUMA))
369795d82edSTiezhu Yang memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE);
370795d82edSTiezhu Yang else
371e7ae8d17SThomas Bogendoerfer memblock_add(start, size);
37273fbc1ebSMarcin Nowakowski
373a09fc446SFranck Bui-Huu return 0;
374a09fc446SFranck Bui-Huu }
375a09fc446SFranck Bui-Huu early_param("mem", early_parse_mem);
3762925aba4SRalf Baechle
early_parse_memmap(char * p)377296a7624SMiodrag Dinic static int __init early_parse_memmap(char *p)
378296a7624SMiodrag Dinic {
379296a7624SMiodrag Dinic char *oldp;
380296a7624SMiodrag Dinic u64 start_at, mem_size;
381296a7624SMiodrag Dinic
382296a7624SMiodrag Dinic if (!p)
383296a7624SMiodrag Dinic return -EINVAL;
384296a7624SMiodrag Dinic
385296a7624SMiodrag Dinic if (!strncmp(p, "exactmap", 8)) {
386296a7624SMiodrag Dinic pr_err("\"memmap=exactmap\" invalid on MIPS\n");
387296a7624SMiodrag Dinic return 0;
388296a7624SMiodrag Dinic }
389296a7624SMiodrag Dinic
390296a7624SMiodrag Dinic oldp = p;
391296a7624SMiodrag Dinic mem_size = memparse(p, &p);
392296a7624SMiodrag Dinic if (p == oldp)
393296a7624SMiodrag Dinic return -EINVAL;
394296a7624SMiodrag Dinic
395296a7624SMiodrag Dinic if (*p == '@') {
396296a7624SMiodrag Dinic start_at = memparse(p+1, &p);
397e7ae8d17SThomas Bogendoerfer memblock_add(start_at, mem_size);
398296a7624SMiodrag Dinic } else if (*p == '#') {
399296a7624SMiodrag Dinic pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n");
400296a7624SMiodrag Dinic return -EINVAL;
401296a7624SMiodrag Dinic } else if (*p == '$') {
402296a7624SMiodrag Dinic start_at = memparse(p+1, &p);
403e7ae8d17SThomas Bogendoerfer memblock_add(start_at, mem_size);
404e7ae8d17SThomas Bogendoerfer memblock_reserve(start_at, mem_size);
405296a7624SMiodrag Dinic } else {
406296a7624SMiodrag Dinic pr_err("\"memmap\" invalid format!\n");
407296a7624SMiodrag Dinic return -EINVAL;
408296a7624SMiodrag Dinic }
409296a7624SMiodrag Dinic
410296a7624SMiodrag Dinic if (*p == '\0') {
411296a7624SMiodrag Dinic usermem = 1;
412296a7624SMiodrag Dinic return 0;
413296a7624SMiodrag Dinic } else
414296a7624SMiodrag Dinic return -EINVAL;
415296a7624SMiodrag Dinic }
416296a7624SMiodrag Dinic early_param("memmap", early_parse_memmap);
417296a7624SMiodrag Dinic
mips_reserve_vmcore(void)418b306c5f5SJinyang He static void __init mips_reserve_vmcore(void)
4194893fc88SCorey Minyard {
420b306c5f5SJinyang He #ifdef CONFIG_PROC_VMCORE
421b10d6bcaSMike Rapoport phys_addr_t start, end;
422b10d6bcaSMike Rapoport u64 i;
4234893fc88SCorey Minyard
424b306c5f5SJinyang He if (!elfcorehdr_size) {
425b10d6bcaSMike Rapoport for_each_mem_range(i, &start, &end) {
426b306c5f5SJinyang He if (elfcorehdr_addr >= start && elfcorehdr_addr < end) {
4274893fc88SCorey Minyard /*
4284893fc88SCorey Minyard * Reserve from the elf core header to the end of
4294893fc88SCorey Minyard * the memory segment, that should all be kdump
4304893fc88SCorey Minyard * reserved memory.
4314893fc88SCorey Minyard */
432b306c5f5SJinyang He elfcorehdr_size = end - elfcorehdr_addr;
4334893fc88SCorey Minyard break;
4344893fc88SCorey Minyard }
4354893fc88SCorey Minyard }
4364893fc88SCorey Minyard }
437b306c5f5SJinyang He
438b306c5f5SJinyang He pr_info("Reserving %ldKB of memory at %ldKB for kdump\n",
439b306c5f5SJinyang He (unsigned long)elfcorehdr_size >> 10, (unsigned long)elfcorehdr_addr >> 10);
440b306c5f5SJinyang He
441b306c5f5SJinyang He memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
4424893fc88SCorey Minyard #endif
443b306c5f5SJinyang He }
4444893fc88SCorey Minyard
44526262396SYouling Tang /* 64M alignment for crash kernel regions */
44626262396SYouling Tang #define CRASH_ALIGN SZ_64M
44726262396SYouling Tang #define CRASH_ADDR_MAX SZ_512M
44826262396SYouling Tang
mips_parse_crashkernel(void)449c2882b7fSPrem Mallappa static void __init mips_parse_crashkernel(void)
450c2882b7fSPrem Mallappa {
451c2882b7fSPrem Mallappa unsigned long long total_mem;
452c2882b7fSPrem Mallappa unsigned long long crash_size, crash_base;
453c2882b7fSPrem Mallappa int ret;
454c2882b7fSPrem Mallappa
455d739f190SBaoquan He if (!IS_ENABLED(CONFIG_CRASH_RESERVE))
456d739f190SBaoquan He return;
457d739f190SBaoquan He
458a94e4f24SJiaxun Yang total_mem = memblock_phys_mem_size();
459c2882b7fSPrem Mallappa ret = parse_crashkernel(boot_command_line, total_mem,
460a9e1a3d8SBaoquan He &crash_size, &crash_base,
461a9e1a3d8SBaoquan He NULL, NULL);
462c2882b7fSPrem Mallappa if (ret != 0 || crash_size <= 0)
463c2882b7fSPrem Mallappa return;
464c2882b7fSPrem Mallappa
46526262396SYouling Tang if (crash_base <= 0) {
466a7259df7SMike Rapoport crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
467a7259df7SMike Rapoport CRASH_ALIGN,
468a7259df7SMike Rapoport CRASH_ADDR_MAX);
46926262396SYouling Tang if (!crash_base) {
47026262396SYouling Tang pr_warn("crashkernel reservation failed - No suitable area found.\n");
47126262396SYouling Tang return;
47226262396SYouling Tang }
47326262396SYouling Tang } else {
47426262396SYouling Tang unsigned long long start;
47526262396SYouling Tang
476a7259df7SMike Rapoport start = memblock_phys_alloc_range(crash_size, 1,
477a7259df7SMike Rapoport crash_base,
478a7259df7SMike Rapoport crash_base + crash_size);
47926262396SYouling Tang if (start != crash_base) {
480a8f108d7SMarcin Nowakowski pr_warn("Invalid memory region reserved for crash kernel\n");
481a8f108d7SMarcin Nowakowski return;
482a8f108d7SMarcin Nowakowski }
48326262396SYouling Tang }
484a8f108d7SMarcin Nowakowski
485c2882b7fSPrem Mallappa crashk_res.start = crash_base;
486c2882b7fSPrem Mallappa crashk_res.end = crash_base + crash_size - 1;
487c2882b7fSPrem Mallappa }
488c2882b7fSPrem Mallappa
request_crashkernel(struct resource * res)489c2882b7fSPrem Mallappa static void __init request_crashkernel(struct resource *res)
490c2882b7fSPrem Mallappa {
491c2882b7fSPrem Mallappa int ret;
492c2882b7fSPrem Mallappa
493d739f190SBaoquan He if (!IS_ENABLED(CONFIG_CRASH_RESERVE))
494d739f190SBaoquan He return;
495d739f190SBaoquan He
496269aa43aSMarcin Nowakowski if (crashk_res.start == crashk_res.end)
497269aa43aSMarcin Nowakowski return;
498269aa43aSMarcin Nowakowski
499c2882b7fSPrem Mallappa ret = request_resource(res, &crashk_res);
500c2882b7fSPrem Mallappa if (!ret)
501c2882b7fSPrem Mallappa pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
502ecb98379SJulia Lawall (unsigned long)(resource_size(&crashk_res) >> 20),
503c2882b7fSPrem Mallappa (unsigned long)(crashk_res.start >> 20));
504c2882b7fSPrem Mallappa }
505c2882b7fSPrem Mallappa
check_kernel_sections_mem(void)506a94e4f24SJiaxun Yang static void __init check_kernel_sections_mem(void)
507a94e4f24SJiaxun Yang {
508d121f125SAlexander Sverdlin phys_addr_t start = __pa_symbol(&_text);
509d121f125SAlexander Sverdlin phys_addr_t size = __pa_symbol(&_end) - start;
510a94e4f24SJiaxun Yang
511a94e4f24SJiaxun Yang if (!memblock_is_region_memory(start, size)) {
512a94e4f24SJiaxun Yang pr_info("Kernel sections are not in the memory maps\n");
513a94e4f24SJiaxun Yang memblock_add(start, size);
514a94e4f24SJiaxun Yang }
515a94e4f24SJiaxun Yang }
516a94e4f24SJiaxun Yang
bootcmdline_append(const char * s,size_t max)5177784cac6SPaul Burton static void __init bootcmdline_append(const char *s, size_t max)
5187784cac6SPaul Burton {
5197784cac6SPaul Burton if (!s[0] || !max)
5207784cac6SPaul Burton return;
5217784cac6SPaul Burton
5227784cac6SPaul Burton if (boot_command_line[0])
5237784cac6SPaul Burton strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
5247784cac6SPaul Burton
5257784cac6SPaul Burton strlcat(boot_command_line, s, max);
5267784cac6SPaul Burton }
5277784cac6SPaul Burton
52897272776SPaul Burton #ifdef CONFIG_OF_EARLY_FLATTREE
52997272776SPaul Burton
bootcmdline_scan_chosen(unsigned long node,const char * uname,int depth,void * data)5307784cac6SPaul Burton static int __init bootcmdline_scan_chosen(unsigned long node, const char *uname,
5317784cac6SPaul Burton int depth, void *data)
5327784cac6SPaul Burton {
5337784cac6SPaul Burton bool *dt_bootargs = data;
5347784cac6SPaul Burton const char *p;
5357784cac6SPaul Burton int l;
5367784cac6SPaul Burton
5377784cac6SPaul Burton if (depth != 1 || !data ||
5387784cac6SPaul Burton (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
5397784cac6SPaul Burton return 0;
5407784cac6SPaul Burton
5417784cac6SPaul Burton p = of_get_flat_dt_prop(node, "bootargs", &l);
5427784cac6SPaul Burton if (p != NULL && l > 0) {
5437784cac6SPaul Burton bootcmdline_append(p, min(l, COMMAND_LINE_SIZE));
5447784cac6SPaul Burton *dt_bootargs = true;
5457784cac6SPaul Burton }
5467784cac6SPaul Burton
5477784cac6SPaul Burton return 1;
5487784cac6SPaul Burton }
5497784cac6SPaul Burton
55097272776SPaul Burton #endif /* CONFIG_OF_EARLY_FLATTREE */
55197272776SPaul Burton
bootcmdline_init(void)552bd6e3898SZhi Li static void __init bootcmdline_init(void)
5537784cac6SPaul Burton {
5547784cac6SPaul Burton bool dt_bootargs = false;
5557784cac6SPaul Burton
5567784cac6SPaul Burton /*
5577784cac6SPaul Burton * If CMDLINE_OVERRIDE is enabled then initializing the command line is
5587784cac6SPaul Burton * trivial - we simply use the built-in command line unconditionally &
5597784cac6SPaul Burton * unmodified.
5607784cac6SPaul Burton */
5617784cac6SPaul Burton if (IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) {
56288ca100cS陈学兵 strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
5637784cac6SPaul Burton return;
5647784cac6SPaul Burton }
5657784cac6SPaul Burton
5667784cac6SPaul Burton /*
5677784cac6SPaul Burton * If the user specified a built-in command line &
5687784cac6SPaul Burton * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
5697784cac6SPaul Burton * prepended to arguments from the bootloader or DT so we'll copy them
5707784cac6SPaul Burton * to the start of boot_command_line here. Otherwise, empty
5717784cac6SPaul Burton * boot_command_line to undo anything early_init_dt_scan_chosen() did.
5727784cac6SPaul Burton */
5737784cac6SPaul Burton if (IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
57488ca100cS陈学兵 strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
5757784cac6SPaul Burton else
5767784cac6SPaul Burton boot_command_line[0] = 0;
5777784cac6SPaul Burton
57897272776SPaul Burton #ifdef CONFIG_OF_EARLY_FLATTREE
5797784cac6SPaul Burton /*
5807784cac6SPaul Burton * If we're configured to take boot arguments from DT, look for those
5817784cac6SPaul Burton * now.
5827784cac6SPaul Burton */
5838e029eb0SPaul Cercueil if (IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) ||
5848e029eb0SPaul Cercueil IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND))
5857784cac6SPaul Burton of_scan_flat_dt(bootcmdline_scan_chosen, &dt_bootargs);
58697272776SPaul Burton #endif
5877784cac6SPaul Burton
5887784cac6SPaul Burton /*
5897784cac6SPaul Burton * If we didn't get any arguments from DT (regardless of whether that's
5907784cac6SPaul Burton * because we weren't configured to look for them, or because we looked
5917784cac6SPaul Burton * & found none) then we'll take arguments from the bootloader.
5927784cac6SPaul Burton * plat_mem_setup() should have filled arcs_cmdline with arguments from
5937784cac6SPaul Burton * the bootloader.
5947784cac6SPaul Burton */
5957784cac6SPaul Burton if (IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) || !dt_bootargs)
5967784cac6SPaul Burton bootcmdline_append(arcs_cmdline, COMMAND_LINE_SIZE);
5977784cac6SPaul Burton
5987784cac6SPaul Burton /*
5997784cac6SPaul Burton * If the user specified a built-in command line & we didn't already
6007784cac6SPaul Burton * prepend it, we append it to boot_command_line here.
6017784cac6SPaul Burton */
6027784cac6SPaul Burton if (IS_ENABLED(CONFIG_CMDLINE_BOOL) &&
6037784cac6SPaul Burton !IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
6047784cac6SPaul Burton bootcmdline_append(builtin_cmdline, COMMAND_LINE_SIZE);
6057784cac6SPaul Burton }
6062024972eSJonas Gorski
60752c985acSPaul Burton /*
60852c985acSPaul Burton * arch_mem_init - initialize memory management subsystem
60952c985acSPaul Burton *
61052c985acSPaul Burton * o plat_mem_setup() detects the memory configuration and will record detected
611e7ae8d17SThomas Bogendoerfer * memory areas using memblock_add.
61252c985acSPaul Burton *
61352c985acSPaul Burton * At this stage the memory configuration of the system is known to the
61452c985acSPaul Burton * kernel but generic memory management system is still entirely uninitialized.
61552c985acSPaul Burton *
61652c985acSPaul Burton * o bootmem_init()
61752c985acSPaul Burton * o sparse_init()
61852c985acSPaul Burton * o paging_init()
61952c985acSPaul Burton * o dma_contiguous_reserve()
62052c985acSPaul Burton *
62152c985acSPaul Burton * At this stage the bootmem allocator is ready to use.
62252c985acSPaul Burton *
62352c985acSPaul Burton * NOTE: historically plat_mem_setup did the entire platform initialization.
62452c985acSPaul Burton * This was rather impractical because it meant plat_mem_setup had to
62552c985acSPaul Burton * get away without any kind of memory allocator. To keep old code from
62652c985acSPaul Burton * breaking plat_setup was just renamed to plat_mem_setup and a second platform
62752c985acSPaul Burton * initialization hook for anything else was introduced.
62852c985acSPaul Burton */
arch_mem_init(char ** cmdline_p)6292925aba4SRalf Baechle static void __init arch_mem_init(char **cmdline_p)
6302925aba4SRalf Baechle {
631951d223cSPaul Burton /* call board setup routine */
632951d223cSPaul Burton plat_mem_setup();
63325517ed4SHuacai Chen memblock_set_bottom_up(true);
634951d223cSPaul Burton
635bd6e3898SZhi Li bootcmdline_init();
63688ca100cS陈学兵 strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
6372925aba4SRalf Baechle *cmdline_p = command_line;
6382925aba4SRalf Baechle
639a09fc446SFranck Bui-Huu parse_early_param();
640a09fc446SFranck Bui-Huu
641a94e4f24SJiaxun Yang if (usermem)
642a94e4f24SJiaxun Yang pr_info("User-defined physical RAM map overwrite\n");
643a94e4f24SJiaxun Yang
644a94e4f24SJiaxun Yang check_kernel_sections_mem();
645a09fc446SFranck Bui-Huu
64673346081SMarcin Nowakowski early_init_fdt_reserve_self();
64773346081SMarcin Nowakowski early_init_fdt_scan_reserved_mem();
64873346081SMarcin Nowakowski
649a94e4f24SJiaxun Yang #ifndef CONFIG_NUMA
650a94e4f24SJiaxun Yang memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
651a94e4f24SJiaxun Yang #endif
6522925aba4SRalf Baechle bootmem_init();
653bcec54bfSMike Rapoport
654bcec54bfSMike Rapoport /*
655bcec54bfSMike Rapoport * Prevent memblock from allocating high memory.
656bcec54bfSMike Rapoport * This cannot be done before max_low_pfn is detected, so up
657bcec54bfSMike Rapoport * to this point is possible to only reserve physical memory
658eb31d559SMike Rapoport * with memblock_reserve; memblock_alloc* can be used
659bcec54bfSMike Rapoport * only after this point
660bcec54bfSMike Rapoport */
661bcec54bfSMike Rapoport memblock_set_current_limit(PFN_PHYS(max_low_pfn));
662bcec54bfSMike Rapoport
663b306c5f5SJinyang He mips_reserve_vmcore();
664c2882b7fSPrem Mallappa
665c2882b7fSPrem Mallappa mips_parse_crashkernel();
666f2ffa5abSDezhong Diao device_tree_init();
667269b3a9aSTiezhu Yang
668269b3a9aSTiezhu Yang /*
669269b3a9aSTiezhu Yang * In order to reduce the possibility of kernel panic when failed to
670269b3a9aSTiezhu Yang * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
671269b3a9aSTiezhu Yang * low memory as small as possible before plat_swiotlb_setup(), so
672269b3a9aSTiezhu Yang * make sparse_init() using top-down allocation.
673269b3a9aSTiezhu Yang */
674269b3a9aSTiezhu Yang memblock_set_bottom_up(false);
6752925aba4SRalf Baechle sparse_init();
676269b3a9aSTiezhu Yang memblock_set_bottom_up(true);
677269b3a9aSTiezhu Yang
678ee71b7d2SDavid Daney plat_swiotlb_setup();
679f4649382SZubair Lutfullah Kakakhel
680f4649382SZubair Lutfullah Kakakhel dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
681a95d0692SHuacai Chen
6824e50a35dSSerge Semin /* Reserve for hibernation. */
6834e50a35dSSerge Semin memblock_reserve(__pa_symbol(&__nosave_begin),
6844e50a35dSSerge Semin __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin));
68530c8f4e4SSerge Semin
686a94e4f24SJiaxun Yang early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
6872925aba4SRalf Baechle }
6882925aba4SRalf Baechle
resource_init(void)6898df32c63SFranck Bui-Huu static void __init resource_init(void)
6901da177e4SLinus Torvalds {
691b10d6bcaSMike Rapoport phys_addr_t start, end;
692b10d6bcaSMike Rapoport u64 i;
6931da177e4SLinus Torvalds
6946adb5fe7SRalf Baechle if (UNCAC_BASE != IO_BASE)
6956adb5fe7SRalf Baechle return;
6966adb5fe7SRalf Baechle
697f5bffe3aSFranck Bui-Huu code_resource.start = __pa_symbol(&_text);
698f5bffe3aSFranck Bui-Huu code_resource.end = __pa_symbol(&_etext) - 1;
699f5bffe3aSFranck Bui-Huu data_resource.start = __pa_symbol(&_etext);
700f5bffe3aSFranck Bui-Huu data_resource.end = __pa_symbol(&_edata) - 1;
701e0c5f36bSDavid Daney bss_resource.start = __pa_symbol(&__bss_start);
702e0c5f36bSDavid Daney bss_resource.end = __pa_symbol(&__bss_stop) - 1;
7031da177e4SLinus Torvalds
704b10d6bcaSMike Rapoport for_each_mem_range(i, &start, &end) {
7051da177e4SLinus Torvalds struct resource *res;
7061da177e4SLinus Torvalds
707*c6f23979SGuo Weikang res = memblock_alloc_or_panic(sizeof(struct resource), SMP_CACHE_BYTES);
70835d98e93SToshi Kani
70935d98e93SToshi Kani res->start = start;
710b10d6bcaSMike Rapoport /*
711b10d6bcaSMike Rapoport * In memblock, end points to the first byte after the
712b10d6bcaSMike Rapoport * range while in resourses, end points to the last byte in
713b10d6bcaSMike Rapoport * the range.
714b10d6bcaSMike Rapoport */
715b10d6bcaSMike Rapoport res->end = end - 1;
716a94e4f24SJiaxun Yang res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
7171da177e4SLinus Torvalds res->name = "System RAM";
7181da177e4SLinus Torvalds
7191da177e4SLinus Torvalds request_resource(&iomem_resource, res);
7201da177e4SLinus Torvalds
7211da177e4SLinus Torvalds /*
7221da177e4SLinus Torvalds * We don't know which RAM region contains kernel data,
7231da177e4SLinus Torvalds * so we try it repeatedly and let the resource manager
7241da177e4SLinus Torvalds * test it.
7251da177e4SLinus Torvalds */
7261da177e4SLinus Torvalds request_resource(res, &code_resource);
7271da177e4SLinus Torvalds request_resource(res, &data_resource);
728e0c5f36bSDavid Daney request_resource(res, &bss_resource);
7297aa1c8f4SRalf Baechle request_crashkernel(res);
7301da177e4SLinus Torvalds }
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds
7330f3f506bSHuacai Chen #ifdef CONFIG_SMP
prefill_possible_map(void)7340f3f506bSHuacai Chen static void __init prefill_possible_map(void)
7350f3f506bSHuacai Chen {
7360f3f506bSHuacai Chen int i, possible = num_possible_cpus();
7370f3f506bSHuacai Chen
7380f3f506bSHuacai Chen if (possible > nr_cpu_ids)
7390f3f506bSHuacai Chen possible = nr_cpu_ids;
7400f3f506bSHuacai Chen
7410f3f506bSHuacai Chen for (i = 0; i < possible; i++)
7420f3f506bSHuacai Chen set_cpu_possible(i, true);
7430f3f506bSHuacai Chen for (; i < NR_CPUS; i++)
7440f3f506bSHuacai Chen set_cpu_possible(i, false);
7450f3f506bSHuacai Chen
74638bef8e5SYury Norov set_nr_cpu_ids(possible);
7470f3f506bSHuacai Chen }
7480f3f506bSHuacai Chen #else
prefill_possible_map(void)7490f3f506bSHuacai Chen static inline void prefill_possible_map(void) {}
7500f3f506bSHuacai Chen #endif
7510f3f506bSHuacai Chen
setup_rng_seed(void)752056a68ceSJason A. Donenfeld static void __init setup_rng_seed(void)
753056a68ceSJason A. Donenfeld {
754056a68ceSJason A. Donenfeld char *rng_seed_hex = fw_getenv("rngseed");
755056a68ceSJason A. Donenfeld u8 rng_seed[512];
756056a68ceSJason A. Donenfeld size_t len;
757056a68ceSJason A. Donenfeld
758056a68ceSJason A. Donenfeld if (!rng_seed_hex)
759056a68ceSJason A. Donenfeld return;
760056a68ceSJason A. Donenfeld
761056a68ceSJason A. Donenfeld len = min(sizeof(rng_seed), strlen(rng_seed_hex) / 2);
762056a68ceSJason A. Donenfeld if (hex2bin(rng_seed, rng_seed_hex, len))
763056a68ceSJason A. Donenfeld return;
764056a68ceSJason A. Donenfeld
765056a68ceSJason A. Donenfeld add_bootloader_randomness(rng_seed, len);
766056a68ceSJason A. Donenfeld memzero_explicit(rng_seed, len);
767056a68ceSJason A. Donenfeld memzero_explicit(rng_seed_hex, len * 2);
768056a68ceSJason A. Donenfeld }
769056a68ceSJason A. Donenfeld
setup_arch(char ** cmdline_p)7701da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
7711da177e4SLinus Torvalds {
7721da177e4SLinus Torvalds cpu_probe();
7733af5a67cSPaul Burton mips_cm_probe();
7741da177e4SLinus Torvalds prom_init();
77536a88530SRalf Baechle
776e934945dSJames Hogan setup_early_fdc_console();
77736a88530SRalf Baechle #ifdef CONFIG_EARLY_PRINTK
77836a88530SRalf Baechle setup_early_printk();
77936a88530SRalf Baechle #endif
7801da177e4SLinus Torvalds cpu_report();
781f4670a1bSNathan Chancellor if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64))
782f4670a1bSNathan Chancellor check_bugs64_early();
7831da177e4SLinus Torvalds
7842925aba4SRalf Baechle arch_mem_init(cmdline_p);
785be8fa1cbSTiezhu Yang dmi_setup();
7861da177e4SLinus Torvalds
7871da177e4SLinus Torvalds resource_init();
7889b6695a8SRalf Baechle plat_smp_setup();
7890f3f506bSHuacai Chen prefill_possible_map();
7906650df3cSDavid Daney
7916650df3cSDavid Daney cpu_cache_init();
792058effe7SPaul Burton paging_init();
7934f1682b8STiezhu Yang
7944f1682b8STiezhu Yang memblock_dump_all();
795056a68ceSJason A. Donenfeld
796056a68ceSJason A. Donenfeld setup_rng_seed();
7971da177e4SLinus Torvalds }
7981da177e4SLinus Torvalds
79969a6c312SAtsushi Nemoto unsigned long kernelsp[NR_CPUS];
80069a6c312SAtsushi Nemoto unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
8016312e0eeSAtsushi Nemoto
8026312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
8036312e0eeSAtsushi Nemoto struct dentry *mips_debugfs_dir;
debugfs_mips(void)8046312e0eeSAtsushi Nemoto static int __init debugfs_mips(void)
8056312e0eeSAtsushi Nemoto {
806d8140426SGreg Kroah-Hartman mips_debugfs_dir = debugfs_create_dir("mips", NULL);
8076312e0eeSAtsushi Nemoto return 0;
8086312e0eeSAtsushi Nemoto }
8096312e0eeSAtsushi Nemoto arch_initcall(debugfs_mips);
8106312e0eeSAtsushi Nemoto #endif
811aa4db775SChristoph Hellwig
812a86497d6SChristoph Hellwig #ifdef CONFIG_DMA_NONCOHERENT
setcoherentio(char * str)813aa4db775SChristoph Hellwig static int __init setcoherentio(char *str)
814aa4db775SChristoph Hellwig {
81514ac09a6SChristoph Hellwig dma_default_coherent = true;
816aa4db775SChristoph Hellwig pr_info("Hardware DMA cache coherency (command line)\n");
817aa4db775SChristoph Hellwig return 0;
818aa4db775SChristoph Hellwig }
819aa4db775SChristoph Hellwig early_param("coherentio", setcoherentio);
820aa4db775SChristoph Hellwig
setnocoherentio(char * str)821aa4db775SChristoph Hellwig static int __init setnocoherentio(char *str)
822aa4db775SChristoph Hellwig {
8231e6ae0e4SRandy Dunlap dma_default_coherent = false;
824aa4db775SChristoph Hellwig pr_info("Software DMA cache coherency (command line)\n");
825aa4db775SChristoph Hellwig return 0;
826aa4db775SChristoph Hellwig }
827aa4db775SChristoph Hellwig early_param("nocoherentio", setnocoherentio);
828aa4db775SChristoph Hellwig #endif
8297f066a22SThomas Gleixner
arch_cpu_finalize_init(void)8307f066a22SThomas Gleixner void __init arch_cpu_finalize_init(void)
8317f066a22SThomas Gleixner {
8327f066a22SThomas Gleixner unsigned int cpu = smp_processor_id();
8337f066a22SThomas Gleixner
8347f066a22SThomas Gleixner cpu_data[cpu].udelay_val = loops_per_jiffy;
8357f066a22SThomas Gleixner check_bugs32();
8367f066a22SThomas Gleixner
8377f066a22SThomas Gleixner if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64))
8387f066a22SThomas Gleixner check_bugs64();
8397f066a22SThomas Gleixner }
840