Coherent4.2.10/i386/lib/spl.c
#define _DDI_DKI 1
#define _SYSV4 1
/*
* Code to manage the processor interrupt-priority level.
*
* This module exists to define external-linkage versions of the macros given
* in <sys/inline.h>, and to give a manual-page entry.
*/
/*
*-IMPORTS:
* <common/ccompat.h>
* __USE_PROTO__
* __ARGS ()
*/
#include <common/ccompat.h>
#include <sys/inline.h>
#if __COHERENT__
#error This file is not for the Coherent version of STREAMS
#endif
/*
*-STATUS:
* DDI/DKI
*
*-NAME:
* spl... () Block/allow interrupts on a processor.
*
*-SYNOPSIS:
* #include <sys/inline.h>
*
* pl_t splbase ();
* pl_t spltimeout ();
* pl_t spldisk ();
* pl_t splstr ();
* pl_t splhi ();
* pl_t splx (pl_t oldlevel);
*
*-ARGUMENTS:
* oldlevel Last set priority value (only splx () has an input
* argument)
*
*-DESCRIPTION:
* The spl... () functions block or allow servicing of interrupts on the
* processor on which the function is called. Hardware devices are
* assigned to interrupt priority levels depending on the type of device.
* Each spl... () function which blocks interrupts is associated with
* with some machine-dependent interrupt priority level and will prevent
* interrupts occurring at or below this priority level from being
* serviced on the processor on which the spl... () function is called.
*
* On a multiprocessor system, interrupts may be serviced by more than
* one processor, and therefore use of an spl... () function alone is not
* sufficient to prevent interrupt code from executing and manipulating
* driver data structures during a critical section. Drivers that must
* prevent execution of interrupt-level code in order to protect the
* integrity of their should use basic locks or read/write locks for
* this purpose [see LOCK_ALLOC () or RW_ALLOC ()].
*
* Calling a given spl... () function will block interrupts specified for
* that function as well as all interrupts at equal an lower levels. The
* notion of low vs. high levels assumes a defined order of priority
* level. The following partial order is defined:
* splbase <= spltimeout <= spldisk, splstr <= splhi
*
* The ordering of spldisk () and splstr () relative to each other is not
* defined.
*
*-RETURN VALUE:
* All spl... () functions return the previous priority level.
*
*-LEVEL:
* Base or Interrupt.
*
*-NOTES:
* All spl... () functions do not sleep.
*
* Driver-defined basic locks and read/write locks may be held across
* calls to these functions, but the spl... () call must not cause the
* priority level to be lowered below the level associated with the
* lock.
*
* Driver-defined sleep locks may be held across calls to these
* functions.
*
* When setting a given priority level, the previous level returned
* should be saved and splx (), UNLOCK () or RW_UNLOCK () should be
* used as appropriate to restore this level.
*
* Interrupt-level code must never lower the interrupt priority level
* below the level at which the interrupt handler was entered. For
* example, is an interrupt handler is entered at the priority level
* associated with spldisk (), the handler must not call spltimeout ().
*/
#if __USE_PROTO__
pl_t (splbase) (void)
#else
pl_t
splbase __ARGS (())
#endif
{
#ifdef splbase
return splbase ();
#else
return splx (plbase);
#endif
}
#if __USE_PROTO__
pl_t (spltimeout) (void)
#else
pl_t
spltimeout __ARGS (())
#endif
{
#ifdef spltimeout
return spltimeout ();
#else
return splx (pltimeout);
#endif
}
#if __USE_PROTO__
pl_t (spldisk) (void)
#else
pl_t
spldisk __ARGS (())
#endif
{
#ifdef spldisk
return spldisk ();
#else
return splx (pldisk);
#endif
}
#if __USE_PROTO__
pl_t (splstr) (void)
#else
pl_t
splstr __ARGS (())
#endif
{
#ifdef splstr
return splstr ();
#else
return splx (plstr);
#endif
}
#if __USE_PROTO__
pl_t (splhi) (void)
#else
pl_t
splhi __ARGS (())
#endif
{
#ifdef splhi
return splhi ();
#else
return splx (plhi);
#endif
}
#if __USE_PROTO__
pl_t (splx) (pl_t newpl)
#else
pl_t
splx __ARGS ((newpl))
pl_t newpl;
#endif
{
#ifdef splx
return splx (newpl);
#else
pl_t prev_pl;
intmask_t mask = __GET_BASE_MASK () | _masktab [newpl];
__OUT_IPL_MASK (mask);
prev_pl = (pl_t) ddi_cpu_data ()->dc_ipl;
ddi_cpu_data ()->dc_ipl = newpl;
return prev_pl;
#endif
}
/*
*-STATUS:
* Private internal (used by various assertions)
*
*-NAME:
* splcmp Compare processor priority levels
*
*-ARGUMENTS:
* l Processor priority level considered to be on the LHS
* of the l < r relational comparison.
* r Processor priority that "l" is to be compared with
*
*-DESCRIPTION:
* This functions performs a relational comparison of processor priority
* levels which can be used to test assertions about the relative order
* in which priority levels are set. It is guaranteed that this function
* will return values consistent with the partial order defined by the
* DDI/DKI.
*
* Note that attempting to compare the values "plstr" and "pldisk" is not
* valid. In a system where processor priorities are implemented using
* masks, "pldisk" and "plstr" may be genuinely unordered in that the
* resulting masks may be disjoint. An implementation is free to diagnose
* such a comparison by causing a kernel panic.
*
* This function is intended for use in ASSERT () statements only. If it
* is desired to set the processor priority level to the maximum of two
* values, use splraise () instead so that in an implementation which
* uses masks the logical union or intersection of the masks can be
* taken.
*
*-RETURNS:
* -1 if the level "l" compares less than "r"
* 0 if "l" and "r" specify the same actual priority level
* 1 if the level "l" compares greater that "r"
*
*-LEVEL:
* Base or Interrupt.
*
*-NOTES:
* This function does not sleep.
*
* Driver-defined basic locks, read/write locks and sleep locks may be
* held across calls to this function.
*/
#if __USE_PROTO__
int (splcmp) (pl_t l, pl_t r)
#else
int
splcmp __ARGS ((l, r))
pl_t l;
pl_t r;
#endif
{
return (l < r) ? -1 : l != r;
}
/*
*-STATUS:
* Private internal (used by freezestr ())
*
*-NAME:
* splraise Raise processor priority level.
*
*-ARGUMENTS:
* pl Processor interrupt priority level to raise to.
*
*-DESCRIPTION:
* splraise () changes the processor interrupt priority level to the
* maximum value defined by the previous level and the current level.
*
* If the previous and requested priority levels are "pldisk" and "plstr"
* (in either order) this function does the appropriate action given that
* the "maximum" level in a mask-based system is in the fact the union or
* intersection of the two masks.
*
*-RETURNS:
* The previous processor interrupt priority level.
*
*-LEVEL:
* Base or Interrupt.
*
*-NOTES:
* This function does not sleep.
*
* Driver-defined basic locks, read/write locks and sleep locks may be
* held across calls to this function.
*/
#if __USE_PROTO__
pl_t (splraise) (pl_t newpl)
#else
pl_t
splraise __ARGS ((newpl))
pl_t newpl;
#endif
{
#ifdef splraise
return splraise (newpl);
#else
pl_t prev_pl;
if (newpl > (prev_pl = (pl_t) ddi_cpu_data ()->dc_ipl)) {
intmask_t mask = __GET_BASE_MASK () | _masktab [newpl];
__OUT_IPL_MASK (mask);
ddi_cpu_data ()->dc_ipl = newpl;
}
return prev_pl;
#endif
}