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

NAME

6       ddi_intr_add_softint,  ddi_intr_remove_softint,  ddi_intr_trigger_soft‐
7       int,  ddi_intr_get_softint_pri,  ddi_intr_set_softint_pri  -   software
8       interrupt handling routines
9

SYNOPSIS

11       #include <sys/types.h>
12       #include <sys/conf.h>
13       #include <sys/ddi.h>
14       #include <sys/sunddi.h>
15
16
17
18       int ddi_intr_add_softint(dev_info_t *dip,
19            ddi_softint_handle_t *h, int soft_pri,
20            ddi_intr_handler_t handler, void *arg1);
21
22
23       int ddi_intr_trigger_softint(ddi_softint_handle_t h,
24             void *arg2);
25
26
27       int ddi_intr_remove_softint(ddi_softint_handle_t h);
28
29
30       int ddi_intr_get_softint_pri(ddi_softint_handle_t h,
31             uint *soft_prip);
32
33
34       int ddi_intr_set_softint_pri(ddi_softint_handle_t h,
35             uint soft_pri);
36
37

INTERFACE LEVEL

39       Solaris DDI specific (Solaris DDI).
40

PARAMETERS

42       ddi_intr_add_softint()
43
44       dip         Pointer to a dev_info structure
45
46
47       h           Pointer to the DDI soft interrupt handle
48
49
50       soft_pri    Priority to associate with a soft interrupt
51
52
53       handler     Pointer to soft interrupt handler
54
55
56       arg1        Argument for the soft interrupt handler
57
58
59
60       ddi_intr_trigger_softint()
61
62       h       DDI soft interrupt handle
63
64
65       arg2    Additional argument for the soft interrupt handler
66
67
68
69       ddi_intr_remove_softint()
70
71       h    DDI soft interrupt handle
72
73
74
75       ddi_intr_get_softint_pri()
76
77       h            DDI soft interrupt handle
78
79
80       soft_prip    Soft interrupt priority of the handle
81
82
83
84       ddi_intr_set_softint_pri()
85
86       h            DDI soft interrupt handle
87
88
89       soft_prip    Soft interrupt priority of the handle
90
91

DESCRIPTION

93       The  ddi_intr_add_softint()  function  adds  the soft interrupt handler
94       given by the handler argument arg1. The handler runs at the soft inter‐
95       rupt priority given by the soft_pri argument.
96
97
98       The  value  returned in the location pointed at by h is the soft inter‐
99       rupt handle. This value is used in later calls to ddi_intr_remove_soft‐
100       int(), ddi_intr_trigger_softint() and ddi_intr_set_softint_pri().
101
102
103       The  software  priority  argument soft_pri is a relative priority value
104       within the range of DDI_INTR_SOFTPRI_MIN and  DDI_INTR_SOFTPRI_MAX.  If
105       the  driver  does  not  know what priority to use, the default soft_pri
106       value of DDI_INTR_SOFTPRI_DEFAULT could be specified. The default value
107       is the lowest possible soft interrupt priority value.
108
109
110       The  soft_pri argument contains the value needed to initialize the lock
111       associated with a soft interrupt. See mutex_init(9F)  and  rw_init(9F).
112       The handler cannot be triggered until the lock is initiatized.
113
114
115       The ddi_intr_remove_softint() function removes the handler for the soft
116       interrupt identified by the interrupt handle h argument. Once  removed,
117       the  soft  interrupt  can  no longer be triggered, although any trigger
118       calls in progress can still be delivered to the handler.
119
120
121       Drivers must remove any soft interrupt  handlers  before  allowing  the
122       system  to  unload  the  driver. Otherwise, kernel resource leaks might
123       occur.
124
125
126       The ddi_intr_trigger_softint() function  triggers  the  soft  interrupt
127       specified  by the interrupt handler h argument. A driver may optionally
128       specify an additional argument arg2 that is passed to the  soft  inter‐
129       rupt  handler. Subsequent ddi_intr_trigger_softint() events, along with
130       arg2, will be dropped until the one pending is serviced and returns the
131       error code DDI_EPENDING.
132
133
134       The  routine  handler, with the arg1 and arg2 arguments, is called upon
135       the receipt of a software interrupt. These were  registered  through  a
136       prior  call to ddi_intr_add_softint(). Software interrupt handlers must
137       not assume that they have work to  do  when  they  run.  Like  hardware
138       interrupt  handlers, they may run because a soft interrupt has occurred
139       for some other reason. For example, another driver may have triggered a
140       soft interrupt at the same level. Before triggering the soft interrupt,
141       the driver must indicate to the soft interrupt handler that it has work
142       to  do.  This is usually done by setting a flag in the state structure.
143       The routine handler checks this flag, reached through arg1 and arg2, to
144       determine if it should claim the interrupt and do its work.
145
146
147       The interrupt handler must return DDI_INTR_CLAIMED if the interrupt was
148       claimed and DDI_INTR_UNCLAIMED otherwise.
149
150
151       The ddi_intr_get_softint_pri() function retrieves  the  soft  interrupt
152       priority,  a  small  integer  value, associated with the soft interrupt
153       handle. The handle is defined by  the  h  argument,  and  the  priority
154       returned  is  in  the  value of the integer pointed to by the soft_prip
155       argument.
156

RETURN VALUES

158       The ddi_intr_add_softint(),  ddi_intr_remove_softint(),  ddi_intr_trig‐
159       ger_softint(),  ddi_intr_get_softint_pri(),  ddi_intr_set_softint_pri()
160       functions return:
161
162       DDI_SUCCESS     On success.
163
164
165       DDI_EAGAIN      On  encountering  internal  error  regarding  currently
166                       unavailable resources.
167
168
169       DDI_EINVAL      On encountering invalid input parameters.
170
171
172       DDI_FAILURE     On any implementation specific failure.
173
174
175       DDI_EPENDING    On  encountering  a  previously triggered softint event
176                       that is pending.
177
178

CONTEXT

180       The ddi_intr_add_softint(),  ddi_intr_remove_softint(),  ddi_intr_trig‐
181       ger_softint(),  ddi_intr_get_softint_pri(),  ddi_intr_set_softint_pri()
182       functions can be called from either user or kernel  non-interrupt  con‐
183       text.
184

EXAMPLES

186       Example 1 Device using high-level interrupts
187
188
189       In  the following example, the device uses high-level interrupts. High-
190       level interrupts are those that interrupt at the level of the scheduler
191       and  above.  High-level interrupts must be handled without using system
192       services that manipulate thread or process states, because these inter‐
193       rupts  are not blocked by the scheduler. In addition, high-level inter‐
194       rupt handlers must take care to do a minimum of work because  they  are
195       not preemptable. See ddi_intr_get_hilevel_pri(9F).
196
197
198
199       In the example, the high-level interrupt routine minimally services the
200       device, and enqueues the data for later processing by the  soft  inter‐
201       rupt  handler.  If the soft interrupt handler is not currently running,
202       the high-level interrupt routine triggers a soft interrupt so the  soft
203       interrupt  handler  can process the data. Once running, the soft inter‐
204       rupt handler processes all the enqueued data before returning.
205
206
207
208       The state structure contains two mutexes. The high-level mutex is  used
209       to protect data shared between the high-level interrupt handler and the
210       soft interrupt handler. The low-level mutex is used to protect the rest
211       of the driver from the soft interrupt handler.
212
213
214         struct xxstate {
215           ...
216           ddi_intr_handle_t       int_hdl;
217           int                     high_pri;
218           kmutex_t                high_mutex;
219           ddi_softint_handle_t    soft_hdl;
220           int                     low_soft_pri;
221           kmutex_t                low_mutex;
222           int                     softint_running;
223           ...
224         };
225
226         struct xxstate *xsp;
227         static uint_t xxsoftint_handler(void *, void *);
228         static uint_t xxhighintr(void *, void *);
229         ...
230
231
232       Example 2 Sample attach() routine
233
234
235       The  following  code  fragment  would  usually  appear  in the driver's
236       attach(9E) routine. ddi_intr_add_handler(9F) is used to add  the  high-
237       level  interrupt  handler and ddi_intr_add_softint() is used to add the
238       low-level interrupt routine.
239
240
241         static uint_t
242         xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
243         {
244            int             types;
245            int             *actual;
246            int             nintrs;
247            struct xxstate  *xsp;
248            ...
249
250            (void) ddi_intr_get_supported_types(dip, &types);
251            (void) ddi_intr_get_nintrs(dip< DDI_INTR_TYPE_FIXED, *nintrs);
252            (void) ddi_intr_alloc(dip, &xsp->int_hdl, DDI_INTR_TYPE_FIXED,
253                1, nintrs, *actual, 0);
254
255            /* initialize high-level mutex */
256            (void) ddi_intr_get_pri(xsp->int_hdl, &>high_pri);
257            mutex_init(&xsp->high_mutex, NULL, MUTEX_DRIVER,
258                DDI_INTR_PRI(xsp->high_pri));
259
260            /* Ensure that this is a hi-level interrupt */
261            if (ddi_intr_get_hilevel_pri(h) != DDI_SUCCESS) {
262                    /* cleanup */
263                    return (DDI_FAILURE); /* fail attach */
264            }
265
266            /* add high-level routine - xxhighintr() */
267            if (ddi_intr_add_handler(xsp->int_hdl, xxhighintr,
268                arg1, NULL) != DDI_SUCCESS) {
269                    /* cleanup */
270                    return (DDI_FAILURE); /* fail attach */
271            }
272
273            /* Enable high-level routine - xxhighintr() */
274            if (ddi_intr_enable(xsp->int_hdl) != DDI_SUCCESS) {
275                    /* cleanup */
276                    return (DDI_FAILURE); /* fail attach */
277            }
278
279            /* Enable soft interrupts */
280            xsp->low_soft_pri = DDI_INTR_SOFTPRI_MIN;
281            if (ddi_intr_add_softint(dip, &xsp>soft_hdl,
282                xsp->low_soft_pri, xxsoftint_handler, arg1) != DDI_SUCCESS) {
283                    /* clean up */
284                    return (DDI_FAILURE); /* fail attach */
285            }
286
287            /* initialize low-level mutex */
288            mutex_init(&xsp->low_mutex, NULL, MUTEX_DRIVER,
289                DDI_INTR_PRI(xsp->low_soft_pri));
290
291            ...
292         }
293
294
295       Example 3 High-level interrupt routine
296
297
298       The next code fragment represents the high-level interrupt routine. The
299       high-level interrupt routine minimally services the device and enqueues
300       the data for later processing by the soft  interrupt  routine.  If  the
301       soft  interrupt  routine is not already running, ddi_intr_trigger_soft‐
302       int() is called to start the routine. The soft interrupt  routine  will
303       run until there is no more data on the queue.
304
305
306         static uint_t
307         xxhighintr(void *arg1, void *arg2)
308         {
309            struct xxstate *xsp = (struct xxstate *)arg1;
310            int need_softint;
311            ...
312            mutex_enter(&xsp->high_mutex);
313            /*
314            * Verify this device generated the interrupt
315            * and disable the device interrupt.
316            * Enqueue data for xxsoftint_handler() processing.
317            */
318
319            /* is xxsoftint_handler() already running ? */
320            need_softint = (xsp->softint_running) ? 0 : 1;
321            mutex_exit(&xsp->high_mutex);
322
323            /* read-only access to xsp->id, no mutex needed */
324            if (xsp->soft_hdl && need_softint)
325                    ddi_intr_trigger_softint(xsp->soft_hdl, arg2);
326            ...
327            return (DDI_INTR_CLAIMED);
328         }
329
330
331         static uint_t
332         xxsoftint_handler(void *arg1, void *arg2)
333         {
334            struct xxstate *xsp = (struct xxstate *)arg1;
335            ...
336            mutex_enter(&xsp->low_mutex);
337            mutex_enter(&xsp->high_mutex);
338
339            /* verify there is work to do */
340            if (work queue empty || xsp->softint_running )  {
341                    mutex_exit(&xsp->high_mutex);
342                    mutex_exit(&xsp->low_mutex);
343                    return (DDI_INTR_UNCLAIMED);
344            }
345
346            xsp->softint_running = 1;
347
348            while ( data on queue )  {
349                    ASSERT(mutex_owned(&xsp->high_mutex));
350                    /* de-queue data */
351                    mutex_exit(&xsp->high_mutex);
352
353                    /* Process data on queue */
354                    mutex_enter(&xsp->high_mutex);
355            }
356
357            xsp->softint_running = 0;
358            mutex_exit(&xsp->high_mutex);
359            mutex_exit(&xsp->low_mutex);
360            return (DDI_INTR_CLAIMED);
361         }
362
363

ATTRIBUTES

365       See attributes(5) for descriptions of the following attributes:
366
367
368
369
370       ┌─────────────────────────────┬─────────────────────────────┐
371       │      ATTRIBUTE TYPE         │      ATTRIBUTE VALUE        │
372       ├─────────────────────────────┼─────────────────────────────┤
373       │Interface Stability          │Evolving                     │
374       └─────────────────────────────┴─────────────────────────────┘
375

SEE ALSO

377       attributes(5),   attach(9E),   ddi_intr_alloc(9F),   ddi_intr_free(9F),
378       ddi_intr_get_hilevel_pri(9F), mutex_init(9F), rw_init(9F), rwlock(9F)
379
380
381       Writing Device Drivers
382

NOTES

384       Consumers of these interfaces should verify that the  return  value  is
385       not  equal  to DDI_SUCCESS. Incomplete checking for failure codes could
386       result in inconsistent behavior among platforms.
387
388
389       The ddi_intr_add_softint() may not be used to  add  the  same  software
390       interrupt  handler  more  than  once.  This is true even if a different
391       value is used for arg1 in each of the calls to  ddi_intr_add_softint().
392       Instead,  the  argument passed to the interrupt handler should indicate
393       what service(s) the interrupt handler should perform. For example,  the
394       argument  could  be a pointer to the soft state structure of the device
395       that could contain a which_service field that the handler examines. The
396       driver  must  set  this  field  to the appropriate value before calling
397       ddi_intr_trigger_softint().
398
399
400       Every time a modifiable valid second argument, arg2, is  provided  when
401       ddi_intr_trigger_softint()  is  invoked,  the  DDI framework saves arg2
402       internally and passes it to the interrupt handler handler.
403
404
405       A call to ddi_intr_set_softint_pri() could fail if a previously  sched‐
406       uled soft interrupt trigger is still pending.
407
408
409
410SunOS 5.11                        16 Oct 2005         ddi_intr_add_softint(9F)
Impressum