Kernel Functions for Drivers ddiintrduphandler(9F)
NAME
ddiintrduphandler - reuse interrupt handler and arguments
for MSI-X interrupts
SYNOPSIS
#include
#include
#include
#include
int ddiintrduphandler(ddiintrhandlet primary, int vector,
ddiintrhandlet *new);
INTERFACE LEVEL
Solaris DI specific (Solaris DI).
PARAMETERS
primary Original DI interrupt handle
vector Interrupt number to duplicate
new Pointer to new DI interrupt handle
DESCRIPTION
The ddiintrduphandler() function is a feature for MSI-X
interrupts that allows an unallocated interrupt vector of a
device to use a previously initialized or added primary
MSI-X interrupt vector in order to share the same vector
address, vector data, interrupt handler, and handler argu-
ments. This feature allows a driver to alias the resources
provided by the Solaris Operating System to the unallocated
interrupt vectors on an associated device. For example, if 2
MSI-X interrupts were allocated to a driver and 32 inter-
rupts were supported on the device, the driver could alias
the 2 interrupts it received to the 30 remaining on the dev-
ice.
The ddiintrduphandler() function must be called after the
primary interrupt handle has been added to the system or
enabled by ddiintraddhandler(9F) and ddiintrenable(9F)
calls, respectively. If successful, the function returns the
new interrupt handle for a given vector in the new argument
passed to the function. The new interrupt handle must not
have been previously allocated with ddiintralloc(9F). Oth-
erwise, the ddiintrduphandler() call will fail.
SunOS 5.11 Last change: 09 May 2006 1
Kernel Functions for Drivers ddiintrduphandler(9F)
The only supported calls on dup-ed interrupt handles are
ddiintrsetmask(9F), ddiintrclrmask(9F),
ddiintrgetpending(9F), ddiintrenable(9F),
ddiintrdisable(9F), and ddiintrfree(9F).
A call to ddiintrduphandler() does not imply that the
interrupt source is automatically enabled. Initially, the
dup-ed handle is in the disabled state and must be enabled
before it can be used by calling ddiintrenable(). Like-
wise, ddiintrdisable() must be called to disable the
enabled dup-ed interrupt source.
A dup-ed interrupt is removed by calling ddiintrfree()
after it has been disabled. The ddiintrremovehandler(9F)
call is not required for a dup-ed handle.
Before removing the original MSI-X interrupt handler, all
dup-ed interrupt handlers associated with this MSI-X inter-
rupt must have been disabled and freed. Otherwise, calls to
ddiintrremovehandler() will fail with DIFAILURE.
See the EXAMPLES section for code that illustrates the use
of the ddiintrduphandler() function.
RETURN VALUES
The ddiintrduphandler() function returns:
DISUCES On success.
Note that the interface should be verified to
ensure that the return value is not equal to
DISUCES. Incomplete checking for failure
codes could result in inconsistent behavior
among platforms.
DIEINVAL On encountering invalid input parameters.
DIEINVAL is also returned if a dup is
attempted from a dup-ed interrupt or if the
hardware device is found not to support MSI-X
interrupts.
DIFAILURE On any implementation specific failure.
EXAMPLES
SunOS 5.11 Last change: 09 May 2006 2
Kernel Functions for Drivers ddiintrduphandler(9F)
Example 1 Using the ddiintrduphandler() function
int
addmsixinterrupts(intrstatet *state)
{
int x, y;
/*
* For this example, assume the device supports multiple
* interrupt vectors, but only request to be allocated
* 1 MSI-X to use and then dup the rest.
*/
if (ddiintrgetnintrs(state->dip, DINTRTYPEMSIX,
&state->intrcount) != DISUCES) {
cmnerr(CEWARN, "Failed to retrieve the MSI-X interrupt count");
return (DIFAILURE);
}
state->intrsize = state->intrcount * sizeof (ddiintrhandlet);
state->intrhtable = kmemzalloc(state->intrsize, KMSLEP);
/* Allocate one MSI-X interrupt handle */
if (ddiintralloc(state->dip, state->intrhtable,
DINTRTYPEMSIX, state->inum, 1, &state->actual,
DINTRALOCSTRICT) != DISUCES) {
cmnerr(CEWARN, "Failed to allocate MSI-X interrupt");
kmemfree(state->intrhtable, state->intrsize);
return (DIFAILURE);
}
/* Get the count of how many MSI-X interrupts we dup */
state->dupcnt = state->intrcount - state->actual;
if (ddiintrgetpri(state->intrhtable[0],
&state->intrpri) != DISUCES) {
cmnerr(CEWARN, "Failed to get interrupt priority");
goto error1;
}
/* Make sure the MSI-X priority is below 'high level' */
if (state->intrpri >= ddiintrgethilevelpri()) {
cmnerr(CEWARN, "Interrupt PRI is too high");
goto error1;
}
/*
* Add the handler for the interrupt
*/
if (ddiintraddhandler(state->intrhtable[0],
(ddiintrhandlert *)intrisr, (caddrt)state,
NUL) != DISUCES) {
cmnerr(CEWARN, "Failed to add interrupt handler");
SunOS 5.11 Last change: 09 May 2006 3
Kernel Functions for Drivers ddiintrduphandler(9F)
goto error1;
}
/* Enable the main MSI-X handle first */
if (ddiintrenable(state->intrhtable[0]) != DISUCES) {
cmnerr(CEWARN, "Failed to enable interrupt");
goto error2;
}
/*
* Create and enable dups of the original MSI-X handler, note
* that the inum we are using starts at 0.
*/
for (x = 1; x < state->dupcnt; x]) {
if (ddiintrduphandler(state->intrhtable[0],
state->inum ] x, &state->intrhtable[x]) != DISUCES) {
for (y = x - 1; y > 0; y--) {
(void) ddiintrdisable(state->intrhtable[y]);
(void) ddiintrfree(state->intrhtable[y]);
}
goto error2;
}
if (ddiintrenable(state->intrhtable[x]) != DISUCES) {
for (y = x; y > 0; y--) {
(void) ddiintrdisable(state->intrhtable[y]);
(void) ddiintrfree(state->intrhtable[y]);
}
goto error2;
}
}
return (DISUCES);
error2:
(void) ddiintrremovehandler(state->intrhtable[0]);
error1:
(void) ddiintrfree(state->intrhtable[0]);
kmemfree(state->intrhtable, state->intrsize);
return (DIFAILURE);
}
void
removemsixinterrupts(intrstatet *state)
{
int x;
/*
* Disable all the handles and free the dup-ed handles
* before we can remove the main MSI-X interrupt handle.
SunOS 5.11 Last change: 09 May 2006 4
Kernel Functions for Drivers ddiintrduphandler(9F)
*/
for (x = 1; x < state->dupcnt; x]) {
(void) ddiintrdisable(state->intrhtable[x]);
(void) ddiintrfree(state->intrhtable[x]);
}
/*
* We can remove and free the main MSI-X handler now
* that all the dups have been freed.
*/
(void) ddiintrdisable(state->intrhtable[0]);
(void) ddiintrremovehandler(state->intrhtable[0]);
(void) ddiintrfree(state->intrhtable[0]);
kmemfree(state->intrhtable, state->intrsize);
}
CONTEXT
The ddiintrduphandler() function can be called from ker-
nel non-interrupt context.
ATRIBUTES
See attributes(5) for descriptions of the following attri-
butes:
ATRIBUTE TYPE ATRIBUTE VALUE
Interface Stability Committed
SEE ALSO
attributes(5), ddiintraddhandler(9F), ddiintralloc(9F),
ddiintrclrmask(9F), ddiintrdisable(9F),
ddiintrenable(9F), ddiintrfree(9F),
ddiintrgetpending(9F), ddiintrgetsupportedtypes(9F),
ddiintrsetmask(9F)
Writing Device Drivers
SunOS 5.11 Last change: 09 May 2006 5
|