Print this page
3605 Xen HVM hangs during boot if apix is enabled
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/ddi_intr.c
+++ new/usr/src/uts/common/os/ddi_intr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include <sys/note.h>
26 26 #include <sys/sysmacros.h>
27 27 #include <sys/types.h>
28 28 #include <sys/param.h>
29 29 #include <sys/systm.h>
30 30 #include <sys/kmem.h>
31 31 #include <sys/cmn_err.h>
32 32 #include <sys/debug.h>
33 33 #include <sys/avintr.h>
34 34 #include <sys/autoconf.h>
35 35 #include <sys/sunndi.h>
36 36 #include <sys/ndi_impldefs.h> /* include prototypes */
37 37 #include <sys/atomic.h>
38 38
39 39 /*
40 40 * New DDI interrupt framework
41 41 */
42 42
43 43 /*
44 44 * ddi_intr_get_supported_types:
45 45 * Return, as a bit mask, the hardware interrupt types supported by
46 46 * both the device and by the host in the integer pointed
47 47 * to be the 'typesp' argument.
48 48 */
49 49 int
50 50 ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
51 51 {
52 52 int ret;
53 53 ddi_intr_handle_impl_t hdl;
54 54
55 55 if (dip == NULL)
56 56 return (DDI_EINVAL);
57 57
58 58 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
59 59 (void *)dip));
60 60
61 61 if (*typesp = i_ddi_intr_get_supported_types(dip))
62 62 return (DDI_SUCCESS);
63 63
64 64 bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
65 65 hdl.ih_dip = dip;
66 66
67 67 ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
68 68 (void *)typesp);
69 69
70 70 if (ret != DDI_SUCCESS)
71 71 return (DDI_INTR_NOTFOUND);
72 72
73 73 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
74 74 *typesp));
75 75
76 76 return (ret);
77 77 }
78 78
79 79 /*
80 80 * ddi_intr_get_nintrs:
81 81 * Return as an integer in the integer pointed to by the argument
82 82 * *nintrsp*, the number of interrupts the device supports for the
83 83 * given interrupt type.
84 84 */
85 85 int
86 86 ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
87 87 {
88 88 int ret;
89 89 ddi_intr_handle_impl_t hdl;
90 90
91 91 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n",
92 92 (void *)dip, type));
93 93
94 94 if ((dip == NULL) || (nintrsp == NULL) ||
95 95 !DDI_INTR_TYPE_FLAG_VALID(type) ||
96 96 !(i_ddi_intr_get_supported_types(dip) & type)) {
97 97 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: "
98 98 "Invalid input args\n"));
99 99 return (DDI_EINVAL);
100 100 }
101 101
102 102 if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
103 103 return (DDI_SUCCESS);
104 104
105 105 bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
106 106 hdl.ih_dip = dip;
107 107 hdl.ih_type = type;
108 108
109 109 ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
110 110 (void *)nintrsp);
111 111
112 112 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
113 113 *nintrsp));
114 114
115 115 return (ret);
116 116 }
117 117
118 118 /*
119 119 * ddi_intr_get_navail:
120 120 * Bus nexus driver will return availble interrupt count value for
121 121 * a given interrupt type.
122 122 *
123 123 * Return as an integer in the integer pointed to by the argument
124 124 * *navailp*, the number of interrupts currently available for the
125 125 * given interrupt type.
126 126 */
127 127 int
128 128 ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
129 129 {
130 130 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n",
131 131 (void *)dip, type));
132 132
133 133 if ((dip == NULL) || (navailp == NULL) ||
134 134 !DDI_INTR_TYPE_FLAG_VALID(type) ||
135 135 !(i_ddi_intr_get_supported_types(dip) & type)) {
136 136 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: "
137 137 "Invalid input args\n"));
138 138 return (DDI_EINVAL);
139 139 }
140 140
141 141 if ((*navailp = i_ddi_intr_get_current_navail(dip, type)) == 0)
142 142 return (DDI_INTR_NOTFOUND);
143 143
144 144 return (DDI_SUCCESS);
145 145 }
146 146
147 147 /*
148 148 * Interrupt allocate/free functions
149 149 */
150 150 int
151 151 ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
152 152 int count, int *actualp, int behavior)
153 153 {
154 154 ddi_intr_handle_impl_t *hdlp, tmp_hdl;
155 155 int i, ret, cap = 0, curr_type, nintrs;
156 156 uint_t pri, navail, curr_nintrs = 0;
157 157
158 158 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
159 159 "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
160 160 (void *)dip, type, inum, count, behavior));
161 161
162 162 /* Validate parameters */
163 163 if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) ||
164 164 (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) {
165 165 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
166 166 "Invalid input args\n"));
167 167 return (DDI_EINVAL);
168 168 }
169 169
170 170 /* Validate interrupt type */
171 171 if (!DDI_INTR_TYPE_FLAG_VALID(type) ||
172 172 !(i_ddi_intr_get_supported_types(dip) & type)) {
173 173 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
174 174 "supported\n", type));
175 175 return (DDI_EINVAL);
176 176 }
177 177
178 178 /* Validate inum not previously allocated */
179 179 if ((type == DDI_INTR_TYPE_FIXED) &&
180 180 (i_ddi_get_intr_handle(dip, inum) != NULL)) {
181 181 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already "
182 182 "in use, cannot allocate again!!\n", inum));
183 183 return (DDI_EINVAL);
184 184 }
185 185
186 186 /* Get how many interrupts the device supports */
187 187 if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) {
188 188 if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
189 189 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
190 190 "interrupts found of type %d\n", type));
191 191 return (DDI_INTR_NOTFOUND);
192 192 }
193 193 }
194 194
195 195 /* Get how many interrupts the device is already using */
196 196 if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) {
197 197 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
198 198 "is already being used\n", curr_type));
199 199 curr_nintrs = i_ddi_intr_get_current_nintrs(dip);
200 200 }
201 201
202 202 /* Validate interrupt type consistency */
203 203 if ((curr_type != 0) && (type != curr_type)) {
204 204 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
205 205 "interrupt type %x is different from interrupt type %x"
206 206 "already in use\n", type, curr_type));
207 207 return (DDI_EINVAL);
208 208 }
209 209
210 210 /* Validate count does not exceed what device supports */
211 211 if (count > nintrs) {
212 212 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
213 213 "requested %d is more than supported %d\n", count, nintrs));
214 214 return (DDI_EINVAL);
215 215 } else if ((count + curr_nintrs) > nintrs) {
216 216 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
217 217 "+ intrs in use %d exceeds supported %d intrs\n",
218 218 count, curr_nintrs, nintrs));
219 219 return (DDI_EINVAL);
220 220 }
221 221
222 222 /* Validate power of 2 requirements for MSI */
223 223 if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) {
224 224 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
225 225 "MSI count %d is not a power of two\n", count));
226 226 return (DDI_EINVAL);
227 227 }
228 228
229 229 /*
230 230 * Initialize the device's interrupt information structure,
231 231 * and establish an association with IRM if it is supported.
232 232 *
233 233 * NOTE: IRM checks minimum support, and can return DDI_EAGAIN.
234 234 */
235 235 if (curr_nintrs == 0) {
236 236 i_ddi_intr_devi_init(dip);
237 237 if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) {
238 238 cmn_err(CE_WARN, "ddi_intr_alloc: "
239 239 "cannot fit into interrupt pool\n");
240 240 return (DDI_EAGAIN);
241 241 }
242 242 }
243 243
244 244 /* Synchronously adjust IRM associations for non-IRM aware drivers */
245 245 if (curr_nintrs && (i_ddi_irm_supported(dip, type) != DDI_SUCCESS))
246 246 (void) i_ddi_irm_modify(dip, count + curr_nintrs);
247 247
248 248 /* Get how many interrupts are currently available */
249 249 navail = i_ddi_intr_get_current_navail(dip, type);
250 250
251 251 /* Validate that requested number of interrupts are available */
252 252 if (curr_nintrs == navail) {
253 253 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d "
254 254 "already allocated\n", navail));
255 255 return (DDI_EAGAIN);
256 256 }
257 257 if ((count + curr_nintrs) > navail) {
258 258 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of "
259 259 "intrs %d exceeds # of available intrs %d\n", count,
260 260 navail - curr_nintrs));
261 261 if (behavior == DDI_INTR_ALLOC_STRICT) {
262 262 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
263 263 "DDI_INTR_ALLOC_STRICT flag is passed, "
264 264 "return failure\n"));
265 265 if (curr_nintrs == 0)
266 266 i_ddi_intr_devi_fini(dip);
267 267 else if (i_ddi_irm_supported(dip, type) != DDI_SUCCESS)
268 268 (void) i_ddi_irm_modify(dip, curr_nintrs);
269 269 return (DDI_EAGAIN);
270 270 }
↓ open down ↓ |
270 lines elided |
↑ open up ↑ |
271 271 count = navail - curr_nintrs;
272 272 }
273 273
274 274 /* Now allocate required number of interrupts */
275 275 bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
276 276 tmp_hdl.ih_type = type;
277 277 tmp_hdl.ih_inum = inum;
278 278 tmp_hdl.ih_scratch1 = count;
279 279 tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior;
280 280 tmp_hdl.ih_dip = dip;
281 + tmp_hdl.ih_irq = -1;
281 282
282 283 if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC,
283 284 &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
284 285 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
285 286 "failed\n"));
286 287 i_ddi_intr_devi_fini(dip);
287 288 return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
288 289 }
289 290
290 291 if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI,
291 292 &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
292 293 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
293 294 "failed\n"));
294 295 goto fail;
295 296 }
296 297
297 298 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
298 299
299 300 if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP,
300 301 &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
301 302 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
302 303 "failed\n"));
303 304 goto fail;
304 305 }
305 306
306 307 /*
307 308 * Save current interrupt type, supported and current intr count.
308 309 */
309 310 i_ddi_intr_set_current_type(dip, type);
310 311 i_ddi_intr_set_supported_nintrs(dip, nintrs);
311 312 i_ddi_intr_set_current_nintrs(dip,
312 313 i_ddi_intr_get_current_nintrs(dip) + *actualp);
313 314
314 315 /* Now, go and handle each "handle" */
315 316 for (i = inum; i < (inum + *actualp); i++) {
316 317 hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
317 318 (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
318 319 rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
319 320 h_array[i] = (struct __ddi_intr_handle *)hdlp;
320 321 hdlp->ih_type = type;
321 322 hdlp->ih_pri = pri;
322 323 hdlp->ih_cap = cap;
323 324 hdlp->ih_ver = DDI_INTR_VERSION;
324 325 hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
325 326 hdlp->ih_dip = dip;
326 327 hdlp->ih_inum = i;
328 + hdlp->ih_irq = -1;
327 329 i_ddi_alloc_intr_phdl(hdlp);
328 - if (type & DDI_INTR_TYPE_FIXED)
330 + if (type & DDI_INTR_TYPE_FIXED) {
331 + if (tmp_hdl.ih_irq != -1)
332 + hdlp->ih_irq = tmp_hdl.ih_irq;
329 333 i_ddi_set_intr_handle(dip, hdlp->ih_inum,
330 334 (ddi_intr_handle_t)hdlp);
335 + }
331 336
332 337 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
333 338 (void *)h_array[i]));
334 339 }
335 340
336 341 return (DDI_SUCCESS);
337 342
338 343 fail:
339 344 (void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip,
340 345 DDI_INTROP_FREE, &tmp_hdl, NULL);
341 346 i_ddi_intr_devi_fini(dip);
342 347
343 348 return (ret);
344 349 }
345 350
346 351 int
347 352 ddi_intr_free(ddi_intr_handle_t h)
348 353 {
349 354 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
350 355 int ret;
351 356
352 357 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
353 358
354 359 if (hdlp == NULL)
355 360 return (DDI_EINVAL);
356 361
357 362 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
358 363 if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) &&
359 364 (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) ||
360 365 ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) &&
361 366 (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) {
362 367 rw_exit(&hdlp->ih_rwlock);
363 368 return (DDI_EINVAL);
364 369 }
365 370
366 371 /* Set the number of interrupts to free */
367 372 hdlp->ih_scratch1 = 1;
368 373
369 374 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
370 375 DDI_INTROP_FREE, hdlp, NULL);
371 376
372 377 rw_exit(&hdlp->ih_rwlock);
373 378 if (ret == DDI_SUCCESS) {
374 379 /* This would be the dup vector */
375 380 if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
376 381 atomic_dec_32(&hdlp->ih_main->ih_dup_cnt);
377 382 else {
378 383 int n, curr_type;
379 384
380 385 n = i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1;
381 386 curr_type = i_ddi_intr_get_current_type(hdlp->ih_dip);
382 387
383 388 i_ddi_intr_set_current_nintrs(hdlp->ih_dip, n);
384 389
385 390 if ((i_ddi_irm_supported(hdlp->ih_dip, curr_type)
386 391 != DDI_SUCCESS) && (n > 0))
387 392 (void) i_ddi_irm_modify(hdlp->ih_dip, n);
388 393
389 394 if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
390 395 i_ddi_set_intr_handle(hdlp->ih_dip,
391 396 hdlp->ih_inum, NULL);
392 397
393 398 i_ddi_intr_devi_fini(hdlp->ih_dip);
394 399 i_ddi_free_intr_phdl(hdlp);
395 400 }
396 401 rw_destroy(&hdlp->ih_rwlock);
397 402 kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
398 403 }
399 404
400 405 return (ret);
401 406 }
402 407
403 408 /*
404 409 * Interrupt get/set capacity functions
405 410 *
406 411 * The logic used to figure this out is shown here:
407 412 *
408 413 * Device level Platform level Intr source
409 414 * 1. Fixed interrupts
410 415 * (non-PCI)
411 416 * o Flags supported N/A Maskable/Pending/ rootnex
412 417 * No Block Enable
413 418 * o navail 1
414 419 *
415 420 * 2. PCI Fixed interrupts
416 421 * o Flags supported pending/Maskable Maskable/pending/ pci
417 422 * No Block enable
418 423 * o navail N/A 1
419 424 *
420 425 * 3. PCI MSI
421 426 * o Flags supported Maskable/Pending Maskable/Pending pci
422 427 * Block Enable (if drvr doesn't) Block Enable
423 428 * o navail N/A #vectors - #used N/A
424 429 *
425 430 * 4. PCI MSI-X
426 431 * o Flags supported Maskable/Pending Maskable/Pending pci
427 432 * Block Enable Block Enable
428 433 * o navail N/A #vectors - #used N/A
429 434 *
430 435 * where:
431 436 * #vectors - Total numbers of vectors available
432 437 * #used - Total numbers of vectors currently being used
433 438 *
434 439 * For devices complying to PCI2.3 or greater, see bit10 of Command Register
435 440 * 0 - enables assertion of INTx
436 441 * 1 - disables assertion of INTx
437 442 *
438 443 * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
439 444 * operations return failure.
440 445 */
441 446 int
442 447 ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
443 448 {
444 449 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
445 450 int ret;
446 451
447 452 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
448 453 (void *)hdlp));
449 454
450 455 *flagsp = 0;
451 456 if (hdlp == NULL)
452 457 return (DDI_EINVAL);
453 458
454 459 rw_enter(&hdlp->ih_rwlock, RW_READER);
455 460
456 461 if (hdlp->ih_cap) {
457 462 *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
458 463 rw_exit(&hdlp->ih_rwlock);
459 464 return (DDI_SUCCESS);
460 465 }
461 466
462 467 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
463 468 DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
464 469
465 470 if (ret == DDI_SUCCESS) {
466 471 hdlp->ih_cap = *flagsp;
467 472
468 473 /* Mask out MSI/X 64-bit support to the consumer */
469 474 *flagsp &= ~DDI_INTR_FLAG_MSI64;
470 475 }
471 476
472 477 rw_exit(&hdlp->ih_rwlock);
473 478 return (ret);
474 479 }
475 480
476 481 int
477 482 ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
478 483 {
479 484 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
480 485 int ret;
481 486
482 487 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
483 488
484 489 if (hdlp == NULL)
485 490 return (DDI_EINVAL);
486 491
487 492 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
488 493 if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
489 494 rw_exit(&hdlp->ih_rwlock);
490 495 return (DDI_EINVAL);
491 496 }
492 497
493 498 /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
494 499 if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
495 500 DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
496 501 "can be set\n", ddi_driver_name(hdlp->ih_dip),
497 502 ddi_get_instance(hdlp->ih_dip)));
498 503 rw_exit(&hdlp->ih_rwlock);
499 504 return (DDI_EINVAL);
500 505 }
501 506
502 507 /* Both level/edge flags must be currently supported */
503 508 if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
504 509 DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
505 510 " must be supported\n", ddi_driver_name(hdlp->ih_dip),
506 511 ddi_get_instance(hdlp->ih_dip)));
507 512 rw_exit(&hdlp->ih_rwlock);
508 513 return (DDI_ENOTSUP);
509 514 }
510 515
511 516 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
512 517 DDI_INTROP_SETCAP, hdlp, &flags);
513 518
514 519 rw_exit(&hdlp->ih_rwlock);
515 520 return (ret);
516 521 }
517 522
518 523 /*
519 524 * Priority related functions
520 525 */
521 526
522 527 /*
523 528 * ddi_intr_get_hilevel_pri:
524 529 * Returns the minimum priority level for a
525 530 * high-level interrupt on a platform.
526 531 */
527 532 uint_t
528 533 ddi_intr_get_hilevel_pri(void)
529 534 {
530 535 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
531 536 return (LOCK_LEVEL + 1);
532 537 }
533 538
534 539 int
535 540 ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
536 541 {
537 542 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
538 543 int ret;
539 544
540 545 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
541 546 (void *)hdlp));
542 547
543 548 *prip = 0;
544 549 if (hdlp == NULL)
545 550 return (DDI_EINVAL);
546 551
547 552 rw_enter(&hdlp->ih_rwlock, RW_READER);
548 553 /* Already initialized, just return that */
549 554 if (hdlp->ih_pri) {
550 555 *prip = hdlp->ih_pri;
551 556 rw_exit(&hdlp->ih_rwlock);
552 557 return (DDI_SUCCESS);
553 558 }
554 559
555 560 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
556 561 DDI_INTROP_GETPRI, hdlp, (void *)prip);
557 562
558 563 if (ret == DDI_SUCCESS)
559 564 hdlp->ih_pri = *prip;
560 565
561 566 rw_exit(&hdlp->ih_rwlock);
562 567 return (ret);
563 568 }
564 569
565 570 int
566 571 ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
567 572 {
568 573 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
569 574 int ret;
570 575
571 576 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
572 577
573 578 if (hdlp == NULL)
574 579 return (DDI_EINVAL);
575 580
576 581 /* Validate priority argument */
577 582 if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
578 583 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
579 584 "specified = %x\n", pri));
580 585 return (DDI_EINVAL);
581 586 }
582 587
583 588 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
584 589 if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
585 590 rw_exit(&hdlp->ih_rwlock);
586 591 return (DDI_EINVAL);
587 592 }
588 593
589 594 /* If the passed priority is same as existing priority; do nothing */
590 595 if (pri == hdlp->ih_pri) {
591 596 rw_exit(&hdlp->ih_rwlock);
592 597 return (DDI_SUCCESS);
593 598 }
594 599
595 600 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
596 601 DDI_INTROP_SETPRI, hdlp, &pri);
597 602
598 603 if (ret == DDI_SUCCESS)
599 604 hdlp->ih_pri = pri;
600 605
601 606 rw_exit(&hdlp->ih_rwlock);
602 607 return (ret);
603 608 }
604 609
605 610 /*
606 611 * Interrupt add/duplicate/remove handlers
607 612 */
608 613 int
609 614 ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
610 615 void *arg1, void *arg2)
611 616 {
612 617 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
613 618 int ret;
614 619
615 620 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
616 621 (void *)hdlp));
617 622
618 623 if ((hdlp == NULL) || (inthandler == NULL))
619 624 return (DDI_EINVAL);
620 625
621 626 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
622 627 if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
623 628 rw_exit(&hdlp->ih_rwlock);
624 629 return (DDI_EINVAL);
625 630 }
626 631
627 632 hdlp->ih_cb_func = inthandler;
628 633 hdlp->ih_cb_arg1 = arg1;
629 634 hdlp->ih_cb_arg2 = arg2;
630 635
631 636 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
632 637 DDI_INTROP_ADDISR, hdlp, NULL);
633 638
634 639 if (ret != DDI_SUCCESS) {
635 640 hdlp->ih_cb_func = NULL;
636 641 hdlp->ih_cb_arg1 = NULL;
637 642 hdlp->ih_cb_arg2 = NULL;
638 643 } else
639 644 hdlp->ih_state = DDI_IHDL_STATE_ADDED;
640 645
641 646 rw_exit(&hdlp->ih_rwlock);
642 647 return (ret);
643 648 }
644 649
645 650 int
646 651 ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum,
647 652 ddi_intr_handle_t *dup)
648 653 {
649 654 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)org;
650 655 ddi_intr_handle_impl_t *dup_hdlp;
651 656 int ret;
652 657
653 658 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
654 659 (void *)hdlp));
655 660
656 661 /* Do some input argument checking ("dup" handle is not allocated) */
657 662 if ((hdlp == NULL) || (*dup != NULL) || (dup_inum < 0)) {
658 663 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: Invalid "
659 664 "input args\n"));
660 665 return (DDI_EINVAL);
661 666 }
662 667
663 668 rw_enter(&hdlp->ih_rwlock, RW_READER);
664 669
665 670 /* Do some input argument checking */
666 671 if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */
667 672 (hdlp->ih_type != DDI_INTR_TYPE_MSIX) || /* only MSI-X allowed */
668 673 (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) { /* only dup original */
669 674 rw_exit(&hdlp->ih_rwlock);
670 675 return (DDI_EINVAL);
671 676 }
672 677
673 678 hdlp->ih_scratch1 = dup_inum;
674 679 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
675 680 DDI_INTROP_DUPVEC, hdlp, NULL);
676 681
677 682 if (ret == DDI_SUCCESS) {
678 683 dup_hdlp = (ddi_intr_handle_impl_t *)
679 684 kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
680 685
681 686 atomic_inc_32(&hdlp->ih_dup_cnt);
682 687
683 688 *dup = (ddi_intr_handle_t)dup_hdlp;
684 689 bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t));
685 690
686 691 /* These fields are unique to each dupped msi-x vector */
687 692 rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
688 693 dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
689 694 dup_hdlp->ih_inum = dup_inum;
690 695 dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP;
691 696 dup_hdlp->ih_dup_cnt = 0;
692 697
693 698 /* Point back to original vector */
694 699 dup_hdlp->ih_main = hdlp;
695 700 }
696 701
697 702 rw_exit(&hdlp->ih_rwlock);
698 703 return (ret);
699 704 }
700 705
701 706 int
702 707 ddi_intr_remove_handler(ddi_intr_handle_t h)
703 708 {
704 709 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
705 710 int ret = DDI_SUCCESS;
706 711
707 712 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
708 713 (void *)hdlp));
709 714
710 715 if (hdlp == NULL)
711 716 return (DDI_EINVAL);
712 717
713 718 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
714 719
715 720 if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
716 721 ret = DDI_EINVAL;
717 722 goto done;
718 723 } else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
719 724 goto done;
720 725
721 726 ASSERT(hdlp->ih_dup_cnt == 0);
722 727 if (hdlp->ih_dup_cnt > 0) {
723 728 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X "
724 729 "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt));
725 730 ret = DDI_FAILURE;
726 731 goto done;
727 732 }
728 733
729 734 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
730 735 DDI_INTROP_REMISR, hdlp, NULL);
731 736
732 737 if (ret == DDI_SUCCESS) {
733 738 hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
734 739 hdlp->ih_cb_func = NULL;
735 740 hdlp->ih_cb_arg1 = NULL;
736 741 hdlp->ih_cb_arg2 = NULL;
737 742 }
738 743
739 744 done:
740 745 rw_exit(&hdlp->ih_rwlock);
741 746 return (ret);
742 747 }
743 748
744 749
745 750 /*
746 751 * Interrupt enable/disable/block_enable/block_disable handlers
747 752 */
748 753 int
749 754 ddi_intr_enable(ddi_intr_handle_t h)
750 755 {
751 756 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
752 757 int ret;
753 758
754 759 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
755 760 (void *)hdlp));
756 761
757 762 if (hdlp == NULL)
758 763 return (DDI_EINVAL);
759 764
760 765 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
761 766 if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
762 767 ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
763 768 (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
764 769 rw_exit(&hdlp->ih_rwlock);
765 770 return (DDI_EINVAL);
766 771 }
767 772
768 773 I_DDI_VERIFY_MSIX_HANDLE(hdlp);
769 774
770 775 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
771 776 DDI_INTROP_ENABLE, hdlp, NULL);
772 777
773 778 if (ret == DDI_SUCCESS) {
774 779 hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
775 780 i_ddi_intr_set_current_nenables(hdlp->ih_dip,
776 781 i_ddi_intr_get_current_nenables(hdlp->ih_dip) + 1);
777 782 }
778 783
779 784 rw_exit(&hdlp->ih_rwlock);
780 785 return (ret);
781 786 }
782 787
783 788 int
784 789 ddi_intr_disable(ddi_intr_handle_t h)
785 790 {
786 791 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
787 792 int ret;
788 793
789 794 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
790 795 (void *)hdlp));
791 796
792 797 if (hdlp == NULL)
793 798 return (DDI_EINVAL);
794 799
795 800 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
796 801 if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
797 802 ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
798 803 (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
799 804 rw_exit(&hdlp->ih_rwlock);
800 805 return (DDI_EINVAL);
801 806 }
802 807
803 808 I_DDI_VERIFY_MSIX_HANDLE(hdlp);
804 809
805 810 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
806 811 DDI_INTROP_DISABLE, hdlp, NULL);
807 812
808 813 if (ret == DDI_SUCCESS) {
809 814 hdlp->ih_state = DDI_IHDL_STATE_ADDED;
810 815 i_ddi_intr_set_current_nenables(hdlp->ih_dip,
811 816 i_ddi_intr_get_current_nenables(hdlp->ih_dip) - 1);
812 817 }
813 818
814 819 rw_exit(&hdlp->ih_rwlock);
815 820 return (ret);
816 821 }
817 822
818 823 int
819 824 ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
820 825 {
821 826 ddi_intr_handle_impl_t *hdlp;
822 827 int i, ret;
823 828
824 829 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
825 830 (void *)h_array));
826 831
827 832 if (h_array == NULL)
828 833 return (DDI_EINVAL);
829 834
830 835 for (i = 0; i < count; i++) {
831 836 hdlp = (ddi_intr_handle_impl_t *)h_array[i];
832 837 rw_enter(&hdlp->ih_rwlock, RW_READER);
833 838
834 839 if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
835 840 hdlp->ih_type != DDI_INTR_TYPE_MSI ||
836 841 !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
837 842 rw_exit(&hdlp->ih_rwlock);
838 843 return (DDI_EINVAL);
839 844 }
840 845 rw_exit(&hdlp->ih_rwlock);
841 846 }
842 847
843 848 hdlp = (ddi_intr_handle_impl_t *)h_array[0];
844 849 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
845 850 hdlp->ih_scratch1 = count;
846 851 hdlp->ih_scratch2 = (void *)h_array;
847 852
848 853 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
849 854 DDI_INTROP_BLOCKENABLE, hdlp, NULL);
850 855
851 856 rw_exit(&hdlp->ih_rwlock);
852 857
853 858 if (ret == DDI_SUCCESS) {
854 859 for (i = 0; i < count; i++) {
855 860 hdlp = (ddi_intr_handle_impl_t *)h_array[i];
856 861 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
857 862 hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
858 863 rw_exit(&hdlp->ih_rwlock);
859 864 }
860 865 i_ddi_intr_set_current_nenables(hdlp->ih_dip, 1);
861 866 }
862 867
863 868 return (ret);
864 869 }
865 870
866 871 int
867 872 ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
868 873 {
869 874 ddi_intr_handle_impl_t *hdlp;
870 875 int i, ret;
871 876
872 877 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
873 878 (void *)h_array));
874 879
875 880 if (h_array == NULL)
876 881 return (DDI_EINVAL);
877 882
878 883 for (i = 0; i < count; i++) {
879 884 hdlp = (ddi_intr_handle_impl_t *)h_array[i];
880 885 rw_enter(&hdlp->ih_rwlock, RW_READER);
881 886 if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
882 887 hdlp->ih_type != DDI_INTR_TYPE_MSI ||
883 888 !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
884 889 rw_exit(&hdlp->ih_rwlock);
885 890 return (DDI_EINVAL);
886 891 }
887 892 rw_exit(&hdlp->ih_rwlock);
888 893 }
889 894
890 895 hdlp = (ddi_intr_handle_impl_t *)h_array[0];
891 896 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
892 897 hdlp->ih_scratch1 = count;
893 898 hdlp->ih_scratch2 = (void *)h_array;
894 899
895 900 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
896 901 DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
897 902
898 903 rw_exit(&hdlp->ih_rwlock);
899 904
900 905 if (ret == DDI_SUCCESS) {
901 906 for (i = 0; i < count; i++) {
902 907 hdlp = (ddi_intr_handle_impl_t *)h_array[i];
903 908 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
904 909 hdlp->ih_state = DDI_IHDL_STATE_ADDED;
905 910 rw_exit(&hdlp->ih_rwlock);
906 911 }
907 912 i_ddi_intr_set_current_nenables(hdlp->ih_dip, 0);
908 913 }
909 914
910 915 return (ret);
911 916 }
912 917
913 918 /*
914 919 * Interrupt set/clr mask handlers
915 920 */
916 921 int
917 922 ddi_intr_set_mask(ddi_intr_handle_t h)
918 923 {
919 924 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
920 925 int ret;
921 926
922 927 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
923 928 (void *)hdlp));
924 929
925 930 if (hdlp == NULL)
926 931 return (DDI_EINVAL);
927 932
928 933 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
929 934 if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
930 935 (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
931 936 rw_exit(&hdlp->ih_rwlock);
932 937 return (DDI_EINVAL);
933 938 }
934 939
935 940 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
936 941 DDI_INTROP_SETMASK, hdlp, NULL);
937 942
938 943 rw_exit(&hdlp->ih_rwlock);
939 944 return (ret);
940 945 }
941 946
942 947 int
943 948 ddi_intr_clr_mask(ddi_intr_handle_t h)
944 949 {
945 950 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
946 951 int ret;
947 952
948 953 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
949 954 (void *)hdlp));
950 955
951 956 if (hdlp == NULL)
952 957 return (DDI_EINVAL);
953 958
954 959 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
955 960 if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
956 961 (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
957 962 rw_exit(&hdlp->ih_rwlock);
958 963 return (DDI_EINVAL);
959 964 }
960 965
961 966 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
962 967 DDI_INTROP_CLRMASK, hdlp, NULL);
963 968
964 969 rw_exit(&hdlp->ih_rwlock);
965 970 return (ret);
966 971 }
967 972
968 973 /*
969 974 * Interrupt get_pending handler
970 975 */
971 976 int
972 977 ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
973 978 {
974 979 ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
975 980 int ret;
976 981
977 982 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
978 983 (void *)hdlp));
979 984
980 985 if (hdlp == NULL)
981 986 return (DDI_EINVAL);
982 987
983 988 rw_enter(&hdlp->ih_rwlock, RW_READER);
984 989 if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
985 990 rw_exit(&hdlp->ih_rwlock);
986 991 return (DDI_EINVAL);
987 992 }
988 993
989 994 ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
990 995 DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
991 996
992 997 rw_exit(&hdlp->ih_rwlock);
993 998 return (ret);
994 999 }
995 1000
996 1001 /*
997 1002 * Set the number of interrupts requested from IRM
998 1003 */
999 1004 int
1000 1005 ddi_intr_set_nreq(dev_info_t *dip, int nreq)
1001 1006 {
1002 1007 int curr_type, nintrs;
1003 1008
1004 1009 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_nreq: dip %p, nreq %d\n",
1005 1010 (void *)dip, nreq));
1006 1011
1007 1012 ASSERT(dip != NULL);
1008 1013 ASSERT(nreq > 0);
1009 1014
1010 1015 /* Sanity check inputs */
1011 1016 if ((dip == NULL) || (nreq < 1))
1012 1017 return (DDI_EINVAL);
1013 1018
1014 1019 curr_type = i_ddi_intr_get_current_type(dip);
1015 1020
1016 1021 /* Only valid for IRM drivers actively using interrupts */
1017 1022 if ((curr_type == 0) ||
1018 1023 (i_ddi_irm_supported(dip, curr_type) != DDI_SUCCESS))
1019 1024 return (DDI_ENOTSUP);
1020 1025
1021 1026 /* Range check */
1022 1027 if (ddi_intr_get_nintrs(dip, curr_type, &nintrs) != DDI_SUCCESS)
1023 1028 return (DDI_FAILURE);
1024 1029 if (nreq > nintrs)
1025 1030 return (DDI_EINVAL);
1026 1031
1027 1032 return (i_ddi_irm_modify(dip, nreq));
1028 1033 }
1029 1034
1030 1035 /*
1031 1036 * Soft interrupt handlers
1032 1037 */
1033 1038 /*
1034 1039 * Add a soft interrupt and register its handler
1035 1040 */
1036 1041 /* ARGSUSED */
1037 1042 int
1038 1043 ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
1039 1044 ddi_intr_handler_t handler, void *arg1)
1040 1045 {
1041 1046 ddi_softint_hdl_impl_t *hdlp;
1042 1047 int ret;
1043 1048
1044 1049 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
1045 1050 "softpri = 0x%x\n", (void *)dip, soft_pri));
1046 1051
1047 1052 if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
1048 1053 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
1049 1054 "invalid arguments"));
1050 1055
1051 1056 return (DDI_EINVAL);
1052 1057 }
1053 1058
1054 1059 /* Validate input arguments */
1055 1060 if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
1056 1061 soft_pri > DDI_INTR_SOFTPRI_MAX) {
1057 1062 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
1058 1063 "soft_pri input given = %x\n", soft_pri));
1059 1064 return (DDI_EINVAL);
1060 1065 }
1061 1066
1062 1067 hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
1063 1068 sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
1064 1069
1065 1070 /* fill up internally */
1066 1071 rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
1067 1072 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1068 1073 hdlp->ih_pri = soft_pri;
1069 1074 hdlp->ih_dip = dip;
1070 1075 hdlp->ih_cb_func = handler;
1071 1076 hdlp->ih_cb_arg1 = arg1;
1072 1077 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
1073 1078 (void *)hdlp));
1074 1079
1075 1080 /* do the platform specific calls */
1076 1081 if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
1077 1082 rw_exit(&hdlp->ih_rwlock);
1078 1083 rw_destroy(&hdlp->ih_rwlock);
1079 1084 kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
1080 1085 return (ret);
1081 1086 }
1082 1087
1083 1088 *h_p = (ddi_softint_handle_t)hdlp;
1084 1089 rw_exit(&hdlp->ih_rwlock);
1085 1090 return (ret);
1086 1091 }
1087 1092
1088 1093 /*
1089 1094 * Remove the soft interrupt
1090 1095 */
1091 1096 int
1092 1097 ddi_intr_remove_softint(ddi_softint_handle_t h)
1093 1098 {
1094 1099 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
1095 1100
1096 1101 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
1097 1102 (void *)hdlp));
1098 1103
1099 1104 if (hdlp == NULL)
1100 1105 return (DDI_EINVAL);
1101 1106
1102 1107 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1103 1108 i_ddi_remove_softint(hdlp);
1104 1109 rw_exit(&hdlp->ih_rwlock);
1105 1110 rw_destroy(&hdlp->ih_rwlock);
1106 1111
1107 1112 /* kmem_free the hdl impl_t structure allocated earlier */
1108 1113 kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
1109 1114 return (DDI_SUCCESS);
1110 1115 }
1111 1116
1112 1117 /*
1113 1118 * Trigger a soft interrupt
1114 1119 */
1115 1120 int
1116 1121 ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
1117 1122 {
1118 1123 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
1119 1124 int ret;
1120 1125
1121 1126 if (hdlp == NULL)
1122 1127 return (DDI_EINVAL);
1123 1128
1124 1129 if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) {
1125 1130 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
1126 1131 " ret 0%x\n", ret));
1127 1132
1128 1133 return (ret);
1129 1134 }
1130 1135
1131 1136 hdlp->ih_cb_arg2 = arg2;
1132 1137 return (DDI_SUCCESS);
1133 1138 }
1134 1139
1135 1140 /*
1136 1141 * Get the soft interrupt priority
1137 1142 */
1138 1143 int
1139 1144 ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
1140 1145 {
1141 1146 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
1142 1147
1143 1148 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
1144 1149 (void *)h));
1145 1150
1146 1151 if (hdlp == NULL)
1147 1152 return (DDI_EINVAL);
1148 1153
1149 1154 rw_enter(&hdlp->ih_rwlock, RW_READER);
1150 1155 *soft_prip = hdlp->ih_pri;
1151 1156 rw_exit(&hdlp->ih_rwlock);
1152 1157 return (DDI_SUCCESS);
1153 1158 }
1154 1159
1155 1160 /*
1156 1161 * Set the soft interrupt priority
1157 1162 */
1158 1163 int
1159 1164 ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
1160 1165 {
1161 1166 ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
1162 1167 int ret;
1163 1168 uint_t orig_soft_pri;
1164 1169
1165 1170 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
1166 1171 (void *)h));
1167 1172
1168 1173 if (hdlp == NULL)
1169 1174 return (DDI_EINVAL);
1170 1175
1171 1176 /* Validate priority argument */
1172 1177 if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
1173 1178 soft_pri > DDI_INTR_SOFTPRI_MAX) {
1174 1179 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
1175 1180 "soft_pri input given = %x\n", soft_pri));
1176 1181 return (DDI_EINVAL);
1177 1182 }
1178 1183
1179 1184 rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1180 1185 orig_soft_pri = hdlp->ih_pri;
1181 1186 hdlp->ih_pri = soft_pri;
1182 1187
1183 1188 if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
1184 1189 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
1185 1190 " ret 0%x\n", ret));
1186 1191 hdlp->ih_pri = orig_soft_pri;
1187 1192 }
1188 1193
1189 1194 rw_exit(&hdlp->ih_rwlock);
1190 1195 return (ret);
1191 1196 }
1192 1197
1193 1198 /*
1194 1199 * Old DDI interrupt framework
1195 1200 *
1196 1201 * The following DDI interrupt interfaces are obsolete.
1197 1202 * Use the above new DDI interrupt interfaces instead.
1198 1203 */
1199 1204
1200 1205 int
1201 1206 ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
1202 1207 {
1203 1208 ddi_intr_handle_t hdl;
1204 1209 ddi_intr_handle_t *hdl_p;
1205 1210 size_t hdl_sz = 0;
1206 1211 int actual, ret;
1207 1212 uint_t high_pri, pri;
1208 1213
1209 1214 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
1210 1215 "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1211 1216 (void *)dip, inumber));
1212 1217
1213 1218 /*
1214 1219 * The device driver may have already registed with the
1215 1220 * framework. If so, first try to get the existing interrupt handle
1216 1221 * for that given inumber and use that handle.
1217 1222 */
1218 1223 if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
1219 1224 hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
1220 1225 hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
1221 1226 if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1222 1227 inumber, 1, &actual,
1223 1228 DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
1224 1229 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
1225 1230 "ddi_intr_alloc failed, ret 0x%x\n", ret));
1226 1231 kmem_free(hdl_p, hdl_sz);
1227 1232 return (0);
1228 1233 }
1229 1234 hdl = hdl_p[inumber];
1230 1235 }
1231 1236
1232 1237 if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
1233 1238 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
1234 1239 "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1235 1240 (void) ddi_intr_free(hdl);
1236 1241 if (hdl_sz)
1237 1242 kmem_free(hdl_p, hdl_sz);
1238 1243 return (0);
1239 1244 }
1240 1245
1241 1246 high_pri = ddi_intr_get_hilevel_pri();
1242 1247
1243 1248 DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
1244 1249 "high_pri = %x\n", pri, high_pri));
1245 1250
1246 1251 /* Free the handle allocated here only if no existing handle exists */
1247 1252 if (hdl_sz) {
1248 1253 (void) ddi_intr_free(hdl);
1249 1254 kmem_free(hdl_p, hdl_sz);
1250 1255 }
1251 1256
1252 1257 return (pri >= high_pri);
1253 1258 }
1254 1259
1255 1260 int
1256 1261 ddi_dev_nintrs(dev_info_t *dip, int *result)
1257 1262 {
1258 1263 DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
1259 1264 ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
1260 1265
1261 1266 if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
1262 1267 result) != DDI_SUCCESS) {
1263 1268 DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
1264 1269 "ddi_intr_get_nintrs failed\n"));
1265 1270 *result = 0;
1266 1271 }
1267 1272
1268 1273 return (DDI_SUCCESS);
1269 1274 }
1270 1275
1271 1276 int
1272 1277 ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
1273 1278 ddi_iblock_cookie_t *iblock_cookiep)
1274 1279 {
1275 1280 ddi_intr_handle_t hdl;
1276 1281 ddi_intr_handle_t *hdl_p;
1277 1282 size_t hdl_sz = 0;
1278 1283 int actual, ret;
1279 1284 uint_t pri;
1280 1285
1281 1286 DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
1282 1287 "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1283 1288 (void *)dip, inumber));
1284 1289
1285 1290 ASSERT(iblock_cookiep != NULL);
1286 1291
1287 1292 /*
1288 1293 * The device driver may have already registed with the
1289 1294 * framework. If so, first try to get the existing interrupt handle
1290 1295 * for that given inumber and use that handle.
1291 1296 */
1292 1297 if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
1293 1298 hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
1294 1299 hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
1295 1300 if ((ret = ddi_intr_alloc(dip, hdl_p,
1296 1301 DDI_INTR_TYPE_FIXED, inumber, 1, &actual,
1297 1302 DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
1298 1303 DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
1299 1304 "ddi_intr_alloc failed, ret 0x%x\n", ret));
1300 1305 kmem_free(hdl_p, hdl_sz);
1301 1306 return (DDI_INTR_NOTFOUND);
1302 1307 }
1303 1308 hdl = hdl_p[inumber];
1304 1309 }
1305 1310
1306 1311 if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
1307 1312 DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
1308 1313 "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1309 1314 (void) ddi_intr_free(hdl);
1310 1315 if (hdl_sz)
1311 1316 kmem_free(hdl_p, hdl_sz);
1312 1317 return (DDI_FAILURE);
1313 1318 }
1314 1319
1315 1320 *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
1316 1321 /* Free the handle allocated here only if no existing handle exists */
1317 1322 if (hdl_sz) {
1318 1323 (void) ddi_intr_free(hdl);
1319 1324 kmem_free(hdl_p, hdl_sz);
1320 1325 }
1321 1326
1322 1327 return (DDI_SUCCESS);
1323 1328 }
1324 1329
1325 1330 int
1326 1331 ddi_add_intr(dev_info_t *dip, uint_t inumber,
1327 1332 ddi_iblock_cookie_t *iblock_cookiep,
1328 1333 ddi_idevice_cookie_t *idevice_cookiep,
1329 1334 uint_t (*int_handler)(caddr_t int_handler_arg),
1330 1335 caddr_t int_handler_arg)
1331 1336 {
1332 1337 ddi_intr_handle_t *hdl_p;
1333 1338 size_t hdl_sz;
1334 1339 int actual, ret;
1335 1340 uint_t pri;
1336 1341
1337 1342 DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
1338 1343 "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1339 1344 (void *)dip, inumber));
1340 1345
1341 1346 hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
1342 1347 hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
1343 1348
1344 1349 if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1345 1350 inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
1346 1351 DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1347 1352 "ddi_intr_alloc failed, ret 0x%x\n", ret));
1348 1353 kmem_free(hdl_p, hdl_sz);
1349 1354 return (DDI_INTR_NOTFOUND);
1350 1355 }
1351 1356
1352 1357 if ((ret = ddi_intr_get_pri(hdl_p[inumber], &pri)) != DDI_SUCCESS) {
1353 1358 DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1354 1359 "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1355 1360 (void) ddi_intr_free(hdl_p[inumber]);
1356 1361 kmem_free(hdl_p, hdl_sz);
1357 1362 return (DDI_FAILURE);
1358 1363 }
1359 1364
1360 1365 if ((ret = ddi_intr_add_handler(hdl_p[inumber], (ddi_intr_handler_t *)
1361 1366 int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
1362 1367 DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1363 1368 "ddi_intr_add_handler failed, ret 0x%x\n", ret));
1364 1369 (void) ddi_intr_free(hdl_p[inumber]);
1365 1370 kmem_free(hdl_p, hdl_sz);
1366 1371 return (DDI_FAILURE);
1367 1372 }
1368 1373
1369 1374 if ((ret = ddi_intr_enable(hdl_p[inumber])) != DDI_SUCCESS) {
1370 1375 DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1371 1376 "ddi_intr_enable failed, ret 0x%x\n", ret));
1372 1377 (void) ddi_intr_remove_handler(hdl_p[inumber]);
1373 1378 (void) ddi_intr_free(hdl_p[inumber]);
1374 1379 kmem_free(hdl_p, hdl_sz);
1375 1380 return (DDI_FAILURE);
1376 1381 }
1377 1382
1378 1383 if (iblock_cookiep)
1379 1384 *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
1380 1385
1381 1386 if (idevice_cookiep) {
1382 1387 idevice_cookiep->idev_vector = 0;
1383 1388 idevice_cookiep->idev_priority = pri;
1384 1389 }
1385 1390
1386 1391 kmem_free(hdl_p, hdl_sz);
1387 1392
1388 1393 return (DDI_SUCCESS);
1389 1394 }
1390 1395
1391 1396 /* ARGSUSED */
1392 1397 int
1393 1398 ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
1394 1399 ddi_iblock_cookie_t *iblock_cookiep,
1395 1400 ddi_idevice_cookie_t *idevice_cookiep,
1396 1401 uint_t (*hi_int_handler)(void))
1397 1402 {
1398 1403 DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
1399 1404 "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
1400 1405 ddi_get_instance(dip), (void *)dip, inumber));
1401 1406
1402 1407 return (DDI_FAILURE);
1403 1408 }
1404 1409
1405 1410 /* ARGSUSED */
1406 1411 void
1407 1412 ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
1408 1413 {
1409 1414 ddi_intr_handle_t hdl;
1410 1415 int ret;
1411 1416
1412 1417 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
1413 1418 "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1414 1419 (void *)dip, inum));
1415 1420
1416 1421 if ((hdl = i_ddi_get_intr_handle(dip, inum)) == NULL) {
1417 1422 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
1418 1423 "found\n"));
1419 1424 return;
1420 1425 }
1421 1426
1422 1427 if ((ret = ddi_intr_disable(hdl)) != DDI_SUCCESS) {
1423 1428 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1424 1429 "ddi_intr_disable failed, ret 0x%x\n", ret));
1425 1430 return;
1426 1431 }
1427 1432
1428 1433 if ((ret = ddi_intr_remove_handler(hdl)) != DDI_SUCCESS) {
1429 1434 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1430 1435 "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
1431 1436 return;
1432 1437 }
1433 1438
1434 1439 if ((ret = ddi_intr_free(hdl)) != DDI_SUCCESS) {
1435 1440 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1436 1441 "ddi_intr_free failed, ret 0x%x\n", ret));
1437 1442 return;
1438 1443 }
1439 1444 }
1440 1445
1441 1446 /* ARGSUSED */
1442 1447 int
1443 1448 ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
1444 1449 ddi_iblock_cookie_t *iblock_cookiep)
1445 1450 {
1446 1451 DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
1447 1452 "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1448 1453 (void *)dip, preference));
1449 1454
1450 1455 ASSERT(iblock_cookiep != NULL);
1451 1456
1452 1457 if (preference == DDI_SOFTINT_FIXED)
1453 1458 return (DDI_FAILURE);
1454 1459
1455 1460 *iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t)
1456 1461 ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
1457 1462 DDI_SOFT_INTR_PRI_M));
1458 1463
1459 1464 return (DDI_SUCCESS);
1460 1465 }
1461 1466
1462 1467 int
1463 1468 ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
1464 1469 ddi_iblock_cookie_t *iblock_cookiep,
1465 1470 ddi_idevice_cookie_t *idevice_cookiep,
1466 1471 uint_t (*int_handler)(caddr_t int_handler_arg),
1467 1472 caddr_t int_handler_arg)
1468 1473 {
1469 1474 ddi_softint_handle_t *hdl_p;
1470 1475 uint64_t softpri;
1471 1476 int ret;
1472 1477
1473 1478 DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
1474 1479 "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1475 1480 (void *)dip, preference));
1476 1481
1477 1482 if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
1478 1483 (iblock_cookiep == NULL)))
1479 1484 return (DDI_FAILURE);
1480 1485
1481 1486 /* Translate the priority preference */
1482 1487 if (preference == DDI_SOFTINT_FIXED) {
1483 1488 softpri = (uint64_t)(uintptr_t)*iblock_cookiep;
1484 1489 softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
1485 1490 } else {
1486 1491 softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
1487 1492 DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
1488 1493 }
1489 1494
1490 1495 DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
1491 1496 "softpri 0x%lx\n", preference, (long)softpri));
1492 1497
1493 1498 hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
1494 1499 if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
1495 1500 (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
1496 1501 DDI_SUCCESS) {
1497 1502 DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
1498 1503 "ddi_intr_add_softint failed, ret 0x%x\n", ret));
1499 1504
1500 1505 kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
1501 1506 return (DDI_FAILURE);
1502 1507 }
1503 1508
1504 1509 if (iblock_cookiep)
1505 1510 *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)softpri;
1506 1511
1507 1512 if (idevice_cookiep) {
1508 1513 idevice_cookiep->idev_vector = 0;
1509 1514 idevice_cookiep->idev_priority = softpri;
1510 1515 }
1511 1516
1512 1517 *idp = (ddi_softintr_t)hdl_p;
1513 1518
1514 1519 DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
1515 1520 "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
1516 1521
1517 1522 return (DDI_SUCCESS);
1518 1523 }
1519 1524
1520 1525 void
1521 1526 ddi_remove_softintr(ddi_softintr_t id)
1522 1527 {
1523 1528 ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id;
1524 1529
1525 1530 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
1526 1531 (void *)id));
1527 1532
1528 1533 if (h_p == NULL)
1529 1534 return;
1530 1535
1531 1536 DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
1532 1537 (void *)h_p));
1533 1538
1534 1539 (void) ddi_intr_remove_softint(*h_p);
1535 1540 kmem_free(h_p, sizeof (ddi_softint_handle_t));
1536 1541 }
1537 1542
1538 1543 void
1539 1544 ddi_trigger_softintr(ddi_softintr_t id)
1540 1545 {
1541 1546 ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id;
1542 1547 int ret;
1543 1548
1544 1549 if (h_p == NULL)
1545 1550 return;
1546 1551
1547 1552 if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
1548 1553 DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
1549 1554 "ddi_intr_trigger_softint failed, hdlp 0x%p "
1550 1555 "ret 0x%x\n", (void *)h_p, ret));
1551 1556 }
1552 1557 }
↓ open down ↓ |
1212 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX