/*1* Copyright (c) 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/* Make sure to build out-of-line versions of spl inline functions */30#define SPL_INLINE /* empty */3132#include <types.h>33#include <lib.h>34#include <cpu.h>35#include <spl.h>36#include <thread.h>37#include <current.h>3839/*40* Machine-independent interrupt handling functions.41*42* Traditionally, all this code is machine-dependent.43*44* However.45*46* Since on OS/161 we don't support interrupt levels on any platform,47* all we require under this logic is cpu_irqoff() and cpu_irqon()48* that explicitly turn interrupts off and on.49*50* If we had multiple interrupt levels, the number of levels would in51* general be different on different platforms (depending on hardware52* requirements and hardware capabilities) so things would get more53* complicated -- but nearly all of this code could remain MI.54*/555657/*58* Raise and lower the interrupt priority level.59*60* Each spinlock acquisition can raise and lower the priority level61* independently. The spl calls also raise and lower the priority62* level independently of the spinlocks. This is necessary because in63* general spinlock acquisitions and releases don't nest perfectly,64* and don't necessarily nest with respect to spl calls either.65*66* For example:67*68* struct spinlock red, blue;69* int s;70*71* spinlock_acquire(&red);72* s = splhigh();73* spinlock_acquire(&blue);74* splx(s);75* spinlock_release(&red);76* spinlock_release(&blue);77*78* In order to make this work we need to count the number of times79* IPL_HIGH (or, if we had multiple interrupt priority levels, each80* level independently) has been raised. Interrupts go off on the81* first raise, and go on again only on the last lower.82*83* curthread->t_iplhigh_count is used to track this.84*/85void86splraise(int oldspl, int newspl)87{88struct thread *cur = curthread;8990/* only one priority level, only one valid args configuration */91KASSERT(oldspl == IPL_NONE);92KASSERT(newspl == IPL_HIGH);9394if (!CURCPU_EXISTS()) {95/* before curcpu initialization; interrupts are off anyway */96return;97}9899if (cur->t_iplhigh_count == 0) {100cpu_irqoff();101}102cur->t_iplhigh_count++;103}104105void106spllower(int oldspl, int newspl)107{108struct thread *cur = curthread;109110/* only one priority level, only one valid args configuration */111KASSERT(oldspl == IPL_HIGH);112KASSERT(newspl == IPL_NONE);113114if (!CURCPU_EXISTS()) {115/* before curcpu initialization; interrupts are off anyway */116return;117}118119cur->t_iplhigh_count--;120if (cur->t_iplhigh_count == 0) {121cpu_irqon();122}123}124125126/*127* Disable or enable interrupts and adjust curspl setting. Return old128* spl level.129*/130int131splx(int spl)132{133struct thread *cur = curthread;134int ret;135136if (cur->t_curspl < spl) {137/* turning interrupts off */138splraise(cur->t_curspl, spl);139ret = cur->t_curspl;140cur->t_curspl = spl;141}142else if (cur->t_curspl > spl) {143/* turning interrupts on */144ret = cur->t_curspl;145cur->t_curspl = spl;146spllower(ret, spl);147}148else {149/* do nothing */150ret = spl;151}152153return ret;154}155156157