1ddi_add_softintr(9F) Kernel Functions for Drivers ddi_add_softintr(9F)
2
3
4
6 ddi_add_softintr, ddi_get_soft_iblock_cookie, ddi_remove_softintr,
7 ddi_trigger_softintr - software interrupt handling routines
8
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
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
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
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
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
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
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
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
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
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)