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