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 5102cb92eSjohnny * Common Development and Distribution License (the "License"). 6102cb92eSjohnny * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22657f87deSgongtian zhao - Sun Microsystems - Beijing China * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * PX nexus interrupt handling: 277c478bd9Sstevel@tonic-gate * PX device interrupt handler wrapper 287c478bd9Sstevel@tonic-gate * PIL lookup routine 297c478bd9Sstevel@tonic-gate * PX device interrupt related initchild code 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 347c478bd9Sstevel@tonic-gate #include <sys/async.h> 357c478bd9Sstevel@tonic-gate #include <sys/spl.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 37f8d2de6bSjchu #include <sys/fm/protocol.h> 38f8d2de6bSjchu #include <sys/fm/util.h> 397c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */ 407c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 417c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 427c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 437c478bd9Sstevel@tonic-gate #include "px_obj.h" 44f8d2de6bSjchu #include <sys/ontrap.h> 45f8d2de6bSjchu #include <sys/membar.h> 466d44af1bSesolom #include <sys/clock.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * interrupt jabber: 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * When an interrupt line is jabbering, every time the state machine for the 527c478bd9Sstevel@tonic-gate * associated ino is idled, a new mondo will be sent and the ino will go into 537c478bd9Sstevel@tonic-gate * the pending state again. The mondo will cause a new call to 547c478bd9Sstevel@tonic-gate * px_intr_wrapper() which normally idles the ino's state machine which would 557c478bd9Sstevel@tonic-gate * precipitate another trip round the loop. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * The loop can be broken by preventing the ino's state machine from being 587c478bd9Sstevel@tonic-gate * idled when an interrupt line is jabbering. See the comment at the 597c478bd9Sstevel@tonic-gate * beginning of px_intr_wrapper() explaining how the 'interrupt jabber 607c478bd9Sstevel@tonic-gate * protection' code does this. 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * If the unclaimed interrupt count has reached the limit set by 677c478bd9Sstevel@tonic-gate * pci_unclaimed_intr_max within the time limit, then all interrupts 687c478bd9Sstevel@tonic-gate * on this ino is blocked by not idling the interrupt state machine. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate static int 71b0fc0e77Sgovinda px_spurintr(px_ino_pil_t *ipil_p) 727c478bd9Sstevel@tonic-gate { 73b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 744bd2626cSDaniel Ice px_ih_t *ih_p; 757c478bd9Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 767c478bd9Sstevel@tonic-gate char *err_fmt_str; 77b0fc0e77Sgovinda boolean_t blocked = B_FALSE; 787c478bd9Sstevel@tonic-gate int i; 797c478bd9Sstevel@tonic-gate 80b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) 817c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 827c478bd9Sstevel@tonic-gate 83b0fc0e77Sgovinda if (!ino_p->ino_unclaimed_intrs) 847c478bd9Sstevel@tonic-gate ino_p->ino_spurintr_begin = ddi_get_lbolt(); 857c478bd9Sstevel@tonic-gate 86b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs++; 877c478bd9Sstevel@tonic-gate 88b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs <= px_unclaimed_intr_max) 897c478bd9Sstevel@tonic-gate goto clear; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin) 927c478bd9Sstevel@tonic-gate > px_spurintr_duration) { 93b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 947c478bd9Sstevel@tonic-gate goto clear; 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate err_fmt_str = "%s%d: ino 0x%x blocked"; 97b0fc0e77Sgovinda blocked = B_TRUE; 987c478bd9Sstevel@tonic-gate goto warn; 997c478bd9Sstevel@tonic-gate clear: 1007c478bd9Sstevel@tonic-gate err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; 1017c478bd9Sstevel@tonic-gate warn: 1027c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, err_fmt_str, NAMEINST(px_p->px_dip), ino_p->ino_ino); 1034bd2626cSDaniel Ice for (ipil_p = ino_p->ino_ipil_p; ipil_p; 1044bd2626cSDaniel Ice ipil_p = ipil_p->ipil_next_p) { 1054bd2626cSDaniel Ice for (i = 0, ih_p = ipil_p->ipil_ih_start; 1064bd2626cSDaniel Ice i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) 1077c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), 1087c478bd9Sstevel@tonic-gate ih_p->ih_inum); 1094bd2626cSDaniel Ice } 1107c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "!\n"); 111b0fc0e77Sgovinda 112b0fc0e77Sgovinda /* Clear the pending state */ 113b0fc0e77Sgovinda if (blocked == B_FALSE) { 114b0fc0e77Sgovinda if (px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 115b0fc0e77Sgovinda INTR_IDLE_STATE) != DDI_SUCCESS) 116b0fc0e77Sgovinda return (DDI_INTR_UNCLAIMED); 117b0fc0e77Sgovinda } 118b0fc0e77Sgovinda 1197c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate extern uint64_t intr_get_time(void); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 125a195726fSgovinda * px_intx_intr (INTx or legacy interrupt handler) 1267c478bd9Sstevel@tonic-gate * 1277c478bd9Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 1287c478bd9Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 1297c478bd9Sstevel@tonic-gate * examines the return codes. 1307c478bd9Sstevel@tonic-gate * 1317c478bd9Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 1327c478bd9Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 1337c478bd9Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 1347c478bd9Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 1357c478bd9Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 1367c478bd9Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 1377c478bd9Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 1387c478bd9Sstevel@tonic-gate * handler is subsequently added or removed. 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 1417c478bd9Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate uint_t 1447c478bd9Sstevel@tonic-gate px_intx_intr(caddr_t arg) 1457c478bd9Sstevel@tonic-gate { 146b0fc0e77Sgovinda px_ino_pil_t *ipil_p = (px_ino_pil_t *)arg; 147b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 1487c478bd9Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 149b0fc0e77Sgovinda px_ih_t *ih_p = ipil_p->ipil_ih_start; 150b0fc0e77Sgovinda ushort_t pil = ipil_p->ipil_pil; 151b0fc0e77Sgovinda uint_t result = 0, r = DDI_INTR_UNCLAIMED; 1527c478bd9Sstevel@tonic-gate int i; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1557c478bd9Sstevel@tonic-gate "ino=%x sysino=%llx pil=%x ih_size=%x ih_lst=%x\n", 156b0fc0e77Sgovinda ino_p->ino_ino, ino_p->ino_sysino, ipil_p->ipil_pil, 157b0fc0e77Sgovinda ipil_p->ipil_ih_size, ipil_p->ipil_ih_head); 1587c478bd9Sstevel@tonic-gate 159b0fc0e77Sgovinda for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 1607c478bd9Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip; 1617c478bd9Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 1627c478bd9Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 1637c478bd9Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (ih_p->ih_intr_state == PX_INTR_STATE_DISABLE) { 1667c478bd9Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, 1677c478bd9Sstevel@tonic-gate "px_intx_intr: %s%d interrupt %d is disabled\n", 1687c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1697c478bd9Sstevel@tonic-gate ino_p->ino_ino); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 1757c478bd9Sstevel@tonic-gate "ino=%x handler=%p arg1 =%p arg2 = %p\n", 1767c478bd9Sstevel@tonic-gate ino_p->ino_ino, handler, arg1, arg2); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 1797c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate r = (*handler)(arg1, arg2); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * Account for time used by this interrupt. Protect against 1857c478bd9Sstevel@tonic-gate * conflicting writes to ih_ticks from ib_intr_dist_all() by 1867c478bd9Sstevel@tonic-gate * using atomic ops. 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate 189b0fc0e77Sgovinda if (pil <= LOCK_LEVEL) 1907c478bd9Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 1937c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, r); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate result += r; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate if (px_check_all_handlers) 1987c478bd9Sstevel@tonic-gate continue; 1997c478bd9Sstevel@tonic-gate if (result) 2007c478bd9Sstevel@tonic-gate break; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 203b0fc0e77Sgovinda if (result) 204b0fc0e77Sgovinda ino_p->ino_claimed |= (1 << pil); 2057c478bd9Sstevel@tonic-gate 206b0fc0e77Sgovinda /* Interrupt can only be cleared after all pil levels are handled */ 207b0fc0e77Sgovinda if (pil != ino_p->ino_lopil) 208b0fc0e77Sgovinda return (DDI_INTR_CLAIMED); 209b0fc0e77Sgovinda 210b0fc0e77Sgovinda if (!ino_p->ino_claimed) { 211b0fc0e77Sgovinda if (px_unclaimed_intr_block) 212b0fc0e77Sgovinda return (px_spurintr(ipil_p)); 213b0fc0e77Sgovinda } 214b0fc0e77Sgovinda 215b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 216b0fc0e77Sgovinda ino_p->ino_claimed = 0; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* Clear the pending state */ 219b0fc0e77Sgovinda if (px_lib_intr_setstate(px_p->px_dip, 2207c478bd9Sstevel@tonic-gate ino_p->ino_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 2217c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* 227a195726fSgovinda * px_msiq_intr (MSI/X or PCIe MSG interrupt handler) 2287c478bd9Sstevel@tonic-gate * 2297c478bd9Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child 2307c478bd9Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and 2317c478bd9Sstevel@tonic-gate * examines the return codes. 2327c478bd9Sstevel@tonic-gate * 2337c478bd9Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at 2347c478bd9Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the 2357c478bd9Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then 2367c478bd9Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled. 2377c478bd9Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max 2387c478bd9Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further 2397c478bd9Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a 2407c478bd9Sstevel@tonic-gate * handler is subsequently added or removed. 2417c478bd9Sstevel@tonic-gate * 2427c478bd9Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 2437c478bd9Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise. 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate uint_t 2467c478bd9Sstevel@tonic-gate px_msiq_intr(caddr_t arg) 2477c478bd9Sstevel@tonic-gate { 248b0fc0e77Sgovinda px_ino_pil_t *ipil_p = (px_ino_pil_t *)arg; 249b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 2507c478bd9Sstevel@tonic-gate px_t *px_p = ino_p->ino_ib_p->ib_px_p; 2517c478bd9Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 2527c478bd9Sstevel@tonic-gate px_msiq_t *msiq_p = ino_p->ino_msiq_p; 2537c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 254b0fc0e77Sgovinda ushort_t pil = ipil_p->ipil_pil; 2557c478bd9Sstevel@tonic-gate msiq_rec_t msiq_rec, *msiq_rec_p = &msiq_rec; 256023ccc1eSegillett msiqhead_t *curr_head_p; 257023ccc1eSegillett msiqtail_t curr_tail_index; 2587c478bd9Sstevel@tonic-gate msgcode_t msg_code; 2597c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 260b0fc0e77Sgovinda uint_t ret = DDI_INTR_UNCLAIMED; 261b0fc0e77Sgovinda int i, j; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x " 2647c478bd9Sstevel@tonic-gate "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino, 265b0fc0e77Sgovinda ipil_p->ipil_pil, ipil_p->ipil_ih_size, ipil_p->ipil_ih_head); 2667c478bd9Sstevel@tonic-gate 267b0fc0e77Sgovinda /* 268b0fc0e77Sgovinda * The px_msiq_intr() handles multiple interrupt priorities and it 269b0fc0e77Sgovinda * will set msiq->msiq_rec2process to the number of MSIQ records to 270b0fc0e77Sgovinda * process while handling the highest priority interrupt. Subsequent 271b0fc0e77Sgovinda * lower priority interrupts will just process any unprocessed MSIQ 272b0fc0e77Sgovinda * records or will just return immediately. 273b0fc0e77Sgovinda */ 274b0fc0e77Sgovinda if (msiq_p->msiq_recs2process == 0) { 2754bd2626cSDaniel Ice ASSERT(ino_p->ino_ipil_cntr == 0); 2764bd2626cSDaniel Ice ino_p->ino_ipil_cntr = ino_p->ino_ipil_size; 2774bd2626cSDaniel Ice 278023ccc1eSegillett /* Read current MSIQ tail index */ 279023ccc1eSegillett px_lib_msiq_gettail(dip, msiq_p->msiq_id, &curr_tail_index); 280b0fc0e77Sgovinda msiq_p->msiq_new_head_index = msiq_p->msiq_curr_head_index; 2817c478bd9Sstevel@tonic-gate 282b0fc0e77Sgovinda if (curr_tail_index < msiq_p->msiq_curr_head_index) 283023ccc1eSegillett curr_tail_index += msiq_state_p->msiq_rec_cnt; 2847c478bd9Sstevel@tonic-gate 285b0fc0e77Sgovinda msiq_p->msiq_recs2process = curr_tail_index - 286b0fc0e77Sgovinda msiq_p->msiq_curr_head_index; 287b0fc0e77Sgovinda } 288b0fc0e77Sgovinda 289b0fc0e77Sgovinda DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x " 290b0fc0e77Sgovinda "rec2process %x\n", msiq_p->msiq_curr_head_index, 291b0fc0e77Sgovinda msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process); 292b0fc0e77Sgovinda 293b0fc0e77Sgovinda /* If all MSIQ records are already processed, just return immediately */ 294b0fc0e77Sgovinda if ((msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index) 295b0fc0e77Sgovinda == msiq_p->msiq_recs2process) 296b0fc0e77Sgovinda goto intr_done; 297b0fc0e77Sgovinda 298b0fc0e77Sgovinda curr_head_p = (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p + 299b0fc0e77Sgovinda (msiq_p->msiq_curr_head_index * sizeof (msiq_rec_t))); 300b0fc0e77Sgovinda 3017c478bd9Sstevel@tonic-gate /* 302023ccc1eSegillett * Calculate the number of recs to process by taking the difference 303023ccc1eSegillett * between the head and tail pointers. For all records we always 304023ccc1eSegillett * verify that we have a valid record type before we do any processing. 305b0fc0e77Sgovinda * If triggered, we should always have at least one valid record. 3067c478bd9Sstevel@tonic-gate */ 307b0fc0e77Sgovinda for (i = 0; i < msiq_p->msiq_recs2process; i++) { 3082324ee65SAlan Adamson, SD OSSD msiq_rec_type_t rec_type; 3092324ee65SAlan Adamson, SD OSSD 310b0fc0e77Sgovinda /* Read next MSIQ record */ 311023ccc1eSegillett px_lib_get_msiq_rec(dip, curr_head_p, msiq_rec_p); 312023ccc1eSegillett 3132324ee65SAlan Adamson, SD OSSD rec_type = msiq_rec_p->msiq_rec_type; 3142324ee65SAlan Adamson, SD OSSD 3157c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, " 3167c478bd9Sstevel@tonic-gate "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n", 3172324ee65SAlan Adamson, SD OSSD rec_type, msiq_rec_p->msiq_rec_rid); 3187c478bd9Sstevel@tonic-gate 3192324ee65SAlan Adamson, SD OSSD if (!rec_type) 320b0fc0e77Sgovinda goto next_rec; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* Check MSIQ record type */ 3232324ee65SAlan Adamson, SD OSSD switch (rec_type) { 3247c478bd9Sstevel@tonic-gate case MSG_REC: 3257c478bd9Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msg.msg_code; 3267c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: PCIE MSG " 3277c478bd9Sstevel@tonic-gate "record, msg type 0x%x\n", msg_code); 3287c478bd9Sstevel@tonic-gate break; 3297c478bd9Sstevel@tonic-gate case MSI32_REC: 3307c478bd9Sstevel@tonic-gate case MSI64_REC: 3317c478bd9Sstevel@tonic-gate msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data; 3327c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, " 3337c478bd9Sstevel@tonic-gate "msi 0x%x\n", msg_code); 3347c478bd9Sstevel@tonic-gate break; 3357c478bd9Sstevel@tonic-gate default: 3367c478bd9Sstevel@tonic-gate msg_code = 0; 3377c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_msiq_intr: 0x%x MSIQ " 3387c478bd9Sstevel@tonic-gate "record type is not supported", 3397c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 3402324ee65SAlan Adamson, SD OSSD rec_type); 341b0fc0e77Sgovinda 3427c478bd9Sstevel@tonic-gate goto next_rec; 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * Scan through px_ih_t linked list, searching for the 3477c478bd9Sstevel@tonic-gate * right px_ih_t, matching MSIQ record data. 3487c478bd9Sstevel@tonic-gate */ 349b0fc0e77Sgovinda for (j = 0, ih_p = ipil_p->ipil_ih_start; 350b0fc0e77Sgovinda ih_p && (j < ipil_p->ipil_ih_size) && 35107f14c08Sgovinda ((ih_p->ih_msg_code != msg_code) || 3522324ee65SAlan Adamson, SD OSSD (ih_p->ih_rec_type != rec_type)); 3532917a9c9Sschwartz ih_p = ih_p->ih_next, j++) 3542917a9c9Sschwartz ; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if ((ih_p->ih_msg_code == msg_code) && 3572324ee65SAlan Adamson, SD OSSD (ih_p->ih_rec_type == rec_type)) { 358d17daf0bSScott Carter, SD IOSW dev_info_t *ih_dip = ih_p->ih_dip; 3597c478bd9Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler; 3607c478bd9Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1; 3617c478bd9Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2; 3627c478bd9Sstevel@tonic-gate 363d17daf0bSScott Carter, SD IOSW DBG(DBG_MSIQ_INTR, ih_dip, "px_msiq_intr: ino=%x " 364d17daf0bSScott Carter, SD IOSW "data=%x handler=%p arg1 =%p arg2=%p\n", 365d17daf0bSScott Carter, SD IOSW ino_p->ino_ino, msg_code, handler, arg1, arg2); 3667c478bd9Sstevel@tonic-gate 367d17daf0bSScott Carter, SD IOSW DTRACE_PROBE4(interrupt__start, dev_info_t, ih_dip, 3687c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2); 3697c478bd9Sstevel@tonic-gate 370d17daf0bSScott Carter, SD IOSW ih_p->ih_intr_flags = PX_INTR_PENDING; 37109b1eac2SEvan Yan 372f8d2de6bSjchu /* 373f8d2de6bSjchu * Special case for PCIE Error Messages. 374f8d2de6bSjchu * The current frame work doesn't fit PCIE Err Msgs 375f8d2de6bSjchu * This should be fixed when PCIE MESSAGES as a whole 376f8d2de6bSjchu * is architected correctly. 377f8d2de6bSjchu */ 3782324ee65SAlan Adamson, SD OSSD if ((rec_type == MSG_REC) && 3792324ee65SAlan Adamson, SD OSSD ((msg_code == PCIE_MSG_CODE_ERR_COR) || 380f8d2de6bSjchu (msg_code == PCIE_MSG_CODE_ERR_NONFATAL) || 3812324ee65SAlan Adamson, SD OSSD (msg_code == PCIE_MSG_CODE_ERR_FATAL))) { 382f8d2de6bSjchu ret = px_err_fabric_intr(px_p, msg_code, 383f8d2de6bSjchu msiq_rec_p->msiq_rec_rid); 384d17daf0bSScott Carter, SD IOSW } else { 385d17daf0bSScott Carter, SD IOSW /* Clear MSI state */ 386d17daf0bSScott Carter, SD IOSW px_lib_msi_setstate(dip, (msinum_t)msg_code, 387d17daf0bSScott Carter, SD IOSW PCI_MSI_STATE_IDLE); 388d17daf0bSScott Carter, SD IOSW 3897c478bd9Sstevel@tonic-gate ret = (*handler)(arg1, arg2); 390d17daf0bSScott Carter, SD IOSW } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * Account for time used by this interrupt. Protect 3947c478bd9Sstevel@tonic-gate * against conflicting writes to ih_ticks from 3957c478bd9Sstevel@tonic-gate * ib_intr_dist_all() by using atomic ops. 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate 398b0fc0e77Sgovinda if (pil <= LOCK_LEVEL) 3997c478bd9Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 4007c478bd9Sstevel@tonic-gate 401d17daf0bSScott Carter, SD IOSW DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_dip, 4027c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, ret); 403023ccc1eSegillett 404d17daf0bSScott Carter, SD IOSW /* clear handler status flags */ 405d17daf0bSScott Carter, SD IOSW ih_p->ih_intr_flags = PX_INTR_IDLE; 406d17daf0bSScott Carter, SD IOSW 407b0fc0e77Sgovinda msiq_p->msiq_new_head_index++; 408d17daf0bSScott Carter, SD IOSW px_lib_clr_msiq_rec(ih_dip, curr_head_p); 4097c478bd9Sstevel@tonic-gate } else { 4107c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: " 411023ccc1eSegillett "No matching MSIQ record found\n"); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate next_rec: 414023ccc1eSegillett /* Get the pointer next EQ record */ 415023ccc1eSegillett curr_head_p = (msiqhead_t *) 416023ccc1eSegillett ((caddr_t)curr_head_p + sizeof (msiq_rec_t)); 417023ccc1eSegillett 418023ccc1eSegillett /* Check for overflow condition */ 419023ccc1eSegillett if (curr_head_p >= (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p 420b0fc0e77Sgovinda + (msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t)))) 421023ccc1eSegillett curr_head_p = (msiqhead_t *)msiq_p->msiq_base_p; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 424b0fc0e77Sgovinda DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n", 425b0fc0e77Sgovinda (msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index)); 426023ccc1eSegillett 427b0fc0e77Sgovinda DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x " 428b0fc0e77Sgovinda "rec2process %x\n", msiq_p->msiq_curr_head_index, 429b0fc0e77Sgovinda msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process); 430b0fc0e77Sgovinda 431b0fc0e77Sgovinda /* ino_claimed used just for debugging purpose */ 432b0fc0e77Sgovinda if (ret) 433b0fc0e77Sgovinda ino_p->ino_claimed |= (1 << pil); 434b0fc0e77Sgovinda 435b0fc0e77Sgovinda intr_done: 436b0fc0e77Sgovinda /* Interrupt can only be cleared after all pil levels are handled */ 4374bd2626cSDaniel Ice if (--ino_p->ino_ipil_cntr != 0) 438b0fc0e77Sgovinda return (DDI_INTR_CLAIMED); 439b0fc0e77Sgovinda 440b0fc0e77Sgovinda if (msiq_p->msiq_new_head_index <= msiq_p->msiq_curr_head_index) { 441b0fc0e77Sgovinda if (px_unclaimed_intr_block) 442b0fc0e77Sgovinda return (px_spurintr(ipil_p)); 443023ccc1eSegillett } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* Update MSIQ head index with no of MSIQ records processed */ 446b0fc0e77Sgovinda if (msiq_p->msiq_new_head_index >= msiq_state_p->msiq_rec_cnt) 447b0fc0e77Sgovinda msiq_p->msiq_new_head_index -= msiq_state_p->msiq_rec_cnt; 4487c478bd9Sstevel@tonic-gate 449b0fc0e77Sgovinda msiq_p->msiq_curr_head_index = msiq_p->msiq_new_head_index; 450b0fc0e77Sgovinda px_lib_msiq_sethead(dip, msiq_p->msiq_id, msiq_p->msiq_new_head_index); 451b0fc0e77Sgovinda 452b0fc0e77Sgovinda msiq_p->msiq_new_head_index = 0; 453b0fc0e77Sgovinda msiq_p->msiq_recs2process = 0; 454b0fc0e77Sgovinda ino_p->ino_claimed = 0; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* Clear the pending state */ 4577c478bd9Sstevel@tonic-gate if (px_lib_intr_setstate(dip, ino_p->ino_sysino, 4587c478bd9Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 4597c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate dev_info_t * 4657c478bd9Sstevel@tonic-gate px_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 4667c478bd9Sstevel@tonic-gate { 4677c478bd9Sstevel@tonic-gate dev_info_t *cdip = rdip; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 4707c478bd9Sstevel@tonic-gate ; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate return (cdip); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4767c478bd9Sstevel@tonic-gate int 4777c478bd9Sstevel@tonic-gate px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 4787c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 4797c478bd9Sstevel@tonic-gate { 4807c478bd9Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 4817c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: dip=%x rdip=%x intr_op=%x " 4847c478bd9Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate switch (intr_op) { 4877c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 4887c478bd9Sstevel@tonic-gate ret = pci_intx_get_cap(rdip, (int *)result); 4897c478bd9Sstevel@tonic-gate break; 4907c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 4917c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_intx_ops: SetCap is not supported\n"); 4927c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 4937c478bd9Sstevel@tonic-gate break; 4947c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 4957c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 4967c478bd9Sstevel@tonic-gate break; 4977c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 4987c478bd9Sstevel@tonic-gate break; 4997c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 500a195726fSgovinda *(int *)result = hdlp->ih_pri ? 501614edcaeSEvan Yan hdlp->ih_pri : pci_class_to_pil(rdip); 5027c478bd9Sstevel@tonic-gate break; 5037c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 5047c478bd9Sstevel@tonic-gate break; 5057c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 5067c478bd9Sstevel@tonic-gate ret = px_add_intx_intr(dip, rdip, hdlp); 5077c478bd9Sstevel@tonic-gate break; 5087c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 5097c478bd9Sstevel@tonic-gate ret = px_rem_intx_intr(dip, rdip, hdlp); 5107c478bd9Sstevel@tonic-gate break; 51109b1eac2SEvan Yan case DDI_INTROP_GETTARGET: 51209b1eac2SEvan Yan ret = px_ib_get_intr_target(px_p, hdlp->ih_vector, 51309b1eac2SEvan Yan (cpuid_t *)result); 51409b1eac2SEvan Yan break; 51509b1eac2SEvan Yan case DDI_INTROP_SETTARGET: 51609b1eac2SEvan Yan ret = DDI_ENOTSUP; 51709b1eac2SEvan Yan break; 5187c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 5197c478bd9Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 520b0fc0e77Sgovinda hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_ENABLE, 0, 0); 5217c478bd9Sstevel@tonic-gate break; 5227c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 5237c478bd9Sstevel@tonic-gate ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 524b0fc0e77Sgovinda hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_DISABLE, 0, 0); 5257c478bd9Sstevel@tonic-gate break; 5267c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 5277c478bd9Sstevel@tonic-gate ret = pci_intx_set_mask(rdip); 5287c478bd9Sstevel@tonic-gate break; 5297c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 5307c478bd9Sstevel@tonic-gate ret = pci_intx_clr_mask(rdip); 5317c478bd9Sstevel@tonic-gate break; 5327c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 5337c478bd9Sstevel@tonic-gate ret = pci_intx_get_pending(rdip, (int *)result); 5347c478bd9Sstevel@tonic-gate break; 5357c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 5367c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 537a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 5387c478bd9Sstevel@tonic-gate break; 5397c478bd9Sstevel@tonic-gate default: 5407c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 5417c478bd9Sstevel@tonic-gate break; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate return (ret); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5487c478bd9Sstevel@tonic-gate int 5497c478bd9Sstevel@tonic-gate px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 5507c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 5517c478bd9Sstevel@tonic-gate { 5527c478bd9Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5537c478bd9Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 5549c75c6bfSgovinda msiq_rec_type_t msiq_rec_type; 5559c75c6bfSgovinda msi_type_t msi_type; 5569c75c6bfSgovinda uint64_t msi_addr; 5577c478bd9Sstevel@tonic-gate msinum_t msi_num; 5587c478bd9Sstevel@tonic-gate msiqid_t msiq_id; 5597c478bd9Sstevel@tonic-gate uint_t nintrs; 56009b1eac2SEvan Yan int ret = DDI_SUCCESS; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x " 5637c478bd9Sstevel@tonic-gate "handle=%p\n", dip, rdip, intr_op, hdlp); 5647c478bd9Sstevel@tonic-gate 5659c75c6bfSgovinda /* Check for MSI64 support */ 56607f14c08Sgovinda if ((hdlp->ih_cap & DDI_INTR_FLAG_MSI64) && msi_state_p->msi_addr64) { 5679c75c6bfSgovinda msiq_rec_type = MSI64_REC; 5689c75c6bfSgovinda msi_type = MSI64_TYPE; 56907f14c08Sgovinda msi_addr = msi_state_p->msi_addr64; 5709c75c6bfSgovinda } else { 5719c75c6bfSgovinda msiq_rec_type = MSI32_REC; 5729c75c6bfSgovinda msi_type = MSI32_TYPE; 5739c75c6bfSgovinda msi_addr = msi_state_p->msi_addr32; 5749c75c6bfSgovinda } 5759c75c6bfSgovinda 57609b1eac2SEvan Yan (void) px_msi_get_msinum(px_p, hdlp->ih_dip, 57709b1eac2SEvan Yan (hdlp->ih_flags & DDI_INTR_MSIX_DUP) ? hdlp->ih_main->ih_inum : 57809b1eac2SEvan Yan hdlp->ih_inum, &msi_num); 57909b1eac2SEvan Yan 5807c478bd9Sstevel@tonic-gate switch (intr_op) { 5817c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5827c478bd9Sstevel@tonic-gate ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result); 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 5857c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: SetCap is not supported\n"); 5867c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * We need to restrict this allocation in future 5917c478bd9Sstevel@tonic-gate * based on Resource Management policies. 5927c478bd9Sstevel@tonic-gate */ 5935febcb4aSScott Carter, SD IOSW if ((ret = px_msi_alloc(px_p, rdip, hdlp->ih_type, 5945febcb4aSScott Carter, SD IOSW hdlp->ih_inum, hdlp->ih_scratch1, 5955febcb4aSScott Carter, SD IOSW (uintptr_t)hdlp->ih_scratch2, 59620036fe5Segillett (int *)result)) != DDI_SUCCESS) { 59720036fe5Segillett DBG(DBG_INTROPS, dip, "px_msix_ops: allocation " 59820036fe5Segillett "failed, rdip 0x%p type 0x%d inum 0x%x " 59920036fe5Segillett "count 0x%x\n", rdip, hdlp->ih_type, hdlp->ih_inum, 60020036fe5Segillett hdlp->ih_scratch1); 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate return (ret); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 60520036fe5Segillett if ((hdlp->ih_type == DDI_INTR_TYPE_MSIX) && 60620036fe5Segillett (i_ddi_get_msix(rdip) == NULL)) { 60720036fe5Segillett ddi_intr_msix_t *msix_p; 60820036fe5Segillett 60920036fe5Segillett if (msix_p = pci_msix_init(rdip)) { 61020036fe5Segillett i_ddi_set_msix(rdip, msix_p); 61120036fe5Segillett break; 61220036fe5Segillett } 61320036fe5Segillett 61420036fe5Segillett DBG(DBG_INTROPS, dip, "px_msix_ops: MSI-X allocation " 61520036fe5Segillett "failed, rdip 0x%p inum 0x%x\n", rdip, 61620036fe5Segillett hdlp->ih_inum); 61720036fe5Segillett 61820036fe5Segillett (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 61920036fe5Segillett hdlp->ih_scratch1); 62020036fe5Segillett 62120036fe5Segillett return (DDI_FAILURE); 62220036fe5Segillett } 62320036fe5Segillett 6247c478bd9Sstevel@tonic-gate break; 6257c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 6267c478bd9Sstevel@tonic-gate (void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum); 62720036fe5Segillett 62820036fe5Segillett if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 62920036fe5Segillett goto msi_free; 63020036fe5Segillett 63120036fe5Segillett if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 63220036fe5Segillett break; 63320036fe5Segillett 63420036fe5Segillett if (((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0) && 63520036fe5Segillett (i_ddi_get_msix(rdip))) { 63620036fe5Segillett pci_msix_fini(i_ddi_get_msix(rdip)); 63720036fe5Segillett i_ddi_set_msix(rdip, NULL); 63820036fe5Segillett } 63920036fe5Segillett msi_free: 6407c478bd9Sstevel@tonic-gate (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 6417c478bd9Sstevel@tonic-gate hdlp->ih_scratch1); 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 6447c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_pri ? 645614edcaeSEvan Yan hdlp->ih_pri : pci_class_to_pil(rdip); 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 6487c478bd9Sstevel@tonic-gate break; 6497c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 6507c478bd9Sstevel@tonic-gate if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 65109b1eac2SEvan Yan msiq_rec_type, msi_num, -1, &msiq_id)) != DDI_SUCCESS) { 6527c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler " 6537c478bd9Sstevel@tonic-gate "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 6547c478bd9Sstevel@tonic-gate return (ret); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setmsiq(dip, msi_num, 6609c75c6bfSgovinda msiq_id, msi_type)) != DDI_SUCCESS) { 6617c478bd9Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 6629c75c6bfSgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 6637c478bd9Sstevel@tonic-gate return (ret); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 6677c478bd9Sstevel@tonic-gate PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) { 6687c478bd9Sstevel@tonic-gate (void) px_rem_msiq_intr(dip, rdip, 6699c75c6bfSgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 6707c478bd9Sstevel@tonic-gate return (ret); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 67309b1eac2SEvan Yan if ((ret = px_lib_msi_setvalid(dip, msi_num, 67409b1eac2SEvan Yan PCI_MSI_VALID)) != DDI_SUCCESS) 67509b1eac2SEvan Yan return (ret); 67609b1eac2SEvan Yan 67709b1eac2SEvan Yan ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 67809b1eac2SEvan Yan px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri, 67909b1eac2SEvan Yan PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num); 68009b1eac2SEvan Yan 6817c478bd9Sstevel@tonic-gate break; 6827c478bd9Sstevel@tonic-gate case DDI_INTROP_DUPVEC: 68320036fe5Segillett DBG(DBG_INTROPS, dip, "px_msix_ops: dupisr - inum: %x, " 68420036fe5Segillett "new_vector: %x\n", hdlp->ih_inum, hdlp->ih_scratch1); 68520036fe5Segillett 68620036fe5Segillett ret = pci_msix_dup(hdlp->ih_dip, hdlp->ih_inum, 68720036fe5Segillett hdlp->ih_scratch1); 6887c478bd9Sstevel@tonic-gate break; 6897c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 6907c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_getmsiq(dip, msi_num, 6917c478bd9Sstevel@tonic-gate &msiq_id)) != DDI_SUCCESS) 6927c478bd9Sstevel@tonic-gate return (ret); 6937c478bd9Sstevel@tonic-gate 69409b1eac2SEvan Yan if ((ret = px_ib_update_intr_state(px_p, rdip, 69509b1eac2SEvan Yan hdlp->ih_inum, px_msiqid_to_devino(px_p, msiq_id), 69609b1eac2SEvan Yan hdlp->ih_pri, PX_INTR_STATE_DISABLE, msiq_rec_type, 69709b1eac2SEvan Yan msi_num)) != DDI_SUCCESS) 69809b1eac2SEvan Yan return (ret); 69909b1eac2SEvan Yan 70009b1eac2SEvan Yan if ((ret = px_lib_msi_setvalid(dip, msi_num, 70109b1eac2SEvan Yan PCI_MSI_INVALID)) != DDI_SUCCESS) 70209b1eac2SEvan Yan return (ret); 70309b1eac2SEvan Yan 7047c478bd9Sstevel@tonic-gate if ((ret = px_lib_msi_setstate(dip, msi_num, 7059c75c6bfSgovinda PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) 7067c478bd9Sstevel@tonic-gate return (ret); 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate ret = px_rem_msiq_intr(dip, rdip, 7099c75c6bfSgovinda hdlp, msiq_rec_type, msi_num, msiq_id); 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate break; 71209b1eac2SEvan Yan case DDI_INTROP_GETTARGET: 71309b1eac2SEvan Yan if ((ret = px_lib_msi_getmsiq(dip, msi_num, 71409b1eac2SEvan Yan &msiq_id)) != DDI_SUCCESS) 7157c478bd9Sstevel@tonic-gate return (ret); 7167c478bd9Sstevel@tonic-gate 71709b1eac2SEvan Yan ret = px_ib_get_intr_target(px_p, 71809b1eac2SEvan Yan px_msiqid_to_devino(px_p, msiq_id), (cpuid_t *)result); 71909b1eac2SEvan Yan break; 72009b1eac2SEvan Yan case DDI_INTROP_SETTARGET: 72109b1eac2SEvan Yan ret = px_ib_set_msix_target(px_p, hdlp, msi_num, 72209b1eac2SEvan Yan *(cpuid_t *)result); 72309b1eac2SEvan Yan break; 72409b1eac2SEvan Yan case DDI_INTROP_ENABLE: 72509b1eac2SEvan Yan /* 7263784a72bSGovinda Tatti * For MSI, just clear the mask bit and return if curr_nenables 7273784a72bSGovinda Tatti * is > 1. For MSI-X, program MSI address and data for every 7283784a72bSGovinda Tatti * MSI-X vector including dup vectors irrespective of current 7293784a72bSGovinda Tatti * curr_nenables value. 73009b1eac2SEvan Yan */ 7313784a72bSGovinda Tatti if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) || 7323784a72bSGovinda Tatti (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) { 7337c478bd9Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 7369c75c6bfSgovinda nintrs, hdlp->ih_inum, msi_addr, 7373784a72bSGovinda Tatti hdlp->ih_type == DDI_INTR_TYPE_MSIX ? 7383784a72bSGovinda Tatti msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7397c478bd9Sstevel@tonic-gate return (ret); 7407c478bd9Sstevel@tonic-gate 7413784a72bSGovinda Tatti if (i_ddi_intr_get_current_nenables(rdip) < 1) { 74209b1eac2SEvan Yan if ((ret = pci_msi_enable_mode(rdip, 74309b1eac2SEvan Yan hdlp->ih_type)) != DDI_SUCCESS) 7447c478bd9Sstevel@tonic-gate return (ret); 7453784a72bSGovinda Tatti } 7463784a72bSGovinda Tatti } 7477c478bd9Sstevel@tonic-gate 74836fe4a92Segillett if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type, 74936fe4a92Segillett hdlp->ih_inum)) != DDI_SUCCESS) 75036fe4a92Segillett return (ret); 75136fe4a92Segillett 7527c478bd9Sstevel@tonic-gate break; 7537c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 7547c478bd9Sstevel@tonic-gate if ((ret = pci_msi_set_mask(rdip, hdlp->ih_type, 7557c478bd9Sstevel@tonic-gate hdlp->ih_inum)) != DDI_SUCCESS) 7567c478bd9Sstevel@tonic-gate return (ret); 7577c478bd9Sstevel@tonic-gate 75809b1eac2SEvan Yan /* 75909b1eac2SEvan Yan * curr_nenables will be greater than 1 if rdip is using 76009b1eac2SEvan Yan * MSI-X and also, if it is using DUP interface. If this 76109b1eac2SEvan Yan * curr_enables is > 1, return after setting the mask bit. 76209b1eac2SEvan Yan */ 76309b1eac2SEvan Yan if (i_ddi_intr_get_current_nenables(rdip) > 1) 76409b1eac2SEvan Yan return (DDI_SUCCESS); 76509b1eac2SEvan Yan 76609b1eac2SEvan Yan if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type)) 76709b1eac2SEvan Yan != DDI_SUCCESS) 76836fe4a92Segillett return (ret); 76936fe4a92Segillett 7707c478bd9Sstevel@tonic-gate break; 7717c478bd9Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 7727c478bd9Sstevel@tonic-gate nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 7759c75c6bfSgovinda nintrs, hdlp->ih_inum, msi_addr, 7767c478bd9Sstevel@tonic-gate msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 7777c478bd9Sstevel@tonic-gate return (ret); 7787c478bd9Sstevel@tonic-gate 77995003185Segillett ret = pci_msi_enable_mode(rdip, hdlp->ih_type); 7807c478bd9Sstevel@tonic-gate break; 7817c478bd9Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 78209b1eac2SEvan Yan ret = pci_msi_disable_mode(rdip, hdlp->ih_type); 7837c478bd9Sstevel@tonic-gate break; 7847c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 7857c478bd9Sstevel@tonic-gate ret = pci_msi_set_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7867c478bd9Sstevel@tonic-gate break; 7877c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 7887c478bd9Sstevel@tonic-gate ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 7897c478bd9Sstevel@tonic-gate break; 7907c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 7917c478bd9Sstevel@tonic-gate ret = pci_msi_get_pending(rdip, hdlp->ih_type, 7927c478bd9Sstevel@tonic-gate hdlp->ih_inum, (int *)result); 7937c478bd9Sstevel@tonic-gate break; 7947c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 7957c478bd9Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 7967c478bd9Sstevel@tonic-gate break; 7977c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 7987c478bd9Sstevel@tonic-gate /* XXX - a new interface may be needed */ 7997c478bd9Sstevel@tonic-gate ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 8007c478bd9Sstevel@tonic-gate break; 8015febcb4aSScott Carter, SD IOSW case DDI_INTROP_GETPOOL: 8025febcb4aSScott Carter, SD IOSW if (msi_state_p->msi_pool_p == NULL) { 8035febcb4aSScott Carter, SD IOSW *(ddi_irm_pool_t **)result = NULL; 8045febcb4aSScott Carter, SD IOSW return (DDI_ENOTSUP); 8055febcb4aSScott Carter, SD IOSW } 8065febcb4aSScott Carter, SD IOSW *(ddi_irm_pool_t **)result = msi_state_p->msi_pool_p; 8075febcb4aSScott Carter, SD IOSW ret = DDI_SUCCESS; 8085febcb4aSScott Carter, SD IOSW break; 8097c478bd9Sstevel@tonic-gate default: 8107c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 8117c478bd9Sstevel@tonic-gate break; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate return (ret); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8176d44af1bSesolom static struct { 8186d44af1bSesolom kstat_named_t pxintr_ks_name; 8196d44af1bSesolom kstat_named_t pxintr_ks_type; 8206d44af1bSesolom kstat_named_t pxintr_ks_cpu; 8216d44af1bSesolom kstat_named_t pxintr_ks_pil; 8226d44af1bSesolom kstat_named_t pxintr_ks_time; 8236d44af1bSesolom kstat_named_t pxintr_ks_ino; 8246d44af1bSesolom kstat_named_t pxintr_ks_cookie; 8256d44af1bSesolom kstat_named_t pxintr_ks_devpath; 8266d44af1bSesolom kstat_named_t pxintr_ks_buspath; 8276d44af1bSesolom } pxintr_ks_template = { 8286d44af1bSesolom { "name", KSTAT_DATA_CHAR }, 8296d44af1bSesolom { "type", KSTAT_DATA_CHAR }, 8306d44af1bSesolom { "cpu", KSTAT_DATA_UINT64 }, 8316d44af1bSesolom { "pil", KSTAT_DATA_UINT64 }, 8326d44af1bSesolom { "time", KSTAT_DATA_UINT64 }, 8336d44af1bSesolom { "ino", KSTAT_DATA_UINT64 }, 8346d44af1bSesolom { "cookie", KSTAT_DATA_UINT64 }, 8356d44af1bSesolom { "devpath", KSTAT_DATA_STRING }, 8366d44af1bSesolom { "buspath", KSTAT_DATA_STRING }, 8376d44af1bSesolom }; 8386d44af1bSesolom 8396d44af1bSesolom static uint32_t pxintr_ks_instance; 840d48713b8Sesolom static char ih_devpath[MAXPATHLEN]; 841d48713b8Sesolom static char ih_buspath[MAXPATHLEN]; 8426d44af1bSesolom kmutex_t pxintr_ks_template_lock; 8436d44af1bSesolom 8446d44af1bSesolom int 8456d44af1bSesolom px_ks_update(kstat_t *ksp, int rw) 8466d44af1bSesolom { 8476d44af1bSesolom px_ih_t *ih_p = ksp->ks_private; 8486d44af1bSesolom int maxlen = sizeof (pxintr_ks_template.pxintr_ks_name.value.c); 849b0fc0e77Sgovinda px_ino_pil_t *ipil_p = ih_p->ih_ipil_p; 850b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 851b0fc0e77Sgovinda px_t *px_p = ino_p->ino_ib_p->ib_px_p; 8526d44af1bSesolom devino_t ino; 8536d44af1bSesolom sysino_t sysino; 8546d44af1bSesolom 855b0fc0e77Sgovinda ino = ino_p->ino_ino; 856d8d130aeSanbui if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino) != 857d8d130aeSanbui DDI_SUCCESS) { 858d8d130aeSanbui cmn_err(CE_WARN, "px_ks_update: px_lib_intr_devino_to_sysino " 859d8d130aeSanbui "failed"); 860d8d130aeSanbui } 8616d44af1bSesolom 8626d44af1bSesolom (void) snprintf(pxintr_ks_template.pxintr_ks_name.value.c, maxlen, 8636d44af1bSesolom "%s%d", ddi_driver_name(ih_p->ih_dip), 8646d44af1bSesolom ddi_get_instance(ih_p->ih_dip)); 8656d44af1bSesolom 8666d44af1bSesolom (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 8676d44af1bSesolom (void) ddi_pathname(px_p->px_dip, ih_buspath); 8686d44af1bSesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_devpath, ih_devpath); 8696d44af1bSesolom kstat_named_setstr(&pxintr_ks_template.pxintr_ks_buspath, ih_buspath); 8706d44af1bSesolom 871e1d9f4e6Sschwartz if (ih_p->ih_intr_state == PX_INTR_STATE_ENABLE) { 872e1d9f4e6Sschwartz 8732917a9c9Sschwartz switch (i_ddi_intr_get_current_type(ih_p->ih_dip)) { 8742917a9c9Sschwartz case DDI_INTR_TYPE_MSI: 875e1d9f4e6Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8762917a9c9Sschwartz "msi"); 8772917a9c9Sschwartz break; 8782917a9c9Sschwartz case DDI_INTR_TYPE_MSIX: 8792917a9c9Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8802917a9c9Sschwartz "msix"); 8812917a9c9Sschwartz break; 8822917a9c9Sschwartz default: 8832917a9c9Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 8842917a9c9Sschwartz "fixed"); 8852917a9c9Sschwartz break; 8862917a9c9Sschwartz } 8872917a9c9Sschwartz 888b0fc0e77Sgovinda pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ino_p->ino_cpuid; 889b0fc0e77Sgovinda pxintr_ks_template.pxintr_ks_pil.value.ui64 = ipil_p->ipil_pil; 890e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_time.value.ui64 = ih_p->ih_nsec + 891e1d9f4e6Sschwartz (uint64_t)tick2ns((hrtime_t)ih_p->ih_ticks, 892b0fc0e77Sgovinda ino_p->ino_cpuid); 893e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_ino.value.ui64 = ino; 894e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_cookie.value.ui64 = sysino; 895e1d9f4e6Sschwartz } else { 896e1d9f4e6Sschwartz (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 897e1d9f4e6Sschwartz "disabled"); 898e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_cpu.value.ui64 = 0; 899e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_pil.value.ui64 = 0; 900e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_time.value.ui64 = 0; 901e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_ino.value.ui64 = 0; 902e1d9f4e6Sschwartz pxintr_ks_template.pxintr_ks_cookie.value.ui64 = 0; 903e1d9f4e6Sschwartz } 9046d44af1bSesolom return (0); 9056d44af1bSesolom } 9066d44af1bSesolom 9076d44af1bSesolom void 9086d44af1bSesolom px_create_intr_kstats(px_ih_t *ih_p) 9096d44af1bSesolom { 9106d44af1bSesolom msiq_rec_type_t rec_type = ih_p->ih_rec_type; 9116d44af1bSesolom 9126d44af1bSesolom ASSERT(ih_p->ih_ksp == NULL); 9136d44af1bSesolom 9146d44af1bSesolom /* 9156d44af1bSesolom * Create pci_intrs::: kstats for all ih types except messages, 9166d44af1bSesolom * which represent unusual conditions and don't need to be tracked. 9176d44af1bSesolom */ 9186d44af1bSesolom if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 9196d44af1bSesolom ih_p->ih_ksp = kstat_create("pci_intrs", 9206d44af1bSesolom atomic_inc_32_nv(&pxintr_ks_instance), "config", 9216d44af1bSesolom "interrupts", KSTAT_TYPE_NAMED, 9226d44af1bSesolom sizeof (pxintr_ks_template) / sizeof (kstat_named_t), 9236d44af1bSesolom KSTAT_FLAG_VIRTUAL); 9246d44af1bSesolom } 9256d44af1bSesolom if (ih_p->ih_ksp != NULL) { 9266d44af1bSesolom ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 9276d44af1bSesolom ih_p->ih_ksp->ks_lock = &pxintr_ks_template_lock; 9286d44af1bSesolom ih_p->ih_ksp->ks_data = &pxintr_ks_template; 9296d44af1bSesolom ih_p->ih_ksp->ks_private = ih_p; 9306d44af1bSesolom ih_p->ih_ksp->ks_update = px_ks_update; 9316d44af1bSesolom } 9326d44af1bSesolom } 9336d44af1bSesolom 934a195726fSgovinda /* 935a195726fSgovinda * px_add_intx_intr: 936a195726fSgovinda * 937a195726fSgovinda * This function is called to register INTx and legacy hardware 938a195726fSgovinda * interrupt pins interrupts. 939a195726fSgovinda */ 9407c478bd9Sstevel@tonic-gate int 9417c478bd9Sstevel@tonic-gate px_add_intx_intr(dev_info_t *dip, dev_info_t *rdip, 9427c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 9437c478bd9Sstevel@tonic-gate { 9447c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 9457c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 9467c478bd9Sstevel@tonic-gate devino_t ino; 9477c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 948b0fc0e77Sgovinda px_ino_t *ino_p; 949b0fc0e77Sgovinda px_ino_pil_t *ipil_p, *ipil_list; 9507c478bd9Sstevel@tonic-gate int32_t weight; 9517c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 9521a92841dSDaniel Ice cpuid_t curr_cpu; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate ino = hdlp->ih_vector; 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: rdip=%s%d ino=%x " 9577c478bd9Sstevel@tonic-gate "handler=%x arg1=%x arg2=%x\n", ddi_driver_name(rdip), 9587c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), ino, hdlp->ih_cb_func, 9597c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, 9627c478bd9Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, 0, 0); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 9657c478bd9Sstevel@tonic-gate 966b0fc0e77Sgovinda ino_p = px_ib_locate_ino(ib_p, ino); 967b0fc0e77Sgovinda ipil_list = ino_p ? ino_p->ino_ipil_p : NULL; 968b0fc0e77Sgovinda 969*34a68653SDavid Major if (hdlp->ih_pri == 0) 970*34a68653SDavid Major hdlp->ih_pri = pci_class_to_pil(rdip); 971*34a68653SDavid Major 9721a92841dSDaniel Ice /* Sharing the INO using a PIL that already exists */ 973b0fc0e77Sgovinda if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 974b0fc0e77Sgovinda if (px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0)) { 9757c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: " 976b0fc0e77Sgovinda "dup intr #%d\n", hdlp->ih_inum); 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 9797c478bd9Sstevel@tonic-gate goto fail1; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* Save mondo value in hdlp */ 9837c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 9847c478bd9Sstevel@tonic-gate 985b0fc0e77Sgovinda if ((ret = px_ib_ino_add_intr(px_p, ipil_p, 986b0fc0e77Sgovinda ih_p)) != DDI_SUCCESS) 9877c478bd9Sstevel@tonic-gate goto fail1; 988b0fc0e77Sgovinda 989b0fc0e77Sgovinda goto ino_done; 990b0fc0e77Sgovinda } 9917c478bd9Sstevel@tonic-gate 9921a92841dSDaniel Ice /* Sharing the INO using a new PIL */ 9931a92841dSDaniel Ice if (ipil_list != NULL) { 9941a92841dSDaniel Ice /* 9951a92841dSDaniel Ice * disable INO to avoid lopil race condition with 9961a92841dSDaniel Ice * px_intx_intr 9971a92841dSDaniel Ice */ 9981a92841dSDaniel Ice 9991a92841dSDaniel Ice if ((ret = px_lib_intr_gettarget(dip, ino_p->ino_sysino, 10001a92841dSDaniel Ice &curr_cpu)) != DDI_SUCCESS) { 10011a92841dSDaniel Ice DBG(DBG_IB, dip, 10021a92841dSDaniel Ice "px_add_intx_intr px_intr_gettarget() failed\n"); 10031a92841dSDaniel Ice 10041a92841dSDaniel Ice goto fail1; 10051a92841dSDaniel Ice } 10061a92841dSDaniel Ice 1007c17ca212SDavid Major /* Wait on pending interrupt */ 1008c17ca212SDavid Major if ((ret = px_ib_intr_pend(dip, ino_p->ino_sysino)) != 1009c17ca212SDavid Major DDI_SUCCESS) { 10101a92841dSDaniel Ice cmn_err(CE_WARN, "%s%d: px_add_intx_intr: " 10111a92841dSDaniel Ice "pending sysino 0x%lx(ino 0x%x) timeout", 10121a92841dSDaniel Ice ddi_driver_name(dip), ddi_get_instance(dip), 10131a92841dSDaniel Ice ino_p->ino_sysino, ino_p->ino_ino); 10141a92841dSDaniel Ice goto fail1; 10151a92841dSDaniel Ice } 10161a92841dSDaniel Ice } 10171a92841dSDaniel Ice 1018b0fc0e77Sgovinda ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 1019b0fc0e77Sgovinda ino_p = ipil_p->ipil_ino_p; 1020b0fc0e77Sgovinda 10217c478bd9Sstevel@tonic-gate /* Save mondo value in hdlp */ 10227c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: pil=0x%x mondo=0x%x\n", 10257c478bd9Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 1028b0fc0e77Sgovinda (ddi_intr_handler_t *)px_intx_intr, (caddr_t)ipil_p, NULL); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * Restore original interrupt handler 10347c478bd9Sstevel@tonic-gate * and arguments in interrupt handle. 10357c478bd9Sstevel@tonic-gate */ 10367c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 10377c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 10407c478bd9Sstevel@tonic-gate goto fail2; 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* Save the pil for this ino */ 1043b0fc0e77Sgovinda ipil_p->ipil_pil = hdlp->ih_pri; 10447c478bd9Sstevel@tonic-gate 1045b0fc0e77Sgovinda /* Select cpu, saving it for sharing and removal */ 1046b0fc0e77Sgovinda if (ipil_list == NULL) { 104709b1eac2SEvan Yan if (ino_p->ino_cpuid == -1) 10487c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* Enable interrupt */ 10517c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 10521a92841dSDaniel Ice } else { 10531a92841dSDaniel Ice /* Re-enable interrupt */ 10541a92841dSDaniel Ice PX_INTR_ENABLE(dip, ino_p->ino_sysino, curr_cpu); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 1057b0fc0e77Sgovinda ino_done: 105809b1eac2SEvan Yan hdlp->ih_target = ino_p->ino_cpuid; 105909b1eac2SEvan Yan 1060b0fc0e77Sgovinda /* Add weight to the cpu that we are already targeting */ 1061614edcaeSEvan Yan weight = pci_class_to_intr_weight(rdip); 10627c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 10637c478bd9Sstevel@tonic-gate 1064b0fc0e77Sgovinda ih_p->ih_ipil_p = ipil_p; 10656d44af1bSesolom px_create_intr_kstats(ih_p); 10667c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp) 10677c478bd9Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 10687c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: done! Interrupt 0x%x pil=%x\n", 10717c478bd9Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate return (ret); 10747c478bd9Sstevel@tonic-gate fail2: 1075b0fc0e77Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 10767c478bd9Sstevel@tonic-gate fail1: 10777c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 10787c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 10817c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate DBG(DBG_A_INTX, dip, "px_add_intx_intr: Failed! Interrupt 0x%x " 10847c478bd9Sstevel@tonic-gate "pil=%x\n", ino_p->ino_sysino, hdlp->ih_pri); 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate return (ret); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 1089a195726fSgovinda /* 1090a195726fSgovinda * px_rem_intx_intr: 1091a195726fSgovinda * 1092a195726fSgovinda * This function is called to unregister INTx and legacy hardware 1093a195726fSgovinda * interrupt pins interrupts. 1094a195726fSgovinda */ 10957c478bd9Sstevel@tonic-gate int 10967c478bd9Sstevel@tonic-gate px_rem_intx_intr(dev_info_t *dip, dev_info_t *rdip, 10977c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 10987c478bd9Sstevel@tonic-gate { 10997c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 11007c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 11017c478bd9Sstevel@tonic-gate devino_t ino; 11027c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 1103b0fc0e77Sgovinda px_ino_t *ino_p; 1104b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 11057c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 11067c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate ino = hdlp->ih_vector; 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, dip, "px_rem_intx_intr: rdip=%s%d ino=%x\n", 11117c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 1116b0fc0e77Sgovinda ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 1117b0fc0e77Sgovinda ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0); 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* Get the current cpu */ 11207c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 11217c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 11227c478bd9Sstevel@tonic-gate goto fail; 11237c478bd9Sstevel@tonic-gate 1124b0fc0e77Sgovinda if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS) 11257c478bd9Sstevel@tonic-gate goto fail; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 11287c478bd9Sstevel@tonic-gate 1129b0fc0e77Sgovinda if (ipil_p->ipil_ih_size == 0) { 11307c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 11317c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 11327c478bd9Sstevel@tonic-gate 1133b0fc0e77Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 1134b0fc0e77Sgovinda } 1135b0fc0e77Sgovinda 1136b0fc0e77Sgovinda if (ino_p->ino_ipil_size == 0) { 1137b0fc0e77Sgovinda kmem_free(ino_p, sizeof (px_ino_t)); 11387c478bd9Sstevel@tonic-gate } else { 11390d2a6fcfSegillett /* Re-enable interrupt only if mapping register still shared */ 11400d2a6fcfSegillett PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate fail: 11447c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 11457c478bd9Sstevel@tonic-gate return (ret); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate 1148a195726fSgovinda /* 1149a195726fSgovinda * px_add_msiq_intr: 1150a195726fSgovinda * 1151a195726fSgovinda * This function is called to register MSI/Xs and PCIe message interrupts. 1152a195726fSgovinda */ 11537c478bd9Sstevel@tonic-gate int 11547c478bd9Sstevel@tonic-gate px_add_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 11557c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 115609b1eac2SEvan Yan msgcode_t msg_code, cpuid_t cpu_id, msiqid_t *msiq_id_p) 11577c478bd9Sstevel@tonic-gate { 11587c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 11597c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 11607c478bd9Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 11617c478bd9Sstevel@tonic-gate devino_t ino; 11627c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 1163b0fc0e77Sgovinda px_ino_t *ino_p; 1164b0fc0e77Sgovinda px_ino_pil_t *ipil_p, *ipil_list; 11657c478bd9Sstevel@tonic-gate int32_t weight; 11667c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 11677c478bd9Sstevel@tonic-gate 116809b1eac2SEvan Yan DBG(DBG_MSIQ, dip, "px_add_msiq_intr: rdip=%s%d handler=0x%x " 116909b1eac2SEvan Yan "arg1=0x%x arg2=0x%x cpu=0x%x\n", ddi_driver_name(rdip), 117009b1eac2SEvan Yan ddi_get_instance(rdip), hdlp->ih_cb_func, hdlp->ih_cb_arg1, 117109b1eac2SEvan Yan hdlp->ih_cb_arg2, cpu_id); 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, hdlp->ih_cb_func, 11747c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rec_type, msg_code); 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 11777c478bd9Sstevel@tonic-gate 117818191143SAlan Adamson, SD OSSD ret = (cpu_id == -1) ? px_msiq_alloc(px_p, rec_type, msg_code, 117918191143SAlan Adamson, SD OSSD msiq_id_p) : px_msiq_alloc_based_on_cpuid(px_p, rec_type, 118018191143SAlan Adamson, SD OSSD cpu_id, msiq_id_p); 118109b1eac2SEvan Yan 118209b1eac2SEvan Yan if (ret != DDI_SUCCESS) { 118309b1eac2SEvan Yan DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 118409b1eac2SEvan Yan "msiq allocation failed\n"); 118509b1eac2SEvan Yan goto fail; 118609b1eac2SEvan Yan } 118709b1eac2SEvan Yan 118809b1eac2SEvan Yan ino = px_msiqid_to_devino(px_p, *msiq_id_p); 118909b1eac2SEvan Yan 1190b0fc0e77Sgovinda ino_p = px_ib_locate_ino(ib_p, ino); 1191b0fc0e77Sgovinda ipil_list = ino_p ? ino_p->ino_ipil_p : NULL; 1192b0fc0e77Sgovinda 1193*34a68653SDavid Major if (hdlp->ih_pri == 0) 1194*34a68653SDavid Major hdlp->ih_pri = pci_class_to_pil(rdip); 1195*34a68653SDavid Major 1196b0fc0e77Sgovinda /* Sharing ino */ 1197b0fc0e77Sgovinda if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 1198b0fc0e77Sgovinda if (px_ib_intr_locate_ih(ipil_p, rdip, 1199b0fc0e77Sgovinda hdlp->ih_inum, rec_type, msg_code)) { 12007c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 1201b0fc0e77Sgovinda "dup intr #%d\n", hdlp->ih_inum); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 12047c478bd9Sstevel@tonic-gate goto fail1; 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 1207b0fc0e77Sgovinda /* Save mondo value in hdlp */ 1208b0fc0e77Sgovinda hdlp->ih_vector = ino_p->ino_sysino; 12097c478bd9Sstevel@tonic-gate 1210b0fc0e77Sgovinda if ((ret = px_ib_ino_add_intr(px_p, ipil_p, 1211b0fc0e77Sgovinda ih_p)) != DDI_SUCCESS) 1212b0fc0e77Sgovinda goto fail1; 1213b0fc0e77Sgovinda 1214b0fc0e77Sgovinda goto ino_done; 1215b0fc0e77Sgovinda } 12167c478bd9Sstevel@tonic-gate 1217b0fc0e77Sgovinda ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 1218b0fc0e77Sgovinda ino_p = ipil_p->ipil_ino_p; 1219b0fc0e77Sgovinda 1220b0fc0e77Sgovinda ino_p->ino_msiq_p = msiq_state_p->msiq_p + 1221b0fc0e77Sgovinda (*msiq_id_p - msiq_state_p->msiq_1st_msiq_id); 1222b0fc0e77Sgovinda 12237c478bd9Sstevel@tonic-gate /* Save mondo value in hdlp */ 12247c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: pil=0x%x mondo=0x%x\n", 12277c478bd9Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector); 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 1230b0fc0e77Sgovinda (ddi_intr_handler_t *)px_msiq_intr, (caddr_t)ipil_p, NULL); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate /* 12357c478bd9Sstevel@tonic-gate * Restore original interrupt handler 12367c478bd9Sstevel@tonic-gate * and arguments in interrupt handle. 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 12397c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 12427c478bd9Sstevel@tonic-gate goto fail2; 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate /* Save the pil for this ino */ 1245b0fc0e77Sgovinda ipil_p->ipil_pil = hdlp->ih_pri; 1246b0fc0e77Sgovinda 1247b0fc0e77Sgovinda /* Select cpu, saving it for sharing and removal */ 1248b0fc0e77Sgovinda if (ipil_list == NULL) { 12497c478bd9Sstevel@tonic-gate /* Enable MSIQ */ 12507c478bd9Sstevel@tonic-gate px_lib_msiq_setstate(dip, *msiq_id_p, PCI_MSIQ_STATE_IDLE); 12517c478bd9Sstevel@tonic-gate px_lib_msiq_setvalid(dip, *msiq_id_p, PCI_MSIQ_VALID); 12527c478bd9Sstevel@tonic-gate 125309b1eac2SEvan Yan if (ino_p->ino_cpuid == -1) 125409b1eac2SEvan Yan ino_p->ino_cpuid = intr_dist_cpuid(); 125509b1eac2SEvan Yan 12567c478bd9Sstevel@tonic-gate /* Enable interrupt */ 1257b0fc0e77Sgovinda px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 1260b0fc0e77Sgovinda ino_done: 126109b1eac2SEvan Yan hdlp->ih_target = ino_p->ino_cpuid; 126209b1eac2SEvan Yan 1263b0fc0e77Sgovinda /* Add weight to the cpu that we are already targeting */ 1264614edcaeSEvan Yan weight = pci_class_to_intr_weight(rdip); 12657c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 12667c478bd9Sstevel@tonic-gate 1267b0fc0e77Sgovinda ih_p->ih_ipil_p = ipil_p; 12686d44af1bSesolom px_create_intr_kstats(ih_p); 12697c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp) 12707c478bd9Sstevel@tonic-gate kstat_install(ih_p->ih_ksp); 12717c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: done! Interrupt 0x%x pil=%x\n", 12747c478bd9Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate return (ret); 12777c478bd9Sstevel@tonic-gate fail2: 1278b0fc0e77Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 12797c478bd9Sstevel@tonic-gate fail1: 128009b1eac2SEvan Yan (void) px_msiq_free(px_p, *msiq_id_p); 128109b1eac2SEvan Yan fail: 12827c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 12837c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 12867c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_add_msiq_intr: Failed! Interrupt 0x%x pil=%x\n", 12897c478bd9Sstevel@tonic-gate ino_p->ino_sysino, hdlp->ih_pri); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate return (ret); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 1294a195726fSgovinda /* 1295a195726fSgovinda * px_rem_msiq_intr: 1296a195726fSgovinda * 1297a195726fSgovinda * This function is called to unregister MSI/Xs and PCIe message interrupts. 1298a195726fSgovinda */ 12997c478bd9Sstevel@tonic-gate int 13007c478bd9Sstevel@tonic-gate px_rem_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 13017c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 13027c478bd9Sstevel@tonic-gate msgcode_t msg_code, msiqid_t msiq_id) 13037c478bd9Sstevel@tonic-gate { 13047c478bd9Sstevel@tonic-gate px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 13057c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 13067c478bd9Sstevel@tonic-gate devino_t ino = px_msiqid_to_devino(px_p, msiq_id); 13077c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 1308b0fc0e77Sgovinda px_ino_t *ino_p; 1309b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 13107c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 13117c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate DBG(DBG_MSIQ, dip, "px_rem_msiq_intr: rdip=%s%d msiq_id=%x ino=%x\n", 13147c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), msiq_id, ino); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate ino_p = px_ib_locate_ino(ib_p, ino); 1319b0fc0e77Sgovinda ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 1320b0fc0e77Sgovinda ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, rec_type, 1321b0fc0e77Sgovinda msg_code); 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate /* Get the current cpu */ 13247c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 13257c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) 13267c478bd9Sstevel@tonic-gate goto fail; 13277c478bd9Sstevel@tonic-gate 1328b0fc0e77Sgovinda if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS) 13297c478bd9Sstevel@tonic-gate goto fail; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 13327c478bd9Sstevel@tonic-gate 1333b0fc0e77Sgovinda if (ipil_p->ipil_ih_size == 0) { 13347c478bd9Sstevel@tonic-gate hdlp->ih_vector = ino_p->ino_sysino; 13357c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 13367c478bd9Sstevel@tonic-gate 1337b0fc0e77Sgovinda px_ib_delete_ino_pil(ib_p, ipil_p); 1338b0fc0e77Sgovinda 1339b0fc0e77Sgovinda if (ino_p->ino_ipil_size == 0) 1340b0fc0e77Sgovinda px_lib_msiq_setvalid(dip, 1341b0fc0e77Sgovinda px_devino_to_msiqid(px_p, ino), PCI_MSIQ_INVALID); 1342b0fc0e77Sgovinda } 1343b0fc0e77Sgovinda 134409b1eac2SEvan Yan (void) px_msiq_free(px_p, msiq_id); 134509b1eac2SEvan Yan 134609b1eac2SEvan Yan if (ino_p->ino_ipil_size) { 13470d2a6fcfSegillett /* Re-enable interrupt only if mapping register still shared */ 13480d2a6fcfSegillett PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate fail: 13527c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 13537c478bd9Sstevel@tonic-gate return (ret); 13547c478bd9Sstevel@tonic-gate } 1355