4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/sysmacros.h>
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
31 #include <sys/cmn_err.h>
32 #include <sys/debug.h>
33 #include <sys/avintr.h>
34 #include <sys/autoconf.h>
35 #include <sys/sunndi.h>
36 #include <sys/ndi_impldefs.h> /* include prototypes */
37 #include <sys/atomic.h>
40 * New DDI interrupt framework
44 * ddi_intr_get_supported_types:
45 * Return, as a bit mask, the hardware interrupt types supported by
46 * both the device and by the host in the integer pointed
47 * to be the 'typesp' argument.
50 ddi_intr_get_supported_types(dev_info_t
*dip
, int *typesp
)
53 ddi_intr_handle_impl_t hdl
;
58 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_supported_types: dip %p\n",
61 if (*typesp
= i_ddi_intr_get_supported_types(dip
))
64 bzero(&hdl
, sizeof (ddi_intr_handle_impl_t
));
67 ret
= i_ddi_intr_ops(dip
, dip
, DDI_INTROP_SUPPORTED_TYPES
, &hdl
,
70 if (ret
!= DDI_SUCCESS
)
71 return (DDI_INTR_NOTFOUND
);
73 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_supported_types: types %x\n",
80 * ddi_intr_get_nintrs:
81 * Return as an integer in the integer pointed to by the argument
82 * *nintrsp*, the number of interrupts the device supports for the
83 * given interrupt type.
86 ddi_intr_get_nintrs(dev_info_t
*dip
, int type
, int *nintrsp
)
89 ddi_intr_handle_impl_t hdl
;
91 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_nintrs: dip %p, type: %d\n",
94 if ((dip
== NULL
) || (nintrsp
== NULL
) ||
95 !DDI_INTR_TYPE_FLAG_VALID(type
) ||
96 !(i_ddi_intr_get_supported_types(dip
) & type
)) {
97 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_nintrs: "
98 "Invalid input args\n"));
102 if (*nintrsp
= i_ddi_intr_get_supported_nintrs(dip
, type
))
103 return (DDI_SUCCESS
);
105 bzero(&hdl
, sizeof (ddi_intr_handle_impl_t
));
109 ret
= i_ddi_intr_ops(dip
, dip
, DDI_INTROP_NINTRS
, &hdl
,
112 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_nintrs:: nintrs %x\n",
119 * ddi_intr_get_navail:
120 * Bus nexus driver will return availble interrupt count value for
121 * a given interrupt type.
123 * Return as an integer in the integer pointed to by the argument
124 * *navailp*, the number of interrupts currently available for the
125 * given interrupt type.
128 ddi_intr_get_navail(dev_info_t
*dip
, int type
, int *navailp
)
130 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_navail: dip %p, type: %d\n",
133 if ((dip
== NULL
) || (navailp
== NULL
) ||
134 !DDI_INTR_TYPE_FLAG_VALID(type
) ||
135 !(i_ddi_intr_get_supported_types(dip
) & type
)) {
136 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_navail: "
137 "Invalid input args\n"));
141 if ((*navailp
= i_ddi_intr_get_current_navail(dip
, type
)) == 0)
142 return (DDI_INTR_NOTFOUND
);
144 return (DDI_SUCCESS
);
148 * Interrupt allocate/free functions
151 ddi_intr_alloc(dev_info_t
*dip
, ddi_intr_handle_t
*h_array
, int type
, int inum
,
152 int count
, int *actualp
, int behavior
)
154 ddi_intr_handle_impl_t
*hdlp
, tmp_hdl
;
155 int i
, ret
, cap
= 0, curr_type
, nintrs
;
156 uint_t pri
, navail
, curr_nintrs
= 0;
158 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: name %s dip 0x%p "
159 "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip
),
160 (void *)dip
, type
, inum
, count
, behavior
));
162 /* Validate parameters */
163 if ((dip
== NULL
) || (h_array
== NULL
) || (inum
< 0) || (count
< 1) ||
164 (actualp
== NULL
) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior
)) {
165 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: "
166 "Invalid input args\n"));
170 /* Validate interrupt type */
171 if (!DDI_INTR_TYPE_FLAG_VALID(type
) ||
172 !(i_ddi_intr_get_supported_types(dip
) & type
)) {
173 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: type %x not "
174 "supported\n", type
));
178 /* Validate inum not previously allocated */
179 if ((type
== DDI_INTR_TYPE_FIXED
) &&
180 (i_ddi_get_intr_handle(dip
, inum
) != NULL
)) {
181 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: inum %d is already "
182 "in use, cannot allocate again!!\n", inum
));
186 /* Get how many interrupts the device supports */
187 if ((nintrs
= i_ddi_intr_get_supported_nintrs(dip
, type
)) == 0) {
188 if (ddi_intr_get_nintrs(dip
, type
, &nintrs
) != DDI_SUCCESS
) {
189 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: no "
190 "interrupts found of type %d\n", type
));
191 return (DDI_INTR_NOTFOUND
);
195 /* Get how many interrupts the device is already using */
196 if ((curr_type
= i_ddi_intr_get_current_type(dip
)) != 0) {
197 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: type %x "
198 "is already being used\n", curr_type
));
199 curr_nintrs
= i_ddi_intr_get_current_nintrs(dip
);
202 /* Validate interrupt type consistency */
203 if ((curr_type
!= 0) && (type
!= curr_type
)) {
204 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: Requested "
205 "interrupt type %x is different from interrupt type %x"
206 "already in use\n", type
, curr_type
));
210 /* Validate count does not exceed what device supports */
211 if (count
> nintrs
) {
212 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: no of interrupts "
213 "requested %d is more than supported %d\n", count
, nintrs
));
215 } else if ((count
+ curr_nintrs
) > nintrs
) {
216 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: count %d "
217 "+ intrs in use %d exceeds supported %d intrs\n",
218 count
, curr_nintrs
, nintrs
));
222 /* Validate power of 2 requirements for MSI */
223 if ((type
== DDI_INTR_TYPE_MSI
) && !ISP2(curr_nintrs
+ count
)) {
224 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: "
225 "MSI count %d is not a power of two\n", count
));
230 * Initialize the device's interrupt information structure,
231 * and establish an association with IRM if it is supported.
233 * NOTE: IRM checks minimum support, and can return DDI_EAGAIN.
235 if (curr_nintrs
== 0) {
236 i_ddi_intr_devi_init(dip
);
237 if (i_ddi_irm_insert(dip
, type
, count
) == DDI_EAGAIN
) {
238 cmn_err(CE_WARN
, "ddi_intr_alloc: "
239 "cannot fit into interrupt pool\n");
244 /* Synchronously adjust IRM associations for non-IRM aware drivers */
245 if (curr_nintrs
&& (i_ddi_irm_supported(dip
, type
) != DDI_SUCCESS
))
246 (void) i_ddi_irm_modify(dip
, count
+ curr_nintrs
);
248 /* Get how many interrupts are currently available */
249 navail
= i_ddi_intr_get_current_navail(dip
, type
);
251 /* Validate that requested number of interrupts are available */
252 if (curr_nintrs
== navail
) {
253 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: max # of intrs %d "
254 "already allocated\n", navail
));
257 if ((count
+ curr_nintrs
) > navail
) {
258 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: requested # of "
259 "intrs %d exceeds # of available intrs %d\n", count
,
260 navail
- curr_nintrs
));
261 if (behavior
== DDI_INTR_ALLOC_STRICT
) {
262 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: "
263 "DDI_INTR_ALLOC_STRICT flag is passed, "
264 "return failure\n"));
265 if (curr_nintrs
== 0)
266 i_ddi_intr_devi_fini(dip
);
267 else if (i_ddi_irm_supported(dip
, type
) != DDI_SUCCESS
)
268 (void) i_ddi_irm_modify(dip
, curr_nintrs
);
271 count
= navail
- curr_nintrs
;
274 /* Now allocate required number of interrupts */
275 bzero(&tmp_hdl
, sizeof (ddi_intr_handle_impl_t
));
276 tmp_hdl
.ih_type
= type
;
277 tmp_hdl
.ih_inum
= inum
;
278 tmp_hdl
.ih_scratch1
= count
;
279 tmp_hdl
.ih_scratch2
= (void *)(uintptr_t)behavior
;
280 tmp_hdl
.ih_dip
= dip
;
282 if (i_ddi_intr_ops(dip
, dip
, DDI_INTROP_ALLOC
,
283 &tmp_hdl
, (void *)actualp
) != DDI_SUCCESS
) {
284 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: allocation "
286 i_ddi_intr_devi_fini(dip
);
287 return (*actualp
? DDI_EAGAIN
: DDI_INTR_NOTFOUND
);
290 if ((ret
= i_ddi_intr_ops(dip
, dip
, DDI_INTROP_GETPRI
,
291 &tmp_hdl
, (void *)&pri
)) != DDI_SUCCESS
) {
292 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: get priority "
297 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: getting capability\n"));
299 if ((ret
= i_ddi_intr_ops(dip
, dip
, DDI_INTROP_GETCAP
,
300 &tmp_hdl
, (void *)&cap
)) != DDI_SUCCESS
) {
301 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: get capability "
307 * Save current interrupt type, supported and current intr count.
309 i_ddi_intr_set_current_type(dip
, type
);
310 i_ddi_intr_set_supported_nintrs(dip
, nintrs
);
311 i_ddi_intr_set_current_nintrs(dip
,
312 i_ddi_intr_get_current_nintrs(dip
) + *actualp
);
314 /* Now, go and handle each "handle" */
315 for (i
= inum
; i
< (inum
+ *actualp
); i
++) {
316 hdlp
= (ddi_intr_handle_impl_t
*)kmem_zalloc(
317 (sizeof (ddi_intr_handle_impl_t
)), KM_SLEEP
);
318 rw_init(&hdlp
->ih_rwlock
, NULL
, RW_DRIVER
, NULL
);
319 h_array
[i
] = (struct __ddi_intr_handle
*)hdlp
;
320 hdlp
->ih_type
= type
;
323 hdlp
->ih_ver
= DDI_INTR_VERSION
;
324 hdlp
->ih_state
= DDI_IHDL_STATE_ALLOC
;
327 i_ddi_alloc_intr_phdl(hdlp
);
328 if (type
& DDI_INTR_TYPE_FIXED
)
329 i_ddi_set_intr_handle(dip
, hdlp
->ih_inum
,
330 (ddi_intr_handle_t
)hdlp
);
332 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_alloc: hdlp = 0x%p\n",
333 (void *)h_array
[i
]));
336 return (DDI_SUCCESS
);
339 (void) i_ddi_intr_ops(tmp_hdl
.ih_dip
, tmp_hdl
.ih_dip
,
340 DDI_INTROP_FREE
, &tmp_hdl
, NULL
);
341 i_ddi_intr_devi_fini(dip
);
347 ddi_intr_free(ddi_intr_handle_t h
)
349 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
352 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_free: hdlp = %p\n", (void *)hdlp
));
357 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
358 if (((hdlp
->ih_flags
& DDI_INTR_MSIX_DUP
) &&
359 (hdlp
->ih_state
!= DDI_IHDL_STATE_ADDED
)) ||
360 ((hdlp
->ih_state
!= DDI_IHDL_STATE_ALLOC
) &&
361 (!(hdlp
->ih_flags
& DDI_INTR_MSIX_DUP
)))) {
362 rw_exit(&hdlp
->ih_rwlock
);
366 /* Set the number of interrupts to free */
367 hdlp
->ih_scratch1
= 1;
369 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
370 DDI_INTROP_FREE
, hdlp
, NULL
);
372 rw_exit(&hdlp
->ih_rwlock
);
373 if (ret
== DDI_SUCCESS
) {
374 /* This would be the dup vector */
375 if (hdlp
->ih_flags
& DDI_INTR_MSIX_DUP
)
376 atomic_dec_32(&hdlp
->ih_main
->ih_dup_cnt
);
380 n
= i_ddi_intr_get_current_nintrs(hdlp
->ih_dip
) - 1;
381 curr_type
= i_ddi_intr_get_current_type(hdlp
->ih_dip
);
383 i_ddi_intr_set_current_nintrs(hdlp
->ih_dip
, n
);
385 if ((i_ddi_irm_supported(hdlp
->ih_dip
, curr_type
)
386 != DDI_SUCCESS
) && (n
> 0))
387 (void) i_ddi_irm_modify(hdlp
->ih_dip
, n
);
389 if (hdlp
->ih_type
& DDI_INTR_TYPE_FIXED
)
390 i_ddi_set_intr_handle(hdlp
->ih_dip
,
391 hdlp
->ih_inum
, NULL
);
393 i_ddi_intr_devi_fini(hdlp
->ih_dip
);
394 i_ddi_free_intr_phdl(hdlp
);
396 rw_destroy(&hdlp
->ih_rwlock
);
397 kmem_free(hdlp
, sizeof (ddi_intr_handle_impl_t
));
404 * Interrupt get/set capacity functions
406 * The logic used to figure this out is shown here:
408 * Device level Platform level Intr source
409 * 1. Fixed interrupts
411 * o Flags supported N/A Maskable/Pending/ rootnex
415 * 2. PCI Fixed interrupts
416 * o Flags supported pending/Maskable Maskable/pending/ pci
421 * o Flags supported Maskable/Pending Maskable/Pending pci
422 * Block Enable (if drvr doesn't) Block Enable
423 * o navail N/A #vectors - #used N/A
426 * o Flags supported Maskable/Pending Maskable/Pending pci
427 * Block Enable Block Enable
428 * o navail N/A #vectors - #used N/A
431 * #vectors - Total numbers of vectors available
432 * #used - Total numbers of vectors currently being used
434 * For devices complying to PCI2.3 or greater, see bit10 of Command Register
435 * 0 - enables assertion of INTx
436 * 1 - disables assertion of INTx
438 * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
439 * operations return failure.
442 ddi_intr_get_cap(ddi_intr_handle_t h
, int *flagsp
)
444 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
447 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_cap: hdlp = %p\n",
454 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
457 *flagsp
= hdlp
->ih_cap
& ~DDI_INTR_FLAG_MSI64
;
458 rw_exit(&hdlp
->ih_rwlock
);
459 return (DDI_SUCCESS
);
462 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
463 DDI_INTROP_GETCAP
, hdlp
, (void *)flagsp
);
465 if (ret
== DDI_SUCCESS
) {
466 hdlp
->ih_cap
= *flagsp
;
468 /* Mask out MSI/X 64-bit support to the consumer */
469 *flagsp
&= ~DDI_INTR_FLAG_MSI64
;
472 rw_exit(&hdlp
->ih_rwlock
);
477 ddi_intr_set_cap(ddi_intr_handle_t h
, int flags
)
479 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
482 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp
));
487 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
488 if (hdlp
->ih_state
!= DDI_IHDL_STATE_ALLOC
) {
489 rw_exit(&hdlp
->ih_rwlock
);
493 /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
494 if (!(flags
& (DDI_INTR_FLAG_EDGE
| DDI_INTR_FLAG_LEVEL
))) {
495 DDI_INTR_APIDBG((CE_CONT
, "%s%d: only LEVEL or EDGE capability "
496 "can be set\n", ddi_driver_name(hdlp
->ih_dip
),
497 ddi_get_instance(hdlp
->ih_dip
)));
498 rw_exit(&hdlp
->ih_rwlock
);
502 /* Both level/edge flags must be currently supported */
503 if (!(hdlp
->ih_cap
& (DDI_INTR_FLAG_EDGE
| DDI_INTR_FLAG_LEVEL
))) {
504 DDI_INTR_APIDBG((CE_CONT
, "%s%d: Both LEVEL and EDGE capability"
505 " must be supported\n", ddi_driver_name(hdlp
->ih_dip
),
506 ddi_get_instance(hdlp
->ih_dip
)));
507 rw_exit(&hdlp
->ih_rwlock
);
508 return (DDI_ENOTSUP
);
511 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
512 DDI_INTROP_SETCAP
, hdlp
, &flags
);
514 rw_exit(&hdlp
->ih_rwlock
);
519 * Priority related functions
523 * ddi_intr_get_hilevel_pri:
524 * Returns the minimum priority level for a
525 * high-level interrupt on a platform.
528 ddi_intr_get_hilevel_pri(void)
530 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_hilevel_pri:\n"));
531 return (LOCK_LEVEL
+ 1);
535 ddi_intr_get_pri(ddi_intr_handle_t h
, uint_t
*prip
)
537 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
540 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_pri: hdlp = %p\n",
547 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
548 /* Already initialized, just return that */
550 *prip
= hdlp
->ih_pri
;
551 rw_exit(&hdlp
->ih_rwlock
);
552 return (DDI_SUCCESS
);
555 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
556 DDI_INTROP_GETPRI
, hdlp
, (void *)prip
);
558 if (ret
== DDI_SUCCESS
)
559 hdlp
->ih_pri
= *prip
;
561 rw_exit(&hdlp
->ih_rwlock
);
566 ddi_intr_set_pri(ddi_intr_handle_t h
, uint_t pri
)
568 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
571 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp
));
576 /* Validate priority argument */
577 if (pri
< DDI_INTR_PRI_MIN
|| pri
> DDI_INTR_PRI_MAX
) {
578 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_pri: invalid priority "
579 "specified = %x\n", pri
));
583 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
584 if (hdlp
->ih_state
!= DDI_IHDL_STATE_ALLOC
) {
585 rw_exit(&hdlp
->ih_rwlock
);
589 /* If the passed priority is same as existing priority; do nothing */
590 if (pri
== hdlp
->ih_pri
) {
591 rw_exit(&hdlp
->ih_rwlock
);
592 return (DDI_SUCCESS
);
595 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
596 DDI_INTROP_SETPRI
, hdlp
, &pri
);
598 if (ret
== DDI_SUCCESS
)
601 rw_exit(&hdlp
->ih_rwlock
);
606 * Interrupt add/duplicate/remove handlers
609 ddi_intr_add_handler(ddi_intr_handle_t h
, ddi_intr_handler_t inthandler
,
610 void *arg1
, void *arg2
)
612 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
615 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_add_handler: hdlp = 0x%p\n",
618 if ((hdlp
== NULL
) || (inthandler
== NULL
))
621 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
622 if (hdlp
->ih_state
!= DDI_IHDL_STATE_ALLOC
) {
623 rw_exit(&hdlp
->ih_rwlock
);
627 hdlp
->ih_cb_func
= inthandler
;
628 hdlp
->ih_cb_arg1
= arg1
;
629 hdlp
->ih_cb_arg2
= arg2
;
631 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
632 DDI_INTROP_ADDISR
, hdlp
, NULL
);
634 if (ret
!= DDI_SUCCESS
) {
635 hdlp
->ih_cb_func
= NULL
;
636 hdlp
->ih_cb_arg1
= NULL
;
637 hdlp
->ih_cb_arg2
= NULL
;
639 hdlp
->ih_state
= DDI_IHDL_STATE_ADDED
;
641 rw_exit(&hdlp
->ih_rwlock
);
646 ddi_intr_dup_handler(ddi_intr_handle_t org
, int dup_inum
,
647 ddi_intr_handle_t
*dup
)
649 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)org
;
650 ddi_intr_handle_impl_t
*dup_hdlp
;
653 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_dup_handler: hdlp = 0x%p\n",
656 /* Do some input argument checking ("dup" handle is not allocated) */
657 if ((hdlp
== NULL
) || (*dup
!= NULL
) || (dup_inum
< 0)) {
658 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_dup_handler: Invalid "
663 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
665 /* Do some input argument checking */
666 if ((hdlp
->ih_state
== DDI_IHDL_STATE_ALLOC
) || /* intr handle alloc? */
667 (hdlp
->ih_type
!= DDI_INTR_TYPE_MSIX
) || /* only MSI-X allowed */
668 (hdlp
->ih_flags
& DDI_INTR_MSIX_DUP
)) { /* only dup original */
669 rw_exit(&hdlp
->ih_rwlock
);
673 hdlp
->ih_scratch1
= dup_inum
;
674 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
675 DDI_INTROP_DUPVEC
, hdlp
, NULL
);
677 if (ret
== DDI_SUCCESS
) {
678 dup_hdlp
= (ddi_intr_handle_impl_t
*)
679 kmem_alloc(sizeof (ddi_intr_handle_impl_t
), KM_SLEEP
);
681 atomic_inc_32(&hdlp
->ih_dup_cnt
);
683 *dup
= (ddi_intr_handle_t
)dup_hdlp
;
684 bcopy(hdlp
, dup_hdlp
, sizeof (ddi_intr_handle_impl_t
));
686 /* These fields are unique to each dupped msi-x vector */
687 rw_init(&dup_hdlp
->ih_rwlock
, NULL
, RW_DRIVER
, NULL
);
688 dup_hdlp
->ih_state
= DDI_IHDL_STATE_ADDED
;
689 dup_hdlp
->ih_inum
= dup_inum
;
690 dup_hdlp
->ih_flags
|= DDI_INTR_MSIX_DUP
;
691 dup_hdlp
->ih_dup_cnt
= 0;
693 /* Point back to original vector */
694 dup_hdlp
->ih_main
= hdlp
;
697 rw_exit(&hdlp
->ih_rwlock
);
702 ddi_intr_remove_handler(ddi_intr_handle_t h
)
704 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
705 int ret
= DDI_SUCCESS
;
707 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_remove_handler: hdlp = %p\n",
713 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
715 if (hdlp
->ih_state
!= DDI_IHDL_STATE_ADDED
) {
718 } else if (hdlp
->ih_flags
& DDI_INTR_MSIX_DUP
)
721 ASSERT(hdlp
->ih_dup_cnt
== 0);
722 if (hdlp
->ih_dup_cnt
> 0) {
723 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_remove_handler: MSI-X "
724 "dup_cnt %d is not 0\n", hdlp
->ih_dup_cnt
));
729 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
730 DDI_INTROP_REMISR
, hdlp
, NULL
);
732 if (ret
== DDI_SUCCESS
) {
733 hdlp
->ih_state
= DDI_IHDL_STATE_ALLOC
;
734 hdlp
->ih_cb_func
= NULL
;
735 hdlp
->ih_cb_arg1
= NULL
;
736 hdlp
->ih_cb_arg2
= NULL
;
740 rw_exit(&hdlp
->ih_rwlock
);
746 * Interrupt enable/disable/block_enable/block_disable handlers
749 ddi_intr_enable(ddi_intr_handle_t h
)
751 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
754 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_enable: hdlp = %p\n",
760 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
761 if ((hdlp
->ih_state
!= DDI_IHDL_STATE_ADDED
) ||
762 ((hdlp
->ih_type
== DDI_INTR_TYPE_MSI
) &&
763 (hdlp
->ih_cap
& DDI_INTR_FLAG_BLOCK
))) {
764 rw_exit(&hdlp
->ih_rwlock
);
768 I_DDI_VERIFY_MSIX_HANDLE(hdlp
);
770 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
771 DDI_INTROP_ENABLE
, hdlp
, NULL
);
773 if (ret
== DDI_SUCCESS
) {
774 hdlp
->ih_state
= DDI_IHDL_STATE_ENABLE
;
775 i_ddi_intr_set_current_nenables(hdlp
->ih_dip
,
776 i_ddi_intr_get_current_nenables(hdlp
->ih_dip
) + 1);
779 rw_exit(&hdlp
->ih_rwlock
);
784 ddi_intr_disable(ddi_intr_handle_t h
)
786 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
789 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_disable: hdlp = %p\n",
795 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
796 if ((hdlp
->ih_state
!= DDI_IHDL_STATE_ENABLE
) ||
797 ((hdlp
->ih_type
== DDI_INTR_TYPE_MSI
) &&
798 (hdlp
->ih_cap
& DDI_INTR_FLAG_BLOCK
))) {
799 rw_exit(&hdlp
->ih_rwlock
);
803 I_DDI_VERIFY_MSIX_HANDLE(hdlp
);
805 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
806 DDI_INTROP_DISABLE
, hdlp
, NULL
);
808 if (ret
== DDI_SUCCESS
) {
809 hdlp
->ih_state
= DDI_IHDL_STATE_ADDED
;
810 i_ddi_intr_set_current_nenables(hdlp
->ih_dip
,
811 i_ddi_intr_get_current_nenables(hdlp
->ih_dip
) - 1);
814 rw_exit(&hdlp
->ih_rwlock
);
819 ddi_intr_block_enable(ddi_intr_handle_t
*h_array
, int count
)
821 ddi_intr_handle_impl_t
*hdlp
;
824 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_block_enable: h_array = %p\n",
830 for (i
= 0; i
< count
; i
++) {
831 hdlp
= (ddi_intr_handle_impl_t
*)h_array
[i
];
832 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
834 if (hdlp
->ih_state
!= DDI_IHDL_STATE_ADDED
||
835 hdlp
->ih_type
!= DDI_INTR_TYPE_MSI
||
836 !(hdlp
->ih_cap
& DDI_INTR_FLAG_BLOCK
)) {
837 rw_exit(&hdlp
->ih_rwlock
);
840 rw_exit(&hdlp
->ih_rwlock
);
843 hdlp
= (ddi_intr_handle_impl_t
*)h_array
[0];
844 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
845 hdlp
->ih_scratch1
= count
;
846 hdlp
->ih_scratch2
= (void *)h_array
;
848 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
849 DDI_INTROP_BLOCKENABLE
, hdlp
, NULL
);
851 rw_exit(&hdlp
->ih_rwlock
);
853 if (ret
== DDI_SUCCESS
) {
854 for (i
= 0; i
< count
; i
++) {
855 hdlp
= (ddi_intr_handle_impl_t
*)h_array
[i
];
856 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
857 hdlp
->ih_state
= DDI_IHDL_STATE_ENABLE
;
858 rw_exit(&hdlp
->ih_rwlock
);
860 i_ddi_intr_set_current_nenables(hdlp
->ih_dip
, 1);
867 ddi_intr_block_disable(ddi_intr_handle_t
*h_array
, int count
)
869 ddi_intr_handle_impl_t
*hdlp
;
872 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_block_disable: h_array = %p\n",
878 for (i
= 0; i
< count
; i
++) {
879 hdlp
= (ddi_intr_handle_impl_t
*)h_array
[i
];
880 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
881 if (hdlp
->ih_state
!= DDI_IHDL_STATE_ENABLE
||
882 hdlp
->ih_type
!= DDI_INTR_TYPE_MSI
||
883 !(hdlp
->ih_cap
& DDI_INTR_FLAG_BLOCK
)) {
884 rw_exit(&hdlp
->ih_rwlock
);
887 rw_exit(&hdlp
->ih_rwlock
);
890 hdlp
= (ddi_intr_handle_impl_t
*)h_array
[0];
891 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
892 hdlp
->ih_scratch1
= count
;
893 hdlp
->ih_scratch2
= (void *)h_array
;
895 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
896 DDI_INTROP_BLOCKDISABLE
, hdlp
, NULL
);
898 rw_exit(&hdlp
->ih_rwlock
);
900 if (ret
== DDI_SUCCESS
) {
901 for (i
= 0; i
< count
; i
++) {
902 hdlp
= (ddi_intr_handle_impl_t
*)h_array
[i
];
903 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
904 hdlp
->ih_state
= DDI_IHDL_STATE_ADDED
;
905 rw_exit(&hdlp
->ih_rwlock
);
907 i_ddi_intr_set_current_nenables(hdlp
->ih_dip
, 0);
914 * Interrupt set/clr mask handlers
917 ddi_intr_set_mask(ddi_intr_handle_t h
)
919 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
922 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_mask: hdlp = %p\n",
928 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
929 if ((hdlp
->ih_state
!= DDI_IHDL_STATE_ENABLE
) ||
930 (!(hdlp
->ih_cap
& DDI_INTR_FLAG_MASKABLE
))) {
931 rw_exit(&hdlp
->ih_rwlock
);
935 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
936 DDI_INTROP_SETMASK
, hdlp
, NULL
);
938 rw_exit(&hdlp
->ih_rwlock
);
943 ddi_intr_clr_mask(ddi_intr_handle_t h
)
945 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
948 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_clr_mask: hdlp = %p\n",
954 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
955 if ((hdlp
->ih_state
!= DDI_IHDL_STATE_ENABLE
) ||
956 (!(hdlp
->ih_cap
& DDI_INTR_FLAG_MASKABLE
))) {
957 rw_exit(&hdlp
->ih_rwlock
);
961 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
962 DDI_INTROP_CLRMASK
, hdlp
, NULL
);
964 rw_exit(&hdlp
->ih_rwlock
);
969 * Interrupt get_pending handler
972 ddi_intr_get_pending(ddi_intr_handle_t h
, int *pendingp
)
974 ddi_intr_handle_impl_t
*hdlp
= (ddi_intr_handle_impl_t
*)h
;
977 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_pending: hdlp = %p\n",
983 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
984 if (!(hdlp
->ih_cap
& DDI_INTR_FLAG_PENDING
)) {
985 rw_exit(&hdlp
->ih_rwlock
);
989 ret
= i_ddi_intr_ops(hdlp
->ih_dip
, hdlp
->ih_dip
,
990 DDI_INTROP_GETPENDING
, hdlp
, (void *)pendingp
);
992 rw_exit(&hdlp
->ih_rwlock
);
997 * Set the number of interrupts requested from IRM
1000 ddi_intr_set_nreq(dev_info_t
*dip
, int nreq
)
1002 int curr_type
, nintrs
;
1004 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_nreq: dip %p, nreq %d\n",
1005 (void *)dip
, nreq
));
1007 ASSERT(dip
!= NULL
);
1010 /* Sanity check inputs */
1011 if ((dip
== NULL
) || (nreq
< 1))
1012 return (DDI_EINVAL
);
1014 curr_type
= i_ddi_intr_get_current_type(dip
);
1016 /* Only valid for IRM drivers actively using interrupts */
1017 if ((curr_type
== 0) ||
1018 (i_ddi_irm_supported(dip
, curr_type
) != DDI_SUCCESS
))
1019 return (DDI_ENOTSUP
);
1022 if (ddi_intr_get_nintrs(dip
, curr_type
, &nintrs
) != DDI_SUCCESS
)
1023 return (DDI_FAILURE
);
1025 return (DDI_EINVAL
);
1027 return (i_ddi_irm_modify(dip
, nreq
));
1031 * Soft interrupt handlers
1034 * Add a soft interrupt and register its handler
1038 ddi_intr_add_softint(dev_info_t
*dip
, ddi_softint_handle_t
*h_p
, int soft_pri
,
1039 ddi_intr_handler_t handler
, void *arg1
)
1041 ddi_softint_hdl_impl_t
*hdlp
;
1044 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_add_softint: dip = %p, "
1045 "softpri = 0x%x\n", (void *)dip
, soft_pri
));
1047 if ((dip
== NULL
) || (h_p
== NULL
) || (handler
== NULL
)) {
1048 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_add_softint: "
1049 "invalid arguments"));
1051 return (DDI_EINVAL
);
1054 /* Validate input arguments */
1055 if (soft_pri
< DDI_INTR_SOFTPRI_MIN
||
1056 soft_pri
> DDI_INTR_SOFTPRI_MAX
) {
1057 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_add_softint: invalid "
1058 "soft_pri input given = %x\n", soft_pri
));
1059 return (DDI_EINVAL
);
1062 hdlp
= (ddi_softint_hdl_impl_t
*)kmem_zalloc(
1063 sizeof (ddi_softint_hdl_impl_t
), KM_SLEEP
);
1065 /* fill up internally */
1066 rw_init(&hdlp
->ih_rwlock
, NULL
, RW_DRIVER
, NULL
);
1067 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
1068 hdlp
->ih_pri
= soft_pri
;
1070 hdlp
->ih_cb_func
= handler
;
1071 hdlp
->ih_cb_arg1
= arg1
;
1072 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_add_softint: hdlp = %p\n",
1075 /* do the platform specific calls */
1076 if ((ret
= i_ddi_add_softint(hdlp
)) != DDI_SUCCESS
) {
1077 rw_exit(&hdlp
->ih_rwlock
);
1078 rw_destroy(&hdlp
->ih_rwlock
);
1079 kmem_free(hdlp
, sizeof (ddi_softint_hdl_impl_t
));
1083 *h_p
= (ddi_softint_handle_t
)hdlp
;
1084 rw_exit(&hdlp
->ih_rwlock
);
1089 * Remove the soft interrupt
1092 ddi_intr_remove_softint(ddi_softint_handle_t h
)
1094 ddi_softint_hdl_impl_t
*hdlp
= (ddi_softint_hdl_impl_t
*)h
;
1096 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_remove_softint: hdlp = %p\n",
1100 return (DDI_EINVAL
);
1102 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
1103 i_ddi_remove_softint(hdlp
);
1104 rw_exit(&hdlp
->ih_rwlock
);
1105 rw_destroy(&hdlp
->ih_rwlock
);
1107 /* kmem_free the hdl impl_t structure allocated earlier */
1108 kmem_free(hdlp
, sizeof (ddi_softint_hdl_impl_t
));
1109 return (DDI_SUCCESS
);
1113 * Trigger a soft interrupt
1116 ddi_intr_trigger_softint(ddi_softint_handle_t h
, void *arg2
)
1118 ddi_softint_hdl_impl_t
*hdlp
= (ddi_softint_hdl_impl_t
*)h
;
1122 return (DDI_EINVAL
);
1124 if ((ret
= i_ddi_trigger_softint(hdlp
, arg2
)) != DDI_SUCCESS
) {
1125 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_trigger_softint: failed, "
1126 " ret 0%x\n", ret
));
1131 hdlp
->ih_cb_arg2
= arg2
;
1132 return (DDI_SUCCESS
);
1136 * Get the soft interrupt priority
1139 ddi_intr_get_softint_pri(ddi_softint_handle_t h
, uint_t
*soft_prip
)
1141 ddi_softint_hdl_impl_t
*hdlp
= (ddi_softint_hdl_impl_t
*)h
;
1143 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_get_softint_pri: h = %p\n",
1147 return (DDI_EINVAL
);
1149 rw_enter(&hdlp
->ih_rwlock
, RW_READER
);
1150 *soft_prip
= hdlp
->ih_pri
;
1151 rw_exit(&hdlp
->ih_rwlock
);
1152 return (DDI_SUCCESS
);
1156 * Set the soft interrupt priority
1159 ddi_intr_set_softint_pri(ddi_softint_handle_t h
, uint_t soft_pri
)
1161 ddi_softint_hdl_impl_t
*hdlp
= (ddi_softint_hdl_impl_t
*)h
;
1163 uint_t orig_soft_pri
;
1165 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_softint_pri: h = %p\n",
1169 return (DDI_EINVAL
);
1171 /* Validate priority argument */
1172 if (soft_pri
< DDI_INTR_SOFTPRI_MIN
||
1173 soft_pri
> DDI_INTR_SOFTPRI_MAX
) {
1174 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_softint_pri: invalid "
1175 "soft_pri input given = %x\n", soft_pri
));
1176 return (DDI_EINVAL
);
1179 rw_enter(&hdlp
->ih_rwlock
, RW_WRITER
);
1180 orig_soft_pri
= hdlp
->ih_pri
;
1181 hdlp
->ih_pri
= soft_pri
;
1183 if ((ret
= i_ddi_set_softint_pri(hdlp
, orig_soft_pri
)) != DDI_SUCCESS
) {
1184 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_set_softint_pri: failed, "
1185 " ret 0%x\n", ret
));
1186 hdlp
->ih_pri
= orig_soft_pri
;
1189 rw_exit(&hdlp
->ih_rwlock
);
1194 * Old DDI interrupt framework
1196 * The following DDI interrupt interfaces are obsolete.
1197 * Use the above new DDI interrupt interfaces instead.
1201 ddi_intr_hilevel(dev_info_t
*dip
, uint_t inumber
)
1203 ddi_intr_handle_t hdl
;
1204 ddi_intr_handle_t
*hdl_p
;
1207 uint_t high_pri
, pri
;
1209 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_hilevel: name=%s%d dip=0x%p "
1210 "inum=0x%x\n", ddi_driver_name(dip
), ddi_get_instance(dip
),
1211 (void *)dip
, inumber
));
1214 * The device driver may have already registed with the
1215 * framework. If so, first try to get the existing interrupt handle
1216 * for that given inumber and use that handle.
1218 if ((hdl
= i_ddi_get_intr_handle(dip
, inumber
)) == NULL
) {
1219 hdl_sz
= sizeof (ddi_intr_handle_t
) * (inumber
+ 1);
1220 hdl_p
= kmem_zalloc(hdl_sz
, KM_SLEEP
);
1221 if ((ret
= ddi_intr_alloc(dip
, hdl_p
, DDI_INTR_TYPE_FIXED
,
1222 inumber
, 1, &actual
,
1223 DDI_INTR_ALLOC_NORMAL
)) != DDI_SUCCESS
) {
1224 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_hilevel: "
1225 "ddi_intr_alloc failed, ret 0x%x\n", ret
));
1226 kmem_free(hdl_p
, hdl_sz
);
1229 hdl
= hdl_p
[inumber
];
1232 if ((ret
= ddi_intr_get_pri(hdl
, &pri
)) != DDI_SUCCESS
) {
1233 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_hilevel: "
1234 "ddi_intr_get_pri failed, ret 0x%x\n", ret
));
1235 (void) ddi_intr_free(hdl
);
1237 kmem_free(hdl_p
, hdl_sz
);
1241 high_pri
= ddi_intr_get_hilevel_pri();
1243 DDI_INTR_APIDBG((CE_CONT
, "ddi_intr_hilevel: pri = %x, "
1244 "high_pri = %x\n", pri
, high_pri
));
1246 /* Free the handle allocated here only if no existing handle exists */
1248 (void) ddi_intr_free(hdl
);
1249 kmem_free(hdl_p
, hdl_sz
);
1252 return (pri
>= high_pri
);
1256 ddi_dev_nintrs(dev_info_t
*dip
, int *result
)
1258 DDI_INTR_APIDBG((CE_CONT
, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
1259 ddi_driver_name(dip
), ddi_get_instance(dip
), (void *)dip
));
1261 if (ddi_intr_get_nintrs(dip
, DDI_INTR_TYPE_FIXED
,
1262 result
) != DDI_SUCCESS
) {
1263 DDI_INTR_APIDBG((CE_CONT
, "ddi_dev_nintrs: "
1264 "ddi_intr_get_nintrs failed\n"));
1268 return (DDI_SUCCESS
);
1272 ddi_get_iblock_cookie(dev_info_t
*dip
, uint_t inumber
,
1273 ddi_iblock_cookie_t
*iblock_cookiep
)
1275 ddi_intr_handle_t hdl
;
1276 ddi_intr_handle_t
*hdl_p
;
1281 DDI_INTR_APIDBG((CE_CONT
, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
1282 "inum=0x%x\n", ddi_driver_name(dip
), ddi_get_instance(dip
),
1283 (void *)dip
, inumber
));
1285 ASSERT(iblock_cookiep
!= NULL
);
1288 * The device driver may have already registed with the
1289 * framework. If so, first try to get the existing interrupt handle
1290 * for that given inumber and use that handle.
1292 if ((hdl
= i_ddi_get_intr_handle(dip
, inumber
)) == NULL
) {
1293 hdl_sz
= sizeof (ddi_intr_handle_t
) * (inumber
+ 1);
1294 hdl_p
= kmem_zalloc(hdl_sz
, KM_SLEEP
);
1295 if ((ret
= ddi_intr_alloc(dip
, hdl_p
,
1296 DDI_INTR_TYPE_FIXED
, inumber
, 1, &actual
,
1297 DDI_INTR_ALLOC_NORMAL
)) != DDI_SUCCESS
) {
1298 DDI_INTR_APIDBG((CE_CONT
, "ddi_get_iblock_cookie: "
1299 "ddi_intr_alloc failed, ret 0x%x\n", ret
));
1300 kmem_free(hdl_p
, hdl_sz
);
1301 return (DDI_INTR_NOTFOUND
);
1303 hdl
= hdl_p
[inumber
];
1306 if ((ret
= ddi_intr_get_pri(hdl
, &pri
)) != DDI_SUCCESS
) {
1307 DDI_INTR_APIDBG((CE_CONT
, "ddi_get_iblock_cookie: "
1308 "ddi_intr_get_pri failed, ret 0x%x\n", ret
));
1309 (void) ddi_intr_free(hdl
);
1311 kmem_free(hdl_p
, hdl_sz
);
1312 return (DDI_FAILURE
);
1315 *iblock_cookiep
= (ddi_iblock_cookie_t
)(uintptr_t)pri
;
1316 /* Free the handle allocated here only if no existing handle exists */
1318 (void) ddi_intr_free(hdl
);
1319 kmem_free(hdl_p
, hdl_sz
);
1322 return (DDI_SUCCESS
);
1326 ddi_add_intr(dev_info_t
*dip
, uint_t inumber
,
1327 ddi_iblock_cookie_t
*iblock_cookiep
,
1328 ddi_idevice_cookie_t
*idevice_cookiep
,
1329 uint_t (*int_handler
)(caddr_t int_handler_arg
),
1330 caddr_t int_handler_arg
)
1332 ddi_intr_handle_t
*hdl_p
;
1337 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_intr: name=%s%d dip=0x%p "
1338 "inum=0x%x\n", ddi_driver_name(dip
), ddi_get_instance(dip
),
1339 (void *)dip
, inumber
));
1341 hdl_sz
= sizeof (ddi_intr_handle_t
) * (inumber
+ 1);
1342 hdl_p
= kmem_zalloc(hdl_sz
, KM_SLEEP
);
1344 if ((ret
= ddi_intr_alloc(dip
, hdl_p
, DDI_INTR_TYPE_FIXED
,
1345 inumber
, 1, &actual
, DDI_INTR_ALLOC_NORMAL
)) != DDI_SUCCESS
) {
1346 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_intr: "
1347 "ddi_intr_alloc failed, ret 0x%x\n", ret
));
1348 kmem_free(hdl_p
, hdl_sz
);
1349 return (DDI_INTR_NOTFOUND
);
1352 if ((ret
= ddi_intr_get_pri(hdl_p
[inumber
], &pri
)) != DDI_SUCCESS
) {
1353 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_intr: "
1354 "ddi_intr_get_pri failed, ret 0x%x\n", ret
));
1355 (void) ddi_intr_free(hdl_p
[inumber
]);
1356 kmem_free(hdl_p
, hdl_sz
);
1357 return (DDI_FAILURE
);
1360 if ((ret
= ddi_intr_add_handler(hdl_p
[inumber
], (ddi_intr_handler_t
*)
1361 int_handler
, int_handler_arg
, NULL
)) != DDI_SUCCESS
) {
1362 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_intr: "
1363 "ddi_intr_add_handler failed, ret 0x%x\n", ret
));
1364 (void) ddi_intr_free(hdl_p
[inumber
]);
1365 kmem_free(hdl_p
, hdl_sz
);
1366 return (DDI_FAILURE
);
1369 if ((ret
= ddi_intr_enable(hdl_p
[inumber
])) != DDI_SUCCESS
) {
1370 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_intr: "
1371 "ddi_intr_enable failed, ret 0x%x\n", ret
));
1372 (void) ddi_intr_remove_handler(hdl_p
[inumber
]);
1373 (void) ddi_intr_free(hdl_p
[inumber
]);
1374 kmem_free(hdl_p
, hdl_sz
);
1375 return (DDI_FAILURE
);
1379 *iblock_cookiep
= (ddi_iblock_cookie_t
)(uintptr_t)pri
;
1381 if (idevice_cookiep
) {
1382 idevice_cookiep
->idev_vector
= 0;
1383 idevice_cookiep
->idev_priority
= pri
;
1386 kmem_free(hdl_p
, hdl_sz
);
1388 return (DDI_SUCCESS
);
1393 ddi_add_fastintr(dev_info_t
*dip
, uint_t inumber
,
1394 ddi_iblock_cookie_t
*iblock_cookiep
,
1395 ddi_idevice_cookie_t
*idevice_cookiep
,
1396 uint_t (*hi_int_handler
)(void))
1398 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_fastintr: name=%s%d dip=0x%p "
1399 "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip
),
1400 ddi_get_instance(dip
), (void *)dip
, inumber
));
1402 return (DDI_FAILURE
);
1407 ddi_remove_intr(dev_info_t
*dip
, uint_t inum
, ddi_iblock_cookie_t iblock_cookie
)
1409 ddi_intr_handle_t hdl
;
1412 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_intr: name=%s%d dip=0x%p "
1413 "inum=0x%x\n", ddi_driver_name(dip
), ddi_get_instance(dip
),
1414 (void *)dip
, inum
));
1416 if ((hdl
= i_ddi_get_intr_handle(dip
, inum
)) == NULL
) {
1417 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_intr: no handle "
1422 if ((ret
= ddi_intr_disable(hdl
)) != DDI_SUCCESS
) {
1423 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_intr: "
1424 "ddi_intr_disable failed, ret 0x%x\n", ret
));
1428 if ((ret
= ddi_intr_remove_handler(hdl
)) != DDI_SUCCESS
) {
1429 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_intr: "
1430 "ddi_intr_remove_handler failed, ret 0x%x\n", ret
));
1434 if ((ret
= ddi_intr_free(hdl
)) != DDI_SUCCESS
) {
1435 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_intr: "
1436 "ddi_intr_free failed, ret 0x%x\n", ret
));
1443 ddi_get_soft_iblock_cookie(dev_info_t
*dip
, int preference
,
1444 ddi_iblock_cookie_t
*iblock_cookiep
)
1446 DDI_INTR_APIDBG((CE_CONT
, "ddi_get_soft_iblock_cookie: name=%s%d "
1447 "dip=0x%p pref=0x%x\n", ddi_driver_name(dip
), ddi_get_instance(dip
),
1448 (void *)dip
, preference
));
1450 ASSERT(iblock_cookiep
!= NULL
);
1452 if (preference
== DDI_SOFTINT_FIXED
)
1453 return (DDI_FAILURE
);
1455 *iblock_cookiep
= (ddi_iblock_cookie_t
)((uintptr_t)
1456 ((preference
> DDI_SOFTINT_MED
) ? DDI_SOFT_INTR_PRI_H
:
1457 DDI_SOFT_INTR_PRI_M
));
1459 return (DDI_SUCCESS
);
1463 ddi_add_softintr(dev_info_t
*dip
, int preference
, ddi_softintr_t
*idp
,
1464 ddi_iblock_cookie_t
*iblock_cookiep
,
1465 ddi_idevice_cookie_t
*idevice_cookiep
,
1466 uint_t (*int_handler
)(caddr_t int_handler_arg
),
1467 caddr_t int_handler_arg
)
1469 ddi_softint_handle_t
*hdl_p
;
1473 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_softintr: name=%s%d dip=0x%p "
1474 "pref=0x%x\n", ddi_driver_name(dip
), ddi_get_instance(dip
),
1475 (void *)dip
, preference
));
1477 if ((idp
== NULL
) || ((preference
== DDI_SOFTINT_FIXED
) &&
1478 (iblock_cookiep
== NULL
)))
1479 return (DDI_FAILURE
);
1481 /* Translate the priority preference */
1482 if (preference
== DDI_SOFTINT_FIXED
) {
1483 softpri
= (uint64_t)(uintptr_t)*iblock_cookiep
;
1484 softpri
= MIN(softpri
, DDI_SOFT_INTR_PRI_H
);
1486 softpri
= (uint64_t)((preference
> DDI_SOFTINT_MED
) ?
1487 DDI_SOFT_INTR_PRI_H
: DDI_SOFT_INTR_PRI_M
);
1490 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_softintr: preference 0x%x "
1491 "softpri 0x%lx\n", preference
, (long)softpri
));
1493 hdl_p
= kmem_zalloc(sizeof (ddi_softint_handle_t
), KM_SLEEP
);
1494 if ((ret
= ddi_intr_add_softint(dip
, hdl_p
, softpri
,
1495 (ddi_intr_handler_t
*)int_handler
, int_handler_arg
)) !=
1497 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_softintr: "
1498 "ddi_intr_add_softint failed, ret 0x%x\n", ret
));
1500 kmem_free(hdl_p
, sizeof (ddi_softint_handle_t
));
1501 return (DDI_FAILURE
);
1505 *iblock_cookiep
= (ddi_iblock_cookie_t
)(uintptr_t)softpri
;
1507 if (idevice_cookiep
) {
1508 idevice_cookiep
->idev_vector
= 0;
1509 idevice_cookiep
->idev_priority
= softpri
;
1512 *idp
= (ddi_softintr_t
)hdl_p
;
1514 DDI_INTR_APIDBG((CE_CONT
, "ddi_add_softintr: dip = 0x%p, "
1515 "idp = 0x%p, ret = %x\n", (void *)dip
, (void *)*idp
, ret
));
1517 return (DDI_SUCCESS
);
1521 ddi_remove_softintr(ddi_softintr_t id
)
1523 ddi_softint_handle_t
*h_p
= (ddi_softint_handle_t
*)id
;
1525 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_softintr: id=0x%p\n",
1531 DDI_INTR_APIDBG((CE_CONT
, "ddi_remove_softintr: handle 0x%p\n",
1534 (void) ddi_intr_remove_softint(*h_p
);
1535 kmem_free(h_p
, sizeof (ddi_softint_handle_t
));
1539 ddi_trigger_softintr(ddi_softintr_t id
)
1541 ddi_softint_handle_t
*h_p
= (ddi_softint_handle_t
*)id
;
1547 if ((ret
= ddi_intr_trigger_softint(*h_p
, NULL
)) != DDI_SUCCESS
) {
1548 DDI_INTR_APIDBG((CE_CONT
, "ddi_trigger_softintr: "
1549 "ddi_intr_trigger_softint failed, hdlp 0x%p "
1550 "ret 0x%x\n", (void *)h_p
, ret
));