9762 Split the custr functions into their own library
[unleashed.git] / usr / src / man / man9f / ddi_add_softintr.9f
blob3b150df8898cd949df37ddee3d7a7caadea68c82
1 '\" te
2 .\" Copyright (c) 2005, Sun Microsystems, Inc.
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_ADD_SOFTINTR 9F "Oct 19, 2005"
7 .SH NAME
8 ddi_add_softintr, ddi_get_soft_iblock_cookie, ddi_remove_softintr,
9 ddi_trigger_softintr \- software interrupt handling routines
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>
20 \fBint\fR \fBddi_get_soft_iblock_cookie\fR(\fBdev_info_t *\fR\fIdip\fR,
21 \fBint\fR \fIpreference\fR, \fBddi_iblock_cookie_t *\fR\fIiblock_cookiep\fR);
22 .fi
24 .LP
25 .nf
26 \fBint\fR \fBddi_add_softintr\fR(\fBdev_info_t *\fR\fIdip\fR, \fBint\fR \fIpreference\fR, \fBddi_softintr_t *\fR\fIidp\fR,
27      \fBddi_iblock_cookie_t *\fR\fIiblock_cookiep\fR, \fBddi_idevice_cookie_t *\fR
28      \fIidevice_cookiep\fR,
29      \fBuint_t(*\fR\fIint_handler\fR) (caddr_t \fIint_handler_arg\fR), \fBcaddr_t\fR
30      \fIint_handler_arg\fR);
31 .fi
33 .LP
34 .nf
35 \fBvoid\fR \fBddi_remove_softintr\fR(\fBddi_softintr_t\fR \fIid\fR);
36 .fi
38 .LP
39 .nf
40 \fBvoid\fR \fBddi_trigger_softintr\fR(\fBddi_softintr_t\fR \fIid\fR);
41 .fi
43 .SH INTERFACE LEVEL
44 .sp
45 .LP
46 Solaris DDI specific (Solaris DDI). These interfaces are obsolete. Use the new
47 interrupt interfaces referenced in \fBIntro\fR(9F). Refer to \fIWriting Device
48 Drivers\fR for more information.
49 .SH PARAMETERS
50 .sp
51 .LP
52 \fBddi_get_soft_iblock_cookie()\fR
53 .sp
54 .ne 2
55 .na
56 \fB\fIdip\fR\fR
57 .ad
58 .RS 18n
59 Pointer to a \fBdev_info\fR structure.
60 .RE
62 .sp
63 .ne 2
64 .na
65 \fB\fIpreference\fR\fR
66 .ad
67 .RS 18n
68 The type of soft interrupt to retrieve the cookie for.
69 .RE
71 .sp
72 .ne 2
73 .na
74 \fB\fIiblock_cookiep\fR\fR
75 .ad
76 .RS 18n
77 Pointer to a location to store the interrupt block cookie.
78 .RE
80 .sp
81 .LP
82 \fBddi_add_softintr()\fR
83 .sp
84 .ne 2
85 .na
86 \fB\fIdip\fR\fR
87 .ad
88 .RS 19n
89 Pointer to \fBdev_info\fR structure.
90 .RE
92 .sp
93 .ne 2
94 .na
95 \fB\fIpreference\fR\fR
96 .ad
97 .RS 19n
98 A hint value describing the type of soft interrupt to generate.
99 .RE
102 .ne 2
104 \fB\fIidp\fR\fR
106 .RS 19n
107 Pointer to a soft interrupt identifier where a returned soft interrupt
108 identifier is stored.
112 .ne 2
114 \fB\fIiblock_cookiep\fR\fR
116 .RS 19n
117 Optional pointer to an interrupt block cookie where a returned interrupt block
118 cookie is stored.
122 .ne 2
124 \fB\fIidevice_cookiep\fR\fR
126 .RS 19n
127 Optional pointer to an interrupt device cookie where a returned interrupt
128 device cookie is stored (not used).
132 .ne 2
134 \fB\fIint_handler\fR\fR
136 .RS 19n
137 Pointer to interrupt handler.
141 .ne 2
143 \fB\fIint_handler_arg\fR\fR
145 .RS 19n
146 Argument for interrupt handler.
151 \fBddi_remove_softintr()\fR
153 .ne 2
155 \fB\fIid\fR\fR
157 .RS 6n
158 The identifier specifying which soft interrupt handler to remove.
163 \fBddi_trigger_softintr()\fR
165 .ne 2
167 \fB\fIid\fR\fR
169 .RS 6n
170 The identifier specifying which soft interrupt to trigger and which soft
171 interrupt handler will be called.
174 .SH DESCRIPTION
177 For \fBddi_get_soft_iblock_cookie()\fR:
180 \fBddi_get_soft_iblock_cookie()\fR retrieves the interrupt block cookie
181 associated with a particular soft interrupt preference level. This routine
182 should be called before \fBddi_add_softintr()\fR to retrieve the interrupt
183 block cookie needed to initialize locks ( \fBmutex\fR(9F), \fBrwlock\fR(9F))
184 used by the software interrupt routine. \fIpreference\fR determines which type
185 of soft interrupt to retrieve the cookie for. The possible values for
186 \fIpreference\fR are:
188 .ne 2
190 \fB\fBDDI_SOFTINT_LOW\fR\fR
192 .RS 20n
193 Low priority soft interrupt.
197 .ne 2
199 \fB\fBDDI_SOFTINT_MED\fR\fR
201 .RS 20n
202 Medium priority soft interrupt.
206 .ne 2
208 \fB\fBDDI_SOFTINT_HIGH\fR\fR
210 .RS 20n
211 High priority soft interrupt.
216 On a successful return, \fIiblock_cookiep\fR contains information needed for
217 initializing locks associated with this soft interrupt (see
218 \fBmutex_init\fR(9F) and \fBrw_init\fR(9F)). The driver can then initialize
219 mutexes acquired by the interrupt routine before calling
220 \fBddi_add_softintr()\fR which prevents a possible race condition where the
221 driver's soft interrupt handler is called immediately \fBafter\fR the driver
222 has called \fBddi_add_softintr()\fR but \fBbefore\fR the driver has initialized
223 the mutexes. This can happen when a soft interrupt for a different device
224 occurs on the same soft interrupt priority level. If the soft interrupt routine
225 acquires the mutex before it has been initialized, undefined behavior may
226 result.
229 For \fBddi_add_softintr()\fR:
232 \fBddi_add_softintr()\fR adds a soft interrupt to the system. The user
233 specified hint \fIpreference\fR identifies three suggested levels for the
234 system to attempt to allocate the soft interrupt priority at. The value for
235 \fIpreference\fR should be the same as that used in the corresponding call to
236 \fBddi_get_soft_iblock_cookie()\fR. Refer to the description of
237 \fBddi_get_soft_iblock_cookie()\fR above.
240 The value returned in the location pointed at by \fIidp\fR is the soft
241 interrupt identifier. This value is used in later calls to
242 \fBddi_remove_softintr()\fR and \fBddi_trigger_softintr()\fR to identify the
243 soft interrupt and the soft interrupt handler.
246 The value returned in the location pointed at by \fIiblock_cookiep\fR is an
247 interrupt block cookie which contains information used for initializing mutexes
248 associated with this soft interrupt (see \fBmutex_init\fR(9F) and
249 \fBrw_init\fR(9F)). Note that the interrupt block cookie is normally obtained
250 using \fBddi_get_soft_iblock_cookie()\fR to avoid the race conditions described
251 above (refer to the description of \fBddi_get_soft_iblock_cookie()\fR above).
252 For this reason, \fIiblock_cookiep\fR is no longer useful and should be set to
253 \fINULL\fR.
256 \fIidevice_cookiep\fR is not used and should be set to \fINULL\fR.
259 The routine \fIint_handler\fR, with its argument \fIint_handler_arg\fR, is
260 called upon receipt of a software interrupt. Software interrupt handlers must
261 not assume that they have work to do when they run, since (like hardware
262 interrupt handlers) they may run because a soft interrupt occurred for some
263 other reason. For example, another driver may have triggered a soft interrupt
264 at the same level. For this reason, before triggering the soft interrupt, the
265 driver must indicate to its soft interrupt handler that it should do work. This
266 is usually done by setting a flag in the state structure. The routine
267 \fIint_handler\fR checks this flag, reachable through \fIint_handler_arg\fR, to
268 determine if it should claim the interrupt and do its work.
271 The interrupt handler must return \fBDDI_INTR_CLAIMED\fR if the interrupt was
272 claimed, \fBDDI_INTR_UNCLAIMED\fR otherwise.
275 If successful, \fBddi_add_softintr()\fR will return \fBDDI_SUCCESS\fR; if the
276 interrupt information cannot be found, it will return \fBDDI_FAILURE\fR.
279 For \fBddi_remove_softintr()\fR:
282 \fBddi_remove_softintr()\fR removes a soft interrupt from the system. The soft
283 interrupt identifier \fIid\fR, which was returned from a call to
284 \fBddi_add_softintr()\fR, is used to determine which soft interrupt and which
285 soft interrupt handler to remove. Drivers must remove any soft interrupt
286 handlers before allowing the system to unload the driver.
289 For \fBddi_trigger_softintr()\fR:
292 \fBddi_trigger_softintr()\fR triggers a soft interrupt. The soft interrupt
293 identifier \fIid\fR is used to determine which soft interrupt to trigger. This
294 function is used by device drivers when they wish to trigger a soft interrupt
295 which has been set up using \fBddi_add_softintr()\fR.
296 .SH RETURN VALUES
299 \fBddi_add_softintr()\fR and \fBddi_get_soft_iblock_cookie()\fR return:
301 .ne 2
303 \fB\fBDDI_SUCCESS\fR\fR
305 .RS 15n
306 on success
310 .ne 2
312 \fB\fBDDI_FAILURE\fR\fR
314 .RS 15n
315 on failure
318 .SH CONTEXT
321 These functions can be called from user or kernel context.
322 \fBddi_trigger_softintr()\fR may be called from high-level interrupt context as
323 well.
324 .SH EXAMPLES
326 \fBExample 1 \fRdevice using high-level interrupts
329 In the following example, the device uses high-level interrupts. High-level
330 interrupts are those that interrupt at the level of the scheduler and above.
331 High level interrupts must be handled without using system services that
332 manipulate thread or process states, because these interrupts are not blocked
333 by the scheduler. In addition, high level interrupt handlers must take care to
334 do a minimum of work because they are not preemptable. See
335 \fBddi_intr_hilevel\fR(9F).
339 In the example, the high-level interrupt routine minimally services the device,
340 and enqueues the data for later processing by the soft interrupt handler. If
341 the soft interrupt handler is not currently running, the high-level interrupt
342 routine triggers a soft interrupt so the soft interrupt handler can process the
343 data. Once running, the soft interrupt handler processes all the enqueued data
344 before returning.
348 The state structure contains two mutexes. The high-level mutex is used to
349 protect data shared between the high-level interrupt handler and the soft
350 interrupt handler. The low-level mutex is used to protect the rest of the
351 driver from the soft interrupt handler.
354 .in +2
356 struct xxstate {
357       .\|.\|.
358       ddi_softintr_t             id;
359          ddi_iblock_cookie_t     high_iblock_cookie;
360          kmutex_t                      high_mutex;
361          ddi_iblock_cookie_t     low_iblock_cookie;
362          kmutex_t                      low_mutex;
363          int                              softint_running;
364       .\|.\|.
366 struct xxstate *xsp;
367 static uint_t xxsoftintr(caddr_t);
368 static uint_t xxhighintr(caddr_t);
369 \&.\|.\|.
371 .in -2
374 \fBExample 2 \fRsample \fBattach()\fR routine
377 The following code fragment would usually appear in the driver's
378 \fBattach\fR(9E) routine. \fBddi_add_intr\fR(9F) is used to add the high-level
379 interrupt handler and \fBddi_add_softintr()\fR is used to add the low-level
380 interrupt routine.
383 .in +2
385 static uint_t
386 xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
388          struct xxstate *xsp;
389          .\|.\|.
390       /* get high-level iblock cookie */
391          if (ddi_get_iblock_cookie(dip, \fIinumber\fR,
392                 &xsp->high_iblock_cookie) != DDI_SUCCESS)  {
393                       /* clean up */
394                       return (DDI_FAILURE); /* fail attach */
395          }
397          /* initialize high-level mutex */
398          mutex_init(&xsp->high_mutex, "xx high mutex", MUTEX_DRIVER,
399                (void *)xsp->high_iblock_cookie);
401          /* add high-level routine - xxhighintr() */
402          if (ddi_add_intr(dip, \fIinumber\fR, NULL, NULL,
403                 xxhighintr, (caddr_t) xsp) != DDI_SUCCESS)  {
404                       /* cleanup */
405                       return (DDI_FAILURE); /* fail attach */
406          }
408          /* get soft iblock cookie */
409          if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
410                 &xsp->low_iblock_cookie) != DDI_SUCCESS)  {
411                       /* clean up */
412                       return (DDI_FAILURE); /* fail attach */
413          }
415          /* initialize low-level mutex */
416          mutex_init(&xsp->low_mutex, "xx low mutex", MUTEX_DRIVER,
417                 (void *)xsp->low_iblock_cookie);
419          /* add low level routine - xxsoftintr() */
420          if ( ddi_add_softintr(dip, DDI_SOFTINT_MED, &xsp->id,
421                 NULL, NULL, xxsoftintr, (caddr_t) xsp) != DDI_SUCCESS) {
422                       /* cleanup */
423                       return (DDI_FAILURE);  /* fail attach */
424          }
426          .\|.\|.
429 .in -2
432 \fBExample 3 \fRHigh-level interrupt routine
435 The next code fragment represents the high-level interrupt routine. The
436 high-level interrupt routine minimally services the device, and enqueues the
437 data for later processing by the soft interrupt routine. If the soft interrupt
438 routine is not already running, \fBddi_trigger_softintr()\fR is called to start
439 the routine. The soft interrupt routine will run until there is no more data on
440 the queue.
443 .in +2
445 static uint_t
446 xxhighintr(caddr_t arg)
448       struct xxstate *xsp = (struct xxstate *) arg;
449          int need_softint;
450          .\|.\|.
451          mutex_enter(&xsp->high_mutex);
452          /*
453          * Verify this device generated the interrupt
454          * and disable the device interrupt.
455          * Enqueue data for xxsoftintr() processing.
456          */
458          /* is xxsoftintr() already running ? */
459          if (xsp->softint_running)
460                 need_softint = 0;
461           else
462                 need_softint = 1;
463           mutex_exit(&xsp->high_mutex);
465           /* read-only access to xsp->id, no mutex needed */
466           if (need_softint)
467                 ddi_trigger_softintr(xsp->id);
468           .\|.\|.
469           return (DDI_INTR_CLAIMED);
472 static uint_t
473 xxsoftintr(caddr_t arg)
475       struct xxstate *xsp = (struct xxstate *) arg;
476       .\|.\|.
477          mutex_enter(&xsp->low_mutex);
478       mutex_enter(&xsp->high_mutex);
480       /* verify there is work to do */
481       if (\fBwork queue empty\fR || xsp->softint_running )  {
482                 mutex_exit(&xsp->high_mutex);
483                 mutex_exit(&xsp->low_mutex);
484                 return (DDI_INTR_UNCLAIMED);
485       }
487       xsp->softint_running = 1;
489          while ( \fBdata on queue\fR )  {
490                 ASSERT(mutex_owned(&xsp->high_mutex));
492                 /* de-queue data */
494                 mutex_exit(&xsp->high_mutex);
496                 /* Process data on queue */
498                 mutex_enter(&xsp->high_mutex);
499           }
501           xsp->softint_running = 0;
502           mutex_exit(&xsp->high_mutex);
503           mutex_exit(&xsp->low_mutex);
505           return (DDI_INTR_CLAIMED);
508 .in -2
510 .SH ATTRIBUTES
513 See \fBattributes\fR(5) for descriptions of the following attributes:
518 box;
519 c | c
520 l | l .
521 ATTRIBUTE TYPE  ATTRIBUTE VALUE
523 Interface Stability     Obsolete
526 .SH SEE ALSO
529 \fBddi_add_intr\fR(9F), \fBddi_in_panic\fR(9F), \fBddi_intr_hilevel\fR(9F),
530 \fBddi_remove_intr\fR(9F), \fBIntro\fR(9F), \fBmutex_init\fR(9F)
533 \fIWriting Device Drivers\fR
534 .SH NOTES
537 \fBddi_add_softintr()\fR may not be used to add the same software interrupt
538 handler more than once. This is true even if a different value is used for
539 \fIint_handler_arg\fR in each of the calls to \fBddi_add_softintr()\fR.
540 Instead, the argument passed to the interrupt handler should indicate what
541 service(s) the interrupt handler should perform. For example, the argument
542 could be a pointer to the device's soft state structure, which could contain
543 a 'which_service' field that the handler examines. The driver must set this field
544 to the appropriate value before calling \fBddi_trigger_softintr()\fR.