setup.c (9132B)
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> 22#include <linux/root_dev.h> 23#include <linux/console.h> 24#include <linux/pfn.h> 25#include <linux/platform_device.h> 26#include <linux/sizes.h> 27#include <linux/device.h> 28#include <linux/dma-map-ops.h> 29#include <linux/swiotlb.h> 30 31#include <asm/addrspace.h> 32#include <asm/bootinfo.h> 33#include <asm/cache.h> 34#include <asm/cpu.h> 35#include <asm/dma.h> 36#include <asm/efi.h> 37#include <asm/loongson.h> 38#include <asm/numa.h> 39#include <asm/pgalloc.h> 40#include <asm/sections.h> 41#include <asm/setup.h> 42#include <asm/time.h> 43 44#define SMBIOS_BIOSSIZE_OFFSET 0x09 45#define SMBIOS_BIOSEXTERN_OFFSET 0x13 46#define SMBIOS_FREQLOW_OFFSET 0x16 47#define SMBIOS_FREQHIGH_OFFSET 0x17 48#define SMBIOS_FREQLOW_MASK 0xFF 49#define SMBIOS_CORE_PACKAGE_OFFSET 0x23 50#define LOONGSON_EFI_ENABLE (1 << 3) 51 52#ifdef CONFIG_VT 53struct screen_info screen_info; 54#endif 55 56unsigned long fw_arg0, fw_arg1; 57DEFINE_PER_CPU(unsigned long, kernelsp); 58struct cpuinfo_loongarch cpu_data[NR_CPUS] __read_mostly; 59 60EXPORT_SYMBOL(cpu_data); 61 62struct loongson_board_info b_info; 63static const char dmi_empty_string[] = " "; 64 65/* 66 * Setup information 67 * 68 * These are initialized so they are in the .data section 69 */ 70 71static int num_standard_resources; 72static struct resource *standard_resources; 73 74static struct resource code_resource = { .name = "Kernel code", }; 75static struct resource data_resource = { .name = "Kernel data", }; 76static struct resource bss_resource = { .name = "Kernel bss", }; 77 78const char *get_system_type(void) 79{ 80 return "generic-loongson-machine"; 81} 82 83static const char *dmi_string_parse(const struct dmi_header *dm, u8 s) 84{ 85 const u8 *bp = ((u8 *) dm) + dm->length; 86 87 if (s) { 88 s--; 89 while (s > 0 && *bp) { 90 bp += strlen(bp) + 1; 91 s--; 92 } 93 94 if (*bp != 0) { 95 size_t len = strlen(bp)+1; 96 size_t cmp_len = len > 8 ? 8 : len; 97 98 if (!memcmp(bp, dmi_empty_string, cmp_len)) 99 return dmi_empty_string; 100 101 return bp; 102 } 103 } 104 105 return ""; 106} 107 108static void __init parse_cpu_table(const struct dmi_header *dm) 109{ 110 long freq_temp = 0; 111 char *dmi_data = (char *)dm; 112 113 freq_temp = ((*(dmi_data + SMBIOS_FREQHIGH_OFFSET) << 8) + 114 ((*(dmi_data + SMBIOS_FREQLOW_OFFSET)) & SMBIOS_FREQLOW_MASK)); 115 cpu_clock_freq = freq_temp * 1000000; 116 117 loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]); 118 loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET); 119 120 pr_info("CpuClock = %llu\n", cpu_clock_freq); 121} 122 123static void __init parse_bios_table(const struct dmi_header *dm) 124{ 125 int bios_extern; 126 char *dmi_data = (char *)dm; 127 128 bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET); 129 b_info.bios_size = *(dmi_data + SMBIOS_BIOSSIZE_OFFSET); 130 131 if (bios_extern & LOONGSON_EFI_ENABLE) 132 set_bit(EFI_BOOT, &efi.flags); 133 else 134 clear_bit(EFI_BOOT, &efi.flags); 135} 136 137static void __init find_tokens(const struct dmi_header *dm, void *dummy) 138{ 139 switch (dm->type) { 140 case 0x0: /* Extern BIOS */ 141 parse_bios_table(dm); 142 break; 143 case 0x4: /* Calling interface */ 144 parse_cpu_table(dm); 145 break; 146 } 147} 148static void __init smbios_parse(void) 149{ 150 b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR); 151 b_info.bios_version = (void *)dmi_get_system_info(DMI_BIOS_VERSION); 152 b_info.bios_release_date = (void *)dmi_get_system_info(DMI_BIOS_DATE); 153 b_info.board_vendor = (void *)dmi_get_system_info(DMI_BOARD_VENDOR); 154 b_info.board_name = (void *)dmi_get_system_info(DMI_BOARD_NAME); 155 dmi_walk(find_tokens, NULL); 156} 157 158static int usermem __initdata; 159 160static int __init early_parse_mem(char *p) 161{ 162 phys_addr_t start, size; 163 164 if (!p) { 165 pr_err("mem parameter is empty, do nothing\n"); 166 return -EINVAL; 167 } 168 169 /* 170 * If a user specifies memory size, we 171 * blow away any automatically generated 172 * size. 173 */ 174 if (usermem == 0) { 175 usermem = 1; 176 memblock_remove(memblock_start_of_DRAM(), 177 memblock_end_of_DRAM() - memblock_start_of_DRAM()); 178 } 179 start = 0; 180 size = memparse(p, &p); 181 if (*p == '@') 182 start = memparse(p + 1, &p); 183 else { 184 pr_err("Invalid format!\n"); 185 return -EINVAL; 186 } 187 188 if (!IS_ENABLED(CONFIG_NUMA)) 189 memblock_add(start, size); 190 else 191 memblock_add_node(start, size, pa_to_nid(start), MEMBLOCK_NONE); 192 193 return 0; 194} 195early_param("mem", early_parse_mem); 196 197void __init platform_init(void) 198{ 199 efi_init(); 200#ifdef CONFIG_ACPI_TABLE_UPGRADE 201 acpi_table_upgrade(); 202#endif 203#ifdef CONFIG_ACPI 204 acpi_gbl_use_default_register_widths = false; 205 acpi_boot_table_init(); 206 acpi_boot_init(); 207#endif 208 209#ifdef CONFIG_NUMA 210 init_numa_memory(); 211#endif 212 dmi_setup(); 213 smbios_parse(); 214 pr_info("The BIOS Version: %s\n", b_info.bios_version); 215 216 efi_runtime_init(); 217} 218 219static void __init check_kernel_sections_mem(void) 220{ 221 phys_addr_t start = __pa_symbol(&_text); 222 phys_addr_t size = __pa_symbol(&_end) - start; 223 224 if (!memblock_is_region_memory(start, size)) { 225 pr_info("Kernel sections are not in the memory maps\n"); 226 memblock_add(start, size); 227 } 228} 229 230/* 231 * arch_mem_init - initialize memory management subsystem 232 */ 233static void __init arch_mem_init(char **cmdline_p) 234{ 235 if (usermem) 236 pr_info("User-defined physical RAM map overwrite\n"); 237 238 check_kernel_sections_mem(); 239 240 /* 241 * In order to reduce the possibility of kernel panic when failed to 242 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate 243 * low memory as small as possible before plat_swiotlb_setup(), so 244 * make sparse_init() using top-down allocation. 245 */ 246 memblock_set_bottom_up(false); 247 sparse_init(); 248 memblock_set_bottom_up(true); 249 250 plat_swiotlb_setup(); 251 252 dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); 253 254 memblock_dump_all(); 255 256 early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn)); 257} 258 259static void __init resource_init(void) 260{ 261 long i = 0; 262 size_t res_size; 263 struct resource *res; 264 struct memblock_region *region; 265 266 code_resource.start = __pa_symbol(&_text); 267 code_resource.end = __pa_symbol(&_etext) - 1; 268 data_resource.start = __pa_symbol(&_etext); 269 data_resource.end = __pa_symbol(&_edata) - 1; 270 bss_resource.start = __pa_symbol(&__bss_start); 271 bss_resource.end = __pa_symbol(&__bss_stop) - 1; 272 273 num_standard_resources = memblock.memory.cnt; 274 res_size = num_standard_resources * sizeof(*standard_resources); 275 standard_resources = memblock_alloc(res_size, SMP_CACHE_BYTES); 276 277 for_each_mem_region(region) { 278 res = &standard_resources[i++]; 279 if (!memblock_is_nomap(region)) { 280 res->name = "System RAM"; 281 res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 282 res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 283 res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 284 } else { 285 res->name = "Reserved"; 286 res->flags = IORESOURCE_MEM; 287 res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region)); 288 res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1; 289 } 290 291 request_resource(&iomem_resource, res); 292 293 /* 294 * We don't know which RAM region contains kernel data, 295 * so we try it repeatedly and let the resource manager 296 * test it. 297 */ 298 request_resource(res, &code_resource); 299 request_resource(res, &data_resource); 300 request_resource(res, &bss_resource); 301 } 302} 303 304static int __init reserve_memblock_reserved_regions(void) 305{ 306 u64 i, j; 307 308 for (i = 0; i < num_standard_resources; ++i) { 309 struct resource *mem = &standard_resources[i]; 310 phys_addr_t r_start, r_end, mem_size = resource_size(mem); 311 312 if (!memblock_is_region_reserved(mem->start, mem_size)) 313 continue; 314 315 for_each_reserved_mem_range(j, &r_start, &r_end) { 316 resource_size_t start, end; 317 318 start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); 319 end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); 320 321 if (start > mem->end || end < mem->start) 322 continue; 323 324 reserve_region_with_split(mem, start, end, "Reserved"); 325 } 326 } 327 328 return 0; 329} 330arch_initcall(reserve_memblock_reserved_regions); 331 332#ifdef CONFIG_SMP 333static void __init prefill_possible_map(void) 334{ 335 int i, possible; 336 337 possible = num_processors + disabled_cpus; 338 if (possible > nr_cpu_ids) 339 possible = nr_cpu_ids; 340 341 pr_info("SMP: Allowing %d CPUs, %d hotplug CPUs\n", 342 possible, max((possible - num_processors), 0)); 343 344 for (i = 0; i < possible; i++) 345 set_cpu_possible(i, true); 346 for (; i < NR_CPUS; i++) 347 set_cpu_possible(i, false); 348 349 nr_cpu_ids = possible; 350} 351#endif 352 353void __init setup_arch(char **cmdline_p) 354{ 355 cpu_probe(); 356 *cmdline_p = boot_command_line; 357 358 init_environ(); 359 memblock_init(); 360 parse_early_param(); 361 362 platform_init(); 363 pagetable_init(); 364 arch_mem_init(cmdline_p); 365 366 resource_init(); 367#ifdef CONFIG_SMP 368 plat_smp_setup(); 369 prefill_possible_map(); 370#endif 371 372 paging_init(); 373}