xref: /netbsd-src/sys/arch/riscv/riscv/interrupt.c (revision 0acb2df480dcd21f20c2f32f3510d830c916d774)
1 /*	$NetBSD: interrupt.c,v 1.3 2024/11/19 08:28:01 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 2022 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Simon Burge and Nick Hudson.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "opt_multiprocessor.h"
33 
34 #include <sys/cdefs.h>
35 
36 __RCSID("$NetBSD: interrupt.c,v 1.3 2024/11/19 08:28:01 skrll Exp $");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 
41 #include <sys/bus.h>
42 #include <sys/cpu.h>
43 #include <sys/kernel.h>
44 
45 #include <machine/locore.h>
46 #include <machine/machdep.h>
47 #include <machine/sbi.h>
48 
49 #include <riscv/dev/plicvar.h>
50 
51 
52 static void
53 riscv_intr_default_handler(struct trapframe *frame, register_t epc,
54     register_t status, register_t cause)
55 {
56 #if 1
57 	panic("not supposed to get here");
58 #else
59 	struct cpu_info * const ci = curcpu();
60 	const int code = CAUSE_CODE(cause);
61 
62 	KASSERT(CAUSE_INTERRUPT_P(cause));
63 
64 	ci->ci_intr_depth++;
65 	switch (code) {
66 	case IRQ_SUPERVISOR_SOFTWARE:
67 #ifdef MULTIPROCESSOR
68 		ipi_handler(tf);
69 #else
70 		panic("%s: SUPERVISOR SOFTWARE interrupt", __func__);
71 #endif
72 		break;
73 	case IRQ_SUPERVISOR_TIMER: {
74 		struct clockframe cf = {
75 			.cf_epc = epc,
76 			.cf_status = status,
77 			.cf_intr_depth = ci->ci_intr_depth
78 		};
79 		timer_handler(&cf);
80 		break;
81 	    }
82 	case IRQ_SUPERVISOR_EXTERNAL:
83 		extintr_handler(tf);
84 		break;
85 	default:
86 		panic("%s: unknown exception code %u", __func__, code);
87 	}
88 	ci->ci_intr_depth--;
89 #endif
90 }
91 
92 
93 static void (*_riscv_intr_handler)(struct trapframe *, register_t,
94     register_t, register_t) = riscv_intr_default_handler;
95 
96 
97 void
98 riscv_intr_set_handler(void (*intr_handler)(struct trapframe *, register_t,
99     register_t, register_t))
100 {
101 	KASSERT(_riscv_intr_handler == riscv_intr_default_handler ||
102 		_riscv_intr_handler == intr_handler);
103 	_riscv_intr_handler = intr_handler;
104 }
105 
106 
107 void
108 cpu_intr(struct trapframe *tf, register_t epc, register_t status,
109     register_t cause)
110 {
111 	_riscv_intr_handler(tf, epc, status, cause);
112 }
113 
114 
115 void *
116 intr_establish_xname(int irq, int ipl, int type, int (*func)(void *), void *arg,
117     const char *xname)
118 {
119 	KASSERT(!cpu_intr_p());
120 	KASSERT(!cpu_softintr_p());
121 
122 	return plic_intr_establish_xname(irq, ipl, type, func, arg, xname);
123 }
124 
125 void *
126 intr_establish(int irq, int ipl, int type, int (*func)(void *), void *arg)
127 {
128 	return intr_establish_xname(irq, ipl, type, func, arg, NULL);
129 }
130 
131 void
132 intr_disestablish(void *ih)
133 {
134 //	struct intrsource * const is = ih;
135 
136 	KASSERT(!cpu_intr_p());
137 	KASSERT(!cpu_softintr_p());
138 }
139 
140 
141 #ifdef MULTIPROCESSOR
142 __CTASSERT(NIPIS < 16);
143 
144 int
145 riscv_ipi_intr(void *arg)
146 {
147 	struct cpu_info * const ci = curcpu();
148 	membar_acquire();
149 
150 	csr_sip_clear(SIP_SSIP);	/* clean pending interrupt status */
151 
152 	unsigned long pending;
153 	while ((pending = atomic_swap_ulong(&ci->ci_request_ipis, 0)) != 0) {
154 		membar_acquire();
155 		atomic_or_ulong(&ci->ci_active_ipis, pending);
156 
157 		ipi_process(ci, pending);
158 
159 		atomic_and_ulong(&ci->ci_active_ipis, pending);
160 	}
161 
162 	return 1;
163 }
164 
165 int
166 cpu_send_ipi(struct cpu_info *ci, int req)
167 {
168 	KASSERT(req < NIPIS);
169 	if (ci == NULL) {
170 		CPU_INFO_ITERATOR cii;
171 		for (CPU_INFO_FOREACH(cii, ci)) {
172 			if (ci != curcpu()) {
173 				cpu_send_ipi(ci, req);
174 			}
175 		}
176 		return 0;
177 	}
178 	const uint32_t ipi_mask = __BIT(req);
179 
180 	membar_release();
181 	atomic_or_ulong(&ci->ci_request_ipis, ipi_mask);
182 
183 	membar_release();
184 	unsigned long hartmask = 0;
185 	const cpuid_t hartid = ci->ci_cpuid;
186 	KASSERT(hartid < sizeof(unsigned long) * NBBY);
187 	hartmask |= __BIT(hartid);
188 	struct sbiret sbiret = sbi_send_ipi(hartmask, 0);
189 
190 	KASSERT(sbiret.error == SBI_SUCCESS);
191 
192 	return 0;
193 }
194 #endif	/* MULTIPROCESSOR */
195