Kernel Functions for Drivers ddiaddsoftintr(9F)
NAME
ddiaddsoftintr, ddigetsoftiblockcookie,
ddiremovesoftintr, dditriggersoftintr - software inter-
rupt handling routines
SYNOPSIS
#include
#include
#include
#include
int ddigetsoftiblockcookie(devinfot *dip,
int preference, ddiiblockcookiet *iblockcookiep);
int ddiaddsoftintr(devinfot *dip, int preference, ddisoftintrt *idp,
ddiiblockcookiet *iblockcookiep, ddiidevicecookiet *
idevicecookiep,
uintt(*inthandler) (caddrt inthandlerarg), caddrt
inthandlerarg);
void ddiremovesoftintr(ddisoftintrt id);
void dditriggersoftintr(ddisoftintrt id);
INTERFACE LEVEL
Solaris DI specific (Solaris DI). These interfaces are
obsolete. Use the new interrupt interfaces referenced in
Intro(9F). Refer to Writing Device Drivers for more informa-
tion.
PARAMETERS
ddigetsoftiblockcookie()
dip Pointer to a devinfo structure.
preference The type of soft interrupt to retrieve the
cookie for.
iblockcookiep Pointer to a location to store the inter-
rupt block cookie.
SunOS 5.11 Last change: 19 Oct 2005 1
Kernel Functions for Drivers ddiaddsoftintr(9F)
ddiaddsoftintr()
dip Pointer to devinfo structure.
preference A hint value describing the type of soft
interrupt to generate.
idp Pointer to a soft interrupt identifier
where a returned soft interrupt identif-
ier is stored.
iblockcookiep Optional pointer to an interrupt block
cookie where a returned interrupt block
cookie is stored.
idevicecookiep Optional pointer to an interrupt device
cookie where a returned interrupt device
cookie is stored (not used).
inthandler Pointer to interrupt handler.
inthandlerarg Argument for interrupt handler.
ddiremovesoftintr()
id The identifier specifying which soft interrupt handler
to remove.
dditriggersoftintr()
id The identifier specifying which soft interrupt to
trigger and which soft interrupt handler will be
called.
DESCRIPTION
For ddigetsoftiblockcookie():
ddigetsoftiblockcookie() retrieves the interrupt block
cookie associated with a particular soft interrupt prefer-
ence level. This routine should be called before
SunOS 5.11 Last change: 19 Oct 2005 2
Kernel Functions for Drivers ddiaddsoftintr(9F)
ddiaddsoftintr() to retrieve the interrupt block cookie
needed to initialize locks ( mutex(9F), rwlock(9F)) used by
the software interrupt routine. preference determines which
type of soft interrupt to retrieve the cookie for. The pos-
sible values for preference are:
DISOFTINTLOW Low priority soft interrupt.
DISOFTINTMED Medium priority soft interrupt.
DISOFTINTHIGH High priority soft interrupt.
On a successful return, iblockcookiep contains information
needed for initializing locks associated with this soft
interrupt (see mutexinit(9F) and rwinit(9F)). The driver
can then initialize mutexes acquired by the interrupt rou-
tine before calling ddiaddsoftintr() which prevents a pos-
sible race condition where the driver's soft interrupt
handler is called immediately after the driver has called
ddiaddsoftintr() but before the driver has initialized the
mutexes. This can happen when a soft interrupt for a dif-
ferent device occurs on the same soft interrupt priority
level. If the soft interrupt routine acquires the mutex
before it has been initialized, undefined behavior may
result.
For ddiaddsoftintr():
ddiaddsoftintr() adds a soft interrupt to the system. The
user specified hint preference identifies three suggested
levels for the system to attempt to allocate the soft inter-
rupt priority at. The value for preference should be the
same as that used in the corresponding call to
ddigetsoftiblockcookie(). Refer to the description of
ddigetsoftiblockcookie() above.
The value returned in the location pointed at by idp is the
soft interrupt identifier. This value is used in later calls
to ddiremovesoftintr() and dditriggersoftintr() to iden-
tify the soft interrupt and the soft interrupt handler.
The value returned in the location pointed at by
iblockcookiep is an interrupt block cookie which contains
information used for initializing mutexes associated with
SunOS 5.11 Last change: 19 Oct 2005 3
Kernel Functions for Drivers ddiaddsoftintr(9F)
this soft interrupt (see mutexinit(9F) and rwinit(9F)).
Note that the interrupt block cookie is normally obtained
using ddigetsoftiblockcookie() to avoid the race condi-
tions described above (refer to the description of
ddigetsoftiblockcookie() above). For this reason,
iblockcookiep is no longer useful and should be set to
NUL.
idevicecookiep is not used and should be set to NUL.
The routine inthandler, with its argument inthandlerarg,
is called upon receipt of a software interrupt. Software
interrupt handlers must not assume that they have work to do
when they run, since (like hardware interrupt handlers) they
may run because a soft interrupt occurred for some other
reason. For example, another driver may have triggered a
soft interrupt at the same level. For this reason, before
triggering the soft interrupt, the driver must indicate to
its soft interrupt handler that it should do work. This is
usually done by setting a flag in the state structure. The
routine inthandler checks this flag, reachable through
inthandlerarg, to determine if it should claim the inter-
rupt and do its work.
The interrupt handler must return DINTRCLAIMED if the
interrupt was claimed, DINTRUNCLAIMED otherwise.
If successful, ddiaddsoftintr() will return DISUCES;
if the interrupt information cannot be found, it will return
DIFAILURE.
For ddiremovesoftintr():
ddiremovesoftintr() removes a soft interrupt from the sys-
tem. The soft interrupt identifier id, which was returned
from a call to ddiaddsoftintr(), is used to determine
which soft interrupt and which soft interrupt handler to
remove. Drivers must remove any soft interrupt handlers
before allowing the system to unload the driver.
For dditriggersoftintr():
dditriggersoftintr() triggers a soft interrupt. The soft
interrupt identifier id is used to determine which soft
SunOS 5.11 Last change: 19 Oct 2005 4
Kernel Functions for Drivers ddiaddsoftintr(9F)
interrupt to trigger. This function is used by device
drivers when they wish to trigger a soft interrupt which has
been set up using ddiaddsoftintr().
RETURN VALUES
ddiaddsoftintr() and ddigetsoftiblockcookie() return:
DISUCES on success
DIFAILURE on failure
CONTEXT
These functions can be called from user or kernel context.
dditriggersoftintr() may be called from high-level inter-
rupt context as well.
EXAMPLES
Example 1 device using high-level interrupts
In the following example, the device uses high-level inter-
rupts. High-level interrupts are those that interrupt at the
level of the scheduler and above. High level interrupts must
be handled without using system services that manipulate
thread or process states, because these interrupts are not
blocked by the scheduler. In addition, high level interrupt
handlers must take care to do a minimum of work because they
are not preemptable. See ddiintrhilevel(9F).
In the example, the high-level interrupt routine minimally
services the device, and enqueues the data for later pro-
cessing by the soft interrupt handler. If the soft interrupt
handler is not currently running, the high-level interrupt
routine triggers a soft interrupt so the soft interrupt
handler can process the data. Once running, the soft inter-
rupt handler processes all the enqueued data before return-
ing.
The state structure contains two mutexes. The high-level
mutex is used to protect data shared between the high-level
interrupt handler and the soft interrupt handler. The low-
level mutex is used to protect the rest of the driver from
the soft interrupt handler.
struct xxstate {
SunOS 5.11 Last change: 19 Oct 2005 5
Kernel Functions for Drivers ddiaddsoftintr(9F)
...
ddisoftintrt id;
ddiiblockcookiet highiblockcookie;
kmutext highmutex;
ddiiblockcookiet lowiblockcookie;
kmutext lowmutex;
int softintrunning;
...
};
struct xxstate *xsp;
static uintt xxsoftintr(caddrt);
static uintt xxhighintr(caddrt);
...
Example 2 sample attach() routine
The following code fragment would usually appear in the
driver's attach(9E) routine. ddiaddintr(9F) is used to add
the high-level interrupt handler and ddiaddsoftintr() is
used to add the low-level interrupt routine.
static uintt
xxattach(devinfot *dip, ddiattachcmdt cmd)
{
struct xxstate *xsp;
...
/* get high-level iblock cookie */
if (ddigetiblockcookie(dip, inumber,
&xsp->highiblockcookie) != DISUCES) {
/* clean up */
return (DIFAILURE); /* fail attach */
}
/* initialize high-level mutex */
mutexinit(&xsp->highmutex, "xx high mutex", MUTEXDRIVER,
(void *)xsp->highiblockcookie);
/* add high-level routine - xxhighintr() */
if (ddiaddintr(dip, inumber, NUL, NUL,
xxhighintr, (caddrt) xsp) != DISUCES) {
/* cleanup */
return (DIFAILURE); /* fail attach */
}
/* get soft iblock cookie */
if (ddigetsoftiblockcookie(dip, DISOFTINTMED,
&xsp->lowiblockcookie) != DISUCES) {
/* clean up */
return (DIFAILURE); /* fail attach */
SunOS 5.11 Last change: 19 Oct 2005 6
Kernel Functions for Drivers ddiaddsoftintr(9F)
}
/* initialize low-level mutex */
mutexinit(&xsp->lowmutex, "xx low mutex", MUTEXDRIVER,
(void *)xsp->lowiblockcookie);
/* add low level routine - xxsoftintr() */
if ( ddiaddsoftintr(dip, DISOFTINTMED, &xsp->id,
NUL, NUL, xxsoftintr, (caddrt) xsp) != DISUCES) {
/* cleanup */
return (DIFAILURE); /* fail attach */
}
...
}
Example 3 High-level interrupt routine
The next code fragment represents the high-level interrupt
routine. The high-level interrupt routine minimally services
the device, and enqueues the data for later processing by
the soft interrupt routine. If the soft interrupt routine is
not already running, dditriggersoftintr() is called to
start the routine. The soft interrupt routine will run until
there is no more data on the queue.
static uintt
xxhighintr(caddrt arg)
{
struct xxstate *xsp = (struct xxstate *) arg;
int needsoftint;
...
mutexenter(&xsp->highmutex);
/*
* Verify this device generated the interrupt
* and disable the device interrupt.
* Enqueue data for xxsoftintr() processing.
*/
/* is xxsoftintr() already running ? */
if (xsp->softintrunning)
needsoftint = 0;
else
needsoftint = 1;
mutexexit(&xsp->highmutex);
/* read-only access to xsp->id, no mutex needed */
if (needsoftint)
dditriggersoftintr(xsp->id);
SunOS 5.11 Last change: 19 Oct 2005 7
Kernel Functions for Drivers ddiaddsoftintr(9F)
...
return (DINTRCLAIMED);
}
static uintt
xxsoftintr(caddrt arg)
{
struct xxstate *xsp = (struct xxstate *) arg;
...
mutexenter(&xsp->lowmutex);
mutexenter(&xsp->highmutex);
/* verify there is work to do */
if (work queue empty xsp->softintrunning ) {
mutexexit(&xsp->highmutex);
mutexexit(&xsp->lowmutex);
return (DINTRUNCLAIMED);
}
xsp->softintrunning = 1;
while ( data on queue ) {
ASERT(mutexowned(&xsp->highmutex));
/* de-queue data */
mutexexit(&xsp->highmutex);
/* Process data on queue */
mutexenter(&xsp->highmutex);
}
xsp->softintrunning = 0;
mutexexit(&xsp->highmutex);
mutexexit(&xsp->lowmutex);
return (DINTRCLAIMED);
}
ATRIBUTES
See attributes(5) for descriptions of the following attri-
butes:
SunOS 5.11 Last change: 19 Oct 2005 8
Kernel Functions for Drivers ddiaddsoftintr(9F)
ATRIBUTE TYPE ATRIBUTE VALUE
Interface Stability Obsolete
SEE ALSO
ddiaddintr(9F), ddiinpanic(9F), ddiintrhilevel(9F),
ddiremoveintr(9F), Intro(9F), mutexinit(9F)
Writing Device Drivers
NOTES
ddiaddsoftintr() may not be used to add the same software
interrupt handler more than once. This is true even if a
different value is used for inthandlerarg in each of the
calls to ddiaddsoftintr(). Instead, the argument passed to
the interrupt handler should indicate what service(s) the
interrupt handler should perform. For example, the argument
could be a pointer to the device's soft state structure,
which could contain a 'whichservice' field that the handler
examines. The driver must set this field to the appropriate
value before calling dditriggersoftintr().
SunOS 5.11 Last change: 19 Oct 2005 9
|