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