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
handle_ipi(int irq,void * dev)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;
set_send_ipi(void (* func)(const struct cpumask * mask),int 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
send_ipi_message(const struct cpumask * to_whom,enum ipi_message_type operation)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
arch_show_interrupts(struct seq_file * p,int prec)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
arch_send_call_function_ipi_mask(struct cpumask * mask)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
arch_send_call_function_single_ipi(int cpu)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
ipi_stop(void * unused)13399106986SGuo Ren static void ipi_stop(void *unused)
13499106986SGuo Ren {
13599106986SGuo Ren while (1);
13699106986SGuo Ren }
13799106986SGuo Ren
smp_send_stop(void)13899106986SGuo Ren void smp_send_stop(void)
13999106986SGuo Ren {
14099106986SGuo Ren on_each_cpu(ipi_stop, NULL, 1);
14199106986SGuo Ren }
14299106986SGuo Ren
arch_smp_send_reschedule(int cpu)143*4c8c3c7fSValentin Schneider void arch_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
arch_irq_work_raise(void)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
smp_prepare_boot_cpu(void)15599106986SGuo Ren void __init smp_prepare_boot_cpu(void)
15699106986SGuo Ren {
15799106986SGuo Ren }
15899106986SGuo Ren
smp_prepare_cpus(unsigned int max_cpus)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
setup_smp_ipi(void)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
setup_smp(void)18099106986SGuo Ren void __init setup_smp(void)
18199106986SGuo Ren {
18299106986SGuo Ren struct device_node *node = NULL;
183316b5e31SRob 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
189316b5e31SRob 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
__cpu_up(unsigned int cpu,struct task_struct * tidle)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
smp_cpus_done(unsigned int max_cpus)24299106986SGuo Ren void __init smp_cpus_done(unsigned int max_cpus)
24399106986SGuo Ren {
24499106986SGuo Ren }
24599106986SGuo Ren
csky_start_secondary(void)24699106986SGuo Ren void csky_start_secondary(void)
24799106986SGuo Ren {
24899106986SGuo Ren struct mm_struct *mm = &init_mm;
24999106986SGuo Ren unsigned int cpu = smp_processor_id();
25099106986SGuo Ren
25199106986SGuo Ren mtcr("cr31", secondary_hint);
2528077e66bSGuo Ren mtcr("cr<21, 1>", secondary_hint2);
25399106986SGuo Ren mtcr("cr18", secondary_ccr);
25499106986SGuo Ren
25599106986SGuo Ren mtcr("vbr", vec_base);
25699106986SGuo Ren
25799106986SGuo Ren flush_tlb_all();
25899106986SGuo Ren write_mmu_pagemask(0);
25999106986SGuo Ren
26099106986SGuo Ren #ifdef CONFIG_CPU_HAS_FPU
26199106986SGuo Ren init_fpu();
26299106986SGuo Ren #endif
26399106986SGuo Ren
264859e5f45SGuo Ren enable_percpu_irq(ipi_irq, 0);
26599106986SGuo Ren
26699106986SGuo Ren mmget(mm);
26799106986SGuo Ren mmgrab(mm);
26899106986SGuo Ren current->active_mm = mm;
26999106986SGuo Ren cpumask_set_cpu(cpu, mm_cpumask(mm));
27099106986SGuo Ren
27199106986SGuo Ren notify_cpu_starting(cpu);
27299106986SGuo Ren set_cpu_online(cpu, true);
27399106986SGuo Ren
27499106986SGuo Ren pr_info("CPU%u Online: %s...\n", cpu, __func__);
27599106986SGuo Ren
27699106986SGuo Ren local_irq_enable();
27799106986SGuo Ren cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
27899106986SGuo Ren }
279859e5f45SGuo Ren
280859e5f45SGuo Ren #ifdef CONFIG_HOTPLUG_CPU
__cpu_disable(void)281859e5f45SGuo Ren int __cpu_disable(void)
282859e5f45SGuo Ren {
283859e5f45SGuo Ren unsigned int cpu = smp_processor_id();
284859e5f45SGuo Ren
285859e5f45SGuo Ren set_cpu_online(cpu, false);
286859e5f45SGuo Ren
287859e5f45SGuo Ren irq_migrate_all_off_this_cpu();
288859e5f45SGuo Ren
289859e5f45SGuo Ren clear_tasks_mm_cpumask(cpu);
290859e5f45SGuo Ren
291859e5f45SGuo Ren return 0;
292859e5f45SGuo Ren }
293859e5f45SGuo Ren
arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)294859e5f45SGuo Ren void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
295859e5f45SGuo Ren {
296859e5f45SGuo Ren pr_notice("CPU%u: shutdown\n", cpu);
297859e5f45SGuo Ren }
298859e5f45SGuo Ren
arch_cpu_idle_dead(void)299859e5f45SGuo Ren void __noreturn arch_cpu_idle_dead(void)
300859e5f45SGuo Ren {
301859e5f45SGuo Ren idle_task_exit();
302859e5f45SGuo Ren
303071c44e4SJosh Poimboeuf cpuhp_ap_report_dead();
304859e5f45SGuo Ren
305859e5f45SGuo Ren while (!secondary_stack)
306859e5f45SGuo Ren arch_cpu_idle();
307859e5f45SGuo Ren
308859e5f45SGuo Ren raw_local_irq_disable();
309859e5f45SGuo Ren
310859e5f45SGuo Ren asm volatile(
311859e5f45SGuo Ren "mov sp, %0\n"
31289b30987SPeter Zijlstra "mov r8, %0\n"
313859e5f45SGuo Ren "jmpi csky_start_secondary"
314859e5f45SGuo Ren :
315859e5f45SGuo Ren : "r" (secondary_stack));
316859e5f45SGuo Ren
317859e5f45SGuo Ren BUG();
318859e5f45SGuo Ren }
319859e5f45SGuo Ren #endif
3201b2442a8SJosh Poimboeuf