1 /* $NetBSD: interrupt.c,v 1.3 2024/11/19 08:28:01 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2022 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Simon Burge and Nick Hudson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "opt_multiprocessor.h" 33 34 #include <sys/cdefs.h> 35 36 __RCSID("$NetBSD: interrupt.c,v 1.3 2024/11/19 08:28:01 skrll Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 41 #include <sys/bus.h> 42 #include <sys/cpu.h> 43 #include <sys/kernel.h> 44 45 #include <machine/locore.h> 46 #include <machine/machdep.h> 47 #include <machine/sbi.h> 48 49 #include <riscv/dev/plicvar.h> 50 51 52 static void 53 riscv_intr_default_handler(struct trapframe *frame, register_t epc, 54 register_t status, register_t cause) 55 { 56 #if 1 57 panic("not supposed to get here"); 58 #else 59 struct cpu_info * const ci = curcpu(); 60 const int code = CAUSE_CODE(cause); 61 62 KASSERT(CAUSE_INTERRUPT_P(cause)); 63 64 ci->ci_intr_depth++; 65 switch (code) { 66 case IRQ_SUPERVISOR_SOFTWARE: 67 #ifdef MULTIPROCESSOR 68 ipi_handler(tf); 69 #else 70 panic("%s: SUPERVISOR SOFTWARE interrupt", __func__); 71 #endif 72 break; 73 case IRQ_SUPERVISOR_TIMER: { 74 struct clockframe cf = { 75 .cf_epc = epc, 76 .cf_status = status, 77 .cf_intr_depth = ci->ci_intr_depth 78 }; 79 timer_handler(&cf); 80 break; 81 } 82 case IRQ_SUPERVISOR_EXTERNAL: 83 extintr_handler(tf); 84 break; 85 default: 86 panic("%s: unknown exception code %u", __func__, code); 87 } 88 ci->ci_intr_depth--; 89 #endif 90 } 91 92 93 static void (*_riscv_intr_handler)(struct trapframe *, register_t, 94 register_t, register_t) = riscv_intr_default_handler; 95 96 97 void 98 riscv_intr_set_handler(void (*intr_handler)(struct trapframe *, register_t, 99 register_t, register_t)) 100 { 101 KASSERT(_riscv_intr_handler == riscv_intr_default_handler || 102 _riscv_intr_handler == intr_handler); 103 _riscv_intr_handler = intr_handler; 104 } 105 106 107 void 108 cpu_intr(struct trapframe *tf, register_t epc, register_t status, 109 register_t cause) 110 { 111 _riscv_intr_handler(tf, epc, status, cause); 112 } 113 114 115 void * 116 intr_establish_xname(int irq, int ipl, int type, int (*func)(void *), void *arg, 117 const char *xname) 118 { 119 KASSERT(!cpu_intr_p()); 120 KASSERT(!cpu_softintr_p()); 121 122 return plic_intr_establish_xname(irq, ipl, type, func, arg, xname); 123 } 124 125 void * 126 intr_establish(int irq, int ipl, int type, int (*func)(void *), void *arg) 127 { 128 return intr_establish_xname(irq, ipl, type, func, arg, NULL); 129 } 130 131 void 132 intr_disestablish(void *ih) 133 { 134 // struct intrsource * const is = ih; 135 136 KASSERT(!cpu_intr_p()); 137 KASSERT(!cpu_softintr_p()); 138 } 139 140 141 #ifdef MULTIPROCESSOR 142 __CTASSERT(NIPIS < 16); 143 144 int 145 riscv_ipi_intr(void *arg) 146 { 147 struct cpu_info * const ci = curcpu(); 148 membar_acquire(); 149 150 csr_sip_clear(SIP_SSIP); /* clean pending interrupt status */ 151 152 unsigned long pending; 153 while ((pending = atomic_swap_ulong(&ci->ci_request_ipis, 0)) != 0) { 154 membar_acquire(); 155 atomic_or_ulong(&ci->ci_active_ipis, pending); 156 157 ipi_process(ci, pending); 158 159 atomic_and_ulong(&ci->ci_active_ipis, pending); 160 } 161 162 return 1; 163 } 164 165 int 166 cpu_send_ipi(struct cpu_info *ci, int req) 167 { 168 KASSERT(req < NIPIS); 169 if (ci == NULL) { 170 CPU_INFO_ITERATOR cii; 171 for (CPU_INFO_FOREACH(cii, ci)) { 172 if (ci != curcpu()) { 173 cpu_send_ipi(ci, req); 174 } 175 } 176 return 0; 177 } 178 const uint32_t ipi_mask = __BIT(req); 179 180 membar_release(); 181 atomic_or_ulong(&ci->ci_request_ipis, ipi_mask); 182 183 membar_release(); 184 unsigned long hartmask = 0; 185 const cpuid_t hartid = ci->ci_cpuid; 186 KASSERT(hartid < sizeof(unsigned long) * NBBY); 187 hartmask |= __BIT(hartid); 188 struct sbiret sbiret = sbi_send_ipi(hartmask, 0); 189 190 KASSERT(sbiret.error == SBI_SUCCESS); 191 192 return 0; 193 } 194 #endif /* MULTIPROCESSOR */ 195