199106986SGuo Ren // SPDX-License-Identifier: GPL-2.0 299106986SGuo Ren 399106986SGuo Ren #include <linux/module.h> 499106986SGuo Ren #include <linux/init.h> 599106986SGuo Ren #include <linux/kernel.h> 699106986SGuo Ren #include <linux/mm.h> 799106986SGuo Ren #include <linux/sched.h> 899106986SGuo Ren #include <linux/kernel_stat.h> 999106986SGuo Ren #include <linux/notifier.h> 1099106986SGuo Ren #include <linux/cpu.h> 1199106986SGuo Ren #include <linux/percpu.h> 1299106986SGuo Ren #include <linux/delay.h> 1399106986SGuo Ren #include <linux/err.h> 1499106986SGuo Ren #include <linux/irq.h> 152c81b076SGuo Ren #include <linux/irq_work.h> 1699106986SGuo Ren #include <linux/irqdomain.h> 1799106986SGuo Ren #include <linux/of.h> 18e6169c4bSGuo Ren #include <linux/seq_file.h> 1999106986SGuo Ren #include <linux/sched/task_stack.h> 2099106986SGuo Ren #include <linux/sched/mm.h> 21859e5f45SGuo Ren #include <linux/sched/hotplug.h> 2299106986SGuo Ren #include <asm/irq.h> 2399106986SGuo Ren #include <asm/traps.h> 2499106986SGuo Ren #include <asm/sections.h> 2599106986SGuo Ren #include <asm/mmu_context.h> 2612879bdaSGuo Ren #ifdef CONFIG_CPU_HAS_FPU 2712879bdaSGuo Ren #include <abi/fpu.h> 2812879bdaSGuo Ren #endif 2999106986SGuo Ren 3099106986SGuo Ren enum ipi_message_type { 3199106986SGuo Ren IPI_EMPTY, 3299106986SGuo Ren IPI_RESCHEDULE, 3399106986SGuo Ren IPI_CALL_FUNC, 342c81b076SGuo Ren IPI_IRQ_WORK, 3599106986SGuo Ren IPI_MAX 3699106986SGuo Ren }; 3799106986SGuo Ren 38e6169c4bSGuo Ren struct ipi_data_struct { 39e6169c4bSGuo Ren unsigned long bits ____cacheline_aligned; 40e6169c4bSGuo Ren unsigned long stats[IPI_MAX] ____cacheline_aligned; 41e6169c4bSGuo Ren }; 42e6169c4bSGuo Ren static DEFINE_PER_CPU(struct ipi_data_struct, ipi_data); 43e6169c4bSGuo Ren 4499106986SGuo Ren static irqreturn_t handle_ipi(int irq, void *dev) 4599106986SGuo Ren { 46e6169c4bSGuo Ren unsigned long *stats = this_cpu_ptr(&ipi_data)->stats; 47e6169c4bSGuo Ren 4899106986SGuo Ren while (true) { 4999106986SGuo Ren unsigned long ops; 5099106986SGuo Ren 5199106986SGuo Ren ops = xchg(&this_cpu_ptr(&ipi_data)->bits, 0); 5299106986SGuo Ren if (ops == 0) 5399106986SGuo Ren return IRQ_HANDLED; 5499106986SGuo Ren 55e6169c4bSGuo Ren if (ops & (1 << IPI_RESCHEDULE)) { 56e6169c4bSGuo Ren stats[IPI_RESCHEDULE]++; 5799106986SGuo Ren scheduler_ipi(); 58e6169c4bSGuo Ren } 5999106986SGuo Ren 60e6169c4bSGuo Ren if (ops & (1 << IPI_CALL_FUNC)) { 61e6169c4bSGuo Ren stats[IPI_CALL_FUNC]++; 6299106986SGuo Ren generic_smp_call_function_interrupt(); 63e6169c4bSGuo Ren } 6499106986SGuo Ren 65e6169c4bSGuo Ren if (ops & (1 << IPI_IRQ_WORK)) { 66e6169c4bSGuo Ren stats[IPI_IRQ_WORK]++; 672c81b076SGuo Ren irq_work_run(); 68e6169c4bSGuo Ren } 692c81b076SGuo Ren 7099106986SGuo Ren BUG_ON((ops >> IPI_MAX) != 0); 7199106986SGuo Ren } 7299106986SGuo Ren 7399106986SGuo Ren return IRQ_HANDLED; 7499106986SGuo Ren } 7599106986SGuo Ren 7699106986SGuo Ren static void (*send_arch_ipi)(const struct cpumask *mask); 7799106986SGuo Ren 7899106986SGuo Ren static int ipi_irq; 7999106986SGuo Ren void __init set_send_ipi(void (*func)(const struct cpumask *mask), int irq) 8099106986SGuo Ren { 8199106986SGuo Ren if (send_arch_ipi) 8299106986SGuo Ren return; 8399106986SGuo Ren 8499106986SGuo Ren send_arch_ipi = func; 8599106986SGuo Ren ipi_irq = irq; 8699106986SGuo Ren } 8799106986SGuo Ren 8899106986SGuo Ren static void 8999106986SGuo Ren send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) 9099106986SGuo Ren { 9199106986SGuo Ren int i; 9299106986SGuo Ren 9399106986SGuo Ren for_each_cpu(i, to_whom) 9499106986SGuo Ren set_bit(operation, &per_cpu_ptr(&ipi_data, i)->bits); 9599106986SGuo Ren 9699106986SGuo Ren smp_mb(); 9799106986SGuo Ren send_arch_ipi(to_whom); 9899106986SGuo Ren } 9999106986SGuo Ren 100e6169c4bSGuo Ren static const char * const ipi_names[] = { 101e6169c4bSGuo Ren [IPI_EMPTY] = "Empty interrupts", 102e6169c4bSGuo Ren [IPI_RESCHEDULE] = "Rescheduling interrupts", 103e6169c4bSGuo Ren [IPI_CALL_FUNC] = "Function call interrupts", 104e6169c4bSGuo Ren [IPI_IRQ_WORK] = "Irq work interrupts", 105e6169c4bSGuo Ren }; 106e6169c4bSGuo Ren 107e6169c4bSGuo Ren int arch_show_interrupts(struct seq_file *p, int prec) 108e6169c4bSGuo Ren { 109e6169c4bSGuo Ren unsigned int cpu, i; 110e6169c4bSGuo Ren 111e6169c4bSGuo Ren for (i = 0; i < IPI_MAX; i++) { 112e6169c4bSGuo Ren seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, 113e6169c4bSGuo Ren prec >= 4 ? " " : ""); 114e6169c4bSGuo Ren for_each_online_cpu(cpu) 115e6169c4bSGuo Ren seq_printf(p, "%10lu ", 116e6169c4bSGuo Ren per_cpu_ptr(&ipi_data, cpu)->stats[i]); 117e6169c4bSGuo Ren seq_printf(p, " %s\n", ipi_names[i]); 118e6169c4bSGuo Ren } 119e6169c4bSGuo Ren 120e6169c4bSGuo Ren return 0; 121e6169c4bSGuo Ren } 122e6169c4bSGuo Ren 12399106986SGuo Ren void arch_send_call_function_ipi_mask(struct cpumask *mask) 12499106986SGuo Ren { 12599106986SGuo Ren send_ipi_message(mask, IPI_CALL_FUNC); 12699106986SGuo Ren } 12799106986SGuo Ren 12899106986SGuo Ren void arch_send_call_function_single_ipi(int cpu) 12999106986SGuo Ren { 13099106986SGuo Ren send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC); 13199106986SGuo Ren } 13299106986SGuo Ren 13399106986SGuo Ren static void ipi_stop(void *unused) 13499106986SGuo Ren { 13599106986SGuo Ren while (1); 13699106986SGuo Ren } 13799106986SGuo Ren 13899106986SGuo Ren void smp_send_stop(void) 13999106986SGuo Ren { 14099106986SGuo Ren on_each_cpu(ipi_stop, NULL, 1); 14199106986SGuo Ren } 14299106986SGuo Ren 14399106986SGuo Ren void smp_send_reschedule(int cpu) 14499106986SGuo Ren { 14599106986SGuo Ren send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); 14699106986SGuo Ren } 14799106986SGuo Ren 1482c81b076SGuo Ren #ifdef CONFIG_IRQ_WORK 1492c81b076SGuo Ren void arch_irq_work_raise(void) 1502c81b076SGuo Ren { 1512c81b076SGuo Ren send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); 1522c81b076SGuo Ren } 1532c81b076SGuo Ren #endif 1542c81b076SGuo Ren 15599106986SGuo Ren void __init smp_prepare_boot_cpu(void) 15699106986SGuo Ren { 15799106986SGuo Ren } 15899106986SGuo Ren 15999106986SGuo Ren void __init smp_prepare_cpus(unsigned int max_cpus) 16099106986SGuo Ren { 16199106986SGuo Ren } 16299106986SGuo Ren 16399106986SGuo Ren static int ipi_dummy_dev; 164859e5f45SGuo Ren 16599106986SGuo Ren void __init setup_smp_ipi(void) 16699106986SGuo Ren { 16799106986SGuo Ren int rc; 16899106986SGuo Ren 16999106986SGuo Ren if (ipi_irq == 0) 170c9492737SGuo Ren return; 17199106986SGuo Ren 17299106986SGuo Ren rc = request_percpu_irq(ipi_irq, handle_ipi, "IPI Interrupt", 17399106986SGuo Ren &ipi_dummy_dev); 17499106986SGuo Ren if (rc) 17599106986SGuo Ren panic("%s IRQ request failed\n", __func__); 17699106986SGuo Ren 177859e5f45SGuo Ren enable_percpu_irq(ipi_irq, 0); 17899106986SGuo Ren } 17999106986SGuo Ren 18099106986SGuo Ren void __init setup_smp(void) 18199106986SGuo Ren { 18299106986SGuo Ren struct device_node *node = NULL; 183*316b5e31SRob Herring unsigned int cpu; 18499106986SGuo Ren 185398539ddSYangtao Li for_each_of_cpu_node(node) { 18699106986SGuo Ren if (!of_device_is_available(node)) 18799106986SGuo Ren continue; 18899106986SGuo Ren 189*316b5e31SRob Herring cpu = of_get_cpu_hwid(node, 0); 19099106986SGuo Ren if (cpu >= NR_CPUS) 19199106986SGuo Ren continue; 19299106986SGuo Ren 19399106986SGuo Ren set_cpu_possible(cpu, true); 19499106986SGuo Ren set_cpu_present(cpu, true); 19599106986SGuo Ren } 19699106986SGuo Ren } 19799106986SGuo Ren 19899106986SGuo Ren extern void _start_smp_secondary(void); 19999106986SGuo Ren 20099106986SGuo Ren volatile unsigned int secondary_hint; 2018077e66bSGuo Ren volatile unsigned int secondary_hint2; 20299106986SGuo Ren volatile unsigned int secondary_ccr; 20399106986SGuo Ren volatile unsigned int secondary_stack; 2040c8a32eeSGuo Ren volatile unsigned int secondary_msa1; 2050c8a32eeSGuo Ren volatile unsigned int secondary_pgd; 206aefd9461SGuo Ren 20799106986SGuo Ren int __cpu_up(unsigned int cpu, struct task_struct *tidle) 20899106986SGuo Ren { 209859e5f45SGuo Ren unsigned long mask = 1 << cpu; 21099106986SGuo Ren 2110f231dcfSGuo Ren secondary_stack = 2120f231dcfSGuo Ren (unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8; 21399106986SGuo Ren secondary_hint = mfcr("cr31"); 2148077e66bSGuo Ren secondary_hint2 = mfcr("cr<21, 1>"); 21599106986SGuo Ren secondary_ccr = mfcr("cr18"); 216aefd9461SGuo Ren secondary_msa1 = read_mmu_msa1(); 2170c8a32eeSGuo Ren secondary_pgd = mfcr("cr<29, 15>"); 21899106986SGuo Ren 21999106986SGuo Ren /* 22099106986SGuo Ren * Because other CPUs are in reset status, we must flush data 22199106986SGuo Ren * from cache to out and secondary CPUs use them in 22299106986SGuo Ren * csky_start_secondary(void) 22399106986SGuo Ren */ 22499106986SGuo Ren mtcr("cr17", 0x22); 22599106986SGuo Ren 226859e5f45SGuo Ren if (mask & mfcr("cr<29, 0>")) { 227859e5f45SGuo Ren send_arch_ipi(cpumask_of(cpu)); 228859e5f45SGuo Ren } else { 22999106986SGuo Ren /* Enable cpu in SMP reset ctrl reg */ 230859e5f45SGuo Ren mask |= mfcr("cr<29, 0>"); 231859e5f45SGuo Ren mtcr("cr<29, 0>", mask); 232859e5f45SGuo Ren } 23399106986SGuo Ren 23499106986SGuo Ren /* Wait for the cpu online */ 23599106986SGuo Ren while (!cpu_online(cpu)); 23699106986SGuo Ren 23799106986SGuo Ren secondary_stack = 0; 23899106986SGuo Ren 23999106986SGuo Ren return 0; 24099106986SGuo Ren } 24199106986SGuo Ren 24299106986SGuo Ren void __init smp_cpus_done(unsigned int max_cpus) 24399106986SGuo Ren { 24499106986SGuo Ren } 24599106986SGuo Ren 24699106986SGuo Ren int setup_profiling_timer(unsigned int multiplier) 24799106986SGuo Ren { 24899106986SGuo Ren return -EINVAL; 24999106986SGuo Ren } 25099106986SGuo Ren 25199106986SGuo Ren void csky_start_secondary(void) 25299106986SGuo Ren { 25399106986SGuo Ren struct mm_struct *mm = &init_mm; 25499106986SGuo Ren unsigned int cpu = smp_processor_id(); 25599106986SGuo Ren 25699106986SGuo Ren mtcr("cr31", secondary_hint); 2578077e66bSGuo Ren mtcr("cr<21, 1>", secondary_hint2); 25899106986SGuo Ren mtcr("cr18", secondary_ccr); 25999106986SGuo Ren 26099106986SGuo Ren mtcr("vbr", vec_base); 26199106986SGuo Ren 26299106986SGuo Ren flush_tlb_all(); 26399106986SGuo Ren write_mmu_pagemask(0); 26499106986SGuo Ren 26599106986SGuo Ren #ifdef CONFIG_CPU_HAS_FPU 26699106986SGuo Ren init_fpu(); 26799106986SGuo Ren #endif 26899106986SGuo Ren 269859e5f45SGuo Ren enable_percpu_irq(ipi_irq, 0); 27099106986SGuo Ren 27199106986SGuo Ren mmget(mm); 27299106986SGuo Ren mmgrab(mm); 27399106986SGuo Ren current->active_mm = mm; 27499106986SGuo Ren cpumask_set_cpu(cpu, mm_cpumask(mm)); 27599106986SGuo Ren 27699106986SGuo Ren notify_cpu_starting(cpu); 27799106986SGuo Ren set_cpu_online(cpu, true); 27899106986SGuo Ren 27999106986SGuo Ren pr_info("CPU%u Online: %s...\n", cpu, __func__); 28099106986SGuo Ren 28199106986SGuo Ren local_irq_enable(); 28299106986SGuo Ren cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 28399106986SGuo Ren } 284859e5f45SGuo Ren 285859e5f45SGuo Ren #ifdef CONFIG_HOTPLUG_CPU 286859e5f45SGuo Ren int __cpu_disable(void) 287859e5f45SGuo Ren { 288859e5f45SGuo Ren unsigned int cpu = smp_processor_id(); 289859e5f45SGuo Ren 290859e5f45SGuo Ren set_cpu_online(cpu, false); 291859e5f45SGuo Ren 292859e5f45SGuo Ren irq_migrate_all_off_this_cpu(); 293859e5f45SGuo Ren 294859e5f45SGuo Ren clear_tasks_mm_cpumask(cpu); 295859e5f45SGuo Ren 296859e5f45SGuo Ren return 0; 297859e5f45SGuo Ren } 298859e5f45SGuo Ren 299859e5f45SGuo Ren void __cpu_die(unsigned int cpu) 300859e5f45SGuo Ren { 301859e5f45SGuo Ren if (!cpu_wait_death(cpu, 5)) { 302859e5f45SGuo Ren pr_crit("CPU%u: shutdown failed\n", cpu); 303859e5f45SGuo Ren return; 304859e5f45SGuo Ren } 305859e5f45SGuo Ren pr_notice("CPU%u: shutdown\n", cpu); 306859e5f45SGuo Ren } 307859e5f45SGuo Ren 308859e5f45SGuo Ren void arch_cpu_idle_dead(void) 309859e5f45SGuo Ren { 310859e5f45SGuo Ren idle_task_exit(); 311859e5f45SGuo Ren 312859e5f45SGuo Ren cpu_report_death(); 313859e5f45SGuo Ren 314859e5f45SGuo Ren while (!secondary_stack) 315859e5f45SGuo Ren arch_cpu_idle(); 316859e5f45SGuo Ren 317859e5f45SGuo Ren local_irq_disable(); 318859e5f45SGuo Ren 319859e5f45SGuo Ren asm volatile( 320859e5f45SGuo Ren "mov sp, %0\n" 321859e5f45SGuo Ren "mov r8, %0\n" 322859e5f45SGuo Ren "jmpi csky_start_secondary" 323859e5f45SGuo Ren : 324859e5f45SGuo Ren : "r" (secondary_stack)); 325859e5f45SGuo Ren } 326859e5f45SGuo Ren #endif 327