xref: /linux/arch/mips/sibyte/sb1250/smp.c (revision 1a59d1b8e05ea6ab45f7e18897de1ef0e6bc3da6)
1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <linux/init.h>
71da177e4SLinus Torvalds #include <linux/delay.h>
81da177e4SLinus Torvalds #include <linux/interrupt.h>
91da177e4SLinus Torvalds #include <linux/smp.h>
101da177e4SLinus Torvalds #include <linux/kernel_stat.h>
11f3ac6067SIngo Molnar #include <linux/sched/task_stack.h>
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #include <asm/mmu_context.h>
141da177e4SLinus Torvalds #include <asm/io.h>
1587353d8aSRalf Baechle #include <asm/fw/cfe/cfe_api.h>
161da177e4SLinus Torvalds #include <asm/sibyte/sb1250.h>
171da177e4SLinus Torvalds #include <asm/sibyte/sb1250_regs.h>
181da177e4SLinus Torvalds #include <asm/sibyte/sb1250_int.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds static void *mailbox_set_regs[] = {
2165bda1a9SMaciej W. Rozycki 	IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU),
2265bda1a9SMaciej W. Rozycki 	IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU)
231da177e4SLinus Torvalds };
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds static void *mailbox_clear_regs[] = {
2665bda1a9SMaciej W. Rozycki 	IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU),
2765bda1a9SMaciej W. Rozycki 	IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU)
281da177e4SLinus Torvalds };
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds static void *mailbox_regs[] = {
3165bda1a9SMaciej W. Rozycki 	IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU),
3265bda1a9SMaciej W. Rozycki 	IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU)
331da177e4SLinus Torvalds };
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds /*
361da177e4SLinus Torvalds  * SMP init and finish on secondary CPUs
371da177e4SLinus Torvalds  */
38078a55fcSPaul Gortmaker void sb1250_smp_init(void)
391da177e4SLinus Torvalds {
401da177e4SLinus Torvalds 	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
411da177e4SLinus Torvalds 		STATUSF_IP1 | STATUSF_IP0;
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	/* Set interrupt mask, but don't enable */
441da177e4SLinus Torvalds 	change_c0_status(ST0_IM, imask);
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds /*
481da177e4SLinus Torvalds  * These are routines for dealing with the sb1250 smp capabilities
491da177e4SLinus Torvalds  * independent of board/firmware
501da177e4SLinus Torvalds  */
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds /*
531da177e4SLinus Torvalds  * Simple enough; everything is set up, so just poke the appropriate mailbox
541da177e4SLinus Torvalds  * register, and we should be set
551da177e4SLinus Torvalds  */
5687353d8aSRalf Baechle static void sb1250_send_ipi_single(int cpu, unsigned int action)
571da177e4SLinus Torvalds {
5865bda1a9SMaciej W. Rozycki 	__raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]);
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
6148a048feSRusty Russell static inline void sb1250_send_ipi_mask(const struct cpumask *mask,
6248a048feSRusty Russell 					unsigned int action)
6387353d8aSRalf Baechle {
6487353d8aSRalf Baechle 	unsigned int i;
6587353d8aSRalf Baechle 
6648a048feSRusty Russell 	for_each_cpu(i, mask)
6787353d8aSRalf Baechle 		sb1250_send_ipi_single(i, action);
6887353d8aSRalf Baechle }
6987353d8aSRalf Baechle 
7087353d8aSRalf Baechle /*
7187353d8aSRalf Baechle  * Code to run on secondary just after probing the CPU
7287353d8aSRalf Baechle  */
73078a55fcSPaul Gortmaker static void sb1250_init_secondary(void)
7487353d8aSRalf Baechle {
7587353d8aSRalf Baechle 	extern void sb1250_smp_init(void);
7687353d8aSRalf Baechle 
7787353d8aSRalf Baechle 	sb1250_smp_init();
7887353d8aSRalf Baechle }
7987353d8aSRalf Baechle 
8087353d8aSRalf Baechle /*
8187353d8aSRalf Baechle  * Do any tidying up before marking online and running the idle
8287353d8aSRalf Baechle  * loop
8387353d8aSRalf Baechle  */
84078a55fcSPaul Gortmaker static void sb1250_smp_finish(void)
8587353d8aSRalf Baechle {
8687353d8aSRalf Baechle 	extern void sb1250_clockevent_init(void);
8787353d8aSRalf Baechle 
8887353d8aSRalf Baechle 	sb1250_clockevent_init();
8987353d8aSRalf Baechle 	local_irq_enable();
9087353d8aSRalf Baechle }
9187353d8aSRalf Baechle 
9287353d8aSRalf Baechle /*
9387353d8aSRalf Baechle  * Setup the PC, SP, and GP of a secondary processor and start it
9487353d8aSRalf Baechle  * running!
9587353d8aSRalf Baechle  */
96d595d423SPaul Burton static int sb1250_boot_secondary(int cpu, struct task_struct *idle)
9787353d8aSRalf Baechle {
9887353d8aSRalf Baechle 	int retval;
9987353d8aSRalf Baechle 
10087353d8aSRalf Baechle 	retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap,
10187353d8aSRalf Baechle 			       __KSTK_TOS(idle),
10287353d8aSRalf Baechle 			       (unsigned long)task_thread_info(idle), 0);
10387353d8aSRalf Baechle 	if (retval != 0)
10487353d8aSRalf Baechle 		printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval);
105d595d423SPaul Burton 	return retval;
10687353d8aSRalf Baechle }
10787353d8aSRalf Baechle 
10887353d8aSRalf Baechle /*
10987353d8aSRalf Baechle  * Use CFE to find out how many CPUs are available, setting up
1100b5f9c00SRusty Russell  * cpu_possible_mask and the logical/physical mappings.
11187353d8aSRalf Baechle  * XXXKW will the boot CPU ever not be physical 0?
11287353d8aSRalf Baechle  *
11387353d8aSRalf Baechle  * Common setup before any secondaries are started
11487353d8aSRalf Baechle  */
11587353d8aSRalf Baechle static void __init sb1250_smp_setup(void)
11687353d8aSRalf Baechle {
11787353d8aSRalf Baechle 	int i, num;
11887353d8aSRalf Baechle 
1190b5f9c00SRusty Russell 	init_cpu_possible(cpumask_of(0));
12087353d8aSRalf Baechle 	__cpu_number_map[0] = 0;
12187353d8aSRalf Baechle 	__cpu_logical_map[0] = 0;
12287353d8aSRalf Baechle 
12387353d8aSRalf Baechle 	for (i = 1, num = 0; i < NR_CPUS; i++) {
12487353d8aSRalf Baechle 		if (cfe_cpu_stop(i) == 0) {
1250b5f9c00SRusty Russell 			set_cpu_possible(i, true);
12687353d8aSRalf Baechle 			__cpu_number_map[i] = ++num;
12787353d8aSRalf Baechle 			__cpu_logical_map[num] = i;
12887353d8aSRalf Baechle 		}
12987353d8aSRalf Baechle 	}
13087353d8aSRalf Baechle 	printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
13187353d8aSRalf Baechle }
13287353d8aSRalf Baechle 
13387353d8aSRalf Baechle static void __init sb1250_prepare_cpus(unsigned int max_cpus)
13487353d8aSRalf Baechle {
13587353d8aSRalf Baechle }
13687353d8aSRalf Baechle 
137ff2c8252SMatt Redfearn const struct plat_smp_ops sb_smp_ops = {
13887353d8aSRalf Baechle 	.send_ipi_single	= sb1250_send_ipi_single,
13987353d8aSRalf Baechle 	.send_ipi_mask		= sb1250_send_ipi_mask,
14087353d8aSRalf Baechle 	.init_secondary		= sb1250_init_secondary,
14187353d8aSRalf Baechle 	.smp_finish		= sb1250_smp_finish,
14287353d8aSRalf Baechle 	.boot_secondary		= sb1250_boot_secondary,
14387353d8aSRalf Baechle 	.smp_setup		= sb1250_smp_setup,
14487353d8aSRalf Baechle 	.prepare_cpus		= sb1250_prepare_cpus,
14587353d8aSRalf Baechle };
14687353d8aSRalf Baechle 
147937a8015SRalf Baechle void sb1250_mailbox_interrupt(void)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	int cpu = smp_processor_id();
150d2287f5eSMike Travis 	int irq = K_INT_MBOX_0;
1511da177e4SLinus Torvalds 	unsigned int action;
1521da177e4SLinus Torvalds 
153310ff2c8SThomas Gleixner 	kstat_incr_irq_this_cpu(irq);
1541da177e4SLinus Torvalds 	/* Load the mailbox register to figure out what we're supposed to do */
15565bda1a9SMaciej W. Rozycki 	action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	/* Clear the mailbox to clear the interrupt */
15865bda1a9SMaciej W. Rozycki 	____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]);
1591da177e4SLinus Torvalds 
160184748ccSPeter Zijlstra 	if (action & SMP_RESCHEDULE_YOURSELF)
161184748ccSPeter Zijlstra 		scheduler_ipi();
1621da177e4SLinus Torvalds 
1634ace6139SAlex Smith 	if (action & SMP_CALL_FUNCTION) {
1644ace6139SAlex Smith 		irq_enter();
1654ace6139SAlex Smith 		generic_smp_call_function_interrupt();
1664ace6139SAlex Smith 		irq_exit();
1674ace6139SAlex Smith 	}
1681da177e4SLinus Torvalds }
169