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*e4517573Srameshc * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * PX Interrupt Block implementation 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/systm.h> /* panicstr */ 367c478bd9Sstevel@tonic-gate #include <sys/spl.h> 377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 387c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* intr_dist_add */ 397c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 407c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 4125cf1a30Sjl #include <sys/time.h> 427c478bd9Sstevel@tonic-gate #include "px_obj.h" 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight); 4769cd775fSschwartz static void px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, 4869cd775fSschwartz uint32_t cpu_id); 497c478bd9Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg); 5069cd775fSschwartz static void px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 5169cd775fSschwartz char *path_name, int instance); 527c478bd9Sstevel@tonic-gate 5325cf1a30Sjl extern uint64_t xc_tick_jump_limit; 5425cf1a30Sjl 557c478bd9Sstevel@tonic-gate int 567c478bd9Sstevel@tonic-gate px_ib_attach(px_t *px_p) 577c478bd9Sstevel@tonic-gate { 587c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 597c478bd9Sstevel@tonic-gate px_ib_t *ib_p; 607c478bd9Sstevel@tonic-gate sysino_t sysino; 617c478bd9Sstevel@tonic-gate px_fault_t *fault_p = &px_p->px_fault; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_attach\n"); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, 66f8d2de6bSjchu px_p->px_inos[PX_INTR_PEC], &sysino) != DDI_SUCCESS) 677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * Allocate interrupt block state structure and link it to 717c478bd9Sstevel@tonic-gate * the px state structure. 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 747c478bd9Sstevel@tonic-gate px_p->px_ib_p = ib_p; 757c478bd9Sstevel@tonic-gate ib_p->ib_px_p = px_p; 76b0fc0e77Sgovinda ib_p->ib_ino_lst = (px_ino_t *)NULL; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 797c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate intr_dist_add_weighted(px_ib_intr_redist, ib_p); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate * Initialize PEC fault data structure 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate fault_p->px_fh_dip = dip; 897c478bd9Sstevel@tonic-gate fault_p->px_fh_sysino = sysino; 90f8d2de6bSjchu fault_p->px_err_func = px_err_dmc_pec_intr; 91f8d2de6bSjchu fault_p->px_intr_ino = px_p->px_inos[PX_INTR_PEC]; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate void 977c478bd9Sstevel@tonic-gate px_ib_detach(px_t *px_p) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 1007c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_detach\n"); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 1057c478bd9Sstevel@tonic-gate intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_ino_lst_mutex); 1087c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_intr_lock); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate px_ib_free_ino_all(ib_p); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate px_p->px_ib_p = NULL; 1137c478bd9Sstevel@tonic-gate kmem_free(ib_p, sizeof (px_ib_t)); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate void 1177c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 1207c478bd9Sstevel@tonic-gate sysino_t sysino; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate /* 1237c478bd9Sstevel@tonic-gate * Determine the cpu for the interrupt 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1287c478bd9Sstevel@tonic-gate "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 1317c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1327c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1337c478bd9Sstevel@tonic-gate "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1367c478bd9Sstevel@tonic-gate return; 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 140a195726fSgovinda px_lib_intr_setstate(px_p->px_dip, sysino, INTR_IDLE_STATE); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1467c478bd9Sstevel@tonic-gate void 1477c478bd9Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 1487c478bd9Sstevel@tonic-gate { 1497c478bd9Sstevel@tonic-gate sysino_t sysino; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 1567c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 1577c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1587c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, 1597c478bd9Sstevel@tonic-gate "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1627c478bd9Sstevel@tonic-gate return; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate 17169cd775fSschwartz void 1727c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 1737c478bd9Sstevel@tonic-gate boolean_t wait_flag) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate uint32_t old_cpu_id; 1767c478bd9Sstevel@tonic-gate sysino_t sysino; 1777c478bd9Sstevel@tonic-gate intr_valid_state_t enabled = 0; 17825cf1a30Sjl hrtime_t start_time, prev, curr, interval, jump; 17925cf1a30Sjl hrtime_t intr_timeout; 1807c478bd9Sstevel@tonic-gate intr_state_t intr_state; 181f8d2de6bSjchu int e = DDI_SUCCESS; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 1867c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 1877c478bd9Sstevel@tonic-gate "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 1887c478bd9Sstevel@tonic-gate return; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* Skip enabling disabled interrupts */ 1927c478bd9Sstevel@tonic-gate if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 1937c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 1947c478bd9Sstevel@tonic-gate "failed, sysino 0x%x\n", sysino); 1957c478bd9Sstevel@tonic-gate return; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate if (!enabled) 1987c478bd9Sstevel@tonic-gate return; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* Done if redistributed onto the same cpuid */ 2017c478bd9Sstevel@tonic-gate if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 2027c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 2037c478bd9Sstevel@tonic-gate "px_intr_gettarget() failed\n"); 2047c478bd9Sstevel@tonic-gate return; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate if (cpu_id == old_cpu_id) 2077c478bd9Sstevel@tonic-gate return; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (!wait_flag) 2107c478bd9Sstevel@tonic-gate goto done; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupts */ 2137c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 2147c478bd9Sstevel@tonic-gate 21525cf1a30Sjl intr_timeout = px_intrpend_timeout; 21625cf1a30Sjl jump = TICK_TO_NSEC(xc_tick_jump_limit); 21725cf1a30Sjl 21825cf1a30Sjl for (curr = start_time = gethrtime(); !panicstr && 2197c478bd9Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 220f0d69850Srameshc DDI_SUCCESS) && 2217c478bd9Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 22225cf1a30Sjl /* 22325cf1a30Sjl * If we have a really large jump in hrtime, it is most 22425cf1a30Sjl * probably because we entered the debugger (or OBP, 22525cf1a30Sjl * in general). So, we adjust the timeout accordingly 22625cf1a30Sjl * to prevent declaring an interrupt timeout. The 22725cf1a30Sjl * master-interrupt mechanism in OBP should deliver 22825cf1a30Sjl * the interrupts properly. 22925cf1a30Sjl */ 23025cf1a30Sjl prev = curr; 23125cf1a30Sjl curr = gethrtime(); 23225cf1a30Sjl interval = curr - prev; 23325cf1a30Sjl if (interval > jump) 23425cf1a30Sjl intr_timeout += interval; 23525cf1a30Sjl if (curr - start_time > intr_timeout) { 2367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 237b40cec45Skrishnae "%s%d: px_ib_intr_dist_en: sysino 0x%lx(ino 0x%x) " 2387c478bd9Sstevel@tonic-gate "from cpu id 0x%x to 0x%x timeout", 2397c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2407c478bd9Sstevel@tonic-gate sysino, ino, old_cpu_id, cpu_id); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate e = DDI_FAILURE; 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate if (e != DDI_SUCCESS) 2487c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 2497c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate done: 2527c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, cpu_id); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 25569cd775fSschwartz static void 25669cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, uint32_t cpu_id) 25769cd775fSschwartz { 25869cd775fSschwartz extern kmutex_t pxintr_ks_template_lock; 25969cd775fSschwartz hrtime_t ticks; 26069cd775fSschwartz 26169cd775fSschwartz /* 26269cd775fSschwartz * Because we are updating two fields in ih_t we must lock 26369cd775fSschwartz * pxintr_ks_template_lock to prevent someone from reading the 26469cd775fSschwartz * kstats after we set ih_ticks to 0 and before we increment 26569cd775fSschwartz * ih_nsec to compensate. 26669cd775fSschwartz * 26769cd775fSschwartz * We must also protect against the interrupt arriving and incrementing 26869cd775fSschwartz * ih_ticks between the time we read it and when we reset it to 0. 26969cd775fSschwartz * To do this we use atomic_swap. 27069cd775fSschwartz */ 27169cd775fSschwartz 27269cd775fSschwartz ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 27369cd775fSschwartz 27469cd775fSschwartz mutex_enter(&pxintr_ks_template_lock); 27569cd775fSschwartz ticks = atomic_swap_64(&ih_p->ih_ticks, 0); 27669cd775fSschwartz ih_p->ih_nsec += (uint64_t)tick2ns(ticks, cpu_id); 27769cd775fSschwartz mutex_exit(&pxintr_ks_template_lock); 27869cd775fSschwartz } 27969cd775fSschwartz 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * Redistribute interrupts of the specified weight. The first call has a weight 2837c478bd9Sstevel@tonic-gate * of weight_max, which can be used to trigger initialization for 2847c478bd9Sstevel@tonic-gate * redistribution. The inos with weight [weight_max, inf.) should be processed 2857c478bd9Sstevel@tonic-gate * on the "weight == weight_max" call. This first call is followed by calls 2867c478bd9Sstevel@tonic-gate * of decreasing weights, inos of that weight should be processed. The final 2877c478bd9Sstevel@tonic-gate * call specifies a weight of zero, this can be used to trigger processing of 2887c478bd9Sstevel@tonic-gate * stragglers. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate static void 2917c478bd9Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 2947c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 2957c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 296b0fc0e77Sgovinda px_ino_t *ino_p; 297b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 2987c478bd9Sstevel@tonic-gate px_ih_t *ih_lst; 2997c478bd9Sstevel@tonic-gate int32_t dweight = 0; 3007c478bd9Sstevel@tonic-gate int i; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* Redistribute internal interrupts */ 3037c478bd9Sstevel@tonic-gate if (weight == 0) { 3047c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 30501689544Sjchu px_ib_intr_dist_en(dip, intr_dist_cpuid(), 30601689544Sjchu px_p->px_inos[PX_INTR_PEC], B_FALSE); 3077c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 308ab4471cdSscarter 309ab4471cdSscarter px_hp_intr_redist(px_p); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* Redistribute device interrupts */ 3137c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 3147c478bd9Sstevel@tonic-gate 315b0fc0e77Sgovinda for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next_p) { 3167c478bd9Sstevel@tonic-gate uint32_t orig_cpuid; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 3207c478bd9Sstevel@tonic-gate * share the same ino upon first call marked by 3217c478bd9Sstevel@tonic-gate * (weight == weight_max). 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate if (weight == weight_max) { 3247c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 325b0fc0e77Sgovinda 326b0fc0e77Sgovinda for (ipil_p = ino_p->ino_ipil_p; ipil_p; 327b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 328b0fc0e77Sgovinda for (i = 0, ih_lst = ipil_p->ipil_ih_head; 329b0fc0e77Sgovinda i < ipil_p->ipil_ih_size; i++, 330b0fc0e77Sgovinda ih_lst = ih_lst->ih_next) { 331b0fc0e77Sgovinda dweight = i_ddi_get_intr_weight( 332b0fc0e77Sgovinda ih_lst->ih_dip); 333b0fc0e77Sgovinda if (dweight > 0) 334b0fc0e77Sgovinda ino_p->ino_intr_weight += 335b0fc0e77Sgovinda dweight; 336b0fc0e77Sgovinda } 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 3427c478bd9Sstevel@tonic-gate * nexus redistributes device interrupts and updates 3437c478bd9Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 3447c478bd9Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 3457c478bd9Sstevel@tonic-gate * attention demanding device gains more cpu attention by 3467c478bd9Sstevel@tonic-gate * making itself heavy. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 3497c478bd9Sstevel@tonic-gate ((weight >= weight_max) && 3507c478bd9Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 3517c478bd9Sstevel@tonic-gate orig_cpuid = ino_p->ino_cpuid; 3527c478bd9Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 3537c478bd9Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* select cpuid to target and mark ino established */ 3567c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 359b0fc0e77Sgovinda for (ipil_p = ino_p->ino_ipil_p; ipil_p; 360b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 361b0fc0e77Sgovinda for (i = 0, ih_lst = ipil_p->ipil_ih_head; 362b0fc0e77Sgovinda i < ipil_p->ipil_ih_size; i++, 363b0fc0e77Sgovinda ih_lst = ih_lst->ih_next) { 364b0fc0e77Sgovinda 365b0fc0e77Sgovinda dweight = i_ddi_get_intr_weight( 366b0fc0e77Sgovinda ih_lst->ih_dip); 367b0fc0e77Sgovinda intr_dist_cpuid_add_device_weight( 368b0fc0e77Sgovinda ino_p->ino_cpuid, ih_lst->ih_dip, 369b0fc0e77Sgovinda dweight); 370b0fc0e77Sgovinda 371b0fc0e77Sgovinda /* 372b0fc0e77Sgovinda * Different cpus may have different 373b0fc0e77Sgovinda * clock speeds. to account for this, 374b0fc0e77Sgovinda * whenever an interrupt is moved to a 375b0fc0e77Sgovinda * new CPU, we convert the accumulated 376b0fc0e77Sgovinda * ticks into nsec, based upon the clock 377b0fc0e77Sgovinda * rate of the prior CPU. 378b0fc0e77Sgovinda * 379b0fc0e77Sgovinda * It is possible that the prior CPU no 380b0fc0e77Sgovinda * longer exists. In this case, fall 381b0fc0e77Sgovinda * back to using this CPU's clock rate. 382b0fc0e77Sgovinda * 383b0fc0e77Sgovinda * Note that the value in ih_ticks has 384b0fc0e77Sgovinda * already been corrected for any power 385b0fc0e77Sgovinda * savings mode which might have been 386b0fc0e77Sgovinda * in effect. 387b0fc0e77Sgovinda */ 388b0fc0e77Sgovinda px_ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst, 389b0fc0e77Sgovinda orig_cpuid); 390b0fc0e77Sgovinda } 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 3947c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 3957c478bd9Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 4037c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 4047c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 4057c478bd9Sstevel@tonic-gate * 4067c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 4077c478bd9Sstevel@tonic-gate * are permanently suspended. 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate static uint_t 4107c478bd9Sstevel@tonic-gate px_ib_intr_reset(void *arg) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 4177c478bd9Sstevel@tonic-gate return (BF_FATAL); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate return (BF_NONE); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 423b0fc0e77Sgovinda * Locate px_ino_t structure on ib_p->ib_ino_lst according to ino# 4247c478bd9Sstevel@tonic-gate * returns NULL if not found. 4257c478bd9Sstevel@tonic-gate */ 426b0fc0e77Sgovinda px_ino_t * 4277c478bd9Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 4287c478bd9Sstevel@tonic-gate { 429b0fc0e77Sgovinda px_ino_t *ino_p = ib_p->ib_ino_lst; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4327c478bd9Sstevel@tonic-gate 433f0d69850Srameshc for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next_p) 434f0d69850Srameshc ; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate return (ino_p); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 439b0fc0e77Sgovinda px_ino_pil_t * 440b0fc0e77Sgovinda px_ib_new_ino_pil(px_ib_t *ib_p, devino_t ino_num, uint_t pil, px_ih_t *ih_p) 4417c478bd9Sstevel@tonic-gate { 442b0fc0e77Sgovinda px_ino_pil_t *ipil_p = kmem_zalloc(sizeof (px_ino_pil_t), KM_SLEEP); 443b0fc0e77Sgovinda px_ino_t *ino_p; 4447c478bd9Sstevel@tonic-gate 445b0fc0e77Sgovinda if ((ino_p = px_ib_locate_ino(ib_p, ino_num)) == NULL) { 446b0fc0e77Sgovinda sysino_t sysino; 4477c478bd9Sstevel@tonic-gate 448b0fc0e77Sgovinda if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, 449b0fc0e77Sgovinda ino_num, &sysino) != DDI_SUCCESS) 450b0fc0e77Sgovinda return (NULL); 4517c478bd9Sstevel@tonic-gate 452b0fc0e77Sgovinda ino_p = kmem_zalloc(sizeof (px_ino_t), KM_SLEEP); 453b0fc0e77Sgovinda 454b0fc0e77Sgovinda ino_p->ino_next_p = ib_p->ib_ino_lst; 455b0fc0e77Sgovinda ib_p->ib_ino_lst = ino_p; 456b0fc0e77Sgovinda 457b0fc0e77Sgovinda ino_p->ino_ino = ino_num; 458b0fc0e77Sgovinda ino_p->ino_sysino = sysino; 459b0fc0e77Sgovinda ino_p->ino_ib_p = ib_p; 460b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 461b0fc0e77Sgovinda ino_p->ino_lopil = pil; 462b0fc0e77Sgovinda } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate ih_p->ih_next = ih_p; 465b0fc0e77Sgovinda ipil_p->ipil_pil = pil; 466b0fc0e77Sgovinda ipil_p->ipil_ih_head = ih_p; 467b0fc0e77Sgovinda ipil_p->ipil_ih_tail = ih_p; 468b0fc0e77Sgovinda ipil_p->ipil_ih_start = ih_p; 469b0fc0e77Sgovinda ipil_p->ipil_ih_size = 1; 470b0fc0e77Sgovinda ipil_p->ipil_ino_p = ino_p; 4717c478bd9Sstevel@tonic-gate 472b0fc0e77Sgovinda ipil_p->ipil_next_p = ino_p->ino_ipil_p; 473b0fc0e77Sgovinda ino_p->ino_ipil_p = ipil_p; 474b0fc0e77Sgovinda ino_p->ino_ipil_size++; 4757c478bd9Sstevel@tonic-gate 476b0fc0e77Sgovinda if (ino_p->ino_lopil > pil) 477b0fc0e77Sgovinda ino_p->ino_lopil = pil; 478b0fc0e77Sgovinda 479b0fc0e77Sgovinda return (ipil_p); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate void 483b0fc0e77Sgovinda px_ib_delete_ino_pil(px_ib_t *ib_p, px_ino_pil_t *ipil_p) 4847c478bd9Sstevel@tonic-gate { 485b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 486b0fc0e77Sgovinda ushort_t pil = ipil_p->ipil_pil; 487b0fc0e77Sgovinda px_ino_pil_t *prev, *next; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4907c478bd9Sstevel@tonic-gate 491b0fc0e77Sgovinda if (ino_p->ino_ipil_p == ipil_p) 492b0fc0e77Sgovinda ino_p->ino_ipil_p = ipil_p->ipil_next_p; 493b0fc0e77Sgovinda else { 494b0fc0e77Sgovinda for (prev = next = ino_p->ino_ipil_p; next != ipil_p; 495f0d69850Srameshc prev = next, next = next->ipil_next_p) 496f0d69850Srameshc ; 497b0fc0e77Sgovinda 498b0fc0e77Sgovinda if (prev) 499b0fc0e77Sgovinda prev->ipil_next_p = ipil_p->ipil_next_p; 500b0fc0e77Sgovinda } 501b0fc0e77Sgovinda 502b0fc0e77Sgovinda kmem_free(ipil_p, sizeof (px_ino_pil_t)); 503b0fc0e77Sgovinda 504*e4517573Srameshc if ((--ino_p->ino_ipil_size) && (ino_p->ino_lopil == pil)) { 505*e4517573Srameshc for (next = ino_p->ino_ipil_p, pil = next->ipil_pil; 506*e4517573Srameshc next; next = next->ipil_next_p) { 507*e4517573Srameshc 508b0fc0e77Sgovinda if (pil > next->ipil_pil) 509b0fc0e77Sgovinda pil = next->ipil_pil; 510b0fc0e77Sgovinda } 511*e4517573Srameshc /* 512*e4517573Srameshc * Value stored in pil should be the lowest pil. 513*e4517573Srameshc */ 514b0fc0e77Sgovinda ino_p->ino_lopil = pil; 515b0fc0e77Sgovinda } 516b0fc0e77Sgovinda 517*e4517573Srameshc if (ino_p->ino_ipil_size) 518b0fc0e77Sgovinda return; 519b0fc0e77Sgovinda 520b0fc0e77Sgovinda if (ib_p->ib_ino_lst == ino_p) 521b0fc0e77Sgovinda ib_p->ib_ino_lst = ino_p->ino_next_p; 5227c478bd9Sstevel@tonic-gate else { 523b0fc0e77Sgovinda px_ino_t *list = ib_p->ib_ino_lst; 524b0fc0e77Sgovinda 525f0d69850Srameshc for (; list->ino_next_p != ino_p; list = list->ino_next_p) 526f0d69850Srameshc ; 527b0fc0e77Sgovinda list->ino_next_p = ino_p->ino_next_p; 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Free all ino when we are detaching. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate void 5357c478bd9Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 5367c478bd9Sstevel@tonic-gate { 537b0fc0e77Sgovinda px_ino_t *ino_p = ib_p->ib_ino_lst; 538b0fc0e77Sgovinda px_ino_t *next = NULL; 5397c478bd9Sstevel@tonic-gate 540b0fc0e77Sgovinda while (ino_p) { 541b0fc0e77Sgovinda next = ino_p->ino_next_p; 542b0fc0e77Sgovinda kmem_free(ino_p, sizeof (px_ino_t)); 543b0fc0e77Sgovinda ino_p = next; 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 547b0fc0e77Sgovinda /* 548b0fc0e77Sgovinda * Locate px_ino_pil_t structure on ino_p->ino_ipil_p according to ino# 549b0fc0e77Sgovinda * returns NULL if not found. 550b0fc0e77Sgovinda */ 551b0fc0e77Sgovinda px_ino_pil_t * 552b0fc0e77Sgovinda px_ib_ino_locate_ipil(px_ino_t *ino_p, uint_t pil) 553b0fc0e77Sgovinda { 554b0fc0e77Sgovinda px_ino_pil_t *ipil_p = ino_p->ino_ipil_p; 555b0fc0e77Sgovinda 556f0d69850Srameshc for (; ipil_p && ipil_p->ipil_pil != pil; ipil_p = ipil_p->ipil_next_p) 557f0d69850Srameshc ; 558b0fc0e77Sgovinda 559b0fc0e77Sgovinda return (ipil_p); 560b0fc0e77Sgovinda } 561b0fc0e77Sgovinda 5627c478bd9Sstevel@tonic-gate int 563b0fc0e77Sgovinda px_ib_ino_add_intr(px_t *px_p, px_ino_pil_t *ipil_p, px_ih_t *ih_p) 5647c478bd9Sstevel@tonic-gate { 565b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 5667c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 5677c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 5687c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 5697c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 5707c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 5717c478bd9Sstevel@tonic-gate hrtime_t start_time; 5727c478bd9Sstevel@tonic-gate intr_state_t intr_state; 5737c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 5767c478bd9Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 5817c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 5827c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 5837c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, 5847c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate return (ret); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5927c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5937c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5947c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5957c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5967c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 597b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 5987c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5997c478bd9Sstevel@tonic-gate sysino, ino); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 6027c478bd9Sstevel@tonic-gate break; 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* 6077c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6087c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6097c478bd9Sstevel@tonic-gate * jabber has gone away. 6107c478bd9Sstevel@tonic-gate */ 611b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) { 6127c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6137c478bd9Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 6147c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 6157c478bd9Sstevel@tonic-gate 616b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 617b0fc0e77Sgovinda ret = px_lib_intr_setstate(dip, sysino, INTR_IDLE_STATE); 618b0fc0e77Sgovinda } 619b0fc0e77Sgovinda 620b0fc0e77Sgovinda if (ret != DDI_SUCCESS) { 621b0fc0e77Sgovinda DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 622b0fc0e77Sgovinda "ino 0x%x sysino 0x%x\n", ino, sysino); 6237c478bd9Sstevel@tonic-gate 624b0fc0e77Sgovinda return (ret); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 627b0fc0e77Sgovinda /* Link up px_ih_t */ 628b0fc0e77Sgovinda ih_p->ih_next = ipil_p->ipil_ih_head; 629b0fc0e77Sgovinda ipil_p->ipil_ih_tail->ih_next = ih_p; 630b0fc0e77Sgovinda ipil_p->ipil_ih_tail = ih_p; 631b0fc0e77Sgovinda 632b0fc0e77Sgovinda ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; 633b0fc0e77Sgovinda ipil_p->ipil_ih_size++; 634b0fc0e77Sgovinda 6357c478bd9Sstevel@tonic-gate /* Re-enable interrupt */ 6367c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate return (ret); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 642b0fc0e77Sgovinda * Removes px_ih_t from the ino's link list. 6437c478bd9Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 6447c478bd9Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 6457c478bd9Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 6467c478bd9Sstevel@tonic-gate * to turn it back on. 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate int 649b0fc0e77Sgovinda px_ib_ino_rem_intr(px_t *px_p, px_ino_pil_t *ipil_p, px_ih_t *ih_p) 6507c478bd9Sstevel@tonic-gate { 651b0fc0e77Sgovinda px_ino_t *ino_p = ipil_p->ipil_ino_p; 6527c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 6537c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 6547c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 655b0fc0e77Sgovinda px_ih_t *ih_lst = ipil_p->ipil_ih_head; 6567c478bd9Sstevel@tonic-gate hrtime_t start_time; 6577c478bd9Sstevel@tonic-gate intr_state_t intr_state; 6587c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 6637c478bd9Sstevel@tonic-gate ino_p->ino_ino); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 6667c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 6677c478bd9Sstevel@tonic-gate 668b0fc0e77Sgovinda if (ipil_p->ipil_ih_size == 1) { 6697c478bd9Sstevel@tonic-gate if (ih_lst != ih_p) 6707c478bd9Sstevel@tonic-gate goto not_found; 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 6737c478bd9Sstevel@tonic-gate goto reset; 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 6777c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 6787c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 6797c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 6807c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 6817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 682b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 6837c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 6847c478bd9Sstevel@tonic-gate sysino, ino); 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 6877c478bd9Sstevel@tonic-gate break; 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6937c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6947c478bd9Sstevel@tonic-gate * jabber has gone away. 6957c478bd9Sstevel@tonic-gate */ 696b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) { 6977c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 6987c478bd9Sstevel@tonic-gate "ino 0x%x has been unblocked", 6997c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 7007c478bd9Sstevel@tonic-gate 701b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0; 702b0fc0e77Sgovinda ret = px_lib_intr_setstate(dip, sysino, INTR_IDLE_STATE); 703b0fc0e77Sgovinda } 7047c478bd9Sstevel@tonic-gate 705b0fc0e77Sgovinda if (ret != DDI_SUCCESS) { 706b0fc0e77Sgovinda DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 707b0fc0e77Sgovinda "ino 0x%x sysino 0x%x\n", ino, sysino); 708b0fc0e77Sgovinda 709b0fc0e77Sgovinda return (ret); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* Search the link list for ih_p */ 713b0fc0e77Sgovinda for (i = 0; (i < ipil_p->ipil_ih_size) && 714f0d69850Srameshc (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next) 715f0d69850Srameshc ; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 7187c478bd9Sstevel@tonic-gate goto not_found; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 7217c478bd9Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 7227c478bd9Sstevel@tonic-gate 723b0fc0e77Sgovinda if (ipil_p->ipil_ih_head == ih_p) 724b0fc0e77Sgovinda ipil_p->ipil_ih_head = ih_p->ih_next; 725b0fc0e77Sgovinda if (ipil_p->ipil_ih_tail == ih_p) 726b0fc0e77Sgovinda ipil_p->ipil_ih_tail = ih_lst; 7277c478bd9Sstevel@tonic-gate 728b0fc0e77Sgovinda ipil_p->ipil_ih_start = ipil_p->ipil_ih_head; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate reset: 7317c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 7327c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 7337c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 7347c478bd9Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 737b0fc0e77Sgovinda ipil_p->ipil_ih_size--; 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate return (ret); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate not_found: 7427c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 743f0d69850Srameshc "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate px_ih_t * 749b0fc0e77Sgovinda px_ib_intr_locate_ih(px_ino_pil_t *ipil_p, dev_info_t *rdip, 7507c478bd9Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 7517c478bd9Sstevel@tonic-gate { 752b0fc0e77Sgovinda px_ih_t *ih_p = ipil_p->ipil_ih_head; 7537c478bd9Sstevel@tonic-gate int i; 7547c478bd9Sstevel@tonic-gate 755b0fc0e77Sgovinda for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 756b0fc0e77Sgovinda if ((ih_p->ih_dip == rdip) && (ih_p->ih_inum == inum) && 757b0fc0e77Sgovinda (ih_p->ih_rec_type == rec_type) && 758b0fc0e77Sgovinda (ih_p->ih_msg_code == msg_code)) 759b0fc0e77Sgovinda return (ih_p); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate return ((px_ih_t *)NULL); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate px_ih_t * 7667c478bd9Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 7677c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 7687c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 7697c478bd9Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 7707c478bd9Sstevel@tonic-gate { 7717c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 7747c478bd9Sstevel@tonic-gate ih_p->ih_dip = rdip; 7757c478bd9Sstevel@tonic-gate ih_p->ih_inum = inum; 7767c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 7777c478bd9Sstevel@tonic-gate ih_p->ih_handler = int_handler; 7787c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 7797c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 7807c478bd9Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 7817c478bd9Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 7827c478bd9Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 7837c478bd9Sstevel@tonic-gate ih_p->ih_nsec = 0; 7847c478bd9Sstevel@tonic-gate ih_p->ih_ticks = 0; 7857c478bd9Sstevel@tonic-gate ih_p->ih_ksp = NULL; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate return (ih_p); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate int 7917c478bd9Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 792b0fc0e77Sgovinda uint_t inum, devino_t ino, uint_t pil, 793b0fc0e77Sgovinda uint_t new_intr_state, msiq_rec_type_t rec_type, 794b0fc0e77Sgovinda msgcode_t msg_code) 7957c478bd9Sstevel@tonic-gate { 7967c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 797b0fc0e77Sgovinda px_ino_t *ino_p; 798b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 7997c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 8007c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 8017c478bd9Sstevel@tonic-gate 802b0fc0e77Sgovinda DBG(DBG_IB, px_p->px_dip, "px_ib_update_intr_state: %s%d " 803b0fc0e77Sgovinda "inum %x devino %x pil %x state %x\n", ddi_driver_name(rdip), 804b0fc0e77Sgovinda ddi_get_instance(rdip), inum, ino, pil, new_intr_state); 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 8077c478bd9Sstevel@tonic-gate 808b0fc0e77Sgovinda ino_p = px_ib_locate_ino(ib_p, ino); 809b0fc0e77Sgovinda if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, pil))) { 810b0fc0e77Sgovinda if (ih_p = px_ib_intr_locate_ih(ipil_p, rdip, inum, rec_type, 81136fe4a92Segillett msg_code)) { 8127c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 8137c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 8187c478bd9Sstevel@tonic-gate return (ret); 8197c478bd9Sstevel@tonic-gate } 82069cd775fSschwartz 82169cd775fSschwartz 82269cd775fSschwartz static void 82369cd775fSschwartz px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 82469cd775fSschwartz char *path_name, int instance) 82569cd775fSschwartz { 82669cd775fSschwartz (void) strncpy(dev->driver_name, driver_name, MAXMODCONFNAME-1); 82769cd775fSschwartz dev->driver_name[MAXMODCONFNAME] = '\0'; 82869cd775fSschwartz (void) strncpy(dev->path, path_name, MAXPATHLEN-1); 82969cd775fSschwartz dev->dev_inst = instance; 83069cd775fSschwartz } 83169cd775fSschwartz 83269cd775fSschwartz 83369cd775fSschwartz /* 83469cd775fSschwartz * Return the dips or number of dips associated with a given interrupt block. 83569cd775fSschwartz * Size of dips array arg is passed in as dips_ret arg. 83669cd775fSschwartz * Number of dips returned is returned in dips_ret arg. 83769cd775fSschwartz * Array of dips gets returned in the dips argument. 83869cd775fSschwartz * Function returns number of dips existing for the given interrupt block. 83969cd775fSschwartz * 84069cd775fSschwartz * Note: this function assumes an enabled/valid INO, which is why it returns 84169cd775fSschwartz * the px node and (Internal) when it finds no other devices (and *devs_ret > 0) 84269cd775fSschwartz */ 84369cd775fSschwartz uint8_t 84469cd775fSschwartz pxtool_ib_get_ino_devs( 84569cd775fSschwartz px_t *px_p, uint32_t ino, uint8_t *devs_ret, pcitool_intr_dev_t *devs) 84669cd775fSschwartz { 847b0fc0e77Sgovinda px_ib_t *ib_p = px_p->px_ib_p; 848b0fc0e77Sgovinda px_ino_t *ino_p; 849b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 850b0fc0e77Sgovinda px_ih_t *ih_p; 851b0fc0e77Sgovinda uint32_t num_devs = 0; 852b0fc0e77Sgovinda char pathname[MAXPATHLEN]; 853b0fc0e77Sgovinda int i, j; 85469cd775fSschwartz 85569cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 85669cd775fSschwartz ino_p = px_ib_locate_ino(ib_p, ino); 85769cd775fSschwartz if (ino_p != NULL) { 858b0fc0e77Sgovinda for (j = 0, ipil_p = ino_p->ino_ipil_p; ipil_p; 859b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 860b0fc0e77Sgovinda num_devs += ipil_p->ipil_ih_size; 861b0fc0e77Sgovinda 862b0fc0e77Sgovinda for (i = 0, ih_p = ipil_p->ipil_ih_head; 863b0fc0e77Sgovinda ((i < ipil_p->ipil_ih_size) && (i < *devs_ret)); 864b0fc0e77Sgovinda i++, j++, ih_p = ih_p->ih_next) { 865b0fc0e77Sgovinda (void) ddi_pathname(ih_p->ih_dip, pathname); 866b0fc0e77Sgovinda px_fill_in_intr_devs(&devs[i], 867b0fc0e77Sgovinda (char *)ddi_driver_name(ih_p->ih_dip), 868b0fc0e77Sgovinda pathname, ddi_get_instance(ih_p->ih_dip)); 869b0fc0e77Sgovinda } 87069cd775fSschwartz } 87169cd775fSschwartz 872b0fc0e77Sgovinda *devs_ret = j; 87369cd775fSschwartz } else if (*devs_ret > 0) { 87469cd775fSschwartz (void) ddi_pathname(px_p->px_dip, pathname); 87569cd775fSschwartz strcat(pathname, " (Internal)"); 87669cd775fSschwartz px_fill_in_intr_devs(&devs[0], 87769cd775fSschwartz (char *)ddi_driver_name(px_p->px_dip), pathname, 87869cd775fSschwartz ddi_get_instance(px_p->px_dip)); 87969cd775fSschwartz num_devs = *devs_ret = 1; 88069cd775fSschwartz } 88169cd775fSschwartz 88269cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 88369cd775fSschwartz 88469cd775fSschwartz return (num_devs); 88569cd775fSschwartz } 88669cd775fSschwartz 88769cd775fSschwartz 88844bb982bSgovinda void 88944bb982bSgovinda px_ib_log_new_cpu(px_ib_t *ib_p, uint32_t old_cpu_id, uint32_t new_cpu_id, 89069cd775fSschwartz uint32_t ino) 89169cd775fSschwartz { 892b0fc0e77Sgovinda px_ino_t *ino_p; 893b0fc0e77Sgovinda px_ino_pil_t *ipil_p; 894b0fc0e77Sgovinda px_ih_t *ih_p; 895b0fc0e77Sgovinda int i; 89669cd775fSschwartz 89769cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 89869cd775fSschwartz 89969cd775fSschwartz /* Log in OS data structures the new CPU. */ 900b0fc0e77Sgovinda if (ino_p = px_ib_locate_ino(ib_p, ino)) { 90169cd775fSschwartz 90269cd775fSschwartz /* Log in OS data structures the new CPU. */ 90369cd775fSschwartz ino_p->ino_cpuid = new_cpu_id; 90469cd775fSschwartz 905b0fc0e77Sgovinda for (ipil_p = ino_p->ino_ipil_p; ipil_p; 906b0fc0e77Sgovinda ipil_p = ipil_p->ipil_next_p) { 907b0fc0e77Sgovinda for (i = 0, ih_p = ipil_p->ipil_ih_head; 908b0fc0e77Sgovinda (i < ipil_p->ipil_ih_size); 909b0fc0e77Sgovinda i++, ih_p = ih_p->ih_next) { 910b0fc0e77Sgovinda /* 911b0fc0e77Sgovinda * Account for any residual time 912b0fc0e77Sgovinda * to be logged for old cpu. 913b0fc0e77Sgovinda */ 914b0fc0e77Sgovinda px_ib_cpu_ticks_to_ih_nsec(ib_p, 915b0fc0e77Sgovinda ih_p, old_cpu_id); 916b0fc0e77Sgovinda } 917b0fc0e77Sgovinda } 91869cd775fSschwartz } 91969cd775fSschwartz 92069cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 92169cd775fSschwartz } 922