xref: /openbsd/sys/arch/amd64/include/intr.h (revision fc30b644)
1 /*	$OpenBSD: intr.h,v 1.34 2024/05/26 13:37:31 kettenis Exp $	*/
2 /*	$NetBSD: intr.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $	*/
3 
4 /*-
5  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Charles M. Hannum, and by Jason R. Thorpe.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef _MACHINE_INTR_H_
34 #define _MACHINE_INTR_H_
35 
36 #include <machine/intrdefs.h>
37 
38 #ifndef _LOCORE
39 #include <machine/cpu.h>
40 
41 #include <sys/evcount.h>
42 
43 /*
44  * Struct describing an interrupt source for a CPU. struct cpu_info
45  * has an array of MAX_INTR_SOURCES of these. The index in the array
46  * is equal to the stub number of the stubcode as present in vector.s
47  *
48  * The primary CPU's array of interrupt sources has its first 16
49  * entries reserved for legacy ISA irq handlers. This means that
50  * they have a 1:1 mapping for arrayindex:irq_num. This is not
51  * true for interrupts that come in through IO APICs, to find
52  * their source, go through ci->ci_isources[index].is_pic
53  *
54  * It's possible to always maintain a 1:1 mapping, but that means
55  * limiting the total number of interrupt sources to MAX_INTR_SOURCES
56  * (32), instead of 32 per CPU. It also would mean that having multiple
57  * IO APICs which deliver interrupts from an equal pin number would
58  * overlap if they were to be sent to the same CPU.
59  */
60 
61 struct intrstub {
62 	void *ist_entry;
63 	void *ist_recurse;
64 	void *ist_resume;
65 };
66 
67 struct intrsource {
68 	int is_maxlevel;		/* max. IPL for this source */
69 	int is_pin;			/* IRQ for legacy; pin for IO APIC */
70 	struct intrhand *is_handlers;	/* handler chain */
71 	struct pic *is_pic;		/* originating PIC */
72 	void *is_recurse;		/* entry for spllower */
73 	void *is_resume;		/* entry for doreti */
74 	char is_evname[32];		/* event counter name */
75 	int is_flags;			/* see below */
76 	int is_type;			/* level, edge */
77 	int is_idtvec;
78 	int is_minlevel;
79 };
80 
81 #define IS_LEGACY	0x0001		/* legacy ISA irq source */
82 #define IS_IPI		0x0002
83 #define IS_LOG		0x0004
84 
85 
86 /*
87  * Interrupt handler chains.  *_intr_establish() insert a handler into
88  * the list.  The handler is called with its (single) argument.
89  */
90 
91 struct intrhand {
92 	int	(*ih_fun)(void *);
93 	void	*ih_arg;
94 	int	ih_level;
95 	int	ih_flags;
96 	struct	intrhand *ih_next;
97 	int	ih_pin;
98 	int	ih_slot;
99 	struct cpu_info *ih_cpu;
100 	int	ih_irq;
101 	struct evcount ih_count;
102 };
103 
104 #define IMASK(ci,level) (ci)->ci_imask[(level)]
105 #define IUNMASK(ci,level) (ci)->ci_iunmask[(level)]
106 
107 extern void Xspllower(int);
108 
109 int splraise(int);
110 int spllower(int);
111 void softintr(int);
112 
113 /*
114  * Convert spl level to local APIC level
115  */
116 #define APIC_LEVEL(l)   ((l) << 4)
117 
118 /*
119  * compiler barrier: prevent reordering of instructions.
120  * This prevents the compiler from reordering code around
121  * this "instruction", acting as a sequence point for code generation.
122  */
123 
124 #define	__splbarrier() __asm volatile("":::"memory")
125 
126 /*
127  * Hardware interrupt masks
128  */
129 #define	splbio()	splraise(IPL_BIO)
130 #define	splnet()	splraise(IPL_NET)
131 #define	spltty()	splraise(IPL_TTY)
132 #define	splaudio()	splraise(IPL_AUDIO)
133 #define	splclock()	splraise(IPL_CLOCK)
134 #define	splstatclock()	splclock()
135 #define splipi()	splraise(IPL_IPI)
136 
137 /*
138  * Software interrupt masks
139  */
140 #define	splsoftclock()	splraise(IPL_SOFTCLOCK)
141 #define	splsoftnet()	splraise(IPL_SOFTNET)
142 #define	splsofttty()	splraise(IPL_SOFTTTY)
143 
144 /*
145  * Miscellaneous
146  */
147 #define	splvm()		splraise(IPL_VM)
148 #define	splhigh()	splraise(IPL_HIGH)
149 #define	spl0()		spllower(IPL_NONE)
150 #define	splsched()	splraise(IPL_SCHED)
151 #define	splx(x)		spllower(x)
152 
153 /* SPL asserts */
154 #ifdef DIAGNOSTIC
155 /*
156  * Although this function is implemented in MI code, it must be in this MD
157  * header because we don't want this header to include MI includes.
158  */
159 void splassert_fail(int, int, const char *);
160 extern int splassert_ctl;
161 void splassert_check(int, const char *);
162 #define splassert(__wantipl) do {			\
163 	if (splassert_ctl > 0) {			\
164 		splassert_check(__wantipl, __func__);	\
165 	}						\
166 } while (0)
167 #define splsoftassert(wantipl) splassert(wantipl)
168 #else
169 #define splassert(wantipl)	do { /* nada */ } while (0)
170 #define splsoftassert(wantipl)	do { /* nada */ } while (0)
171 #endif
172 
173 #define IPLSHIFT 4			/* The upper nibble of vectors is the IPL.      */
174 #define IPL(level) ((level) >> IPLSHIFT)	/* Extract the IPL.    */
175 
176 #include <machine/pic.h>
177 
178 /*
179  * Stub declarations.
180  */
181 
182 extern void Xsoftclock(void);
183 extern void Xsoftnet(void);
184 extern void Xsofttty(void);
185 
186 extern struct intrstub i8259_stubs[];
187 extern struct intrstub ioapic_edge_stubs[];
188 extern struct intrstub ioapic_level_stubs[];
189 
190 struct cpu_info;
191 
192 extern int intr_shared_edge;
193 
194 extern char idt_allocmap[];
195 
196 void intr_default_setup(void);
197 int x86_nmi(void);
198 void intr_calculatemasks(struct cpu_info *);
199 int intr_allocate_slot_cpu(struct cpu_info *, struct pic *, int, int *);
200 int intr_allocate_slot(struct pic *, int, int, int, struct cpu_info **, int *,
201 	    int *);
202 void *intr_establish(int, struct pic *, int, int, int,
203 	    struct cpu_info *, int (*)(void *), void *, const char *);
204 void intr_disestablish(struct intrhand *);
205 int intr_handler(struct intrframe *, struct intrhand *);
206 void cpu_intr_init(struct cpu_info *);
207 void intr_printconfig(void);
208 void intr_barrier(void *);
209 void intr_enable_wakeup(void);
210 void intr_disable_wakeup(void);
211 
212 #ifdef MULTIPROCESSOR
213 void x86_send_ipi(struct cpu_info *, int);
214 int x86_fast_ipi(struct cpu_info *, int);
215 void x86_broadcast_ipi(int);
216 void x86_ipi_handler(void);
217 void x86_setperf_ipi(struct cpu_info *);
218 
219 extern void (*ipifunc[X86_NIPI])(struct cpu_info *);
220 #endif
221 
222 #endif /* !_LOCORE */
223 
224 /*
225  * Generic software interrupt support.
226  */
227 
228 #define	X86_SOFTINTR_SOFTCLOCK		0
229 #define	X86_SOFTINTR_SOFTNET		1
230 #define	X86_SOFTINTR_SOFTTTY		2
231 #define	X86_NSOFTINTR			3
232 
233 #ifndef _LOCORE
234 #include <sys/queue.h>
235 
236 struct x86_soft_intrhand {
237 	TAILQ_ENTRY(x86_soft_intrhand)
238 		sih_q;
239 	struct x86_soft_intr *sih_intrhead;
240 	void	(*sih_fn)(void *);
241 	void	*sih_arg;
242 	int	sih_pending;
243 };
244 
245 struct x86_soft_intr {
246 	TAILQ_HEAD(, x86_soft_intrhand)
247 			softintr_q;
248 	int		softintr_ssir;
249 	struct mutex	softintr_lock;
250 };
251 
252 void	*softintr_establish(int, void (*)(void *), void *);
253 void	softintr_disestablish(void *);
254 void	softintr_init(void);
255 void	softintr_dispatch(int);
256 
257 #define	softintr_schedule(arg)						\
258 do {									\
259 	struct x86_soft_intrhand *__sih = (arg);			\
260 	struct x86_soft_intr *__si = __sih->sih_intrhead;		\
261 									\
262 	mtx_enter(&__si->softintr_lock);				\
263 	if (__sih->sih_pending == 0) {					\
264 		TAILQ_INSERT_TAIL(&__si->softintr_q, __sih, sih_q);	\
265 		__sih->sih_pending = 1;					\
266 		softintr(__si->softintr_ssir);				\
267 	}								\
268 	mtx_leave(&__si->softintr_lock);				\
269 } while (/*CONSTCOND*/ 0)
270 #endif /* _LOCORE */
271 
272 #endif /* !_MACHINE_INTR_H_ */
273