1 /* 2 * SMP initialisation and IPI support 3 * Based on arch/arm64/kernel/smp.c 4 * 5 * Copyright (C) 2012 ARM Ltd. 6 * Copyright (C) 2015 Regents of the University of California 7 * Copyright (C) 2017 SiFive 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include <linux/interrupt.h> 23 #include <linux/smp.h> 24 #include <linux/sched.h> 25 26 #include <asm/sbi.h> 27 #include <asm/tlbflush.h> 28 #include <asm/cacheflush.h> 29 30 /* A collection of single bit ipi messages. */ 31 static struct { 32 unsigned long bits ____cacheline_aligned; 33 } ipi_data[NR_CPUS] __cacheline_aligned; 34 35 enum ipi_message_type { 36 IPI_RESCHEDULE, 37 IPI_CALL_FUNC, 38 IPI_MAX 39 }; 40 41 irqreturn_t handle_ipi(void) 42 { 43 unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; 44 45 /* Clear pending IPI */ 46 csr_clear(sip, SIE_SSIE); 47 48 while (true) { 49 unsigned long ops; 50 51 /* Order bit clearing and data access. */ 52 mb(); 53 54 ops = xchg(pending_ipis, 0); 55 if (ops == 0) 56 return IRQ_HANDLED; 57 58 if (ops & (1 << IPI_RESCHEDULE)) 59 scheduler_ipi(); 60 61 if (ops & (1 << IPI_CALL_FUNC)) 62 generic_smp_call_function_interrupt(); 63 64 BUG_ON((ops >> IPI_MAX) != 0); 65 66 /* Order data access and bit testing. */ 67 mb(); 68 } 69 70 return IRQ_HANDLED; 71 } 72 73 static void 74 send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) 75 { 76 int i; 77 78 mb(); 79 for_each_cpu(i, to_whom) 80 set_bit(operation, &ipi_data[i].bits); 81 82 mb(); 83 sbi_send_ipi(cpumask_bits(to_whom)); 84 } 85 86 void arch_send_call_function_ipi_mask(struct cpumask *mask) 87 { 88 send_ipi_message(mask, IPI_CALL_FUNC); 89 } 90 91 void arch_send_call_function_single_ipi(int cpu) 92 { 93 send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC); 94 } 95 96 static void ipi_stop(void *unused) 97 { 98 while (1) 99 wait_for_interrupt(); 100 } 101 102 void smp_send_stop(void) 103 { 104 on_each_cpu(ipi_stop, NULL, 1); 105 } 106 107 void smp_send_reschedule(int cpu) 108 { 109 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); 110 } 111