1 /* 2 * SMP initialisation and IPI support 3 * Based on arch/arm64/kernel/smp.c 4 * 5 * Copyright (C) 2012 ARM Ltd. 6 * Copyright (C) 2015 Regents of the University of California 7 * Copyright (C) 2017 SiFive 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/module.h> 20 #include <linux/init.h> 21 #include <linux/kernel.h> 22 #include <linux/mm.h> 23 #include <linux/sched.h> 24 #include <linux/kernel_stat.h> 25 #include <linux/notifier.h> 26 #include <linux/cpu.h> 27 #include <linux/percpu.h> 28 #include <linux/delay.h> 29 #include <linux/err.h> 30 #include <linux/irq.h> 31 #include <linux/of.h> 32 #include <linux/sched/task_stack.h> 33 #include <linux/sched/mm.h> 34 #include <asm/irq.h> 35 #include <asm/mmu_context.h> 36 #include <asm/tlbflush.h> 37 #include <asm/sections.h> 38 #include <asm/sbi.h> 39 40 void *__cpu_up_stack_pointer[NR_CPUS]; 41 void *__cpu_up_task_pointer[NR_CPUS]; 42 static DECLARE_COMPLETION(cpu_running); 43 44 void __init smp_prepare_boot_cpu(void) 45 { 46 } 47 48 void __init smp_prepare_cpus(unsigned int max_cpus) 49 { 50 } 51 52 void __init setup_smp(void) 53 { 54 struct device_node *dn; 55 int hart; 56 bool found_boot_cpu = false; 57 int cpuid = 1; 58 59 for_each_of_cpu_node(dn) { 60 hart = riscv_of_processor_hartid(dn); 61 if (hart < 0) 62 continue; 63 64 if (hart == cpuid_to_hartid_map(0)) { 65 BUG_ON(found_boot_cpu); 66 found_boot_cpu = 1; 67 continue; 68 } 69 if (cpuid >= NR_CPUS) { 70 pr_warn("Invalid cpuid [%d] for hartid [%d]\n", 71 cpuid, hart); 72 break; 73 } 74 75 cpuid_to_hartid_map(cpuid) = hart; 76 set_cpu_possible(cpuid, true); 77 set_cpu_present(cpuid, true); 78 cpuid++; 79 } 80 81 BUG_ON(!found_boot_cpu); 82 } 83 84 int __cpu_up(unsigned int cpu, struct task_struct *tidle) 85 { 86 int ret = 0; 87 int hartid = cpuid_to_hartid_map(cpu); 88 tidle->thread_info.cpu = cpu; 89 90 /* 91 * On RISC-V systems, all harts boot on their own accord. Our _start 92 * selects the first hart to boot the kernel and causes the remainder 93 * of the harts to spin in a loop waiting for their stack pointer to be 94 * setup by that main hart. Writing __cpu_up_stack_pointer signals to 95 * the spinning harts that they can continue the boot process. 96 */ 97 smp_mb(); 98 WRITE_ONCE(__cpu_up_stack_pointer[hartid], 99 task_stack_page(tidle) + THREAD_SIZE); 100 WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle); 101 102 lockdep_assert_held(&cpu_running); 103 wait_for_completion_timeout(&cpu_running, 104 msecs_to_jiffies(1000)); 105 106 if (!cpu_online(cpu)) { 107 pr_crit("CPU%u: failed to come online\n", cpu); 108 ret = -EIO; 109 } 110 111 return ret; 112 } 113 114 void __init smp_cpus_done(unsigned int max_cpus) 115 { 116 } 117 118 /* 119 * C entry point for a secondary processor. 120 */ 121 asmlinkage void __init smp_callin(void) 122 { 123 struct mm_struct *mm = &init_mm; 124 125 /* All kernel threads share the same mm context. */ 126 mmgrab(mm); 127 current->active_mm = mm; 128 129 trap_init(); 130 notify_cpu_starting(smp_processor_id()); 131 set_cpu_online(smp_processor_id(), 1); 132 /* 133 * Remote TLB flushes are ignored while the CPU is offline, so emit 134 * a local TLB flush right now just in case. 135 */ 136 local_flush_tlb_all(); 137 complete(&cpu_running); 138 /* 139 * Disable preemption before enabling interrupts, so we don't try to 140 * schedule a CPU that hasn't actually started yet. 141 */ 142 preempt_disable(); 143 local_irq_enable(); 144 cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 145 } 146