18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Common boot and setup code for both 32-bit and 64-bit. 48c2ecf20Sopenharmony_ci * Extracted from arch/powerpc/kernel/setup_64.c. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 PPC64 Team, IBM Corp 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#undef DEBUG 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/export.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/sched.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/reboot.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/initrd.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 218c2ecf20Sopenharmony_ci#include <linux/ioport.h> 228c2ecf20Sopenharmony_ci#include <linux/console.h> 238c2ecf20Sopenharmony_ci#include <linux/screen_info.h> 248c2ecf20Sopenharmony_ci#include <linux/root_dev.h> 258c2ecf20Sopenharmony_ci#include <linux/notifier.h> 268c2ecf20Sopenharmony_ci#include <linux/cpu.h> 278c2ecf20Sopenharmony_ci#include <linux/unistd.h> 288c2ecf20Sopenharmony_ci#include <linux/serial.h> 298c2ecf20Sopenharmony_ci#include <linux/serial_8250.h> 308c2ecf20Sopenharmony_ci#include <linux/percpu.h> 318c2ecf20Sopenharmony_ci#include <linux/memblock.h> 328c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 338c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 348c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 358c2ecf20Sopenharmony_ci#include <asm/debugfs.h> 368c2ecf20Sopenharmony_ci#include <asm/io.h> 378c2ecf20Sopenharmony_ci#include <asm/paca.h> 388c2ecf20Sopenharmony_ci#include <asm/prom.h> 398c2ecf20Sopenharmony_ci#include <asm/processor.h> 408c2ecf20Sopenharmony_ci#include <asm/vdso_datapage.h> 418c2ecf20Sopenharmony_ci#include <asm/smp.h> 428c2ecf20Sopenharmony_ci#include <asm/elf.h> 438c2ecf20Sopenharmony_ci#include <asm/machdep.h> 448c2ecf20Sopenharmony_ci#include <asm/time.h> 458c2ecf20Sopenharmony_ci#include <asm/cputable.h> 468c2ecf20Sopenharmony_ci#include <asm/sections.h> 478c2ecf20Sopenharmony_ci#include <asm/firmware.h> 488c2ecf20Sopenharmony_ci#include <asm/btext.h> 498c2ecf20Sopenharmony_ci#include <asm/nvram.h> 508c2ecf20Sopenharmony_ci#include <asm/setup.h> 518c2ecf20Sopenharmony_ci#include <asm/rtas.h> 528c2ecf20Sopenharmony_ci#include <asm/iommu.h> 538c2ecf20Sopenharmony_ci#include <asm/serial.h> 548c2ecf20Sopenharmony_ci#include <asm/cache.h> 558c2ecf20Sopenharmony_ci#include <asm/page.h> 568c2ecf20Sopenharmony_ci#include <asm/mmu.h> 578c2ecf20Sopenharmony_ci#include <asm/xmon.h> 588c2ecf20Sopenharmony_ci#include <asm/cputhreads.h> 598c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h> 608c2ecf20Sopenharmony_ci#include <asm/fadump.h> 618c2ecf20Sopenharmony_ci#include <asm/udbg.h> 628c2ecf20Sopenharmony_ci#include <asm/hugetlb.h> 638c2ecf20Sopenharmony_ci#include <asm/livepatch.h> 648c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 658c2ecf20Sopenharmony_ci#include <asm/cpu_has_feature.h> 668c2ecf20Sopenharmony_ci#include <asm/kasan.h> 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#include "setup.h" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#ifdef DEBUG 718c2ecf20Sopenharmony_ci#include <asm/udbg.h> 728c2ecf20Sopenharmony_ci#define DBG(fmt...) udbg_printf(fmt) 738c2ecf20Sopenharmony_ci#else 748c2ecf20Sopenharmony_ci#define DBG(fmt...) 758c2ecf20Sopenharmony_ci#endif 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* The main machine-dep calls structure 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistruct machdep_calls ppc_md; 808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ppc_md); 818c2ecf20Sopenharmony_cistruct machdep_calls *machine_id; 828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(machine_id); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint boot_cpuid = -1; 858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(boot_cpuid); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * These are used in binfmt_elf.c to put aux entries on the stack 898c2ecf20Sopenharmony_ci * for each elf executable being started. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ciint dcache_bsize; 928c2ecf20Sopenharmony_ciint icache_bsize; 938c2ecf20Sopenharmony_ciint ucache_bsize; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciunsigned long klimit = (unsigned long) _end; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * This still seems to be needed... -- paulus 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistruct screen_info screen_info = { 1028c2ecf20Sopenharmony_ci .orig_x = 0, 1038c2ecf20Sopenharmony_ci .orig_y = 25, 1048c2ecf20Sopenharmony_ci .orig_video_cols = 80, 1058c2ecf20Sopenharmony_ci .orig_video_lines = 25, 1068c2ecf20Sopenharmony_ci .orig_video_isVGA = 1, 1078c2ecf20Sopenharmony_ci .orig_video_points = 16 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_VGA16_MODULE) 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(screen_info); 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Variables required to store legacy IO irq routing */ 1148c2ecf20Sopenharmony_ciint of_i8042_kbd_irq; 1158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_i8042_kbd_irq); 1168c2ecf20Sopenharmony_ciint of_i8042_aux_irq; 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_i8042_aux_irq); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#ifdef __DO_IRQ_CANON 1208c2ecf20Sopenharmony_ci/* XXX should go elsewhere eventually */ 1218c2ecf20Sopenharmony_ciint ppc_do_canonicalize_irqs; 1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ppc_do_canonicalize_irqs); 1238c2ecf20Sopenharmony_ci#endif 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#ifdef CONFIG_CRASH_CORE 1268c2ecf20Sopenharmony_ci/* This keeps a track of which one is the crashing cpu. */ 1278c2ecf20Sopenharmony_ciint crashing_cpu = -1; 1288c2ecf20Sopenharmony_ci#endif 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* also used by kexec */ 1318c2ecf20Sopenharmony_civoid machine_shutdown(void) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * if fadump is active, cleanup the fadump registration before we 1358c2ecf20Sopenharmony_ci * shutdown. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci fadump_cleanup(); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (ppc_md.machine_shutdown) 1408c2ecf20Sopenharmony_ci ppc_md.machine_shutdown(); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void machine_hang(void) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci pr_emerg("System Halted, OK to turn off power\n"); 1468c2ecf20Sopenharmony_ci local_irq_disable(); 1478c2ecf20Sopenharmony_ci while (1) 1488c2ecf20Sopenharmony_ci ; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_civoid machine_restart(char *cmd) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci machine_shutdown(); 1548c2ecf20Sopenharmony_ci if (ppc_md.restart) 1558c2ecf20Sopenharmony_ci ppc_md.restart(cmd); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci smp_send_stop(); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci do_kernel_restart(cmd); 1608c2ecf20Sopenharmony_ci mdelay(1000); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci machine_hang(); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_civoid machine_power_off(void) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci machine_shutdown(); 1688c2ecf20Sopenharmony_ci if (pm_power_off) 1698c2ecf20Sopenharmony_ci pm_power_off(); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci smp_send_stop(); 1728c2ecf20Sopenharmony_ci machine_hang(); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci/* Used by the G5 thermal driver */ 1758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(machine_power_off); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_civoid (*pm_power_off)(void); 1788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_power_off); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_civoid machine_halt(void) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci machine_shutdown(); 1838c2ecf20Sopenharmony_ci if (ppc_md.halt) 1848c2ecf20Sopenharmony_ci ppc_md.halt(); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci smp_send_stop(); 1878c2ecf20Sopenharmony_ci machine_hang(); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 1918c2ecf20Sopenharmony_ciDEFINE_PER_CPU(unsigned int, cpu_pvr); 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic void show_cpuinfo_summary(struct seq_file *m) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct device_node *root; 1978c2ecf20Sopenharmony_ci const char *model = NULL; 1988c2ecf20Sopenharmony_ci unsigned long bogosum = 0; 1998c2ecf20Sopenharmony_ci int i; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SMP) && IS_ENABLED(CONFIG_PPC32)) { 2028c2ecf20Sopenharmony_ci for_each_online_cpu(i) 2038c2ecf20Sopenharmony_ci bogosum += loops_per_jiffy; 2048c2ecf20Sopenharmony_ci seq_printf(m, "total bogomips\t: %lu.%02lu\n", 2058c2ecf20Sopenharmony_ci bogosum / (500000 / HZ), bogosum / (5000 / HZ) % 100); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); 2088c2ecf20Sopenharmony_ci if (ppc_md.name) 2098c2ecf20Sopenharmony_ci seq_printf(m, "platform\t: %s\n", ppc_md.name); 2108c2ecf20Sopenharmony_ci root = of_find_node_by_path("/"); 2118c2ecf20Sopenharmony_ci if (root) 2128c2ecf20Sopenharmony_ci model = of_get_property(root, "model", NULL); 2138c2ecf20Sopenharmony_ci if (model) 2148c2ecf20Sopenharmony_ci seq_printf(m, "model\t\t: %s\n", model); 2158c2ecf20Sopenharmony_ci of_node_put(root); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (ppc_md.show_cpuinfo != NULL) 2188c2ecf20Sopenharmony_ci ppc_md.show_cpuinfo(m); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Display the amount of memory */ 2218c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC32)) 2228c2ecf20Sopenharmony_ci seq_printf(m, "Memory\t\t: %d MB\n", 2238c2ecf20Sopenharmony_ci (unsigned int)(total_memory / (1024 * 1024))); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int show_cpuinfo(struct seq_file *m, void *v) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci unsigned long cpu_id = (unsigned long)v - 1; 2298c2ecf20Sopenharmony_ci unsigned int pvr; 2308c2ecf20Sopenharmony_ci unsigned long proc_freq; 2318c2ecf20Sopenharmony_ci unsigned short maj; 2328c2ecf20Sopenharmony_ci unsigned short min; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 2358c2ecf20Sopenharmony_ci pvr = per_cpu(cpu_pvr, cpu_id); 2368c2ecf20Sopenharmony_ci#else 2378c2ecf20Sopenharmony_ci pvr = mfspr(SPRN_PVR); 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci maj = (pvr >> 8) & 0xFF; 2408c2ecf20Sopenharmony_ci min = pvr & 0xFF; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci seq_printf(m, "processor\t: %lu\n", cpu_id); 2438c2ecf20Sopenharmony_ci seq_printf(m, "cpu\t\t: "); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (cur_cpu_spec->pvr_mask && cur_cpu_spec->cpu_name) 2468c2ecf20Sopenharmony_ci seq_printf(m, "%s", cur_cpu_spec->cpu_name); 2478c2ecf20Sopenharmony_ci else 2488c2ecf20Sopenharmony_ci seq_printf(m, "unknown (%08x)", pvr); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ALTIVEC)) 2518c2ecf20Sopenharmony_ci seq_printf(m, ", altivec supported"); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci seq_printf(m, "\n"); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci#ifdef CONFIG_TAU 2568c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_TAU)) { 2578c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_TAU_AVERAGE)) { 2588c2ecf20Sopenharmony_ci /* more straightforward, but potentially misleading */ 2598c2ecf20Sopenharmony_ci seq_printf(m, "temperature \t: %u C (uncalibrated)\n", 2608c2ecf20Sopenharmony_ci cpu_temp(cpu_id)); 2618c2ecf20Sopenharmony_ci } else { 2628c2ecf20Sopenharmony_ci /* show the actual temp sensor range */ 2638c2ecf20Sopenharmony_ci u32 temp; 2648c2ecf20Sopenharmony_ci temp = cpu_temp_both(cpu_id); 2658c2ecf20Sopenharmony_ci seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", 2668c2ecf20Sopenharmony_ci temp & 0xff, temp >> 16); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci#endif /* CONFIG_TAU */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * Platforms that have variable clock rates, should implement 2738c2ecf20Sopenharmony_ci * the method ppc_md.get_proc_freq() that reports the clock 2748c2ecf20Sopenharmony_ci * rate of a given cpu. The rest can use ppc_proc_freq to 2758c2ecf20Sopenharmony_ci * report the clock rate that is same across all cpus. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (ppc_md.get_proc_freq) 2788c2ecf20Sopenharmony_ci proc_freq = ppc_md.get_proc_freq(cpu_id); 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci proc_freq = ppc_proc_freq; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (proc_freq) 2838c2ecf20Sopenharmony_ci seq_printf(m, "clock\t\t: %lu.%06luMHz\n", 2848c2ecf20Sopenharmony_ci proc_freq / 1000000, proc_freq % 1000000); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (ppc_md.show_percpuinfo != NULL) 2878c2ecf20Sopenharmony_ci ppc_md.show_percpuinfo(m, cpu_id); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* If we are a Freescale core do a simple check so 2908c2ecf20Sopenharmony_ci * we dont have to keep adding cases in the future */ 2918c2ecf20Sopenharmony_ci if (PVR_VER(pvr) & 0x8000) { 2928c2ecf20Sopenharmony_ci switch (PVR_VER(pvr)) { 2938c2ecf20Sopenharmony_ci case 0x8000: /* 7441/7450/7451, Voyager */ 2948c2ecf20Sopenharmony_ci case 0x8001: /* 7445/7455, Apollo 6 */ 2958c2ecf20Sopenharmony_ci case 0x8002: /* 7447/7457, Apollo 7 */ 2968c2ecf20Sopenharmony_ci case 0x8003: /* 7447A, Apollo 7 PM */ 2978c2ecf20Sopenharmony_ci case 0x8004: /* 7448, Apollo 8 */ 2988c2ecf20Sopenharmony_ci case 0x800c: /* 7410, Nitro */ 2998c2ecf20Sopenharmony_ci maj = ((pvr >> 8) & 0xF); 3008c2ecf20Sopenharmony_ci min = PVR_MIN(pvr); 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci default: /* e500/book-e */ 3038c2ecf20Sopenharmony_ci maj = PVR_MAJ(pvr); 3048c2ecf20Sopenharmony_ci min = PVR_MIN(pvr); 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } else { 3088c2ecf20Sopenharmony_ci switch (PVR_VER(pvr)) { 3098c2ecf20Sopenharmony_ci case 0x1008: /* 740P/750P ?? */ 3108c2ecf20Sopenharmony_ci maj = ((pvr >> 8) & 0xFF) - 1; 3118c2ecf20Sopenharmony_ci min = pvr & 0xFF; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case 0x004e: /* POWER9 bits 12-15 give chip type */ 3148c2ecf20Sopenharmony_ci case 0x0080: /* POWER10 bit 12 gives SMT8/4 */ 3158c2ecf20Sopenharmony_ci maj = (pvr >> 8) & 0x0F; 3168c2ecf20Sopenharmony_ci min = pvr & 0xFF; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci default: 3198c2ecf20Sopenharmony_ci maj = (pvr >> 8) & 0xFF; 3208c2ecf20Sopenharmony_ci min = pvr & 0xFF; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", 3268c2ecf20Sopenharmony_ci maj, min, PVR_VER(pvr), PVR_REV(pvr)); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC32)) 3298c2ecf20Sopenharmony_ci seq_printf(m, "bogomips\t: %lu.%02lu\n", loops_per_jiffy / (500000 / HZ), 3308c2ecf20Sopenharmony_ci (loops_per_jiffy / (5000 / HZ)) % 100); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci seq_printf(m, "\n"); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* If this is the last cpu, print the summary */ 3358c2ecf20Sopenharmony_ci if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids) 3368c2ecf20Sopenharmony_ci show_cpuinfo_summary(m); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void *c_start(struct seq_file *m, loff_t *pos) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci if (*pos == 0) /* just in case, cpu 0 is not the first */ 3448c2ecf20Sopenharmony_ci *pos = cpumask_first(cpu_online_mask); 3458c2ecf20Sopenharmony_ci else 3468c2ecf20Sopenharmony_ci *pos = cpumask_next(*pos - 1, cpu_online_mask); 3478c2ecf20Sopenharmony_ci if ((*pos) < nr_cpu_ids) 3488c2ecf20Sopenharmony_ci return (void *)(unsigned long)(*pos + 1); 3498c2ecf20Sopenharmony_ci return NULL; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void *c_next(struct seq_file *m, void *v, loff_t *pos) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci (*pos)++; 3558c2ecf20Sopenharmony_ci return c_start(m, pos); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void c_stop(struct seq_file *m, void *v) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ciconst struct seq_operations cpuinfo_op = { 3638c2ecf20Sopenharmony_ci .start = c_start, 3648c2ecf20Sopenharmony_ci .next = c_next, 3658c2ecf20Sopenharmony_ci .stop = c_stop, 3668c2ecf20Sopenharmony_ci .show = show_cpuinfo, 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid __init check_for_initrd(void) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_INITRD 3728c2ecf20Sopenharmony_ci DBG(" -> check_for_initrd() initrd_start=0x%lx initrd_end=0x%lx\n", 3738c2ecf20Sopenharmony_ci initrd_start, initrd_end); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* If we were passed an initrd, set the ROOT_DEV properly if the values 3768c2ecf20Sopenharmony_ci * look sensible. If not, clear initrd reference. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) && 3798c2ecf20Sopenharmony_ci initrd_end > initrd_start) 3808c2ecf20Sopenharmony_ci ROOT_DEV = Root_RAM0; 3818c2ecf20Sopenharmony_ci else 3828c2ecf20Sopenharmony_ci initrd_start = initrd_end = 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (initrd_start) 3858c2ecf20Sopenharmony_ci pr_info("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci DBG(" <- check_for_initrd()\n"); 3888c2ecf20Sopenharmony_ci#endif /* CONFIG_BLK_DEV_INITRD */ 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciint threads_per_core, threads_per_subcore, threads_shift __read_mostly; 3948c2ecf20Sopenharmony_cicpumask_t threads_core_mask __read_mostly; 3958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(threads_per_core); 3968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(threads_per_subcore); 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(threads_shift); 3988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(threads_core_mask); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void __init cpu_init_thread_core_maps(int tpc) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci int i; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci threads_per_core = tpc; 4058c2ecf20Sopenharmony_ci threads_per_subcore = tpc; 4068c2ecf20Sopenharmony_ci cpumask_clear(&threads_core_mask); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* This implementation only supports power of 2 number of threads 4098c2ecf20Sopenharmony_ci * for simplicity and performance 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci threads_shift = ilog2(tpc); 4128c2ecf20Sopenharmony_ci BUG_ON(tpc != (1 << threads_shift)); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci for (i = 0; i < tpc; i++) 4158c2ecf20Sopenharmony_ci cpumask_set_cpu(i, &threads_core_mask); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n", 4188c2ecf20Sopenharmony_ci tpc, tpc > 1 ? "s" : ""); 4198c2ecf20Sopenharmony_ci printk(KERN_DEBUG " (thread shift is %d)\n", threads_shift); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciu32 *cpu_to_phys_id = NULL; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci/** 4268c2ecf20Sopenharmony_ci * setup_cpu_maps - initialize the following cpu maps: 4278c2ecf20Sopenharmony_ci * cpu_possible_mask 4288c2ecf20Sopenharmony_ci * cpu_present_mask 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * Having the possible map set up early allows us to restrict allocations 4318c2ecf20Sopenharmony_ci * of things like irqstacks to nr_cpu_ids rather than NR_CPUS. 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * We do not initialize the online map here; cpus set their own bits in 4348c2ecf20Sopenharmony_ci * cpu_online_mask as they come up. 4358c2ecf20Sopenharmony_ci * 4368c2ecf20Sopenharmony_ci * This function is valid only for Open Firmware systems. finish_device_tree 4378c2ecf20Sopenharmony_ci * must be called before using this. 4388c2ecf20Sopenharmony_ci * 4398c2ecf20Sopenharmony_ci * While we're here, we may as well set the "physical" cpu ids in the paca. 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * NOTE: This must match the parsing done in early_init_dt_scan_cpus. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_civoid __init smp_setup_cpu_maps(void) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct device_node *dn; 4468c2ecf20Sopenharmony_ci int cpu = 0; 4478c2ecf20Sopenharmony_ci int nthreads = 1; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci DBG("smp_setup_cpu_maps()\n"); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci cpu_to_phys_id = memblock_alloc(nr_cpu_ids * sizeof(u32), 4528c2ecf20Sopenharmony_ci __alignof__(u32)); 4538c2ecf20Sopenharmony_ci if (!cpu_to_phys_id) 4548c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %zu bytes align=0x%zx\n", 4558c2ecf20Sopenharmony_ci __func__, nr_cpu_ids * sizeof(u32), __alignof__(u32)); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci for_each_node_by_type(dn, "cpu") { 4588c2ecf20Sopenharmony_ci const __be32 *intserv; 4598c2ecf20Sopenharmony_ci __be32 cpu_be; 4608c2ecf20Sopenharmony_ci int j, len; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci DBG(" * %pOF...\n", dn); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", 4658c2ecf20Sopenharmony_ci &len); 4668c2ecf20Sopenharmony_ci if (intserv) { 4678c2ecf20Sopenharmony_ci DBG(" ibm,ppc-interrupt-server#s -> %d threads\n", 4688c2ecf20Sopenharmony_ci nthreads); 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n"); 4718c2ecf20Sopenharmony_ci intserv = of_get_property(dn, "reg", &len); 4728c2ecf20Sopenharmony_ci if (!intserv) { 4738c2ecf20Sopenharmony_ci cpu_be = cpu_to_be32(cpu); 4748c2ecf20Sopenharmony_ci /* XXX: what is this? uninitialized?? */ 4758c2ecf20Sopenharmony_ci intserv = &cpu_be; /* assume logical == phys */ 4768c2ecf20Sopenharmony_ci len = 4; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci nthreads = len / sizeof(int); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { 4838c2ecf20Sopenharmony_ci bool avail; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci DBG(" thread %d -> cpu %d (hard id %d)\n", 4868c2ecf20Sopenharmony_ci j, cpu, be32_to_cpu(intserv[j])); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci avail = of_device_is_available(dn); 4898c2ecf20Sopenharmony_ci if (!avail) 4908c2ecf20Sopenharmony_ci avail = !of_property_match_string(dn, 4918c2ecf20Sopenharmony_ci "enable-method", "spin-table"); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci set_cpu_present(cpu, avail); 4948c2ecf20Sopenharmony_ci set_cpu_possible(cpu, true); 4958c2ecf20Sopenharmony_ci cpu_to_phys_id[cpu] = be32_to_cpu(intserv[j]); 4968c2ecf20Sopenharmony_ci cpu++; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (cpu >= nr_cpu_ids) { 5008c2ecf20Sopenharmony_ci of_node_put(dn); 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* If no SMT supported, nthreads is forced to 1 */ 5068c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_SMT)) { 5078c2ecf20Sopenharmony_ci DBG(" SMT disabled ! nthreads forced to 1\n"); 5088c2ecf20Sopenharmony_ci nthreads = 1; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 5128c2ecf20Sopenharmony_ci /* 5138c2ecf20Sopenharmony_ci * On pSeries LPAR, we need to know how many cpus 5148c2ecf20Sopenharmony_ci * could possibly be added to this partition. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci if (firmware_has_feature(FW_FEATURE_LPAR) && 5178c2ecf20Sopenharmony_ci (dn = of_find_node_by_path("/rtas"))) { 5188c2ecf20Sopenharmony_ci int num_addr_cell, num_size_cell, maxcpus; 5198c2ecf20Sopenharmony_ci const __be32 *ireg; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci num_addr_cell = of_n_addr_cells(dn); 5228c2ecf20Sopenharmony_ci num_size_cell = of_n_size_cells(dn); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci ireg = of_get_property(dn, "ibm,lrdr-capacity", NULL); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (!ireg) 5278c2ecf20Sopenharmony_ci goto out; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci maxcpus = be32_to_cpup(ireg + num_addr_cell + num_size_cell); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Double maxcpus for processors which have SMT capability */ 5328c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_SMT)) 5338c2ecf20Sopenharmony_ci maxcpus *= nthreads; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (maxcpus > nr_cpu_ids) { 5368c2ecf20Sopenharmony_ci printk(KERN_WARNING 5378c2ecf20Sopenharmony_ci "Partition configured for %d cpus, " 5388c2ecf20Sopenharmony_ci "operating system maximum is %u.\n", 5398c2ecf20Sopenharmony_ci maxcpus, nr_cpu_ids); 5408c2ecf20Sopenharmony_ci maxcpus = nr_cpu_ids; 5418c2ecf20Sopenharmony_ci } else 5428c2ecf20Sopenharmony_ci printk(KERN_INFO "Partition configured for %d cpus.\n", 5438c2ecf20Sopenharmony_ci maxcpus); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci for (cpu = 0; cpu < maxcpus; cpu++) 5468c2ecf20Sopenharmony_ci set_cpu_possible(cpu, true); 5478c2ecf20Sopenharmony_ci out: 5488c2ecf20Sopenharmony_ci of_node_put(dn); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci vdso_data->processorCount = num_present_cpus(); 5518c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Initialize CPU <=> thread mapping/ 5548c2ecf20Sopenharmony_ci * 5558c2ecf20Sopenharmony_ci * WARNING: We assume that the number of threads is the same for 5568c2ecf20Sopenharmony_ci * every CPU in the system. If that is not the case, then some code 5578c2ecf20Sopenharmony_ci * here will have to be reworked 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci cpu_init_thread_core_maps(nthreads); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Now that possible cpus are set, set nr_cpu_ids for later use */ 5628c2ecf20Sopenharmony_ci setup_nr_cpu_ids(); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci free_unused_pacas(); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */ 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci#ifdef CONFIG_PCSPKR_PLATFORM 5698c2ecf20Sopenharmony_cistatic __init int add_pcspkr(void) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct device_node *np; 5728c2ecf20Sopenharmony_ci struct platform_device *pd; 5738c2ecf20Sopenharmony_ci int ret; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "pnpPNP,100"); 5768c2ecf20Sopenharmony_ci of_node_put(np); 5778c2ecf20Sopenharmony_ci if (!np) 5788c2ecf20Sopenharmony_ci return -ENODEV; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci pd = platform_device_alloc("pcspkr", -1); 5818c2ecf20Sopenharmony_ci if (!pd) 5828c2ecf20Sopenharmony_ci return -ENOMEM; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci ret = platform_device_add(pd); 5858c2ecf20Sopenharmony_ci if (ret) 5868c2ecf20Sopenharmony_ci platform_device_put(pd); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_cidevice_initcall(add_pcspkr); 5918c2ecf20Sopenharmony_ci#endif /* CONFIG_PCSPKR_PLATFORM */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_civoid probe_machine(void) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci extern struct machdep_calls __machine_desc_start; 5968c2ecf20Sopenharmony_ci extern struct machdep_calls __machine_desc_end; 5978c2ecf20Sopenharmony_ci unsigned int i; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* 6008c2ecf20Sopenharmony_ci * Iterate all ppc_md structures until we find the proper 6018c2ecf20Sopenharmony_ci * one for the current machine type 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci DBG("Probing machine type ...\n"); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * Check ppc_md is empty, if not we have a bug, ie, we setup an 6078c2ecf20Sopenharmony_ci * entry before probe_machine() which will be overwritten 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci for (i = 0; i < (sizeof(ppc_md) / sizeof(void *)); i++) { 6108c2ecf20Sopenharmony_ci if (((void **)&ppc_md)[i]) { 6118c2ecf20Sopenharmony_ci printk(KERN_ERR "Entry %d in ppc_md non empty before" 6128c2ecf20Sopenharmony_ci " machine probe !\n", i); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci for (machine_id = &__machine_desc_start; 6178c2ecf20Sopenharmony_ci machine_id < &__machine_desc_end; 6188c2ecf20Sopenharmony_ci machine_id++) { 6198c2ecf20Sopenharmony_ci DBG(" %s ...", machine_id->name); 6208c2ecf20Sopenharmony_ci memcpy(&ppc_md, machine_id, sizeof(struct machdep_calls)); 6218c2ecf20Sopenharmony_ci if (ppc_md.probe()) { 6228c2ecf20Sopenharmony_ci DBG(" match !\n"); 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci DBG("\n"); 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci /* What can we do if we didn't find ? */ 6288c2ecf20Sopenharmony_ci if (machine_id >= &__machine_desc_end) { 6298c2ecf20Sopenharmony_ci pr_err("No suitable machine description found !\n"); 6308c2ecf20Sopenharmony_ci for (;;); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci printk(KERN_INFO "Using %s machine description\n", ppc_md.name); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/* Match a class of boards, not a specific device configuration. */ 6378c2ecf20Sopenharmony_ciint check_legacy_ioport(unsigned long base_port) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct device_node *parent, *np = NULL; 6408c2ecf20Sopenharmony_ci int ret = -ENODEV; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci switch(base_port) { 6438c2ecf20Sopenharmony_ci case I8042_DATA_REG: 6448c2ecf20Sopenharmony_ci if (!(np = of_find_compatible_node(NULL, NULL, "pnpPNP,303"))) 6458c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "pnpPNP,f03"); 6468c2ecf20Sopenharmony_ci if (np) { 6478c2ecf20Sopenharmony_ci parent = of_get_parent(np); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci of_i8042_kbd_irq = irq_of_parse_and_map(parent, 0); 6508c2ecf20Sopenharmony_ci if (!of_i8042_kbd_irq) 6518c2ecf20Sopenharmony_ci of_i8042_kbd_irq = 1; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci of_i8042_aux_irq = irq_of_parse_and_map(parent, 1); 6548c2ecf20Sopenharmony_ci if (!of_i8042_aux_irq) 6558c2ecf20Sopenharmony_ci of_i8042_aux_irq = 12; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci of_node_put(np); 6588c2ecf20Sopenharmony_ci np = parent; 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci np = of_find_node_by_type(NULL, "8042"); 6628c2ecf20Sopenharmony_ci /* Pegasos has no device_type on its 8042 node, look for the 6638c2ecf20Sopenharmony_ci * name instead */ 6648c2ecf20Sopenharmony_ci if (!np) 6658c2ecf20Sopenharmony_ci np = of_find_node_by_name(NULL, "8042"); 6668c2ecf20Sopenharmony_ci if (np) { 6678c2ecf20Sopenharmony_ci of_i8042_kbd_irq = 1; 6688c2ecf20Sopenharmony_ci of_i8042_aux_irq = 12; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case FDC_BASE: /* FDC1 */ 6728c2ecf20Sopenharmony_ci np = of_find_node_by_type(NULL, "fdc"); 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci default: 6758c2ecf20Sopenharmony_ci /* ipmi is supposed to fail here */ 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci if (!np) 6798c2ecf20Sopenharmony_ci return ret; 6808c2ecf20Sopenharmony_ci parent = of_get_parent(np); 6818c2ecf20Sopenharmony_ci if (parent) { 6828c2ecf20Sopenharmony_ci if (of_node_is_type(parent, "isa")) 6838c2ecf20Sopenharmony_ci ret = 0; 6848c2ecf20Sopenharmony_ci of_node_put(parent); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci of_node_put(np); 6878c2ecf20Sopenharmony_ci return ret; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(check_legacy_ioport); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int ppc_panic_event(struct notifier_block *this, 6928c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci /* 6958c2ecf20Sopenharmony_ci * panic does a local_irq_disable, but we really 6968c2ecf20Sopenharmony_ci * want interrupts to be hard disabled. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci hard_irq_disable(); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* 7018c2ecf20Sopenharmony_ci * If firmware-assisted dump has been registered then trigger 7028c2ecf20Sopenharmony_ci * firmware-assisted dump and let firmware handle everything else. 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_ci crash_fadump(NULL, ptr); 7058c2ecf20Sopenharmony_ci if (ppc_md.panic) 7068c2ecf20Sopenharmony_ci ppc_md.panic(ptr); /* May not return */ 7078c2ecf20Sopenharmony_ci return NOTIFY_DONE; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic struct notifier_block ppc_panic_block = { 7118c2ecf20Sopenharmony_ci .notifier_call = ppc_panic_event, 7128c2ecf20Sopenharmony_ci .priority = INT_MIN /* may not return; must be done last */ 7138c2ecf20Sopenharmony_ci}; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci/* 7168c2ecf20Sopenharmony_ci * Dump out kernel offset information on panic. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_cistatic int dump_kernel_offset(struct notifier_block *self, unsigned long v, 7198c2ecf20Sopenharmony_ci void *p) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n", 7228c2ecf20Sopenharmony_ci kaslr_offset(), KERNELBASE); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic struct notifier_block kernel_offset_notifier = { 7288c2ecf20Sopenharmony_ci .notifier_call = dump_kernel_offset 7298c2ecf20Sopenharmony_ci}; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_civoid __init setup_panic(void) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset() > 0) 7348c2ecf20Sopenharmony_ci atomic_notifier_chain_register(&panic_notifier_list, 7358c2ecf20Sopenharmony_ci &kernel_offset_notifier); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* PPC64 always does a hard irq disable in its panic handler */ 7388c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PPC64) && !ppc_md.panic) 7398c2ecf20Sopenharmony_ci return; 7408c2ecf20Sopenharmony_ci atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci#ifdef CONFIG_CHECK_CACHE_COHERENCY 7448c2ecf20Sopenharmony_ci/* 7458c2ecf20Sopenharmony_ci * For platforms that have configurable cache-coherency. This function 7468c2ecf20Sopenharmony_ci * checks that the cache coherency setting of the kernel matches the setting 7478c2ecf20Sopenharmony_ci * left by the firmware, as indicated in the device tree. Since a mismatch 7488c2ecf20Sopenharmony_ci * will eventually result in DMA failures, we print * and error and call 7498c2ecf20Sopenharmony_ci * BUG() in that case. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci#define KERNEL_COHERENCY (!IS_ENABLED(CONFIG_NOT_COHERENT_CACHE)) 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int __init check_cache_coherency(void) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct device_node *np; 7578c2ecf20Sopenharmony_ci const void *prop; 7588c2ecf20Sopenharmony_ci bool devtree_coherency; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci np = of_find_node_by_path("/"); 7618c2ecf20Sopenharmony_ci prop = of_get_property(np, "coherency-off", NULL); 7628c2ecf20Sopenharmony_ci of_node_put(np); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci devtree_coherency = prop ? false : true; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (devtree_coherency != KERNEL_COHERENCY) { 7678c2ecf20Sopenharmony_ci printk(KERN_ERR 7688c2ecf20Sopenharmony_ci "kernel coherency:%s != device tree_coherency:%s\n", 7698c2ecf20Sopenharmony_ci KERNEL_COHERENCY ? "on" : "off", 7708c2ecf20Sopenharmony_ci devtree_coherency ? "on" : "off"); 7718c2ecf20Sopenharmony_ci BUG(); 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return 0; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cilate_initcall(check_cache_coherency); 7788c2ecf20Sopenharmony_ci#endif /* CONFIG_CHECK_CACHE_COHERENCY */ 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 7818c2ecf20Sopenharmony_cistruct dentry *powerpc_debugfs_root; 7828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(powerpc_debugfs_root); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int powerpc_debugfs_init(void) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci powerpc_debugfs_root = debugfs_create_dir("powerpc", NULL); 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ciarch_initcall(powerpc_debugfs_init); 7908c2ecf20Sopenharmony_ci#endif 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_civoid ppc_printk_progress(char *s, unsigned short hex) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci pr_info("%s\n", s); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic __init void print_system_info(void) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci pr_info("-----------------------------------------------------\n"); 8008c2ecf20Sopenharmony_ci pr_info("phys_mem_size = 0x%llx\n", 8018c2ecf20Sopenharmony_ci (unsigned long long)memblock_phys_mem_size()); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci pr_info("dcache_bsize = 0x%x\n", dcache_bsize); 8048c2ecf20Sopenharmony_ci pr_info("icache_bsize = 0x%x\n", icache_bsize); 8058c2ecf20Sopenharmony_ci if (ucache_bsize != 0) 8068c2ecf20Sopenharmony_ci pr_info("ucache_bsize = 0x%x\n", ucache_bsize); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci pr_info("cpu_features = 0x%016lx\n", cur_cpu_spec->cpu_features); 8098c2ecf20Sopenharmony_ci pr_info(" possible = 0x%016lx\n", 8108c2ecf20Sopenharmony_ci (unsigned long)CPU_FTRS_POSSIBLE); 8118c2ecf20Sopenharmony_ci pr_info(" always = 0x%016lx\n", 8128c2ecf20Sopenharmony_ci (unsigned long)CPU_FTRS_ALWAYS); 8138c2ecf20Sopenharmony_ci pr_info("cpu_user_features = 0x%08x 0x%08x\n", 8148c2ecf20Sopenharmony_ci cur_cpu_spec->cpu_user_features, 8158c2ecf20Sopenharmony_ci cur_cpu_spec->cpu_user_features2); 8168c2ecf20Sopenharmony_ci pr_info("mmu_features = 0x%08x\n", cur_cpu_spec->mmu_features); 8178c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 8188c2ecf20Sopenharmony_ci pr_info("firmware_features = 0x%016lx\n", powerpc_firmware_features); 8198c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S 8208c2ecf20Sopenharmony_ci pr_info("vmalloc start = 0x%lx\n", KERN_VIRT_START); 8218c2ecf20Sopenharmony_ci pr_info("IO start = 0x%lx\n", KERN_IO_START); 8228c2ecf20Sopenharmony_ci pr_info("vmemmap start = 0x%lx\n", (unsigned long)vmemmap); 8238c2ecf20Sopenharmony_ci#endif 8248c2ecf20Sopenharmony_ci#endif 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (!early_radix_enabled()) 8278c2ecf20Sopenharmony_ci print_system_hash_info(); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (PHYSICAL_START > 0) 8308c2ecf20Sopenharmony_ci pr_info("physical_start = 0x%llx\n", 8318c2ecf20Sopenharmony_ci (unsigned long long)PHYSICAL_START); 8328c2ecf20Sopenharmony_ci pr_info("-----------------------------------------------------\n"); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 8368c2ecf20Sopenharmony_cistatic void smp_setup_pacas(void) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int cpu; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 8418c2ecf20Sopenharmony_ci if (cpu == smp_processor_id()) 8428c2ecf20Sopenharmony_ci continue; 8438c2ecf20Sopenharmony_ci allocate_paca(cpu); 8448c2ecf20Sopenharmony_ci set_hard_smp_processor_id(cpu, cpu_to_phys_id[cpu]); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci memblock_free(__pa(cpu_to_phys_id), nr_cpu_ids * sizeof(u32)); 8488c2ecf20Sopenharmony_ci cpu_to_phys_id = NULL; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci#endif 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/* 8538c2ecf20Sopenharmony_ci * Called into from start_kernel this initializes memblock, which is used 8548c2ecf20Sopenharmony_ci * to manage page allocation until mem_init is called. 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_civoid __init setup_arch(char **cmdline_p) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci kasan_init(); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci *cmdline_p = boot_command_line; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* Set a half-reasonable default so udelay does something sensible */ 8638c2ecf20Sopenharmony_ci loops_per_jiffy = 500000000 / HZ; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci /* Unflatten the device-tree passed by prom_init or kexec */ 8668c2ecf20Sopenharmony_ci unflatten_device_tree(); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* 8698c2ecf20Sopenharmony_ci * Initialize cache line/block info from device-tree (on ppc64) or 8708c2ecf20Sopenharmony_ci * just cputable (on ppc32). 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci initialize_cache_info(); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Initialize RTAS if available. */ 8758c2ecf20Sopenharmony_ci rtas_initialize(); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Check if we have an initrd provided via the device-tree. */ 8788c2ecf20Sopenharmony_ci check_for_initrd(); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* Probe the machine type, establish ppc_md. */ 8818c2ecf20Sopenharmony_ci probe_machine(); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* Setup panic notifier if requested by the platform. */ 8848c2ecf20Sopenharmony_ci setup_panic(); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* 8878c2ecf20Sopenharmony_ci * Configure ppc_md.power_save (ppc32 only, 64-bit machines do 8888c2ecf20Sopenharmony_ci * it from their respective probe() function. 8898c2ecf20Sopenharmony_ci */ 8908c2ecf20Sopenharmony_ci setup_power_save(); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci /* Discover standard serial ports. */ 8938c2ecf20Sopenharmony_ci find_legacy_serial_ports(); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* Register early console with the printk subsystem. */ 8968c2ecf20Sopenharmony_ci register_early_udbg_console(); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Setup the various CPU maps based on the device-tree. */ 8998c2ecf20Sopenharmony_ci smp_setup_cpu_maps(); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Initialize xmon. */ 9028c2ecf20Sopenharmony_ci xmon_setup(); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* Check the SMT related command line arguments (ppc64). */ 9058c2ecf20Sopenharmony_ci check_smt_enabled(); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* Parse memory topology */ 9088c2ecf20Sopenharmony_ci mem_topology_setup(); 9098c2ecf20Sopenharmony_ci /* Set max_mapnr before paging_init() */ 9108c2ecf20Sopenharmony_ci set_max_mapnr(max_pfn); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* 9138c2ecf20Sopenharmony_ci * Release secondary cpus out of their spinloops at 0x60 now that 9148c2ecf20Sopenharmony_ci * we can map physical -> logical CPU ids. 9158c2ecf20Sopenharmony_ci * 9168c2ecf20Sopenharmony_ci * Freescale Book3e parts spin in a loop provided by firmware, 9178c2ecf20Sopenharmony_ci * so smp_release_cpus() does nothing for them. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 9208c2ecf20Sopenharmony_ci smp_setup_pacas(); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* On BookE, setup per-core TLB data structures. */ 9238c2ecf20Sopenharmony_ci setup_tlb_core_data(); 9248c2ecf20Sopenharmony_ci#endif 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* Print various info about the machine that has been gathered so far. */ 9278c2ecf20Sopenharmony_ci print_system_info(); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* Reserve large chunks of memory for use by CMA for KVM. */ 9308c2ecf20Sopenharmony_ci kvm_cma_reserve(); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* Reserve large chunks of memory for us by CMA for hugetlb */ 9338c2ecf20Sopenharmony_ci gigantic_hugetlb_cma_reserve(); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci klp_init_thread_info(&init_task); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci init_mm.start_code = (unsigned long)_stext; 9388c2ecf20Sopenharmony_ci init_mm.end_code = (unsigned long) _etext; 9398c2ecf20Sopenharmony_ci init_mm.end_data = (unsigned long) _edata; 9408c2ecf20Sopenharmony_ci init_mm.brk = klimit; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci mm_iommu_init(&init_mm); 9438c2ecf20Sopenharmony_ci irqstack_early_init(); 9448c2ecf20Sopenharmony_ci exc_lvl_early_init(); 9458c2ecf20Sopenharmony_ci emergency_stack_init(); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci smp_release_cpus(); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci initmem_init(); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (ppc_md.setup_arch) 9548c2ecf20Sopenharmony_ci ppc_md.setup_arch(); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci setup_barrier_nospec(); 9578c2ecf20Sopenharmony_ci setup_spectre_v2(); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci paging_init(); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* Initialize the MMU context management stuff. */ 9628c2ecf20Sopenharmony_ci mmu_context_init(); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* Interrupt code needs to be 64K-aligned. */ 9658c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC64) && (unsigned long)_stext & 0xffff) 9668c2ecf20Sopenharmony_ci panic("Kernelbase not 64K-aligned (0x%lx)!\n", 9678c2ecf20Sopenharmony_ci (unsigned long)_stext); 9688c2ecf20Sopenharmony_ci} 969