xref: /linux/arch/mips/sibyte/bcm1480/smp.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f137e463SAndrew Isaacson /*
3f137e463SAndrew Isaacson  * Copyright (C) 2001,2002,2004 Broadcom Corporation
4f137e463SAndrew Isaacson  */
5f137e463SAndrew Isaacson 
6f137e463SAndrew Isaacson #include <linux/init.h>
7f137e463SAndrew Isaacson #include <linux/delay.h>
8f137e463SAndrew Isaacson #include <linux/smp.h>
9f137e463SAndrew Isaacson #include <linux/kernel_stat.h>
10184748ccSPeter Zijlstra #include <linux/sched.h>
1168db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
12f137e463SAndrew Isaacson 
13f137e463SAndrew Isaacson #include <asm/mmu_context.h>
14f137e463SAndrew Isaacson #include <asm/io.h>
1587353d8aSRalf Baechle #include <asm/fw/cfe/cfe_api.h>
16f137e463SAndrew Isaacson #include <asm/sibyte/sb1250.h>
17f137e463SAndrew Isaacson #include <asm/sibyte/bcm1480_regs.h>
18f137e463SAndrew Isaacson #include <asm/sibyte/bcm1480_int.h>
19f137e463SAndrew Isaacson 
20f137e463SAndrew Isaacson /*
21f137e463SAndrew Isaacson  * These are routines for dealing with the bcm1480 smp capabilities
22f137e463SAndrew Isaacson  * independent of board/firmware
23f137e463SAndrew Isaacson  */
24f137e463SAndrew Isaacson 
258fb303c7SRalf Baechle static void *mailbox_0_set_regs[] = {
26f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
27f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
28f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
29f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
30f137e463SAndrew Isaacson };
31f137e463SAndrew Isaacson 
328fb303c7SRalf Baechle static void *mailbox_0_clear_regs[] = {
33f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
34f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
35f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
36f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
37f137e463SAndrew Isaacson };
38f137e463SAndrew Isaacson 
398fb303c7SRalf Baechle static void *mailbox_0_regs[] = {
40f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
41f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
42f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
43f137e463SAndrew Isaacson 	IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
44f137e463SAndrew Isaacson };
45f137e463SAndrew Isaacson 
46f137e463SAndrew Isaacson /*
47f137e463SAndrew Isaacson  * SMP init and finish on secondary CPUs
48f137e463SAndrew Isaacson  */
bcm1480_smp_init(void)49078a55fcSPaul Gortmaker void bcm1480_smp_init(void)
50f137e463SAndrew Isaacson {
51f137e463SAndrew Isaacson 	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
52f137e463SAndrew Isaacson 		STATUSF_IP1 | STATUSF_IP0;
53f137e463SAndrew Isaacson 
54f137e463SAndrew Isaacson 	/* Set interrupt mask, but don't enable */
55f137e463SAndrew Isaacson 	change_c0_status(ST0_IM, imask);
56f137e463SAndrew Isaacson }
57f137e463SAndrew Isaacson 
58f137e463SAndrew Isaacson /*
59f137e463SAndrew Isaacson  * These are routines for dealing with the sb1250 smp capabilities
60f137e463SAndrew Isaacson  * independent of board/firmware
61f137e463SAndrew Isaacson  */
62f137e463SAndrew Isaacson 
63f137e463SAndrew Isaacson /*
64f137e463SAndrew Isaacson  * Simple enough; everything is set up, so just poke the appropriate mailbox
65f137e463SAndrew Isaacson  * register, and we should be set
66f137e463SAndrew Isaacson  */
bcm1480_send_ipi_single(int cpu,unsigned int action)6787353d8aSRalf Baechle static void bcm1480_send_ipi_single(int cpu, unsigned int action)
68f137e463SAndrew Isaacson {
69f137e463SAndrew Isaacson 	__raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
70f137e463SAndrew Isaacson }
71f137e463SAndrew Isaacson 
bcm1480_send_ipi_mask(const struct cpumask * mask,unsigned int action)7248a048feSRusty Russell static void bcm1480_send_ipi_mask(const struct cpumask *mask,
7348a048feSRusty Russell 				  unsigned int action)
7487353d8aSRalf Baechle {
7587353d8aSRalf Baechle 	unsigned int i;
7687353d8aSRalf Baechle 
7748a048feSRusty Russell 	for_each_cpu(i, mask)
7887353d8aSRalf Baechle 		bcm1480_send_ipi_single(i, action);
7987353d8aSRalf Baechle }
8087353d8aSRalf Baechle 
8187353d8aSRalf Baechle /*
8287353d8aSRalf Baechle  * Code to run on secondary just after probing the CPU
8387353d8aSRalf Baechle  */
bcm1480_init_secondary(void)84078a55fcSPaul Gortmaker static void bcm1480_init_secondary(void)
8587353d8aSRalf Baechle {
8687353d8aSRalf Baechle 	extern void bcm1480_smp_init(void);
8787353d8aSRalf Baechle 
8887353d8aSRalf Baechle 	bcm1480_smp_init();
8987353d8aSRalf Baechle }
9087353d8aSRalf Baechle 
9187353d8aSRalf Baechle /*
9287353d8aSRalf Baechle  * Do any tidying up before marking online and running the idle
9387353d8aSRalf Baechle  * loop
9487353d8aSRalf Baechle  */
bcm1480_smp_finish(void)95078a55fcSPaul Gortmaker static void bcm1480_smp_finish(void)
9687353d8aSRalf Baechle {
9787353d8aSRalf Baechle 	extern void sb1480_clockevent_init(void);
9887353d8aSRalf Baechle 
9987353d8aSRalf Baechle 	sb1480_clockevent_init();
10087353d8aSRalf Baechle 	local_irq_enable();
10187353d8aSRalf Baechle }
10287353d8aSRalf Baechle 
10387353d8aSRalf Baechle /*
10487353d8aSRalf Baechle  * Setup the PC, SP, and GP of a secondary processor and start it
10587353d8aSRalf Baechle  * running!
10687353d8aSRalf Baechle  */
bcm1480_boot_secondary(int cpu,struct task_struct * idle)107d595d423SPaul Burton static int bcm1480_boot_secondary(int cpu, struct task_struct *idle)
10887353d8aSRalf Baechle {
10987353d8aSRalf Baechle 	int retval;
11087353d8aSRalf Baechle 
11187353d8aSRalf Baechle 	retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
11287353d8aSRalf Baechle 			       __KSTK_TOS(idle),
11387353d8aSRalf Baechle 			       (unsigned long)task_thread_info(idle), 0);
11487353d8aSRalf Baechle 	if (retval != 0)
11587353d8aSRalf Baechle 		printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
116d595d423SPaul Burton 	return retval;
11787353d8aSRalf Baechle }
11887353d8aSRalf Baechle 
11987353d8aSRalf Baechle /*
12087353d8aSRalf Baechle  * Use CFE to find out how many CPUs are available, setting up
1215f054e31SRusty Russell  * cpu_possible_mask and the logical/physical mappings.
12287353d8aSRalf Baechle  * XXXKW will the boot CPU ever not be physical 0?
12387353d8aSRalf Baechle  *
12487353d8aSRalf Baechle  * Common setup before any secondaries are started
12587353d8aSRalf Baechle  */
bcm1480_smp_setup(void)12687353d8aSRalf Baechle static void __init bcm1480_smp_setup(void)
12787353d8aSRalf Baechle {
12887353d8aSRalf Baechle 	int i, num;
12987353d8aSRalf Baechle 
1300b5f9c00SRusty Russell 	init_cpu_possible(cpumask_of(0));
13187353d8aSRalf Baechle 	__cpu_number_map[0] = 0;
13287353d8aSRalf Baechle 	__cpu_logical_map[0] = 0;
13387353d8aSRalf Baechle 
13487353d8aSRalf Baechle 	for (i = 1, num = 0; i < NR_CPUS; i++) {
13587353d8aSRalf Baechle 		if (cfe_cpu_stop(i) == 0) {
1360b5f9c00SRusty Russell 			set_cpu_possible(i, true);
13787353d8aSRalf Baechle 			__cpu_number_map[i] = ++num;
13887353d8aSRalf Baechle 			__cpu_logical_map[num] = i;
13987353d8aSRalf Baechle 		}
14087353d8aSRalf Baechle 	}
14187353d8aSRalf Baechle 	printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
14287353d8aSRalf Baechle }
14387353d8aSRalf Baechle 
bcm1480_prepare_cpus(unsigned int max_cpus)14487353d8aSRalf Baechle static void __init bcm1480_prepare_cpus(unsigned int max_cpus)
14587353d8aSRalf Baechle {
14687353d8aSRalf Baechle }
14787353d8aSRalf Baechle 
148ff2c8252SMatt Redfearn const struct plat_smp_ops bcm1480_smp_ops = {
14987353d8aSRalf Baechle 	.send_ipi_single	= bcm1480_send_ipi_single,
15087353d8aSRalf Baechle 	.send_ipi_mask		= bcm1480_send_ipi_mask,
15187353d8aSRalf Baechle 	.init_secondary		= bcm1480_init_secondary,
15287353d8aSRalf Baechle 	.smp_finish		= bcm1480_smp_finish,
15387353d8aSRalf Baechle 	.boot_secondary		= bcm1480_boot_secondary,
15487353d8aSRalf Baechle 	.smp_setup		= bcm1480_smp_setup,
15587353d8aSRalf Baechle 	.prepare_cpus		= bcm1480_prepare_cpus,
15687353d8aSRalf Baechle };
15787353d8aSRalf Baechle 
bcm1480_mailbox_interrupt(void)158937a8015SRalf Baechle void bcm1480_mailbox_interrupt(void)
159f137e463SAndrew Isaacson {
160f137e463SAndrew Isaacson 	int cpu = smp_processor_id();
161d2287f5eSMike Travis 	int irq = K_BCM1480_INT_MBOX_0_0;
162f137e463SAndrew Isaacson 	unsigned int action;
163f137e463SAndrew Isaacson 
164310ff2c8SThomas Gleixner 	kstat_incr_irq_this_cpu(irq);
165f137e463SAndrew Isaacson 	/* Load the mailbox register to figure out what we're supposed to do */
166f137e463SAndrew Isaacson 	action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
167f137e463SAndrew Isaacson 
168f137e463SAndrew Isaacson 	/* Clear the mailbox to clear the interrupt */
169f137e463SAndrew Isaacson 	__raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]);
170f137e463SAndrew Isaacson 
171184748ccSPeter Zijlstra 	if (action & SMP_RESCHEDULE_YOURSELF)
172184748ccSPeter Zijlstra 		scheduler_ipi();
173f137e463SAndrew Isaacson 
1744ace6139SAlex Smith 	if (action & SMP_CALL_FUNCTION) {
1754ace6139SAlex Smith 		irq_enter();
1764ace6139SAlex Smith 		generic_smp_call_function_interrupt();
1774ace6139SAlex Smith 		irq_exit();
1784ace6139SAlex Smith 	}
179f137e463SAndrew Isaacson }
180