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 */
sb1250_smp_init(void)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 */
sb1250_send_ipi_single(int cpu,unsigned int action)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
sb1250_send_ipi_mask(const struct cpumask * mask,unsigned int action)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 */
sb1250_init_secondary(void)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 */
sb1250_smp_finish(void)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 */
sb1250_boot_secondary(int cpu,struct task_struct * idle)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 */
sb1250_smp_setup(void)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
sb1250_prepare_cpus(unsigned int max_cpus)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
sb1250_mailbox_interrupt(void)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