xref: /linux/arch/csky/kernel/smp.c (revision 71261072)
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)1434c8c3c7fSValentin 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_cpus(unsigned int max_cpus)15599106986SGuo Ren void __init smp_prepare_cpus(unsigned int max_cpus)
15699106986SGuo Ren {
15799106986SGuo Ren }
15899106986SGuo Ren 
15999106986SGuo Ren static int ipi_dummy_dev;
160859e5f45SGuo Ren 
setup_smp_ipi(void)16199106986SGuo Ren void __init setup_smp_ipi(void)
16299106986SGuo Ren {
16399106986SGuo Ren 	int rc;
16499106986SGuo Ren 
16599106986SGuo Ren 	if (ipi_irq == 0)
166c9492737SGuo Ren 		return;
16799106986SGuo Ren 
16899106986SGuo Ren 	rc = request_percpu_irq(ipi_irq, handle_ipi, "IPI Interrupt",
16999106986SGuo Ren 				&ipi_dummy_dev);
17099106986SGuo Ren 	if (rc)
17199106986SGuo Ren 		panic("%s IRQ request failed\n", __func__);
17299106986SGuo Ren 
173859e5f45SGuo Ren 	enable_percpu_irq(ipi_irq, 0);
17499106986SGuo Ren }
17599106986SGuo Ren 
setup_smp(void)17699106986SGuo Ren void __init setup_smp(void)
17799106986SGuo Ren {
17899106986SGuo Ren 	struct device_node *node = NULL;
179316b5e31SRob Herring 	unsigned int cpu;
18099106986SGuo Ren 
181398539ddSYangtao Li 	for_each_of_cpu_node(node) {
18299106986SGuo Ren 		if (!of_device_is_available(node))
18399106986SGuo Ren 			continue;
18499106986SGuo Ren 
185316b5e31SRob Herring 		cpu = of_get_cpu_hwid(node, 0);
18699106986SGuo Ren 		if (cpu >= NR_CPUS)
18799106986SGuo Ren 			continue;
18899106986SGuo Ren 
18999106986SGuo Ren 		set_cpu_possible(cpu, true);
19099106986SGuo Ren 		set_cpu_present(cpu, true);
19199106986SGuo Ren 	}
19299106986SGuo Ren }
19399106986SGuo Ren 
19499106986SGuo Ren extern void _start_smp_secondary(void);
19599106986SGuo Ren 
19699106986SGuo Ren volatile unsigned int secondary_hint;
1978077e66bSGuo Ren volatile unsigned int secondary_hint2;
19899106986SGuo Ren volatile unsigned int secondary_ccr;
19999106986SGuo Ren volatile unsigned int secondary_stack;
2000c8a32eeSGuo Ren volatile unsigned int secondary_msa1;
2010c8a32eeSGuo Ren volatile unsigned int secondary_pgd;
202aefd9461SGuo Ren 
__cpu_up(unsigned int cpu,struct task_struct * tidle)20399106986SGuo Ren int __cpu_up(unsigned int cpu, struct task_struct *tidle)
20499106986SGuo Ren {
205859e5f45SGuo Ren 	unsigned long mask = 1 << cpu;
20699106986SGuo Ren 
2070f231dcfSGuo Ren 	secondary_stack =
2080f231dcfSGuo Ren 		(unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8;
20999106986SGuo Ren 	secondary_hint = mfcr("cr31");
2108077e66bSGuo Ren 	secondary_hint2 = mfcr("cr<21, 1>");
21199106986SGuo Ren 	secondary_ccr  = mfcr("cr18");
212aefd9461SGuo Ren 	secondary_msa1 = read_mmu_msa1();
2130c8a32eeSGuo Ren 	secondary_pgd = mfcr("cr<29, 15>");
21499106986SGuo Ren 
21599106986SGuo Ren 	/*
21699106986SGuo Ren 	 * Because other CPUs are in reset status, we must flush data
21799106986SGuo Ren 	 * from cache to out and secondary CPUs use them in
21899106986SGuo Ren 	 * csky_start_secondary(void)
21999106986SGuo Ren 	 */
22099106986SGuo Ren 	mtcr("cr17", 0x22);
22199106986SGuo Ren 
222859e5f45SGuo Ren 	if (mask & mfcr("cr<29, 0>")) {
223859e5f45SGuo Ren 		send_arch_ipi(cpumask_of(cpu));
224859e5f45SGuo Ren 	} else {
22599106986SGuo Ren 		/* Enable cpu in SMP reset ctrl reg */
226859e5f45SGuo Ren 		mask |= mfcr("cr<29, 0>");
227859e5f45SGuo Ren 		mtcr("cr<29, 0>", mask);
228859e5f45SGuo Ren 	}
22999106986SGuo Ren 
23099106986SGuo Ren 	/* Wait for the cpu online */
23199106986SGuo Ren 	while (!cpu_online(cpu));
23299106986SGuo Ren 
23399106986SGuo Ren 	secondary_stack = 0;
23499106986SGuo Ren 
23599106986SGuo Ren 	return 0;
23699106986SGuo Ren }
23799106986SGuo Ren 
smp_cpus_done(unsigned int max_cpus)23899106986SGuo Ren void __init smp_cpus_done(unsigned int max_cpus)
23999106986SGuo Ren {
24099106986SGuo Ren }
24199106986SGuo Ren 
csky_start_secondary(void)24299106986SGuo Ren void csky_start_secondary(void)
24399106986SGuo Ren {
24499106986SGuo Ren 	struct mm_struct *mm = &init_mm;
24599106986SGuo Ren 	unsigned int cpu = smp_processor_id();
24699106986SGuo Ren 
24799106986SGuo Ren 	mtcr("cr31", secondary_hint);
2488077e66bSGuo Ren 	mtcr("cr<21, 1>", secondary_hint2);
24999106986SGuo Ren 	mtcr("cr18", secondary_ccr);
25099106986SGuo Ren 
25199106986SGuo Ren 	mtcr("vbr", vec_base);
25299106986SGuo Ren 
25399106986SGuo Ren 	flush_tlb_all();
25499106986SGuo Ren 	write_mmu_pagemask(0);
25599106986SGuo Ren 
25699106986SGuo Ren #ifdef CONFIG_CPU_HAS_FPU
25799106986SGuo Ren 	init_fpu();
25899106986SGuo Ren #endif
25999106986SGuo Ren 
260859e5f45SGuo Ren 	enable_percpu_irq(ipi_irq, 0);
26199106986SGuo Ren 
26299106986SGuo Ren 	mmget(mm);
26399106986SGuo Ren 	mmgrab(mm);
26499106986SGuo Ren 	current->active_mm = mm;
26599106986SGuo Ren 	cpumask_set_cpu(cpu, mm_cpumask(mm));
26699106986SGuo Ren 
26799106986SGuo Ren 	notify_cpu_starting(cpu);
26899106986SGuo Ren 	set_cpu_online(cpu, true);
26999106986SGuo Ren 
27099106986SGuo Ren 	pr_info("CPU%u Online: %s...\n", cpu, __func__);
27199106986SGuo Ren 
27299106986SGuo Ren 	local_irq_enable();
27399106986SGuo Ren 	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
27499106986SGuo Ren }
275859e5f45SGuo Ren 
276859e5f45SGuo Ren #ifdef CONFIG_HOTPLUG_CPU
__cpu_disable(void)277859e5f45SGuo Ren int __cpu_disable(void)
278859e5f45SGuo Ren {
279859e5f45SGuo Ren 	unsigned int cpu = smp_processor_id();
280859e5f45SGuo Ren 
281859e5f45SGuo Ren 	set_cpu_online(cpu, false);
282859e5f45SGuo Ren 
283859e5f45SGuo Ren 	irq_migrate_all_off_this_cpu();
284859e5f45SGuo Ren 
285859e5f45SGuo Ren 	clear_tasks_mm_cpumask(cpu);
286859e5f45SGuo Ren 
287859e5f45SGuo Ren 	return 0;
288859e5f45SGuo Ren }
289859e5f45SGuo Ren 
arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)290*7202e979SThomas Gleixner void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
291859e5f45SGuo Ren {
292859e5f45SGuo Ren 	pr_notice("CPU%u: shutdown\n", cpu);
293859e5f45SGuo Ren }
294859e5f45SGuo Ren 
arch_cpu_idle_dead(void)295071c44e4SJosh Poimboeuf void __noreturn arch_cpu_idle_dead(void)
296859e5f45SGuo Ren {
297859e5f45SGuo Ren 	idle_task_exit();
298859e5f45SGuo Ren 
299*7202e979SThomas Gleixner 	cpuhp_ap_report_dead();
300859e5f45SGuo Ren 
301859e5f45SGuo Ren 	while (!secondary_stack)
302859e5f45SGuo Ren 		arch_cpu_idle();
303859e5f45SGuo Ren 
30489b30987SPeter Zijlstra 	raw_local_irq_disable();
305859e5f45SGuo Ren 
306859e5f45SGuo Ren 	asm volatile(
307859e5f45SGuo Ren 		"mov	sp, %0\n"
308859e5f45SGuo Ren 		"mov	r8, %0\n"
309859e5f45SGuo Ren 		"jmpi	csky_start_secondary"
310859e5f45SGuo Ren 		:
311859e5f45SGuo Ren 		: "r" (secondary_stack));
3121b2442a8SJosh Poimboeuf 
3131b2442a8SJosh Poimboeuf 	BUG();
314859e5f45SGuo Ren }
315859e5f45SGuo Ren #endif
316