1ddi_intr_add_softint(9F) Kernel Functions for Drivers ddi_intr_add_softint(9F)
2
3
4
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
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
39 Solaris DDI specific (Solaris DDI).
40
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
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
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
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
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
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
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
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)