]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/riscv/riscv/intr_machdep.c
MFV r333789: libpcap 1.9.0 (pre-release)
[FreeBSD/FreeBSD.git] / sys / riscv / riscv / intr_machdep.c
1 /*-
2  * Copyright (c) 2015-2017 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 #include <sys/vmmeter.h>
45
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>
52
53 #ifdef SMP
54 #include <machine/smp.h>
55 #endif
56
57 u_long intrcnt[NIRQS];
58 size_t sintrcnt = sizeof(intrcnt);
59
60 char intrnames[NIRQS * (MAXCOMLEN + 1) * 2];
61 size_t sintrnames = sizeof(intrnames);
62
63 static struct intr_event *intr_events[NIRQS];
64 static riscv_intrcnt_t riscv_intr_counters[NIRQS];
65
66 static int intrcnt_index;
67
68 riscv_intrcnt_t
69 riscv_intrcnt_create(const char* name)
70 {
71         riscv_intrcnt_t counter;
72
73         counter = &intrcnt[intrcnt_index++];
74         riscv_intrcnt_setname(counter, name);
75
76         return (counter);
77 }
78
79 void
80 riscv_intrcnt_setname(riscv_intrcnt_t counter, const char *name)
81 {
82         int i;
83
84         i = (counter - intrcnt);
85
86         KASSERT(counter != NULL, ("riscv_intrcnt_setname: NULL counter"));
87
88         snprintf(intrnames + (MAXCOMLEN + 1) * i,
89             MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name);
90 }
91
92 static void
93 riscv_mask_irq(void *source)
94 {
95         uintptr_t irq;
96
97         irq = (uintptr_t)source;
98
99         switch (irq) {
100         case IRQ_TIMER_SUPERVISOR:
101                 csr_clear(sie, SIE_STIE);
102                 break;
103         case IRQ_SOFTWARE_USER:
104                 csr_clear(sie, SIE_USIE);
105         case IRQ_SOFTWARE_SUPERVISOR:
106                 csr_clear(sie, SIE_SSIE);
107                 break;
108 #if 0
109         /* lowRISC TODO */
110         case IRQ_UART:
111                 machine_command(ECALL_IO_IRQ_MASK, 0);
112                 break;
113 #endif
114         default:
115                 panic("Unknown irq %d\n", irq);
116         }
117 }
118
119 static void
120 riscv_unmask_irq(void *source)
121 {
122         uintptr_t irq;
123
124         irq = (uintptr_t)source;
125
126         switch (irq) {
127         case IRQ_TIMER_SUPERVISOR:
128                 csr_set(sie, SIE_STIE);
129                 break;
130         case IRQ_SOFTWARE_USER:
131                 csr_set(sie, SIE_USIE);
132                 break;
133         case IRQ_SOFTWARE_SUPERVISOR:
134                 csr_set(sie, SIE_SSIE);
135                 break;
136 #if 0
137         /* lowRISC TODO */
138         case IRQ_UART:
139                 machine_command(ECALL_IO_IRQ_MASK, 1);
140                 break;
141 #endif
142         default:
143                 panic("Unknown irq %d\n", irq);
144         }
145 }
146
147 void
148 riscv_init_interrupts(void)
149 {
150         char name[MAXCOMLEN + 1];
151         int i;
152
153         for (i = 0; i < NIRQS; i++) {
154                 snprintf(name, MAXCOMLEN + 1, "int%d:", i);
155                 riscv_intr_counters[i] = riscv_intrcnt_create(name);
156         }
157 }
158
159 int
160 riscv_setup_intr(const char *name, driver_filter_t *filt,
161     void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
162 {
163         struct intr_event *event;
164         int error;
165
166         if (irq < 0 || irq >= NIRQS)
167                 panic("%s: unknown intr %d", __func__, irq);
168
169         event = intr_events[irq];
170         if (event == NULL) {
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);
174                 if (error)
175                         return (error);
176                 intr_events[irq] = event;
177                 riscv_unmask_irq((void*)(uintptr_t)irq);
178         }
179
180         error = intr_event_add_handler(event, name, filt, handler, arg,
181             intr_priority(flags), flags, cookiep);
182         if (error) {
183                 printf("Failed to setup intr: %d\n", irq);
184                 return (error);
185         }
186
187         riscv_intrcnt_setname(riscv_intr_counters[irq],
188                              event->ie_fullname);
189
190         return (0);
191 }
192
193 int
194 riscv_teardown_intr(void *ih)
195 {
196
197         /* TODO */
198
199         return (0);
200 }
201
202 int
203 riscv_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
204 {
205
206         /* There is no configuration for interrupts */
207
208         return (0);
209 }
210
211 void
212 riscv_cpu_intr(struct trapframe *frame)
213 {
214         struct intr_event *event;
215         int active_irq;
216
217         critical_enter();
218
219         KASSERT(frame->tf_scause & EXCP_INTR,
220                 ("riscv_cpu_intr: wrong frame passed"));
221
222         active_irq = (frame->tf_scause & EXCP_MASK);
223
224         switch (active_irq) {
225 #if 0
226         /* lowRISC TODO */
227         case IRQ_UART:
228 #endif
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);
235                 VM_CNT_INC(v_intr);
236                 break;
237         default:
238                 event = NULL;
239         }
240
241         if (!event || TAILQ_EMPTY(&event->ie_handlers) ||
242             (intr_event_handle(event, frame) != 0))
243                 printf("stray interrupt %d\n", active_irq);
244
245         critical_exit();
246 }
247
248 #ifdef SMP
249 void
250 riscv_setup_ipihandler(driver_filter_t *filt)
251 {
252
253         riscv_setup_intr("ipi", filt, NULL, NULL, IRQ_SOFTWARE_SUPERVISOR,
254             INTR_TYPE_MISC, NULL);
255 }
256
257 void
258 riscv_unmask_ipi(void)
259 {
260
261         csr_set(sie, SIE_SSIE);
262 }
263
264 /* Sending IPI */
265 static void
266 ipi_send(struct pcpu *pc, int ipi)
267 {
268         uintptr_t mask;
269
270         CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi);
271
272         atomic_set_32(&pc->pc_pending_ipis, ipi);
273         mask = (1 << (pc->pc_cpuid));
274
275         sbi_send_ipi(&mask);
276
277         CTR1(KTR_SMP, "%s: sent", __func__);
278 }
279
280 void
281 ipi_all_but_self(u_int ipi)
282 {
283         cpuset_t other_cpus;
284
285         other_cpus = all_cpus;
286         CPU_CLR(PCPU_GET(cpuid), &other_cpus);
287
288         CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
289         ipi_selected(other_cpus, ipi);
290 }
291
292 void
293 ipi_cpu(int cpu, u_int ipi)
294 {
295         cpuset_t cpus;
296
297         CPU_ZERO(&cpus);
298         CPU_SET(cpu, &cpus);
299
300         CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi);
301         ipi_send(cpuid_to_pcpu[cpu], ipi);
302 }
303
304 void
305 ipi_selected(cpuset_t cpus, u_int ipi)
306 {
307         struct pcpu *pc;
308         uintptr_t mask;
309
310         CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi);
311
312         mask = 0;
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,
316                             ipi);
317                         atomic_set_32(&pc->pc_pending_ipis, ipi);
318                         mask |= (1 << (pc->pc_cpuid));
319                 }
320         }
321         sbi_send_ipi(&mask);
322 }
323
324 #endif