xref: /linux/arch/csky/kernel/smp.c (revision aefd9461d34a1b0a2acad0750c43216c1c27b9d4)
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>
1599106986SGuo Ren #include <linux/irqdomain.h>
1699106986SGuo Ren #include <linux/of.h>
1799106986SGuo Ren #include <linux/sched/task_stack.h>
1899106986SGuo Ren #include <linux/sched/mm.h>
19859e5f45SGuo Ren #include <linux/sched/hotplug.h>
2099106986SGuo Ren #include <asm/irq.h>
2199106986SGuo Ren #include <asm/traps.h>
2299106986SGuo Ren #include <asm/sections.h>
2399106986SGuo Ren #include <asm/mmu_context.h>
2499106986SGuo Ren #include <asm/pgalloc.h>
2512879bdaSGuo Ren #ifdef CONFIG_CPU_HAS_FPU
2612879bdaSGuo Ren #include <abi/fpu.h>
2712879bdaSGuo Ren #endif
2899106986SGuo Ren 
2999106986SGuo Ren struct ipi_data_struct {
3099106986SGuo Ren 	unsigned long bits ____cacheline_aligned;
3199106986SGuo Ren };
3299106986SGuo Ren static DEFINE_PER_CPU(struct ipi_data_struct, ipi_data);
3399106986SGuo Ren 
3499106986SGuo Ren enum ipi_message_type {
3599106986SGuo Ren 	IPI_EMPTY,
3699106986SGuo Ren 	IPI_RESCHEDULE,
3799106986SGuo Ren 	IPI_CALL_FUNC,
3899106986SGuo Ren 	IPI_MAX
3999106986SGuo Ren };
4099106986SGuo Ren 
4199106986SGuo Ren static irqreturn_t handle_ipi(int irq, void *dev)
4299106986SGuo Ren {
4399106986SGuo Ren 	while (true) {
4499106986SGuo Ren 		unsigned long ops;
4599106986SGuo Ren 
4699106986SGuo Ren 		ops = xchg(&this_cpu_ptr(&ipi_data)->bits, 0);
4799106986SGuo Ren 		if (ops == 0)
4899106986SGuo Ren 			return IRQ_HANDLED;
4999106986SGuo Ren 
5099106986SGuo Ren 		if (ops & (1 << IPI_RESCHEDULE))
5199106986SGuo Ren 			scheduler_ipi();
5299106986SGuo Ren 
5399106986SGuo Ren 		if (ops & (1 << IPI_CALL_FUNC))
5499106986SGuo Ren 			generic_smp_call_function_interrupt();
5599106986SGuo Ren 
5699106986SGuo Ren 		BUG_ON((ops >> IPI_MAX) != 0);
5799106986SGuo Ren 	}
5899106986SGuo Ren 
5999106986SGuo Ren 	return IRQ_HANDLED;
6099106986SGuo Ren }
6199106986SGuo Ren 
6299106986SGuo Ren static void (*send_arch_ipi)(const struct cpumask *mask);
6399106986SGuo Ren 
6499106986SGuo Ren static int ipi_irq;
6599106986SGuo Ren void __init set_send_ipi(void (*func)(const struct cpumask *mask), int irq)
6699106986SGuo Ren {
6799106986SGuo Ren 	if (send_arch_ipi)
6899106986SGuo Ren 		return;
6999106986SGuo Ren 
7099106986SGuo Ren 	send_arch_ipi = func;
7199106986SGuo Ren 	ipi_irq = irq;
7299106986SGuo Ren }
7399106986SGuo Ren 
7499106986SGuo Ren static void
7599106986SGuo Ren send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
7699106986SGuo Ren {
7799106986SGuo Ren 	int i;
7899106986SGuo Ren 
7999106986SGuo Ren 	for_each_cpu(i, to_whom)
8099106986SGuo Ren 		set_bit(operation, &per_cpu_ptr(&ipi_data, i)->bits);
8199106986SGuo Ren 
8299106986SGuo Ren 	smp_mb();
8399106986SGuo Ren 	send_arch_ipi(to_whom);
8499106986SGuo Ren }
8599106986SGuo Ren 
8699106986SGuo Ren void arch_send_call_function_ipi_mask(struct cpumask *mask)
8799106986SGuo Ren {
8899106986SGuo Ren 	send_ipi_message(mask, IPI_CALL_FUNC);
8999106986SGuo Ren }
9099106986SGuo Ren 
9199106986SGuo Ren void arch_send_call_function_single_ipi(int cpu)
9299106986SGuo Ren {
9399106986SGuo Ren 	send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
9499106986SGuo Ren }
9599106986SGuo Ren 
9699106986SGuo Ren static void ipi_stop(void *unused)
9799106986SGuo Ren {
9899106986SGuo Ren 	while (1);
9999106986SGuo Ren }
10099106986SGuo Ren 
10199106986SGuo Ren void smp_send_stop(void)
10299106986SGuo Ren {
10399106986SGuo Ren 	on_each_cpu(ipi_stop, NULL, 1);
10499106986SGuo Ren }
10599106986SGuo Ren 
10699106986SGuo Ren void smp_send_reschedule(int cpu)
10799106986SGuo Ren {
10899106986SGuo Ren 	send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
10999106986SGuo Ren }
11099106986SGuo Ren 
11199106986SGuo Ren void __init smp_prepare_boot_cpu(void)
11299106986SGuo Ren {
11399106986SGuo Ren }
11499106986SGuo Ren 
11599106986SGuo Ren void __init smp_prepare_cpus(unsigned int max_cpus)
11699106986SGuo Ren {
11799106986SGuo Ren }
11899106986SGuo Ren 
11999106986SGuo Ren static int ipi_dummy_dev;
120859e5f45SGuo Ren 
12199106986SGuo Ren void __init setup_smp_ipi(void)
12299106986SGuo Ren {
12399106986SGuo Ren 	int rc;
12499106986SGuo Ren 
12599106986SGuo Ren 	if (ipi_irq == 0)
126c9492737SGuo Ren 		return;
12799106986SGuo Ren 
12899106986SGuo Ren 	rc = request_percpu_irq(ipi_irq, handle_ipi, "IPI Interrupt",
12999106986SGuo Ren 				&ipi_dummy_dev);
13099106986SGuo Ren 	if (rc)
13199106986SGuo Ren 		panic("%s IRQ request failed\n", __func__);
13299106986SGuo Ren 
133859e5f45SGuo Ren 	enable_percpu_irq(ipi_irq, 0);
13499106986SGuo Ren }
13599106986SGuo Ren 
13699106986SGuo Ren void __init setup_smp(void)
13799106986SGuo Ren {
13899106986SGuo Ren 	struct device_node *node = NULL;
13999106986SGuo Ren 	int cpu;
14099106986SGuo Ren 
141398539ddSYangtao Li 	for_each_of_cpu_node(node) {
14299106986SGuo Ren 		if (!of_device_is_available(node))
14399106986SGuo Ren 			continue;
14499106986SGuo Ren 
14599106986SGuo Ren 		if (of_property_read_u32(node, "reg", &cpu))
14699106986SGuo Ren 			continue;
14799106986SGuo Ren 
14899106986SGuo Ren 		if (cpu >= NR_CPUS)
14999106986SGuo Ren 			continue;
15099106986SGuo Ren 
15199106986SGuo Ren 		set_cpu_possible(cpu, true);
15299106986SGuo Ren 		set_cpu_present(cpu, true);
15399106986SGuo Ren 	}
15499106986SGuo Ren }
15599106986SGuo Ren 
15699106986SGuo Ren extern void _start_smp_secondary(void);
15799106986SGuo Ren 
15899106986SGuo Ren volatile unsigned int secondary_hint;
15999106986SGuo Ren volatile unsigned int secondary_ccr;
16099106986SGuo Ren volatile unsigned int secondary_stack;
16199106986SGuo Ren 
162*aefd9461SGuo Ren unsigned long secondary_msa1;
163*aefd9461SGuo Ren 
16499106986SGuo Ren int __cpu_up(unsigned int cpu, struct task_struct *tidle)
16599106986SGuo Ren {
166859e5f45SGuo Ren 	unsigned long mask = 1 << cpu;
16799106986SGuo Ren 
1680f231dcfSGuo Ren 	secondary_stack =
1690f231dcfSGuo Ren 		(unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8;
17099106986SGuo Ren 	secondary_hint = mfcr("cr31");
17199106986SGuo Ren 	secondary_ccr  = mfcr("cr18");
172*aefd9461SGuo Ren 	secondary_msa1 = read_mmu_msa1();
17399106986SGuo Ren 
17499106986SGuo Ren 	/*
17599106986SGuo Ren 	 * Because other CPUs are in reset status, we must flush data
17699106986SGuo Ren 	 * from cache to out and secondary CPUs use them in
17799106986SGuo Ren 	 * csky_start_secondary(void)
17899106986SGuo Ren 	 */
17999106986SGuo Ren 	mtcr("cr17", 0x22);
18099106986SGuo Ren 
181859e5f45SGuo Ren 	if (mask & mfcr("cr<29, 0>")) {
182859e5f45SGuo Ren 		send_arch_ipi(cpumask_of(cpu));
183859e5f45SGuo Ren 	} else {
18499106986SGuo Ren 		/* Enable cpu in SMP reset ctrl reg */
185859e5f45SGuo Ren 		mask |= mfcr("cr<29, 0>");
186859e5f45SGuo Ren 		mtcr("cr<29, 0>", mask);
187859e5f45SGuo Ren 	}
18899106986SGuo Ren 
18999106986SGuo Ren 	/* Wait for the cpu online */
19099106986SGuo Ren 	while (!cpu_online(cpu));
19199106986SGuo Ren 
19299106986SGuo Ren 	secondary_stack = 0;
19399106986SGuo Ren 
19499106986SGuo Ren 	return 0;
19599106986SGuo Ren }
19699106986SGuo Ren 
19799106986SGuo Ren void __init smp_cpus_done(unsigned int max_cpus)
19899106986SGuo Ren {
19999106986SGuo Ren }
20099106986SGuo Ren 
20199106986SGuo Ren int setup_profiling_timer(unsigned int multiplier)
20299106986SGuo Ren {
20399106986SGuo Ren 	return -EINVAL;
20499106986SGuo Ren }
20599106986SGuo Ren 
20699106986SGuo Ren void csky_start_secondary(void)
20799106986SGuo Ren {
20899106986SGuo Ren 	struct mm_struct *mm = &init_mm;
20999106986SGuo Ren 	unsigned int cpu = smp_processor_id();
21099106986SGuo Ren 
21199106986SGuo Ren 	mtcr("cr31", secondary_hint);
21299106986SGuo Ren 	mtcr("cr18", secondary_ccr);
21399106986SGuo Ren 
21499106986SGuo Ren 	mtcr("vbr", vec_base);
21599106986SGuo Ren 
21699106986SGuo Ren 	flush_tlb_all();
21799106986SGuo Ren 	write_mmu_pagemask(0);
21899106986SGuo Ren 	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir);
21999106986SGuo Ren 	TLBMISS_HANDLER_SETUP_PGD_KERNEL(swapper_pg_dir);
22099106986SGuo Ren 
22199106986SGuo Ren #ifdef CONFIG_CPU_HAS_FPU
22299106986SGuo Ren 	init_fpu();
22399106986SGuo Ren #endif
22499106986SGuo Ren 
225859e5f45SGuo Ren 	enable_percpu_irq(ipi_irq, 0);
22699106986SGuo Ren 
22799106986SGuo Ren 	mmget(mm);
22899106986SGuo Ren 	mmgrab(mm);
22999106986SGuo Ren 	current->active_mm = mm;
23099106986SGuo Ren 	cpumask_set_cpu(cpu, mm_cpumask(mm));
23199106986SGuo Ren 
23299106986SGuo Ren 	notify_cpu_starting(cpu);
23399106986SGuo Ren 	set_cpu_online(cpu, true);
23499106986SGuo Ren 
23599106986SGuo Ren 	pr_info("CPU%u Online: %s...\n", cpu, __func__);
23699106986SGuo Ren 
23799106986SGuo Ren 	local_irq_enable();
23899106986SGuo Ren 	preempt_disable();
23999106986SGuo Ren 	cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
24099106986SGuo Ren }
241859e5f45SGuo Ren 
242859e5f45SGuo Ren #ifdef CONFIG_HOTPLUG_CPU
243859e5f45SGuo Ren int __cpu_disable(void)
244859e5f45SGuo Ren {
245859e5f45SGuo Ren 	unsigned int cpu = smp_processor_id();
246859e5f45SGuo Ren 
247859e5f45SGuo Ren 	set_cpu_online(cpu, false);
248859e5f45SGuo Ren 
249859e5f45SGuo Ren 	irq_migrate_all_off_this_cpu();
250859e5f45SGuo Ren 
251859e5f45SGuo Ren 	clear_tasks_mm_cpumask(cpu);
252859e5f45SGuo Ren 
253859e5f45SGuo Ren 	return 0;
254859e5f45SGuo Ren }
255859e5f45SGuo Ren 
256859e5f45SGuo Ren void __cpu_die(unsigned int cpu)
257859e5f45SGuo Ren {
258859e5f45SGuo Ren 	if (!cpu_wait_death(cpu, 5)) {
259859e5f45SGuo Ren 		pr_crit("CPU%u: shutdown failed\n", cpu);
260859e5f45SGuo Ren 		return;
261859e5f45SGuo Ren 	}
262859e5f45SGuo Ren 	pr_notice("CPU%u: shutdown\n", cpu);
263859e5f45SGuo Ren }
264859e5f45SGuo Ren 
265859e5f45SGuo Ren void arch_cpu_idle_dead(void)
266859e5f45SGuo Ren {
267859e5f45SGuo Ren 	idle_task_exit();
268859e5f45SGuo Ren 
269859e5f45SGuo Ren 	cpu_report_death();
270859e5f45SGuo Ren 
271859e5f45SGuo Ren 	while (!secondary_stack)
272859e5f45SGuo Ren 		arch_cpu_idle();
273859e5f45SGuo Ren 
274859e5f45SGuo Ren 	local_irq_disable();
275859e5f45SGuo Ren 
276859e5f45SGuo Ren 	asm volatile(
277859e5f45SGuo Ren 		"mov	sp, %0\n"
278859e5f45SGuo Ren 		"mov	r8, %0\n"
279859e5f45SGuo Ren 		"jmpi	csky_start_secondary"
280859e5f45SGuo Ren 		:
281859e5f45SGuo Ren 		: "r" (secondary_stack));
282859e5f45SGuo Ren }
283859e5f45SGuo Ren #endif
284