8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / man / man9f / ddi_intr_dup_handler.9f
blob0015714550d6c97bf0bf669aa2ed477a64fca018
1 '\" te
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"
7 .SH NAME
8 ddi_intr_dup_handler \- reuse interrupt handler and arguments for MSI-X
9 interrupts
10 .SH SYNOPSIS
11 .LP
12 .nf
13 #include <sys/types.h>
14 #include <sys/conf.h>
15 #include <sys/ddi.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);
20 .fi
22 .SH INTERFACE LEVEL
23 .sp
24 .LP
25 Solaris DDI specific (Solaris DDI).
26 .SH PARAMETERS
27 .sp
28 .ne 2
29 .na
30 \fB\fIprimary\fR\fR
31 .ad
32 .RS 11n
33 Original DDI interrupt handle
34 .RE
36 .sp
37 .ne 2
38 .na
39 \fB\fIvector\fR\fR
40 .ad
41 .RS 11n
42 Interrupt number to duplicate
43 .RE
45 .sp
46 .ne 2
47 .na
48 \fB\fInew\fR\fR
49 .ad
50 .RS 11n
51 Pointer to new DDI interrupt handle
52 .RE
54 .SH DESCRIPTION
55 .sp
56 .LP
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.
66 .sp
67 .LP
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
75 fail.
76 .sp
77 .LP
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).
82 .sp
83 .LP
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
88 interrupt source.
89 .sp
90 .LP
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
93 dup-ed handle.
94 .sp
95 .LP
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
99 \fBDDI_FAILURE\fR.
102 See the EXAMPLES section for code that illustrates the use of the
103 \fBddi_intr_dup_handler()\fR function.
104 .SH RETURN VALUES
107 The \fBddi_intr_dup_handler()\fR function returns:
109 .ne 2
111 \fB\fBDDI_SUCCESS\fR\fR
113 .RS 15n
114 On success.
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.
122 .ne 2
124 \fB\fBDDI_EINVAL\fR\fR
126 .RS 15n
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.
133 .ne 2
135 \fB\fBDDI_FAILURE\fR\fR
137 .RS 15n
138 On any implementation specific failure.
141 .SH EXAMPLES
143 \fBExample 1 \fRUsing the \fBddi_intr_dup_handler()\fR function
145 .in +2
148 add_msix_interrupts(intr_state_t *state)
150   int x, y;
152   /*
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.
156    */
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);
161   }
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);
173   }
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");
181           goto error1;
182   }
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");
187           goto error1;
188   }
190   /*
191    * Add the handler for the interrupt
192    */
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");
197           goto error1;
198   }
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");
203           goto error2;
204   }
206   /*
207    * Create and enable dups of the original MSI-X handler, note
208    * that the inum we are using starts at 0.
209    */
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]);
216               }
218           goto error2;
219       }
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]);
224           }
226           goto error2;
227       }
228   }
230   return (DDI_SUCCESS);
232 error2:
233     (void) ddi_intr_remove_handler(state->intr_htable[0]);
234 error1:
235     (void) ddi_intr_free(state->intr_htable[0]);
237     kmem_free(state->intr_htable, state->intr_size);
238     return (DDI_FAILURE);
241 void
242 remove_msix_interrupts(intr_state_t *state)
244     int x;
246     /*
247      * Disable all the handles and free the dup-ed handles
248      * before we can remove the main MSI-X interrupt handle.
249      */
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]);
253     }
255     /*
256      * We can remove and free the main MSI-X handler now
257      * that all the dups have been freed.
258      */
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);
266 .in -2
268 .SH CONTEXT
271 The \fBddi_intr_dup_handler()\fR function can be called from kernel
272 non-interrupt context.
273 .SH ATTRIBUTES
276 See \fBattributes\fR(5) for descriptions of the following attributes:
281 box;
282 c | c
283 l | l .
284 ATTRIBUTE TYPE  ATTRIBUTE VALUE
286 Interface Stability     Committed
289 .SH SEE ALSO
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