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 544bb982bSgovinda * Common Development and Distribution License (the "License"). 644bb982bSgovinda * 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 /* 22*09b1eac2SEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * PX Interrupt Block implementation 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 327c478bd9Sstevel@tonic-gate #include <sys/async.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> /* panicstr */ 347c478bd9Sstevel@tonic-gate #include <sys/spl.h> 357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* intr_dist_add */ 377c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 387c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 3925cf1a30Sjl #include <sys/time.h> 407c478bd9Sstevel@tonic-gate #include "px_obj.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight); 4569cd775fSschwartz static void px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, 4669cd775fSschwartz uint32_t cpu_id); 477c478bd9Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg); 4869cd775fSschwartz static void px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 4969cd775fSschwartz char *path_name, int instance); 507c478bd9Sstevel@tonic-gate 5125cf1a30Sjl extern uint64_t xc_tick_jump_limit; 5225cf1a30Sjl 537c478bd9Sstevel@tonic-gate int 547c478bd9Sstevel@tonic-gate px_ib_attach(px_t *px_p) 557c478bd9Sstevel@tonic-gate { 567c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 577c478bd9Sstevel@tonic-gate px_ib_t *ib_p; 587c478bd9Sstevel@tonic-gate sysino_t sysino; 597c478bd9Sstevel@tonic-gate px_fault_t *fault_p = &px_p->px_fault; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_attach\n"); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, 64f8d2de6bSjchu px_p->px_inos[PX_INTR_PEC], &sysino) != DDI_SUCCESS) 657c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * Allocate interrupt block state structure and link it to 697c478bd9Sstevel@tonic-gate * the px state structure. 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 727c478bd9Sstevel@tonic-gate px_p->px_ib_p = ib_p; 737c478bd9Sstevel@tonic-gate ib_p->ib_px_p = px_p; 74b0fc0e77Sgovinda ib_p->ib_ino_lst = (px_ino_t *)NULL; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 777c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate intr_dist_add_weighted(px_ib_intr_redist, ib_p); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * Initialize PEC fault data structure 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate fault_p->px_fh_dip = dip; 877c478bd9Sstevel@tonic-gate fault_p->px_fh_sysino = sysino; 88f8d2de6bSjchu fault_p->px_err_func = px_err_dmc_pec_intr; 89f8d2de6bSjchu fault_p->px_intr_ino = px_p->px_inos[PX_INTR_PEC]; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate void 957c478bd9Sstevel@tonic-gate px_ib_detach(px_t *px_p) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 987c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_detach\n"); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 1037c478bd9Sstevel@tonic-gate intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_ino_lst_mutex); 1067c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_intr_lock); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate px_ib_free_ino_all(ib_p); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate px_p->px_ib_p = NULL; 1117c478bd9Sstevel@tonic-gate kmem_free(ib_p, sizeof (px_ib_t)); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate void 1157c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 1167c478bd9Sstevel@tonic-gate { 1177c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 1187c478bd9Sstevel@tonic-gate sysino_t sysino; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * Determine the cpu for the interrupt 1227c478bd9Sstevel@tonic-gate */ 1237c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1267c478bd9Sstevel@tonic-gate "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 1297c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1307c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1317c478bd9Sstevel@tonic-gate "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1347c478bd9Sstevel@tonic-gate return; 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 138a195726fSgovinda px_lib_intr_setstate(px_p->px_dip, sysino, INTR_IDLE_STATE); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1447c478bd9Sstevel@tonic-gate void 1457c478bd9Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate sysino_t sysino; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 1547c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 1557c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1567c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, 1577c478bd9Sstevel@tonic-gate "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1607c478bd9Sstevel@tonic-gate return; 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate 16969cd775fSschwartz void 1707c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 1717c478bd9Sstevel@tonic-gate boolean_t wait_flag) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate uint32_t old_cpu_id; 1747c478bd9Sstevel@tonic-gate sysino_t sysino; 1757c478bd9Sstevel@tonic-gate intr_valid_state_t enabled = 0; 17625cf1a30Sjl hrtime_t start_time, prev, curr, interval, jump; 17725cf1a30Sjl hrtime_t intr_timeout; 1787c478bd9Sstevel@tonic-gate intr_state_t intr_state; 179f8d2de6bSjchu int e = DDI_SUCCESS; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 1847c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 1857c478bd9Sstevel@tonic-gate "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 1867c478bd9Sstevel@tonic-gate return; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* Skip enabling disabled interrupts */ 1907c478bd9Sstevel@tonic-gate if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 1917c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 1927c478bd9Sstevel@tonic-gate "failed, sysino 0x%x\n", sysino); 1937c478bd9Sstevel@tonic-gate return; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate if (!enabled) 1967c478bd9Sstevel@tonic-gate return; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* Done if redistributed onto the same cpuid */ 1997c478bd9Sstevel@tonic-gate if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 2007c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 2017c478bd9Sstevel@tonic-gate "px_intr_gettarget() failed\n"); 2027c478bd9Sstevel@tonic-gate return; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate if (cpu_id == old_cpu_id) 2057c478bd9Sstevel@tonic-gate return; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if (!wait_flag) 2087c478bd9Sstevel@tonic-gate goto done; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupts */ 2117c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 2127c478bd9Sstevel@tonic-gate 21325cf1a30Sjl intr_timeout = px_intrpend_timeout; 21425cf1a30Sjl jump = TICK_TO_NSEC(xc_tick_jump_limit); 21525cf1a30Sjl 21625cf1a30Sjl for (curr = start_time = gethrtime(); !panicstr && 2177c478bd9Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 218f0d69850Srameshc DDI_SUCCESS) && 2197c478bd9Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 22025cf1a30Sjl /* 22125cf1a30Sjl * If we have a really large jump in hrtime, it is most 22225cf1a30Sjl * probably because we entered the debugger (or OBP, 22325cf1a30Sjl * in general). So, we adjust the timeout accordingly 22425cf1a30Sjl * to prevent declaring an interrupt timeout. The 22525cf1a30Sjl * master-interrupt mechanism in OBP should deliver 22625cf1a30Sjl * the interrupts properly. 22725cf1a30Sjl */ 22825cf1a30Sjl prev = curr; 22925cf1a30Sjl curr = gethrtime(); 23025cf1a30Sjl interval = curr - prev; 23125cf1a30Sjl if (interval > jump) 23225cf1a30Sjl intr_timeout += interval; 23325cf1a30Sjl if (curr - start_time > intr_timeout) { 2347c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 235b40cec45Skrishnae "%s%d: px_ib_intr_dist_en: sysino 0x%lx(ino 0x%x) " 2367c478bd9Sstevel@tonic-gate "from cpu id 0x%x to 0x%x timeout", 2377c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2387c478bd9Sstevel@tonic-gate sysino, ino, old_cpu_id, cpu_id); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate e = DDI_FAILURE; 2417c478bd9Sstevel@tonic-gate break; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (e != DDI_SUCCESS) 2467c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 2477c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate done: 2507c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, cpu_id); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 25369cd775fSschwartz static void 25469cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, uint32_t cpu_id) 25569cd775fSschwartz { 25669cd775fSschwartz extern kmutex_t pxintr_ks_template_lock; 25769cd775fSschwartz hrtime_t ticks; 25869cd775fSschwartz 25969cd775fSschwartz /* 26069cd775fSschwartz * Because we are updating two fields in ih_t we must lock 26169cd775fSschwartz * pxintr_ks_template_lock to prevent someone from reading the 26269cd775fSschwartz * kstats after we set ih_ticks to 0 and before we increment 26369cd775fSschwartz * ih_nsec to compensate. 26469cd775fSschwartz * 26569cd775fSschwartz * We must also protect against the interrupt arriving and incrementing 26669cd775fSschwartz * ih_ticks between the time we read it and when we reset it to 0. 26769cd775fSschwartz * To do this we use atomic_swap. 26869cd775fSschwartz */ 26969cd775fSschwartz 27069cd775fSschwartz ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 27169cd775fSschwartz 27269cd775fSschwartz mutex_enter(&pxintr_ks_template_lock); 27369cd775fSschwartz ticks = atomic_swap_64(&ih_p->ih_ticks, 0); 27469cd775fSschwartz ih_p->ih_nsec += (uint64_t)tick2ns(ticks, cpu_id); 27569cd775fSschwartz mutex_exit(&pxintr_ks_template_lock); 27669cd775fSschwartz } 27769cd775fSschwartz 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Redistribute interrupts of the specified weight. The first call has a weight 2817c478bd9Sstevel@tonic-gate * of weight_max, which can be used to trigger initialization for 2827c478bd9Sstevel@tonic-gate * redistribution. The inos with weight [weight_max, inf.) should be processed 2837c478bd9Sstevel@tonic-gate * on the "weight == weight_max" call. This first call is followed by calls 2847c478bd9Sstevel@tonic-gate * of decreasing weights, inos of that weight should be processed. The final 2857c478bd9Sstevel@tonic-gate * call specifies a weight of zero, this can be used to trigger processing of 2867c478bd9Sstevel@tonic-gate * stragglers. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate static void 2897c478bd9Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 2927c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 2937c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 294b0fc0e77Sgovinda px_ino_t *ino_p; 295b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 2967c478bd9Sstevel@tonic-gate px_ih_t *ih_lst; 2977c478bd9Sstevel@tonic-gate int32_t dweight = 0; 2987c478bd9Sstevel@tonic-gate int i; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* Redistribute internal interrupts */ 3017c478bd9Sstevel@tonic-gate if (weight == 0) { 3027c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 30301689544Sjchu px_ib_intr_dist_en(dip, intr_dist_cpuid(), 30401689544Sjchu px_p->px_inos[PX_INTR_PEC], B_FALSE); 3057c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 306ab4471cdSscarter 307ab4471cdSscarter px_hp_intr_redist(px_p); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* Redistribute device interrupts */ 3117c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 312*09b1eac2SEvan Yan px_msiq_redist(px_p); 3137c478bd9Sstevel@tonic-gate 314b0fc0e77Sgovinda for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next_p) { 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 3177c478bd9Sstevel@tonic-gate * share the same ino upon first call marked by 3187c478bd9Sstevel@tonic-gate * (weight == weight_max). 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate if (weight == weight_max) { 3217c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 322b0fc0e77Sgovinda 323b0fc0e77Sgovinda for (ipil_p = ino_p->ino_ipil_p; ipil_p; 324b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 325b0fc0e77Sgovinda for (i = 0, ih_lst = ipil_p->ipil_ih_head; 326b0fc0e77Sgovinda i < ipil_p->ipil_ih_size; i++, 327b0fc0e77Sgovinda ih_lst = ih_lst->ih_next) { 328b0fc0e77Sgovinda dweight = i_ddi_get_intr_weight( 329b0fc0e77Sgovinda ih_lst->ih_dip); 330b0fc0e77Sgovinda if (dweight > 0) 331b0fc0e77Sgovinda ino_p->ino_intr_weight += 332b0fc0e77Sgovinda dweight; 333b0fc0e77Sgovinda } 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 3397c478bd9Sstevel@tonic-gate * nexus redistributes device interrupts and updates 3407c478bd9Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 3417c478bd9Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 3427c478bd9Sstevel@tonic-gate * attention demanding device gains more cpu attention by 3437c478bd9Sstevel@tonic-gate * making itself heavy. 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 3467c478bd9Sstevel@tonic-gate ((weight >= weight_max) && 3477c478bd9Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 348*09b1eac2SEvan Yan uint32_t orig_cpuid = ino_p->ino_cpuid; 349*09b1eac2SEvan Yan 3507c478bd9Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 3517c478bd9Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 3527c478bd9Sstevel@tonic-gate 353*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_intr_redist: sysino 0x%llx " 354*09b1eac2SEvan Yan "current cpuid 0x%x current default cpuid 0x%x\n", 355*09b1eac2SEvan Yan ino_p->ino_sysino, ino_p->ino_cpuid, 356*09b1eac2SEvan Yan ino_p->ino_default_cpuid); 357*09b1eac2SEvan Yan 358*09b1eac2SEvan Yan /* select target cpuid and mark ino established */ 359*09b1eac2SEvan Yan if (ino_p->ino_default_cpuid == -1) 360*09b1eac2SEvan Yan ino_p->ino_cpuid = ino_p->ino_default_cpuid = 361*09b1eac2SEvan Yan intr_dist_cpuid(); 362*09b1eac2SEvan Yan else if ((ino_p->ino_cpuid != 363*09b1eac2SEvan Yan ino_p->ino_default_cpuid) && 364*09b1eac2SEvan Yan (cpu_intr_on(cpu[ino_p->ino_default_cpuid]))) 365*09b1eac2SEvan Yan ino_p->ino_cpuid = ino_p->ino_default_cpuid; 366*09b1eac2SEvan Yan else if (!cpu_intr_on(cpu[ino_p->ino_cpuid])) 367*09b1eac2SEvan Yan ino_p->ino_cpuid = intr_dist_cpuid(); 368*09b1eac2SEvan Yan 369*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_intr_redist: sysino 0x%llx " 370*09b1eac2SEvan Yan "new cpuid 0x%x new default cpuid 0x%x\n", 371*09b1eac2SEvan Yan ino_p->ino_sysino, ino_p->ino_cpuid, 372*09b1eac2SEvan Yan ino_p->ino_default_cpuid); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 375b0fc0e77Sgovinda for (ipil_p = ino_p->ino_ipil_p; ipil_p; 376b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 377b0fc0e77Sgovinda for (i = 0, ih_lst = ipil_p->ipil_ih_head; 378b0fc0e77Sgovinda i < ipil_p->ipil_ih_size; i++, 379b0fc0e77Sgovinda ih_lst = ih_lst->ih_next) { 380b0fc0e77Sgovinda 381b0fc0e77Sgovinda dweight = i_ddi_get_intr_weight( 382b0fc0e77Sgovinda ih_lst->ih_dip); 383b0fc0e77Sgovinda intr_dist_cpuid_add_device_weight( 384b0fc0e77Sgovinda ino_p->ino_cpuid, ih_lst->ih_dip, 385b0fc0e77Sgovinda dweight); 386b0fc0e77Sgovinda 387b0fc0e77Sgovinda /* 388b0fc0e77Sgovinda * Different cpus may have different 389b0fc0e77Sgovinda * clock speeds. to account for this, 390b0fc0e77Sgovinda * whenever an interrupt is moved to a 391b0fc0e77Sgovinda * new CPU, we convert the accumulated 392b0fc0e77Sgovinda * ticks into nsec, based upon the clock 393b0fc0e77Sgovinda * rate of the prior CPU. 394b0fc0e77Sgovinda * 395b0fc0e77Sgovinda * It is possible that the prior CPU no 396b0fc0e77Sgovinda * longer exists. In this case, fall 397b0fc0e77Sgovinda * back to using this CPU's clock rate. 398b0fc0e77Sgovinda * 399b0fc0e77Sgovinda * Note that the value in ih_ticks has 400b0fc0e77Sgovinda * already been corrected for any power 401b0fc0e77Sgovinda * savings mode which might have been 402b0fc0e77Sgovinda * in effect. 403b0fc0e77Sgovinda */ 404b0fc0e77Sgovinda px_ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst, 405b0fc0e77Sgovinda orig_cpuid); 406b0fc0e77Sgovinda } 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 4107c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 4117c478bd9Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 4197c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 4207c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 4217c478bd9Sstevel@tonic-gate * 4227c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 4237c478bd9Sstevel@tonic-gate * are permanently suspended. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate static uint_t 4267c478bd9Sstevel@tonic-gate px_ib_intr_reset(void *arg) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 4337c478bd9Sstevel@tonic-gate return (BF_FATAL); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate return (BF_NONE); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 439b0fc0e77Sgovinda * Locate px_ino_t structure on ib_p->ib_ino_lst according to ino# 4407c478bd9Sstevel@tonic-gate * returns NULL if not found. 4417c478bd9Sstevel@tonic-gate */ 442b0fc0e77Sgovinda px_ino_t * 4437c478bd9Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 4447c478bd9Sstevel@tonic-gate { 445b0fc0e77Sgovinda px_ino_t *ino_p = ib_p->ib_ino_lst; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4487c478bd9Sstevel@tonic-gate 449f0d69850Srameshc for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next_p) 450f0d69850Srameshc ; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate return (ino_p); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 455*09b1eac2SEvan Yan px_ino_t * 456*09b1eac2SEvan Yan px_ib_alloc_ino(px_ib_t *ib_p, devino_t ino_num) 4577c478bd9Sstevel@tonic-gate { 458*09b1eac2SEvan Yan sysino_t sysino; 459b0fc0e77Sgovinda px_ino_t *ino_p; 4607c478bd9Sstevel@tonic-gate 461*09b1eac2SEvan Yan if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, 462*09b1eac2SEvan Yan ino_num, &sysino) != DDI_SUCCESS) 463*09b1eac2SEvan Yan return (NULL); 4647c478bd9Sstevel@tonic-gate 465*09b1eac2SEvan Yan ino_p = kmem_zalloc(sizeof (px_ino_t), KM_SLEEP); 4667c478bd9Sstevel@tonic-gate 467*09b1eac2SEvan Yan ino_p->ino_next_p = ib_p->ib_ino_lst; 468*09b1eac2SEvan Yan ib_p->ib_ino_lst = ino_p; 469b0fc0e77Sgovinda 470*09b1eac2SEvan Yan ino_p->ino_ino = ino_num; 471*09b1eac2SEvan Yan ino_p->ino_sysino = sysino; 472*09b1eac2SEvan Yan ino_p->ino_ib_p = ib_p; 473*09b1eac2SEvan Yan ino_p->ino_unclaimed_intrs = 0; 474*09b1eac2SEvan Yan ino_p->ino_lopil = 0; 475*09b1eac2SEvan Yan ino_p->ino_cpuid = ino_p->ino_default_cpuid = (cpuid_t)-1; 476b0fc0e77Sgovinda 477*09b1eac2SEvan Yan return (ino_p); 478*09b1eac2SEvan Yan } 479*09b1eac2SEvan Yan 480*09b1eac2SEvan Yan px_ino_pil_t * 481*09b1eac2SEvan Yan px_ib_new_ino_pil(px_ib_t *ib_p, devino_t ino_num, uint_t pil, px_ih_t *ih_p) 482*09b1eac2SEvan Yan { 483*09b1eac2SEvan Yan px_ino_pil_t *ipil_p = kmem_zalloc(sizeof (px_ino_pil_t), KM_SLEEP); 484*09b1eac2SEvan Yan px_ino_t *ino_p; 485*09b1eac2SEvan Yan 486*09b1eac2SEvan Yan if ((ino_p = px_ib_locate_ino(ib_p, ino_num)) == NULL) 487*09b1eac2SEvan Yan ino_p = px_ib_alloc_ino(ib_p, ino_num); 488*09b1eac2SEvan Yan 489*09b1eac2SEvan Yan ASSERT(ino_p != NULL); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate ih_p->ih_next = ih_p; 492b0fc0e77Sgovinda ipil_p->ipil_pil = pil; 493b0fc0e77Sgovinda ipil_p->ipil_ih_head = ih_p; 494b0fc0e77Sgovinda ipil_p->ipil_ih_tail = ih_p; 495b0fc0e77Sgovinda ipil_p->ipil_ih_start = ih_p; 496b0fc0e77Sgovinda ipil_p->ipil_ih_size = 1; 497b0fc0e77Sgovinda ipil_p->ipil_ino_p = ino_p; 4987c478bd9Sstevel@tonic-gate 499b0fc0e77Sgovinda ipil_p->ipil_next_p = ino_p->ino_ipil_p; 500b0fc0e77Sgovinda ino_p->ino_ipil_p = ipil_p; 501b0fc0e77Sgovinda ino_p->ino_ipil_size++; 5027c478bd9Sstevel@tonic-gate 503*09b1eac2SEvan Yan if ((ino_p->ino_lopil == 0) || (ino_p->ino_lopil > pil)) 504b0fc0e77Sgovinda ino_p->ino_lopil = pil; 505b0fc0e77Sgovinda 506b0fc0e77Sgovinda return (ipil_p); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate void 510b0fc0e77Sgovinda px_ib_delete_ino_pil(px_ib_t *ib_p, px_ino_pil_t *ipil_p) 5117c478bd9Sstevel@tonic-gate { 512b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 513b0fc0e77Sgovinda ushort_t pil = ipil_p->ipil_pil; 514b0fc0e77Sgovinda px_ino_pil_t *prev, *next; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 5177c478bd9Sstevel@tonic-gate 518b0fc0e77Sgovinda if (ino_p->ino_ipil_p == ipil_p) 519b0fc0e77Sgovinda ino_p->ino_ipil_p = ipil_p->ipil_next_p; 520b0fc0e77Sgovinda else { 521b0fc0e77Sgovinda for (prev = next = ino_p->ino_ipil_p; next != ipil_p; 522f0d69850Srameshc prev = next, next = next->ipil_next_p) 523f0d69850Srameshc ; 524b0fc0e77Sgovinda 525b0fc0e77Sgovinda if (prev) 526b0fc0e77Sgovinda prev->ipil_next_p = ipil_p->ipil_next_p; 527b0fc0e77Sgovinda } 528b0fc0e77Sgovinda 529b0fc0e77Sgovinda kmem_free(ipil_p, sizeof (px_ino_pil_t)); 530b0fc0e77Sgovinda 531e4517573Srameshc if ((--ino_p->ino_ipil_size) && (ino_p->ino_lopil == pil)) { 532e4517573Srameshc for (next = ino_p->ino_ipil_p, pil = next->ipil_pil; 533e4517573Srameshc next; next = next->ipil_next_p) { 534e4517573Srameshc 535b0fc0e77Sgovinda if (pil > next->ipil_pil) 536b0fc0e77Sgovinda pil = next->ipil_pil; 537b0fc0e77Sgovinda } 538*09b1eac2SEvan Yan 539e4517573Srameshc /* 540e4517573Srameshc * Value stored in pil should be the lowest pil. 541e4517573Srameshc */ 542b0fc0e77Sgovinda ino_p->ino_lopil = pil; 543b0fc0e77Sgovinda } 544b0fc0e77Sgovinda 545e4517573Srameshc if (ino_p->ino_ipil_size) 546b0fc0e77Sgovinda return; 547b0fc0e77Sgovinda 548*09b1eac2SEvan Yan ino_p->ino_lopil = 0; 549*09b1eac2SEvan Yan 550*09b1eac2SEvan Yan if (ino_p->ino_msiq_p) 551*09b1eac2SEvan Yan return; 552*09b1eac2SEvan Yan 553b0fc0e77Sgovinda if (ib_p->ib_ino_lst == ino_p) 554b0fc0e77Sgovinda ib_p->ib_ino_lst = ino_p->ino_next_p; 5557c478bd9Sstevel@tonic-gate else { 556b0fc0e77Sgovinda px_ino_t *list = ib_p->ib_ino_lst; 557b0fc0e77Sgovinda 558f0d69850Srameshc for (; list->ino_next_p != ino_p; list = list->ino_next_p) 559f0d69850Srameshc ; 560b0fc0e77Sgovinda list->ino_next_p = ino_p->ino_next_p; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * Free all ino when we are detaching. 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate void 5687c478bd9Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 5697c478bd9Sstevel@tonic-gate { 570b0fc0e77Sgovinda px_ino_t *ino_p = ib_p->ib_ino_lst; 571b0fc0e77Sgovinda px_ino_t *next = NULL; 5727c478bd9Sstevel@tonic-gate 573b0fc0e77Sgovinda while (ino_p) { 574b0fc0e77Sgovinda next = ino_p->ino_next_p; 575b0fc0e77Sgovinda kmem_free(ino_p, sizeof (px_ino_t)); 576b0fc0e77Sgovinda ino_p = next; 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 580b0fc0e77Sgovinda /* 581b0fc0e77Sgovinda * Locate px_ino_pil_t structure on ino_p->ino_ipil_p according to ino# 582b0fc0e77Sgovinda * returns NULL if not found. 583b0fc0e77Sgovinda */ 584b0fc0e77Sgovinda px_ino_pil_t * 585b0fc0e77Sgovinda px_ib_ino_locate_ipil(px_ino_t *ino_p, uint_t pil) 586b0fc0e77Sgovinda { 587b0fc0e77Sgovinda px_ino_pil_t *ipil_p = ino_p->ino_ipil_p; 588b0fc0e77Sgovinda 589f0d69850Srameshc for (; ipil_p && ipil_p->ipil_pil != pil; ipil_p = ipil_p->ipil_next_p) 590f0d69850Srameshc ; 591b0fc0e77Sgovinda 592b0fc0e77Sgovinda return (ipil_p); 593b0fc0e77Sgovinda } 594b0fc0e77Sgovinda 5957c478bd9Sstevel@tonic-gate int 596b0fc0e77Sgovinda px_ib_ino_add_intr(px_t *px_p, px_ino_pil_t *ipil_p, px_ih_t *ih_p) 5977c478bd9Sstevel@tonic-gate { 598b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 5997c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 6007c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 6017c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 6027c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 6037c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 6047c478bd9Sstevel@tonic-gate hrtime_t start_time; 6057c478bd9Sstevel@tonic-gate intr_state_t intr_state; 6067c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 6097c478bd9Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 6147c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 6157c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 6167c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, 6177c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate return (ret); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 6257c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 6267c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 6277c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 6287c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 6297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 630b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 6317c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 6327c478bd9Sstevel@tonic-gate sysino, ino); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 6357c478bd9Sstevel@tonic-gate break; 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6417c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6427c478bd9Sstevel@tonic-gate * jabber has gone away. 6437c478bd9Sstevel@tonic-gate */ 644b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) { 6457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6467c478bd9Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 6477c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 6487c478bd9Sstevel@tonic-gate 649b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 650b0fc0e77Sgovinda ret = px_lib_intr_setstate(dip, sysino, INTR_IDLE_STATE); 651b0fc0e77Sgovinda } 652b0fc0e77Sgovinda 653b0fc0e77Sgovinda if (ret != DDI_SUCCESS) { 654b0fc0e77Sgovinda DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 655b0fc0e77Sgovinda "ino 0x%x sysino 0x%x\n", ino, sysino); 6567c478bd9Sstevel@tonic-gate 657b0fc0e77Sgovinda return (ret); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 660b0fc0e77Sgovinda /* Link up px_ih_t */ 661b0fc0e77Sgovinda ih_p->ih_next = ipil_p->ipil_ih_head; 662b0fc0e77Sgovinda ipil_p->ipil_ih_tail->ih_next = ih_p; 663b0fc0e77Sgovinda ipil_p->ipil_ih_tail = ih_p; 664b0fc0e77Sgovinda 665b0fc0e77Sgovinda ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; 666b0fc0e77Sgovinda ipil_p->ipil_ih_size++; 667b0fc0e77Sgovinda 6687c478bd9Sstevel@tonic-gate /* Re-enable interrupt */ 6697c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate return (ret); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 675b0fc0e77Sgovinda * Removes px_ih_t from the ino's link list. 6767c478bd9Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 6777c478bd9Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 6787c478bd9Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 6797c478bd9Sstevel@tonic-gate * to turn it back on. 6807c478bd9Sstevel@tonic-gate */ 6817c478bd9Sstevel@tonic-gate int 682b0fc0e77Sgovinda px_ib_ino_rem_intr(px_t *px_p, px_ino_pil_t *ipil_p, px_ih_t *ih_p) 6837c478bd9Sstevel@tonic-gate { 684b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 6857c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 6867c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 6877c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 688b0fc0e77Sgovinda px_ih_t *ih_lst = ipil_p->ipil_ih_head; 6897c478bd9Sstevel@tonic-gate hrtime_t start_time; 6907c478bd9Sstevel@tonic-gate intr_state_t intr_state; 6917c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 6967c478bd9Sstevel@tonic-gate ino_p->ino_ino); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 6997c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 7007c478bd9Sstevel@tonic-gate 701b0fc0e77Sgovinda if (ipil_p->ipil_ih_size == 1) { 7027c478bd9Sstevel@tonic-gate if (ih_lst != ih_p) 7037c478bd9Sstevel@tonic-gate goto not_found; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 7067c478bd9Sstevel@tonic-gate goto reset; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 7107c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 7117c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 7127c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 7137c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 7147c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 715b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 7167c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 7177c478bd9Sstevel@tonic-gate sysino, ino); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 7207c478bd9Sstevel@tonic-gate break; 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 7267c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 7277c478bd9Sstevel@tonic-gate * jabber has gone away. 7287c478bd9Sstevel@tonic-gate */ 729b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) { 7307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 7317c478bd9Sstevel@tonic-gate "ino 0x%x has been unblocked", 7327c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 7337c478bd9Sstevel@tonic-gate 734b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 735b0fc0e77Sgovinda ret = px_lib_intr_setstate(dip, sysino, INTR_IDLE_STATE); 736b0fc0e77Sgovinda } 7377c478bd9Sstevel@tonic-gate 738b0fc0e77Sgovinda if (ret != DDI_SUCCESS) { 739b0fc0e77Sgovinda DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 740b0fc0e77Sgovinda "ino 0x%x sysino 0x%x\n", ino, sysino); 741b0fc0e77Sgovinda 742b0fc0e77Sgovinda return (ret); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* Search the link list for ih_p */ 746b0fc0e77Sgovinda for (i = 0; (i < ipil_p->ipil_ih_size) && 747f0d69850Srameshc (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next) 748f0d69850Srameshc ; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 7517c478bd9Sstevel@tonic-gate goto not_found; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 7547c478bd9Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 7557c478bd9Sstevel@tonic-gate 756b0fc0e77Sgovinda if (ipil_p->ipil_ih_head == ih_p) 757b0fc0e77Sgovinda ipil_p->ipil_ih_head = ih_p->ih_next; 758b0fc0e77Sgovinda if (ipil_p->ipil_ih_tail == ih_p) 759b0fc0e77Sgovinda ipil_p->ipil_ih_tail = ih_lst; 7607c478bd9Sstevel@tonic-gate 761b0fc0e77Sgovinda ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate reset: 7647c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 7657c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 7667c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 7677c478bd9Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 770b0fc0e77Sgovinda ipil_p->ipil_ih_size--; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate return (ret); 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate not_found: 7757c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 776f0d69850Srameshc "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate px_ih_t * 782b0fc0e77Sgovinda px_ib_intr_locate_ih(px_ino_pil_t *ipil_p, dev_info_t *rdip, 7837c478bd9Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 7847c478bd9Sstevel@tonic-gate { 785b0fc0e77Sgovinda px_ih_t *ih_p = ipil_p->ipil_ih_head; 7867c478bd9Sstevel@tonic-gate int i; 7877c478bd9Sstevel@tonic-gate 788b0fc0e77Sgovinda for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 789b0fc0e77Sgovinda if ((ih_p->ih_dip == rdip) && (ih_p->ih_inum == inum) && 790b0fc0e77Sgovinda (ih_p->ih_rec_type == rec_type) && 791b0fc0e77Sgovinda (ih_p->ih_msg_code == msg_code)) 792b0fc0e77Sgovinda return (ih_p); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate return ((px_ih_t *)NULL); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate px_ih_t * 7997c478bd9Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 8007c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 8017c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 8027c478bd9Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 8037c478bd9Sstevel@tonic-gate { 8047c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 8077c478bd9Sstevel@tonic-gate ih_p->ih_dip = rdip; 8087c478bd9Sstevel@tonic-gate ih_p->ih_inum = inum; 8097c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 8107c478bd9Sstevel@tonic-gate ih_p->ih_handler = int_handler; 8117c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 8127c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 8137c478bd9Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 8147c478bd9Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 8157c478bd9Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 8167c478bd9Sstevel@tonic-gate ih_p->ih_nsec = 0; 8177c478bd9Sstevel@tonic-gate ih_p->ih_ticks = 0; 8187c478bd9Sstevel@tonic-gate ih_p->ih_ksp = NULL; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate return (ih_p); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate int 8247c478bd9Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 825b0fc0e77Sgovinda uint_t inum, devino_t ino, uint_t pil, 826b0fc0e77Sgovinda uint_t new_intr_state, msiq_rec_type_t rec_type, 827b0fc0e77Sgovinda msgcode_t msg_code) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 830b0fc0e77Sgovinda px_ino_t *ino_p; 831b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 8327c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 8337c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 8347c478bd9Sstevel@tonic-gate 835b0fc0e77Sgovinda DBG(DBG_IB, px_p->px_dip, "px_ib_update_intr_state: %s%d " 836b0fc0e77Sgovinda "inum %x devino %x pil %x state %x\n", ddi_driver_name(rdip), 837b0fc0e77Sgovinda ddi_get_instance(rdip), inum, ino, pil, new_intr_state); 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 8407c478bd9Sstevel@tonic-gate 841b0fc0e77Sgovinda ino_p = px_ib_locate_ino(ib_p, ino); 842b0fc0e77Sgovinda if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, pil))) { 843b0fc0e77Sgovinda if (ih_p = px_ib_intr_locate_ih(ipil_p, rdip, inum, rec_type, 84436fe4a92Segillett msg_code)) { 8457c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 8467c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 8517c478bd9Sstevel@tonic-gate return (ret); 8527c478bd9Sstevel@tonic-gate } 85369cd775fSschwartz 85469cd775fSschwartz 855*09b1eac2SEvan Yan /* 856*09b1eac2SEvan Yan * Get interrupt CPU for a given ino. 857*09b1eac2SEvan Yan * Return info only for inos which are already mapped to devices. 858*09b1eac2SEvan Yan */ 859*09b1eac2SEvan Yan /*ARGSUSED*/ 860*09b1eac2SEvan Yan int 861*09b1eac2SEvan Yan px_ib_get_intr_target(px_t *px_p, devino_t ino, cpuid_t *cpu_id_p) 862*09b1eac2SEvan Yan { 863*09b1eac2SEvan Yan dev_info_t *dip = px_p->px_dip; 864*09b1eac2SEvan Yan sysino_t sysino; 865*09b1eac2SEvan Yan int ret; 866*09b1eac2SEvan Yan 867*09b1eac2SEvan Yan DBG(DBG_IB, px_p->px_dip, "px_ib_get_intr_target: devino %x\n", ino); 868*09b1eac2SEvan Yan 869*09b1eac2SEvan Yan /* Convert leaf-wide intr to system-wide intr */ 870*09b1eac2SEvan Yan if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) 871*09b1eac2SEvan Yan return (DDI_FAILURE); 872*09b1eac2SEvan Yan 873*09b1eac2SEvan Yan ret = px_lib_intr_gettarget(dip, sysino, cpu_id_p); 874*09b1eac2SEvan Yan 875*09b1eac2SEvan Yan DBG(DBG_IB, px_p->px_dip, "px_ib_get_intr_target: cpu_id %x\n", 876*09b1eac2SEvan Yan *cpu_id_p); 877*09b1eac2SEvan Yan 878*09b1eac2SEvan Yan return (ret); 879*09b1eac2SEvan Yan } 880*09b1eac2SEvan Yan 881*09b1eac2SEvan Yan 882*09b1eac2SEvan Yan /* 883*09b1eac2SEvan Yan * Associate a new CPU with a given ino. 884*09b1eac2SEvan Yan * Operate only on INOs which are already mapped to devices. 885*09b1eac2SEvan Yan */ 886*09b1eac2SEvan Yan int 887*09b1eac2SEvan Yan px_ib_set_intr_target(px_t *px_p, devino_t ino, cpuid_t cpu_id) 888*09b1eac2SEvan Yan { 889*09b1eac2SEvan Yan dev_info_t *dip = px_p->px_dip; 890*09b1eac2SEvan Yan cpuid_t old_cpu_id; 891*09b1eac2SEvan Yan sysino_t sysino; 892*09b1eac2SEvan Yan int ret = DDI_SUCCESS; 893*09b1eac2SEvan Yan extern const int _ncpu; 894*09b1eac2SEvan Yan extern cpu_t *cpu[]; 895*09b1eac2SEvan Yan 896*09b1eac2SEvan Yan DBG(DBG_IB, px_p->px_dip, "px_ib_set_intr_target: devino %x " 897*09b1eac2SEvan Yan "cpu_id %x\n", ino, cpu_id); 898*09b1eac2SEvan Yan 899*09b1eac2SEvan Yan mutex_enter(&cpu_lock); 900*09b1eac2SEvan Yan 901*09b1eac2SEvan Yan /* Convert leaf-wide intr to system-wide intr */ 902*09b1eac2SEvan Yan if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 903*09b1eac2SEvan Yan ret = DDI_FAILURE; 904*09b1eac2SEvan Yan goto done; 905*09b1eac2SEvan Yan } 906*09b1eac2SEvan Yan 907*09b1eac2SEvan Yan if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 908*09b1eac2SEvan Yan ret = DDI_FAILURE; 909*09b1eac2SEvan Yan goto done; 910*09b1eac2SEvan Yan } 911*09b1eac2SEvan Yan 912*09b1eac2SEvan Yan /* 913*09b1eac2SEvan Yan * Get lock, validate cpu and write it. 914*09b1eac2SEvan Yan */ 915*09b1eac2SEvan Yan if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) { 916*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_intr_target: Enabling CPU %d\n", 917*09b1eac2SEvan Yan cpu_id); 918*09b1eac2SEvan Yan px_ib_intr_dist_en(dip, cpu_id, ino, B_TRUE); 919*09b1eac2SEvan Yan px_ib_log_new_cpu(px_p->px_ib_p, old_cpu_id, cpu_id, ino); 920*09b1eac2SEvan Yan } else { /* Invalid cpu */ 921*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_intr_target: Invalid cpuid %x\n", 922*09b1eac2SEvan Yan cpu_id); 923*09b1eac2SEvan Yan ret = DDI_EINVAL; 924*09b1eac2SEvan Yan } 925*09b1eac2SEvan Yan 926*09b1eac2SEvan Yan done: 927*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 928*09b1eac2SEvan Yan return (ret); 929*09b1eac2SEvan Yan } 930*09b1eac2SEvan Yan 931*09b1eac2SEvan Yan hrtime_t px_ib_msix_retarget_timeout = 120ll * NANOSEC; /* 120 seconds */ 932*09b1eac2SEvan Yan 933*09b1eac2SEvan Yan /* 934*09b1eac2SEvan Yan * Associate a new CPU with a given MSI/X. 935*09b1eac2SEvan Yan * Operate only on MSI/Xs which are already mapped to devices. 936*09b1eac2SEvan Yan */ 937*09b1eac2SEvan Yan int 938*09b1eac2SEvan Yan px_ib_set_msix_target(px_t *px_p, ddi_intr_handle_impl_t *hdlp, 939*09b1eac2SEvan Yan msinum_t msi_num, cpuid_t cpu_id) 940*09b1eac2SEvan Yan { 941*09b1eac2SEvan Yan px_ib_t *ib_p = px_p->px_ib_p; 942*09b1eac2SEvan Yan px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 943*09b1eac2SEvan Yan dev_info_t *dip = px_p->px_dip; 944*09b1eac2SEvan Yan dev_info_t *rdip = hdlp->ih_dip; 945*09b1eac2SEvan Yan msiqid_t msiq_id, old_msiq_id; 946*09b1eac2SEvan Yan pci_msi_state_t msi_state; 947*09b1eac2SEvan Yan msiq_rec_type_t msiq_rec_type; 948*09b1eac2SEvan Yan msi_type_t msi_type; 949*09b1eac2SEvan Yan px_ino_t *ino_p; 950*09b1eac2SEvan Yan px_ih_t *ih_p, *old_ih_p; 951*09b1eac2SEvan Yan cpuid_t old_cpu_id; 952*09b1eac2SEvan Yan hrtime_t start_time, end_time; 953*09b1eac2SEvan Yan int ret = DDI_SUCCESS; 954*09b1eac2SEvan Yan extern const int _ncpu; 955*09b1eac2SEvan Yan extern cpu_t *cpu[]; 956*09b1eac2SEvan Yan 957*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_msix_target: msi_num %x new cpu_id %x\n", 958*09b1eac2SEvan Yan msi_num, cpu_id); 959*09b1eac2SEvan Yan 960*09b1eac2SEvan Yan mutex_enter(&cpu_lock); 961*09b1eac2SEvan Yan 962*09b1eac2SEvan Yan /* Check for MSI64 support */ 963*09b1eac2SEvan Yan if ((hdlp->ih_cap & DDI_INTR_FLAG_MSI64) && msi_state_p->msi_addr64) { 964*09b1eac2SEvan Yan msiq_rec_type = MSI64_REC; 965*09b1eac2SEvan Yan msi_type = MSI64_TYPE; 966*09b1eac2SEvan Yan } else { 967*09b1eac2SEvan Yan msiq_rec_type = MSI32_REC; 968*09b1eac2SEvan Yan msi_type = MSI32_TYPE; 969*09b1eac2SEvan Yan } 970*09b1eac2SEvan Yan 971*09b1eac2SEvan Yan if ((ret = px_lib_msi_getmsiq(dip, msi_num, 972*09b1eac2SEvan Yan &old_msiq_id)) != DDI_SUCCESS) { 973*09b1eac2SEvan Yan 974*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 975*09b1eac2SEvan Yan return (ret); 976*09b1eac2SEvan Yan } 977*09b1eac2SEvan Yan 978*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_msix_target: current msiq 0x%x\n", 979*09b1eac2SEvan Yan old_msiq_id); 980*09b1eac2SEvan Yan 981*09b1eac2SEvan Yan if ((ret = px_ib_get_intr_target(px_p, 982*09b1eac2SEvan Yan px_msiqid_to_devino(px_p, old_msiq_id), 983*09b1eac2SEvan Yan &old_cpu_id)) != DDI_SUCCESS) { 984*09b1eac2SEvan Yan 985*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 986*09b1eac2SEvan Yan return (ret); 987*09b1eac2SEvan Yan } 988*09b1eac2SEvan Yan 989*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_msix_target: current cpuid 0x%x\n", 990*09b1eac2SEvan Yan old_cpu_id); 991*09b1eac2SEvan Yan 992*09b1eac2SEvan Yan if (cpu_id == old_cpu_id) { 993*09b1eac2SEvan Yan 994*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 995*09b1eac2SEvan Yan return (DDI_SUCCESS); 996*09b1eac2SEvan Yan } 997*09b1eac2SEvan Yan 998*09b1eac2SEvan Yan /* 999*09b1eac2SEvan Yan * Get lock, validate cpu and write it. 1000*09b1eac2SEvan Yan */ 1001*09b1eac2SEvan Yan if (!((cpu_id < _ncpu) && (cpu[cpu_id] && 1002*09b1eac2SEvan Yan cpu_is_online(cpu[cpu_id])))) { 1003*09b1eac2SEvan Yan /* Invalid cpu */ 1004*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_msix_target: Invalid cpuid %x\n", 1005*09b1eac2SEvan Yan cpu_id); 1006*09b1eac2SEvan Yan 1007*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 1008*09b1eac2SEvan Yan return (DDI_EINVAL); 1009*09b1eac2SEvan Yan } 1010*09b1eac2SEvan Yan 1011*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_msix_target: Enabling CPU %d\n", cpu_id); 1012*09b1eac2SEvan Yan 1013*09b1eac2SEvan Yan if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 1014*09b1eac2SEvan Yan msiq_rec_type, msi_num, cpu_id, &msiq_id)) != DDI_SUCCESS) { 1015*09b1eac2SEvan Yan DBG(DBG_IB, dip, "px_ib_set_msix_target: Add MSI handler " 1016*09b1eac2SEvan Yan "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 1017*09b1eac2SEvan Yan 1018*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 1019*09b1eac2SEvan Yan return (ret); 1020*09b1eac2SEvan Yan } 1021*09b1eac2SEvan Yan 1022*09b1eac2SEvan Yan if ((ret = px_lib_msi_setmsiq(dip, msi_num, 1023*09b1eac2SEvan Yan msiq_id, msi_type)) != DDI_SUCCESS) { 1024*09b1eac2SEvan Yan (void) px_rem_msiq_intr(dip, rdip, 1025*09b1eac2SEvan Yan hdlp, msiq_rec_type, msi_num, msiq_id); 1026*09b1eac2SEvan Yan 1027*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 1028*09b1eac2SEvan Yan return (ret); 1029*09b1eac2SEvan Yan } 1030*09b1eac2SEvan Yan 1031*09b1eac2SEvan Yan if ((ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 1032*09b1eac2SEvan Yan px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri, 1033*09b1eac2SEvan Yan PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num)) != DDI_SUCCESS) { 1034*09b1eac2SEvan Yan (void) px_rem_msiq_intr(dip, rdip, 1035*09b1eac2SEvan Yan hdlp, msiq_rec_type, msi_num, msiq_id); 1036*09b1eac2SEvan Yan 1037*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 1038*09b1eac2SEvan Yan return (ret); 1039*09b1eac2SEvan Yan } 1040*09b1eac2SEvan Yan 1041*09b1eac2SEvan Yan mutex_exit(&cpu_lock); 1042*09b1eac2SEvan Yan mutex_enter(&ib_p->ib_ino_lst_mutex); 1043*09b1eac2SEvan Yan 1044*09b1eac2SEvan Yan ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, old_msiq_id)); 1045*09b1eac2SEvan Yan old_ih_p = px_ib_intr_locate_ih(px_ib_ino_locate_ipil(ino_p, 1046*09b1eac2SEvan Yan hdlp->ih_pri), rdip, hdlp->ih_inum, msiq_rec_type, msi_num); 1047*09b1eac2SEvan Yan old_ih_p->ih_retarget_flag = B_TRUE; 1048*09b1eac2SEvan Yan 1049*09b1eac2SEvan Yan ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, msiq_id)); 1050*09b1eac2SEvan Yan ih_p = px_ib_intr_locate_ih(px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri), 1051*09b1eac2SEvan Yan rdip, hdlp->ih_inum, msiq_rec_type, msi_num); 1052*09b1eac2SEvan Yan ih_p->ih_retarget_flag = B_TRUE; 1053*09b1eac2SEvan Yan 1054*09b1eac2SEvan Yan if ((ret = px_lib_msi_getstate(dip, msi_num, 1055*09b1eac2SEvan Yan &msi_state)) != DDI_SUCCESS) { 1056*09b1eac2SEvan Yan (void) px_rem_msiq_intr(dip, rdip, 1057*09b1eac2SEvan Yan hdlp, msiq_rec_type, msi_num, msiq_id); 1058*09b1eac2SEvan Yan 1059*09b1eac2SEvan Yan mutex_exit(&ib_p->ib_ino_lst_mutex); 1060*09b1eac2SEvan Yan return (ret); 1061*09b1eac2SEvan Yan } 1062*09b1eac2SEvan Yan 1063*09b1eac2SEvan Yan if (msi_state == PCI_MSI_STATE_IDLE) 1064*09b1eac2SEvan Yan ih_p->ih_retarget_flag = B_FALSE; 1065*09b1eac2SEvan Yan 1066*09b1eac2SEvan Yan start_time = gethrtime(); 1067*09b1eac2SEvan Yan while ((ih_p->ih_retarget_flag == B_TRUE) && 1068*09b1eac2SEvan Yan (old_ih_p->ih_retarget_flag == B_TRUE)) { 1069*09b1eac2SEvan Yan if ((end_time = (gethrtime() - start_time)) > 1070*09b1eac2SEvan Yan px_ib_msix_retarget_timeout) { 1071*09b1eac2SEvan Yan cmn_err(CE_WARN, "MSIX retarget %x is not completed, " 1072*09b1eac2SEvan Yan "even after waiting %llx ticks\n", 1073*09b1eac2SEvan Yan msi_num, end_time); 1074*09b1eac2SEvan Yan 1075*09b1eac2SEvan Yan break; 1076*09b1eac2SEvan Yan } 1077*09b1eac2SEvan Yan 1078*09b1eac2SEvan Yan /* Wait for one second */ 1079*09b1eac2SEvan Yan delay(drv_usectohz(1000000)); 1080*09b1eac2SEvan Yan } 1081*09b1eac2SEvan Yan 1082*09b1eac2SEvan Yan mutex_exit(&ib_p->ib_ino_lst_mutex); 1083*09b1eac2SEvan Yan 1084*09b1eac2SEvan Yan ret = px_rem_msiq_intr(dip, rdip, 1085*09b1eac2SEvan Yan hdlp, msiq_rec_type, msi_num, old_msiq_id); 1086*09b1eac2SEvan Yan 1087*09b1eac2SEvan Yan return (ret); 1088*09b1eac2SEvan Yan } 1089*09b1eac2SEvan Yan 1090*09b1eac2SEvan Yan 109169cd775fSschwartz static void 109269cd775fSschwartz px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 109369cd775fSschwartz char *path_name, int instance) 109469cd775fSschwartz { 109569cd775fSschwartz (void) strncpy(dev->driver_name, driver_name, MAXMODCONFNAME-1); 109669cd775fSschwartz dev->driver_name[MAXMODCONFNAME] = '\0'; 109769cd775fSschwartz (void) strncpy(dev->path, path_name, MAXPATHLEN-1); 109869cd775fSschwartz dev->dev_inst = instance; 109969cd775fSschwartz } 110069cd775fSschwartz 110169cd775fSschwartz 110269cd775fSschwartz /* 110369cd775fSschwartz * Return the dips or number of dips associated with a given interrupt block. 110469cd775fSschwartz * Size of dips array arg is passed in as dips_ret arg. 110569cd775fSschwartz * Number of dips returned is returned in dips_ret arg. 110669cd775fSschwartz * Array of dips gets returned in the dips argument. 110769cd775fSschwartz * Function returns number of dips existing for the given interrupt block. 110869cd775fSschwartz * 110969cd775fSschwartz * Note: this function assumes an enabled/valid INO, which is why it returns 111069cd775fSschwartz * the px node and (Internal) when it finds no other devices (and *devs_ret > 0) 111169cd775fSschwartz */ 111269cd775fSschwartz uint8_t 1113*09b1eac2SEvan Yan pxtool_ib_get_ino_devs(px_t *px_p, uint32_t ino, uint32_t msi_num, 1114*09b1eac2SEvan Yan uint8_t *devs_ret, pcitool_intr_dev_t *devs) 111569cd775fSschwartz { 1116b0fc0e77Sgovinda px_ib_t *ib_p = px_p->px_ib_p; 1117b0fc0e77Sgovinda px_ino_t *ino_p; 1118b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 1119b0fc0e77Sgovinda px_ih_t *ih_p; 1120b0fc0e77Sgovinda uint32_t num_devs = 0; 1121b0fc0e77Sgovinda char pathname[MAXPATHLEN]; 1122b0fc0e77Sgovinda int i, j; 112369cd775fSschwartz 112469cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 112569cd775fSschwartz ino_p = px_ib_locate_ino(ib_p, ino); 112669cd775fSschwartz if (ino_p != NULL) { 1127b0fc0e77Sgovinda for (j = 0, ipil_p = ino_p->ino_ipil_p; ipil_p; 1128b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 1129b0fc0e77Sgovinda num_devs += ipil_p->ipil_ih_size; 1130b0fc0e77Sgovinda 1131b0fc0e77Sgovinda for (i = 0, ih_p = ipil_p->ipil_ih_head; 1132b0fc0e77Sgovinda ((i < ipil_p->ipil_ih_size) && (i < *devs_ret)); 1133b0fc0e77Sgovinda i++, j++, ih_p = ih_p->ih_next) { 1134b0fc0e77Sgovinda (void) ddi_pathname(ih_p->ih_dip, pathname); 1135*09b1eac2SEvan Yan 1136*09b1eac2SEvan Yan if (ih_p->ih_msg_code == msi_num) { 1137*09b1eac2SEvan Yan num_devs = *devs_ret = 1; 1138*09b1eac2SEvan Yan px_fill_in_intr_devs(&devs[0], 1139*09b1eac2SEvan Yan (char *)ddi_driver_name( 1140*09b1eac2SEvan Yan ih_p->ih_dip), pathname, 1141*09b1eac2SEvan Yan ddi_get_instance(ih_p->ih_dip)); 1142*09b1eac2SEvan Yan goto done; 1143*09b1eac2SEvan Yan } 1144*09b1eac2SEvan Yan 1145*09b1eac2SEvan Yan px_fill_in_intr_devs(&devs[j], 1146b0fc0e77Sgovinda (char *)ddi_driver_name(ih_p->ih_dip), 1147b0fc0e77Sgovinda pathname, ddi_get_instance(ih_p->ih_dip)); 1148b0fc0e77Sgovinda } 114969cd775fSschwartz } 115069cd775fSschwartz 1151b0fc0e77Sgovinda *devs_ret = j; 115269cd775fSschwartz } else if (*devs_ret > 0) { 115369cd775fSschwartz (void) ddi_pathname(px_p->px_dip, pathname); 115469cd775fSschwartz strcat(pathname, " (Internal)"); 115569cd775fSschwartz px_fill_in_intr_devs(&devs[0], 115669cd775fSschwartz (char *)ddi_driver_name(px_p->px_dip), pathname, 115769cd775fSschwartz ddi_get_instance(px_p->px_dip)); 115869cd775fSschwartz num_devs = *devs_ret = 1; 115969cd775fSschwartz } 116069cd775fSschwartz 1161*09b1eac2SEvan Yan done: 116269cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 116369cd775fSschwartz 116469cd775fSschwartz return (num_devs); 116569cd775fSschwartz } 116669cd775fSschwartz 116769cd775fSschwartz 1168*09b1eac2SEvan Yan int 1169*09b1eac2SEvan Yan pxtool_ib_get_msi_info(px_t *px_p, devino_t ino, msinum_t msi_num, 1170*09b1eac2SEvan Yan ddi_intr_handle_impl_t *hdlp) 1171*09b1eac2SEvan Yan { 1172*09b1eac2SEvan Yan px_ib_t *ib_p = px_p->px_ib_p; 1173*09b1eac2SEvan Yan px_ino_t *ino_p; 1174*09b1eac2SEvan Yan px_ino_pil_t *ipil_p; 1175*09b1eac2SEvan Yan px_ih_t *ih_p; 1176*09b1eac2SEvan Yan int i; 1177*09b1eac2SEvan Yan 1178*09b1eac2SEvan Yan mutex_enter(&ib_p->ib_ino_lst_mutex); 1179*09b1eac2SEvan Yan 1180*09b1eac2SEvan Yan if ((ino_p = px_ib_locate_ino(ib_p, ino)) == NULL) { 1181*09b1eac2SEvan Yan mutex_exit(&ib_p->ib_ino_lst_mutex); 1182*09b1eac2SEvan Yan return (DDI_FAILURE); 1183*09b1eac2SEvan Yan } 1184*09b1eac2SEvan Yan 1185*09b1eac2SEvan Yan for (ipil_p = ino_p->ino_ipil_p; ipil_p; 1186*09b1eac2SEvan Yan ipil_p = ipil_p->ipil_next_p) { 1187*09b1eac2SEvan Yan for (i = 0, ih_p = ipil_p->ipil_ih_head; 1188*09b1eac2SEvan Yan ((i < ipil_p->ipil_ih_size) && ih_p); 1189*09b1eac2SEvan Yan i++, ih_p = ih_p->ih_next) { 1190*09b1eac2SEvan Yan 1191*09b1eac2SEvan Yan if (ih_p->ih_msg_code != msi_num) 1192*09b1eac2SEvan Yan continue; 1193*09b1eac2SEvan Yan 1194*09b1eac2SEvan Yan hdlp->ih_dip = ih_p->ih_dip; 1195*09b1eac2SEvan Yan hdlp->ih_inum = ih_p->ih_inum; 1196*09b1eac2SEvan Yan hdlp->ih_cb_func = ih_p->ih_handler; 1197*09b1eac2SEvan Yan hdlp->ih_cb_arg1 = ih_p->ih_handler_arg1; 1198*09b1eac2SEvan Yan hdlp->ih_cb_arg2 = ih_p->ih_handler_arg2; 1199*09b1eac2SEvan Yan if (ih_p->ih_rec_type == MSI64_REC) 1200*09b1eac2SEvan Yan hdlp->ih_cap = DDI_INTR_FLAG_MSI64; 1201*09b1eac2SEvan Yan hdlp->ih_pri = ipil_p->ipil_pil; 1202*09b1eac2SEvan Yan hdlp->ih_ver = DDI_INTR_VERSION; 1203*09b1eac2SEvan Yan 1204*09b1eac2SEvan Yan mutex_exit(&ib_p->ib_ino_lst_mutex); 1205*09b1eac2SEvan Yan return (DDI_SUCCESS); 1206*09b1eac2SEvan Yan } 1207*09b1eac2SEvan Yan } 1208*09b1eac2SEvan Yan 1209*09b1eac2SEvan Yan mutex_exit(&ib_p->ib_ino_lst_mutex); 1210*09b1eac2SEvan Yan return (DDI_FAILURE); 1211*09b1eac2SEvan Yan } 1212*09b1eac2SEvan Yan 121344bb982bSgovinda void 1214*09b1eac2SEvan Yan px_ib_log_new_cpu(px_ib_t *ib_p, cpuid_t old_cpu_id, cpuid_t new_cpu_id, 121569cd775fSschwartz uint32_t ino) 121669cd775fSschwartz { 1217b0fc0e77Sgovinda px_ino_t *ino_p; 1218b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 1219b0fc0e77Sgovinda px_ih_t *ih_p; 1220b0fc0e77Sgovinda int i; 122169cd775fSschwartz 122269cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 122369cd775fSschwartz 122469cd775fSschwartz /* Log in OS data structures the new CPU. */ 1225b0fc0e77Sgovinda if (ino_p = px_ib_locate_ino(ib_p, ino)) { 122669cd775fSschwartz 122769cd775fSschwartz /* Log in OS data structures the new CPU. */ 122869cd775fSschwartz ino_p->ino_cpuid = new_cpu_id; 122969cd775fSschwartz 1230b0fc0e77Sgovinda for (ipil_p = ino_p->ino_ipil_p; ipil_p; 1231b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 1232b0fc0e77Sgovinda for (i = 0, ih_p = ipil_p->ipil_ih_head; 1233b0fc0e77Sgovinda (i < ipil_p->ipil_ih_size); 1234b0fc0e77Sgovinda i++, ih_p = ih_p->ih_next) { 1235b0fc0e77Sgovinda /* 1236b0fc0e77Sgovinda * Account for any residual time 1237b0fc0e77Sgovinda * to be logged for old cpu. 1238b0fc0e77Sgovinda */ 1239b0fc0e77Sgovinda px_ib_cpu_ticks_to_ih_nsec(ib_p, 1240b0fc0e77Sgovinda ih_p, old_cpu_id); 1241b0fc0e77Sgovinda } 1242b0fc0e77Sgovinda } 124369cd775fSschwartz } 124469cd775fSschwartz 124569cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 124669cd775fSschwartz } 1247