Home | History | Annotate | Download | only in px
      1 /*
      2  * CDDL HEADER START
      3  *
      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.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * PX nexus interrupt handling:
     28  *	PX device interrupt handler wrapper
     29  *	PIL lookup routine
     30  *	PX device interrupt related initchild code
     31  */
     32 
     33 #include <sys/types.h>
     34 #include <sys/kmem.h>
     35 #include <sys/async.h>
     36 #include <sys/spl.h>
     37 #include <sys/sunddi.h>
     38 #include <sys/fm/protocol.h>
     39 #include <sys/fm/util.h>
     40 #include <sys/machsystm.h>	/* e_ddi_nodeid_to_dip() */
     41 #include <sys/ddi_impldefs.h>
     42 #include <sys/sdt.h>
     43 #include <sys/atomic.h>
     44 #include "px_obj.h"
     45 #include <sys/ontrap.h>
     46 #include <sys/membar.h>
     47 #include <sys/clock.h>
     48 
     49 /*
     50  * interrupt jabber:
     51  *
     52  * When an interrupt line is jabbering, every time the state machine for the
     53  * associated ino is idled, a new mondo will be sent and the ino will go into
     54  * the pending state again. The mondo will cause a new call to
     55  * px_intr_wrapper() which normally idles the ino's state machine which would
     56  * precipitate another trip round the loop.
     57  *
     58  * The loop can be broken by preventing the ino's state machine from being
     59  * idled when an interrupt line is jabbering. See the comment at the
     60  * beginning of px_intr_wrapper() explaining how the 'interrupt jabber
     61  * protection' code does this.
     62  */
     63 
     64 /*LINTLIBRARY*/
     65 
     66 /*
     67  * If the unclaimed interrupt count has reached the limit set by
     68  * pci_unclaimed_intr_max within the time limit, then all interrupts
     69  * on this ino is blocked by not idling the interrupt state machine.
     70  */
     71 static int
     72 px_spurintr(px_ino_pil_t *ipil_p)
     73 {
     74 	px_ino_t	*ino_p = ipil_p->ipil_ino_p;
     75 	px_ih_t		*ih_p;
     76 	px_t		*px_p = ino_p->ino_ib_p->ib_px_p;
     77 	char		*err_fmt_str;
     78 	boolean_t	blocked = B_FALSE;
     79 	int		i;
     80 
     81 	if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max)
     82 		return (DDI_INTR_CLAIMED);
     83 
     84 	if (!ino_p->ino_unclaimed_intrs)
     85 		ino_p->ino_spurintr_begin = ddi_get_lbolt();
     86 
     87 	ino_p->ino_unclaimed_intrs++;
     88 
     89 	if (ino_p->ino_unclaimed_intrs <= px_unclaimed_intr_max)
     90 		goto clear;
     91 
     92 	if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin)
     93 	    > px_spurintr_duration) {
     94 		ino_p->ino_unclaimed_intrs = 0;
     95 		goto clear;
     96 	}
     97 	err_fmt_str = "%s%d: ino 0x%x blocked";
     98 	blocked = B_TRUE;
     99 	goto warn;
    100 clear:
    101 	err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x";
    102 warn:
    103 	cmn_err(CE_WARN, err_fmt_str, NAMEINST(px_p->px_dip), ino_p->ino_ino);
    104 	for (ipil_p = ino_p->ino_ipil_p; ipil_p;
    105 	    ipil_p = ipil_p->ipil_next_p) {
    106 		for (i = 0, ih_p = ipil_p->ipil_ih_start;
    107 		    i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next)
    108 			cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip),
    109 			    ih_p->ih_inum);
    110 	}
    111 	cmn_err(CE_CONT, "!\n");
    112 
    113 	/* Clear the pending state */
    114 	if (blocked == B_FALSE) {
    115 		if (px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino,
    116 		    INTR_IDLE_STATE) != DDI_SUCCESS)
    117 			return (DDI_INTR_UNCLAIMED);
    118 	}
    119 
    120 	return (DDI_INTR_CLAIMED);
    121 }
    122 
    123 extern uint64_t intr_get_time(void);
    124 
    125 /*
    126  * px_intx_intr (INTx or legacy interrupt handler)
    127  *
    128  * This routine is used as wrapper around interrupt handlers installed by child
    129  * device drivers.  This routine invokes the driver interrupt handlers and
    130  * examines the return codes.
    131  *
    132  * There is a count of unclaimed interrupts kept on a per-ino basis. If at
    133  * least one handler claims the interrupt then the counter is halved and the
    134  * interrupt state machine is idled. If no handler claims the interrupt then
    135  * the counter is incremented by one and the state machine is idled.
    136  * If the count ever reaches the limit value set by pci_unclaimed_intr_max
    137  * then the interrupt state machine is not idled thus preventing any further
    138  * interrupts on that ino. The state machine will only be idled again if a
    139  * handler is subsequently added or removed.
    140  *
    141  * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt,
    142  * DDI_INTR_UNCLAIMED otherwise.
    143  */
    144 uint_t
    145 px_intx_intr(caddr_t arg)
    146 {
    147 	px_ino_pil_t	*ipil_p = (px_ino_pil_t *)arg;
    148 	px_ino_t	*ino_p = ipil_p->ipil_ino_p;
    149 	px_t		*px_p = ino_p->ino_ib_p->ib_px_p;
    150 	px_ih_t		*ih_p = ipil_p->ipil_ih_start;
    151 	ushort_t	pil = ipil_p->ipil_pil;
    152 	uint_t		result = 0, r = DDI_INTR_UNCLAIMED;
    153 	int		i;
    154 
    155 	DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:"
    156 	    "ino=%x sysino=%llx pil=%x ih_size=%x ih_lst=%x\n",
    157 	    ino_p->ino_ino, ino_p->ino_sysino, ipil_p->ipil_pil,
    158 	    ipil_p->ipil_ih_size, ipil_p->ipil_ih_head);
    159 
    160 	for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) {
    161 		dev_info_t *dip = ih_p->ih_dip;
    162 		uint_t (*handler)() = ih_p->ih_handler;
    163 		caddr_t arg1 = ih_p->ih_handler_arg1;
    164 		caddr_t arg2 = ih_p->ih_handler_arg2;
    165 
    166 		if (ih_p->ih_intr_state == PX_INTR_STATE_DISABLE) {
    167 			DBG(DBG_INTX_INTR, px_p->px_dip,
    168 			    "px_intx_intr: %s%d interrupt %d is disabled\n",
    169 			    ddi_driver_name(dip), ddi_get_instance(dip),
    170 			    ino_p->ino_ino);
    171 
    172 			continue;
    173 		}
    174 
    175 		DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:"
    176 		    "ino=%x handler=%p arg1 =%p arg2 = %p\n",
    177 		    ino_p->ino_ino, handler, arg1, arg2);
    178 
    179 		DTRACE_PROBE4(interrupt__start, dev_info_t, dip,
    180 		    void *, handler, caddr_t, arg1, caddr_t, arg2);
    181 
    182 		r = (*handler)(arg1, arg2);
    183 
    184 		/*
    185 		 * Account for time used by this interrupt. Protect against
    186 		 * conflicting writes to ih_ticks from ib_intr_dist_all() by
    187 		 * using atomic ops.
    188 		 */
    189 
    190 		if (pil <= LOCK_LEVEL)
    191 			atomic_add_64(&ih_p->ih_ticks, intr_get_time());
    192 
    193 		DTRACE_PROBE4(interrupt__complete, dev_info_t, dip,
    194 		    void *, handler, caddr_t, arg1, int, r);
    195 
    196 		result += r;
    197 
    198 		if (px_check_all_handlers)
    199 			continue;
    200 		if (result)
    201 			break;
    202 	}
    203 
    204 	if (result)
    205 		ino_p->ino_claimed |= (1 << pil);
    206 
    207 	/* Interrupt can only be cleared after all pil levels are handled */
    208 	if (pil != ino_p->ino_lopil)
    209 		return (DDI_INTR_CLAIMED);
    210 
    211 	if (!ino_p->ino_claimed) {
    212 		if (px_unclaimed_intr_block)
    213 			return (px_spurintr(ipil_p));
    214 	}
    215 
    216 	ino_p->ino_unclaimed_intrs = 0;
    217 	ino_p->ino_claimed = 0;
    218 
    219 	/* Clear the pending state */
    220 	if (px_lib_intr_setstate(px_p->px_dip,
    221 	    ino_p->ino_sysino, INTR_IDLE_STATE) != DDI_SUCCESS)
    222 		return (DDI_INTR_UNCLAIMED);
    223 
    224 	return (DDI_INTR_CLAIMED);
    225 }
    226 
    227 /*
    228  * px_msiq_intr (MSI/X or PCIe MSG interrupt handler)
    229  *
    230  * This routine is used as wrapper around interrupt handlers installed by child
    231  * device drivers.  This routine invokes the driver interrupt handlers and
    232  * examines the return codes.
    233  *
    234  * There is a count of unclaimed interrupts kept on a per-ino basis. If at
    235  * least one handler claims the interrupt then the counter is halved and the
    236  * interrupt state machine is idled. If no handler claims the interrupt then
    237  * the counter is incremented by one and the state machine is idled.
    238  * If the count ever reaches the limit value set by pci_unclaimed_intr_max
    239  * then the interrupt state machine is not idled thus preventing any further
    240  * interrupts on that ino. The state machine will only be idled again if a
    241  * handler is subsequently added or removed.
    242  *
    243  * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt,
    244  * DDI_INTR_UNCLAIMED otherwise.
    245  */
    246 uint_t
    247 px_msiq_intr(caddr_t arg)
    248 {
    249 	px_ino_pil_t	*ipil_p = (px_ino_pil_t *)arg;
    250 	px_ino_t	*ino_p = ipil_p->ipil_ino_p;
    251 	px_t		*px_p = ino_p->ino_ib_p->ib_px_p;
    252 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
    253 	px_msiq_t	*msiq_p = ino_p->ino_msiq_p;
    254 	dev_info_t	*dip = px_p->px_dip;
    255 	ushort_t	pil = ipil_p->ipil_pil;
    256 	msiq_rec_t	msiq_rec, *msiq_rec_p = &msiq_rec;
    257 	msiqhead_t	*curr_head_p;
    258 	msiqtail_t	curr_tail_index;
    259 	msgcode_t	msg_code;
    260 	px_ih_t		*ih_p;
    261 	uint_t		ret = DDI_INTR_UNCLAIMED;
    262 	int		i, j;
    263 
    264 	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x "
    265 	    "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino,
    266 	    ipil_p->ipil_pil, ipil_p->ipil_ih_size, ipil_p->ipil_ih_head);
    267 
    268 	/*
    269 	 * The px_msiq_intr() handles multiple interrupt priorities and it
    270 	 * will set msiq->msiq_rec2process to the number of MSIQ records to
    271 	 * process while handling the highest priority interrupt. Subsequent
    272 	 * lower priority interrupts will just process any unprocessed MSIQ
    273 	 * records or will just return immediately.
    274 	 */
    275 	if (msiq_p->msiq_recs2process == 0) {
    276 		ASSERT(ino_p->ino_ipil_cntr == 0);
    277 		ino_p->ino_ipil_cntr = ino_p->ino_ipil_size;
    278 
    279 		/* Read current MSIQ tail index */
    280 		px_lib_msiq_gettail(dip, msiq_p->msiq_id, &curr_tail_index);
    281 		msiq_p->msiq_new_head_index = msiq_p->msiq_curr_head_index;
    282 
    283 		if (curr_tail_index < msiq_p->msiq_curr_head_index)
    284 			curr_tail_index += msiq_state_p->msiq_rec_cnt;
    285 
    286 		msiq_p->msiq_recs2process = curr_tail_index -
    287 		    msiq_p->msiq_curr_head_index;
    288 	}
    289 
    290 	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x "
    291 	    "rec2process %x\n", msiq_p->msiq_curr_head_index,
    292 	    msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process);
    293 
    294 	/* If all MSIQ records are already processed, just return immediately */
    295 	if ((msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index)
    296 	    == msiq_p->msiq_recs2process)
    297 		goto intr_done;
    298 
    299 	curr_head_p = (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p +
    300 	    (msiq_p->msiq_curr_head_index * sizeof (msiq_rec_t)));
    301 
    302 	/*
    303 	 * Calculate the number of recs to process by taking the difference
    304 	 * between the head and tail pointers. For all records we always
    305 	 * verify that we have a valid record type before we do any processing.
    306 	 * If triggered, we should always have at least one valid record.
    307 	 */
    308 	for (i = 0; i < msiq_p->msiq_recs2process; i++) {
    309 		msiq_rec_type_t rec_type;
    310 
    311 		/* Read next MSIQ record */
    312 		px_lib_get_msiq_rec(dip, curr_head_p, msiq_rec_p);
    313 
    314 		rec_type = msiq_rec_p->msiq_rec_type;
    315 
    316 		DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, "
    317 		    "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n",
    318 		    rec_type, msiq_rec_p->msiq_rec_rid);
    319 
    320 		if (!rec_type)
    321 			goto next_rec;
    322 
    323 		/* Check MSIQ record type */
    324 		switch (rec_type) {
    325 		case MSG_REC:
    326 			msg_code = msiq_rec_p->msiq_rec_data.msg.msg_code;
    327 			DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: PCIE MSG "
    328 			    "record, msg type 0x%x\n", msg_code);
    329 			break;
    330 		case MSI32_REC:
    331 		case MSI64_REC:
    332 			msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data;
    333 			DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, "
    334 			    "msi 0x%x\n", msg_code);
    335 			break;
    336 		default:
    337 			msg_code = 0;
    338 			cmn_err(CE_WARN, "%s%d: px_msiq_intr: 0x%x MSIQ "
    339 			    "record type is not supported",
    340 			    ddi_driver_name(dip), ddi_get_instance(dip),
    341 			    rec_type);
    342 
    343 			goto next_rec;
    344 		}
    345 
    346 		/*
    347 		 * Scan through px_ih_t linked list, searching for the
    348 		 * right px_ih_t, matching MSIQ record data.
    349 		 */
    350 		for (j = 0, ih_p = ipil_p->ipil_ih_start;
    351 		    ih_p && (j < ipil_p->ipil_ih_size) &&
    352 		    ((ih_p->ih_msg_code != msg_code) ||
    353 		    (ih_p->ih_rec_type != rec_type));
    354 		    ih_p = ih_p->ih_next, j++)
    355 			;
    356 
    357 		if ((ih_p->ih_msg_code == msg_code) &&
    358 		    (ih_p->ih_rec_type == rec_type)) {
    359 			dev_info_t *ih_dip = ih_p->ih_dip;
    360 			uint_t (*handler)() = ih_p->ih_handler;
    361 			caddr_t arg1 = ih_p->ih_handler_arg1;
    362 			caddr_t arg2 = ih_p->ih_handler_arg2;
    363 
    364 			DBG(DBG_MSIQ_INTR, ih_dip, "px_msiq_intr: ino=%x "
    365 			    "data=%x handler=%p arg1 =%p arg2=%p\n",
    366 			    ino_p->ino_ino, msg_code, handler, arg1, arg2);
    367 
    368 			DTRACE_PROBE4(interrupt__start, dev_info_t, ih_dip,
    369 			    void *, handler, caddr_t, arg1, caddr_t, arg2);
    370 
    371 			ih_p->ih_intr_flags = PX_INTR_PENDING;
    372 
    373 			/*
    374 			 * Special case for PCIE Error Messages.
    375 			 * The current frame work doesn't fit PCIE Err Msgs
    376 			 * This should be fixed when PCIE MESSAGES as a whole
    377 			 * is architected correctly.
    378 			 */
    379 			if ((rec_type == MSG_REC) &&
    380 			    ((msg_code == PCIE_MSG_CODE_ERR_COR) ||
    381 			    (msg_code == PCIE_MSG_CODE_ERR_NONFATAL) ||
    382 			    (msg_code == PCIE_MSG_CODE_ERR_FATAL))) {
    383 				ret = px_err_fabric_intr(px_p, msg_code,
    384 				    msiq_rec_p->msiq_rec_rid);
    385 			} else {
    386 				/* Clear MSI state */
    387 				px_lib_msi_setstate(dip, (msinum_t)msg_code,
    388 				    PCI_MSI_STATE_IDLE);
    389 
    390 				ret = (*handler)(arg1, arg2);
    391 			}
    392 
    393 			/*
    394 			 * Account for time used by this interrupt. Protect
    395 			 * against conflicting writes to ih_ticks from
    396 			 * ib_intr_dist_all() by using atomic ops.
    397 			 */
    398 
    399 			if (pil <= LOCK_LEVEL)
    400 				atomic_add_64(&ih_p->ih_ticks, intr_get_time());
    401 
    402 			DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_dip,
    403 			    void *, handler, caddr_t, arg1, int, ret);
    404 
    405 			/* clear handler status flags */
    406 			ih_p->ih_intr_flags = PX_INTR_IDLE;
    407 
    408 			msiq_p->msiq_new_head_index++;
    409 			px_lib_clr_msiq_rec(ih_dip, curr_head_p);
    410 		} else {
    411 			DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: "
    412 			    "No matching MSIQ record found\n");
    413 		}
    414 next_rec:
    415 		/* Get the pointer next EQ record */
    416 		curr_head_p = (msiqhead_t *)
    417 		    ((caddr_t)curr_head_p + sizeof (msiq_rec_t));
    418 
    419 		/* Check for overflow condition */
    420 		if (curr_head_p >= (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p
    421 		    + (msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t))))
    422 			curr_head_p = (msiqhead_t *)msiq_p->msiq_base_p;
    423 	}
    424 
    425 	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n",
    426 	    (msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index));
    427 
    428 	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x "
    429 	    "rec2process %x\n", msiq_p->msiq_curr_head_index,
    430 	    msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process);
    431 
    432 	/* ino_claimed used just for debugging purpose */
    433 	if (ret)
    434 		ino_p->ino_claimed |= (1 << pil);
    435 
    436 intr_done:
    437 	/* Interrupt can only be cleared after all pil levels are handled */
    438 	if (--ino_p->ino_ipil_cntr != 0)
    439 		return (DDI_INTR_CLAIMED);
    440 
    441 	if (msiq_p->msiq_new_head_index <= msiq_p->msiq_curr_head_index)  {
    442 		if (px_unclaimed_intr_block)
    443 			return (px_spurintr(ipil_p));
    444 	}
    445 
    446 	/*  Update MSIQ head index with no of MSIQ records processed */
    447 	if (msiq_p->msiq_new_head_index >= msiq_state_p->msiq_rec_cnt)
    448 		msiq_p->msiq_new_head_index -= msiq_state_p->msiq_rec_cnt;
    449 
    450 	msiq_p->msiq_curr_head_index = msiq_p->msiq_new_head_index;
    451 	px_lib_msiq_sethead(dip, msiq_p->msiq_id, msiq_p->msiq_new_head_index);
    452 
    453 	msiq_p->msiq_new_head_index = 0;
    454 	msiq_p->msiq_recs2process = 0;
    455 	ino_p->ino_claimed = 0;
    456 
    457 	/* Clear the pending state */
    458 	if (px_lib_intr_setstate(dip, ino_p->ino_sysino,
    459 	    INTR_IDLE_STATE) != DDI_SUCCESS)
    460 		return (DDI_INTR_UNCLAIMED);
    461 
    462 	return (DDI_INTR_CLAIMED);
    463 }
    464 
    465 dev_info_t *
    466 px_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
    467 {
    468 	dev_info_t	*cdip = rdip;
    469 
    470 	for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
    471 		;
    472 
    473 	return (cdip);
    474 }
    475 
    476 /* ARGSUSED */
    477 int
    478 px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    479     ddi_intr_handle_impl_t *hdlp, void *result)
    480 {
    481 	px_t	*px_p = DIP_TO_STATE(dip);
    482 	int	ret = DDI_SUCCESS;
    483 
    484 	DBG(DBG_INTROPS, dip, "px_intx_ops: dip=%x rdip=%x intr_op=%x "
    485 	    "handle=%p\n", dip, rdip, intr_op, hdlp);
    486 
    487 	switch (intr_op) {
    488 	case DDI_INTROP_GETCAP:
    489 		ret = pci_intx_get_cap(rdip, (int *)result);
    490 		break;
    491 	case DDI_INTROP_SETCAP:
    492 		DBG(DBG_INTROPS, dip, "px_intx_ops: SetCap is not supported\n");
    493 		ret = DDI_ENOTSUP;
    494 		break;
    495 	case DDI_INTROP_ALLOC:
    496 		*(int *)result = hdlp->ih_scratch1;
    497 		break;
    498 	case DDI_INTROP_FREE:
    499 		break;
    500 	case DDI_INTROP_GETPRI:
    501 		*(int *)result = hdlp->ih_pri ?
    502 		    hdlp->ih_pri : pci_class_to_pil(rdip);
    503 		break;
    504 	case DDI_INTROP_SETPRI:
    505 		break;
    506 	case DDI_INTROP_ADDISR:
    507 		ret = px_add_intx_intr(dip, rdip, hdlp);
    508 		break;
    509 	case DDI_INTROP_REMISR:
    510 		ret = px_rem_intx_intr(dip, rdip, hdlp);
    511 		break;
    512 	case DDI_INTROP_GETTARGET:
    513 		ret = px_ib_get_intr_target(px_p, hdlp->ih_vector,
    514 		    (cpuid_t *)result);
    515 		break;
    516 	case DDI_INTROP_SETTARGET:
    517 		ret = DDI_ENOTSUP;
    518 		break;
    519 	case DDI_INTROP_ENABLE:
    520 		ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum,
    521 		    hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_ENABLE, 0, 0);
    522 		break;
    523 	case DDI_INTROP_DISABLE:
    524 		ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum,
    525 		    hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_DISABLE, 0, 0);
    526 		break;
    527 	case DDI_INTROP_SETMASK:
    528 		ret = pci_intx_set_mask(rdip);
    529 		break;
    530 	case DDI_INTROP_CLRMASK:
    531 		ret = pci_intx_clr_mask(rdip);
    532 		break;
    533 	case DDI_INTROP_GETPENDING:
    534 		ret = pci_intx_get_pending(rdip, (int *)result);
    535 		break;
    536 	case DDI_INTROP_NINTRS:
    537 	case DDI_INTROP_NAVAIL:
    538 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
    539 		break;
    540 	default:
    541 		ret = DDI_ENOTSUP;
    542 		break;
    543 	}
    544 
    545 	return (ret);
    546 }
    547 
    548 /* ARGSUSED */
    549 int
    550 px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    551     ddi_intr_handle_impl_t *hdlp, void *result)
    552 {
    553 	px_t			*px_p = DIP_TO_STATE(dip);
    554 	px_msi_state_t		*msi_state_p = &px_p->px_ib_p->ib_msi_state;
    555 	msiq_rec_type_t		msiq_rec_type;
    556 	msi_type_t		msi_type;
    557 	uint64_t		msi_addr;
    558 	msinum_t		msi_num;
    559 	msiqid_t		msiq_id;
    560 	uint_t			nintrs;
    561 	int			ret = DDI_SUCCESS;
    562 
    563 	DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x "
    564 	    "handle=%p\n", dip, rdip, intr_op, hdlp);
    565 
    566 	/* Check for MSI64 support */
    567 	if ((hdlp->ih_cap & DDI_INTR_FLAG_MSI64) && msi_state_p->msi_addr64) {
    568 		msiq_rec_type = MSI64_REC;
    569 		msi_type = MSI64_TYPE;
    570 		msi_addr = msi_state_p->msi_addr64;
    571 	} else {
    572 		msiq_rec_type = MSI32_REC;
    573 		msi_type = MSI32_TYPE;
    574 		msi_addr = msi_state_p->msi_addr32;
    575 	}
    576 
    577 	(void) px_msi_get_msinum(px_p, hdlp->ih_dip,
    578 	    (hdlp->ih_flags & DDI_INTR_MSIX_DUP) ? hdlp->ih_main->ih_inum :
    579 	    hdlp->ih_inum, &msi_num);
    580 
    581 	switch (intr_op) {
    582 	case DDI_INTROP_GETCAP:
    583 		ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result);
    584 		if (ret == DDI_SUCCESS)
    585 			*(int *)result |= DDI_INTR_FLAG_RETARGETABLE;
    586 		break;
    587 	case DDI_INTROP_SETCAP:
    588 		DBG(DBG_INTROPS, dip, "px_msix_ops: SetCap is not supported\n");
    589 		ret = DDI_ENOTSUP;
    590 		break;
    591 	case DDI_INTROP_ALLOC:
    592 		/*
    593 		 * We need to restrict this allocation in future
    594 		 * based on Resource Management policies.
    595 		 */
    596 		if ((ret = px_msi_alloc(px_p, rdip, hdlp->ih_type,
    597 		    hdlp->ih_inum, hdlp->ih_scratch1,
    598 		    (uintptr_t)hdlp->ih_scratch2,
    599 		    (int *)result)) != DDI_SUCCESS) {
    600 			DBG(DBG_INTROPS, dip, "px_msix_ops: allocation "
    601 			    "failed, rdip 0x%p type 0x%d inum 0x%x "
    602 			    "count 0x%x\n", rdip, hdlp->ih_type, hdlp->ih_inum,
    603 			    hdlp->ih_scratch1);
    604 
    605 			return (ret);
    606 		}
    607 
    608 		if ((hdlp->ih_type == DDI_INTR_TYPE_MSIX) &&
    609 		    (i_ddi_get_msix(rdip) == NULL)) {
    610 			ddi_intr_msix_t		*msix_p;
    611 
    612 			if (msix_p = pci_msix_init(rdip)) {
    613 				i_ddi_set_msix(rdip, msix_p);
    614 				break;
    615 			}
    616 
    617 			DBG(DBG_INTROPS, dip, "px_msix_ops: MSI-X allocation "
    618 			    "failed, rdip 0x%p inum 0x%x\n", rdip,
    619 			    hdlp->ih_inum);
    620 
    621 			(void) px_msi_free(px_p, rdip, hdlp->ih_inum,
    622 			    hdlp->ih_scratch1);
    623 
    624 			return (DDI_FAILURE);
    625 		}
    626 
    627 		break;
    628 	case DDI_INTROP_FREE:
    629 		(void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum);
    630 
    631 		if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
    632 			goto msi_free;
    633 
    634 		if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
    635 			break;
    636 
    637 		if (((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0) &&
    638 		    (i_ddi_get_msix(rdip))) {
    639 			pci_msix_fini(i_ddi_get_msix(rdip));
    640 			i_ddi_set_msix(rdip, NULL);
    641 		}
    642 msi_free:
    643 		(void) px_msi_free(px_p, rdip, hdlp->ih_inum,
    644 		    hdlp->ih_scratch1);
    645 		break;
    646 	case DDI_INTROP_GETPRI:
    647 		*(int *)result = hdlp->ih_pri ?
    648 		    hdlp->ih_pri : pci_class_to_pil(rdip);
    649 		break;
    650 	case DDI_INTROP_SETPRI:
    651 		break;
    652 	case DDI_INTROP_ADDISR:
    653 		if ((ret = px_add_msiq_intr(dip, rdip, hdlp,
    654 		    msiq_rec_type, msi_num, -1, &msiq_id)) != DDI_SUCCESS) {
    655 			DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler "
    656 			    "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num);
    657 			return (ret);
    658 		}
    659 
    660 		DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id);
    661 
    662 		if ((ret = px_lib_msi_setmsiq(dip, msi_num,
    663 		    msiq_id, msi_type)) != DDI_SUCCESS) {
    664 			(void) px_rem_msiq_intr(dip, rdip,
    665 			    hdlp, msiq_rec_type, msi_num, msiq_id);
    666 			return (ret);
    667 		}
    668 
    669 		if ((ret = px_lib_msi_setstate(dip, msi_num,
    670 		    PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) {
    671 			(void) px_rem_msiq_intr(dip, rdip,
    672 			    hdlp, msiq_rec_type, msi_num, msiq_id);
    673 			return (ret);
    674 		}
    675 
    676 		if ((ret = px_lib_msi_setvalid(dip, msi_num,
    677 		    PCI_MSI_VALID)) != DDI_SUCCESS)
    678 			return (ret);
    679 
    680 		ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum,
    681 		    px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri,
    682 		    PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num);
    683 
    684 		break;
    685 	case DDI_INTROP_DUPVEC:
    686 		DBG(DBG_INTROPS, dip, "px_msix_ops: dupisr - inum: %x, "
    687 		    "new_vector: %x\n", hdlp->ih_inum, hdlp->ih_scratch1);
    688 
    689 		ret = pci_msix_dup(hdlp->ih_dip, hdlp->ih_inum,
    690 		    hdlp->ih_scratch1);
    691 		break;
    692 	case DDI_INTROP_REMISR:
    693 		if ((ret = px_lib_msi_getmsiq(dip, msi_num,
    694 		    &msiq_id)) != DDI_SUCCESS)
    695 			return (ret);
    696 
    697 		if ((ret = px_ib_update_intr_state(px_p, rdip,
    698 		    hdlp->ih_inum, px_msiqid_to_devino(px_p, msiq_id),
    699 		    hdlp->ih_pri, PX_INTR_STATE_DISABLE, msiq_rec_type,
    700 		    msi_num)) != DDI_SUCCESS)
    701 			return (ret);
    702 
    703 		if ((ret = px_lib_msi_setvalid(dip, msi_num,
    704 		    PCI_MSI_INVALID)) != DDI_SUCCESS)
    705 			return (ret);
    706 
    707 		if ((ret = px_lib_msi_setstate(dip, msi_num,
    708 		    PCI_MSI_STATE_IDLE)) != DDI_SUCCESS)
    709 			return (ret);
    710 
    711 		ret = px_rem_msiq_intr(dip, rdip,
    712 		    hdlp, msiq_rec_type, msi_num, msiq_id);
    713 
    714 		break;
    715 	case DDI_INTROP_GETTARGET:
    716 		if ((ret = px_lib_msi_getmsiq(dip, msi_num,
    717 		    &msiq_id)) != DDI_SUCCESS)
    718 			return (ret);
    719 
    720 		ret = px_ib_get_intr_target(px_p,
    721 		    px_msiqid_to_devino(px_p, msiq_id), (cpuid_t *)result);
    722 		break;
    723 	case DDI_INTROP_SETTARGET:
    724 		ret = px_ib_set_msix_target(px_p, hdlp, msi_num,
    725 		    *(cpuid_t *)result);
    726 		break;
    727 	case DDI_INTROP_ENABLE:
    728 		/*
    729 		 * For MSI, just clear the mask bit and return if curr_nenables
    730 		 * is > 1. For MSI-X, program MSI address and data for every
    731 		 * MSI-X vector including dup vectors irrespective of current
    732 		 * curr_nenables value.
    733 		 */
    734 		if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) ||
    735 		    (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) {
    736 			nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
    737 
    738 			if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
    739 			    nintrs, hdlp->ih_inum, msi_addr,
    740 			    hdlp->ih_type == DDI_INTR_TYPE_MSIX ?
    741 			    msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
    742 				return (ret);
    743 
    744 			if (i_ddi_intr_get_current_nenables(rdip) < 1) {
    745 				if ((ret = pci_msi_enable_mode(rdip,
    746 				    hdlp->ih_type)) != DDI_SUCCESS)
    747 					return (ret);
    748 			}
    749 		}
    750 
    751 		if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type,
    752 		    hdlp->ih_inum)) != DDI_SUCCESS)
    753 			return (ret);
    754 
    755 		break;
    756 	case DDI_INTROP_DISABLE:
    757 		if ((ret = pci_msi_set_mask(rdip, hdlp->ih_type,
    758 		    hdlp->ih_inum)) != DDI_SUCCESS)
    759 			return (ret);
    760 
    761 		/*
    762 		 * curr_nenables will be greater than 1 if rdip is using
    763 		 * MSI-X and also, if it is using DUP interface. If this
    764 		 * curr_enables is > 1, return after setting the mask bit.
    765 		 */
    766 		if (i_ddi_intr_get_current_nenables(rdip) > 1)
    767 			return (DDI_SUCCESS);
    768 
    769 		if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type))
    770 		    != DDI_SUCCESS)
    771 			return (ret);
    772 
    773 		break;
    774 	case DDI_INTROP_BLOCKENABLE:
    775 		nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
    776 
    777 		if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
    778 		    nintrs, hdlp->ih_inum, msi_addr,
    779 		    msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
    780 			return (ret);
    781 
    782 		ret = pci_msi_enable_mode(rdip, hdlp->ih_type);
    783 		break;
    784 	case DDI_INTROP_BLOCKDISABLE:
    785 		ret = pci_msi_disable_mode(rdip, hdlp->ih_type);
    786 		break;
    787 	case DDI_INTROP_SETMASK:
    788 		ret = pci_msi_set_mask(rdip, hdlp->ih_type, hdlp->ih_inum);
    789 		break;
    790 	case DDI_INTROP_CLRMASK:
    791 		ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum);
    792 		break;
    793 	case DDI_INTROP_GETPENDING:
    794 		ret = pci_msi_get_pending(rdip, hdlp->ih_type,
    795 		    hdlp->ih_inum, (int *)result);
    796 		break;
    797 	case DDI_INTROP_NINTRS:
    798 		ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result);
    799 		break;
    800 	case DDI_INTROP_NAVAIL:
    801 		/* XXX - a new interface may be needed */
    802 		ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result);
    803 		break;
    804 	case DDI_INTROP_GETPOOL:
    805 		if (msi_state_p->msi_pool_p == NULL) {
    806 			*(ddi_irm_pool_t **)result = NULL;
    807 			return (DDI_ENOTSUP);
    808 		}
    809 		*(ddi_irm_pool_t **)result = msi_state_p->msi_pool_p;
    810 		ret = DDI_SUCCESS;
    811 		break;
    812 	default:
    813 		ret = DDI_ENOTSUP;
    814 		break;
    815 	}
    816 
    817 	return (ret);
    818 }
    819 
    820 static struct {
    821 	kstat_named_t pxintr_ks_name;
    822 	kstat_named_t pxintr_ks_type;
    823 	kstat_named_t pxintr_ks_cpu;
    824 	kstat_named_t pxintr_ks_pil;
    825 	kstat_named_t pxintr_ks_time;
    826 	kstat_named_t pxintr_ks_ino;
    827 	kstat_named_t pxintr_ks_cookie;
    828 	kstat_named_t pxintr_ks_devpath;
    829 	kstat_named_t pxintr_ks_buspath;
    830 } pxintr_ks_template = {
    831 	{ "name",	KSTAT_DATA_CHAR },
    832 	{ "type",	KSTAT_DATA_CHAR },
    833 	{ "cpu",	KSTAT_DATA_UINT64 },
    834 	{ "pil",	KSTAT_DATA_UINT64 },
    835 	{ "time",	KSTAT_DATA_UINT64 },
    836 	{ "ino",	KSTAT_DATA_UINT64 },
    837 	{ "cookie",	KSTAT_DATA_UINT64 },
    838 	{ "devpath",	KSTAT_DATA_STRING },
    839 	{ "buspath",	KSTAT_DATA_STRING },
    840 };
    841 
    842 static uint32_t pxintr_ks_instance;
    843 static char ih_devpath[MAXPATHLEN];
    844 static char ih_buspath[MAXPATHLEN];
    845 kmutex_t pxintr_ks_template_lock;
    846 
    847 int
    848 px_ks_update(kstat_t *ksp, int rw)
    849 {
    850 	px_ih_t *ih_p = ksp->ks_private;
    851 	int maxlen = sizeof (pxintr_ks_template.pxintr_ks_name.value.c);
    852 	px_ino_pil_t *ipil_p = ih_p->ih_ipil_p;
    853 	px_ino_t *ino_p = ipil_p->ipil_ino_p;
    854 	px_t *px_p = ino_p->ino_ib_p->ib_px_p;
    855 	devino_t ino;
    856 	sysino_t sysino;
    857 
    858 	ino = ino_p->ino_ino;
    859 	if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino) !=
    860 	    DDI_SUCCESS) {
    861 		cmn_err(CE_WARN, "px_ks_update: px_lib_intr_devino_to_sysino "
    862 		    "failed");
    863 	}
    864 
    865 	(void) snprintf(pxintr_ks_template.pxintr_ks_name.value.c, maxlen,
    866 	    "%s%d", ddi_driver_name(ih_p->ih_dip),
    867 	    ddi_get_instance(ih_p->ih_dip));
    868 
    869 	(void) ddi_pathname(ih_p->ih_dip, ih_devpath);
    870 	(void) ddi_pathname(px_p->px_dip, ih_buspath);
    871 	kstat_named_setstr(&pxintr_ks_template.pxintr_ks_devpath, ih_devpath);
    872 	kstat_named_setstr(&pxintr_ks_template.pxintr_ks_buspath, ih_buspath);
    873 
    874 	if (ih_p->ih_intr_state == PX_INTR_STATE_ENABLE) {
    875 
    876 		switch (i_ddi_intr_get_current_type(ih_p->ih_dip)) {
    877 		case DDI_INTR_TYPE_MSI:
    878 			(void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
    879 			    "msi");
    880 			break;
    881 		case DDI_INTR_TYPE_MSIX:
    882 			(void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
    883 			    "msix");
    884 			break;
    885 		default:
    886 			(void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
    887 			    "fixed");
    888 			break;
    889 		}
    890 
    891 		pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ino_p->ino_cpuid;
    892 		pxintr_ks_template.pxintr_ks_pil.value.ui64 = ipil_p->ipil_pil;
    893 		pxintr_ks_template.pxintr_ks_time.value.ui64 = ih_p->ih_nsec +
    894 		    (uint64_t)tick2ns((hrtime_t)ih_p->ih_ticks,
    895 		    ino_p->ino_cpuid);
    896 		pxintr_ks_template.pxintr_ks_ino.value.ui64 = ino;
    897 		pxintr_ks_template.pxintr_ks_cookie.value.ui64 = sysino;
    898 	} else {
    899 		(void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c,
    900 		    "disabled");
    901 		pxintr_ks_template.pxintr_ks_cpu.value.ui64 = 0;
    902 		pxintr_ks_template.pxintr_ks_pil.value.ui64 = 0;
    903 		pxintr_ks_template.pxintr_ks_time.value.ui64 = 0;
    904 		pxintr_ks_template.pxintr_ks_ino.value.ui64 = 0;
    905 		pxintr_ks_template.pxintr_ks_cookie.value.ui64 = 0;
    906 	}
    907 	return (0);
    908 }
    909 
    910 void
    911 px_create_intr_kstats(px_ih_t *ih_p)
    912 {
    913 	msiq_rec_type_t rec_type = ih_p->ih_rec_type;
    914 
    915 	ASSERT(ih_p->ih_ksp == NULL);
    916 
    917 	/*
    918 	 * Create pci_intrs::: kstats for all ih types except messages,
    919 	 * which represent unusual conditions and don't need to be tracked.
    920 	 */
    921 	if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) {
    922 		ih_p->ih_ksp = kstat_create("pci_intrs",
    923 		    atomic_inc_32_nv(&pxintr_ks_instance), "config",
    924 		    "interrupts", KSTAT_TYPE_NAMED,
    925 		    sizeof (pxintr_ks_template) / sizeof (kstat_named_t),
    926 		    KSTAT_FLAG_VIRTUAL);
    927 	}
    928 	if (ih_p->ih_ksp != NULL) {
    929 		ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2;
    930 		ih_p->ih_ksp->ks_lock = &pxintr_ks_template_lock;
    931 		ih_p->ih_ksp->ks_data = &pxintr_ks_template;
    932 		ih_p->ih_ksp->ks_private = ih_p;
    933 		ih_p->ih_ksp->ks_update = px_ks_update;
    934 	}
    935 }
    936 
    937 /*
    938  * px_add_intx_intr:
    939  *
    940  * This function is called to register INTx and legacy hardware
    941  * interrupt pins interrupts.
    942  */
    943 int
    944 px_add_intx_intr(dev_info_t *dip, dev_info_t *rdip,
    945     ddi_intr_handle_impl_t *hdlp)
    946 {
    947 	px_t		*px_p = INST_TO_STATE(ddi_get_instance(dip));
    948 	px_ib_t		*ib_p = px_p->px_ib_p;
    949 	devino_t	ino;
    950 	px_ih_t		*ih_p;
    951 	px_ino_t	*ino_p;
    952 	px_ino_pil_t	*ipil_p, *ipil_list;
    953 	int32_t		weight;
    954 	int		ret = DDI_SUCCESS;
    955 
    956 	ino = hdlp->ih_vector;
    957 
    958 	DBG(DBG_A_INTX, dip, "px_add_intx_intr: rdip=%s%d ino=%x "
    959 	    "handler=%x arg1=%x arg2=%x\n", ddi_driver_name(rdip),
    960 	    ddi_get_instance(rdip), ino, hdlp->ih_cb_func,
    961 	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2);
    962 
    963 	ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum,
    964 	    hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, 0, 0);
    965 
    966 	mutex_enter(&ib_p->ib_ino_lst_mutex);
    967 
    968 	ino_p = px_ib_locate_ino(ib_p, ino);
    969 	ipil_list = ino_p ? ino_p->ino_ipil_p : NULL;
    970 
    971 	/* Sharing ino */
    972 	if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) {
    973 		if (px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0)) {
    974 			DBG(DBG_A_INTX, dip, "px_add_intx_intr: "
    975 			    "dup intr #%d\n", hdlp->ih_inum);
    976 
    977 			ret = DDI_FAILURE;
    978 			goto fail1;
    979 		}
    980 
    981 		/* Save mondo value in hdlp */
    982 		hdlp->ih_vector = ino_p->ino_sysino;
    983 
    984 		if ((ret = px_ib_ino_add_intr(px_p, ipil_p,
    985 		    ih_p)) != DDI_SUCCESS)
    986 			goto fail1;
    987 
    988 		goto ino_done;
    989 	}
    990 
    991 	if (hdlp->ih_pri == 0)
    992 		hdlp->ih_pri = pci_class_to_pil(rdip);
    993 
    994 	ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p);
    995 	ino_p = ipil_p->ipil_ino_p;
    996 
    997 	/* Save mondo value in hdlp */
    998 	hdlp->ih_vector = ino_p->ino_sysino;
    999 
   1000 	DBG(DBG_A_INTX, dip, "px_add_intx_intr: pil=0x%x mondo=0x%x\n",
   1001 	    hdlp->ih_pri, hdlp->ih_vector);
   1002 
   1003 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
   1004 	    (ddi_intr_handler_t *)px_intx_intr, (caddr_t)ipil_p, NULL);
   1005 
   1006 	ret = i_ddi_add_ivintr(hdlp);
   1007 
   1008 	/*
   1009 	 * Restore original interrupt handler
   1010 	 * and arguments in interrupt handle.
   1011 	 */
   1012 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler,
   1013 	    ih_p->ih_handler_arg1, ih_p->ih_handler_arg2);
   1014 
   1015 	if (ret != DDI_SUCCESS)
   1016 		goto fail2;
   1017 
   1018 	/* Save the pil for this ino */
   1019 	ipil_p->ipil_pil = hdlp->ih_pri;
   1020 
   1021 	/* Select cpu, saving it for sharing and removal */
   1022 	if (ipil_list == NULL) {
   1023 		if (ino_p->ino_cpuid == -1)
   1024 			ino_p->ino_cpuid = intr_dist_cpuid();
   1025 
   1026 		/* Enable interrupt */
   1027 		px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino);
   1028 	}
   1029 
   1030 ino_done:
   1031 	hdlp->ih_target = ino_p->ino_cpuid;
   1032 
   1033 	/* Add weight to the cpu that we are already targeting */
   1034 	weight = pci_class_to_intr_weight(rdip);
   1035 	intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight);
   1036 
   1037 	ih_p->ih_ipil_p = ipil_p;
   1038 	px_create_intr_kstats(ih_p);
   1039 	if (ih_p->ih_ksp)
   1040 		kstat_install(ih_p->ih_ksp);
   1041 	mutex_exit(&ib_p->ib_ino_lst_mutex);
   1042 
   1043 	DBG(DBG_A_INTX, dip, "px_add_intx_intr: done! Interrupt 0x%x pil=%x\n",
   1044 	    ino_p->ino_sysino, hdlp->ih_pri);
   1045 
   1046 	return (ret);
   1047 fail2:
   1048 	px_ib_delete_ino_pil(ib_p, ipil_p);
   1049 fail1:
   1050 	if (ih_p->ih_config_handle)
   1051 		pci_config_teardown(&ih_p->ih_config_handle);
   1052 
   1053 	mutex_exit(&ib_p->ib_ino_lst_mutex);
   1054 	kmem_free(ih_p, sizeof (px_ih_t));
   1055 
   1056 	DBG(DBG_A_INTX, dip, "px_add_intx_intr: Failed! Interrupt 0x%x "
   1057 	    "pil=%x\n", ino_p->ino_sysino, hdlp->ih_pri);
   1058 
   1059 	return (ret);
   1060 }
   1061 
   1062 /*
   1063  * px_rem_intx_intr:
   1064  *
   1065  * This function is called to unregister INTx and legacy hardware
   1066  * interrupt pins interrupts.
   1067  */
   1068 int
   1069 px_rem_intx_intr(dev_info_t *dip, dev_info_t *rdip,
   1070     ddi_intr_handle_impl_t *hdlp)
   1071 {
   1072 	px_t		*px_p = INST_TO_STATE(ddi_get_instance(dip));
   1073 	px_ib_t		*ib_p = px_p->px_ib_p;
   1074 	devino_t	ino;
   1075 	cpuid_t		curr_cpu;
   1076 	px_ino_t	*ino_p;
   1077 	px_ino_pil_t	*ipil_p;
   1078 	px_ih_t		*ih_p;
   1079 	int		ret = DDI_SUCCESS;
   1080 
   1081 	ino = hdlp->ih_vector;
   1082 
   1083 	DBG(DBG_R_INTX, dip, "px_rem_intx_intr: rdip=%s%d ino=%x\n",
   1084 	    ddi_driver_name(rdip), ddi_get_instance(rdip), ino);
   1085 
   1086 	mutex_enter(&ib_p->ib_ino_lst_mutex);
   1087 
   1088 	ino_p = px_ib_locate_ino(ib_p, ino);
   1089 	ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri);
   1090 	ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0);
   1091 
   1092 	/* Get the current cpu */
   1093 	if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino,
   1094 	    &curr_cpu)) != DDI_SUCCESS)
   1095 		goto fail;
   1096 
   1097 	if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS)
   1098 		goto fail;
   1099 
   1100 	intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip);
   1101 
   1102 	if (ipil_p->ipil_ih_size == 0) {
   1103 		hdlp->ih_vector = ino_p->ino_sysino;
   1104 		i_ddi_rem_ivintr(hdlp);
   1105 
   1106 		px_ib_delete_ino_pil(ib_p, ipil_p);
   1107 	}
   1108 
   1109 	if (ino_p->ino_ipil_size == 0) {
   1110 		kmem_free(ino_p, sizeof (px_ino_t));
   1111 	} else {
   1112 		/* Re-enable interrupt only if mapping register still shared */
   1113 		PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu);
   1114 	}
   1115 
   1116 fail:
   1117 	mutex_exit(&ib_p->ib_ino_lst_mutex);
   1118 	return (ret);
   1119 }
   1120 
   1121 /*
   1122  * px_add_msiq_intr:
   1123  *
   1124  * This function is called to register MSI/Xs and PCIe message interrupts.
   1125  */
   1126 int
   1127 px_add_msiq_intr(dev_info_t *dip, dev_info_t *rdip,
   1128     ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type,
   1129     msgcode_t msg_code, cpuid_t cpu_id, msiqid_t *msiq_id_p)
   1130 {
   1131 	px_t		*px_p = INST_TO_STATE(ddi_get_instance(dip));
   1132 	px_ib_t		*ib_p = px_p->px_ib_p;
   1133 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
   1134 	devino_t	ino;
   1135 	px_ih_t		*ih_p;
   1136 	px_ino_t	*ino_p;
   1137 	px_ino_pil_t	*ipil_p, *ipil_list;
   1138 	int32_t		weight;
   1139 	int		ret = DDI_SUCCESS;
   1140 
   1141 	DBG(DBG_MSIQ, dip, "px_add_msiq_intr: rdip=%s%d handler=0x%x "
   1142 	    "arg1=0x%x arg2=0x%x cpu=0x%x\n", ddi_driver_name(rdip),
   1143 	    ddi_get_instance(rdip), hdlp->ih_cb_func, hdlp->ih_cb_arg1,
   1144 	    hdlp->ih_cb_arg2, cpu_id);
   1145 
   1146 	ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, hdlp->ih_cb_func,
   1147 	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rec_type, msg_code);
   1148 
   1149 	mutex_enter(&ib_p->ib_ino_lst_mutex);
   1150 
   1151 	ret = (cpu_id == -1) ? px_msiq_alloc(px_p, rec_type, msg_code,
   1152 	    msiq_id_p) : px_msiq_alloc_based_on_cpuid(px_p, rec_type,
   1153 	    cpu_id, msiq_id_p);
   1154 
   1155 	if (ret != DDI_SUCCESS) {
   1156 		DBG(DBG_MSIQ, dip, "px_add_msiq_intr: "
   1157 		    "msiq allocation failed\n");
   1158 		goto fail;
   1159 	}
   1160 
   1161 	ino = px_msiqid_to_devino(px_p, *msiq_id_p);
   1162 
   1163 	ino_p = px_ib_locate_ino(ib_p, ino);
   1164 	ipil_list = ino_p ? ino_p->ino_ipil_p : NULL;
   1165 
   1166 	/* Sharing ino */
   1167 	if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) {
   1168 		if (px_ib_intr_locate_ih(ipil_p, rdip,
   1169 		    hdlp->ih_inum, rec_type, msg_code)) {
   1170 			DBG(DBG_MSIQ, dip, "px_add_msiq_intr: "
   1171 			    "dup intr #%d\n", hdlp->ih_inum);
   1172 
   1173 			ret = DDI_FAILURE;
   1174 			goto fail1;
   1175 		}
   1176 
   1177 		/* Save mondo value in hdlp */
   1178 		hdlp->ih_vector = ino_p->ino_sysino;
   1179 
   1180 		if ((ret = px_ib_ino_add_intr(px_p, ipil_p,
   1181 		    ih_p)) != DDI_SUCCESS)
   1182 			goto fail1;
   1183 
   1184 		goto ino_done;
   1185 	}
   1186 
   1187 	if (hdlp->ih_pri == 0)
   1188 		hdlp->ih_pri = pci_class_to_pil(rdip);
   1189 
   1190 	ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p);
   1191 	ino_p = ipil_p->ipil_ino_p;
   1192 
   1193 	ino_p->ino_msiq_p = msiq_state_p->msiq_p +
   1194 	    (*msiq_id_p - msiq_state_p->msiq_1st_msiq_id);
   1195 
   1196 	/* Save mondo value in hdlp */
   1197 	hdlp->ih_vector = ino_p->ino_sysino;
   1198 
   1199 	DBG(DBG_MSIQ, dip, "px_add_msiq_intr: pil=0x%x mondo=0x%x\n",
   1200 	    hdlp->ih_pri, hdlp->ih_vector);
   1201 
   1202 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
   1203 	    (ddi_intr_handler_t *)px_msiq_intr, (caddr_t)ipil_p, NULL);
   1204 
   1205 	ret = i_ddi_add_ivintr(hdlp);
   1206 
   1207 	/*
   1208 	 * Restore original interrupt handler
   1209 	 * and arguments in interrupt handle.
   1210 	 */
   1211 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler,
   1212 	    ih_p->ih_handler_arg1, ih_p->ih_handler_arg2);
   1213 
   1214 	if (ret != DDI_SUCCESS)
   1215 		goto fail2;
   1216 
   1217 	/* Save the pil for this ino */
   1218 	ipil_p->ipil_pil = hdlp->ih_pri;
   1219 
   1220 	/* Select cpu, saving it for sharing and removal */
   1221 	if (ipil_list == NULL) {
   1222 		/* Enable MSIQ */
   1223 		px_lib_msiq_setstate(dip, *msiq_id_p, PCI_MSIQ_STATE_IDLE);
   1224 		px_lib_msiq_setvalid(dip, *msiq_id_p, PCI_MSIQ_VALID);
   1225 
   1226 		if (ino_p->ino_cpuid == -1)
   1227 			ino_p->ino_cpuid = intr_dist_cpuid();
   1228 
   1229 		/* Enable interrupt */
   1230 		px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino);
   1231 	}
   1232 
   1233 ino_done:
   1234 	hdlp->ih_target = ino_p->ino_cpuid;
   1235 
   1236 	/* Add weight to the cpu that we are already targeting */
   1237 	weight = pci_class_to_intr_weight(rdip);
   1238 	intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight);
   1239 
   1240 	ih_p->ih_ipil_p = ipil_p;
   1241 	px_create_intr_kstats(ih_p);
   1242 	if (ih_p->ih_ksp)
   1243 		kstat_install(ih_p->ih_ksp);
   1244 	mutex_exit(&ib_p->ib_ino_lst_mutex);
   1245 
   1246 	DBG(DBG_MSIQ, dip, "px_add_msiq_intr: done! Interrupt 0x%x pil=%x\n",
   1247 	    ino_p->ino_sysino, hdlp->ih_pri);
   1248 
   1249 	return (ret);
   1250 fail2:
   1251 	px_ib_delete_ino_pil(ib_p, ipil_p);
   1252 fail1:
   1253 	(void) px_msiq_free(px_p, *msiq_id_p);
   1254 fail:
   1255 	if (ih_p->ih_config_handle)
   1256 		pci_config_teardown(&ih_p->ih_config_handle);
   1257 
   1258 	mutex_exit(&ib_p->ib_ino_lst_mutex);
   1259 	kmem_free(ih_p, sizeof (px_ih_t));
   1260 
   1261 	DBG(DBG_MSIQ, dip, "px_add_msiq_intr: Failed! Interrupt 0x%x pil=%x\n",
   1262 	    ino_p->ino_sysino, hdlp->ih_pri);
   1263 
   1264 	return (ret);
   1265 }
   1266 
   1267 /*
   1268  * px_rem_msiq_intr:
   1269  *
   1270  * This function is called to unregister MSI/Xs and PCIe message interrupts.
   1271  */
   1272 int
   1273 px_rem_msiq_intr(dev_info_t *dip, dev_info_t *rdip,
   1274     ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type,
   1275     msgcode_t msg_code, msiqid_t msiq_id)
   1276 {
   1277 	px_t		*px_p = INST_TO_STATE(ddi_get_instance(dip));
   1278 	px_ib_t		*ib_p = px_p->px_ib_p;
   1279 	devino_t	ino = px_msiqid_to_devino(px_p, msiq_id);
   1280 	cpuid_t		curr_cpu;
   1281 	px_ino_t	*ino_p;
   1282 	px_ino_pil_t	*ipil_p;
   1283 	px_ih_t		*ih_p;
   1284 	int		ret = DDI_SUCCESS;
   1285 
   1286 	DBG(DBG_MSIQ, dip, "px_rem_msiq_intr: rdip=%s%d msiq_id=%x ino=%x\n",
   1287 	    ddi_driver_name(rdip), ddi_get_instance(rdip), msiq_id, ino);
   1288 
   1289 	mutex_enter(&ib_p->ib_ino_lst_mutex);
   1290 
   1291 	ino_p = px_ib_locate_ino(ib_p, ino);
   1292 	ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri);
   1293 	ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, rec_type,
   1294 	    msg_code);
   1295 
   1296 	/* Get the current cpu */
   1297 	if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino,
   1298 	    &curr_cpu)) != DDI_SUCCESS)
   1299 		goto fail;
   1300 
   1301 	if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS)
   1302 		goto fail;
   1303 
   1304 	intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip);
   1305 
   1306 	if (ipil_p->ipil_ih_size == 0) {
   1307 		hdlp->ih_vector = ino_p->ino_sysino;
   1308 		i_ddi_rem_ivintr(hdlp);
   1309 
   1310 		px_ib_delete_ino_pil(ib_p, ipil_p);
   1311 
   1312 		if (ino_p->ino_ipil_size == 0)
   1313 			px_lib_msiq_setvalid(dip,
   1314 			    px_devino_to_msiqid(px_p, ino), PCI_MSIQ_INVALID);
   1315 	}
   1316 
   1317 	(void) px_msiq_free(px_p, msiq_id);
   1318 
   1319 	if (ino_p->ino_ipil_size) {
   1320 		/* Re-enable interrupt only if mapping register still shared */
   1321 		PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu);
   1322 	}
   1323 
   1324 fail:
   1325 	mutex_exit(&ib_p->ib_ino_lst_mutex);
   1326 	return (ret);
   1327 }
   1328