Linux and UNIX Man Pages

Linux & Unix Commands - Search Man Pages

ddi_intr_dup_handler(9f) [opensolaris man page]

ddi_intr_dup_handler(9F)				   Kernel Functions for Drivers 				  ddi_intr_dup_handler(9F)

ddi_intr_dup_handler - reuse interrupt handler and arguments for MSI-X interrupts SYNOPSIS
#include <sys/types.h> #include <sys/conf.h> #include <sys/ddi.h> #include <sys/sunddi.h> int ddi_intr_dup_handler(ddi_intr_handle_t primary, int vector, ddi_intr_handle_t *new); INTERFACE LEVEL
Solaris DDI specific (Solaris DDI). PARAMETERS
primary Original DDI interrupt handle vector Interrupt number to duplicate new Pointer to new DDI interrupt handle DESCRIPTION
The ddi_intr_dup_handler() function is a feature for MSI-X interrupts that allows an unallocated interrupt vector of a device to use a pre- viously initialized or added primary MSI-X interrupt vector in order to share the same vector address, vector data, interrupt handler, and handler arguments. This feature allows a driver to alias the resources provided by the Solaris Operating System to the unallocated inter- rupt vectors on an associated device. For example, if 2 MSI-X interrupts were allocated to a driver and 32 interrupts were supported on the device, the driver could alias the 2 interrupts it received to the 30 remaining on the device. The ddi_intr_dup_handler() function must be called after the primary interrupt handle has been added to the system or enabled by ddi_intr_add_handler(9F) and ddi_intr_enable(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 ddi_intr_alloc(9F). Otherwise, the ddi_intr_dup_handler() call will fail. The only supported calls on dup-ed interrupt handles are ddi_intr_set_mask(9F), ddi_intr_clr_mask(9F), ddi_intr_get_pending(9F), ddi_intr_enable(9F), ddi_intr_disable(9F), and ddi_intr_free(9F). A call to ddi_intr_dup_handler() 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 ddi_intr_enable(). Likewise, ddi_intr_disable() must be called to dis- able the enabled dup-ed interrupt source. A dup-ed interrupt is removed by calling ddi_intr_free() after it has been disabled. The ddi_intr_remove_handler(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 interrupt must have been disabled and freed. Otherwise, calls to ddi_intr_remove_handler() will fail with DDI_FAILURE. See the EXAMPLES section for code that illustrates the use of the ddi_intr_dup_handler() function. RETURN VALUES
The ddi_intr_dup_handler() function returns: DDI_SUCCESS On success. Note that the interface should be verified to ensure that the return value is not equal to DDI_SUCCESS. Incomplete checking for failure codes could result in inconsistent behavior among platforms. DDI_EINVAL On encountering invalid input parameters. DDI_EINVAL 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. DDI_FAILURE On any implementation specific failure. EXAMPLES
Example 1 Using the ddi_intr_dup_handler() function int add_msix_interrupts(intr_state_t *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 (ddi_intr_get_nintrs(state->dip, DDI_INTR_TYPE_MSIX, &state->intr_count) != DDI_SUCCESS) { cmn_err(CE_WARN, "Failed to retrieve the MSI-X interrupt count"); return (DDI_FAILURE); } state->intr_size = state->intr_count * sizeof (ddi_intr_handle_t); state->intr_htable = kmem_zalloc(state->intr_size, KM_SLEEP); /* Allocate one MSI-X interrupt handle */ if (ddi_intr_alloc(state->dip, state->intr_htable, DDI_INTR_TYPE_MSIX, state->inum, 1, &state->actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) { cmn_err(CE_WARN, "Failed to allocate MSI-X interrupt"); kmem_free(state->intr_htable, state->intr_size); return (DDI_FAILURE); } /* Get the count of how many MSI-X interrupts we dup */ state->dup_cnt = state->intr_count - state->actual; if (ddi_intr_get_pri(state->intr_htable[0], &state->intr_pri) != DDI_SUCCESS) { cmn_err(CE_WARN, "Failed to get interrupt priority"); goto error1; } /* Make sure the MSI-X priority is below 'high level' */ if (state->intr_pri >= ddi_intr_get_hilevel_pri()) { cmn_err(CE_WARN, "Interrupt PRI is too high"); goto error1; } /* * Add the handler for the interrupt */ if (ddi_intr_add_handler(state->intr_htable[0], (ddi_intr_handler_t *)intr_isr, (caddr_t)state, NULL) != DDI_SUCCESS) { cmn_err(CE_WARN, "Failed to add interrupt handler"); goto error1; } /* Enable the main MSI-X handle first */ if (ddi_intr_enable(state->intr_htable[0]) != DDI_SUCCESS) { cmn_err(CE_WARN, "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->dup_cnt; x++) { if (ddi_intr_dup_handler(state->intr_htable[0], state->inum + x, &state->intr_htable[x]) != DDI_SUCCESS) { for (y = x - 1; y > 0; y--) { (void) ddi_intr_disable(state->intr_htable[y]); (void) ddi_intr_free(state->intr_htable[y]); } goto error2; } if (ddi_intr_enable(state->intr_htable[x]) != DDI_SUCCESS) { for (y = x; y > 0; y--) { (void) ddi_intr_disable(state->intr_htable[y]); (void) ddi_intr_free(state->intr_htable[y]); } goto error2; } } return (DDI_SUCCESS); error2: (void) ddi_intr_remove_handler(state->intr_htable[0]); error1: (void) ddi_intr_free(state->intr_htable[0]); kmem_free(state->intr_htable, state->intr_size); return (DDI_FAILURE); } void remove_msix_interrupts(intr_state_t *state) { int x; /* * Disable all the handles and free the dup-ed handles * before we can remove the main MSI-X interrupt handle. */ for (x = 1; x < state->dup_cnt; x++) { (void) ddi_intr_disable(state->intr_htable[x]); (void) ddi_intr_free(state->intr_htable[x]); } /* * We can remove and free the main MSI-X handler now * that all the dups have been freed. */ (void) ddi_intr_disable(state->intr_htable[0]); (void) ddi_intr_remove_handler(state->intr_htable[0]); (void) ddi_intr_free(state->intr_htable[0]); kmem_free(state->intr_htable, state->intr_size); } CONTEXT
The ddi_intr_dup_handler() function can be called from kernel non-interrupt context. ATTRIBUTES
See attributes(5) for descriptions of the following attributes: +-----------------------------+-----------------------------+ | ATTRIBUTE TYPE | ATTRIBUTE VALUE | +-----------------------------+-----------------------------+ |Interface Stability |Committed | +-----------------------------+-----------------------------+ SEE ALSO
attributes(5), ddi_intr_add_handler(9F), ddi_intr_alloc(9F), ddi_intr_clr_mask(9F), ddi_intr_disable(9F), ddi_intr_enable(9F), ddi_intr_free(9F), ddi_intr_get_pending(9F), ddi_intr_get_supported_types(9F), ddi_intr_set_mask(9F) Writing Device Drivers SunOS 5.11 09 May 2006 ddi_intr_dup_handler(9F)
Man Page