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

NAME

6       ddi_add_softintr,    ddi_get_soft_iblock_cookie,   ddi_remove_softintr,
7       ddi_trigger_softintr - software interrupt handling routines
8

SYNOPSIS

10       #include <sys/types.h>
11       #include <sys/conf.h>
12       #include <sys/ddi.h>
13       #include <sys/sunddi.h>
14
15
16
17       int ddi_get_soft_iblock_cookie(dev_info_t *dip,
18       int preference, ddi_iblock_cookie_t *iblock_cookiep);
19
20
21       int ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
22            ddi_iblock_cookie_t *iblock_cookiep, ddi_idevice_cookie_t *
23            idevice_cookiep,
24            uint_t(*int_handler) (caddr_t int_handler_arg), caddr_t
25            int_handler_arg);
26
27
28       void ddi_remove_softintr(ddi_softintr_t id);
29
30
31       void ddi_trigger_softintr(ddi_softintr_t id);
32
33

INTERFACE LEVEL

35       Solaris DDI specific (Solaris DDI). These interfaces are obsolete.  Use
36       the  new interrupt interfaces referenced in Intro(9F). Refer to Writing
37       Device Drivers for more information.
38

PARAMETERS

40       ddi_get_soft_iblock_cookie()
41
42       dip               Pointer to a dev_info structure.
43
44
45       preference        The type of soft interrupt  to  retrieve  the  cookie
46                         for.
47
48
49       iblock_cookiep    Pointer  to  a  location to store the interrupt block
50                         cookie.
51
52
53
54       ddi_add_softintr()
55
56       dip                Pointer to dev_info structure.
57
58
59       preference         A hint value describing the type of  soft  interrupt
60                          to generate.
61
62
63       idp                Pointer  to  a  soft  interrupt  identifier  where a
64                          returned soft interrupt identifier is stored.
65
66
67       iblock_cookiep     Optional pointer to an interrupt block cookie  where
68                          a returned interrupt block cookie is stored.
69
70
71       idevice_cookiep    Optional pointer to an interrupt device cookie where
72                          a returned interrupt device cookie  is  stored  (not
73                          used).
74
75
76       int_handler        Pointer to interrupt handler.
77
78
79       int_handler_arg    Argument for interrupt handler.
80
81
82
83       ddi_remove_softintr()
84
85       id    The identifier specifying which soft interrupt handler to remove.
86
87
88
89       ddi_trigger_softintr()
90
91       id    The  identifier  specifying  which  soft interrupt to trigger and
92             which soft interrupt handler will be called.
93
94

DESCRIPTION

96       For ddi_get_soft_iblock_cookie():
97
98
99       ddi_get_soft_iblock_cookie() retrieves the interrupt block cookie asso‐
100       ciated  with a particular soft interrupt preference level. This routine
101       should be called before ddi_add_softintr() to  retrieve  the  interrupt
102       block  cookie  needed to initialize locks ( mutex(9F), rwlock(9F)) used
103       by the software interrupt routine. preference determines which type  of
104       soft  interrupt  to  retrieve  the  cookie for. The possible values for
105       preference are:
106
107       DDI_SOFTINT_LOW     Low priority soft interrupt.
108
109
110       DDI_SOFTINT_MED     Medium priority soft interrupt.
111
112
113       DDI_SOFTINT_HIGH    High priority soft interrupt.
114
115
116
117       On a successful return, iblock_cookiep contains information needed  for
118       initializing   locks   associated   with   this   soft  interrupt  (see
119       mutex_init(9F) and rw_init(9F)). The driver can then initialize mutexes
120       acquired  by  the  interrupt  routine before calling ddi_add_softintr()
121       which prevents a possible race condition where the driver's soft inter‐
122       rupt  handler  is  called  immediately  after  the  driver  has  called
123       ddi_add_softintr() but before the driver has initialized  the  mutexes.
124       This  can happen when a soft interrupt for a different device occurs on
125       the same soft interrupt priority level. If the soft  interrupt  routine
126       acquires  the  mutex before it has been initialized, undefined behavior
127       may result.
128
129
130       For ddi_add_softintr():
131
132
133       ddi_add_softintr() adds a soft interrupt to the system. The user speci‐
134       fied  hint  preference identifies three suggested levels for the system
135       to attempt to allocate the soft interrupt priority at.  The  value  for
136       preference should be the same as that used in the corresponding call to
137       ddi_get_soft_iblock_cookie().   Refer    to    the    description    of
138       ddi_get_soft_iblock_cookie() above.
139
140
141       The value returned in the location pointed at by idp is the soft inter‐
142       rupt identifier. This value is used in later calls to  ddi_remove_soft‐
143       intr()  and  ddi_trigger_softintr()  to identify the soft interrupt and
144       the soft interrupt handler.
145
146
147       The value returned in the location pointed at by iblock_cookiep  is  an
148       interrupt block cookie which contains information used for initializing
149       mutexes associated with this soft  interrupt  (see  mutex_init(9F)  and
150       rw_init(9F)). Note that the interrupt block cookie is normally obtained
151       using  ddi_get_soft_iblock_cookie()  to  avoid  the   race   conditions
152       described      above      (refer      to     the     description     of
153       ddi_get_soft_iblock_cookie() above). For this reason, iblock_cookiep is
154       no longer useful and should be set to NULL.
155
156
157       idevice_cookiep is not used and should be set to NULL.
158
159
160       The  routine  int_handler, with its argument int_handler_arg, is called
161       upon receipt of a software interrupt. Software interrupt handlers  must
162       not  assume  that they have work to do when they run, since (like hard‐
163       ware interrupt handlers) they may run because a soft interrupt occurred
164       for some other reason. For example, another driver may have triggered a
165       soft interrupt at the same level. For this  reason,  before  triggering
166       the soft interrupt, the driver must indicate to its soft interrupt han‐
167       dler that it should do work. This is usually done by setting a flag  in
168       the  state  structure. The routine int_handler checks this flag, reach‐
169       able through int_handler_arg, to  determine  if  it  should  claim  the
170       interrupt and do its work.
171
172
173       The interrupt handler must return DDI_INTR_CLAIMED if the interrupt was
174       claimed, DDI_INTR_UNCLAIMED otherwise.
175
176
177       If successful,  ddi_add_softintr()  will  return  DDI_SUCCESS;  if  the
178       interrupt information cannot be found, it will return DDI_FAILURE.
179
180
181       For ddi_remove_softintr():
182
183
184       ddi_remove_softintr()  removes  a  soft  interrupt from the system. The
185       soft interrupt identifier  id,  which  was  returned  from  a  call  to
186       ddi_add_softintr(), is used to determine which soft interrupt and which
187       soft interrupt handler to remove. Drivers must remove any  soft  inter‐
188       rupt handlers before allowing the system to unload the driver.
189
190
191       For ddi_trigger_softintr():
192
193
194       ddi_trigger_softintr()  triggers  a  soft interrupt. The soft interrupt
195       identifier id is used to determine which  soft  interrupt  to  trigger.
196       This  function  is  used  by device drivers when they wish to trigger a
197       soft interrupt which has been set up using ddi_add_softintr().
198

RETURN VALUES

200       ddi_add_softintr() and ddi_get_soft_iblock_cookie() return:
201
202       DDI_SUCCESS    on success
203
204
205       DDI_FAILURE    on failure
206
207

CONTEXT

209       These functions can be called from user or  kernel  context.  ddi_trig‐
210       ger_softintr() may be called from high-level interrupt context as well.
211

EXAMPLES

213       Example 1 device using high-level interrupts
214
215
216       In  the following example, the device uses high-level interrupts. High-
217       level interrupts are those that interrupt at the level of the scheduler
218       and  above.  High level interrupts must be handled without using system
219       services that manipulate thread or process states, because these inter‐
220       rupts  are not blocked by the scheduler. In addition, high level inter‐
221       rupt handlers must take care to do a minimum of work because  they  are
222       not preemptable. See ddi_intr_hilevel(9F).
223
224
225
226       In the example, the high-level interrupt routine minimally services the
227       device, and enqueues the data for later processing by the  soft  inter‐
228       rupt  handler.  If the soft interrupt handler is not currently running,
229       the high-level interrupt routine triggers a soft interrupt so the  soft
230       interrupt  handler  can process the data. Once running, the soft inter‐
231       rupt handler processes all the enqueued data before returning.
232
233
234
235       The state structure contains two mutexes. The high-level mutex is  used
236       to protect data shared between the high-level interrupt handler and the
237       soft interrupt handler. The low-level mutex is used to protect the rest
238       of the driver from the soft interrupt handler.
239
240
241         struct xxstate {
242               ...
243               ddi_softintr_t             id;
244                  ddi_iblock_cookie_t     high_iblock_cookie;
245                  kmutex_t                      high_mutex;
246                  ddi_iblock_cookie_t     low_iblock_cookie;
247                  kmutex_t                      low_mutex;
248                  int                              softint_running;
249               ...
250         };
251         struct xxstate *xsp;
252         static uint_t xxsoftintr(caddr_t);
253         static uint_t xxhighintr(caddr_t);
254         ...
255
256
257       Example 2 sample attach() routine
258
259
260       The  following  code  fragment  would  usually  appear  in the driver's
261       attach(9E) routine. ddi_add_intr(9F) is  used  to  add  the  high-level
262       interrupt  handler  and ddi_add_softintr() is used to add the low-level
263       interrupt routine.
264
265
266         static uint_t
267         xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
268         {
269                  struct xxstate *xsp;
270                  ...
271               /* get high-level iblock cookie */
272                  if (ddi_get_iblock_cookie(dip, inumber,
273                         &xsp->high_iblock_cookie) != DDI_SUCCESS)  {
274                               /* clean up */
275                               return (DDI_FAILURE); /* fail attach */
276                  }
277
278                  /* initialize high-level mutex */
279                  mutex_init(&xsp->high_mutex, "xx high mutex", MUTEX_DRIVER,
280                        (void *)xsp->high_iblock_cookie);
281
282                  /* add high-level routine - xxhighintr() */
283                  if (ddi_add_intr(dip, inumber, NULL, NULL,
284                         xxhighintr, (caddr_t) xsp) != DDI_SUCCESS)  {
285                               /* cleanup */
286                               return (DDI_FAILURE); /* fail attach */
287                  }
288
289                  /* get soft iblock cookie */
290                  if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
291                         &xsp->low_iblock_cookie) != DDI_SUCCESS)  {
292                               /* clean up */
293                               return (DDI_FAILURE); /* fail attach */
294                  }
295
296                  /* initialize low-level mutex */
297                  mutex_init(&xsp->low_mutex, "xx low mutex", MUTEX_DRIVER,
298                         (void *)xsp->low_iblock_cookie);
299
300                  /* add low level routine - xxsoftintr() */
301                  if ( ddi_add_softintr(dip, DDI_SOFTINT_MED, &xsp->id,
302                         NULL, NULL, xxsoftintr, (caddr_t) xsp) != DDI_SUCCESS) {
303                               /* cleanup */
304                               return (DDI_FAILURE);  /* fail attach */
305                  }
306
307                  ...
308         }
309
310
311       Example 3 High-level interrupt routine
312
313
314       The next code fragment represents the high-level interrupt routine. The
315       high-level   interrupt  routine  minimally  services  the  device,  and
316       enqueues the data for later processing by the soft  interrupt  routine.
317       If the soft interrupt routine is not already running, ddi_trigger_soft‐
318       intr() is called to start the routine. The soft interrupt routine  will
319       run until there is no more data on the queue.
320
321
322         static uint_t
323         xxhighintr(caddr_t arg)
324         {
325               struct xxstate *xsp = (struct xxstate *) arg;
326                  int need_softint;
327                  ...
328                  mutex_enter(&xsp->high_mutex);
329                  /*
330                  * Verify this device generated the interrupt
331                  * and disable the device interrupt.
332                  * Enqueue data for xxsoftintr() processing.
333                  */
334
335                  /* is xxsoftintr() already running ? */
336                  if (xsp->softint_running)
337                         need_softint = 0;
338                   else
339                         need_softint = 1;
340                   mutex_exit(&xsp->high_mutex);
341
342                   /* read-only access to xsp->id, no mutex needed */
343                   if (need_softint)
344                         ddi_trigger_softintr(xsp->id);
345                   ...
346                   return (DDI_INTR_CLAIMED);
347         }
348
349         static uint_t
350         xxsoftintr(caddr_t arg)
351         {
352               struct xxstate *xsp = (struct xxstate *) arg;
353               ...
354                  mutex_enter(&xsp->low_mutex);
355               mutex_enter(&xsp->high_mutex);
356
357               /* verify there is work to do */
358               if (work queue empty || xsp->softint_running )  {
359                         mutex_exit(&xsp->high_mutex);
360                         mutex_exit(&xsp->low_mutex);
361                         return (DDI_INTR_UNCLAIMED);
362               }
363
364               xsp->softint_running = 1;
365
366                  while ( data on queue )  {
367                         ASSERT(mutex_owned(&xsp->high_mutex));
368
369                         /* de-queue data */
370
371                         mutex_exit(&xsp->high_mutex);
372
373                         /* Process data on queue */
374
375                         mutex_enter(&xsp->high_mutex);
376                   }
377
378                   xsp->softint_running = 0;
379                   mutex_exit(&xsp->high_mutex);
380                   mutex_exit(&xsp->low_mutex);
381
382                   return (DDI_INTR_CLAIMED);
383         }
384
385

ATTRIBUTES

387       See attributes(5) for descriptions of the following attributes:
388
389
390
391
392       ┌─────────────────────────────┬─────────────────────────────┐
393       │      ATTRIBUTE TYPE         │      ATTRIBUTE VALUE        │
394       ├─────────────────────────────┼─────────────────────────────┤
395       │Interface Stability          │Obsolete                     │
396       └─────────────────────────────┴─────────────────────────────┘
397

SEE ALSO

399       ddi_add_intr(9F),        ddi_in_panic(9F),        ddi_intr_hilevel(9F),
400       ddi_remove_intr(9F), Intro(9F), mutex_init(9F)
401
402
403       Writing Device Drivers
404

NOTES

406       ddi_add_softintr() may not be used to add the same  software  interrupt
407       handler  more than once. This is true even if a different value is used
408       for  int_handler_arg  in  each  of  the  calls  to  ddi_add_softintr().
409       Instead,  the  argument passed to the interrupt handler should indicate
410       what service(s) the interrupt handler should perform. For example,  the
411       argument could be a pointer to the device's soft state structure, which
412       could contain a 'which_service' field that the  handler  examines.  The
413       driver  must  set  this  field  to the appropriate value before calling
414       ddi_trigger_softintr().
415
416
417
418SunOS 5.11                        19 Oct 2005             ddi_add_softintr(9F)
Impressum