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: releng/12.0/sys/riscv/riscv/intr_machdep.c 335007 2018-06-12 17:45:15Z br $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/cpuset.h>
44 #include <sys/interrupt.h>
45 #include <sys/smp.h>
46
47 #include <machine/bus.h>
48 #include <machine/clock.h>
49 #include <machine/cpu.h>
50 #include <machine/cpufunc.h>
51 #include <machine/frame.h>
52 #include <machine/intr.h>
53 #include <machine/sbi.h>
54
55 #include <dev/ofw/openfirm.h>
56 #include <dev/ofw/ofw_bus.h>
57 #include <dev/ofw/ofw_bus_subr.h>
58
59 #ifdef SMP
60 #include <machine/smp.h>
61 #endif
62
63 void intr_irq_handler(struct trapframe *tf);
64
65 struct intc_irqsrc {
66 struct intr_irqsrc isrc;
67 u_int irq;
68 };
69
70 struct intc_irqsrc isrcs[INTC_NIRQS];
71
72 static void
73 riscv_mask_irq(void *source)
74 {
75 uintptr_t irq;
76
77 irq = (uintptr_t)source;
78
79 switch (irq) {
80 case IRQ_TIMER_SUPERVISOR:
81 csr_clear(sie, SIE_STIE);
82 break;
83 case IRQ_SOFTWARE_USER:
84 csr_clear(sie, SIE_USIE);
85 break;
86 case IRQ_SOFTWARE_SUPERVISOR:
87 csr_clear(sie, SIE_SSIE);
88 break;
89 default:
90 panic("Unknown irq %d\n", irq);
91 }
92 }
93
94 static void
95 riscv_unmask_irq(void *source)
96 {
97 uintptr_t irq;
98
99 irq = (uintptr_t)source;
100
101 switch (irq) {
102 case IRQ_TIMER_SUPERVISOR:
103 csr_set(sie, SIE_STIE);
104 break;
105 case IRQ_SOFTWARE_USER:
106 csr_set(sie, SIE_USIE);
107 break;
108 case IRQ_SOFTWARE_SUPERVISOR:
109 csr_set(sie, SIE_SSIE);
110 break;
111 default:
112 panic("Unknown irq %d\n", irq);
113 }
114 }
115
116 int
117 riscv_setup_intr(const char *name, driver_filter_t *filt,
118 void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
119 {
120 struct intr_irqsrc *isrc;
121 int error;
122
123 if (irq < 0 || irq >= INTC_NIRQS)
124 panic("%s: unknown intr %d", __func__, irq);
125
126 isrc = &isrcs[irq].isrc;
127 if (isrc->isrc_event == NULL) {
128 error = intr_event_create(&isrc->isrc_event, isrc, 0, irq,
129 riscv_mask_irq, riscv_unmask_irq, NULL, NULL, "int%d", irq);
130 if (error)
131 return (error);
132 riscv_unmask_irq((void*)(uintptr_t)irq);
133 }
134
135 error = intr_event_add_handler(isrc->isrc_event, name,
136 filt, handler, arg, intr_priority(flags), flags, cookiep);
137 if (error) {
138 printf("Failed to setup intr: %d\n", irq);
139 return (error);
140 }
141
142 return (0);
143 }
144
145 int
146 riscv_teardown_intr(void *ih)
147 {
148
149 /* TODO */
150
151 return (0);
152 }
153
154 void
155 riscv_cpu_intr(struct trapframe *frame)
156 {
157 struct intr_irqsrc *isrc;
158 int active_irq;
159
160 critical_enter();
161
162 KASSERT(frame->tf_scause & EXCP_INTR,
163 ("riscv_cpu_intr: wrong frame passed"));
164
165 active_irq = (frame->tf_scause & EXCP_MASK);
166
167 switch (active_irq) {
168 case IRQ_SOFTWARE_USER:
169 case IRQ_SOFTWARE_SUPERVISOR:
170 case IRQ_TIMER_SUPERVISOR:
171 isrc = &isrcs[active_irq].isrc;
172 if (intr_isrc_dispatch(isrc, frame) != 0)
173 printf("stray interrupt %d\n", active_irq);
174 break;
175 case IRQ_EXTERNAL_SUPERVISOR:
176 intr_irq_handler(frame);
177 break;
178 default:
179 break;
180 }
181
182 critical_exit();
183 }
184
185 #ifdef SMP
186 void
187 riscv_setup_ipihandler(driver_filter_t *filt)
188 {
189
190 riscv_setup_intr("ipi", filt, NULL, NULL, IRQ_SOFTWARE_SUPERVISOR,
191 INTR_TYPE_MISC, NULL);
192 }
193
194 void
195 riscv_unmask_ipi(void)
196 {
197
198 csr_set(sie, SIE_SSIE);
199 }
200
201 /* Sending IPI */
202 static void
203 ipi_send(struct pcpu *pc, int ipi)
204 {
205 uintptr_t mask;
206
207 CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi);
208
209 atomic_set_32(&pc->pc_pending_ipis, ipi);
210 mask = (1 << (pc->pc_cpuid));
211
212 sbi_send_ipi(&mask);
213
214 CTR1(KTR_SMP, "%s: sent", __func__);
215 }
216
217 void
218 ipi_all_but_self(u_int ipi)
219 {
220 cpuset_t other_cpus;
221
222 other_cpus = all_cpus;
223 CPU_CLR(PCPU_GET(cpuid), &other_cpus);
224
225 CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
226 ipi_selected(other_cpus, ipi);
227 }
228
229 void
230 ipi_cpu(int cpu, u_int ipi)
231 {
232 cpuset_t cpus;
233
234 CPU_ZERO(&cpus);
235 CPU_SET(cpu, &cpus);
236
237 CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi);
238 ipi_send(cpuid_to_pcpu[cpu], ipi);
239 }
240
241 void
242 ipi_selected(cpuset_t cpus, u_int ipi)
243 {
244 struct pcpu *pc;
245 uintptr_t mask;
246
247 CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi);
248
249 mask = 0;
250 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
251 if (CPU_ISSET(pc->pc_cpuid, &cpus)) {
252 CTR3(KTR_SMP, "%s: pc: %p, ipi: %x\n", __func__, pc,
253 ipi);
254 atomic_set_32(&pc->pc_pending_ipis, ipi);
255 mask |= (1 << (pc->pc_cpuid));
256 }
257 }
258 sbi_send_ipi(&mask);
259 }
260 #endif
261
262 /* Interrupt machdep initialization routine. */
263 static void
264 intc_init(void *dummy __unused)
265 {
266 int error;
267 int i;
268
269 for (i = 0; i < INTC_NIRQS; i++) {
270 isrcs[i].irq = i;
271 error = intr_isrc_register(&isrcs[i].isrc, NULL,
272 0, "intc,%u", i);
273 if (error != 0)
274 printf("Can't register interrupt %d\n", i);
275 }
276 }
277
278 SYSINIT(intc_init, SI_SUB_INTR, SI_ORDER_MIDDLE, intc_init, NULL);
Cache object: b4e8cfbe5eed903c8672f3b21396f830
|