1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2001, 2002, 2003 Broadcom Corporation 4 */ 5 6 #include <linux/init.h> 7 #include <linux/delay.h> 8 #include <linux/interrupt.h> 9 #include <linux/smp.h> 10 #include <linux/kernel_stat.h> 11 #include <linux/sched/task_stack.h> 12 13 #include <asm/mmu_context.h> 14 #include <asm/io.h> 15 #include <asm/fw/cfe/cfe_api.h> 16 #include <asm/sibyte/sb1250.h> 17 #include <asm/sibyte/sb1250_regs.h> 18 #include <asm/sibyte/sb1250_int.h> 19 20 static void *mailbox_set_regs[] = { 21 IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_SET_CPU), 22 IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_SET_CPU) 23 }; 24 25 static void *mailbox_clear_regs[] = { 26 IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CLR_CPU), 27 IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CLR_CPU) 28 }; 29 30 static void *mailbox_regs[] = { 31 IOADDR(A_IMR_CPU0_BASE + R_IMR_MAILBOX_CPU), 32 IOADDR(A_IMR_CPU1_BASE + R_IMR_MAILBOX_CPU) 33 }; 34 35 /* 36 * SMP init and finish on secondary CPUs 37 */ 38 void sb1250_smp_init(void) 39 { 40 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 41 STATUSF_IP1 | STATUSF_IP0; 42 43 /* Set interrupt mask, but don't enable */ 44 change_c0_status(ST0_IM, imask); 45 } 46 47 /* 48 * These are routines for dealing with the sb1250 smp capabilities 49 * independent of board/firmware 50 */ 51 52 /* 53 * Simple enough; everything is set up, so just poke the appropriate mailbox 54 * register, and we should be set 55 */ 56 static void sb1250_send_ipi_single(int cpu, unsigned int action) 57 { 58 __raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]); 59 } 60 61 static inline void sb1250_send_ipi_mask(const struct cpumask *mask, 62 unsigned int action) 63 { 64 unsigned int i; 65 66 for_each_cpu(i, mask) 67 sb1250_send_ipi_single(i, action); 68 } 69 70 /* 71 * Code to run on secondary just after probing the CPU 72 */ 73 static void sb1250_init_secondary(void) 74 { 75 extern void sb1250_smp_init(void); 76 77 sb1250_smp_init(); 78 } 79 80 /* 81 * Do any tidying up before marking online and running the idle 82 * loop 83 */ 84 static void sb1250_smp_finish(void) 85 { 86 extern void sb1250_clockevent_init(void); 87 88 sb1250_clockevent_init(); 89 local_irq_enable(); 90 } 91 92 /* 93 * Setup the PC, SP, and GP of a secondary processor and start it 94 * running! 95 */ 96 static int sb1250_boot_secondary(int cpu, struct task_struct *idle) 97 { 98 int retval; 99 100 retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap, 101 __KSTK_TOS(idle), 102 (unsigned long)task_thread_info(idle), 0); 103 if (retval != 0) 104 printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval); 105 return retval; 106 } 107 108 /* 109 * Use CFE to find out how many CPUs are available, setting up 110 * cpu_possible_mask and the logical/physical mappings. 111 * XXXKW will the boot CPU ever not be physical 0? 112 * 113 * Common setup before any secondaries are started 114 */ 115 static void __init sb1250_smp_setup(void) 116 { 117 int i, num; 118 119 init_cpu_possible(cpumask_of(0)); 120 __cpu_number_map[0] = 0; 121 __cpu_logical_map[0] = 0; 122 123 for (i = 1, num = 0; i < NR_CPUS; i++) { 124 if (cfe_cpu_stop(i) == 0) { 125 set_cpu_possible(i, true); 126 __cpu_number_map[i] = ++num; 127 __cpu_logical_map[num] = i; 128 } 129 } 130 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); 131 } 132 133 static void __init sb1250_prepare_cpus(unsigned int max_cpus) 134 { 135 } 136 137 const struct plat_smp_ops sb_smp_ops = { 138 .send_ipi_single = sb1250_send_ipi_single, 139 .send_ipi_mask = sb1250_send_ipi_mask, 140 .init_secondary = sb1250_init_secondary, 141 .smp_finish = sb1250_smp_finish, 142 .boot_secondary = sb1250_boot_secondary, 143 .smp_setup = sb1250_smp_setup, 144 .prepare_cpus = sb1250_prepare_cpus, 145 }; 146 147 void sb1250_mailbox_interrupt(void) 148 { 149 int cpu = smp_processor_id(); 150 int irq = K_INT_MBOX_0; 151 unsigned int action; 152 153 kstat_incr_irq_this_cpu(irq); 154 /* Load the mailbox register to figure out what we're supposed to do */ 155 action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff; 156 157 /* Clear the mailbox to clear the interrupt */ 158 ____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]); 159 160 if (action & SMP_RESCHEDULE_YOURSELF) 161 scheduler_ipi(); 162 163 if (action & SMP_CALL_FUNCTION) { 164 irq_enter(); 165 generic_smp_call_function_interrupt(); 166 irq_exit(); 167 } 168 } 169
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.