2 * Copyright (c) 2015-2017 Ruslan Bukin <br@bsdpad.com>
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.
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).
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
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.
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
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/cpuset.h>
42 #include <sys/interrupt.h>
44 #include <sys/vmmeter.h>
46 #include <machine/clock.h>
47 #include <machine/cpu.h>
48 #include <machine/cpufunc.h>
49 #include <machine/frame.h>
50 #include <machine/intr.h>
51 #include <machine/sbi.h>
54 #include <machine/smp.h>
57 u_long intrcnt[NIRQS];
58 size_t sintrcnt = sizeof(intrcnt);
60 char intrnames[NIRQS * (MAXCOMLEN + 1) * 2];
61 size_t sintrnames = sizeof(intrnames);
63 static struct intr_event *intr_events[NIRQS];
64 static riscv_intrcnt_t riscv_intr_counters[NIRQS];
66 static int intrcnt_index;
69 riscv_intrcnt_create(const char* name)
71 riscv_intrcnt_t counter;
73 counter = &intrcnt[intrcnt_index++];
74 riscv_intrcnt_setname(counter, name);
80 riscv_intrcnt_setname(riscv_intrcnt_t counter, const char *name)
84 i = (counter - intrcnt);
86 KASSERT(counter != NULL, ("riscv_intrcnt_setname: NULL counter"));
88 snprintf(intrnames + (MAXCOMLEN + 1) * i,
89 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name);
93 riscv_mask_irq(void *source)
97 irq = (uintptr_t)source;
100 case IRQ_TIMER_SUPERVISOR:
101 csr_clear(sie, SIE_STIE);
103 case IRQ_SOFTWARE_USER:
104 csr_clear(sie, SIE_USIE);
105 case IRQ_SOFTWARE_SUPERVISOR:
106 csr_clear(sie, SIE_SSIE);
111 machine_command(ECALL_IO_IRQ_MASK, 0);
115 panic("Unknown irq %d\n", irq);
120 riscv_unmask_irq(void *source)
124 irq = (uintptr_t)source;
127 case IRQ_TIMER_SUPERVISOR:
128 csr_set(sie, SIE_STIE);
130 case IRQ_SOFTWARE_USER:
131 csr_set(sie, SIE_USIE);
133 case IRQ_SOFTWARE_SUPERVISOR:
134 csr_set(sie, SIE_SSIE);
139 machine_command(ECALL_IO_IRQ_MASK, 1);
143 panic("Unknown irq %d\n", irq);
148 riscv_init_interrupts(void)
150 char name[MAXCOMLEN + 1];
153 for (i = 0; i < NIRQS; i++) {
154 snprintf(name, MAXCOMLEN + 1, "int%d:", i);
155 riscv_intr_counters[i] = riscv_intrcnt_create(name);
160 riscv_setup_intr(const char *name, driver_filter_t *filt,
161 void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
163 struct intr_event *event;
166 if (irq < 0 || irq >= NIRQS)
167 panic("%s: unknown intr %d", __func__, irq);
169 event = intr_events[irq];
171 error = intr_event_create(&event, (void *)(uintptr_t)irq, 0,
172 irq, riscv_mask_irq, riscv_unmask_irq,
173 NULL, NULL, "int%d", irq);
176 intr_events[irq] = event;
177 riscv_unmask_irq((void*)(uintptr_t)irq);
180 error = intr_event_add_handler(event, name, filt, handler, arg,
181 intr_priority(flags), flags, cookiep);
183 printf("Failed to setup intr: %d\n", irq);
187 riscv_intrcnt_setname(riscv_intr_counters[irq],
194 riscv_teardown_intr(void *ih)
203 riscv_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
206 /* There is no configuration for interrupts */
212 riscv_cpu_intr(struct trapframe *frame)
214 struct intr_event *event;
219 KASSERT(frame->tf_scause & EXCP_INTR,
220 ("riscv_cpu_intr: wrong frame passed"));
222 active_irq = (frame->tf_scause & EXCP_MASK);
224 switch (active_irq) {
229 case IRQ_SOFTWARE_USER:
230 case IRQ_SOFTWARE_SUPERVISOR:
231 case IRQ_TIMER_SUPERVISOR:
232 event = intr_events[active_irq];
233 /* Update counters */
234 atomic_add_long(riscv_intr_counters[active_irq], 1);
241 if (!event || TAILQ_EMPTY(&event->ie_handlers) ||
242 (intr_event_handle(event, frame) != 0))
243 printf("stray interrupt %d\n", active_irq);
250 riscv_setup_ipihandler(driver_filter_t *filt)
253 riscv_setup_intr("ipi", filt, NULL, NULL, IRQ_SOFTWARE_SUPERVISOR,
254 INTR_TYPE_MISC, NULL);
258 riscv_unmask_ipi(void)
261 csr_set(sie, SIE_SSIE);
266 ipi_send(struct pcpu *pc, int ipi)
270 CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi);
272 atomic_set_32(&pc->pc_pending_ipis, ipi);
273 mask = (1 << (pc->pc_cpuid));
277 CTR1(KTR_SMP, "%s: sent", __func__);
281 ipi_all_but_self(u_int ipi)
285 other_cpus = all_cpus;
286 CPU_CLR(PCPU_GET(cpuid), &other_cpus);
288 CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
289 ipi_selected(other_cpus, ipi);
293 ipi_cpu(int cpu, u_int ipi)
300 CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi);
301 ipi_send(cpuid_to_pcpu[cpu], ipi);
305 ipi_selected(cpuset_t cpus, u_int ipi)
310 CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi);
313 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
314 if (CPU_ISSET(pc->pc_cpuid, &cpus)) {
315 CTR3(KTR_SMP, "%s: pc: %p, ipi: %x\n", __func__, pc,
317 atomic_set_32(&pc->pc_pending_ipis, ipi);
318 mask |= (1 << (pc->pc_cpuid));