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: releng/11.2/sys/riscv/riscv/intr_machdep.c 298636 2016-04-26 12:56:44Z br $");
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
55 u_long intrcnt[NIRQS];
56 size_t sintrcnt = sizeof(intrcnt);
57
58 char intrnames[NIRQS * (MAXCOMLEN + 1) * 2];
59 size_t sintrnames = sizeof(intrnames);
60
61 static struct intr_event *intr_events[NIRQS];
62 static riscv_intrcnt_t riscv_intr_counters[NIRQS];
63
64 static int intrcnt_index;
65
66 riscv_intrcnt_t
67 riscv_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
77 void
78 riscv_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
90 static void
91 riscv_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
112 static void
113 riscv_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
134 void
135 riscv_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
146 int
147 riscv_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
180 int
181 riscv_teardown_intr(void *ih)
182 {
183
184 /* TODO */
185
186 return (0);
187 }
188
189 int
190 riscv_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
198 void
199 riscv_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
236 void
237 riscv_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
244 void
245 riscv_unmask_ipi(void)
246 {
247
248 csr_set(sie, SIE_SSIE);
249 }
250
251 /* Sending IPI */
252 static void
253 ipi_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
264 void
265 ipi_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
276 void
277 ipi_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
288 void
289 ipi_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
Cache object: b77f6b7a43d3a11d613535ca58272fb6
|