1ddi_intr_dup_handler(9F) Kernel Functions for Drivers ddi_intr_dup_handler(9F)
2
3
4

NAME

6       ddi_intr_dup_handler  - reuse interrupt handler and arguments for MSI-X
7       interrupts
8

SYNOPSIS

10       #include <sys/types.h>
11       #include <sys/conf.h>
12       #include <sys/ddi.h>
13       #include <sys/sunddi.h>
14
15       int ddi_intr_dup_handler(ddi_intr_handle_t primary, int vector,
16            ddi_intr_handle_t *new);
17
18

INTERFACE LEVEL

20       Solaris DDI specific (Solaris DDI).
21

PARAMETERS

23       primary    Original DDI interrupt handle
24
25
26       vector     Interrupt number to duplicate
27
28
29       new        Pointer to new DDI interrupt handle
30
31

DESCRIPTION

33       The ddi_intr_dup_handler() function is a feature for  MSI-X  interrupts
34       that allows an unallocated interrupt vector of a device to use a previ‐
35       ously initialized or added primary MSI-X interrupt vector in  order  to
36       share the same vector address, vector data, interrupt handler, and han‐
37       dler arguments. This feature allows a driver  to  alias  the  resources
38       provided  by  the Solaris Operating System to the unallocated interrupt
39       vectors on an associated device. For example,  if  2  MSI-X  interrupts
40       were  allocated  to  a  driver  and 32 interrupts were supported on the
41       device, the driver could alias the 2 interrupts it received to  the  30
42       remaining on the device.
43
44
45       The  ddi_intr_dup_handler()  function  must be called after the primary
46       interrupt  handle  has  been  added  to  the  system  or   enabled   by
47       ddi_intr_add_handler(9F)  and  ddi_intr_enable(9F) calls, respectively.
48       If successful, the function returns the  new  interrupt  handle  for  a
49       given vector in the new argument passed to the function. The new inter‐
50       rupt  handle   must   not   have   been   previously   allocated   with
51       ddi_intr_alloc(9F).  Otherwise,  the  ddi_intr_dup_handler()  call will
52       fail.
53
54
55       The  only   supported   calls   on   dup-ed   interrupt   handles   are
56       ddi_intr_set_mask(9F), ddi_intr_clr_mask(9F), ddi_intr_get_pending(9F),
57       ddi_intr_enable(9F), ddi_intr_disable(9F), and ddi_intr_free(9F).
58
59
60       A call to ddi_intr_dup_handler() does  not  imply  that  the  interrupt
61       source is automatically enabled. Initially, the dup-ed handle is in the
62       disabled state and must be enabled before it can  be  used  by  calling
63       ddi_intr_enable().  Likewise, ddi_intr_disable() must be called to dis‐
64       able the enabled dup-ed interrupt source.
65
66
67       A dup-ed interrupt is removed by calling ddi_intr_free() after  it  has
68       been disabled. The ddi_intr_remove_handler(9F) call is not required for
69       a dup-ed handle.
70
71
72       Before removing the original MSI-X interrupt handler, all dup-ed inter‐
73       rupt  handlers associated with this MSI-X interrupt must have been dis‐
74       abled and freed. Otherwise,  calls  to  ddi_intr_remove_handler()  will
75       fail with DDI_FAILURE.
76
77
78       See  the  EXAMPLES  section  for  code  that illustrates the use of the
79       ddi_intr_dup_handler() function.
80

RETURN VALUES

82       The ddi_intr_dup_handler() function returns:
83
84       DDI_SUCCESS    On success.
85
86                      Note that the interface should  be  verified  to  ensure
87                      that  the  return  value  is  not  equal to DDI_SUCCESS.
88                      Incomplete checking for failure codes  could  result  in
89                      inconsistent behavior among platforms.
90
91
92       DDI_EINVAL     On  encountering invalid input parameters. DDI_EINVAL is
93                      also returned if a dup is attempted from a dup-ed inter‐
94                      rupt  or  if the hardware device is found not to support
95                      MSI-X interrupts.
96
97
98       DDI_FAILURE    On any implementation specific failure.
99
100

EXAMPLES

102       Example 1 Using the ddi_intr_dup_handler() function
103
104         int
105         add_msix_interrupts(intr_state_t *state)
106         {
107           int x, y;
108
109           /*
110            * For this example, assume the device supports multiple
111            * interrupt vectors, but only request to be allocated
112            * 1 MSI-X to use and then dup the rest.
113            */
114           if (ddi_intr_get_nintrs(state->dip, DDI_INTR_TYPE_MSIX,
115              &state->intr_count) != DDI_SUCCESS) {
116                   cmn_err(CE_WARN, "Failed to retrieve the MSI-X interrupt count");
117                   return (DDI_FAILURE);
118           }
119
120           state->intr_size = state->intr_count * sizeof (ddi_intr_handle_t);
121           state->intr_htable = kmem_zalloc(state->intr_size, KM_SLEEP);
122
123           /* Allocate one MSI-X interrupt handle */
124           if (ddi_intr_alloc(state->dip, state->intr_htable,
125               DDI_INTR_TYPE_MSIX, state->inum, 1, &state->actual,
126               DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) {
127                   cmn_err(CE_WARN, "Failed to allocate MSI-X interrupt");
128                   kmem_free(state->intr_htable, state->intr_size);
129                   return (DDI_FAILURE);
130           }
131
132           /* Get the count of how many MSI-X interrupts we dup */
133           state->dup_cnt = state->intr_count - state->actual;
134
135           if (ddi_intr_get_pri(state->intr_htable[0],
136               &state->intr_pri) != DDI_SUCCESS) {
137                   cmn_err(CE_WARN, "Failed to get interrupt priority");
138                   goto error1;
139           }
140
141           /* Make sure the MSI-X priority is below 'high level' */
142           if (state->intr_pri >= ddi_intr_get_hilevel_pri()) {
143                  cmn_err(CE_WARN, "Interrupt PRI is too high");
144                   goto error1;
145           }
146
147           /*
148            * Add the handler for the interrupt
149            */
150           if (ddi_intr_add_handler(state->intr_htable[0],
151               (ddi_intr_handler_t *)intr_isr, (caddr_t)state,
152               NULL) != DDI_SUCCESS) {
153                   cmn_err(CE_WARN, "Failed to add interrupt handler");
154                   goto error1;
155           }
156
157           /* Enable the main MSI-X handle first */
158           if (ddi_intr_enable(state->intr_htable[0]) != DDI_SUCCESS) {
159                   cmn_err(CE_WARN, "Failed to enable interrupt");
160                   goto error2;
161           }
162
163           /*
164            * Create and enable dups of the original MSI-X handler, note
165            * that the inum we are using starts at 0.
166            */
167           for (x = 1; x < state->dup_cnt; x++) {
168               if (ddi_intr_dup_handler(state->intr_htable[0],
169                   state->inum + x, &state->intr_htable[x]) != DDI_SUCCESS) {
170                       for (y = x - 1; y > 0; y--) {
171                           (void) ddi_intr_disable(state->intr_htable[y]);
172                           (void) ddi_intr_free(state->intr_htable[y]);
173                       }
174
175                   goto error2;
176               }
177               if (ddi_intr_enable(state->intr_htable[x]) != DDI_SUCCESS) {
178                   for (y = x; y > 0; y--) {
179                       (void) ddi_intr_disable(state->intr_htable[y]);
180                       (void) ddi_intr_free(state->intr_htable[y]);
181                   }
182
183                   goto error2;
184               }
185           }
186
187           return (DDI_SUCCESS);
188
189         error2:
190             (void) ddi_intr_remove_handler(state->intr_htable[0]);
191         error1:
192             (void) ddi_intr_free(state->intr_htable[0]);
193
194             kmem_free(state->intr_htable, state->intr_size);
195             return (DDI_FAILURE);
196         }
197
198         void
199         remove_msix_interrupts(intr_state_t *state)
200         {
201             int x;
202
203             /*
204              * Disable all the handles and free the dup-ed handles
205              * before we can remove the main MSI-X interrupt handle.
206              */
207             for (x = 1; x < state->dup_cnt; x++) {
208                 (void) ddi_intr_disable(state->intr_htable[x]);
209                 (void) ddi_intr_free(state->intr_htable[x]);
210             }
211
212             /*
213              * We can remove and free the main MSI-X handler now
214              * that all the dups have been freed.
215              */
216             (void) ddi_intr_disable(state->intr_htable[0]);
217             (void) ddi_intr_remove_handler(state->intr_htable[0]);
218             (void) ddi_intr_free(state->intr_htable[0]);
219
220             kmem_free(state->intr_htable, state->intr_size);
221         }
222
223

CONTEXT

225       The ddi_intr_dup_handler() function can  be  called  from  kernel  non-
226       interrupt context.
227

ATTRIBUTES

229       See attributes(5) for descriptions of the following attributes:
230
231
232
233
234       ┌─────────────────────────────┬─────────────────────────────┐
235       │      ATTRIBUTE TYPE         │      ATTRIBUTE VALUE        │
236       ├─────────────────────────────┼─────────────────────────────┤
237       │Interface Stability          │Committed                    │
238       └─────────────────────────────┴─────────────────────────────┘
239

SEE ALSO

241       attributes(5),       ddi_intr_add_handler(9F),      ddi_intr_alloc(9F),
242       ddi_intr_clr_mask(9F),    ddi_intr_disable(9F),    ddi_intr_enable(9F),
243       ddi_intr_free(9F),      ddi_intr_get_pending(9F),     ddi_intr_get_sup‐
244       ported_types(9F), ddi_intr_set_mask(9F)
245
246
247       Writing Device Drivers
248
249
250
251SunOS 5.11                        09 May 2006         ddi_intr_dup_handler(9F)
Impressum