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 51542Sjohnny * Common Development and Distribution License (the "License"). 61542Sjohnny * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 2211520SScott.Carter@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * PX nexus interrupt handling: 280Sstevel@tonic-gate * PX device interrupt handler wrapper 290Sstevel@tonic-gate * PIL lookup routine 300Sstevel@tonic-gate * PX device interrupt related initchild code 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/async.h> 360Sstevel@tonic-gate #include <sys/spl.h> 370Sstevel@tonic-gate #include <sys/sunddi.h> 3827Sjchu #include <sys/fm/protocol.h> 3927Sjchu #include <sys/fm/util.h> 400Sstevel@tonic-gate #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */ 410Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 420Sstevel@tonic-gate #include <sys/sdt.h> 430Sstevel@tonic-gate #include <sys/atomic.h> 440Sstevel@tonic-gate #include "px_obj.h" 4527Sjchu #include <sys/ontrap.h> 4627Sjchu #include <sys/membar.h> 4766Sesolom #include <sys/clock.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * interrupt jabber: 510Sstevel@tonic-gate * 520Sstevel@tonic-gate * When an interrupt line is jabbering, every time the state machine for the 530Sstevel@tonic-gate * associated ino is idled, a new mondo will be sent and the ino will go into 540Sstevel@tonic-gate * the pending state again. The mondo will cause a new call to 550Sstevel@tonic-gate * px_intr_wrapper() which normally idles the ino's state machine which would 560Sstevel@tonic-gate * precipitate another trip round the loop. 570Sstevel@tonic-gate * 580Sstevel@tonic-gate * The loop can be broken by preventing the ino's state machine from being 590Sstevel@tonic-gate * idled when an interrupt line is jabbering. See the comment at the 600Sstevel@tonic-gate * beginning of px_intr_wrapper() explaining how the 'interrupt jabber 610Sstevel@tonic-gate * protection' code does this. 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate /*LINTLIBRARY*/ 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * If the unclaimed interrupt count has reached the limit set by 680Sstevel@tonic-gate * pci_unclaimed_intr_max within the time limit, then all interrupts 690Sstevel@tonic-gate * on this ino is blocked by not idling the interrupt state machine. 700Sstevel@tonic-gate */ 710Sstevel@tonic-gate static int 722973Sgovinda px_spurintr(px_ino_pil_t *ipil_p) 730Sstevel@tonic-gate { 742973Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 7510596SDaniel.Ice@Sun.COM px_ih_t *ih_p; 762973Sgovinda px_t *px_p = ino_p->ino_ib_p->ib_px_p; 772973Sgovinda char *err_fmt_str; 782973Sgovinda boolean_t blocked = B_FALSE; 792973Sgovinda int i; 800Sstevel@tonic-gate 812973Sgovinda if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) 820Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 830Sstevel@tonic-gate 842973Sgovinda if (!ino_p->ino_unclaimed_intrs) 850Sstevel@tonic-gate ino_p->ino_spurintr_begin = ddi_get_lbolt(); 860Sstevel@tonic-gate 872973Sgovinda ino_p->ino_unclaimed_intrs++; 880Sstevel@tonic-gate 892973Sgovinda if (ino_p->ino_unclaimed_intrs <= px_unclaimed_intr_max) 900Sstevel@tonic-gate goto clear; 910Sstevel@tonic-gate 920Sstevel@tonic-gate if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin) 930Sstevel@tonic-gate > px_spurintr_duration) { 942973Sgovinda ino_p->ino_unclaimed_intrs = 0; 950Sstevel@tonic-gate goto clear; 960Sstevel@tonic-gate } 970Sstevel@tonic-gate err_fmt_str = "%s%d: ino 0x%x blocked"; 982973Sgovinda blocked = B_TRUE; 990Sstevel@tonic-gate goto warn; 1000Sstevel@tonic-gate clear: 1010Sstevel@tonic-gate err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; 1020Sstevel@tonic-gate warn: 1030Sstevel@tonic-gate cmn_err(CE_WARN, err_fmt_str, NAMEINST(px_p->px_dip), ino_p->ino_ino); 10410596SDaniel.Ice@Sun.COM for (ipil_p = ino_p->ino_ipil_p; ipil_p; 10510596SDaniel.Ice@Sun.COM ipil_p = ipil_p->ipil_next_p) { 10610596SDaniel.Ice@Sun.COM for (i = 0, ih_p = ipil_p->ipil_ih_start; 10710596SDaniel.Ice@Sun.COM i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) 10810596SDaniel.Ice@Sun.COM cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), 10910596SDaniel.Ice@Sun.COM ih_p->ih_inum); 11010596SDaniel.Ice@Sun.COM } 1110Sstevel@tonic-gate cmn_err(CE_CONT, "!\n"); 1122973Sgovinda 1132973Sgovinda /* Clear the pending state */ 1142973Sgovinda if (blocked == B_FALSE) { 1152973Sgovinda if (px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 1162973Sgovinda INTR_IDLE_STATE) != DDI_SUCCESS) 1172973Sgovinda return (DDI_INTR_UNCLAIMED); 1182973Sgovinda } 1192973Sgovinda 1200Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate extern uint64_t intr_get_time(void); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* 126693Sgovinda * px_intx_intr (INTx or legacy interrupt handler) 1270Sstevel@tonic-gate * 1280Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 1290Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 1300Sstevel@tonic-gate * examines the return codes. 1310Sstevel@tonic-gate * 1320Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 1330Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 1340Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 1350Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 1360Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 1370Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 1380Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 1390Sstevel@tonic-gate * handler is subsequently added or removed. 1400Sstevel@tonic-gate * 1410Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 1420Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 1430Sstevel@tonic-gate */ 1440Sstevel@tonic-gate uint_t 1450Sstevel@tonic-gate px_intx_intr(caddr_t arg) 1460Sstevel@tonic-gate { 1472973Sgovinda px_ino_pil_t *ipil_p = (px_ino_pil_t *)arg; 1482973Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 1490Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 1502973Sgovinda px_ih_t *ih_p = ipil_p->ipil_ih_start; 1512973Sgovinda ushort_t pil = ipil_p->ipil_pil; 1522973Sgovinda uint_t result = 0, r = DDI_INTR_UNCLAIMED; 1530Sstevel@tonic-gate int i; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1560Sstevel@tonic-gate "ino=%x sysino=%llx pil=%x ih_size=%x ih_lst=%x\n", 1572973Sgovinda ino_p->ino_ino, ino_p->ino_sysino, ipil_p->ipil_pil, 1582973Sgovinda ipil_p->ipil_ih_size, ipil_p->ipil_ih_head); 1590Sstevel@tonic-gate 1602973Sgovinda for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 1610Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip; 1620Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 1630Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 1640Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate if (ih_p->ih_intr_state == PX_INTR_STATE_DISABLE) { 1670Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, 1680Sstevel@tonic-gate "px_intx_intr: %s%d interrupt %d is disabled\n", 1690Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1700Sstevel@tonic-gate ino_p->ino_ino); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate continue; 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1760Sstevel@tonic-gate "ino=%x handler=%p arg1 =%p arg2 = %p\n", 1770Sstevel@tonic-gate ino_p->ino_ino, handler, arg1, arg2); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 1800Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate r = (*handler)(arg1, arg2); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate /* 1850Sstevel@tonic-gate * Account for time used by this interrupt. Protect against 1860Sstevel@tonic-gate * conflicting writes to ih_ticks from ib_intr_dist_all() by 1870Sstevel@tonic-gate * using atomic ops. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate 1902973Sgovinda if (pil <= LOCK_LEVEL) 1910Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 1940Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, r); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate result += r; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate if (px_check_all_handlers) 1990Sstevel@tonic-gate continue; 2000Sstevel@tonic-gate if (result) 2010Sstevel@tonic-gate break; 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2042973Sgovinda if (result) 2052973Sgovinda ino_p->ino_claimed |= (1 << pil); 2062973Sgovinda 2072973Sgovinda /* Interrupt can only be cleared after all pil levels are handled */ 2082973Sgovinda if (pil != ino_p->ino_lopil) 2092973Sgovinda return (DDI_INTR_CLAIMED); 2100Sstevel@tonic-gate 2112973Sgovinda if (!ino_p->ino_claimed) { 2122973Sgovinda if (px_unclaimed_intr_block) 2132973Sgovinda return (px_spurintr(ipil_p)); 2142973Sgovinda } 2152973Sgovinda 2162973Sgovinda ino_p->ino_unclaimed_intrs = 0; 2172973Sgovinda ino_p->ino_claimed = 0; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* Clear the pending state */ 2202973Sgovinda if (px_lib_intr_setstate(px_p->px_dip, 2210Sstevel@tonic-gate ino_p->ino_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 2220Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* 228693Sgovinda * px_msiq_intr (MSI/X or PCIe MSG interrupt handler) 2290Sstevel@tonic-gate * 2300Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 2310Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 2320Sstevel@tonic-gate * examines the return codes. 2330Sstevel@tonic-gate * 2340Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 2350Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 2360Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 2370Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 2380Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 2390Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 2400Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 2410Sstevel@tonic-gate * handler is subsequently added or removed. 2420Sstevel@tonic-gate * 2430Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 2440Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate uint_t 2470Sstevel@tonic-gate px_msiq_intr(caddr_t arg) 2480Sstevel@tonic-gate { 2492973Sgovinda px_ino_pil_t *ipil_p = (px_ino_pil_t *)arg; 2502973Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 2510Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 2520Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 2530Sstevel@tonic-gate px_msiq_t *msiq_p = ino_p->ino_msiq_p; 2540Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 2552973Sgovinda ushort_t pil = ipil_p->ipil_pil; 2560Sstevel@tonic-gate msiq_rec_t msiq_rec, *msiq_rec_p = &msiq_rec; 2572588Segillett msiqhead_t *curr_head_p; 2582588Segillett msiqtail_t curr_tail_index; 2590Sstevel@tonic-gate msgcode_t msg_code; 2600Sstevel@tonic-gate px_ih_t *ih_p; 2612973Sgovinda uint_t ret = DDI_INTR_UNCLAIMED; 2622973Sgovinda int i, j; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x " 2650Sstevel@tonic-gate "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino, 2662973Sgovinda ipil_p->ipil_pil, ipil_p->ipil_ih_size, ipil_p->ipil_ih_head); 2672973Sgovinda 2682973Sgovinda /* 2692973Sgovinda * The px_msiq_intr() handles multiple interrupt priorities and it 2702973Sgovinda * will set msiq->msiq_rec2process to the number of MSIQ records to 2712973Sgovinda * process while handling the highest priority interrupt. Subsequent 2722973Sgovinda * lower priority interrupts will just process any unprocessed MSIQ 2732973Sgovinda * records or will just return immediately. 2742973Sgovinda */ 2752973Sgovinda if (msiq_p->msiq_recs2process == 0) { 27610596SDaniel.Ice@Sun.COM ASSERT(ino_p->ino_ipil_cntr == 0); 27710596SDaniel.Ice@Sun.COM ino_p->ino_ipil_cntr = ino_p->ino_ipil_size; 27810596SDaniel.Ice@Sun.COM 2792973Sgovinda /* Read current MSIQ tail index */ 2802973Sgovinda px_lib_msiq_gettail(dip, msiq_p->msiq_id, &curr_tail_index); 2812973Sgovinda msiq_p->msiq_new_head_index = msiq_p->msiq_curr_head_index; 2820Sstevel@tonic-gate 2832973Sgovinda if (curr_tail_index < msiq_p->msiq_curr_head_index) 2842973Sgovinda curr_tail_index += msiq_state_p->msiq_rec_cnt; 2852973Sgovinda 2862973Sgovinda msiq_p->msiq_recs2process = curr_tail_index - 2872973Sgovinda msiq_p->msiq_curr_head_index; 2882973Sgovinda } 2890Sstevel@tonic-gate 2902973Sgovinda DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x " 2912973Sgovinda "rec2process %x\n", msiq_p->msiq_curr_head_index, 2922973Sgovinda msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process); 2932973Sgovinda 2942973Sgovinda /* If all MSIQ records are already processed, just return immediately */ 2952973Sgovinda if ((msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index) 2962973Sgovinda == msiq_p->msiq_recs2process) 2972973Sgovinda goto intr_done; 2982973Sgovinda 2992973Sgovinda curr_head_p = (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p + 3002973Sgovinda (msiq_p->msiq_curr_head_index * sizeof (msiq_rec_t))); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /* 3032588Segillett * Calculate the number of recs to process by taking the difference 3042588Segillett * between the head and tail pointers. For all records we always 3052588Segillett * verify that we have a valid record type before we do any processing. 3062973Sgovinda * If triggered, we should always have at least one valid record. 3070Sstevel@tonic-gate */ 3082973Sgovinda for (i = 0; i < msiq_p->msiq_recs2process; i++) { 3099686SAlan.Adamson@Sun.COM msiq_rec_type_t rec_type; 3109686SAlan.Adamson@Sun.COM 3112973Sgovinda /* Read next MSIQ record */ 3122588Segillett px_lib_get_msiq_rec(dip, curr_head_p, msiq_rec_p); 3132588Segillett 3149686SAlan.Adamson@Sun.COM rec_type = msiq_rec_p->msiq_rec_type; 3159686SAlan.Adamson@Sun.COM 3160Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, " 3170Sstevel@tonic-gate "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n", 3189686SAlan.Adamson@Sun.COM rec_type, msiq_rec_p->msiq_rec_rid); 3190Sstevel@tonic-gate 3209686SAlan.Adamson@Sun.COM if (!rec_type) 3212973Sgovinda goto next_rec; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate /* Check MSIQ record type */ 3249686SAlan.Adamson@Sun.COM switch (rec_type) { 3250Sstevel@tonic-gate case MSG_REC: 3260Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msg.msg_code; 3270Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: PCIE MSG " 3280Sstevel@tonic-gate "record, msg type 0x%x\n", msg_code); 3290Sstevel@tonic-gate break; 3300Sstevel@tonic-gate case MSI32_REC: 3310Sstevel@tonic-gate case MSI64_REC: 3320Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data; 3330Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, " 3340Sstevel@tonic-gate "msi 0x%x\n", msg_code); 3350Sstevel@tonic-gate break; 3360Sstevel@tonic-gate default: 3370Sstevel@tonic-gate msg_code = 0; 3380Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_msiq_intr: 0x%x MSIQ " 3390Sstevel@tonic-gate "record type is not supported", 3400Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 3419686SAlan.Adamson@Sun.COM rec_type); 3422973Sgovinda 3430Sstevel@tonic-gate goto next_rec; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * Scan through px_ih_t linked list, searching for the 3480Sstevel@tonic-gate * right px_ih_t, matching MSIQ record data. 3490Sstevel@tonic-gate */ 3502973Sgovinda for (j = 0, ih_p = ipil_p->ipil_ih_start; 3512973Sgovinda ih_p && (j < ipil_p->ipil_ih_size) && 3521653Sgovinda ((ih_p->ih_msg_code != msg_code) || 3539686SAlan.Adamson@Sun.COM (ih_p->ih_rec_type != rec_type)); 3544397Sschwartz ih_p = ih_p->ih_next, j++) 3554397Sschwartz ; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate if ((ih_p->ih_msg_code == msg_code) && 3589686SAlan.Adamson@Sun.COM (ih_p->ih_rec_type == rec_type)) { 35911520SScott.Carter@Sun.COM dev_info_t *ih_dip = ih_p->ih_dip; 3600Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 3610Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 3620Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 3630Sstevel@tonic-gate 36411520SScott.Carter@Sun.COM DBG(DBG_MSIQ_INTR, ih_dip, "px_msiq_intr: ino=%x " 36511520SScott.Carter@Sun.COM "data=%x handler=%p arg1 =%p arg2=%p\n", 36611520SScott.Carter@Sun.COM ino_p->ino_ino, msg_code, handler, arg1, arg2); 3670Sstevel@tonic-gate 36811520SScott.Carter@Sun.COM DTRACE_PROBE4(interrupt__start, dev_info_t, ih_dip, 3690Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 3700Sstevel@tonic-gate 37111520SScott.Carter@Sun.COM ih_p->ih_intr_flags = PX_INTR_PENDING; 37210053SEvan.Yan@Sun.COM 37327Sjchu /* 37427Sjchu * Special case for PCIE Error Messages. 37527Sjchu * The current frame work doesn't fit PCIE Err Msgs 37627Sjchu * This should be fixed when PCIE MESSAGES as a whole 37727Sjchu * is architected correctly. 37827Sjchu */ 3799686SAlan.Adamson@Sun.COM if ((rec_type == MSG_REC) && 3809686SAlan.Adamson@Sun.COM ((msg_code == PCIE_MSG_CODE_ERR_COR) || 38127Sjchu (msg_code == PCIE_MSG_CODE_ERR_NONFATAL) || 3829686SAlan.Adamson@Sun.COM (msg_code == PCIE_MSG_CODE_ERR_FATAL))) { 38327Sjchu ret = px_err_fabric_intr(px_p, msg_code, 38427Sjchu msiq_rec_p->msiq_rec_rid); 38511520SScott.Carter@Sun.COM } else { 38611520SScott.Carter@Sun.COM /* Clear MSI state */ 38711520SScott.Carter@Sun.COM px_lib_msi_setstate(dip, (msinum_t)msg_code, 38811520SScott.Carter@Sun.COM PCI_MSI_STATE_IDLE); 38911520SScott.Carter@Sun.COM 39027Sjchu ret = (*handler)(arg1, arg2); 39111520SScott.Carter@Sun.COM } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * Account for time used by this interrupt. Protect 3950Sstevel@tonic-gate * against conflicting writes to ih_ticks from 3960Sstevel@tonic-gate * ib_intr_dist_all() by using atomic ops. 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate 3992973Sgovinda if (pil <= LOCK_LEVEL) 4000Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 4010Sstevel@tonic-gate 40211520SScott.Carter@Sun.COM DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_dip, 4030Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, ret); 4042588Segillett 40511520SScott.Carter@Sun.COM /* clear handler status flags */ 40611520SScott.Carter@Sun.COM ih_p->ih_intr_flags = PX_INTR_IDLE; 40711520SScott.Carter@Sun.COM 4082973Sgovinda msiq_p->msiq_new_head_index++; 40911520SScott.Carter@Sun.COM px_lib_clr_msiq_rec(ih_dip, curr_head_p); 4100Sstevel@tonic-gate } else { 41111520SScott.Carter@Sun.COM DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: " 4122588Segillett "No matching MSIQ record found\n"); 4132588Segillett } 4142588Segillett next_rec: 4152588Segillett /* Get the pointer next EQ record */ 4162588Segillett curr_head_p = (msiqhead_t *) 4172588Segillett ((caddr_t)curr_head_p + sizeof (msiq_rec_t)); 4180Sstevel@tonic-gate 4192588Segillett /* Check for overflow condition */ 4202588Segillett if (curr_head_p >= (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p 4212973Sgovinda + (msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t)))) 4222588Segillett curr_head_p = (msiqhead_t *)msiq_p->msiq_base_p; 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4252973Sgovinda DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n", 4262973Sgovinda (msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index)); 4272973Sgovinda 4282973Sgovinda DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x " 4292973Sgovinda "rec2process %x\n", msiq_p->msiq_curr_head_index, 4302973Sgovinda msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process); 4312588Segillett 4322973Sgovinda /* ino_claimed used just for debugging purpose */ 4332973Sgovinda if (ret) 4342973Sgovinda ino_p->ino_claimed |= (1 << pil); 4352973Sgovinda 4362973Sgovinda intr_done: 4372973Sgovinda /* Interrupt can only be cleared after all pil levels are handled */ 43810596SDaniel.Ice@Sun.COM if (--ino_p->ino_ipil_cntr != 0) 4392973Sgovinda return (DDI_INTR_CLAIMED); 4402973Sgovinda 4412973Sgovinda if (msiq_p->msiq_new_head_index <= msiq_p->msiq_curr_head_index) { 4422973Sgovinda if (px_unclaimed_intr_block) 4432973Sgovinda return (px_spurintr(ipil_p)); 4442588Segillett } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* Update MSIQ head index with no of MSIQ records processed */ 4472973Sgovinda if (msiq_p->msiq_new_head_index >= msiq_state_p->msiq_rec_cnt) 4482973Sgovinda msiq_p->msiq_new_head_index -= msiq_state_p->msiq_rec_cnt; 4490Sstevel@tonic-gate 4502973Sgovinda msiq_p->msiq_curr_head_index = msiq_p->msiq_new_head_index; 4512973Sgovinda px_lib_msiq_sethead(dip, msiq_p->msiq_id, msiq_p->msiq_new_head_index); 4522973Sgovinda 4532973Sgovinda msiq_p->msiq_new_head_index = 0; 4542973Sgovinda msiq_p->msiq_recs2process = 0; 4552973Sgovinda ino_p->ino_claimed = 0; 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* Clear the pending state */ 4580Sstevel@tonic-gate if (px_lib_intr_setstate(dip, ino_p->ino_sysino, 4590Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 4600Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate dev_info_t * 4660Sstevel@tonic-gate px_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 4670Sstevel@tonic-gate { 4680Sstevel@tonic-gate dev_info_t *cdip = rdip; 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 4710Sstevel@tonic-gate ; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate return (cdip); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* ARGSUSED */ 4770Sstevel@tonic-gate int 4780Sstevel@tonic-gate px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 4790Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 4800Sstevel@tonic-gate { 481693Sgovinda px_t *px_p = DIP_TO_STATE(dip); 482693Sgovinda int ret = DDI_SUCCESS; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: dip=%x rdip=%x intr_op=%x " 4850Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate switch (intr_op) { 4880Sstevel@tonic-gate case DDI_INTROP_GETCAP: 4890Sstevel@tonic-gate ret = pci_intx_get_cap(rdip, (int *)result); 4900Sstevel@tonic-gate break; 4910Sstevel@tonic-gate case DDI_INTROP_SETCAP: 4920Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: SetCap is not supported\n"); 4930Sstevel@tonic-gate ret = DDI_ENOTSUP; 4940Sstevel@tonic-gate break; 4950Sstevel@tonic-gate case DDI_INTROP_ALLOC: 4960Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 4970Sstevel@tonic-gate break; 4980Sstevel@tonic-gate case DDI_INTROP_FREE: 4990Sstevel@tonic-gate break; 5000Sstevel@tonic-gate case DDI_INTROP_GETPRI: 501693Sgovinda *(int *)result = hdlp->ih_pri ? 5028535Sevan.yan@sun.com hdlp->ih_pri : pci_class_to_pil(rdip); 5030Sstevel@tonic-gate break; 5040Sstevel@tonic-gate case DDI_INTROP_SETPRI: 5050Sstevel@tonic-gate break; 5060Sstevel@tonic-gate case DDI_INTROP_ADDISR: 5070Sstevel@tonic-gate ret = px_add_intx_intr(dip, rdip, hdlp); 5080Sstevel@tonic-gate break; 5090Sstevel@tonic-gate case DDI_INTROP_REMISR: 5100Sstevel@tonic-gate ret = px_rem_intx_intr(dip, rdip, hdlp); 5110Sstevel@tonic-gate break; 51210053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET: 51310053SEvan.Yan@Sun.COM ret = px_ib_get_intr_target(px_p, hdlp->ih_vector, 51410053SEvan.Yan@Sun.COM (cpuid_t *)result); 51510053SEvan.Yan@Sun.COM break; 51610053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET: 51710053SEvan.Yan@Sun.COM ret = DDI_ENOTSUP; 51810053SEvan.Yan@Sun.COM break; 5190Sstevel@tonic-gate case DDI_INTROP_ENABLE: 5200Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 5212973Sgovinda hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_ENABLE, 0, 0); 5220Sstevel@tonic-gate break; 5230Sstevel@tonic-gate case DDI_INTROP_DISABLE: 5240Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 5252973Sgovinda hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_DISABLE, 0, 0); 5260Sstevel@tonic-gate break; 5270Sstevel@tonic-gate case DDI_INTROP_SETMASK: 5280Sstevel@tonic-gate ret = pci_intx_set_mask(rdip); 5290Sstevel@tonic-gate break; 5300Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 5310Sstevel@tonic-gate ret = pci_intx_clr_mask(rdip); 5320Sstevel@tonic-gate break; 5330Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 5340Sstevel@tonic-gate ret = pci_intx_get_pending(rdip, (int *)result); 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate case DDI_INTROP_NINTRS: 5370Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5382580Sanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 5390Sstevel@tonic-gate break; 5400Sstevel@tonic-gate default: 5410Sstevel@tonic-gate ret = DDI_ENOTSUP; 5420Sstevel@tonic-gate break; 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate return (ret); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /* ARGSUSED */ 5490Sstevel@tonic-gate int 5500Sstevel@tonic-gate px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 5510Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 5520Sstevel@tonic-gate { 5530Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5540Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 555965Sgovinda msiq_rec_type_t msiq_rec_type; 556965Sgovinda msi_type_t msi_type; 557965Sgovinda uint64_t msi_addr; 5580Sstevel@tonic-gate msinum_t msi_num; 5590Sstevel@tonic-gate msiqid_t msiq_id; 5600Sstevel@tonic-gate uint_t nintrs; 56110053SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x " 5640Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 5650Sstevel@tonic-gate 566965Sgovinda /* Check for MSI64 support */ 5671653Sgovinda if ((hdlp->ih_cap & DDI_INTR_FLAG_MSI64) && msi_state_p->msi_addr64) { 568965Sgovinda msiq_rec_type = MSI64_REC; 569965Sgovinda msi_type = MSI64_TYPE; 5701653Sgovinda msi_addr = msi_state_p->msi_addr64; 571965Sgovinda } else { 572965Sgovinda msiq_rec_type = MSI32_REC; 573965Sgovinda msi_type = MSI32_TYPE; 574965Sgovinda msi_addr = msi_state_p->msi_addr32; 575965Sgovinda } 576965Sgovinda 57710053SEvan.Yan@Sun.COM (void) px_msi_get_msinum(px_p, hdlp->ih_dip, 57810053SEvan.Yan@Sun.COM (hdlp->ih_flags & DDI_INTR_MSIX_DUP) ? hdlp->ih_main->ih_inum : 57910053SEvan.Yan@Sun.COM hdlp->ih_inum, &msi_num); 58010053SEvan.Yan@Sun.COM 5810Sstevel@tonic-gate switch (intr_op) { 5820Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5830Sstevel@tonic-gate ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result); 58410053SEvan.Yan@Sun.COM if (ret == DDI_SUCCESS) 58510053SEvan.Yan@Sun.COM *(int *)result |= DDI_INTR_FLAG_RETARGETABLE; 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate case DDI_INTROP_SETCAP: 5880Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: SetCap is not supported\n"); 5890Sstevel@tonic-gate ret = DDI_ENOTSUP; 5900Sstevel@tonic-gate break; 5910Sstevel@tonic-gate case DDI_INTROP_ALLOC: 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * We need to restrict this allocation in future 5940Sstevel@tonic-gate * based on Resource Management policies. 5950Sstevel@tonic-gate */ 5968561SScott.Carter@Sun.COM if ((ret = px_msi_alloc(px_p, rdip, hdlp->ih_type, 5978561SScott.Carter@Sun.COM hdlp->ih_inum, hdlp->ih_scratch1, 5988561SScott.Carter@Sun.COM (uintptr_t)hdlp->ih_scratch2, 5991725Segillett (int *)result)) != DDI_SUCCESS) { 6001725Segillett DBG(DBG_INTROPS, dip, "px_msix_ops: allocation " 6011725Segillett "failed, rdip 0x%p type 0x%d inum 0x%x " 6021725Segillett "count 0x%x\n", rdip, hdlp->ih_type, hdlp->ih_inum, 6031725Segillett hdlp->ih_scratch1); 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate return (ret); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6081725Segillett if ((hdlp->ih_type == DDI_INTR_TYPE_MSIX) && 6091725Segillett (i_ddi_get_msix(rdip) == NULL)) { 6101725Segillett ddi_intr_msix_t *msix_p; 6111725Segillett 6121725Segillett if (msix_p = pci_msix_init(rdip)) { 6131725Segillett i_ddi_set_msix(rdip, msix_p); 6141725Segillett break; 6151725Segillett } 6161725Segillett 6171725Segillett DBG(DBG_INTROPS, dip, "px_msix_ops: MSI-X allocation " 6181725Segillett "failed, rdip 0x%p inum 0x%x\n", rdip, 6191725Segillett hdlp->ih_inum); 6201725Segillett 6211725Segillett (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 6221725Segillett hdlp->ih_scratch1); 6231725Segillett 6241725Segillett return (DDI_FAILURE); 6251725Segillett } 6261725Segillett 6270Sstevel@tonic-gate break; 6280Sstevel@tonic-gate case DDI_INTROP_FREE: 6290Sstevel@tonic-gate (void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum); 6301725Segillett 6311725Segillett if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 6321725Segillett goto msi_free; 6331725Segillett 6341725Segillett if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 6351725Segillett break; 6361725Segillett 6371725Segillett if (((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0) && 6381725Segillett (i_ddi_get_msix(rdip))) { 6391725Segillett pci_msix_fini(i_ddi_get_msix(rdip)); 6401725Segillett i_ddi_set_msix(rdip, NULL); 6411725Segillett } 6421725Segillett msi_free: 6430Sstevel@tonic-gate (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 6440Sstevel@tonic-gate hdlp->ih_scratch1); 6450Sstevel@tonic-gate break; 6460Sstevel@tonic-gate case DDI_INTROP_GETPRI: 6470Sstevel@tonic-gate *(int *)result = hdlp->ih_pri ? 6488535Sevan.yan@sun.com hdlp->ih_pri : pci_class_to_pil(rdip); 6490Sstevel@tonic-gate break; 6500Sstevel@tonic-gate case DDI_INTROP_SETPRI: 6510Sstevel@tonic-gate break; 6520Sstevel@tonic-gate case DDI_INTROP_ADDISR: 6530Sstevel@tonic-gate if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 65410053SEvan.Yan@Sun.COM msiq_rec_type, msi_num, -1, &msiq_id)) != DDI_SUCCESS) { 6550Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler " 6560Sstevel@tonic-gate "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 6570Sstevel@tonic-gate return (ret); 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if ((ret = px_lib_msi_setmsiq(dip, msi_num, 663965Sgovinda msiq_id, msi_type)) != DDI_SUCCESS) { 6640Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 665965Sgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 6660Sstevel@tonic-gate return (ret); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 6700Sstevel@tonic-gate PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) { 6710Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 672965Sgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 6730Sstevel@tonic-gate return (ret); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate 67610053SEvan.Yan@Sun.COM if ((ret = px_lib_msi_setvalid(dip, msi_num, 67710053SEvan.Yan@Sun.COM PCI_MSI_VALID)) != DDI_SUCCESS) 67810053SEvan.Yan@Sun.COM return (ret); 67910053SEvan.Yan@Sun.COM 68010053SEvan.Yan@Sun.COM ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 68110053SEvan.Yan@Sun.COM px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri, 68210053SEvan.Yan@Sun.COM PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num); 68310053SEvan.Yan@Sun.COM 6840Sstevel@tonic-gate break; 6850Sstevel@tonic-gate case DDI_INTROP_DUPVEC: 6861725Segillett DBG(DBG_INTROPS, dip, "px_msix_ops: dupisr - inum: %x, " 6871725Segillett "new_vector: %x\n", hdlp->ih_inum, hdlp->ih_scratch1); 6881725Segillett 6891725Segillett ret = pci_msix_dup(hdlp->ih_dip, hdlp->ih_inum, 6901725Segillett hdlp->ih_scratch1); 6910Sstevel@tonic-gate break; 6920Sstevel@tonic-gate case DDI_INTROP_REMISR: 6930Sstevel@tonic-gate if ((ret = px_lib_msi_getmsiq(dip, msi_num, 6940Sstevel@tonic-gate &msiq_id)) != DDI_SUCCESS) 6950Sstevel@tonic-gate return (ret); 6960Sstevel@tonic-gate 69710053SEvan.Yan@Sun.COM if ((ret = px_ib_update_intr_state(px_p, rdip, 69810053SEvan.Yan@Sun.COM hdlp->ih_inum, px_msiqid_to_devino(px_p, msiq_id), 69910053SEvan.Yan@Sun.COM hdlp->ih_pri, PX_INTR_STATE_DISABLE, msiq_rec_type, 70010053SEvan.Yan@Sun.COM msi_num)) != DDI_SUCCESS) 70110053SEvan.Yan@Sun.COM return (ret); 70210053SEvan.Yan@Sun.COM 70310053SEvan.Yan@Sun.COM if ((ret = px_lib_msi_setvalid(dip, msi_num, 70410053SEvan.Yan@Sun.COM PCI_MSI_INVALID)) != DDI_SUCCESS) 70510053SEvan.Yan@Sun.COM return (ret); 70610053SEvan.Yan@Sun.COM 7070Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 708965Sgovinda PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) 7090Sstevel@tonic-gate return (ret); 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate ret = px_rem_msiq_intr(dip, rdip, 712965Sgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate break; 71510053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET: 71610053SEvan.Yan@Sun.COM if ((ret = px_lib_msi_getmsiq(dip, msi_num, 71710053SEvan.Yan@Sun.COM &msiq_id)) != DDI_SUCCESS) 7180Sstevel@tonic-gate return (ret); 7190Sstevel@tonic-gate 72010053SEvan.Yan@Sun.COM ret = px_ib_get_intr_target(px_p, 72110053SEvan.Yan@Sun.COM px_msiqid_to_devino(px_p, msiq_id), (cpuid_t *)result); 72210053SEvan.Yan@Sun.COM break; 72310053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET: 72410053SEvan.Yan@Sun.COM ret = px_ib_set_msix_target(px_p, hdlp, msi_num, 72510053SEvan.Yan@Sun.COM *(cpuid_t *)result); 72610053SEvan.Yan@Sun.COM break; 72710053SEvan.Yan@Sun.COM case DDI_INTROP_ENABLE: 72810053SEvan.Yan@Sun.COM /* 72910115SGovinda.Tatti@Sun.COM * For MSI, just clear the mask bit and return if curr_nenables 73010115SGovinda.Tatti@Sun.COM * is > 1. For MSI-X, program MSI address and data for every 73110115SGovinda.Tatti@Sun.COM * MSI-X vector including dup vectors irrespective of current 73210115SGovinda.Tatti@Sun.COM * curr_nenables value. 73310053SEvan.Yan@Sun.COM */ 73410115SGovinda.Tatti@Sun.COM if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) || 73510115SGovinda.Tatti@Sun.COM (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) { 73610115SGovinda.Tatti@Sun.COM nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7370Sstevel@tonic-gate 73810115SGovinda.Tatti@Sun.COM if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 73910115SGovinda.Tatti@Sun.COM nintrs, hdlp->ih_inum, msi_addr, 74010115SGovinda.Tatti@Sun.COM hdlp->ih_type == DDI_INTR_TYPE_MSIX ? 74110115SGovinda.Tatti@Sun.COM msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 74210115SGovinda.Tatti@Sun.COM return (ret); 7430Sstevel@tonic-gate 74410115SGovinda.Tatti@Sun.COM if (i_ddi_intr_get_current_nenables(rdip) < 1) { 74510115SGovinda.Tatti@Sun.COM if ((ret = pci_msi_enable_mode(rdip, 74610115SGovinda.Tatti@Sun.COM hdlp->ih_type)) != DDI_SUCCESS) 74710115SGovinda.Tatti@Sun.COM return (ret); 74810115SGovinda.Tatti@Sun.COM } 74910115SGovinda.Tatti@Sun.COM } 7500Sstevel@tonic-gate 751909Segillett if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type, 752909Segillett hdlp->ih_inum)) != DDI_SUCCESS) 753909Segillett return (ret); 754909Segillett 7550Sstevel@tonic-gate break; 7560Sstevel@tonic-gate case DDI_INTROP_DISABLE: 7570Sstevel@tonic-gate if ((ret = pci_msi_set_mask(rdip, hdlp->ih_type, 7580Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7590Sstevel@tonic-gate return (ret); 7600Sstevel@tonic-gate 76110053SEvan.Yan@Sun.COM /* 76210053SEvan.Yan@Sun.COM * curr_nenables will be greater than 1 if rdip is using 76310053SEvan.Yan@Sun.COM * MSI-X and also, if it is using DUP interface. If this 76410053SEvan.Yan@Sun.COM * curr_enables is > 1, return after setting the mask bit. 76510053SEvan.Yan@Sun.COM */ 76610053SEvan.Yan@Sun.COM if (i_ddi_intr_get_current_nenables(rdip) > 1) 76710053SEvan.Yan@Sun.COM return (DDI_SUCCESS); 7681725Segillett 76910053SEvan.Yan@Sun.COM if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type)) 77010053SEvan.Yan@Sun.COM != DDI_SUCCESS) 771909Segillett return (ret); 772909Segillett 7730Sstevel@tonic-gate break; 7740Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 7750Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 778965Sgovinda nintrs, hdlp->ih_inum, msi_addr, 7790Sstevel@tonic-gate msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7800Sstevel@tonic-gate return (ret); 7810Sstevel@tonic-gate 7822755Segillett ret = pci_msi_enable_mode(rdip, hdlp->ih_type); 7830Sstevel@tonic-gate break; 7840Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 78510053SEvan.Yan@Sun.COM ret = pci_msi_disable_mode(rdip, hdlp->ih_type); 7860Sstevel@tonic-gate break; 7870Sstevel@tonic-gate case DDI_INTROP_SETMASK: 7880Sstevel@tonic-gate ret = pci_msi_set_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7890Sstevel@tonic-gate break; 7900Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 7910Sstevel@tonic-gate ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7920Sstevel@tonic-gate break; 7930Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 7940Sstevel@tonic-gate ret = pci_msi_get_pending(rdip, hdlp->ih_type, 7950Sstevel@tonic-gate hdlp->ih_inum, (int *)result); 7960Sstevel@tonic-gate break; 7970Sstevel@tonic-gate case DDI_INTROP_NINTRS: 7980Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 7990Sstevel@tonic-gate break; 8000Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 8010Sstevel@tonic-gate /* XXX - a new interface may be needed */ 8020Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 8030Sstevel@tonic-gate break; 8048561SScott.Carter@Sun.COM case DDI_INTROP_GETPOOL: 8058561SScott.Carter@Sun.COM if (msi_state_p->msi_pool_p == NULL) { 8068561SScott.Carter@Sun.COM *(ddi_irm_pool_t **)result = NULL; 8078561SScott.Carter@Sun.COM return (DDI_ENOTSUP); 8088561SScott.Carter@Sun.COM } 8098561SScott.Carter@Sun.COM *(ddi_irm_pool_t **)result = msi_state_p->msi_pool_p; 8108561SScott.Carter@Sun.COM ret = DDI_SUCCESS; 8118561SScott.Carter@Sun.COM break; 8120Sstevel@tonic-gate default: 8130Sstevel@tonic-gate ret = DDI_ENOTSUP; 8140Sstevel@tonic-gate break; 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate return (ret); 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 82066Sesolom static struct { 82166Sesolom kstat_named_t pxintr_ks_name; 82266Sesolom kstat_named_t pxintr_ks_type; 82366Sesolom kstat_named_t pxintr_ks_cpu; 82466Sesolom kstat_named_t pxintr_ks_pil; 82566Sesolom kstat_named_t pxintr_ks_time; 82666Sesolom kstat_named_t pxintr_ks_ino; 82766Sesolom kstat_named_t pxintr_ks_cookie; 82866Sesolom kstat_named_t pxintr_ks_devpath; 82966Sesolom kstat_named_t pxintr_ks_buspath; 83066Sesolom } pxintr_ks_template = { 83166Sesolom { "name", KSTAT_DATA_CHAR }, 83266Sesolom { "type", KSTAT_DATA_CHAR }, 83366Sesolom { "cpu", KSTAT_DATA_UINT64 }, 83466Sesolom { "pil", KSTAT_DATA_UINT64 }, 83566Sesolom { "time", KSTAT_DATA_UINT64 }, 83666Sesolom { "ino", KSTAT_DATA_UINT64 }, 83766Sesolom { "cookie", KSTAT_DATA_UINT64 }, 83866Sesolom { "devpath", KSTAT_DATA_STRING }, 83966Sesolom { "buspath", KSTAT_DATA_STRING }, 84066Sesolom }; 84166Sesolom 84266Sesolom static uint32_t pxintr_ks_instance; 8431811Sesolom static char ih_devpath[MAXPATHLEN]; 8441811Sesolom static char ih_buspath[MAXPATHLEN]; 84566Sesolom kmutex_t pxintr_ks_template_lock; 84666Sesolom 84766Sesolom int 84866Sesolom px_ks_update(kstat_t *ksp, int rw) 84966Sesolom { 85066Sesolom px_ih_t *ih_p = ksp->ks_private; 85166Sesolom int maxlen = sizeof (pxintr_ks_template.pxintr_ks_name.value.c); 8522973Sgovinda px_ino_pil_t *ipil_p = ih_p->ih_ipil_p; 8532973Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 8542973Sgovinda px_t *px_p = ino_p->ino_ib_p->ib_px_p; 85566Sesolom devino_t ino; 85666Sesolom sysino_t sysino; 85766Sesolom 8582973Sgovinda ino = ino_p->ino_ino; 8597124Sanbui if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino) != 8607124Sanbui DDI_SUCCESS) { 8617124Sanbui cmn_err(CE_WARN, "px_ks_update: px_lib_intr_devino_to_sysino " 8627124Sanbui "failed"); 8637124Sanbui } 86466Sesolom 86566Sesolom (void) snprintf(pxintr_ks_template.pxintr_ks_name.value.c, maxlen, 86666Sesolom "%s%d", ddi_driver_name(ih_p->ih_dip), 86766Sesolom ddi_get_instance(ih_p->ih_dip)); 86866Sesolom 86966Sesolom (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 87066Sesolom (void) ddi_pathname(px_p->px_dip, ih_buspath); 87166Sesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_devpath, ih_devpath); 87266Sesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_buspath, ih_buspath); 87366Sesolom 8741087Sschwartz if (ih_p->ih_intr_state == PX_INTR_STATE_ENABLE) { 8751087Sschwartz 8764397Sschwartz switch (i_ddi_intr_get_current_type(ih_p->ih_dip)) { 8774397Sschwartz case DDI_INTR_TYPE_MSI: 8784397Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8794397Sschwartz "msi"); 8804397Sschwartz break; 8814397Sschwartz case DDI_INTR_TYPE_MSIX: 8824397Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8834397Sschwartz "msix"); 8844397Sschwartz break; 8854397Sschwartz default: 8864397Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8874397Sschwartz "fixed"); 8884397Sschwartz break; 8894397Sschwartz } 8904397Sschwartz 8912973Sgovinda pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ino_p->ino_cpuid; 8922973Sgovinda pxintr_ks_template.pxintr_ks_pil.value.ui64 = ipil_p->ipil_pil; 8931087Sschwartz pxintr_ks_template.pxintr_ks_time.value.ui64 = ih_p->ih_nsec + 8941087Sschwartz (uint64_t)tick2ns((hrtime_t)ih_p->ih_ticks, 8952973Sgovinda ino_p->ino_cpuid); 8961087Sschwartz pxintr_ks_template.pxintr_ks_ino.value.ui64 = ino; 8971087Sschwartz pxintr_ks_template.pxintr_ks_cookie.value.ui64 = sysino; 8981087Sschwartz } else { 8991087Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 9001087Sschwartz "disabled"); 9011087Sschwartz pxintr_ks_template.pxintr_ks_cpu.value.ui64 = 0; 9021087Sschwartz pxintr_ks_template.pxintr_ks_pil.value.ui64 = 0; 9031087Sschwartz pxintr_ks_template.pxintr_ks_time.value.ui64 = 0; 9041087Sschwartz pxintr_ks_template.pxintr_ks_ino.value.ui64 = 0; 9051087Sschwartz pxintr_ks_template.pxintr_ks_cookie.value.ui64 = 0; 9061087Sschwartz } 90766Sesolom return (0); 90866Sesolom } 90966Sesolom 91066Sesolom void 91166Sesolom px_create_intr_kstats(px_ih_t *ih_p) 91266Sesolom { 91366Sesolom msiq_rec_type_t rec_type = ih_p->ih_rec_type; 91466Sesolom 91566Sesolom ASSERT(ih_p->ih_ksp == NULL); 91666Sesolom 91766Sesolom /* 91866Sesolom * Create pci_intrs::: kstats for all ih types except messages, 91966Sesolom * which represent unusual conditions and don't need to be tracked. 92066Sesolom */ 92166Sesolom if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 92266Sesolom ih_p->ih_ksp = kstat_create("pci_intrs", 92366Sesolom atomic_inc_32_nv(&pxintr_ks_instance), "config", 92466Sesolom "interrupts", KSTAT_TYPE_NAMED, 92566Sesolom sizeof (pxintr_ks_template) / sizeof (kstat_named_t), 92666Sesolom KSTAT_FLAG_VIRTUAL); 92766Sesolom } 92866Sesolom if (ih_p->ih_ksp != NULL) { 92966Sesolom ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 93066Sesolom ih_p->ih_ksp->ks_lock = &pxintr_ks_template_lock; 93166Sesolom ih_p->ih_ksp->ks_data = &pxintr_ks_template; 93266Sesolom ih_p->ih_ksp->ks_private = ih_p; 93366Sesolom ih_p->ih_ksp->ks_update = px_ks_update; 93466Sesolom } 93566Sesolom } 93666Sesolom 937693Sgovinda /* 938693Sgovinda * px_add_intx_intr: 939693Sgovinda * 940693Sgovinda * This function is called to register INTx and legacy hardware 941693Sgovinda * interrupt pins interrupts. 942693Sgovinda */ 9430Sstevel@tonic-gate int 9440Sstevel@tonic-gate px_add_intx_intr(dev_info_t *dip, dev_info_t *rdip, 9450Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 9460Sstevel@tonic-gate { 9470Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 9480Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 9490Sstevel@tonic-gate devino_t ino; 9500Sstevel@tonic-gate px_ih_t *ih_p; 9512973Sgovinda px_ino_t *ino_p; 9522973Sgovinda px_ino_pil_t *ipil_p, *ipil_list; 9530Sstevel@tonic-gate int32_t weight; 9540Sstevel@tonic-gate int ret = DDI_SUCCESS; 955*11836SDaniel.Ice@Sun.COM cpuid_t curr_cpu; 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate ino = hdlp->ih_vector; 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: rdip=%s%d ino=%x " 9600Sstevel@tonic-gate "handler=%x arg1=%x arg2=%x\n", ddi_driver_name(rdip), 9610Sstevel@tonic-gate ddi_get_instance(rdip), ino, hdlp->ih_cb_func, 9620Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, 9650Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, 0, 0); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 9680Sstevel@tonic-gate 9692973Sgovinda ino_p = px_ib_locate_ino(ib_p, ino); 9702973Sgovinda ipil_list = ino_p ? ino_p->ino_ipil_p : NULL; 9712973Sgovinda 972*11836SDaniel.Ice@Sun.COM /* Sharing the INO using a PIL that already exists */ 9732973Sgovinda if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 9742973Sgovinda if (px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0)) { 9750Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: " 9762973Sgovinda "dup intr #%d\n", hdlp->ih_inum); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate ret = DDI_FAILURE; 9790Sstevel@tonic-gate goto fail1; 9800Sstevel@tonic-gate } 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate /* Save mondo value in hdlp */ 9830Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 9840Sstevel@tonic-gate 9852973Sgovinda if ((ret = px_ib_ino_add_intr(px_p, ipil_p, 9862973Sgovinda ih_p)) != DDI_SUCCESS) 9870Sstevel@tonic-gate goto fail1; 9882973Sgovinda 9892973Sgovinda goto ino_done; 9902973Sgovinda } 9910Sstevel@tonic-gate 992*11836SDaniel.Ice@Sun.COM /* Sharing the INO using a new PIL */ 993*11836SDaniel.Ice@Sun.COM if (ipil_list != NULL) { 994*11836SDaniel.Ice@Sun.COM intr_state_t intr_state; 995*11836SDaniel.Ice@Sun.COM hrtime_t start_time; 996*11836SDaniel.Ice@Sun.COM 997*11836SDaniel.Ice@Sun.COM /* 998*11836SDaniel.Ice@Sun.COM * disable INO to avoid lopil race condition with 999*11836SDaniel.Ice@Sun.COM * px_intx_intr 1000*11836SDaniel.Ice@Sun.COM */ 1001*11836SDaniel.Ice@Sun.COM 1002*11836SDaniel.Ice@Sun.COM if ((ret = px_lib_intr_gettarget(dip, ino_p->ino_sysino, 1003*11836SDaniel.Ice@Sun.COM &curr_cpu)) != DDI_SUCCESS) { 1004*11836SDaniel.Ice@Sun.COM DBG(DBG_IB, dip, 1005*11836SDaniel.Ice@Sun.COM "px_add_intx_intr px_intr_gettarget() failed\n"); 1006*11836SDaniel.Ice@Sun.COM 1007*11836SDaniel.Ice@Sun.COM goto fail1; 1008*11836SDaniel.Ice@Sun.COM } 1009*11836SDaniel.Ice@Sun.COM 1010*11836SDaniel.Ice@Sun.COM /* Disable the interrupt */ 1011*11836SDaniel.Ice@Sun.COM PX_INTR_DISABLE(dip, ino_p->ino_sysino); 1012*11836SDaniel.Ice@Sun.COM 1013*11836SDaniel.Ice@Sun.COM /* Busy wait on pending interrupt */ 1014*11836SDaniel.Ice@Sun.COM for (start_time = gethrtime(); !panicstr && 1015*11836SDaniel.Ice@Sun.COM ((ret = px_lib_intr_getstate(dip, ino_p->ino_sysino, 1016*11836SDaniel.Ice@Sun.COM &intr_state)) == DDI_SUCCESS) && 1017*11836SDaniel.Ice@Sun.COM (intr_state == INTR_DELIVERED_STATE); /* */) { 1018*11836SDaniel.Ice@Sun.COM if (gethrtime() - start_time > px_intrpend_timeout) { 1019*11836SDaniel.Ice@Sun.COM cmn_err(CE_WARN, "%s%d: px_add_intx_intr: " 1020*11836SDaniel.Ice@Sun.COM "pending sysino 0x%lx(ino 0x%x) timeout", 1021*11836SDaniel.Ice@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), 1022*11836SDaniel.Ice@Sun.COM ino_p->ino_sysino, ino_p->ino_ino); 1023*11836SDaniel.Ice@Sun.COM 1024*11836SDaniel.Ice@Sun.COM ret = DDI_FAILURE; 1025*11836SDaniel.Ice@Sun.COM goto fail1; 1026*11836SDaniel.Ice@Sun.COM } 1027*11836SDaniel.Ice@Sun.COM } 1028*11836SDaniel.Ice@Sun.COM } 1029*11836SDaniel.Ice@Sun.COM 10302973Sgovinda if (hdlp->ih_pri == 0) 10318535Sevan.yan@sun.com hdlp->ih_pri = pci_class_to_pil(rdip); 10322973Sgovinda 10332973Sgovinda ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 10342973Sgovinda ino_p = ipil_p->ipil_ino_p; 10350Sstevel@tonic-gate 10362973Sgovinda /* Save mondo value in hdlp */ 10372973Sgovinda hdlp->ih_vector = ino_p->ino_sysino; 10380Sstevel@tonic-gate 10392973Sgovinda DBG(DBG_A_INTX, dip, "px_add_intx_intr: pil=0x%x mondo=0x%x\n", 10402973Sgovinda hdlp->ih_pri, hdlp->ih_vector); 10410Sstevel@tonic-gate 10422973Sgovinda DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 10432973Sgovinda (ddi_intr_handler_t *)px_intx_intr, (caddr_t)ipil_p, NULL); 10440Sstevel@tonic-gate 10452973Sgovinda ret = i_ddi_add_ivintr(hdlp); 10460Sstevel@tonic-gate 10472973Sgovinda /* 10482973Sgovinda * Restore original interrupt handler 10492973Sgovinda * and arguments in interrupt handle. 10502973Sgovinda */ 10512973Sgovinda DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 10522973Sgovinda ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 10530Sstevel@tonic-gate 10542973Sgovinda if (ret != DDI_SUCCESS) 10552973Sgovinda goto fail2; 10560Sstevel@tonic-gate 10572973Sgovinda /* Save the pil for this ino */ 10582973Sgovinda ipil_p->ipil_pil = hdlp->ih_pri; 10590Sstevel@tonic-gate 10602973Sgovinda /* Select cpu, saving it for sharing and removal */ 10612973Sgovinda if (ipil_list == NULL) { 106210053SEvan.Yan@Sun.COM if (ino_p->ino_cpuid == -1) 106310053SEvan.Yan@Sun.COM ino_p->ino_cpuid = intr_dist_cpuid(); 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate /* Enable interrupt */ 10660Sstevel@tonic-gate px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 1067*11836SDaniel.Ice@Sun.COM } else { 1068*11836SDaniel.Ice@Sun.COM /* Re-enable interrupt */ 1069*11836SDaniel.Ice@Sun.COM PX_INTR_ENABLE(dip, ino_p->ino_sysino, curr_cpu); 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate 10722973Sgovinda ino_done: 107310053SEvan.Yan@Sun.COM hdlp->ih_target = ino_p->ino_cpuid; 107410053SEvan.Yan@Sun.COM 10752973Sgovinda /* Add weight to the cpu that we are already targeting */ 10768535Sevan.yan@sun.com weight = pci_class_to_intr_weight(rdip); 10770Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 10780Sstevel@tonic-gate 10792973Sgovinda ih_p->ih_ipil_p = ipil_p; 108066Sesolom px_create_intr_kstats(ih_p); 10810Sstevel@tonic-gate if (ih_p->ih_ksp) 10820Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 10830Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: done! Interrupt 0x%x pil=%x\n", 10860Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate return (ret); 10890Sstevel@tonic-gate fail2: 10902973Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 10910Sstevel@tonic-gate fail1: 10920Sstevel@tonic-gate if (ih_p->ih_config_handle) 10930Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10960Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: Failed! Interrupt 0x%x " 10990Sstevel@tonic-gate "pil=%x\n", ino_p->ino_sysino, hdlp->ih_pri); 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate return (ret); 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate 1104693Sgovinda /* 1105693Sgovinda * px_rem_intx_intr: 1106693Sgovinda * 1107693Sgovinda * This function is called to unregister INTx and legacy hardware 1108693Sgovinda * interrupt pins interrupts. 1109693Sgovinda */ 11100Sstevel@tonic-gate int 11110Sstevel@tonic-gate px_rem_intx_intr(dev_info_t *dip, dev_info_t *rdip, 11120Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 11130Sstevel@tonic-gate { 11140Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 11150Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 11160Sstevel@tonic-gate devino_t ino; 11170Sstevel@tonic-gate cpuid_t curr_cpu; 11182973Sgovinda px_ino_t *ino_p; 11192973Sgovinda px_ino_pil_t *ipil_p; 11200Sstevel@tonic-gate px_ih_t *ih_p; 11210Sstevel@tonic-gate int ret = DDI_SUCCESS; 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate ino = hdlp->ih_vector; 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate DBG(DBG_R_INTX, dip, "px_rem_intx_intr: rdip=%s%d ino=%x\n", 11260Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 11312973Sgovinda ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 11322973Sgovinda ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0); 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate /* Get the current cpu */ 11350Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 11360Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 11370Sstevel@tonic-gate goto fail; 11380Sstevel@tonic-gate 11392973Sgovinda if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS) 11400Sstevel@tonic-gate goto fail; 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 11430Sstevel@tonic-gate 11442973Sgovinda if (ipil_p->ipil_ih_size == 0) { 11450Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 11460Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 11470Sstevel@tonic-gate 11482973Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 11492973Sgovinda } 11502973Sgovinda 11512973Sgovinda if (ino_p->ino_ipil_size == 0) { 11522973Sgovinda kmem_free(ino_p, sizeof (px_ino_t)); 11530Sstevel@tonic-gate } else { 11543780Segillett /* Re-enable interrupt only if mapping register still shared */ 11553780Segillett PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate fail: 11590Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 11600Sstevel@tonic-gate return (ret); 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate 1163693Sgovinda /* 1164693Sgovinda * px_add_msiq_intr: 1165693Sgovinda * 1166693Sgovinda * This function is called to register MSI/Xs and PCIe message interrupts. 1167693Sgovinda */ 11680Sstevel@tonic-gate int 11690Sstevel@tonic-gate px_add_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 11700Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 117110053SEvan.Yan@Sun.COM msgcode_t msg_code, cpuid_t cpu_id, msiqid_t *msiq_id_p) 11720Sstevel@tonic-gate { 11730Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 11740Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 11750Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 11760Sstevel@tonic-gate devino_t ino; 11770Sstevel@tonic-gate px_ih_t *ih_p; 11782973Sgovinda px_ino_t *ino_p; 11792973Sgovinda px_ino_pil_t *ipil_p, *ipil_list; 11800Sstevel@tonic-gate int32_t weight; 11810Sstevel@tonic-gate int ret = DDI_SUCCESS; 11820Sstevel@tonic-gate 118310053SEvan.Yan@Sun.COM DBG(DBG_MSIQ, dip, "px_add_msiq_intr: rdip=%s%d handler=0x%x " 118410053SEvan.Yan@Sun.COM "arg1=0x%x arg2=0x%x cpu=0x%x\n", ddi_driver_name(rdip), 118510053SEvan.Yan@Sun.COM ddi_get_instance(rdip), hdlp->ih_cb_func, hdlp->ih_cb_arg1, 118610053SEvan.Yan@Sun.COM hdlp->ih_cb_arg2, cpu_id); 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, hdlp->ih_cb_func, 11890Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rec_type, msg_code); 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 11920Sstevel@tonic-gate 119310841SAlan.Adamson@Sun.COM ret = (cpu_id == -1) ? px_msiq_alloc(px_p, rec_type, msg_code, 119410841SAlan.Adamson@Sun.COM msiq_id_p) : px_msiq_alloc_based_on_cpuid(px_p, rec_type, 119510841SAlan.Adamson@Sun.COM cpu_id, msiq_id_p); 119610053SEvan.Yan@Sun.COM 119710053SEvan.Yan@Sun.COM if (ret != DDI_SUCCESS) { 119810053SEvan.Yan@Sun.COM DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 119910053SEvan.Yan@Sun.COM "msiq allocation failed\n"); 120010053SEvan.Yan@Sun.COM goto fail; 120110053SEvan.Yan@Sun.COM } 120210053SEvan.Yan@Sun.COM 120310053SEvan.Yan@Sun.COM ino = px_msiqid_to_devino(px_p, *msiq_id_p); 120410053SEvan.Yan@Sun.COM 12052973Sgovinda ino_p = px_ib_locate_ino(ib_p, ino); 12062973Sgovinda ipil_list = ino_p ? ino_p->ino_ipil_p : NULL; 12072973Sgovinda 12082973Sgovinda /* Sharing ino */ 12092973Sgovinda if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 12102973Sgovinda if (px_ib_intr_locate_ih(ipil_p, rdip, 12112973Sgovinda hdlp->ih_inum, rec_type, msg_code)) { 12120Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 12132973Sgovinda "dup intr #%d\n", hdlp->ih_inum); 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate ret = DDI_FAILURE; 12160Sstevel@tonic-gate goto fail1; 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate /* Save mondo value in hdlp */ 12200Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 12210Sstevel@tonic-gate 12222973Sgovinda if ((ret = px_ib_ino_add_intr(px_p, ipil_p, 12232973Sgovinda ih_p)) != DDI_SUCCESS) 12242973Sgovinda goto fail1; 12252973Sgovinda 12262973Sgovinda goto ino_done; 12272973Sgovinda } 12282973Sgovinda 12292973Sgovinda if (hdlp->ih_pri == 0) 12308535Sevan.yan@sun.com hdlp->ih_pri = pci_class_to_pil(rdip); 12310Sstevel@tonic-gate 12322973Sgovinda ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 12332973Sgovinda ino_p = ipil_p->ipil_ino_p; 12342973Sgovinda 12352973Sgovinda ino_p->ino_msiq_p = msiq_state_p->msiq_p + 12362973Sgovinda (*msiq_id_p - msiq_state_p->msiq_1st_msiq_id); 12370Sstevel@tonic-gate 12382973Sgovinda /* Save mondo value in hdlp */ 12392973Sgovinda hdlp->ih_vector = ino_p->ino_sysino; 12402973Sgovinda 12412973Sgovinda DBG(DBG_MSIQ, dip, "px_add_msiq_intr: pil=0x%x mondo=0x%x\n", 12422973Sgovinda hdlp->ih_pri, hdlp->ih_vector); 12430Sstevel@tonic-gate 12442973Sgovinda DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 12452973Sgovinda (ddi_intr_handler_t *)px_msiq_intr, (caddr_t)ipil_p, NULL); 12462973Sgovinda 12472973Sgovinda ret = i_ddi_add_ivintr(hdlp); 12480Sstevel@tonic-gate 12492973Sgovinda /* 12502973Sgovinda * Restore original interrupt handler 12512973Sgovinda * and arguments in interrupt handle. 12522973Sgovinda */ 12532973Sgovinda DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 12542973Sgovinda ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 12550Sstevel@tonic-gate 12562973Sgovinda if (ret != DDI_SUCCESS) 12572973Sgovinda goto fail2; 12582973Sgovinda 12592973Sgovinda /* Save the pil for this ino */ 12602973Sgovinda ipil_p->ipil_pil = hdlp->ih_pri; 12612973Sgovinda 12622973Sgovinda /* Select cpu, saving it for sharing and removal */ 12632973Sgovinda if (ipil_list == NULL) { 12640Sstevel@tonic-gate /* Enable MSIQ */ 12650Sstevel@tonic-gate px_lib_msiq_setstate(dip, *msiq_id_p, PCI_MSIQ_STATE_IDLE); 12660Sstevel@tonic-gate px_lib_msiq_setvalid(dip, *msiq_id_p, PCI_MSIQ_VALID); 12670Sstevel@tonic-gate 126810053SEvan.Yan@Sun.COM if (ino_p->ino_cpuid == -1) 126910053SEvan.Yan@Sun.COM ino_p->ino_cpuid = intr_dist_cpuid(); 127010053SEvan.Yan@Sun.COM 12710Sstevel@tonic-gate /* Enable interrupt */ 12722973Sgovinda px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate 12752973Sgovinda ino_done: 127610053SEvan.Yan@Sun.COM hdlp->ih_target = ino_p->ino_cpuid; 127710053SEvan.Yan@Sun.COM 12782973Sgovinda /* Add weight to the cpu that we are already targeting */ 12798535Sevan.yan@sun.com weight = pci_class_to_intr_weight(rdip); 12800Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 12810Sstevel@tonic-gate 12822973Sgovinda ih_p->ih_ipil_p = ipil_p; 128366Sesolom px_create_intr_kstats(ih_p); 12840Sstevel@tonic-gate if (ih_p->ih_ksp) 12850Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 12860Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: done! Interrupt 0x%x pil=%x\n", 12890Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate return (ret); 12920Sstevel@tonic-gate fail2: 12932973Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 12940Sstevel@tonic-gate fail1: 129510053SEvan.Yan@Sun.COM (void) px_msiq_free(px_p, *msiq_id_p); 129610053SEvan.Yan@Sun.COM fail: 12970Sstevel@tonic-gate if (ih_p->ih_config_handle) 12980Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 13010Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: Failed! Interrupt 0x%x pil=%x\n", 13040Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate return (ret); 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 1309693Sgovinda /* 1310693Sgovinda * px_rem_msiq_intr: 1311693Sgovinda * 1312693Sgovinda * This function is called to unregister MSI/Xs and PCIe message interrupts. 1313693Sgovinda */ 13140Sstevel@tonic-gate int 13150Sstevel@tonic-gate px_rem_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 13160Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 13170Sstevel@tonic-gate msgcode_t msg_code, msiqid_t msiq_id) 13180Sstevel@tonic-gate { 13190Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 13200Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 13210Sstevel@tonic-gate devino_t ino = px_msiqid_to_devino(px_p, msiq_id); 13220Sstevel@tonic-gate cpuid_t curr_cpu; 13232973Sgovinda px_ino_t *ino_p; 13242973Sgovinda px_ino_pil_t *ipil_p; 13250Sstevel@tonic-gate px_ih_t *ih_p; 13260Sstevel@tonic-gate int ret = DDI_SUCCESS; 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_rem_msiq_intr: rdip=%s%d msiq_id=%x ino=%x\n", 13290Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), msiq_id, ino); 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 13342973Sgovinda ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 13352973Sgovinda ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, rec_type, 13362973Sgovinda msg_code); 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate /* Get the current cpu */ 13390Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 13400Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 13410Sstevel@tonic-gate goto fail; 13420Sstevel@tonic-gate 13432973Sgovinda if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS) 13440Sstevel@tonic-gate goto fail; 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 13470Sstevel@tonic-gate 13482973Sgovinda if (ipil_p->ipil_ih_size == 0) { 13490Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 13500Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 13510Sstevel@tonic-gate 13522973Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 13532973Sgovinda 13542973Sgovinda if (ino_p->ino_ipil_size == 0) 13552973Sgovinda px_lib_msiq_setvalid(dip, 13562973Sgovinda px_devino_to_msiqid(px_p, ino), PCI_MSIQ_INVALID); 13572973Sgovinda } 13582973Sgovinda 135910053SEvan.Yan@Sun.COM (void) px_msiq_free(px_p, msiq_id); 136010053SEvan.Yan@Sun.COM 136110053SEvan.Yan@Sun.COM if (ino_p->ino_ipil_size) { 13623780Segillett /* Re-enable interrupt only if mapping register still shared */ 13633780Segillett PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate fail: 13670Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 13680Sstevel@tonic-gate return (ret); 13690Sstevel@tonic-gate } 1370