17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * PX nexus interrupt handling: 317c478bd9Sstevel@tonic-gate * PX device interrupt handler wrapper 327c478bd9Sstevel@tonic-gate * PIL lookup routine 337c478bd9Sstevel@tonic-gate * PX device interrupt related initchild code 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 387c478bd9Sstevel@tonic-gate #include <sys/async.h> 397c478bd9Sstevel@tonic-gate #include <sys/spl.h> 407c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 41f8d2de6bSjchu #include <sys/fm/protocol.h> 42f8d2de6bSjchu #include <sys/fm/util.h> 437c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */ 447c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 457c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 467c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 477c478bd9Sstevel@tonic-gate #include "px_obj.h" 48f8d2de6bSjchu #include <sys/ontrap.h> 49f8d2de6bSjchu #include <sys/membar.h> 506d44af1bSesolom #include <sys/clock.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * interrupt jabber: 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * When an interrupt line is jabbering, every time the state machine for the 567c478bd9Sstevel@tonic-gate * associated ino is idled, a new mondo will be sent and the ino will go into 577c478bd9Sstevel@tonic-gate * the pending state again. The mondo will cause a new call to 587c478bd9Sstevel@tonic-gate * px_intr_wrapper() which normally idles the ino's state machine which would 597c478bd9Sstevel@tonic-gate * precipitate another trip round the loop. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * The loop can be broken by preventing the ino's state machine from being 627c478bd9Sstevel@tonic-gate * idled when an interrupt line is jabbering. See the comment at the 637c478bd9Sstevel@tonic-gate * beginning of px_intr_wrapper() explaining how the 'interrupt jabber 647c478bd9Sstevel@tonic-gate * protection' code does this. 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * If the unclaimed interrupt count has reached the limit set by 717c478bd9Sstevel@tonic-gate * pci_unclaimed_intr_max within the time limit, then all interrupts 727c478bd9Sstevel@tonic-gate * on this ino is blocked by not idling the interrupt state machine. 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate static int 757c478bd9Sstevel@tonic-gate px_spurintr(px_ib_ino_info_t *ino_p) 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate px_ih_t *ih_p = ino_p->ino_ih_start; 787c478bd9Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 797c478bd9Sstevel@tonic-gate char *err_fmt_str; 807c478bd9Sstevel@tonic-gate int i; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) 837c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate if (!ino_p->ino_unclaimed) 867c478bd9Sstevel@tonic-gate ino_p->ino_spurintr_begin = ddi_get_lbolt(); 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed++; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed <= px_unclaimed_intr_max) 917c478bd9Sstevel@tonic-gate goto clear; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin) 947c478bd9Sstevel@tonic-gate > px_spurintr_duration) { 957c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 967c478bd9Sstevel@tonic-gate goto clear; 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate err_fmt_str = "%s%d: ino 0x%x blocked"; 997c478bd9Sstevel@tonic-gate goto warn; 1007c478bd9Sstevel@tonic-gate clear: 1017c478bd9Sstevel@tonic-gate /* Clear the pending state */ 1027c478bd9Sstevel@tonic-gate if (px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 1037c478bd9Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 1047c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; 1077c478bd9Sstevel@tonic-gate warn: 1087c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, err_fmt_str, NAMEINST(px_p->px_dip), ino_p->ino_ino); 1097c478bd9Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_p = ih_p->ih_next) 1107c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), 1117c478bd9Sstevel@tonic-gate ih_p->ih_inum); 1127c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "!\n"); 1137c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate extern uint64_t intr_get_time(void); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 119a195726fSgovinda * px_intx_intr (INTx or legacy interrupt handler) 1207c478bd9Sstevel@tonic-gate * 1217c478bd9Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 1227c478bd9Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 1237c478bd9Sstevel@tonic-gate * examines the return codes. 1247c478bd9Sstevel@tonic-gate * 1257c478bd9Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 1267c478bd9Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 1277c478bd9Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 1287c478bd9Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 1297c478bd9Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 1307c478bd9Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 1317c478bd9Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 1327c478bd9Sstevel@tonic-gate * handler is subsequently added or removed. 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 1357c478bd9Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate uint_t 1387c478bd9Sstevel@tonic-gate px_intx_intr(caddr_t arg) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = (px_ib_ino_info_t *)arg; 1417c478bd9Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 1427c478bd9Sstevel@tonic-gate px_ih_t *ih_p = ino_p->ino_ih_start; 1437c478bd9Sstevel@tonic-gate uint_t result = 0, r; 1447c478bd9Sstevel@tonic-gate int i; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1477c478bd9Sstevel@tonic-gate "ino=%x sysino=%llx pil=%x ih_size=%x ih_lst=%x\n", 1487c478bd9Sstevel@tonic-gate ino_p->ino_ino, ino_p->ino_sysino, ino_p->ino_pil, 1497c478bd9Sstevel@tonic-gate ino_p->ino_ih_size, ino_p->ino_ih_head); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_p = ih_p->ih_next) { 1527c478bd9Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip; 1537c478bd9Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 1547c478bd9Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 1557c478bd9Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (ih_p->ih_intr_state == PX_INTR_STATE_DISABLE) { 1587c478bd9Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, 1597c478bd9Sstevel@tonic-gate "px_intx_intr: %s%d interrupt %d is disabled\n", 1607c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1617c478bd9Sstevel@tonic-gate ino_p->ino_ino); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate continue; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1677c478bd9Sstevel@tonic-gate "ino=%x handler=%p arg1 =%p arg2 = %p\n", 1687c478bd9Sstevel@tonic-gate ino_p->ino_ino, handler, arg1, arg2); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 1717c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate r = (*handler)(arg1, arg2); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * Account for time used by this interrupt. Protect against 1777c478bd9Sstevel@tonic-gate * conflicting writes to ih_ticks from ib_intr_dist_all() by 1787c478bd9Sstevel@tonic-gate * using atomic ops. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (ino_p->ino_pil <= LOCK_LEVEL) 1827c478bd9Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 1857c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, r); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate result += r; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate if (px_check_all_handlers) 1907c478bd9Sstevel@tonic-gate continue; 1917c478bd9Sstevel@tonic-gate if (result) 1927c478bd9Sstevel@tonic-gate break; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate if (!result && px_unclaimed_intr_block) 1967c478bd9Sstevel@tonic-gate return (px_spurintr(ino_p)); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* Clear the pending state */ 2017c478bd9Sstevel@tonic-gate if (px_lib_intr_setstate(ino_p->ino_ib_p->ib_px_p->px_dip, 2027c478bd9Sstevel@tonic-gate ino_p->ino_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 2037c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* 209a195726fSgovinda * px_msiq_intr (MSI/X or PCIe MSG interrupt handler) 2107c478bd9Sstevel@tonic-gate * 2117c478bd9Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 2127c478bd9Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 2137c478bd9Sstevel@tonic-gate * examines the return codes. 2147c478bd9Sstevel@tonic-gate * 2157c478bd9Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 2167c478bd9Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 2177c478bd9Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 2187c478bd9Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 2197c478bd9Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 2207c478bd9Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 2217c478bd9Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 2227c478bd9Sstevel@tonic-gate * handler is subsequently added or removed. 2237c478bd9Sstevel@tonic-gate * 2247c478bd9Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 2257c478bd9Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate uint_t 2287c478bd9Sstevel@tonic-gate px_msiq_intr(caddr_t arg) 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = (px_ib_ino_info_t *)arg; 2317c478bd9Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 2327c478bd9Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 2337c478bd9Sstevel@tonic-gate px_msiq_t *msiq_p = ino_p->ino_msiq_p; 2347c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 2357c478bd9Sstevel@tonic-gate msiq_rec_t msiq_rec, *msiq_rec_p = &msiq_rec; 2367c478bd9Sstevel@tonic-gate msiqhead_t curr_msiq_rec_cnt, new_msiq_rec_cnt; 2377c478bd9Sstevel@tonic-gate msgcode_t msg_code; 2387c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 2397c478bd9Sstevel@tonic-gate int ret; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x " 2427c478bd9Sstevel@tonic-gate "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino, 2437c478bd9Sstevel@tonic-gate ino_p->ino_pil, ino_p->ino_ih_size, ino_p->ino_ih_head); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* Read current MSIQ head index */ 2467c478bd9Sstevel@tonic-gate px_lib_msiq_gethead(dip, msiq_p->msiq_id, &curr_msiq_rec_cnt); 2477c478bd9Sstevel@tonic-gate msiq_p->msiq_curr = (uint64_t)((caddr_t)msiq_p->msiq_base + 2487c478bd9Sstevel@tonic-gate curr_msiq_rec_cnt * sizeof (msiq_rec_t)); 2497c478bd9Sstevel@tonic-gate new_msiq_rec_cnt = curr_msiq_rec_cnt; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* Read next MSIQ record */ 2527c478bd9Sstevel@tonic-gate px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* 2553ee8f295Smg * Process current MSIQ record as long as record type 2567c478bd9Sstevel@tonic-gate * field is non-zero. 2577c478bd9Sstevel@tonic-gate */ 2583ee8f295Smg while (msiq_rec_p->msiq_rec_type) { 2597c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, " 2607c478bd9Sstevel@tonic-gate "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n", 2617c478bd9Sstevel@tonic-gate msiq_rec_p->msiq_rec_type, msiq_rec_p->msiq_rec_rid); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* Get the pointer next EQ record */ 2647c478bd9Sstevel@tonic-gate msiq_p->msiq_curr = (uint64_t) 2657c478bd9Sstevel@tonic-gate ((caddr_t)msiq_p->msiq_curr + sizeof (msiq_rec_t)); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* Check for overflow condition */ 2687c478bd9Sstevel@tonic-gate if (msiq_p->msiq_curr >= (uint64_t)((caddr_t)msiq_p->msiq_base + 2697c478bd9Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t))) 2707c478bd9Sstevel@tonic-gate msiq_p->msiq_curr = msiq_p->msiq_base; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* Check MSIQ record type */ 2737c478bd9Sstevel@tonic-gate switch (msiq_rec_p->msiq_rec_type) { 2747c478bd9Sstevel@tonic-gate case MSG_REC: 2757c478bd9Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msg.msg_code; 2767c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: PCIE MSG " 2777c478bd9Sstevel@tonic-gate "record, msg type 0x%x\n", msg_code); 2787c478bd9Sstevel@tonic-gate break; 2797c478bd9Sstevel@tonic-gate case MSI32_REC: 2807c478bd9Sstevel@tonic-gate case MSI64_REC: 2817c478bd9Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data; 2827c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, " 2837c478bd9Sstevel@tonic-gate "msi 0x%x\n", msg_code); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate /* Clear MSI state */ 2867c478bd9Sstevel@tonic-gate px_lib_msi_setstate(dip, (msinum_t)msg_code, 2877c478bd9Sstevel@tonic-gate PCI_MSI_STATE_IDLE); 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate default: 2907c478bd9Sstevel@tonic-gate msg_code = 0; 2917c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_msiq_intr: 0x%x MSIQ " 2927c478bd9Sstevel@tonic-gate "record type is not supported", 2937c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2947c478bd9Sstevel@tonic-gate msiq_rec_p->msiq_rec_type); 2957c478bd9Sstevel@tonic-gate goto next_rec; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate ih_p = ino_p->ino_ih_start; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * Scan through px_ih_t linked list, searching for the 3027c478bd9Sstevel@tonic-gate * right px_ih_t, matching MSIQ record data. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate while ((ih_p) && (ih_p->ih_msg_code != msg_code) && 3057c478bd9Sstevel@tonic-gate (ih_p->ih_rec_type != msiq_rec_p->msiq_rec_type)) 3067c478bd9Sstevel@tonic-gate ih_p = ih_p->ih_next; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate if ((ih_p->ih_msg_code == msg_code) && 3097c478bd9Sstevel@tonic-gate (ih_p->ih_rec_type == msiq_rec_p->msiq_rec_type)) { 3107c478bd9Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip; 3117c478bd9Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 3127c478bd9Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 3137c478bd9Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: ino=%x data=%x " 3167c478bd9Sstevel@tonic-gate "handler=%p arg1 =%p arg2=%p\n", ino_p->ino_ino, 3177c478bd9Sstevel@tonic-gate msg_code, handler, arg1, arg2); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 3207c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 3217c478bd9Sstevel@tonic-gate 322f8d2de6bSjchu /* 323f8d2de6bSjchu * Special case for PCIE Error Messages. 324f8d2de6bSjchu * The current frame work doesn't fit PCIE Err Msgs 325f8d2de6bSjchu * This should be fixed when PCIE MESSAGES as a whole 326f8d2de6bSjchu * is architected correctly. 327f8d2de6bSjchu */ 328f8d2de6bSjchu if ((msg_code == PCIE_MSG_CODE_ERR_COR) || 329f8d2de6bSjchu (msg_code == PCIE_MSG_CODE_ERR_NONFATAL) || 330f8d2de6bSjchu (msg_code == PCIE_MSG_CODE_ERR_FATAL)) { 331f8d2de6bSjchu ret = px_err_fabric_intr(px_p, msg_code, 332f8d2de6bSjchu msiq_rec_p->msiq_rec_rid); 333f8d2de6bSjchu } else 334f8d2de6bSjchu ret = (*handler)(arg1, arg2); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * Account for time used by this interrupt. Protect 3387c478bd9Sstevel@tonic-gate * against conflicting writes to ih_ticks from 3397c478bd9Sstevel@tonic-gate * ib_intr_dist_all() by using atomic ops. 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if (ino_p->ino_pil <= LOCK_LEVEL) 3437c478bd9Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 3467c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, ret); 3477c478bd9Sstevel@tonic-gate } else { 3487c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr:" 3497c478bd9Sstevel@tonic-gate "Not found matching MSIQ record\n"); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* px_spurintr(ino_p); */ 3527c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed++; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate next_rec: 3567c478bd9Sstevel@tonic-gate new_msiq_rec_cnt++; 3577c478bd9Sstevel@tonic-gate 3583ee8f295Smg /* Zero out msiq_rec_type field */ 3593ee8f295Smg msiq_rec_p->msiq_rec_type = 0; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* Read next MSIQ record */ 3627c478bd9Sstevel@tonic-gate px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n", 3667c478bd9Sstevel@tonic-gate (new_msiq_rec_cnt - curr_msiq_rec_cnt)); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* Update MSIQ head index with no of MSIQ records processed */ 3697c478bd9Sstevel@tonic-gate if (new_msiq_rec_cnt > curr_msiq_rec_cnt) { 3707c478bd9Sstevel@tonic-gate if (new_msiq_rec_cnt >= msiq_state_p->msiq_rec_cnt) 3717c478bd9Sstevel@tonic-gate new_msiq_rec_cnt -= msiq_state_p->msiq_rec_cnt; 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate px_lib_msiq_sethead(dip, msiq_p->msiq_id, new_msiq_rec_cnt); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* Clear the pending state */ 3777c478bd9Sstevel@tonic-gate if (px_lib_intr_setstate(dip, ino_p->ino_sysino, 3787c478bd9Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 3797c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate dev_info_t * 3857c478bd9Sstevel@tonic-gate px_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate dev_info_t *cdip = rdip; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 3907c478bd9Sstevel@tonic-gate ; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate return (cdip); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* Default class to pil value mapping */ 3967c478bd9Sstevel@tonic-gate px_class_val_t px_default_pil [] = { 3977c478bd9Sstevel@tonic-gate {0x000000, 0xff0000, 0x1}, /* Class code for pre-2.0 devices */ 3987c478bd9Sstevel@tonic-gate {0x010000, 0xff0000, 0x4}, /* Mass Storage Controller */ 3997c478bd9Sstevel@tonic-gate {0x020000, 0xff0000, 0x6}, /* Network Controller */ 4007c478bd9Sstevel@tonic-gate {0x030000, 0xff0000, 0x9}, /* Display Controller */ 4017c478bd9Sstevel@tonic-gate {0x040000, 0xff0000, 0x9}, /* Multimedia Controller */ 4027c478bd9Sstevel@tonic-gate {0x050000, 0xff0000, 0xb}, /* Memory Controller */ 4037c478bd9Sstevel@tonic-gate {0x060000, 0xff0000, 0xb}, /* Bridge Controller */ 4047c478bd9Sstevel@tonic-gate {0x0c0000, 0xffff00, 0x9}, /* Serial Bus, FireWire (IEEE 1394) */ 4057c478bd9Sstevel@tonic-gate {0x0c0100, 0xffff00, 0x4}, /* Serial Bus, ACCESS.bus */ 4067c478bd9Sstevel@tonic-gate {0x0c0200, 0xffff00, 0x4}, /* Serial Bus, SSA */ 4077c478bd9Sstevel@tonic-gate {0x0c0300, 0xffff00, 0x9}, /* Serial Bus Universal Serial Bus */ 4087c478bd9Sstevel@tonic-gate {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */ 4097c478bd9Sstevel@tonic-gate {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */ 4107c478bd9Sstevel@tonic-gate }; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * Default class to intr_weight value mapping (% of CPU). A driver.conf 4147c478bd9Sstevel@tonic-gate * entry on or above the pci node like 4157c478bd9Sstevel@tonic-gate * 4167c478bd9Sstevel@tonic-gate * pci-class-intr-weights= 0x020000, 0xff0000, 30; 4177c478bd9Sstevel@tonic-gate * 4187c478bd9Sstevel@tonic-gate * can be used to augment or override entries in the default table below. 4197c478bd9Sstevel@tonic-gate * 4207c478bd9Sstevel@tonic-gate * NB: The values below give NICs preference on redistribution, and provide 4217c478bd9Sstevel@tonic-gate * NICs some isolation from other interrupt sources. We need better interfaces 4227c478bd9Sstevel@tonic-gate * that allow the NIC driver to identify a specific NIC instance as high 4237c478bd9Sstevel@tonic-gate * bandwidth, and thus deserving of separation from other low bandwidth 4247c478bd9Sstevel@tonic-gate * NICs additional isolation from other interrupt sources. 4257c478bd9Sstevel@tonic-gate * 4267c478bd9Sstevel@tonic-gate * NB: We treat Infiniband like a NIC. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate px_class_val_t px_default_intr_weight [] = { 4297c478bd9Sstevel@tonic-gate {0x020000, 0xff0000, 35}, /* Network Controller */ 4307c478bd9Sstevel@tonic-gate {0x010000, 0xff0000, 10}, /* Mass Storage Controller */ 4317c478bd9Sstevel@tonic-gate {0x0c0400, 0xffff00, 10}, /* Serial Bus, Fibre Channel */ 4327c478bd9Sstevel@tonic-gate {0x0c0600, 0xffff00, 50} /* Serial Bus, Infiniband */ 4337c478bd9Sstevel@tonic-gate }; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate static uint32_t 4367c478bd9Sstevel@tonic-gate px_match_class_val(uint32_t key, px_class_val_t *rec_p, int nrec, 4377c478bd9Sstevel@tonic-gate uint32_t default_val) 4387c478bd9Sstevel@tonic-gate { 4397c478bd9Sstevel@tonic-gate int i; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate for (i = 0; i < nrec; rec_p++, i++) { 4427c478bd9Sstevel@tonic-gate if ((rec_p->class_code & rec_p->class_mask) == 4437c478bd9Sstevel@tonic-gate (key & rec_p->class_mask)) 4447c478bd9Sstevel@tonic-gate return (rec_p->class_val); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate return (default_val); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * px_class_to_val 4527c478bd9Sstevel@tonic-gate * 4537c478bd9Sstevel@tonic-gate * Return the configuration value, based on class code and sub class code, 4547c478bd9Sstevel@tonic-gate * from the specified property based or default px_class_val_t table. 4557c478bd9Sstevel@tonic-gate */ 4567c478bd9Sstevel@tonic-gate uint32_t 4577c478bd9Sstevel@tonic-gate px_class_to_val(dev_info_t *rdip, char *property_name, px_class_val_t *rec_p, 4587c478bd9Sstevel@tonic-gate int nrec, uint32_t default_val) 4597c478bd9Sstevel@tonic-gate { 4607c478bd9Sstevel@tonic-gate int property_len; 4617c478bd9Sstevel@tonic-gate uint32_t class_code; 4627c478bd9Sstevel@tonic-gate px_class_val_t *conf; 4637c478bd9Sstevel@tonic-gate uint32_t val = default_val; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * Use the "class-code" property to get the base and sub class 4677c478bd9Sstevel@tonic-gate * codes for the requesting device. 4687c478bd9Sstevel@tonic-gate */ 4697c478bd9Sstevel@tonic-gate class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 4707c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "class-code", -1); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (class_code == -1) 4737c478bd9Sstevel@tonic-gate return (val); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* look up the val from the default table */ 4767c478bd9Sstevel@tonic-gate val = px_match_class_val(class_code, rec_p, nrec, val); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* see if there is a more specific property specified value */ 4797c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_NOTPROM, 4807c478bd9Sstevel@tonic-gate property_name, (caddr_t)&conf, &property_len)) 4817c478bd9Sstevel@tonic-gate return (val); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate if ((property_len % sizeof (px_class_val_t)) == 0) 4847c478bd9Sstevel@tonic-gate val = px_match_class_val(class_code, conf, 4857c478bd9Sstevel@tonic-gate property_len / sizeof (px_class_val_t), val); 4867c478bd9Sstevel@tonic-gate kmem_free(conf, property_len); 4877c478bd9Sstevel@tonic-gate return (val); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* px_class_to_pil: return the pil for a given device. */ 4917c478bd9Sstevel@tonic-gate uint32_t 4927c478bd9Sstevel@tonic-gate px_class_to_pil(dev_info_t *rdip) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate uint32_t pil; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* default pil is 0 (uninitialized) */ 4977c478bd9Sstevel@tonic-gate pil = px_class_to_val(rdip, 4987c478bd9Sstevel@tonic-gate "pci-class-priorities", px_default_pil, 4997c478bd9Sstevel@tonic-gate sizeof (px_default_pil) / sizeof (px_class_val_t), 0); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* range check the result */ 5027c478bd9Sstevel@tonic-gate if (pil >= 0xf) 5037c478bd9Sstevel@tonic-gate pil = 0; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate return (pil); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* px_class_to_intr_weight: return the intr_weight for a given device. */ 5097c478bd9Sstevel@tonic-gate static int32_t 5107c478bd9Sstevel@tonic-gate px_class_to_intr_weight(dev_info_t *rdip) 5117c478bd9Sstevel@tonic-gate { 5127c478bd9Sstevel@tonic-gate int32_t intr_weight; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* default weight is 0% */ 5157c478bd9Sstevel@tonic-gate intr_weight = px_class_to_val(rdip, 5167c478bd9Sstevel@tonic-gate "pci-class-intr-weights", px_default_intr_weight, 5177c478bd9Sstevel@tonic-gate sizeof (px_default_intr_weight) / sizeof (px_class_val_t), 0); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* range check the result */ 5207c478bd9Sstevel@tonic-gate if (intr_weight < 0) 5217c478bd9Sstevel@tonic-gate intr_weight = 0; 5227c478bd9Sstevel@tonic-gate if (intr_weight > 1000) 5237c478bd9Sstevel@tonic-gate intr_weight = 1000; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate return (intr_weight); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5297c478bd9Sstevel@tonic-gate int 5307c478bd9Sstevel@tonic-gate px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 5317c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 5327c478bd9Sstevel@tonic-gate { 533a195726fSgovinda px_t *px_p = DIP_TO_STATE(dip); 534a195726fSgovinda int ret = DDI_SUCCESS; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: dip=%x rdip=%x intr_op=%x " 5377c478bd9Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate switch (intr_op) { 5407c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5417c478bd9Sstevel@tonic-gate ret = pci_intx_get_cap(rdip, (int *)result); 5427c478bd9Sstevel@tonic-gate break; 5437c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 5447c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: SetCap is not supported\n"); 5457c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 5467c478bd9Sstevel@tonic-gate break; 5477c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 5487c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 5497c478bd9Sstevel@tonic-gate break; 5507c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 553a195726fSgovinda *(int *)result = hdlp->ih_pri ? 554a195726fSgovinda hdlp->ih_pri : px_class_to_pil(rdip); 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 5577c478bd9Sstevel@tonic-gate break; 5587c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 5597c478bd9Sstevel@tonic-gate ret = px_add_intx_intr(dip, rdip, hdlp); 5607c478bd9Sstevel@tonic-gate break; 5617c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 5627c478bd9Sstevel@tonic-gate ret = px_rem_intx_intr(dip, rdip, hdlp); 5637c478bd9Sstevel@tonic-gate break; 5647c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 5657c478bd9Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 56636fe4a92Segillett hdlp->ih_vector, PX_INTR_STATE_ENABLE, 0, 0); 5677c478bd9Sstevel@tonic-gate break; 5687c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 5697c478bd9Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 57036fe4a92Segillett hdlp->ih_vector, PX_INTR_STATE_DISABLE, 0, 0); 5717c478bd9Sstevel@tonic-gate break; 5727c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 5737c478bd9Sstevel@tonic-gate ret = pci_intx_set_mask(rdip); 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 5767c478bd9Sstevel@tonic-gate ret = pci_intx_clr_mask(rdip); 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 5797c478bd9Sstevel@tonic-gate ret = pci_intx_get_pending(rdip, (int *)result); 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 5827c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5837c478bd9Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip); 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate default: 5867c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate return (ret); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5947c478bd9Sstevel@tonic-gate int 5957c478bd9Sstevel@tonic-gate px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 5967c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 5977c478bd9Sstevel@tonic-gate { 5987c478bd9Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5997c478bd9Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 600*9c75c6bfSgovinda msiq_rec_type_t msiq_rec_type; 601*9c75c6bfSgovinda msi_type_t msi_type; 602*9c75c6bfSgovinda uint64_t msi_addr; 6037c478bd9Sstevel@tonic-gate msinum_t msi_num; 6047c478bd9Sstevel@tonic-gate msiqid_t msiq_id; 6057c478bd9Sstevel@tonic-gate uint_t nintrs; 6067c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x " 6097c478bd9Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 6107c478bd9Sstevel@tonic-gate 611*9c75c6bfSgovinda /* Check for MSI64 support */ 612*9c75c6bfSgovinda if (hdlp->ih_cap & DDI_INTR_FLAG_MSI64) { 613*9c75c6bfSgovinda msiq_rec_type = MSI64_REC; 614*9c75c6bfSgovinda msi_type = MSI64_TYPE; 615*9c75c6bfSgovinda msi_addr = msi_state_p->msi_addr64 ? 616*9c75c6bfSgovinda msi_state_p->msi_addr64:msi_state_p->msi_addr32; 617*9c75c6bfSgovinda } else { 618*9c75c6bfSgovinda msiq_rec_type = MSI32_REC; 619*9c75c6bfSgovinda msi_type = MSI32_TYPE; 620*9c75c6bfSgovinda msi_addr = msi_state_p->msi_addr32; 621*9c75c6bfSgovinda } 622*9c75c6bfSgovinda 6237c478bd9Sstevel@tonic-gate switch (intr_op) { 6247c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 6257c478bd9Sstevel@tonic-gate ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result); 6267c478bd9Sstevel@tonic-gate break; 6277c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 6287c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: SetCap is not supported\n"); 6297c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * We need to restrict this allocation in future 6347c478bd9Sstevel@tonic-gate * based on Resource Management policies. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate if ((ret = px_msi_alloc(px_p, rdip, hdlp->ih_inum, 6377c478bd9Sstevel@tonic-gate hdlp->ih_scratch1, hdlp->ih_scratch2, &msi_num, 6387c478bd9Sstevel@tonic-gate (int *)result)) != DDI_SUCCESS) { 6397c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: MSI allocation " 6407c478bd9Sstevel@tonic-gate "failed, rdip 0x%p inum 0x%x count 0x%x\n", 6417c478bd9Sstevel@tonic-gate rdip, hdlp->ih_inum, hdlp->ih_scratch1); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate return (ret); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 6487c478bd9Sstevel@tonic-gate (void) pci_msi_disable_mode(rdip, hdlp->ih_type, hdlp->ih_inum); 6497c478bd9Sstevel@tonic-gate (void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum); 6507c478bd9Sstevel@tonic-gate (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 6517c478bd9Sstevel@tonic-gate hdlp->ih_scratch1); 6527c478bd9Sstevel@tonic-gate break; 6537c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 6547c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_pri ? 6557c478bd9Sstevel@tonic-gate hdlp->ih_pri : px_class_to_pil(rdip); 6567c478bd9Sstevel@tonic-gate break; 6577c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 6587c478bd9Sstevel@tonic-gate break; 6597c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 6607c478bd9Sstevel@tonic-gate if ((ret = px_msi_get_msinum(px_p, hdlp->ih_dip, 6617c478bd9Sstevel@tonic-gate hdlp->ih_inum, &msi_num)) != DDI_SUCCESS) 6627c478bd9Sstevel@tonic-gate return (ret); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 665*9c75c6bfSgovinda msiq_rec_type, msi_num, &msiq_id)) != DDI_SUCCESS) { 6667c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler " 6677c478bd9Sstevel@tonic-gate "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 6687c478bd9Sstevel@tonic-gate return (ret); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setmsiq(dip, msi_num, 674*9c75c6bfSgovinda msiq_id, msi_type)) != DDI_SUCCESS) { 6757c478bd9Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 676*9c75c6bfSgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 6777c478bd9Sstevel@tonic-gate return (ret); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 6817c478bd9Sstevel@tonic-gate PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) { 6827c478bd9Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 683*9c75c6bfSgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 6847c478bd9Sstevel@tonic-gate return (ret); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate hdlp->ih_vector = msi_num; 6887c478bd9Sstevel@tonic-gate break; 6897c478bd9Sstevel@tonic-gate case DDI_INTROP_DUPVEC: 6907c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: DupIsr is not supported\n"); 6917c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 6927c478bd9Sstevel@tonic-gate break; 6937c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 6947c478bd9Sstevel@tonic-gate msi_num = hdlp->ih_vector; 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_getmsiq(dip, msi_num, 6977c478bd9Sstevel@tonic-gate &msiq_id)) != DDI_SUCCESS) 6987c478bd9Sstevel@tonic-gate return (ret); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 701*9c75c6bfSgovinda PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) 7027c478bd9Sstevel@tonic-gate return (ret); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate ret = px_rem_msiq_intr(dip, rdip, 705*9c75c6bfSgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate hdlp->ih_vector = 0; 7087c478bd9Sstevel@tonic-gate break; 7097c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 7107c478bd9Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setvalid(dip, msi_num, 7137c478bd9Sstevel@tonic-gate PCI_MSI_VALID)) != DDI_SUCCESS) 7147c478bd9Sstevel@tonic-gate return (ret); 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) { 7177c478bd9Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 720*9c75c6bfSgovinda nintrs, hdlp->ih_inum, msi_addr, 7217c478bd9Sstevel@tonic-gate msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7227c478bd9Sstevel@tonic-gate return (ret); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate if ((ret = pci_msi_enable_mode(rdip, hdlp->ih_type, 7257c478bd9Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7267c478bd9Sstevel@tonic-gate return (ret); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 72936fe4a92Segillett if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type, 73036fe4a92Segillett hdlp->ih_inum)) != DDI_SUCCESS) 73136fe4a92Segillett return (ret); 73236fe4a92Segillett 73336fe4a92Segillett if ((ret = px_lib_msi_getmsiq(dip, msi_num, 73436fe4a92Segillett &msiq_id)) != DDI_SUCCESS) 73536fe4a92Segillett return (ret); 73636fe4a92Segillett 73736fe4a92Segillett ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 73836fe4a92Segillett px_msiqid_to_devino(px_p, msiq_id), PX_INTR_STATE_ENABLE, 739*9c75c6bfSgovinda msiq_rec_type, msi_num); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate break; 7427c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 7437c478bd9Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if ((ret = pci_msi_set_mask(rdip, hdlp->ih_type, 7467c478bd9Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7477c478bd9Sstevel@tonic-gate return (ret); 7487c478bd9Sstevel@tonic-gate 74936fe4a92Segillett if ((ret = px_lib_msi_setvalid(dip, msi_num, 75036fe4a92Segillett PCI_MSI_INVALID)) != DDI_SUCCESS) 75136fe4a92Segillett return (ret); 75236fe4a92Segillett 75336fe4a92Segillett if ((ret = px_lib_msi_getmsiq(dip, msi_num, 75436fe4a92Segillett &msiq_id)) != DDI_SUCCESS) 75536fe4a92Segillett return (ret); 75636fe4a92Segillett 75736fe4a92Segillett ret = px_ib_update_intr_state(px_p, rdip, 75836fe4a92Segillett hdlp->ih_inum, px_msiqid_to_devino(px_p, msiq_id), 759*9c75c6bfSgovinda PX_INTR_STATE_DISABLE, msiq_rec_type, msi_num); 76036fe4a92Segillett 7617c478bd9Sstevel@tonic-gate break; 7627c478bd9Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 7637c478bd9Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7647c478bd9Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 767*9c75c6bfSgovinda nintrs, hdlp->ih_inum, msi_addr, 7687c478bd9Sstevel@tonic-gate msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7697c478bd9Sstevel@tonic-gate return (ret); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate for (i = 0; i < nintrs; i++, msi_num++) { 7727c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setvalid(dip, msi_num, 7737c478bd9Sstevel@tonic-gate PCI_MSI_VALID)) != DDI_SUCCESS) 7747c478bd9Sstevel@tonic-gate return (ret); 77536fe4a92Segillett 77636fe4a92Segillett if ((ret = px_lib_msi_getmsiq(dip, msi_num, 77736fe4a92Segillett &msiq_id)) != DDI_SUCCESS) 77836fe4a92Segillett return (ret); 77936fe4a92Segillett 78036fe4a92Segillett if ((ret = px_ib_update_intr_state(px_p, rdip, 78136fe4a92Segillett hdlp->ih_inum + i, px_msiqid_to_devino(px_p, 782*9c75c6bfSgovinda msiq_id), PX_INTR_STATE_ENABLE, msiq_rec_type, 783*9c75c6bfSgovinda msi_num)) != DDI_SUCCESS) 78436fe4a92Segillett return (ret); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate ret = pci_msi_enable_mode(rdip, hdlp->ih_type, hdlp->ih_inum); 7887c478bd9Sstevel@tonic-gate break; 7897c478bd9Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 7907c478bd9Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7917c478bd9Sstevel@tonic-gate msi_num = hdlp->ih_vector; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type, 7947c478bd9Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7957c478bd9Sstevel@tonic-gate return (ret); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate for (i = 0; i < nintrs; i++, msi_num++) { 7987c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setvalid(dip, msi_num, 7997c478bd9Sstevel@tonic-gate PCI_MSI_INVALID)) != DDI_SUCCESS) 8007c478bd9Sstevel@tonic-gate return (ret); 80136fe4a92Segillett 80236fe4a92Segillett if ((ret = px_lib_msi_getmsiq(dip, msi_num, 80336fe4a92Segillett &msiq_id)) != DDI_SUCCESS) 80436fe4a92Segillett return (ret); 80536fe4a92Segillett 80636fe4a92Segillett if ((ret = px_ib_update_intr_state(px_p, rdip, 80736fe4a92Segillett hdlp->ih_inum + i, px_msiqid_to_devino(px_p, 808*9c75c6bfSgovinda msiq_id), PX_INTR_STATE_DISABLE, msiq_rec_type, 80936fe4a92Segillett msi_num)) != DDI_SUCCESS) 81036fe4a92Segillett return (ret); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate break; 8147c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 8157c478bd9Sstevel@tonic-gate ret = pci_msi_set_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 8167c478bd9Sstevel@tonic-gate break; 8177c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 8187c478bd9Sstevel@tonic-gate ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 8197c478bd9Sstevel@tonic-gate break; 8207c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 8217c478bd9Sstevel@tonic-gate ret = pci_msi_get_pending(rdip, hdlp->ih_type, 8227c478bd9Sstevel@tonic-gate hdlp->ih_inum, (int *)result); 8237c478bd9Sstevel@tonic-gate break; 8247c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 8257c478bd9Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 8267c478bd9Sstevel@tonic-gate break; 8277c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 8287c478bd9Sstevel@tonic-gate /* XXX - a new interface may be needed */ 8297c478bd9Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 8307c478bd9Sstevel@tonic-gate break; 8317c478bd9Sstevel@tonic-gate default: 8327c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 8337c478bd9Sstevel@tonic-gate break; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate return (ret); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate 8396d44af1bSesolom static struct { 8406d44af1bSesolom kstat_named_t pxintr_ks_name; 8416d44af1bSesolom kstat_named_t pxintr_ks_type; 8426d44af1bSesolom kstat_named_t pxintr_ks_cpu; 8436d44af1bSesolom kstat_named_t pxintr_ks_pil; 8446d44af1bSesolom kstat_named_t pxintr_ks_time; 8456d44af1bSesolom kstat_named_t pxintr_ks_ino; 8466d44af1bSesolom kstat_named_t pxintr_ks_cookie; 8476d44af1bSesolom kstat_named_t pxintr_ks_devpath; 8486d44af1bSesolom kstat_named_t pxintr_ks_buspath; 8496d44af1bSesolom } pxintr_ks_template = { 8506d44af1bSesolom { "name", KSTAT_DATA_CHAR }, 8516d44af1bSesolom { "type", KSTAT_DATA_CHAR }, 8526d44af1bSesolom { "cpu", KSTAT_DATA_UINT64 }, 8536d44af1bSesolom { "pil", KSTAT_DATA_UINT64 }, 8546d44af1bSesolom { "time", KSTAT_DATA_UINT64 }, 8556d44af1bSesolom { "ino", KSTAT_DATA_UINT64 }, 8566d44af1bSesolom { "cookie", KSTAT_DATA_UINT64 }, 8576d44af1bSesolom { "devpath", KSTAT_DATA_STRING }, 8586d44af1bSesolom { "buspath", KSTAT_DATA_STRING }, 8596d44af1bSesolom }; 8606d44af1bSesolom 8616d44af1bSesolom static uint32_t pxintr_ks_instance; 8626d44af1bSesolom kmutex_t pxintr_ks_template_lock; 8636d44af1bSesolom 8646d44af1bSesolom int 8656d44af1bSesolom px_ks_update(kstat_t *ksp, int rw) 8666d44af1bSesolom { 8676d44af1bSesolom px_ih_t *ih_p = ksp->ks_private; 8686d44af1bSesolom int maxlen = sizeof (pxintr_ks_template.pxintr_ks_name.value.c); 8696d44af1bSesolom px_ib_t *ib_p = ih_p->ih_ino_p->ino_ib_p; 8706d44af1bSesolom px_t *px_p = ib_p->ib_px_p; 8716d44af1bSesolom devino_t ino; 8726d44af1bSesolom sysino_t sysino; 8736d44af1bSesolom char ih_devpath[MAXPATHLEN]; 8746d44af1bSesolom char ih_buspath[MAXPATHLEN]; 8756d44af1bSesolom 8766d44af1bSesolom ino = ih_p->ih_ino_p->ino_ino; 8776d44af1bSesolom (void) px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino); 8786d44af1bSesolom 8796d44af1bSesolom (void) snprintf(pxintr_ks_template.pxintr_ks_name.value.c, maxlen, 8806d44af1bSesolom "%s%d", ddi_driver_name(ih_p->ih_dip), 8816d44af1bSesolom ddi_get_instance(ih_p->ih_dip)); 8826d44af1bSesolom 8836d44af1bSesolom (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8846d44af1bSesolom (ih_p->ih_rec_type == 0) ? "fixed" : "msi"); 8856d44af1bSesolom pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ih_p->ih_ino_p->ino_cpuid; 8866d44af1bSesolom pxintr_ks_template.pxintr_ks_pil.value.ui64 = ih_p->ih_ino_p->ino_pil; 8876d44af1bSesolom pxintr_ks_template.pxintr_ks_time.value.ui64 = 8886d44af1bSesolom ih_p->ih_nsec + (uint64_t) 8896d44af1bSesolom tick2ns((hrtime_t)ih_p->ih_ticks, ih_p->ih_ino_p->ino_cpuid); 8906d44af1bSesolom pxintr_ks_template.pxintr_ks_ino.value.ui64 = ino; 8916d44af1bSesolom pxintr_ks_template.pxintr_ks_cookie.value.ui64 = sysino; 8926d44af1bSesolom 8936d44af1bSesolom (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 8946d44af1bSesolom (void) ddi_pathname(px_p->px_dip, ih_buspath); 8956d44af1bSesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_devpath, ih_devpath); 8966d44af1bSesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_buspath, ih_buspath); 8976d44af1bSesolom 8986d44af1bSesolom return (0); 8996d44af1bSesolom } 9006d44af1bSesolom 9016d44af1bSesolom void 9026d44af1bSesolom px_create_intr_kstats(px_ih_t *ih_p) 9036d44af1bSesolom { 9046d44af1bSesolom msiq_rec_type_t rec_type = ih_p->ih_rec_type; 9056d44af1bSesolom 9066d44af1bSesolom ASSERT(ih_p->ih_ksp == NULL); 9076d44af1bSesolom 9086d44af1bSesolom /* 9096d44af1bSesolom * Create pci_intrs::: kstats for all ih types except messages, 9106d44af1bSesolom * which represent unusual conditions and don't need to be tracked. 9116d44af1bSesolom */ 9126d44af1bSesolom if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 9136d44af1bSesolom ih_p->ih_ksp = kstat_create("pci_intrs", 9146d44af1bSesolom atomic_inc_32_nv(&pxintr_ks_instance), "config", 9156d44af1bSesolom "interrupts", KSTAT_TYPE_NAMED, 9166d44af1bSesolom sizeof (pxintr_ks_template) / sizeof (kstat_named_t), 9176d44af1bSesolom KSTAT_FLAG_VIRTUAL); 9186d44af1bSesolom } 9196d44af1bSesolom if (ih_p->ih_ksp != NULL) { 9206d44af1bSesolom ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 9216d44af1bSesolom ih_p->ih_ksp->ks_lock = &pxintr_ks_template_lock; 9226d44af1bSesolom ih_p->ih_ksp->ks_data = &pxintr_ks_template; 9236d44af1bSesolom ih_p->ih_ksp->ks_private = ih_p; 9246d44af1bSesolom ih_p->ih_ksp->ks_update = px_ks_update; 9256d44af1bSesolom } 9266d44af1bSesolom } 9276d44af1bSesolom 928a195726fSgovinda /* 929a195726fSgovinda * px_add_intx_intr: 930a195726fSgovinda * 931a195726fSgovinda * This function is called to register INTx and legacy hardware 932a195726fSgovinda * interrupt pins interrupts. 933a195726fSgovinda */ 9347c478bd9Sstevel@tonic-gate int 9357c478bd9Sstevel@tonic-gate px_add_intx_intr(dev_info_t *dip, dev_info_t *rdip, 9367c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 9377c478bd9Sstevel@tonic-gate { 9387c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 9397c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 9407c478bd9Sstevel@tonic-gate devino_t ino; 9417c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 9427c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 9437c478bd9Sstevel@tonic-gate int32_t weight; 9447c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate ino = hdlp->ih_vector; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: rdip=%s%d ino=%x " 9497c478bd9Sstevel@tonic-gate "handler=%x arg1=%x arg2=%x\n", ddi_driver_name(rdip), 9507c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), ino, hdlp->ih_cb_func, 9517c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, 9547c478bd9Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, 0, 0); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { /* sharing ino */ 9597c478bd9Sstevel@tonic-gate uint32_t intr_index = hdlp->ih_inum; 9607c478bd9Sstevel@tonic-gate if (px_ib_ino_locate_intr(ino_p, rdip, intr_index, 0, 0)) { 9617c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: " 9627c478bd9Sstevel@tonic-gate "dup intr #%d\n", intr_index); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 9657c478bd9Sstevel@tonic-gate goto fail1; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* Save mondo value in hdlp */ 9697c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate if ((ret = px_ib_ino_add_intr(px_p, ino_p, ih_p)) 9727c478bd9Sstevel@tonic-gate != DDI_SUCCESS) 9737c478bd9Sstevel@tonic-gate goto fail1; 9747c478bd9Sstevel@tonic-gate } else { 9757c478bd9Sstevel@tonic-gate ino_p = px_ib_new_ino(ib_p, ino, ih_p); 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate if (hdlp->ih_pri == 0) 9787c478bd9Sstevel@tonic-gate hdlp->ih_pri = px_class_to_pil(rdip); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* Save mondo value in hdlp */ 9817c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: pil=0x%x mondo=0x%x\n", 9847c478bd9Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 9877c478bd9Sstevel@tonic-gate (ddi_intr_handler_t *)px_intx_intr, (caddr_t)ino_p, NULL); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * Restore original interrupt handler 9937c478bd9Sstevel@tonic-gate * and arguments in interrupt handle. 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 9967c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 9997c478bd9Sstevel@tonic-gate goto fail2; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* Save the pil for this ino */ 10027c478bd9Sstevel@tonic-gate ino_p->ino_pil = hdlp->ih_pri; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* select cpu, saving it for sharing and removal */ 10057c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* Enable interrupt */ 10087c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate /* add weight to the cpu that we are already targeting */ 10127c478bd9Sstevel@tonic-gate weight = px_class_to_intr_weight(rdip); 10137c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate ih_p->ih_ino_p = ino_p; 10166d44af1bSesolom px_create_intr_kstats(ih_p); 10177c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp) 10187c478bd9Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 10197c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: done! Interrupt 0x%x pil=%x\n", 10227c478bd9Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate return (ret); 10257c478bd9Sstevel@tonic-gate fail2: 10267c478bd9Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 10277c478bd9Sstevel@tonic-gate fail1: 10287c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 10297c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10327c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: Failed! Interrupt 0x%x " 10357c478bd9Sstevel@tonic-gate "pil=%x\n", ino_p->ino_sysino, hdlp->ih_pri); 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate return (ret); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate 1040a195726fSgovinda /* 1041a195726fSgovinda * px_rem_intx_intr: 1042a195726fSgovinda * 1043a195726fSgovinda * This function is called to unregister INTx and legacy hardware 1044a195726fSgovinda * interrupt pins interrupts. 1045a195726fSgovinda */ 10467c478bd9Sstevel@tonic-gate int 10477c478bd9Sstevel@tonic-gate px_rem_intx_intr(dev_info_t *dip, dev_info_t *rdip, 10487c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 10517c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 10527c478bd9Sstevel@tonic-gate devino_t ino; 10537c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 10547c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 10557c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 10567c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate ino = hdlp->ih_vector; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, dip, "px_rem_intx_intr: rdip=%s%d ino=%x\n", 10617c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 10667c478bd9Sstevel@tonic-gate ih_p = px_ib_ino_locate_intr(ino_p, rdip, hdlp->ih_inum, 0, 0); 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* Get the current cpu */ 10697c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 10707c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 10717c478bd9Sstevel@tonic-gate goto fail; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate if ((ret = px_ib_ino_rem_intr(px_p, ino_p, ih_p)) != DDI_SUCCESS) 10747c478bd9Sstevel@tonic-gate goto fail; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_size == 0) { 10797c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 10807c478bd9Sstevel@tonic-gate INTR_DELIVERED_STATE)) != DDI_SUCCESS) 10817c478bd9Sstevel@tonic-gate goto fail; 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 10847c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 10877c478bd9Sstevel@tonic-gate kmem_free(ino_p, sizeof (px_ib_ino_info_t)); 10887c478bd9Sstevel@tonic-gate } else { 10897c478bd9Sstevel@tonic-gate /* Re-enable interrupt only if mapping regsiter still shared */ 1090a195726fSgovinda PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate fail: 10947c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10957c478bd9Sstevel@tonic-gate return (ret); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 1098a195726fSgovinda /* 1099a195726fSgovinda * px_add_msiq_intr: 1100a195726fSgovinda * 1101a195726fSgovinda * This function is called to register MSI/Xs and PCIe message interrupts. 1102a195726fSgovinda */ 11037c478bd9Sstevel@tonic-gate int 11047c478bd9Sstevel@tonic-gate px_add_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 11057c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 11067c478bd9Sstevel@tonic-gate msgcode_t msg_code, msiqid_t *msiq_id_p) 11077c478bd9Sstevel@tonic-gate { 11087c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 11097c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 11107c478bd9Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 11117c478bd9Sstevel@tonic-gate devino_t ino; 11127c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 11137c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 11147c478bd9Sstevel@tonic-gate int32_t weight; 11157c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: rdip=%s%d handler=%x " 11187c478bd9Sstevel@tonic-gate "arg1=%x arg2=%x\n", ddi_driver_name(rdip), ddi_get_instance(rdip), 11197c478bd9Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate if ((ret = px_msiq_alloc(px_p, rec_type, msiq_id_p)) != DDI_SUCCESS) { 11227c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 11237c478bd9Sstevel@tonic-gate "msiq allocation failed\n"); 11247c478bd9Sstevel@tonic-gate return (ret); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate ino = px_msiqid_to_devino(px_p, *msiq_id_p); 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, hdlp->ih_cb_func, 11307c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rec_type, msg_code); 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { /* sharing ino */ 11357c478bd9Sstevel@tonic-gate uint32_t intr_index = hdlp->ih_inum; 11367c478bd9Sstevel@tonic-gate if (px_ib_ino_locate_intr(ino_p, rdip, 11377c478bd9Sstevel@tonic-gate intr_index, rec_type, msg_code)) { 11387c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 11397c478bd9Sstevel@tonic-gate "dup intr #%d\n", intr_index); 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 11427c478bd9Sstevel@tonic-gate goto fail1; 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate if ((ret = px_ib_ino_add_intr(px_p, ino_p, ih_p)) 11467c478bd9Sstevel@tonic-gate != DDI_SUCCESS) 11477c478bd9Sstevel@tonic-gate goto fail1; 11487c478bd9Sstevel@tonic-gate } else { 11497c478bd9Sstevel@tonic-gate ino_p = px_ib_new_ino(ib_p, ino, ih_p); 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate ino_p->ino_msiq_p = msiq_state_p->msiq_p + 11527c478bd9Sstevel@tonic-gate (*msiq_id_p - msiq_state_p->msiq_1st_msiq_id); 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate if (hdlp->ih_pri == 0) 11557c478bd9Sstevel@tonic-gate hdlp->ih_pri = px_class_to_pil(rdip); 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* Save mondo value in hdlp */ 11587c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: pil=0x%x mondo=0x%x\n", 11617c478bd9Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 11647c478bd9Sstevel@tonic-gate (ddi_intr_handler_t *)px_msiq_intr, (caddr_t)ino_p, NULL); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* 11697c478bd9Sstevel@tonic-gate * Restore original interrupt handler 11707c478bd9Sstevel@tonic-gate * and arguments in interrupt handle. 11717c478bd9Sstevel@tonic-gate */ 11727c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 11737c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 11767c478bd9Sstevel@tonic-gate goto fail2; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* Save the pil for this ino */ 11797c478bd9Sstevel@tonic-gate ino_p->ino_pil = hdlp->ih_pri; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* Enable MSIQ */ 11827c478bd9Sstevel@tonic-gate px_lib_msiq_setstate(dip, *msiq_id_p, PCI_MSIQ_STATE_IDLE); 11837c478bd9Sstevel@tonic-gate px_lib_msiq_setvalid(dip, *msiq_id_p, PCI_MSIQ_VALID); 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate /* select cpu, saving it for sharing and removal */ 11867c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* Enable interrupt */ 11897c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino_p->ino_ino); 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate /* add weight to the cpu that we are already targeting */ 11937c478bd9Sstevel@tonic-gate weight = px_class_to_intr_weight(rdip); 11947c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate ih_p->ih_ino_p = ino_p; 11976d44af1bSesolom px_create_intr_kstats(ih_p); 11987c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp) 11997c478bd9Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 12007c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: done! Interrupt 0x%x pil=%x\n", 12037c478bd9Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate return (ret); 12067c478bd9Sstevel@tonic-gate fail2: 12077c478bd9Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 12087c478bd9Sstevel@tonic-gate fail1: 12097c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 12107c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12137c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: Failed! Interrupt 0x%x pil=%x\n", 12167c478bd9Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate return (ret); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 1221a195726fSgovinda /* 1222a195726fSgovinda * px_rem_msiq_intr: 1223a195726fSgovinda * 1224a195726fSgovinda * This function is called to unregister MSI/Xs and PCIe message interrupts. 1225a195726fSgovinda */ 12267c478bd9Sstevel@tonic-gate int 12277c478bd9Sstevel@tonic-gate px_rem_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 12287c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 12297c478bd9Sstevel@tonic-gate msgcode_t msg_code, msiqid_t msiq_id) 12307c478bd9Sstevel@tonic-gate { 12317c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 12327c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 12337c478bd9Sstevel@tonic-gate devino_t ino = px_msiqid_to_devino(px_p, msiq_id); 12347c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 12357c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 12367c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 12377c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_rem_msiq_intr: rdip=%s%d msiq_id=%x ino=%x\n", 12407c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), msiq_id, ino); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 12457c478bd9Sstevel@tonic-gate ih_p = px_ib_ino_locate_intr(ino_p, rdip, hdlp->ih_inum, 12467c478bd9Sstevel@tonic-gate rec_type, msg_code); 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate /* Get the current cpu */ 12497c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 12507c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 12517c478bd9Sstevel@tonic-gate goto fail; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate if ((ret = px_ib_ino_rem_intr(px_p, ino_p, ih_p)) != DDI_SUCCESS) 12547c478bd9Sstevel@tonic-gate goto fail; 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_size == 0) { 12597c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 12607c478bd9Sstevel@tonic-gate INTR_DELIVERED_STATE)) != DDI_SUCCESS) 12617c478bd9Sstevel@tonic-gate goto fail; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate px_lib_msiq_setvalid(dip, px_devino_to_msiqid(px_p, ino), 12647c478bd9Sstevel@tonic-gate PCI_MSIQ_INVALID); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 12677c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate px_ib_delete_ino(ib_p, ino_p); 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate (void) px_msiq_free(px_p, msiq_id); 12727c478bd9Sstevel@tonic-gate kmem_free(ino_p, sizeof (px_ib_ino_info_t)); 12737c478bd9Sstevel@tonic-gate } else { 12747c478bd9Sstevel@tonic-gate /* Re-enable interrupt only if mapping regsiter still shared */ 1275a195726fSgovinda PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate fail: 12797c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12807c478bd9Sstevel@tonic-gate return (ret); 12817c478bd9Sstevel@tonic-gate } 1282