/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- splraise
- spllower
- splx
1 /*
2 * Copyright (c) 2009
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /* Make sure to build out-of-line versions of spl inline functions */
31 #define SPL_INLINE /* empty */
32
33 #include <types.h>
34 #include <lib.h>
35 #include <cpu.h>
36 #include <spl.h>
37 #include <thread.h>
38 #include <current.h>
39
40 /*
41 * Machine-independent interrupt handling functions.
42 *
43 * Traditionally, all this code is machine-dependent.
44 *
45 * However.
46 *
47 * Since on OS/161 we don't support interrupt levels on any platform,
48 * all we require under this logic is cpu_irqoff() and cpu_irqon()
49 * that explicitly turn interrupts off and on.
50 *
51 * If we had multiple interrupt levels, the number of levels would in
52 * general be different on different platforms (depending on hardware
53 * requirements and hardware capabilities) so things would get more
54 * complicated -- but nearly all of this code could remain MI.
55 */
56
57
58 /*
59 * Raise and lower the interrupt priority level.
60 *
61 * Each spinlock acquisition can raise and lower the priority level
62 * independently. The spl calls also raise and lower the priority
63 * level independently of the spinlocks. This is necessary because in
64 * general spinlock acquisitions and releases don't nest perfectly,
65 * and don't necessarily nest with respect to spl calls either.
66 *
67 * For example:
68 *
69 * struct spinlock red, blue;
70 * int s;
71 *
72 * spinlock_acquire(&red);
73 * s = splhigh();
74 * spinlock_acquire(&blue);
75 * splx(s);
76 * spinlock_release(&red);
77 * spinlock_release(&blue);
78 *
79 * In order to make this work we need to count the number of times
80 * IPL_HIGH (or, if we had multiple interrupt priority levels, each
81 * level independently) has been raised. Interrupts go off on the
82 * first raise, and go on again only on the last lower.
83 *
84 * curthread->t_iplhigh_count is used to track this.
85 */
86 void
87 splraise(int oldspl, int newspl)
88 {
89 struct thread *cur = curthread;
90
91 /* only one priority level, only one valid args configuration */
92 KASSERT(oldspl == IPL_NONE);
93 KASSERT(newspl == IPL_HIGH);
94
95 if (!CURCPU_EXISTS()) {
96 /* before curcpu initialization; interrupts are off anyway */
97 return;
98 }
99
100 if (cur->t_iplhigh_count == 0) {
101 cpu_irqoff();
102 }
103 cur->t_iplhigh_count++;
104 }
105
106 void
107 spllower(int oldspl, int newspl)
108 {
109 struct thread *cur = curthread;
110
111 /* only one priority level, only one valid args configuration */
112 KASSERT(oldspl == IPL_HIGH);
113 KASSERT(newspl == IPL_NONE);
114
115 if (!CURCPU_EXISTS()) {
116 /* before curcpu initialization; interrupts are off anyway */
117 return;
118 }
119
120 cur->t_iplhigh_count--;
121 if (cur->t_iplhigh_count == 0) {
122 cpu_irqon();
123 }
124 }
125
126
127 /*
128 * Disable or enable interrupts and adjust curspl setting. Return old
129 * spl level.
130 */
131 int
132 splx(int spl)
133 {
134 struct thread *cur = curthread;
135 int ret;
136
137 if (cur->t_curspl < spl) {
138 /* turning interrupts off */
139 splraise(cur->t_curspl, spl);
140 ret = cur->t_curspl;
141 cur->t_curspl = spl;
142 }
143 else if (cur->t_curspl > spl) {
144 /* turning interrupts on */
145 ret = cur->t_curspl;
146 cur->t_curspl = spl;
147 spllower(ret, spl);
148 }
149 else {
150 /* do nothing */
151 ret = spl;
152 }
153
154 return ret;
155 }