2 .\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved.
3 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
4 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
5 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
6 .TH DDI_INTR_DUP_HANDLER 9F "May 09, 2006"
8 ddi_intr_dup_handler \- reuse interrupt handler and arguments for MSI-X
13 #include <sys/types.h>
16 #include <sys/sunddi.h>
18 \fBint\fR \fBddi_intr_dup_handler\fR(\fBddi_intr_handle_t\fR \fIprimary\fR, \fBint\fR \fIvector\fR,
19 \fBddi_intr_handle_t *\fR\fInew\fR);
25 Solaris DDI specific (Solaris DDI).
33 Original DDI interrupt handle
42 Interrupt number to duplicate
51 Pointer to new DDI interrupt handle
57 The \fBddi_intr_dup_handler()\fR function is a feature for MSI-X interrupts
58 that allows an unallocated interrupt vector of a device to use a previously
59 initialized or added primary MSI-X interrupt vector in order to share the same
60 vector address, vector data, interrupt handler, and handler arguments. This
61 feature allows a driver to alias the resources provided by the Solaris
62 Operating System to the unallocated interrupt vectors on an associated device.
63 For example, if 2 MSI-X interrupts were allocated to a driver and 32 interrupts
64 were supported on the device, the driver could alias the 2 interrupts it
65 received to the 30 remaining on the device.
68 The \fBddi_intr_dup_handler()\fR function must be called after the primary
69 interrupt handle has been added to the system or enabled by
70 \fBddi_intr_add_handler\fR(9F) and \fBddi_intr_enable\fR(9F) calls,
71 respectively. If successful, the function returns the new interrupt handle for
72 a given vector in the \fInew\fR argument passed to the function. The new
73 interrupt handle must not have been previously allocated with
74 \fBddi_intr_alloc\fR(9F). Otherwise, the \fBddi_intr_dup_handler()\fR call will
78 The only supported calls on \fIdup-ed\fR interrupt handles are
79 \fBddi_intr_set_mask\fR(9F), \fBddi_intr_clr_mask\fR(9F),
80 \fBddi_intr_get_pending\fR(9F), \fBddi_intr_enable\fR(9F),
81 \fBddi_intr_disable\fR(9F), and \fBddi_intr_free\fR(9F).
84 A call to \fBddi_intr_dup_handler()\fR does not imply that the interrupt source
85 is automatically enabled. Initially, the dup-ed handle is in the disabled state
86 and must be enabled before it can be used by calling \fBddi_intr_enable()\fR.
87 Likewise, \fBddi_intr_disable()\fR must be called to disable the enabled dup-ed
91 A dup-ed interrupt is removed by calling \fBddi_intr_free()\fR after it has
92 been disabled. The \fBddi_intr_remove_handler\fR(9F) call is not required for a
96 Before removing the original MSI-X interrupt handler, all dup-ed interrupt
97 handlers associated with this MSI-X interrupt must have been disabled and
98 freed. Otherwise, calls to \fBddi_intr_remove_handler()\fR will fail with
102 See the EXAMPLES section for code that illustrates the use of the
103 \fBddi_intr_dup_handler()\fR function.
107 The \fBddi_intr_dup_handler()\fR function returns:
111 \fB\fBDDI_SUCCESS\fR\fR
116 Note that the interface should be verified to ensure that the return value is
117 not equal to \fBDDI_SUCCESS\fR. Incomplete checking for failure codes could
118 result in inconsistent behavior among platforms.
124 \fB\fBDDI_EINVAL\fR\fR
127 On encountering invalid input parameters. \fBDDI_EINVAL\fR is also returned if
128 a dup is attempted from a dup-ed interrupt or if the hardware device is found
129 not to support MSI-X interrupts.
135 \fB\fBDDI_FAILURE\fR\fR
138 On any implementation specific failure.
143 \fBExample 1 \fRUsing the \fBddi_intr_dup_handler()\fR function
148 add_msix_interrupts(intr_state_t *state)
153 * For this example, assume the device supports multiple
154 * interrupt vectors, but only request to be allocated
155 * 1 MSI-X to use and then dup the rest.
157 if (ddi_intr_get_nintrs(state->dip, DDI_INTR_TYPE_MSIX,
158 &state->intr_count) != DDI_SUCCESS) {
159 cmn_err(CE_WARN, "Failed to retrieve the MSI-X interrupt count");
160 return (DDI_FAILURE);
163 state->intr_size = state->intr_count * sizeof (ddi_intr_handle_t);
164 state->intr_htable = kmem_zalloc(state->intr_size, KM_SLEEP);
166 /* Allocate one MSI-X interrupt handle */
167 if (ddi_intr_alloc(state->dip, state->intr_htable,
168 DDI_INTR_TYPE_MSIX, state->inum, 1, &state->actual,
169 DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) {
170 cmn_err(CE_WARN, "Failed to allocate MSI-X interrupt");
171 kmem_free(state->intr_htable, state->intr_size);
172 return (DDI_FAILURE);
175 /* Get the count of how many MSI-X interrupts we dup */
176 state->dup_cnt = state->intr_count - state->actual;
178 if (ddi_intr_get_pri(state->intr_htable[0],
179 &state->intr_pri) != DDI_SUCCESS) {
180 cmn_err(CE_WARN, "Failed to get interrupt priority");
184 /* Make sure the MSI-X priority is below 'high level' */
185 if (state->intr_pri >= ddi_intr_get_hilevel_pri()) {
186 cmn_err(CE_WARN, "Interrupt PRI is too high");
191 * Add the handler for the interrupt
193 if (ddi_intr_add_handler(state->intr_htable[0],
194 (ddi_intr_handler_t *)intr_isr, (caddr_t)state,
195 NULL) != DDI_SUCCESS) {
196 cmn_err(CE_WARN, "Failed to add interrupt handler");
200 /* Enable the main MSI-X handle first */
201 if (ddi_intr_enable(state->intr_htable[0]) != DDI_SUCCESS) {
202 cmn_err(CE_WARN, "Failed to enable interrupt");
207 * Create and enable dups of the original MSI-X handler, note
208 * that the inum we are using starts at 0.
210 for (x = 1; x < state->dup_cnt; x++) {
211 if (ddi_intr_dup_handler(state->intr_htable[0],
212 state->inum + x, &state->intr_htable[x]) != DDI_SUCCESS) {
213 for (y = x - 1; y > 0; y--) {
214 (void) ddi_intr_disable(state->intr_htable[y]);
215 (void) ddi_intr_free(state->intr_htable[y]);
220 if (ddi_intr_enable(state->intr_htable[x]) != DDI_SUCCESS) {
221 for (y = x; y > 0; y--) {
222 (void) ddi_intr_disable(state->intr_htable[y]);
223 (void) ddi_intr_free(state->intr_htable[y]);
230 return (DDI_SUCCESS);
233 (void) ddi_intr_remove_handler(state->intr_htable[0]);
235 (void) ddi_intr_free(state->intr_htable[0]);
237 kmem_free(state->intr_htable, state->intr_size);
238 return (DDI_FAILURE);
242 remove_msix_interrupts(intr_state_t *state)
247 * Disable all the handles and free the dup-ed handles
248 * before we can remove the main MSI-X interrupt handle.
250 for (x = 1; x < state->dup_cnt; x++) {
251 (void) ddi_intr_disable(state->intr_htable[x]);
252 (void) ddi_intr_free(state->intr_htable[x]);
256 * We can remove and free the main MSI-X handler now
257 * that all the dups have been freed.
259 (void) ddi_intr_disable(state->intr_htable[0]);
260 (void) ddi_intr_remove_handler(state->intr_htable[0]);
261 (void) ddi_intr_free(state->intr_htable[0]);
263 kmem_free(state->intr_htable, state->intr_size);
271 The \fBddi_intr_dup_handler()\fR function can be called from kernel
272 non-interrupt context.
276 See \fBattributes\fR(5) for descriptions of the following attributes:
284 ATTRIBUTE TYPE ATTRIBUTE VALUE
286 Interface Stability Committed
292 \fBattributes\fR(5), \fBddi_intr_add_handler\fR(9F), \fBddi_intr_alloc\fR(9F),
293 \fBddi_intr_clr_mask\fR(9F), \fBddi_intr_disable\fR(9F),
294 \fBddi_intr_enable\fR(9F), \fBddi_intr_free\fR(9F),
295 \fBddi_intr_get_pending\fR(9F), \fBddi_intr_get_supported_types\fR(9F),
296 \fBddi_intr_set_mask\fR(9F)
299 \fIWriting Device Drivers\fR