19703d9d7SCatalin Marinas /* 29703d9d7SCatalin Marinas * Based on arch/arm/kernel/setup.c 39703d9d7SCatalin Marinas * 49703d9d7SCatalin Marinas * Copyright (C) 1995-2001 Russell King 59703d9d7SCatalin Marinas * Copyright (C) 2012 ARM Ltd. 69703d9d7SCatalin Marinas * 79703d9d7SCatalin Marinas * This program is free software; you can redistribute it and/or modify 89703d9d7SCatalin Marinas * it under the terms of the GNU General Public License version 2 as 99703d9d7SCatalin Marinas * published by the Free Software Foundation. 109703d9d7SCatalin Marinas * 119703d9d7SCatalin Marinas * This program is distributed in the hope that it will be useful, 129703d9d7SCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of 139703d9d7SCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149703d9d7SCatalin Marinas * GNU General Public License for more details. 159703d9d7SCatalin Marinas * 169703d9d7SCatalin Marinas * You should have received a copy of the GNU General Public License 179703d9d7SCatalin Marinas * along with this program. If not, see <http://www.gnu.org/licenses/>. 189703d9d7SCatalin Marinas */ 199703d9d7SCatalin Marinas 2037655163SAl Stone #include <linux/acpi.h> 219703d9d7SCatalin Marinas #include <linux/export.h> 229703d9d7SCatalin Marinas #include <linux/kernel.h> 239703d9d7SCatalin Marinas #include <linux/stddef.h> 249703d9d7SCatalin Marinas #include <linux/ioport.h> 259703d9d7SCatalin Marinas #include <linux/delay.h> 269703d9d7SCatalin Marinas #include <linux/utsname.h> 279703d9d7SCatalin Marinas #include <linux/initrd.h> 289703d9d7SCatalin Marinas #include <linux/console.h> 29a41dc0e8SCatalin Marinas #include <linux/cache.h> 309703d9d7SCatalin Marinas #include <linux/bootmem.h> 319703d9d7SCatalin Marinas #include <linux/screen_info.h> 329703d9d7SCatalin Marinas #include <linux/init.h> 339703d9d7SCatalin Marinas #include <linux/kexec.h> 349703d9d7SCatalin Marinas #include <linux/crash_dump.h> 359703d9d7SCatalin Marinas #include <linux/root_dev.h> 369703d9d7SCatalin Marinas #include <linux/cpu.h> 379703d9d7SCatalin Marinas #include <linux/interrupt.h> 389703d9d7SCatalin Marinas #include <linux/smp.h> 399703d9d7SCatalin Marinas #include <linux/fs.h> 409703d9d7SCatalin Marinas #include <linux/proc_fs.h> 419703d9d7SCatalin Marinas #include <linux/memblock.h> 4278d51e0bSRobin Murphy #include <linux/of_iommu.h> 439703d9d7SCatalin Marinas #include <linux/of_fdt.h> 44d6bafb9bSCatalin Marinas #include <linux/of_platform.h> 45f84d0275SMark Salter #include <linux/efi.h> 46bff60792SMark Rutland #include <linux/psci.h> 479703d9d7SCatalin Marinas 4837655163SAl Stone #include <asm/acpi.h> 49bf4b558eSMark Salter #include <asm/fixmap.h> 50df857416SMark Rutland #include <asm/cpu.h> 519703d9d7SCatalin Marinas #include <asm/cputype.h> 529703d9d7SCatalin Marinas #include <asm/elf.h> 53930da09fSAndre Przywara #include <asm/cpufeature.h> 54e8765b26SMark Rutland #include <asm/cpu_ops.h> 5539d114ddSAndrey Ryabinin #include <asm/kasan.h> 569703d9d7SCatalin Marinas #include <asm/sections.h> 579703d9d7SCatalin Marinas #include <asm/setup.h> 584c7aa002SJavi Merino #include <asm/smp_plat.h> 599703d9d7SCatalin Marinas #include <asm/cacheflush.h> 609703d9d7SCatalin Marinas #include <asm/tlbflush.h> 619703d9d7SCatalin Marinas #include <asm/traps.h> 629703d9d7SCatalin Marinas #include <asm/memblock.h> 63f84d0275SMark Salter #include <asm/efi.h> 645882bfefSStefano Stabellini #include <asm/xen/hypervisor.h> 659703d9d7SCatalin Marinas 669703d9d7SCatalin Marinas phys_addr_t __fdt_pointer __initdata; 679703d9d7SCatalin Marinas 689703d9d7SCatalin Marinas /* 699703d9d7SCatalin Marinas * Standard memory resources 709703d9d7SCatalin Marinas */ 719703d9d7SCatalin Marinas static struct resource mem_res[] = { 729703d9d7SCatalin Marinas { 739703d9d7SCatalin Marinas .name = "Kernel code", 749703d9d7SCatalin Marinas .start = 0, 759703d9d7SCatalin Marinas .end = 0, 76*35d98e93SToshi Kani .flags = IORESOURCE_SYSTEM_RAM 779703d9d7SCatalin Marinas }, 789703d9d7SCatalin Marinas { 799703d9d7SCatalin Marinas .name = "Kernel data", 809703d9d7SCatalin Marinas .start = 0, 819703d9d7SCatalin Marinas .end = 0, 82*35d98e93SToshi Kani .flags = IORESOURCE_SYSTEM_RAM 839703d9d7SCatalin Marinas } 849703d9d7SCatalin Marinas }; 859703d9d7SCatalin Marinas 869703d9d7SCatalin Marinas #define kernel_code mem_res[0] 879703d9d7SCatalin Marinas #define kernel_data mem_res[1] 889703d9d7SCatalin Marinas 89da9c177dSArd Biesheuvel /* 90da9c177dSArd Biesheuvel * The recorded values of x0 .. x3 upon kernel entry. 91da9c177dSArd Biesheuvel */ 92da9c177dSArd Biesheuvel u64 __cacheline_aligned boot_args[4]; 93da9c177dSArd Biesheuvel 9471586276SWill Deacon void __init smp_setup_processor_id(void) 9571586276SWill Deacon { 9680708677SMark Rutland u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; 9780708677SMark Rutland cpu_logical_map(0) = mpidr; 9880708677SMark Rutland 9971586276SWill Deacon /* 10071586276SWill Deacon * clear __my_cpu_offset on boot CPU to avoid hang caused by 10171586276SWill Deacon * using percpu variable early, for example, lockdep will 10271586276SWill Deacon * access percpu variable inside lock_release 10371586276SWill Deacon */ 10471586276SWill Deacon set_my_cpu_offset(0); 10580708677SMark Rutland pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr); 10671586276SWill Deacon } 10771586276SWill Deacon 1086e15d0e0SSudeep KarkadaNagesha bool arch_match_cpu_phys_id(int cpu, u64 phys_id) 1096e15d0e0SSudeep KarkadaNagesha { 1106e15d0e0SSudeep KarkadaNagesha return phys_id == cpu_logical_map(cpu); 1116e15d0e0SSudeep KarkadaNagesha } 1126e15d0e0SSudeep KarkadaNagesha 113976d7d3fSLorenzo Pieralisi struct mpidr_hash mpidr_hash; 114976d7d3fSLorenzo Pieralisi /** 115976d7d3fSLorenzo Pieralisi * smp_build_mpidr_hash - Pre-compute shifts required at each affinity 116976d7d3fSLorenzo Pieralisi * level in order to build a linear index from an 117976d7d3fSLorenzo Pieralisi * MPIDR value. Resulting algorithm is a collision 118976d7d3fSLorenzo Pieralisi * free hash carried out through shifting and ORing 119976d7d3fSLorenzo Pieralisi */ 120976d7d3fSLorenzo Pieralisi static void __init smp_build_mpidr_hash(void) 121976d7d3fSLorenzo Pieralisi { 122976d7d3fSLorenzo Pieralisi u32 i, affinity, fs[4], bits[4], ls; 123976d7d3fSLorenzo Pieralisi u64 mask = 0; 124976d7d3fSLorenzo Pieralisi /* 125976d7d3fSLorenzo Pieralisi * Pre-scan the list of MPIDRS and filter out bits that do 126976d7d3fSLorenzo Pieralisi * not contribute to affinity levels, ie they never toggle. 127976d7d3fSLorenzo Pieralisi */ 128976d7d3fSLorenzo Pieralisi for_each_possible_cpu(i) 129976d7d3fSLorenzo Pieralisi mask |= (cpu_logical_map(i) ^ cpu_logical_map(0)); 130976d7d3fSLorenzo Pieralisi pr_debug("mask of set bits %#llx\n", mask); 131976d7d3fSLorenzo Pieralisi /* 132976d7d3fSLorenzo Pieralisi * Find and stash the last and first bit set at all affinity levels to 133976d7d3fSLorenzo Pieralisi * check how many bits are required to represent them. 134976d7d3fSLorenzo Pieralisi */ 135976d7d3fSLorenzo Pieralisi for (i = 0; i < 4; i++) { 136976d7d3fSLorenzo Pieralisi affinity = MPIDR_AFFINITY_LEVEL(mask, i); 137976d7d3fSLorenzo Pieralisi /* 138976d7d3fSLorenzo Pieralisi * Find the MSB bit and LSB bits position 139976d7d3fSLorenzo Pieralisi * to determine how many bits are required 140976d7d3fSLorenzo Pieralisi * to express the affinity level. 141976d7d3fSLorenzo Pieralisi */ 142976d7d3fSLorenzo Pieralisi ls = fls(affinity); 143976d7d3fSLorenzo Pieralisi fs[i] = affinity ? ffs(affinity) - 1 : 0; 144976d7d3fSLorenzo Pieralisi bits[i] = ls - fs[i]; 145976d7d3fSLorenzo Pieralisi } 146976d7d3fSLorenzo Pieralisi /* 147976d7d3fSLorenzo Pieralisi * An index can be created from the MPIDR_EL1 by isolating the 148976d7d3fSLorenzo Pieralisi * significant bits at each affinity level and by shifting 149976d7d3fSLorenzo Pieralisi * them in order to compress the 32 bits values space to a 150976d7d3fSLorenzo Pieralisi * compressed set of values. This is equivalent to hashing 151976d7d3fSLorenzo Pieralisi * the MPIDR_EL1 through shifting and ORing. It is a collision free 152976d7d3fSLorenzo Pieralisi * hash though not minimal since some levels might contain a number 153976d7d3fSLorenzo Pieralisi * of CPUs that is not an exact power of 2 and their bit 154976d7d3fSLorenzo Pieralisi * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}. 155976d7d3fSLorenzo Pieralisi */ 156976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0]; 157976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0]; 158976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] - 159976d7d3fSLorenzo Pieralisi (bits[1] + bits[0]); 160976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) + 161976d7d3fSLorenzo Pieralisi fs[3] - (bits[2] + bits[1] + bits[0]); 162976d7d3fSLorenzo Pieralisi mpidr_hash.mask = mask; 163976d7d3fSLorenzo Pieralisi mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0]; 164976d7d3fSLorenzo Pieralisi pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n", 165976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[0], 166976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[1], 167976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[2], 168976d7d3fSLorenzo Pieralisi mpidr_hash.shift_aff[3], 169976d7d3fSLorenzo Pieralisi mpidr_hash.mask, 170976d7d3fSLorenzo Pieralisi mpidr_hash.bits); 171976d7d3fSLorenzo Pieralisi /* 172976d7d3fSLorenzo Pieralisi * 4x is an arbitrary value used to warn on a hash table much bigger 173976d7d3fSLorenzo Pieralisi * than expected on most systems. 174976d7d3fSLorenzo Pieralisi */ 175976d7d3fSLorenzo Pieralisi if (mpidr_hash_size() > 4 * num_possible_cpus()) 176976d7d3fSLorenzo Pieralisi pr_warn("Large number of MPIDR hash buckets detected\n"); 177976d7d3fSLorenzo Pieralisi __flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash)); 178976d7d3fSLorenzo Pieralisi } 179137650aaSMark Rutland 1809703d9d7SCatalin Marinas static void __init setup_machine_fdt(phys_addr_t dt_phys) 1819703d9d7SCatalin Marinas { 18261bd93ceSArd Biesheuvel void *dt_virt = fixmap_remap_fdt(dt_phys); 18361bd93ceSArd Biesheuvel 18461bd93ceSArd Biesheuvel if (!dt_virt || !early_init_dt_scan(dt_virt)) { 18561bd93ceSArd Biesheuvel pr_crit("\n" 18661bd93ceSArd Biesheuvel "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n" 18761bd93ceSArd Biesheuvel "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" 18861bd93ceSArd Biesheuvel "\nPlease check your bootloader.", 18961bd93ceSArd Biesheuvel &dt_phys, dt_virt); 1909703d9d7SCatalin Marinas 1919703d9d7SCatalin Marinas while (true) 1929703d9d7SCatalin Marinas cpu_relax(); 1939703d9d7SCatalin Marinas } 1945e39977eSWill Deacon 19544b82b77SMark Rutland dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name()); 1969703d9d7SCatalin Marinas } 1979703d9d7SCatalin Marinas 1989703d9d7SCatalin Marinas static void __init request_standard_resources(void) 1999703d9d7SCatalin Marinas { 2009703d9d7SCatalin Marinas struct memblock_region *region; 2019703d9d7SCatalin Marinas struct resource *res; 2029703d9d7SCatalin Marinas 2039703d9d7SCatalin Marinas kernel_code.start = virt_to_phys(_text); 2049703d9d7SCatalin Marinas kernel_code.end = virt_to_phys(_etext - 1); 2059703d9d7SCatalin Marinas kernel_data.start = virt_to_phys(_sdata); 2069703d9d7SCatalin Marinas kernel_data.end = virt_to_phys(_end - 1); 2079703d9d7SCatalin Marinas 2089703d9d7SCatalin Marinas for_each_memblock(memory, region) { 2099703d9d7SCatalin Marinas res = alloc_bootmem_low(sizeof(*res)); 2109703d9d7SCatalin Marinas res->name = "System RAM"; 2119703d9d7SCatalin Marinas res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 2129703d9d7SCatalin Marinas res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 213*35d98e93SToshi Kani res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 2149703d9d7SCatalin Marinas 2159703d9d7SCatalin Marinas request_resource(&iomem_resource, res); 2169703d9d7SCatalin Marinas 2179703d9d7SCatalin Marinas if (kernel_code.start >= res->start && 2189703d9d7SCatalin Marinas kernel_code.end <= res->end) 2199703d9d7SCatalin Marinas request_resource(res, &kernel_code); 2209703d9d7SCatalin Marinas if (kernel_data.start >= res->start && 2219703d9d7SCatalin Marinas kernel_data.end <= res->end) 2229703d9d7SCatalin Marinas request_resource(res, &kernel_data); 2239703d9d7SCatalin Marinas } 2249703d9d7SCatalin Marinas } 2259703d9d7SCatalin Marinas 2261570f0d7SMark Salter #ifdef CONFIG_BLK_DEV_INITRD 2271570f0d7SMark Salter /* 2281570f0d7SMark Salter * Relocate initrd if it is not completely within the linear mapping. 2291570f0d7SMark Salter * This would be the case if mem= cuts out all or part of it. 2301570f0d7SMark Salter */ 2311570f0d7SMark Salter static void __init relocate_initrd(void) 2321570f0d7SMark Salter { 2331570f0d7SMark Salter phys_addr_t orig_start = __virt_to_phys(initrd_start); 2341570f0d7SMark Salter phys_addr_t orig_end = __virt_to_phys(initrd_end); 2351570f0d7SMark Salter phys_addr_t ram_end = memblock_end_of_DRAM(); 2361570f0d7SMark Salter phys_addr_t new_start; 2371570f0d7SMark Salter unsigned long size, to_free = 0; 2381570f0d7SMark Salter void *dest; 2391570f0d7SMark Salter 2401570f0d7SMark Salter if (orig_end <= ram_end) 2411570f0d7SMark Salter return; 2421570f0d7SMark Salter 2431570f0d7SMark Salter /* 2441570f0d7SMark Salter * Any of the original initrd which overlaps the linear map should 2451570f0d7SMark Salter * be freed after relocating. 2461570f0d7SMark Salter */ 2471570f0d7SMark Salter if (orig_start < ram_end) 2481570f0d7SMark Salter to_free = ram_end - orig_start; 2491570f0d7SMark Salter 2501570f0d7SMark Salter size = orig_end - orig_start; 2514ca3bc86SMark Rutland if (!size) 2524ca3bc86SMark Rutland return; 2531570f0d7SMark Salter 2541570f0d7SMark Salter /* initrd needs to be relocated completely inside linear mapping */ 2551570f0d7SMark Salter new_start = memblock_find_in_range(0, PFN_PHYS(max_pfn), 2561570f0d7SMark Salter size, PAGE_SIZE); 2571570f0d7SMark Salter if (!new_start) 2581570f0d7SMark Salter panic("Cannot relocate initrd of size %ld\n", size); 2591570f0d7SMark Salter memblock_reserve(new_start, size); 2601570f0d7SMark Salter 2611570f0d7SMark Salter initrd_start = __phys_to_virt(new_start); 2621570f0d7SMark Salter initrd_end = initrd_start + size; 2631570f0d7SMark Salter 2641570f0d7SMark Salter pr_info("Moving initrd from [%llx-%llx] to [%llx-%llx]\n", 2651570f0d7SMark Salter orig_start, orig_start + size - 1, 2661570f0d7SMark Salter new_start, new_start + size - 1); 2671570f0d7SMark Salter 2681570f0d7SMark Salter dest = (void *)initrd_start; 2691570f0d7SMark Salter 2701570f0d7SMark Salter if (to_free) { 2711570f0d7SMark Salter memcpy(dest, (void *)__phys_to_virt(orig_start), to_free); 2721570f0d7SMark Salter dest += to_free; 2731570f0d7SMark Salter } 2741570f0d7SMark Salter 2751570f0d7SMark Salter copy_from_early_mem(dest, orig_start + to_free, size - to_free); 2761570f0d7SMark Salter 2771570f0d7SMark Salter if (to_free) { 2781570f0d7SMark Salter pr_info("Freeing original RAMDISK from [%llx-%llx]\n", 2791570f0d7SMark Salter orig_start, orig_start + to_free - 1); 2801570f0d7SMark Salter memblock_free(orig_start, to_free); 2811570f0d7SMark Salter } 2821570f0d7SMark Salter } 2831570f0d7SMark Salter #else 2841570f0d7SMark Salter static inline void __init relocate_initrd(void) 2851570f0d7SMark Salter { 2861570f0d7SMark Salter } 2871570f0d7SMark Salter #endif 2881570f0d7SMark Salter 2894c7aa002SJavi Merino u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID }; 2904c7aa002SJavi Merino 2919703d9d7SCatalin Marinas void __init setup_arch(char **cmdline_p) 2929703d9d7SCatalin Marinas { 2934b998ff1SSuzuki K. Poulose pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id()); 2949703d9d7SCatalin Marinas 2954b998ff1SSuzuki K. Poulose sprintf(init_utsname()->machine, ELF_PLATFORM); 2969703d9d7SCatalin Marinas init_mm.start_code = (unsigned long) _text; 2979703d9d7SCatalin Marinas init_mm.end_code = (unsigned long) _etext; 2989703d9d7SCatalin Marinas init_mm.end_data = (unsigned long) _edata; 2999703d9d7SCatalin Marinas init_mm.brk = (unsigned long) _end; 3009703d9d7SCatalin Marinas 3019703d9d7SCatalin Marinas *cmdline_p = boot_command_line; 3029703d9d7SCatalin Marinas 303af86e597SLaura Abbott early_fixmap_init(); 304bf4b558eSMark Salter early_ioremap_init(); 3050bf757c7SMark Salter 30661bd93ceSArd Biesheuvel setup_machine_fdt(__fdt_pointer); 30761bd93ceSArd Biesheuvel 3089703d9d7SCatalin Marinas parse_early_param(); 3099703d9d7SCatalin Marinas 3107a9c43beSJon Masters /* 3117a9c43beSJon Masters * Unmask asynchronous aborts after bringing up possible earlycon. 3127a9c43beSJon Masters * (Report possible System Errors once we can report this occurred) 3137a9c43beSJon Masters */ 3147a9c43beSJon Masters local_async_enable(); 3157a9c43beSJon Masters 316f84d0275SMark Salter efi_init(); 3179703d9d7SCatalin Marinas arm64_memblock_init(); 3189703d9d7SCatalin Marinas 31937655163SAl Stone /* Parse the ACPI tables for possible boot-time configuration */ 32037655163SAl Stone acpi_boot_table_init(); 32137655163SAl Stone 3229703d9d7SCatalin Marinas paging_init(); 3231570f0d7SMark Salter relocate_initrd(); 32439d114ddSAndrey Ryabinin 32539d114ddSAndrey Ryabinin kasan_init(); 32639d114ddSAndrey Ryabinin 3279703d9d7SCatalin Marinas request_standard_resources(); 3289703d9d7SCatalin Marinas 3290e63ea48SArd Biesheuvel early_ioremap_reset(); 330f84d0275SMark Salter 331fb094eb1SLorenzo Pieralisi if (acpi_disabled) { 3329703d9d7SCatalin Marinas unflatten_device_tree(); 3337c59a3dfSGraeme Gregory psci_dt_init(); 334fccb9a81SHanjun Guo } else { 335fccb9a81SHanjun Guo psci_acpi_init(); 336fccb9a81SHanjun Guo } 3375882bfefSStefano Stabellini xen_early_init(); 338fccb9a81SHanjun Guo 3390f078336SLorenzo Pieralisi cpu_read_bootcpu_ops(); 3400f078336SLorenzo Pieralisi smp_init_cpus(); 341976d7d3fSLorenzo Pieralisi smp_build_mpidr_hash(); 3429703d9d7SCatalin Marinas 3439703d9d7SCatalin Marinas #ifdef CONFIG_VT 3449703d9d7SCatalin Marinas #if defined(CONFIG_VGA_CONSOLE) 3459703d9d7SCatalin Marinas conswitchp = &vga_con; 3469703d9d7SCatalin Marinas #elif defined(CONFIG_DUMMY_CONSOLE) 3479703d9d7SCatalin Marinas conswitchp = &dummy_con; 3489703d9d7SCatalin Marinas #endif 3499703d9d7SCatalin Marinas #endif 350da9c177dSArd Biesheuvel if (boot_args[1] || boot_args[2] || boot_args[3]) { 351da9c177dSArd Biesheuvel pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n" 352da9c177dSArd Biesheuvel "\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n" 353da9c177dSArd Biesheuvel "This indicates a broken bootloader or old kernel\n", 354da9c177dSArd Biesheuvel boot_args[1], boot_args[2], boot_args[3]); 355da9c177dSArd Biesheuvel } 3569703d9d7SCatalin Marinas } 3579703d9d7SCatalin Marinas 358c560ecfeSCatalin Marinas static int __init arm64_device_init(void) 359de79a64dSCatalin Marinas { 360e094d445SSudeep Holla if (of_have_populated_dt()) { 36178d51e0bSRobin Murphy of_iommu_init(); 362e094d445SSudeep Holla of_platform_populate(NULL, of_default_bus_match_table, 363e094d445SSudeep Holla NULL, NULL); 364e094d445SSudeep Holla } else if (acpi_disabled) { 365e094d445SSudeep Holla pr_crit("Device tree not populated\n"); 366e094d445SSudeep Holla } 367de79a64dSCatalin Marinas return 0; 368de79a64dSCatalin Marinas } 3696ecba8ebSCatalin Marinas arch_initcall_sync(arm64_device_init); 370de79a64dSCatalin Marinas 3719703d9d7SCatalin Marinas static int __init topology_init(void) 3729703d9d7SCatalin Marinas { 3739703d9d7SCatalin Marinas int i; 3749703d9d7SCatalin Marinas 3759703d9d7SCatalin Marinas for_each_possible_cpu(i) { 376df857416SMark Rutland struct cpu *cpu = &per_cpu(cpu_data.cpu, i); 3779703d9d7SCatalin Marinas cpu->hotpluggable = 1; 3789703d9d7SCatalin Marinas register_cpu(cpu, i); 3799703d9d7SCatalin Marinas } 3809703d9d7SCatalin Marinas 3819703d9d7SCatalin Marinas return 0; 3829703d9d7SCatalin Marinas } 3839703d9d7SCatalin Marinas subsys_initcall(topology_init); 384