10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * PX nexus interrupt handling: 310Sstevel@tonic-gate * PX device interrupt handler wrapper 320Sstevel@tonic-gate * PIL lookup routine 330Sstevel@tonic-gate * PX device interrupt related initchild code 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <sys/types.h> 370Sstevel@tonic-gate #include <sys/kmem.h> 380Sstevel@tonic-gate #include <sys/async.h> 390Sstevel@tonic-gate #include <sys/spl.h> 400Sstevel@tonic-gate #include <sys/sunddi.h> 4127Sjchu #include <sys/fm/protocol.h> 4227Sjchu #include <sys/fm/util.h> 430Sstevel@tonic-gate #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */ 440Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 450Sstevel@tonic-gate #include <sys/sdt.h> 460Sstevel@tonic-gate #include <sys/atomic.h> 470Sstevel@tonic-gate #include "px_obj.h" 4827Sjchu #include <sys/ontrap.h> 4927Sjchu #include <sys/membar.h> 5066Sesolom #include <sys/clock.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * interrupt jabber: 540Sstevel@tonic-gate * 550Sstevel@tonic-gate * When an interrupt line is jabbering, every time the state machine for the 560Sstevel@tonic-gate * associated ino is idled, a new mondo will be sent and the ino will go into 570Sstevel@tonic-gate * the pending state again. The mondo will cause a new call to 580Sstevel@tonic-gate * px_intr_wrapper() which normally idles the ino's state machine which would 590Sstevel@tonic-gate * precipitate another trip round the loop. 600Sstevel@tonic-gate * 610Sstevel@tonic-gate * The loop can be broken by preventing the ino's state machine from being 620Sstevel@tonic-gate * idled when an interrupt line is jabbering. See the comment at the 630Sstevel@tonic-gate * beginning of px_intr_wrapper() explaining how the 'interrupt jabber 640Sstevel@tonic-gate * protection' code does this. 650Sstevel@tonic-gate */ 660Sstevel@tonic-gate 670Sstevel@tonic-gate /*LINTLIBRARY*/ 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * If the unclaimed interrupt count has reached the limit set by 710Sstevel@tonic-gate * pci_unclaimed_intr_max within the time limit, then all interrupts 720Sstevel@tonic-gate * on this ino is blocked by not idling the interrupt state machine. 730Sstevel@tonic-gate */ 740Sstevel@tonic-gate static int 750Sstevel@tonic-gate px_spurintr(px_ib_ino_info_t *ino_p) 760Sstevel@tonic-gate { 770Sstevel@tonic-gate px_ih_t *ih_p = ino_p->ino_ih_start; 780Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 790Sstevel@tonic-gate char *err_fmt_str; 800Sstevel@tonic-gate int i; 810Sstevel@tonic-gate 820Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) 830Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 840Sstevel@tonic-gate 850Sstevel@tonic-gate if (!ino_p->ino_unclaimed) 860Sstevel@tonic-gate ino_p->ino_spurintr_begin = ddi_get_lbolt(); 870Sstevel@tonic-gate 880Sstevel@tonic-gate ino_p->ino_unclaimed++; 890Sstevel@tonic-gate 900Sstevel@tonic-gate if (ino_p->ino_unclaimed <= px_unclaimed_intr_max) 910Sstevel@tonic-gate goto clear; 920Sstevel@tonic-gate 930Sstevel@tonic-gate if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin) 940Sstevel@tonic-gate > px_spurintr_duration) { 950Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 960Sstevel@tonic-gate goto clear; 970Sstevel@tonic-gate } 980Sstevel@tonic-gate err_fmt_str = "%s%d: ino 0x%x blocked"; 990Sstevel@tonic-gate goto warn; 1000Sstevel@tonic-gate clear: 1010Sstevel@tonic-gate /* Clear the pending state */ 1020Sstevel@tonic-gate if (px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 1030Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 1040Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; 1070Sstevel@tonic-gate warn: 1080Sstevel@tonic-gate cmn_err(CE_WARN, err_fmt_str, NAMEINST(px_p->px_dip), ino_p->ino_ino); 1090Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_p = ih_p->ih_next) 1100Sstevel@tonic-gate cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), 1110Sstevel@tonic-gate ih_p->ih_inum); 1120Sstevel@tonic-gate cmn_err(CE_CONT, "!\n"); 1130Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate extern uint64_t intr_get_time(void); 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /* 1190Sstevel@tonic-gate * px_intx_intr (legacy or intx interrupt handler) 1200Sstevel@tonic-gate * 1210Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 1220Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 1230Sstevel@tonic-gate * examines the return codes. 1240Sstevel@tonic-gate * 1250Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 1260Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 1270Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 1280Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 1290Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 1300Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 1310Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 1320Sstevel@tonic-gate * handler is subsequently added or removed. 1330Sstevel@tonic-gate * 1340Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 1350Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate uint_t 1380Sstevel@tonic-gate px_intx_intr(caddr_t arg) 1390Sstevel@tonic-gate { 1400Sstevel@tonic-gate px_ib_ino_info_t *ino_p = (px_ib_ino_info_t *)arg; 1410Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 1420Sstevel@tonic-gate px_ih_t *ih_p = ino_p->ino_ih_start; 1430Sstevel@tonic-gate uint_t result = 0, r; 1440Sstevel@tonic-gate int i; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1470Sstevel@tonic-gate "ino=%x sysino=%llx pil=%x ih_size=%x ih_lst=%x\n", 1480Sstevel@tonic-gate ino_p->ino_ino, ino_p->ino_sysino, ino_p->ino_pil, 1490Sstevel@tonic-gate ino_p->ino_ih_size, ino_p->ino_ih_head); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_p = ih_p->ih_next) { 1520Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip; 1530Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 1540Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 1550Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate if (ih_p->ih_intr_state == PX_INTR_STATE_DISABLE) { 1580Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, 1590Sstevel@tonic-gate "px_intx_intr: %s%d interrupt %d is disabled\n", 1600Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1610Sstevel@tonic-gate ino_p->ino_ino); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate continue; 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1670Sstevel@tonic-gate "ino=%x handler=%p arg1 =%p arg2 = %p\n", 1680Sstevel@tonic-gate ino_p->ino_ino, handler, arg1, arg2); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 1710Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate r = (*handler)(arg1, arg2); 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * Account for time used by this interrupt. Protect against 1770Sstevel@tonic-gate * conflicting writes to ih_ticks from ib_intr_dist_all() by 1780Sstevel@tonic-gate * using atomic ops. 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate if (ino_p->ino_pil <= LOCK_LEVEL) 1820Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 1850Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, r); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate result += r; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate if (px_check_all_handlers) 1900Sstevel@tonic-gate continue; 1910Sstevel@tonic-gate if (result) 1920Sstevel@tonic-gate break; 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate if (!result && px_unclaimed_intr_block) 1960Sstevel@tonic-gate return (px_spurintr(ino_p)); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* Clear the pending state */ 2010Sstevel@tonic-gate if (px_lib_intr_setstate(ino_p->ino_ib_p->ib_px_p->px_dip, 2020Sstevel@tonic-gate ino_p->ino_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 2030Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * px_msiq_intr (MSI/MSIX/MSG interrupt handler) 2100Sstevel@tonic-gate * 2110Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 2120Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 2130Sstevel@tonic-gate * examines the return codes. 2140Sstevel@tonic-gate * 2150Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 2160Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 2170Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 2180Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 2190Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 2200Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 2210Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 2220Sstevel@tonic-gate * handler is subsequently added or removed. 2230Sstevel@tonic-gate * 2240Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 2250Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 2260Sstevel@tonic-gate */ 2270Sstevel@tonic-gate uint_t 2280Sstevel@tonic-gate px_msiq_intr(caddr_t arg) 2290Sstevel@tonic-gate { 2300Sstevel@tonic-gate px_ib_ino_info_t *ino_p = (px_ib_ino_info_t *)arg; 2310Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 2320Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 2330Sstevel@tonic-gate px_msiq_t *msiq_p = ino_p->ino_msiq_p; 2340Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 2350Sstevel@tonic-gate msiq_rec_t msiq_rec, *msiq_rec_p = &msiq_rec; 2360Sstevel@tonic-gate msiqhead_t curr_msiq_rec_cnt, new_msiq_rec_cnt; 2370Sstevel@tonic-gate msgcode_t msg_code; 2380Sstevel@tonic-gate px_ih_t *ih_p; 2390Sstevel@tonic-gate int ret; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x " 2420Sstevel@tonic-gate "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino, 2430Sstevel@tonic-gate ino_p->ino_pil, ino_p->ino_ih_size, ino_p->ino_ih_head); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* Read current MSIQ head index */ 2460Sstevel@tonic-gate px_lib_msiq_gethead(dip, msiq_p->msiq_id, &curr_msiq_rec_cnt); 2470Sstevel@tonic-gate msiq_p->msiq_curr = (uint64_t)((caddr_t)msiq_p->msiq_base + 2480Sstevel@tonic-gate curr_msiq_rec_cnt * sizeof (msiq_rec_t)); 2490Sstevel@tonic-gate new_msiq_rec_cnt = curr_msiq_rec_cnt; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* Read next MSIQ record */ 2520Sstevel@tonic-gate px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* 255*287Smg140465 * Process current MSIQ record as long as record type 2560Sstevel@tonic-gate * field is non-zero. 2570Sstevel@tonic-gate */ 258*287Smg140465 while (msiq_rec_p->msiq_rec_type) { 2590Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, " 2600Sstevel@tonic-gate "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n", 2610Sstevel@tonic-gate msiq_rec_p->msiq_rec_type, msiq_rec_p->msiq_rec_rid); 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate /* Get the pointer next EQ record */ 2640Sstevel@tonic-gate msiq_p->msiq_curr = (uint64_t) 2650Sstevel@tonic-gate ((caddr_t)msiq_p->msiq_curr + sizeof (msiq_rec_t)); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate /* Check for overflow condition */ 2680Sstevel@tonic-gate if (msiq_p->msiq_curr >= (uint64_t)((caddr_t)msiq_p->msiq_base + 2690Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t))) 2700Sstevel@tonic-gate msiq_p->msiq_curr = msiq_p->msiq_base; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* Check MSIQ record type */ 2730Sstevel@tonic-gate switch (msiq_rec_p->msiq_rec_type) { 2740Sstevel@tonic-gate case MSG_REC: 2750Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msg.msg_code; 2760Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: PCIE MSG " 2770Sstevel@tonic-gate "record, msg type 0x%x\n", msg_code); 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate case MSI32_REC: 2800Sstevel@tonic-gate case MSI64_REC: 2810Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data; 2820Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, " 2830Sstevel@tonic-gate "msi 0x%x\n", msg_code); 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /* Clear MSI state */ 2860Sstevel@tonic-gate px_lib_msi_setstate(dip, (msinum_t)msg_code, 2870Sstevel@tonic-gate PCI_MSI_STATE_IDLE); 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate default: 2900Sstevel@tonic-gate msg_code = 0; 2910Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_msiq_intr: 0x%x MSIQ " 2920Sstevel@tonic-gate "record type is not supported", 2930Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2940Sstevel@tonic-gate msiq_rec_p->msiq_rec_type); 2950Sstevel@tonic-gate goto next_rec; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate ih_p = ino_p->ino_ih_start; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * Scan through px_ih_t linked list, searching for the 3020Sstevel@tonic-gate * right px_ih_t, matching MSIQ record data. 3030Sstevel@tonic-gate */ 3040Sstevel@tonic-gate while ((ih_p) && (ih_p->ih_msg_code != msg_code) && 3050Sstevel@tonic-gate (ih_p->ih_rec_type != msiq_rec_p->msiq_rec_type)) 3060Sstevel@tonic-gate ih_p = ih_p->ih_next; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if ((ih_p->ih_msg_code == msg_code) && 3090Sstevel@tonic-gate (ih_p->ih_rec_type == msiq_rec_p->msiq_rec_type)) { 3100Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip; 3110Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 3120Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 3130Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: ino=%x data=%x " 3160Sstevel@tonic-gate "handler=%p arg1 =%p arg2=%p\n", ino_p->ino_ino, 3170Sstevel@tonic-gate msg_code, handler, arg1, arg2); 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 3200Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 3210Sstevel@tonic-gate 32227Sjchu /* 32327Sjchu * Special case for PCIE Error Messages. 32427Sjchu * The current frame work doesn't fit PCIE Err Msgs 32527Sjchu * This should be fixed when PCIE MESSAGES as a whole 32627Sjchu * is architected correctly. 32727Sjchu */ 32827Sjchu if ((msg_code == PCIE_MSG_CODE_ERR_COR) || 32927Sjchu (msg_code == PCIE_MSG_CODE_ERR_NONFATAL) || 33027Sjchu (msg_code == PCIE_MSG_CODE_ERR_FATAL)) { 33127Sjchu ret = px_err_fabric_intr(px_p, msg_code, 33227Sjchu msiq_rec_p->msiq_rec_rid); 33327Sjchu } else 33427Sjchu ret = (*handler)(arg1, arg2); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Account for time used by this interrupt. Protect 3380Sstevel@tonic-gate * against conflicting writes to ih_ticks from 3390Sstevel@tonic-gate * ib_intr_dist_all() by using atomic ops. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate if (ino_p->ino_pil <= LOCK_LEVEL) 3430Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 3460Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, ret); 3470Sstevel@tonic-gate } else { 3480Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr:" 3490Sstevel@tonic-gate "Not found matching MSIQ record\n"); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate /* px_spurintr(ino_p); */ 3520Sstevel@tonic-gate ino_p->ino_unclaimed++; 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate next_rec: 3560Sstevel@tonic-gate new_msiq_rec_cnt++; 3570Sstevel@tonic-gate 358*287Smg140465 /* Zero out msiq_rec_type field */ 359*287Smg140465 msiq_rec_p->msiq_rec_type = 0; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate /* Read next MSIQ record */ 3620Sstevel@tonic-gate px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n", 3660Sstevel@tonic-gate (new_msiq_rec_cnt - curr_msiq_rec_cnt)); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* Update MSIQ head index with no of MSIQ records processed */ 3690Sstevel@tonic-gate if (new_msiq_rec_cnt > curr_msiq_rec_cnt) { 3700Sstevel@tonic-gate if (new_msiq_rec_cnt >= msiq_state_p->msiq_rec_cnt) 3710Sstevel@tonic-gate new_msiq_rec_cnt -= msiq_state_p->msiq_rec_cnt; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate px_lib_msiq_sethead(dip, msiq_p->msiq_id, new_msiq_rec_cnt); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* Clear the pending state */ 3770Sstevel@tonic-gate if (px_lib_intr_setstate(dip, ino_p->ino_sysino, 3780Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 3790Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate dev_info_t * 3850Sstevel@tonic-gate px_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 3860Sstevel@tonic-gate { 3870Sstevel@tonic-gate dev_info_t *cdip = rdip; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 3900Sstevel@tonic-gate ; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate return (cdip); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate /* Default class to pil value mapping */ 3960Sstevel@tonic-gate px_class_val_t px_default_pil [] = { 3970Sstevel@tonic-gate {0x000000, 0xff0000, 0x1}, /* Class code for pre-2.0 devices */ 3980Sstevel@tonic-gate {0x010000, 0xff0000, 0x4}, /* Mass Storage Controller */ 3990Sstevel@tonic-gate {0x020000, 0xff0000, 0x6}, /* Network Controller */ 4000Sstevel@tonic-gate {0x030000, 0xff0000, 0x9}, /* Display Controller */ 4010Sstevel@tonic-gate {0x040000, 0xff0000, 0x9}, /* Multimedia Controller */ 4020Sstevel@tonic-gate {0x050000, 0xff0000, 0xb}, /* Memory Controller */ 4030Sstevel@tonic-gate {0x060000, 0xff0000, 0xb}, /* Bridge Controller */ 4040Sstevel@tonic-gate {0x0c0000, 0xffff00, 0x9}, /* Serial Bus, FireWire (IEEE 1394) */ 4050Sstevel@tonic-gate {0x0c0100, 0xffff00, 0x4}, /* Serial Bus, ACCESS.bus */ 4060Sstevel@tonic-gate {0x0c0200, 0xffff00, 0x4}, /* Serial Bus, SSA */ 4070Sstevel@tonic-gate {0x0c0300, 0xffff00, 0x9}, /* Serial Bus Universal Serial Bus */ 4080Sstevel@tonic-gate {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */ 4090Sstevel@tonic-gate {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */ 4100Sstevel@tonic-gate }; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Default class to intr_weight value mapping (% of CPU). A driver.conf 4140Sstevel@tonic-gate * entry on or above the pci node like 4150Sstevel@tonic-gate * 4160Sstevel@tonic-gate * pci-class-intr-weights= 0x020000, 0xff0000, 30; 4170Sstevel@tonic-gate * 4180Sstevel@tonic-gate * can be used to augment or override entries in the default table below. 4190Sstevel@tonic-gate * 4200Sstevel@tonic-gate * NB: The values below give NICs preference on redistribution, and provide 4210Sstevel@tonic-gate * NICs some isolation from other interrupt sources. We need better interfaces 4220Sstevel@tonic-gate * that allow the NIC driver to identify a specific NIC instance as high 4230Sstevel@tonic-gate * bandwidth, and thus deserving of separation from other low bandwidth 4240Sstevel@tonic-gate * NICs additional isolation from other interrupt sources. 4250Sstevel@tonic-gate * 4260Sstevel@tonic-gate * NB: We treat Infiniband like a NIC. 4270Sstevel@tonic-gate */ 4280Sstevel@tonic-gate px_class_val_t px_default_intr_weight [] = { 4290Sstevel@tonic-gate {0x020000, 0xff0000, 35}, /* Network Controller */ 4300Sstevel@tonic-gate {0x010000, 0xff0000, 10}, /* Mass Storage Controller */ 4310Sstevel@tonic-gate {0x0c0400, 0xffff00, 10}, /* Serial Bus, Fibre Channel */ 4320Sstevel@tonic-gate {0x0c0600, 0xffff00, 50} /* Serial Bus, Infiniband */ 4330Sstevel@tonic-gate }; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate static uint32_t 4360Sstevel@tonic-gate px_match_class_val(uint32_t key, px_class_val_t *rec_p, int nrec, 4370Sstevel@tonic-gate uint32_t default_val) 4380Sstevel@tonic-gate { 4390Sstevel@tonic-gate int i; 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate for (i = 0; i < nrec; rec_p++, i++) { 4420Sstevel@tonic-gate if ((rec_p->class_code & rec_p->class_mask) == 4430Sstevel@tonic-gate (key & rec_p->class_mask)) 4440Sstevel@tonic-gate return (rec_p->class_val); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate return (default_val); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * px_class_to_val 4520Sstevel@tonic-gate * 4530Sstevel@tonic-gate * Return the configuration value, based on class code and sub class code, 4540Sstevel@tonic-gate * from the specified property based or default px_class_val_t table. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate uint32_t 4570Sstevel@tonic-gate px_class_to_val(dev_info_t *rdip, char *property_name, px_class_val_t *rec_p, 4580Sstevel@tonic-gate int nrec, uint32_t default_val) 4590Sstevel@tonic-gate { 4600Sstevel@tonic-gate int property_len; 4610Sstevel@tonic-gate uint32_t class_code; 4620Sstevel@tonic-gate px_class_val_t *conf; 4630Sstevel@tonic-gate uint32_t val = default_val; 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4660Sstevel@tonic-gate * Use the "class-code" property to get the base and sub class 4670Sstevel@tonic-gate * codes for the requesting device. 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 4700Sstevel@tonic-gate DDI_PROP_DONTPASS, "class-code", -1); 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate if (class_code == -1) 4730Sstevel@tonic-gate return (val); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate /* look up the val from the default table */ 4760Sstevel@tonic-gate val = px_match_class_val(class_code, rec_p, nrec, val); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /* see if there is a more specific property specified value */ 4790Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_NOTPROM, 4800Sstevel@tonic-gate property_name, (caddr_t)&conf, &property_len)) 4810Sstevel@tonic-gate return (val); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate if ((property_len % sizeof (px_class_val_t)) == 0) 4840Sstevel@tonic-gate val = px_match_class_val(class_code, conf, 4850Sstevel@tonic-gate property_len / sizeof (px_class_val_t), val); 4860Sstevel@tonic-gate kmem_free(conf, property_len); 4870Sstevel@tonic-gate return (val); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* px_class_to_pil: return the pil for a given device. */ 4910Sstevel@tonic-gate uint32_t 4920Sstevel@tonic-gate px_class_to_pil(dev_info_t *rdip) 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate uint32_t pil; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* default pil is 0 (uninitialized) */ 4970Sstevel@tonic-gate pil = px_class_to_val(rdip, 4980Sstevel@tonic-gate "pci-class-priorities", px_default_pil, 4990Sstevel@tonic-gate sizeof (px_default_pil) / sizeof (px_class_val_t), 0); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* range check the result */ 5020Sstevel@tonic-gate if (pil >= 0xf) 5030Sstevel@tonic-gate pil = 0; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate return (pil); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* px_class_to_intr_weight: return the intr_weight for a given device. */ 5090Sstevel@tonic-gate static int32_t 5100Sstevel@tonic-gate px_class_to_intr_weight(dev_info_t *rdip) 5110Sstevel@tonic-gate { 5120Sstevel@tonic-gate int32_t intr_weight; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* default weight is 0% */ 5150Sstevel@tonic-gate intr_weight = px_class_to_val(rdip, 5160Sstevel@tonic-gate "pci-class-intr-weights", px_default_intr_weight, 5170Sstevel@tonic-gate sizeof (px_default_intr_weight) / sizeof (px_class_val_t), 0); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate /* range check the result */ 5200Sstevel@tonic-gate if (intr_weight < 0) 5210Sstevel@tonic-gate intr_weight = 0; 5220Sstevel@tonic-gate if (intr_weight > 1000) 5230Sstevel@tonic-gate intr_weight = 1000; 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate return (intr_weight); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* ARGSUSED */ 5290Sstevel@tonic-gate int 5300Sstevel@tonic-gate px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 5310Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 5320Sstevel@tonic-gate { 5330Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5340Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 5350Sstevel@tonic-gate int ret = DDI_SUCCESS; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: dip=%x rdip=%x intr_op=%x " 5380Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate switch (intr_op) { 5410Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5420Sstevel@tonic-gate ret = pci_intx_get_cap(rdip, (int *)result); 5430Sstevel@tonic-gate break; 5440Sstevel@tonic-gate case DDI_INTROP_SETCAP: 5450Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: SetCap is not supported\n"); 5460Sstevel@tonic-gate ret = DDI_ENOTSUP; 5470Sstevel@tonic-gate break; 5480Sstevel@tonic-gate case DDI_INTROP_ALLOC: 5490Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 5500Sstevel@tonic-gate break; 5510Sstevel@tonic-gate case DDI_INTROP_FREE: 5520Sstevel@tonic-gate break; 5530Sstevel@tonic-gate case DDI_INTROP_GETPRI: 5540Sstevel@tonic-gate *(int *)result = ip->is_pil ? 5550Sstevel@tonic-gate ip->is_pil : px_class_to_pil(rdip); 5560Sstevel@tonic-gate break; 5570Sstevel@tonic-gate case DDI_INTROP_SETPRI: 5580Sstevel@tonic-gate ip->is_pil = (*(int *)result); 5590Sstevel@tonic-gate break; 5600Sstevel@tonic-gate case DDI_INTROP_ADDISR: 5610Sstevel@tonic-gate hdlp->ih_vector = *ip->is_intr; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate ret = px_add_intx_intr(dip, rdip, hdlp); 5640Sstevel@tonic-gate break; 5650Sstevel@tonic-gate case DDI_INTROP_REMISR: 5660Sstevel@tonic-gate hdlp->ih_vector = *ip->is_intr; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate ret = px_rem_intx_intr(dip, rdip, hdlp); 5690Sstevel@tonic-gate break; 5700Sstevel@tonic-gate case DDI_INTROP_ENABLE: 5710Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 5720Sstevel@tonic-gate *ip->is_intr, PX_INTR_STATE_ENABLE); 5730Sstevel@tonic-gate break; 5740Sstevel@tonic-gate case DDI_INTROP_DISABLE: 5750Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 5760Sstevel@tonic-gate *ip->is_intr, PX_INTR_STATE_DISABLE); 5770Sstevel@tonic-gate break; 5780Sstevel@tonic-gate case DDI_INTROP_SETMASK: 5790Sstevel@tonic-gate ret = pci_intx_set_mask(rdip); 5800Sstevel@tonic-gate break; 5810Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 5820Sstevel@tonic-gate ret = pci_intx_clr_mask(rdip); 5830Sstevel@tonic-gate break; 5840Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 5850Sstevel@tonic-gate ret = pci_intx_get_pending(rdip, (int *)result); 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate case DDI_INTROP_NINTRS: 5880Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5890Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip); 5900Sstevel@tonic-gate break; 5910Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 5920Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 5930Sstevel@tonic-gate break; 5940Sstevel@tonic-gate default: 5950Sstevel@tonic-gate ret = DDI_ENOTSUP; 5960Sstevel@tonic-gate break; 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate return (ret); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* ARGSUSED */ 6030Sstevel@tonic-gate int 6040Sstevel@tonic-gate px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 6050Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 6060Sstevel@tonic-gate { 6070Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 6080Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 6090Sstevel@tonic-gate msinum_t msi_num; 6100Sstevel@tonic-gate msiqid_t msiq_id; 6110Sstevel@tonic-gate uint_t nintrs; 6120Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x " 6150Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate switch (intr_op) { 6180Sstevel@tonic-gate case DDI_INTROP_GETCAP: 6190Sstevel@tonic-gate ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result); 6200Sstevel@tonic-gate break; 6210Sstevel@tonic-gate case DDI_INTROP_SETCAP: 6220Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: SetCap is not supported\n"); 6230Sstevel@tonic-gate ret = DDI_ENOTSUP; 6240Sstevel@tonic-gate break; 6250Sstevel@tonic-gate case DDI_INTROP_ALLOC: 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * We need to restrict this allocation in future 6280Sstevel@tonic-gate * based on Resource Management policies. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate if ((ret = px_msi_alloc(px_p, rdip, hdlp->ih_inum, 6310Sstevel@tonic-gate hdlp->ih_scratch1, hdlp->ih_scratch2, &msi_num, 6320Sstevel@tonic-gate (int *)result)) != DDI_SUCCESS) { 6330Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: MSI allocation " 6340Sstevel@tonic-gate "failed, rdip 0x%p inum 0x%x count 0x%x\n", 6350Sstevel@tonic-gate rdip, hdlp->ih_inum, hdlp->ih_scratch1); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate return (ret); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate break; 6410Sstevel@tonic-gate case DDI_INTROP_FREE: 6420Sstevel@tonic-gate (void) pci_msi_disable_mode(rdip, hdlp->ih_type, hdlp->ih_inum); 6430Sstevel@tonic-gate (void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum); 6440Sstevel@tonic-gate (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 6450Sstevel@tonic-gate hdlp->ih_scratch1); 6460Sstevel@tonic-gate break; 6470Sstevel@tonic-gate case DDI_INTROP_GETPRI: 6480Sstevel@tonic-gate *(int *)result = hdlp->ih_pri ? 6490Sstevel@tonic-gate hdlp->ih_pri : px_class_to_pil(rdip); 6500Sstevel@tonic-gate break; 6510Sstevel@tonic-gate case DDI_INTROP_SETPRI: 6520Sstevel@tonic-gate break; 6530Sstevel@tonic-gate case DDI_INTROP_ADDISR: 6540Sstevel@tonic-gate if ((ret = px_msi_get_msinum(px_p, hdlp->ih_dip, 6550Sstevel@tonic-gate hdlp->ih_inum, &msi_num)) != DDI_SUCCESS) 6560Sstevel@tonic-gate return (ret); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 6590Sstevel@tonic-gate MSI32_REC, msi_num, &msiq_id)) != DDI_SUCCESS) { 6600Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler " 6610Sstevel@tonic-gate "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 6620Sstevel@tonic-gate return (ret); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if ((ret = px_lib_msi_setmsiq(dip, msi_num, 6680Sstevel@tonic-gate msiq_id, MSI32_TYPE)) != DDI_SUCCESS) { 6690Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 6700Sstevel@tonic-gate hdlp, MSI32_REC, msi_num, msiq_id); 6710Sstevel@tonic-gate return (ret); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 6750Sstevel@tonic-gate PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) { 6760Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 6770Sstevel@tonic-gate hdlp, MSI32_REC, msi_num, msiq_id); 6780Sstevel@tonic-gate return (ret); 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate hdlp->ih_vector = msi_num; 6820Sstevel@tonic-gate break; 6830Sstevel@tonic-gate case DDI_INTROP_DUPVEC: 6840Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: DupIsr is not supported\n"); 6850Sstevel@tonic-gate ret = DDI_ENOTSUP; 6860Sstevel@tonic-gate break; 6870Sstevel@tonic-gate case DDI_INTROP_REMISR: 6880Sstevel@tonic-gate msi_num = hdlp->ih_vector; 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate if ((ret = px_lib_msi_getmsiq(dip, msi_num, 6910Sstevel@tonic-gate &msiq_id)) != DDI_SUCCESS) 6920Sstevel@tonic-gate return (ret); 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 6950Sstevel@tonic-gate PCI_MSI_STATE_DELIVERED)) != DDI_SUCCESS) 6960Sstevel@tonic-gate return (ret); 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate ret = px_rem_msiq_intr(dip, rdip, 6990Sstevel@tonic-gate hdlp, MSI32_REC, msi_num, msiq_id); 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate hdlp->ih_vector = 0; 7020Sstevel@tonic-gate break; 7030Sstevel@tonic-gate case DDI_INTROP_ENABLE: 7040Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate if ((ret = px_lib_msi_setvalid(dip, msi_num, 7070Sstevel@tonic-gate PCI_MSI_VALID)) != DDI_SUCCESS) 7080Sstevel@tonic-gate return (ret); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate if (pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) { 7110Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 7140Sstevel@tonic-gate nintrs, hdlp->ih_inum, msi_state_p->msi_addr32, 7150Sstevel@tonic-gate msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7160Sstevel@tonic-gate return (ret); 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate if ((ret = pci_msi_enable_mode(rdip, hdlp->ih_type, 7190Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7200Sstevel@tonic-gate return (ret); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate break; 7260Sstevel@tonic-gate case DDI_INTROP_DISABLE: 7270Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if ((ret = pci_msi_set_mask(rdip, hdlp->ih_type, 7300Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7310Sstevel@tonic-gate return (ret); 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate ret = px_lib_msi_setvalid(dip, msi_num, PCI_MSI_INVALID); 7340Sstevel@tonic-gate break; 7350Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 7360Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7370Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 7400Sstevel@tonic-gate nintrs, hdlp->ih_inum, msi_state_p->msi_addr32, 7410Sstevel@tonic-gate msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7420Sstevel@tonic-gate return (ret); 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate for (i = 0; i < nintrs; i++, msi_num++) { 7450Sstevel@tonic-gate if ((ret = px_lib_msi_setvalid(dip, msi_num, 7460Sstevel@tonic-gate PCI_MSI_VALID)) != DDI_SUCCESS) 7470Sstevel@tonic-gate return (ret); 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate ret = pci_msi_enable_mode(rdip, hdlp->ih_type, hdlp->ih_inum); 7510Sstevel@tonic-gate break; 7520Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 7530Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7540Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type, 7570Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7580Sstevel@tonic-gate return (ret); 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate for (i = 0; i < nintrs; i++, msi_num++) { 7610Sstevel@tonic-gate if ((ret = px_lib_msi_setvalid(dip, msi_num, 7620Sstevel@tonic-gate PCI_MSI_INVALID)) != DDI_SUCCESS) 7630Sstevel@tonic-gate return (ret); 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate break; 7670Sstevel@tonic-gate case DDI_INTROP_SETMASK: 7680Sstevel@tonic-gate ret = pci_msi_set_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7690Sstevel@tonic-gate break; 7700Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 7710Sstevel@tonic-gate ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7720Sstevel@tonic-gate break; 7730Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 7740Sstevel@tonic-gate ret = pci_msi_get_pending(rdip, hdlp->ih_type, 7750Sstevel@tonic-gate hdlp->ih_inum, (int *)result); 7760Sstevel@tonic-gate break; 7770Sstevel@tonic-gate case DDI_INTROP_NINTRS: 7780Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 7790Sstevel@tonic-gate break; 7800Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 7810Sstevel@tonic-gate /* XXX - a new interface may be needed */ 7820Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 7830Sstevel@tonic-gate break; 7840Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 7850Sstevel@tonic-gate ret = pci_msi_get_supported_type(rdip, (int *)result); 7860Sstevel@tonic-gate break; 7870Sstevel@tonic-gate default: 7880Sstevel@tonic-gate ret = DDI_ENOTSUP; 7890Sstevel@tonic-gate break; 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate return (ret); 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate 79566Sesolom static struct { 79666Sesolom kstat_named_t pxintr_ks_name; 79766Sesolom kstat_named_t pxintr_ks_type; 79866Sesolom kstat_named_t pxintr_ks_cpu; 79966Sesolom kstat_named_t pxintr_ks_pil; 80066Sesolom kstat_named_t pxintr_ks_time; 80166Sesolom kstat_named_t pxintr_ks_ino; 80266Sesolom kstat_named_t pxintr_ks_cookie; 80366Sesolom kstat_named_t pxintr_ks_devpath; 80466Sesolom kstat_named_t pxintr_ks_buspath; 80566Sesolom } pxintr_ks_template = { 80666Sesolom { "name", KSTAT_DATA_CHAR }, 80766Sesolom { "type", KSTAT_DATA_CHAR }, 80866Sesolom { "cpu", KSTAT_DATA_UINT64 }, 80966Sesolom { "pil", KSTAT_DATA_UINT64 }, 81066Sesolom { "time", KSTAT_DATA_UINT64 }, 81166Sesolom { "ino", KSTAT_DATA_UINT64 }, 81266Sesolom { "cookie", KSTAT_DATA_UINT64 }, 81366Sesolom { "devpath", KSTAT_DATA_STRING }, 81466Sesolom { "buspath", KSTAT_DATA_STRING }, 81566Sesolom }; 81666Sesolom 81766Sesolom static uint32_t pxintr_ks_instance; 81866Sesolom kmutex_t pxintr_ks_template_lock; 81966Sesolom 82066Sesolom int 82166Sesolom px_ks_update(kstat_t *ksp, int rw) 82266Sesolom { 82366Sesolom px_ih_t *ih_p = ksp->ks_private; 82466Sesolom int maxlen = sizeof (pxintr_ks_template.pxintr_ks_name.value.c); 82566Sesolom px_ib_t *ib_p = ih_p->ih_ino_p->ino_ib_p; 82666Sesolom px_t *px_p = ib_p->ib_px_p; 82766Sesolom devino_t ino; 82866Sesolom sysino_t sysino; 82966Sesolom char ih_devpath[MAXPATHLEN]; 83066Sesolom char ih_buspath[MAXPATHLEN]; 83166Sesolom 83266Sesolom ino = ih_p->ih_ino_p->ino_ino; 83366Sesolom (void) px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino); 83466Sesolom 83566Sesolom (void) snprintf(pxintr_ks_template.pxintr_ks_name.value.c, maxlen, 83666Sesolom "%s%d", ddi_driver_name(ih_p->ih_dip), 83766Sesolom ddi_get_instance(ih_p->ih_dip)); 83866Sesolom 83966Sesolom (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 84066Sesolom (ih_p->ih_rec_type == 0) ? "fixed" : "msi"); 84166Sesolom pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ih_p->ih_ino_p->ino_cpuid; 84266Sesolom pxintr_ks_template.pxintr_ks_pil.value.ui64 = ih_p->ih_ino_p->ino_pil; 84366Sesolom pxintr_ks_template.pxintr_ks_time.value.ui64 = 84466Sesolom ih_p->ih_nsec + (uint64_t) 84566Sesolom tick2ns((hrtime_t)ih_p->ih_ticks, ih_p->ih_ino_p->ino_cpuid); 84666Sesolom pxintr_ks_template.pxintr_ks_ino.value.ui64 = ino; 84766Sesolom pxintr_ks_template.pxintr_ks_cookie.value.ui64 = sysino; 84866Sesolom 84966Sesolom (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 85066Sesolom (void) ddi_pathname(px_p->px_dip, ih_buspath); 85166Sesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_devpath, ih_devpath); 85266Sesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_buspath, ih_buspath); 85366Sesolom 85466Sesolom return (0); 85566Sesolom } 85666Sesolom 85766Sesolom void 85866Sesolom px_create_intr_kstats(px_ih_t *ih_p) 85966Sesolom { 86066Sesolom msiq_rec_type_t rec_type = ih_p->ih_rec_type; 86166Sesolom 86266Sesolom ASSERT(ih_p->ih_ksp == NULL); 86366Sesolom 86466Sesolom /* 86566Sesolom * Create pci_intrs::: kstats for all ih types except messages, 86666Sesolom * which represent unusual conditions and don't need to be tracked. 86766Sesolom */ 86866Sesolom if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 86966Sesolom ih_p->ih_ksp = kstat_create("pci_intrs", 87066Sesolom atomic_inc_32_nv(&pxintr_ks_instance), "config", 87166Sesolom "interrupts", KSTAT_TYPE_NAMED, 87266Sesolom sizeof (pxintr_ks_template) / sizeof (kstat_named_t), 87366Sesolom KSTAT_FLAG_VIRTUAL); 87466Sesolom } 87566Sesolom if (ih_p->ih_ksp != NULL) { 87666Sesolom ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 87766Sesolom ih_p->ih_ksp->ks_lock = &pxintr_ks_template_lock; 87866Sesolom ih_p->ih_ksp->ks_data = &pxintr_ks_template; 87966Sesolom ih_p->ih_ksp->ks_private = ih_p; 88066Sesolom ih_p->ih_ksp->ks_update = px_ks_update; 88166Sesolom } 88266Sesolom } 88366Sesolom 8840Sstevel@tonic-gate int 8850Sstevel@tonic-gate px_add_intx_intr(dev_info_t *dip, dev_info_t *rdip, 8860Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 8870Sstevel@tonic-gate { 8880Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 8890Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 8900Sstevel@tonic-gate devino_t ino; 8910Sstevel@tonic-gate px_ih_t *ih_p; 8920Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 8930Sstevel@tonic-gate int32_t weight; 8940Sstevel@tonic-gate int ret = DDI_SUCCESS; 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate ino = hdlp->ih_vector; 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: rdip=%s%d ino=%x " 8990Sstevel@tonic-gate "handler=%x arg1=%x arg2=%x\n", ddi_driver_name(rdip), 9000Sstevel@tonic-gate ddi_get_instance(rdip), ino, hdlp->ih_cb_func, 9010Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, 9040Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, 0, 0); 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { /* sharing ino */ 9090Sstevel@tonic-gate uint32_t intr_index = hdlp->ih_inum; 9100Sstevel@tonic-gate if (px_ib_ino_locate_intr(ino_p, rdip, intr_index, 0, 0)) { 9110Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: " 9120Sstevel@tonic-gate "dup intr #%d\n", intr_index); 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate ret = DDI_FAILURE; 9150Sstevel@tonic-gate goto fail1; 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate /* Save mondo value in hdlp */ 9190Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate if ((ret = px_ib_ino_add_intr(px_p, ino_p, ih_p)) 9220Sstevel@tonic-gate != DDI_SUCCESS) 9230Sstevel@tonic-gate goto fail1; 9240Sstevel@tonic-gate } else { 9250Sstevel@tonic-gate ino_p = px_ib_new_ino(ib_p, ino, ih_p); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate if (hdlp->ih_pri == 0) 9280Sstevel@tonic-gate hdlp->ih_pri = px_class_to_pil(rdip); 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate /* Save mondo value in hdlp */ 9310Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: pil=0x%x mondo=0x%x\n", 9340Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector); 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 9370Sstevel@tonic-gate (ddi_intr_handler_t *)px_intx_intr, (caddr_t)ino_p, NULL); 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* 9420Sstevel@tonic-gate * Restore original interrupt handler 9430Sstevel@tonic-gate * and arguments in interrupt handle. 9440Sstevel@tonic-gate */ 9450Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 9460Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if (ret != DDI_SUCCESS) 9490Sstevel@tonic-gate goto fail2; 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate /* Save the pil for this ino */ 9520Sstevel@tonic-gate ino_p->ino_pil = hdlp->ih_pri; 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate /* select cpu, saving it for sharing and removal */ 9550Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate /* Enable interrupt */ 9580Sstevel@tonic-gate px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 9590Sstevel@tonic-gate } 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate /* add weight to the cpu that we are already targeting */ 9620Sstevel@tonic-gate weight = px_class_to_intr_weight(rdip); 9630Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate ih_p->ih_ino_p = ino_p; 96666Sesolom px_create_intr_kstats(ih_p); 9670Sstevel@tonic-gate if (ih_p->ih_ksp) 9680Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 9690Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: done! Interrupt 0x%x pil=%x\n", 9720Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate return (ret); 9750Sstevel@tonic-gate fail2: 9760Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 9770Sstevel@tonic-gate fail1: 9780Sstevel@tonic-gate if (ih_p->ih_config_handle) 9790Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 9820Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: Failed! Interrupt 0x%x " 9850Sstevel@tonic-gate "pil=%x\n", ino_p->ino_sysino, hdlp->ih_pri); 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate return (ret); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate int 9910Sstevel@tonic-gate px_rem_intx_intr(dev_info_t *dip, dev_info_t *rdip, 9920Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 9930Sstevel@tonic-gate { 9940Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 9950Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 9960Sstevel@tonic-gate devino_t ino; 9970Sstevel@tonic-gate cpuid_t curr_cpu; 9980Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 9990Sstevel@tonic-gate px_ih_t *ih_p; 10000Sstevel@tonic-gate int ret = DDI_SUCCESS; 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate ino = hdlp->ih_vector; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate DBG(DBG_R_INTX, dip, "px_rem_intx_intr: rdip=%s%d ino=%x\n", 10050Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 10100Sstevel@tonic-gate ih_p = px_ib_ino_locate_intr(ino_p, rdip, hdlp->ih_inum, 0, 0); 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate /* Get the current cpu */ 10130Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 10140Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 10150Sstevel@tonic-gate goto fail; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate if ((ret = px_ib_ino_rem_intr(px_p, ino_p, ih_p)) != DDI_SUCCESS) 10180Sstevel@tonic-gate goto fail; 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate if (ino_p->ino_ih_size == 0) { 10230Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 10240Sstevel@tonic-gate INTR_DELIVERED_STATE)) != DDI_SUCCESS) 10250Sstevel@tonic-gate goto fail; 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 10280Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 10310Sstevel@tonic-gate kmem_free(ino_p, sizeof (px_ib_ino_info_t)); 10320Sstevel@tonic-gate } else { 10330Sstevel@tonic-gate /* Re-enable interrupt only if mapping regsiter still shared */ 10340Sstevel@tonic-gate if ((ret = px_lib_intr_settarget(px_p->px_dip, 10350Sstevel@tonic-gate ino_p->ino_sysino, curr_cpu)) != DDI_SUCCESS) 10360Sstevel@tonic-gate goto fail; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate ret = px_lib_intr_setvalid(px_p->px_dip, ino_p->ino_sysino, 10390Sstevel@tonic-gate INTR_VALID); 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate fail: 10430Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10440Sstevel@tonic-gate return (ret); 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate int 10480Sstevel@tonic-gate px_add_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 10490Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 10500Sstevel@tonic-gate msgcode_t msg_code, msiqid_t *msiq_id_p) 10510Sstevel@tonic-gate { 10520Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 10530Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 10540Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 10550Sstevel@tonic-gate devino_t ino; 10560Sstevel@tonic-gate px_ih_t *ih_p; 10570Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 10580Sstevel@tonic-gate int32_t weight; 10590Sstevel@tonic-gate int ret = DDI_SUCCESS; 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: rdip=%s%d handler=%x " 10620Sstevel@tonic-gate "arg1=%x arg2=%x\n", ddi_driver_name(rdip), ddi_get_instance(rdip), 10630Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate if ((ret = px_msiq_alloc(px_p, rec_type, msiq_id_p)) != DDI_SUCCESS) { 10660Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 10670Sstevel@tonic-gate "msiq allocation failed\n"); 10680Sstevel@tonic-gate return (ret); 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate ino = px_msiqid_to_devino(px_p, *msiq_id_p); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, hdlp->ih_cb_func, 10740Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rec_type, msg_code); 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { /* sharing ino */ 10790Sstevel@tonic-gate uint32_t intr_index = hdlp->ih_inum; 10800Sstevel@tonic-gate if (px_ib_ino_locate_intr(ino_p, rdip, 10810Sstevel@tonic-gate intr_index, rec_type, msg_code)) { 10820Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 10830Sstevel@tonic-gate "dup intr #%d\n", intr_index); 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate ret = DDI_FAILURE; 10860Sstevel@tonic-gate goto fail1; 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate if ((ret = px_ib_ino_add_intr(px_p, ino_p, ih_p)) 10900Sstevel@tonic-gate != DDI_SUCCESS) 10910Sstevel@tonic-gate goto fail1; 10920Sstevel@tonic-gate } else { 10930Sstevel@tonic-gate ino_p = px_ib_new_ino(ib_p, ino, ih_p); 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate ino_p->ino_msiq_p = msiq_state_p->msiq_p + 10960Sstevel@tonic-gate (*msiq_id_p - msiq_state_p->msiq_1st_msiq_id); 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate if (hdlp->ih_pri == 0) 10990Sstevel@tonic-gate hdlp->ih_pri = px_class_to_pil(rdip); 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* Save mondo value in hdlp */ 11020Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: pil=0x%x mondo=0x%x\n", 11050Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector); 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 11080Sstevel@tonic-gate (ddi_intr_handler_t *)px_msiq_intr, (caddr_t)ino_p, NULL); 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate /* 11130Sstevel@tonic-gate * Restore original interrupt handler 11140Sstevel@tonic-gate * and arguments in interrupt handle. 11150Sstevel@tonic-gate */ 11160Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 11170Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate if (ret != DDI_SUCCESS) 11200Sstevel@tonic-gate goto fail2; 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate /* Save the pil for this ino */ 11230Sstevel@tonic-gate ino_p->ino_pil = hdlp->ih_pri; 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate /* Enable MSIQ */ 11260Sstevel@tonic-gate px_lib_msiq_setstate(dip, *msiq_id_p, PCI_MSIQ_STATE_IDLE); 11270Sstevel@tonic-gate px_lib_msiq_setvalid(dip, *msiq_id_p, PCI_MSIQ_VALID); 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /* select cpu, saving it for sharing and removal */ 11300Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate /* Enable interrupt */ 11330Sstevel@tonic-gate px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino_p->ino_ino); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate /* add weight to the cpu that we are already targeting */ 11370Sstevel@tonic-gate weight = px_class_to_intr_weight(rdip); 11380Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate ih_p->ih_ino_p = ino_p; 114166Sesolom px_create_intr_kstats(ih_p); 11420Sstevel@tonic-gate if (ih_p->ih_ksp) 11430Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 11440Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: done! Interrupt 0x%x pil=%x\n", 11470Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate return (ret); 11500Sstevel@tonic-gate fail2: 11510Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 11520Sstevel@tonic-gate fail1: 11530Sstevel@tonic-gate if (ih_p->ih_config_handle) 11540Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 11570Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: Failed! Interrupt 0x%x pil=%x\n", 11600Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate return (ret); 11630Sstevel@tonic-gate } 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate int 11660Sstevel@tonic-gate px_rem_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 11670Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 11680Sstevel@tonic-gate msgcode_t msg_code, msiqid_t msiq_id) 11690Sstevel@tonic-gate { 11700Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 11710Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 11720Sstevel@tonic-gate devino_t ino = px_msiqid_to_devino(px_p, msiq_id); 11730Sstevel@tonic-gate cpuid_t curr_cpu; 11740Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 11750Sstevel@tonic-gate px_ih_t *ih_p; 11760Sstevel@tonic-gate int ret = DDI_SUCCESS; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_rem_msiq_intr: rdip=%s%d msiq_id=%x ino=%x\n", 11790Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), msiq_id, ino); 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 11840Sstevel@tonic-gate ih_p = px_ib_ino_locate_intr(ino_p, rdip, hdlp->ih_inum, 11850Sstevel@tonic-gate rec_type, msg_code); 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate /* Get the current cpu */ 11880Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 11890Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 11900Sstevel@tonic-gate goto fail; 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate if ((ret = px_ib_ino_rem_intr(px_p, ino_p, ih_p)) != DDI_SUCCESS) 11930Sstevel@tonic-gate goto fail; 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate if (ino_p->ino_ih_size == 0) { 11980Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 11990Sstevel@tonic-gate INTR_DELIVERED_STATE)) != DDI_SUCCESS) 12000Sstevel@tonic-gate goto fail; 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate px_lib_msiq_setvalid(dip, px_devino_to_msiqid(px_p, ino), 12030Sstevel@tonic-gate PCI_MSIQ_INVALID); 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 12060Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate (void) px_msiq_free(px_p, msiq_id); 12110Sstevel@tonic-gate kmem_free(ino_p, sizeof (px_ib_ino_info_t)); 12120Sstevel@tonic-gate } else { 12130Sstevel@tonic-gate /* Re-enable interrupt only if mapping regsiter still shared */ 12140Sstevel@tonic-gate if ((ret = px_lib_intr_settarget(px_p->px_dip, 121527Sjchu ino_p->ino_sysino, curr_cpu)) != DDI_SUCCESS) 12160Sstevel@tonic-gate goto fail; 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate ret = px_lib_intr_setvalid(px_p->px_dip, ino_p->ino_sysino, 12190Sstevel@tonic-gate INTR_VALID); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate fail: 12230Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12240Sstevel@tonic-gate return (ret); 12250Sstevel@tonic-gate } 1226