1/*- 2 * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD$"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/bus.h> 41#include <sys/cpuset.h> 42#include <sys/interrupt.h> 43#include <sys/smp.h> 44 45#include <machine/clock.h> 46#include <machine/cpu.h> 47#include <machine/cpufunc.h> 48#include <machine/frame.h> 49#include <machine/intr.h> 50 51#ifdef SMP 52#include <machine/smp.h> 53#endif 54 55u_long intrcnt[NIRQS]; 56size_t sintrcnt = sizeof(intrcnt); 57 58char intrnames[NIRQS * (MAXCOMLEN + 1) * 2]; 59size_t sintrnames = sizeof(intrnames); 60 61static struct intr_event *intr_events[NIRQS]; 62static riscv_intrcnt_t riscv_intr_counters[NIRQS]; 63 64static int intrcnt_index; 65 66riscv_intrcnt_t 67riscv_intrcnt_create(const char* name) 68{ 69 riscv_intrcnt_t counter; 70 71 counter = &intrcnt[intrcnt_index++]; 72 riscv_intrcnt_setname(counter, name); 73 74 return (counter); 75} 76 77void 78riscv_intrcnt_setname(riscv_intrcnt_t counter, const char *name) 79{ 80 int i; 81 82 i = (counter - intrcnt); 83 84 KASSERT(counter != NULL, ("riscv_intrcnt_setname: NULL counter")); 85 86 snprintf(intrnames + (MAXCOMLEN + 1) * i, 87 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); 88} 89 90static void 91riscv_mask_irq(void *source) 92{ 93 uintptr_t irq; 94 95 irq = (uintptr_t)source; 96 97 switch (irq) { 98 case IRQ_TIMER: 99 csr_clear(sie, SIE_STIE); 100 break; 101 case IRQ_SOFTWARE: 102 csr_clear(sie, SIE_SSIE); 103 break; 104 case IRQ_UART: 105 machine_command(ECALL_IO_IRQ_MASK, 0); 106 break; 107 default: 108 panic("Unknown irq %d\n", irq); 109 } 110} 111 112static void 113riscv_unmask_irq(void *source) 114{ 115 uintptr_t irq; 116 117 irq = (uintptr_t)source; 118 119 switch (irq) { 120 case IRQ_TIMER: 121 csr_set(sie, SIE_STIE); 122 break; 123 case IRQ_SOFTWARE: 124 csr_set(sie, SIE_SSIE); 125 break; 126 case IRQ_UART: 127 machine_command(ECALL_IO_IRQ_MASK, 1); 128 break; 129 default: 130 panic("Unknown irq %d\n", irq); 131 } 132} 133 134void 135riscv_init_interrupts(void) 136{ 137 char name[MAXCOMLEN + 1]; 138 int i; 139 140 for (i = 0; i < NIRQS; i++) { 141 snprintf(name, MAXCOMLEN + 1, "int%d:", i); 142 riscv_intr_counters[i] = riscv_intrcnt_create(name); 143 } 144} 145 146int 147riscv_setup_intr(const char *name, driver_filter_t *filt, 148 void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) 149{ 150 struct intr_event *event; 151 int error; 152 153 if (irq < 0 || irq >= NIRQS) 154 panic("%s: unknown intr %d", __func__, irq); 155 156 event = intr_events[irq]; 157 if (event == NULL) { 158 error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, 159 irq, riscv_mask_irq, riscv_unmask_irq, 160 NULL, NULL, "int%d", irq); 161 if (error) 162 return (error); 163 intr_events[irq] = event; 164 riscv_unmask_irq((void*)(uintptr_t)irq); 165 } 166 167 error = intr_event_add_handler(event, name, filt, handler, arg, 168 intr_priority(flags), flags, cookiep); 169 if (error) { 170 printf("Failed to setup intr: %d\n", irq); 171 return (error); 172 } 173 174 riscv_intrcnt_setname(riscv_intr_counters[irq], 175 event->ie_fullname); 176 177 return (0); 178} 179 180int 181riscv_teardown_intr(void *ih) 182{ 183 184 /* TODO */ 185 186 return (0); 187} 188 189int 190riscv_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol) 191{ 192 193 /* There is no configuration for interrupts */ 194 195 return (0); 196} 197 198void 199riscv_cpu_intr(struct trapframe *frame) 200{ 201 struct intr_event *event; 202 int active_irq; 203 204 critical_enter(); 205 206 KASSERT(frame->tf_scause & EXCP_INTR, 207 ("riscv_cpu_intr: wrong frame passed")); 208 209 active_irq = (frame->tf_scause & EXCP_MASK); 210 211 switch (active_irq) { 212 case IRQ_UART: 213 case IRQ_SOFTWARE: 214 case IRQ_TIMER: 215 event = intr_events[active_irq]; 216 /* Update counters */ 217 atomic_add_long(riscv_intr_counters[active_irq], 1); 218 PCPU_INC(cnt.v_intr); 219 break; 220 case IRQ_HTIF: 221 /* HTIF interrupts are only handled in machine mode */ 222 panic("%s: HTIF interrupt", __func__); 223 break; 224 default: 225 event = NULL; 226 } 227 228 if (!event || TAILQ_EMPTY(&event->ie_handlers) || 229 (intr_event_handle(event, frame) != 0)) 230 printf("stray interrupt %d\n", active_irq); 231 232 critical_exit(); 233} 234 235#ifdef SMP 236void 237riscv_setup_ipihandler(driver_filter_t *filt) 238{ 239 240 riscv_setup_intr("ipi", filt, NULL, NULL, IRQ_SOFTWARE, 241 INTR_TYPE_MISC, NULL); 242} 243 244void 245riscv_unmask_ipi(void) 246{ 247 248 csr_set(sie, SIE_SSIE); 249} 250 251/* Sending IPI */ 252static void 253ipi_send(struct pcpu *pc, int ipi) 254{ 255 256 CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi); 257 258 atomic_set_32(&pc->pc_pending_ipis, ipi); 259 machine_command(ECALL_SEND_IPI, pc->pc_reg); 260 261 CTR1(KTR_SMP, "%s: sent", __func__); 262} 263 264void 265ipi_all_but_self(u_int ipi) 266{ 267 cpuset_t other_cpus; 268 269 other_cpus = all_cpus; 270 CPU_CLR(PCPU_GET(cpuid), &other_cpus); 271 272 CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi); 273 ipi_selected(other_cpus, ipi); 274} 275 276void 277ipi_cpu(int cpu, u_int ipi) 278{ 279 cpuset_t cpus; 280 281 CPU_ZERO(&cpus); 282 CPU_SET(cpu, &cpus); 283 284 CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi); 285 ipi_send(cpuid_to_pcpu[cpu], ipi); 286} 287 288void 289ipi_selected(cpuset_t cpus, u_int ipi) 290{ 291 struct pcpu *pc; 292 293 CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi); 294 295 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 296 if (CPU_ISSET(pc->pc_cpuid, &cpus)) { 297 CTR3(KTR_SMP, "%s: pc: %p, ipi: %x\n", __func__, pc, 298 ipi); 299 ipi_send(pc, ipi); 300 } 301 } 302} 303 304#endif 305