1 /* $OpenBSD: intr.h,v 1.19 2003/04/17 03:42:14 drahn Exp $ */
2 /* $NetBSD: intr.h,v 1.5 1996/05/13 06:11:28 mycroft Exp $ */
3
4 /*
5 * Copyright (c) 1996 Charles M. Hannum. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Charles M. Hannum.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifndef _I386_INTR_H_
34 #define _I386_INTR_H_
35
36 /*
37 * Intel APICs (advanced programmable interrupt controllers) have
38 * bytesized priority registers where the upper nibble is the actual
39 * interrupt priority level (a.k.a. IPL). Interrupt vectors are
40 * closely tied to these levels as interrupts whose vectors' upper
41 * nibble is lower than or equal to the current level are blocked.
42 * Not all 256 possible vectors are available for interrupts in
43 * APIC systems, only
44 *
45 * For systems where instead the older ICU (interrupt controlling
46 * unit, a.k.a. PIC or 82C59) is used, the IPL is not directly useful,
47 * since the interrupt blocking is handled via interrupt masks instead
48 * of levels. However the IPL is easily used as an offset into arrays
49 * of masks.
50 */
51 #define IPLSHIFT 4 /* The upper nibble of vectors is the IPL. */
52 #define NIPL 16 /* Four bits of information gives as much. */
53 #define IPL(level) ((level) >> IPLSHIFT) /* Extract the IPL. */
54 /* XXX Maybe this IDTVECOFF definition should be elsewhere? */
55 #define IDTVECOFF 0x20 /* The lower 32 IDT vectors are reserved. */
56
57 /*
58 * This macro is only defined for 0 <= x < 14, i.e. there are fourteen
59 * distinct priority levels available for interrupts.
60 */
61 #define MAKEIPL(priority) (IDTVECOFF + ((priority) << IPLSHIFT))
62
63 /*
64 * Interrupt priority levels.
65 * XXX We are somewhat sloppy about what we mean by IPLs, sometimes
66 * XXX we refer to the eight-bit value suitable for storing into APICs'
67 * XXX priority registers, other times about the four-bit entity found
68 * XXX in the former values' upper nibble, which can be used as offsets
69 * XXX in various arrays of our implementation. We are hoping that
70 * XXX the context will provide enough information to not make this
71 * XXX sloppy naming a real problem.
72 */
73 #define IPL_NONE 0 /* nothing */
74 #define IPL_SOFTCLOCK MAKEIPL(0) /* timeouts */
75 #define IPL_SOFTNET MAKEIPL(1) /* protocol stacks */
76 #define IPL_BIO MAKEIPL(2) /* block I/O */
77 #define IPL_NET MAKEIPL(3) /* network */
78 #define IPL_SOFTTTY MAKEIPL(4) /* delayed terminal handling */
79 #define IPL_TTY MAKEIPL(5) /* terminal */
80 #define IPL_VM MAKEIPL(6) /* memory allocation */
81 #define IPL_IMP IPL_VM /* XXX - should not be here. */
82 #define IPL_AUDIO MAKEIPL(7) /* audio */
83 #define IPL_CLOCK MAKEIPL(8) /* clock */
84 #define IPL_STATCLOCK MAKEIPL(9) /* statclock */
85 #define IPL_HIGH MAKEIPL(9) /* everything */
86
87 /* Interrupt sharing types. */
88 #define IST_NONE 0 /* none */
89 #define IST_PULSE 1 /* pulsed */
90 #define IST_EDGE 2 /* edge-triggered */
91 #define IST_LEVEL 3 /* level-triggered */
92
93 /* Soft interrupt masks. */
94 #define SIR_CLOCK 31
95 #define SIR_NET 30
96 #define SIR_TTY 29
97
98 #ifndef _LOCORE
99
100 volatile int cpl; /* Current interrupt priority level. */
101 volatile int ipending; /* Interrupts pending. */
102 volatile int astpending;/* Asynchronous software traps (softints) pending. */
103 int imask[NIPL]; /* Bitmasks telling what interrupts are blocked. */
104 int iunmask[NIPL]; /* Bitmasks telling what interrupts are accepted. */
105
106 #define IMASK(level) imask[IPL(level)]
107 #define IUNMASK(level) iunmask[IPL(level)]
108
109 extern void Xspllower(void);
110
111 static __inline int splraise(int);
112 static __inline int spllower(int);
113 #define SPLX_DECL void splx(int);
114 static __inline void softintr(int);
115
116 /* SPL asserts */
117 #ifdef DIAGNOSTIC
118 /*
119 * Although this function is implemented in MI code, it must be in this MD
120 * header because we don't want this header to include MI includes.
121 */
122 void splassert_fail(int, int, const char *);
123 extern int splassert_ctl;
124 void splassert_check(int, const char *);
125 #define splassert(__wantipl) do { \
126 if (__predict_false(splassert_ctl > 0)) { \
127 splassert_check(__wantipl, __func__); \
128 } \
129 } while (0)
130 #else
131 #define splassert(wantipl) do { /* nada */ } while (0)
132 #endif
133
134 /*
135 * Raise current interrupt priority level, and return the old one.
136 */
137 static __inline int
splraise(ncpl)138 splraise(ncpl)
139 int ncpl;
140 {
141 int ocpl = cpl;
142
143 if (ncpl > ocpl)
144 cpl = ncpl;
145 __asm __volatile("":::"memory");
146 return (ocpl);
147 }
148
149 /*
150 * Restore an old interrupt priority level. If any thereby unmasked
151 * interrupts are pending, call Xspllower() to process them.
152 */
153 #define SPLX_BODY \
154 void \
155 splx(ncpl) \
156 int ncpl; \
157 { \
158 __asm __volatile("":::"memory"); \
159 cpl = ncpl; \
160 if (ipending & IUNMASK(ncpl)) \
161 Xspllower(); \
162 }
163
164 /* If SMALL_KERNEL make splx out of line, otherwise inline it. */
165 #ifdef SMALL_KERNEL
166 #define SPLX_INLINED_BODY
167 #define SPLX_OUTLINED_BODY SPLX_BODY
168 SPLX_DECL
169 #else
170 #define SPLX_INLINED_BODY static __inline SPLX_BODY
171 #define SPLX_OUTLINED_BODY
172 static __inline SPLX_DECL
173 #endif
174
175 SPLX_INLINED_BODY
176
177 /*
178 * Same as splx(), but we return the old value of spl, for the
179 * benefit of some splsoftclock() callers.
180 */
181 static __inline int
spllower(ncpl)182 spllower(ncpl)
183 int ncpl;
184 {
185 int ocpl = cpl;
186
187 splx(ncpl);
188 return (ocpl);
189 }
190
191 /*
192 * Hardware interrupt masks
193 */
194 #define splbio() splraise(IPL_BIO)
195 #define splnet() splraise(IPL_NET)
196 #define spltty() splraise(IPL_TTY)
197 #define splaudio() splraise(IPL_AUDIO)
198 #define splclock() splraise(IPL_CLOCK)
199 #define splstatclock() splhigh()
200
201 /*
202 * Software interrupt masks
203 *
204 * NOTE: spllowersoftclock() is used by hardclock() to lower the priority from
205 * clock to softclock before it calls softclock().
206 */
207 #define spllowersoftclock() spllower(IPL_SOFTCLOCK)
208 #define splsoftclock() splraise(IPL_SOFTCLOCK)
209 #define splsoftnet() splraise(IPL_SOFTNET)
210 #define splsofttty() splraise(IPL_SOFTTTY)
211
212 /*
213 * Miscellaneous
214 */
215 #define splvm() splraise(IPL_VM)
216 #define splimp() splvm()
217 #define splhigh() splraise(IPL_HIGH)
218 #define spl0() spllower(IPL_NONE)
219
220 /*
221 * Software interrupt registration
222 *
223 * We hand-code this to ensure that it's atomic.
224 */
225 static __inline void
softintr(mask)226 softintr(mask)
227 int mask;
228 {
229 __asm __volatile("orl %1, %0" : "=m"(ipending) : "ir" (mask));
230
231 }
232
233 #define setsoftast() (astpending = 1)
234 #define setsoftclock() softintr(1 << SIR_CLOCK)
235 #define setsoftnet() softintr(1 << SIR_NET)
236 #define setsofttty() softintr(1 << SIR_TTY)
237
238 #endif /* !_LOCORE */
239
240 #endif /* !_I386_INTR_H_ */
241