Commit | Line | Data |
---|---|---|
628c3bb4 HC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2020-2022 Loongson Technology Corporation Limited | |
4 | * | |
5 | * Derived from MIPS: | |
6 | * Copyright (C) 1995 Linus Torvalds | |
7 | * Copyright (C) 1995 Waldorf Electronics | |
8 | * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Ralf Baechle | |
9 | * Copyright (C) 1996 Stoned Elipot | |
10 | * Copyright (C) 1999 Silicon Graphics, Inc. | |
11 | * Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki | |
12 | */ | |
13 | #include <linux/init.h> | |
14 | #include <linux/acpi.h> | |
15 | #include <linux/dmi.h> | |
16 | #include <linux/efi.h> | |
17 | #include <linux/export.h> | |
18 | #include <linux/screen_info.h> | |
19 | #include <linux/memblock.h> | |
20 | #include <linux/initrd.h> | |
21 | #include <linux/ioport.h> | |
4e62d1d8 YT |
22 | #include <linux/kexec.h> |
23 | #include <linux/crash_dump.h> | |
628c3bb4 HC |
24 | #include <linux/root_dev.h> |
25 | #include <linux/console.h> | |
26 | #include <linux/pfn.h> | |
27 | #include <linux/platform_device.h> | |
28 | #include <linux/sizes.h> | |
29 | #include <linux/device.h> | |
30 | #include <linux/dma-map-ops.h> | |
88d4d957 BZ |
31 | #include <linux/libfdt.h> |
32 | #include <linux/of_fdt.h> | |
33 | #include <linux/of_address.h> | |
7db54bfe | 34 | #include <linux/suspend.h> |
628c3bb4 HC |
35 | #include <linux/swiotlb.h> |
36 | ||
37 | #include <asm/addrspace.h> | |
19e5eb15 | 38 | #include <asm/alternative.h> |
628c3bb4 | 39 | #include <asm/bootinfo.h> |
19e5eb15 | 40 | #include <asm/bugs.h> |
628c3bb4 HC |
41 | #include <asm/cache.h> |
42 | #include <asm/cpu.h> | |
43 | #include <asm/dma.h> | |
44 | #include <asm/efi.h> | |
45 | #include <asm/loongson.h> | |
d4b6f156 | 46 | #include <asm/numa.h> |
628c3bb4 HC |
47 | #include <asm/pgalloc.h> |
48 | #include <asm/sections.h> | |
49 | #include <asm/setup.h> | |
50 | #include <asm/time.h> | |
51 | ||
52 | #define SMBIOS_BIOSSIZE_OFFSET 0x09 | |
53 | #define SMBIOS_BIOSEXTERN_OFFSET 0x13 | |
54 | #define SMBIOS_FREQLOW_OFFSET 0x16 | |
55 | #define SMBIOS_FREQHIGH_OFFSET 0x17 | |
56 | #define SMBIOS_FREQLOW_MASK 0xFF | |
57 | #define SMBIOS_CORE_PACKAGE_OFFSET 0x23 | |
58 | #define LOONGSON_EFI_ENABLE (1 << 3) | |
59 | ||
ead384d9 | 60 | struct screen_info screen_info __section(".data"); |
628c3bb4 | 61 | |
40cd01a9 | 62 | unsigned long fw_arg0, fw_arg1, fw_arg2; |
628c3bb4 HC |
63 | DEFINE_PER_CPU(unsigned long, kernelsp); |
64 | struct cpuinfo_loongarch cpu_data[NR_CPUS] __read_mostly; | |
65 | ||
66 | EXPORT_SYMBOL(cpu_data); | |
67 | ||
68 | struct loongson_board_info b_info; | |
69 | static const char dmi_empty_string[] = " "; | |
70 | ||
71 | /* | |
72 | * Setup information | |
73 | * | |
74 | * These are initialized so they are in the .data section | |
75 | */ | |
88d4d957 | 76 | char init_command_line[COMMAND_LINE_SIZE] __initdata; |
628c3bb4 HC |
77 | |
78 | static int num_standard_resources; | |
79 | static struct resource *standard_resources; | |
80 | ||
81 | static struct resource code_resource = { .name = "Kernel code", }; | |
82 | static struct resource data_resource = { .name = "Kernel data", }; | |
83 | static struct resource bss_resource = { .name = "Kernel bss", }; | |
84 | ||
85 | const char *get_system_type(void) | |
86 | { | |
87 | return "generic-loongson-machine"; | |
88 | } | |
89 | ||
19e5eb15 HC |
90 | void __init check_bugs(void) |
91 | { | |
92 | alternative_instructions(); | |
93 | } | |
94 | ||
628c3bb4 HC |
95 | static const char *dmi_string_parse(const struct dmi_header *dm, u8 s) |
96 | { | |
97 | const u8 *bp = ((u8 *) dm) + dm->length; | |
98 | ||
99 | if (s) { | |
100 | s--; | |
101 | while (s > 0 && *bp) { | |
102 | bp += strlen(bp) + 1; | |
103 | s--; | |
104 | } | |
105 | ||
106 | if (*bp != 0) { | |
107 | size_t len = strlen(bp)+1; | |
108 | size_t cmp_len = len > 8 ? 8 : len; | |
109 | ||
110 | if (!memcmp(bp, dmi_empty_string, cmp_len)) | |
111 | return dmi_empty_string; | |
112 | ||
113 | return bp; | |
114 | } | |
115 | } | |
116 | ||
117 | return ""; | |
118 | } | |
119 | ||
120 | static void __init parse_cpu_table(const struct dmi_header *dm) | |
121 | { | |
122 | long freq_temp = 0; | |
123 | char *dmi_data = (char *)dm; | |
124 | ||
125 | freq_temp = ((*(dmi_data + SMBIOS_FREQHIGH_OFFSET) << 8) + | |
126 | ((*(dmi_data + SMBIOS_FREQLOW_OFFSET)) & SMBIOS_FREQLOW_MASK)); | |
127 | cpu_clock_freq = freq_temp * 1000000; | |
128 | ||
129 | loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]); | |
130 | loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET); | |
131 | ||
132 | pr_info("CpuClock = %llu\n", cpu_clock_freq); | |
133 | } | |
134 | ||
135 | static void __init parse_bios_table(const struct dmi_header *dm) | |
136 | { | |
628c3bb4 HC |
137 | char *dmi_data = (char *)dm; |
138 | ||
45b53c90 | 139 | b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6; |
628c3bb4 HC |
140 | } |
141 | ||
142 | static void __init find_tokens(const struct dmi_header *dm, void *dummy) | |
143 | { | |
144 | switch (dm->type) { | |
145 | case 0x0: /* Extern BIOS */ | |
146 | parse_bios_table(dm); | |
147 | break; | |
148 | case 0x4: /* Calling interface */ | |
149 | parse_cpu_table(dm); | |
150 | break; | |
151 | } | |
152 | } | |
153 | static void __init smbios_parse(void) | |
154 | { | |
155 | b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR); | |
156 | b_info.bios_version = (void *)dmi_get_system_info(DMI_BIOS_VERSION); | |
157 | b_info.bios_release_date = (void *)dmi_get_system_info(DMI_BIOS_DATE); | |
158 | b_info.board_vendor = (void *)dmi_get_system_info(DMI_BOARD_VENDOR); | |
159 | b_info.board_name = (void *)dmi_get_system_info(DMI_BOARD_NAME); | |
160 | dmi_walk(find_tokens, NULL); | |
161 | } | |
162 | ||
16c52e50 HC |
163 | #ifdef CONFIG_ARCH_WRITECOMBINE |
164 | pgprot_t pgprot_wc = PAGE_KERNEL_WUC; | |
165 | #else | |
166 | pgprot_t pgprot_wc = PAGE_KERNEL_SUC; | |
167 | #endif | |
168 | ||
169 | EXPORT_SYMBOL(pgprot_wc); | |
170 | ||
171 | static int __init setup_writecombine(char *p) | |
172 | { | |
173 | if (!strcmp(p, "on")) | |
174 | pgprot_wc = PAGE_KERNEL_WUC; | |
175 | else if (!strcmp(p, "off")) | |
176 | pgprot_wc = PAGE_KERNEL_SUC; | |
177 | else | |
178 | pr_warn("Unknown writecombine setting \"%s\".\n", p); | |
179 | ||
180 | return 0; | |
181 | } | |
182 | early_param("writecombine", setup_writecombine); | |
183 | ||
628c3bb4 HC |
184 | static int usermem __initdata; |
185 | ||
186 | static int __init early_parse_mem(char *p) | |
187 | { | |
188 | phys_addr_t start, size; | |
189 | ||
190 | if (!p) { | |
191 | pr_err("mem parameter is empty, do nothing\n"); | |
192 | return -EINVAL; | |
193 | } | |
194 | ||
195 | /* | |
196 | * If a user specifies memory size, we | |
197 | * blow away any automatically generated | |
198 | * size. | |
199 | */ | |
200 | if (usermem == 0) { | |
201 | usermem = 1; | |
202 | memblock_remove(memblock_start_of_DRAM(), | |
203 | memblock_end_of_DRAM() - memblock_start_of_DRAM()); | |
204 | } | |
205 | start = 0; | |
206 | size = memparse(p, &p); | |
207 | if (*p == '@') | |
208 | start = memparse(p + 1, &p); | |
209 | else { | |
210 | pr_err("Invalid format!\n"); | |
211 | return -EINVAL; | |
212 | } | |
213 | ||
d4b6f156 HC |
214 | if (!IS_ENABLED(CONFIG_NUMA)) |
215 | memblock_add(start, size); | |
216 | else | |
217 | memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE); | |
628c3bb4 HC |
218 | |
219 | return 0; | |
220 | } | |
221 | early_param("mem", early_parse_mem); | |
222 | ||
4e62d1d8 YT |
223 | static void __init arch_reserve_vmcore(void) |
224 | { | |
225 | #ifdef CONFIG_PROC_VMCORE | |
226 | u64 i; | |
227 | phys_addr_t start, end; | |
228 | ||
229 | if (!is_kdump_kernel()) | |
230 | return; | |
231 | ||
232 | if (!elfcorehdr_size) { | |
233 | for_each_mem_range(i, &start, &end) { | |
234 | if (elfcorehdr_addr >= start && elfcorehdr_addr < end) { | |
235 | /* | |
236 | * Reserve from the elf core header to the end of | |
237 | * the memory segment, that should all be kdump | |
238 | * reserved memory. | |
239 | */ | |
240 | elfcorehdr_size = end - elfcorehdr_addr; | |
241 | break; | |
242 | } | |
243 | } | |
244 | } | |
245 | ||
246 | if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) { | |
247 | pr_warn("elfcorehdr is overlapped\n"); | |
248 | return; | |
249 | } | |
250 | ||
251 | memblock_reserve(elfcorehdr_addr, elfcorehdr_size); | |
252 | ||
253 | pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n", | |
254 | elfcorehdr_size >> 10, elfcorehdr_addr); | |
255 | #endif | |
256 | } | |
257 | ||
35c94fab YT |
258 | /* 2MB alignment for crash kernel regions */ |
259 | #define CRASH_ALIGN SZ_2M | |
260 | #define CRASH_ADDR_MAX SZ_4G | |
261 | ||
4e62d1d8 YT |
262 | static void __init arch_parse_crashkernel(void) |
263 | { | |
264 | #ifdef CONFIG_KEXEC | |
265 | int ret; | |
4e62d1d8 YT |
266 | unsigned long long total_mem; |
267 | unsigned long long crash_base, crash_size; | |
268 | ||
269 | total_mem = memblock_phys_mem_size(); | |
270 | ret = parse_crashkernel(boot_command_line, total_mem, &crash_size, &crash_base); | |
271 | if (ret < 0 || crash_size <= 0) | |
272 | return; | |
273 | ||
35c94fab YT |
274 | if (crash_base <= 0) { |
275 | crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN, CRASH_ALIGN, CRASH_ADDR_MAX); | |
276 | if (!crash_base) { | |
277 | pr_warn("crashkernel reservation failed - No suitable area found.\n"); | |
278 | return; | |
279 | } | |
280 | } else if (!memblock_phys_alloc_range(crash_size, CRASH_ALIGN, crash_base, crash_base + crash_size)) { | |
4e62d1d8 YT |
281 | pr_warn("Invalid memory region reserved for crash kernel\n"); |
282 | return; | |
283 | } | |
284 | ||
285 | crashk_res.start = crash_base; | |
286 | crashk_res.end = crash_base + crash_size - 1; | |
287 | #endif | |
288 | } | |
289 | ||
88d4d957 BZ |
290 | static void __init fdt_setup(void) |
291 | { | |
292 | #ifdef CONFIG_OF_EARLY_FLATTREE | |
293 | void *fdt_pointer; | |
294 | ||
295 | /* ACPI-based systems do not require parsing fdt */ | |
296 | if (acpi_os_get_root_pointer()) | |
297 | return; | |
298 | ||
299 | /* Look for a device tree configuration table entry */ | |
300 | fdt_pointer = efi_fdt_pointer(); | |
301 | if (!fdt_pointer || fdt_check_header(fdt_pointer)) | |
302 | return; | |
303 | ||
304 | early_init_dt_scan(fdt_pointer); | |
305 | early_init_fdt_reserve_self(); | |
306 | ||
307 | max_low_pfn = PFN_PHYS(memblock_end_of_DRAM()); | |
308 | #endif | |
309 | } | |
310 | ||
311 | static void __init bootcmdline_init(char **cmdline_p) | |
312 | { | |
313 | /* | |
314 | * If CONFIG_CMDLINE_FORCE is enabled then initializing the command line | |
315 | * is trivial - we simply use the built-in command line unconditionally & | |
316 | * unmodified. | |
317 | */ | |
318 | if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) { | |
319 | strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); | |
320 | goto out; | |
321 | } | |
322 | ||
323 | #ifdef CONFIG_OF_FLATTREE | |
324 | /* | |
325 | * If CONFIG_CMDLINE_BOOTLOADER is enabled and we are in FDT-based system, | |
326 | * the boot_command_line will be overwritten by early_init_dt_scan_chosen(). | |
327 | * So we need to append init_command_line (the original copy of boot_command_line) | |
328 | * to boot_command_line. | |
329 | */ | |
330 | if (initial_boot_params) { | |
331 | if (boot_command_line[0]) | |
332 | strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); | |
333 | ||
334 | strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE); | |
335 | } | |
336 | #endif | |
337 | ||
338 | out: | |
339 | *cmdline_p = boot_command_line; | |
340 | } | |
341 | ||
628c3bb4 HC |
342 | void __init platform_init(void) |
343 | { | |
4e62d1d8 YT |
344 | arch_reserve_vmcore(); |
345 | arch_parse_crashkernel(); | |
346 | ||
628c3bb4 HC |
347 | #ifdef CONFIG_ACPI_TABLE_UPGRADE |
348 | acpi_table_upgrade(); | |
349 | #endif | |
350 | #ifdef CONFIG_ACPI | |
351 | acpi_gbl_use_default_register_widths = false; | |
352 | acpi_boot_table_init(); | |
628c3bb4 | 353 | #endif |
88d4d957 | 354 | unflatten_and_copy_device_tree(); |
628c3bb4 | 355 | |
d4b6f156 HC |
356 | #ifdef CONFIG_NUMA |
357 | init_numa_memory(); | |
358 | #endif | |
628c3bb4 HC |
359 | dmi_setup(); |
360 | smbios_parse(); | |
361 | pr_info("The BIOS Version: %s\n", b_info.bios_version); | |
362 | ||
363 | efi_runtime_init(); | |
364 | } | |
365 | ||
366 | static void __init check_kernel_sections_mem(void) | |
367 | { | |
368 | phys_addr_t start = __pa_symbol(&_text); | |
369 | phys_addr_t size = __pa_symbol(&_end) - start; | |
370 | ||
371 | if (!memblock_is_region_memory(start, size)) { | |
372 | pr_info("Kernel sections are not in the memory maps\n"); | |
373 | memblock_add(start, size); | |
374 | } | |
375 | } | |
376 | ||
377 | /* | |
378 | * arch_mem_init - initialize memory management subsystem | |
379 | */ | |
380 | static void __init arch_mem_init(char **cmdline_p) | |
381 | { | |
382 | if (usermem) | |
383 | pr_info("User-defined physical RAM map overwrite\n"); | |
384 | ||
385 | check_kernel_sections_mem(); | |
386 | ||
88d4d957 BZ |
387 | early_init_fdt_scan_reserved_mem(); |
388 | ||
628c3bb4 HC |
389 | /* |
390 | * In order to reduce the possibility of kernel panic when failed to | |
391 | * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate | |
afca6e06 TY |
392 | * low memory as small as possible before swiotlb_init(), so make |
393 | * sparse_init() using top-down allocation. | |
628c3bb4 HC |
394 | */ |
395 | memblock_set_bottom_up(false); | |
396 | sparse_init(); | |
397 | memblock_set_bottom_up(true); | |
398 | ||
c78c43fe | 399 | swiotlb_init(true, SWIOTLB_VERBOSE); |
628c3bb4 HC |
400 | |
401 | dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); | |
402 | ||
7db54bfe HC |
403 | /* Reserve for hibernation. */ |
404 | register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)), | |
405 | PFN_UP(__pa_symbol(&__nosave_end))); | |
406 | ||
628c3bb4 HC |
407 | memblock_dump_all(); |
408 | ||
409 | early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); | |
410 | } | |
411 | ||
412 | static void __init resource_init(void) | |
413 | { | |
414 | long i = 0; | |
415 | size_t res_size; | |
416 | struct resource *res; | |
417 | struct memblock_region *region; | |
418 | ||
419 | code_resource.start = __pa_symbol(&_text); | |
420 | code_resource.end = __pa_symbol(&_etext) - 1; | |
421 | data_resource.start = __pa_symbol(&_etext); | |
422 | data_resource.end = __pa_symbol(&_edata) - 1; | |
423 | bss_resource.start = __pa_symbol(&__bss_start); | |
424 | bss_resource.end = __pa_symbol(&__bss_stop) - 1; | |
425 | ||
426 | num_standard_resources = memblock.memory.cnt; | |
427 | res_size = num_standard_resources * sizeof(*standard_resources); | |
428 | standard_resources = memblock_alloc(res_size, SMP_CACHE_BYTES); | |
429 | ||
430 | for_each_mem_region(region) { | |
431 | res = &standard_resources[i++]; | |
432 | if (!memblock_is_nomap(region)) { | |
433 | res->name = "System RAM"; | |
434 | res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | |
435 | res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); | |
436 | res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; | |
437 | } else { | |
438 | res->name = "Reserved"; | |
439 | res->flags = IORESOURCE_MEM; | |
440 | res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region)); | |
441 | res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1; | |
442 | } | |
443 | ||
444 | request_resource(&iomem_resource, res); | |
445 | ||
446 | /* | |
447 | * We don't know which RAM region contains kernel data, | |
448 | * so we try it repeatedly and let the resource manager | |
449 | * test it. | |
450 | */ | |
451 | request_resource(res, &code_resource); | |
452 | request_resource(res, &data_resource); | |
453 | request_resource(res, &bss_resource); | |
454 | } | |
4e62d1d8 YT |
455 | |
456 | #ifdef CONFIG_KEXEC | |
457 | if (crashk_res.start < crashk_res.end) { | |
458 | insert_resource(&iomem_resource, &crashk_res); | |
459 | pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n", | |
460 | (unsigned long)((crashk_res.end - crashk_res.start + 1) >> 20), | |
461 | (unsigned long)(crashk_res.start >> 20)); | |
462 | } | |
463 | #endif | |
628c3bb4 HC |
464 | } |
465 | ||
27cab431 BZ |
466 | static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, |
467 | resource_size_t hw_start, resource_size_t size) | |
468 | { | |
469 | int ret = 0; | |
470 | unsigned long vaddr; | |
471 | struct logic_pio_hwaddr *range; | |
472 | ||
473 | range = kzalloc(sizeof(*range), GFP_ATOMIC); | |
474 | if (!range) | |
475 | return -ENOMEM; | |
476 | ||
477 | range->fwnode = fwnode; | |
478 | range->size = size = round_up(size, PAGE_SIZE); | |
479 | range->hw_start = hw_start; | |
480 | range->flags = LOGIC_PIO_CPU_MMIO; | |
481 | ||
482 | ret = logic_pio_register_range(range); | |
483 | if (ret) { | |
484 | kfree(range); | |
485 | return ret; | |
486 | } | |
487 | ||
488 | /* Legacy ISA must placed at the start of PCI_IOBASE */ | |
489 | if (range->io_start != 0) { | |
490 | logic_pio_unregister_range(range); | |
491 | kfree(range); | |
492 | return -EINVAL; | |
493 | } | |
494 | ||
495 | vaddr = (unsigned long)(PCI_IOBASE + range->io_start); | |
496 | ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL)); | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
501 | static __init int arch_reserve_pio_range(void) | |
502 | { | |
503 | struct device_node *np; | |
504 | ||
505 | for_each_node_by_name(np, "isa") { | |
506 | struct of_range range; | |
507 | struct of_range_parser parser; | |
508 | ||
509 | pr_info("ISA Bridge: %pOF\n", np); | |
510 | ||
511 | if (of_range_parser_init(&parser, np)) { | |
512 | pr_info("Failed to parse resources.\n"); | |
513 | of_node_put(np); | |
514 | break; | |
515 | } | |
516 | ||
517 | for_each_of_range(&parser, &range) { | |
518 | switch (range.flags & IORESOURCE_TYPE_BITS) { | |
519 | case IORESOURCE_IO: | |
520 | pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", | |
521 | range.cpu_addr, | |
522 | range.cpu_addr + range.size - 1, | |
523 | range.bus_addr); | |
524 | if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size)) | |
525 | pr_warn("Failed to reserve legacy IO in Logic PIO\n"); | |
526 | break; | |
527 | case IORESOURCE_MEM: | |
528 | pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n", | |
529 | range.cpu_addr, | |
530 | range.cpu_addr + range.size - 1, | |
531 | range.bus_addr); | |
532 | break; | |
533 | } | |
534 | } | |
535 | } | |
536 | ||
537 | return 0; | |
538 | } | |
539 | arch_initcall(arch_reserve_pio_range); | |
540 | ||
628c3bb4 HC |
541 | static int __init reserve_memblock_reserved_regions(void) |
542 | { | |
543 | u64 i, j; | |
544 | ||
545 | for (i = 0; i < num_standard_resources; ++i) { | |
546 | struct resource *mem = &standard_resources[i]; | |
547 | phys_addr_t r_start, r_end, mem_size = resource_size(mem); | |
548 | ||
549 | if (!memblock_is_region_reserved(mem->start, mem_size)) | |
550 | continue; | |
551 | ||
552 | for_each_reserved_mem_range(j, &r_start, &r_end) { | |
553 | resource_size_t start, end; | |
554 | ||
555 | start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); | |
556 | end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); | |
557 | ||
558 | if (start > mem->end || end < mem->start) | |
559 | continue; | |
560 | ||
561 | reserve_region_with_split(mem, start, end, "Reserved"); | |
562 | } | |
563 | } | |
564 | ||
565 | return 0; | |
566 | } | |
567 | arch_initcall(reserve_memblock_reserved_regions); | |
568 | ||
46859ac8 HC |
569 | #ifdef CONFIG_SMP |
570 | static void __init prefill_possible_map(void) | |
571 | { | |
572 | int i, possible; | |
573 | ||
574 | possible = num_processors + disabled_cpus; | |
575 | if (possible > nr_cpu_ids) | |
576 | possible = nr_cpu_ids; | |
577 | ||
578 | pr_info("SMP: Allowing %d CPUs, %d hotplug CPUs\n", | |
579 | possible, max((possible - num_processors), 0)); | |
580 | ||
581 | for (i = 0; i < possible; i++) | |
582 | set_cpu_possible(i, true); | |
583 | for (; i < NR_CPUS; i++) | |
584 | set_cpu_possible(i, false); | |
585 | ||
38bef8e5 | 586 | set_nr_cpu_ids(possible); |
46859ac8 | 587 | } |
46859ac8 HC |
588 | #endif |
589 | ||
628c3bb4 HC |
590 | void __init setup_arch(char **cmdline_p) |
591 | { | |
592 | cpu_probe(); | |
628c3bb4 HC |
593 | |
594 | init_environ(); | |
40cd01a9 | 595 | efi_init(); |
88d4d957 | 596 | fdt_setup(); |
628c3bb4 | 597 | memblock_init(); |
d2791341 | 598 | pagetable_init(); |
88d4d957 | 599 | bootcmdline_init(cmdline_p); |
628c3bb4 | 600 | parse_early_param(); |
4e62d1d8 | 601 | reserve_initrd_mem(); |
628c3bb4 HC |
602 | |
603 | platform_init(); | |
628c3bb4 HC |
604 | arch_mem_init(cmdline_p); |
605 | ||
606 | resource_init(); | |
255b4658 | 607 | #ifdef CONFIG_SMP |
46859ac8 HC |
608 | plat_smp_setup(); |
609 | prefill_possible_map(); | |
255b4658 | 610 | #endif |
628c3bb4 HC |
611 | |
612 | paging_init(); | |
613 | } |