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"
8 ddi_add_softintr, ddi_get_soft_iblock_cookie, ddi_remove_softintr,
9 ddi_trigger_softintr \- software interrupt handling routines
13 #include <sys/types.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);
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);
35 \fBvoid\fR \fBddi_remove_softintr\fR(\fBddi_softintr_t\fR \fIid\fR);
40 \fBvoid\fR \fBddi_trigger_softintr\fR(\fBddi_softintr_t\fR \fIid\fR);
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.
52 \fBddi_get_soft_iblock_cookie()\fR
59 Pointer to a \fBdev_info\fR structure.
65 \fB\fIpreference\fR\fR
68 The type of soft interrupt to retrieve the cookie for.
74 \fB\fIiblock_cookiep\fR\fR
77 Pointer to a location to store the interrupt block cookie.
82 \fBddi_add_softintr()\fR
89 Pointer to \fBdev_info\fR structure.
95 \fB\fIpreference\fR\fR
98 A hint value describing the type of soft interrupt to generate.
107 Pointer to a soft interrupt identifier where a returned soft interrupt
108 identifier is stored.
114 \fB\fIiblock_cookiep\fR\fR
117 Optional pointer to an interrupt block cookie where a returned interrupt block
124 \fB\fIidevice_cookiep\fR\fR
127 Optional pointer to an interrupt device cookie where a returned interrupt
128 device cookie is stored (not used).
134 \fB\fIint_handler\fR\fR
137 Pointer to interrupt handler.
143 \fB\fIint_handler_arg\fR\fR
146 Argument for interrupt handler.
151 \fBddi_remove_softintr()\fR
158 The identifier specifying which soft interrupt handler to remove.
163 \fBddi_trigger_softintr()\fR
170 The identifier specifying which soft interrupt to trigger and which soft
171 interrupt handler will be called.
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:
190 \fB\fBDDI_SOFTINT_LOW\fR\fR
193 Low priority soft interrupt.
199 \fB\fBDDI_SOFTINT_MED\fR\fR
202 Medium priority soft interrupt.
208 \fB\fBDDI_SOFTINT_HIGH\fR\fR
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
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
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.
299 \fBddi_add_softintr()\fR and \fBddi_get_soft_iblock_cookie()\fR return:
303 \fB\fBDDI_SUCCESS\fR\fR
312 \fB\fBDDI_FAILURE\fR\fR
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
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
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.
359 ddi_iblock_cookie_t high_iblock_cookie;
361 ddi_iblock_cookie_t low_iblock_cookie;
367 static uint_t xxsoftintr(caddr_t);
368 static uint_t xxhighintr(caddr_t);
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
386 xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
390 /* get high-level iblock cookie */
391 if (ddi_get_iblock_cookie(dip, \fIinumber\fR,
392 &xsp->high_iblock_cookie) != DDI_SUCCESS) {
394 return (DDI_FAILURE); /* fail attach */
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) {
405 return (DDI_FAILURE); /* fail attach */
408 /* get soft iblock cookie */
409 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
410 &xsp->low_iblock_cookie) != DDI_SUCCESS) {
412 return (DDI_FAILURE); /* fail attach */
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) {
423 return (DDI_FAILURE); /* fail attach */
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
446 xxhighintr(caddr_t arg)
448 struct xxstate *xsp = (struct xxstate *) arg;
451 mutex_enter(&xsp->high_mutex);
453 * Verify this device generated the interrupt
454 * and disable the device interrupt.
455 * Enqueue data for xxsoftintr() processing.
458 /* is xxsoftintr() already running ? */
459 if (xsp->softint_running)
463 mutex_exit(&xsp->high_mutex);
465 /* read-only access to xsp->id, no mutex needed */
467 ddi_trigger_softintr(xsp->id);
469 return (DDI_INTR_CLAIMED);
473 xxsoftintr(caddr_t arg)
475 struct xxstate *xsp = (struct xxstate *) arg;
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);
487 xsp->softint_running = 1;
489 while ( \fBdata on queue\fR ) {
490 ASSERT(mutex_owned(&xsp->high_mutex));
494 mutex_exit(&xsp->high_mutex);
496 /* Process data on queue */
498 mutex_enter(&xsp->high_mutex);
501 xsp->softint_running = 0;
502 mutex_exit(&xsp->high_mutex);
503 mutex_exit(&xsp->low_mutex);
505 return (DDI_INTR_CLAIMED);
513 See \fBattributes\fR(5) for descriptions of the following attributes:
521 ATTRIBUTE TYPE ATTRIBUTE VALUE
523 Interface Stability Obsolete
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
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.