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 /* 2244bb982bSgovinda * Copyright 2006 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> 41*25cf1a30Sjl #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 53*25cf1a30Sjl extern uint64_t xc_tick_jump_limit; 54*25cf1a30Sjl 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; 767c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = (px_ib_ino_info_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; 178*25cf1a30Sjl hrtime_t start_time, prev, curr, interval, jump; 179*25cf1a30Sjl 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 215*25cf1a30Sjl intr_timeout = px_intrpend_timeout; 216*25cf1a30Sjl jump = TICK_TO_NSEC(xc_tick_jump_limit); 217*25cf1a30Sjl 218*25cf1a30Sjl for (curr = start_time = gethrtime(); !panicstr && 2197c478bd9Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 2207c478bd9Sstevel@tonic-gate DDI_SUCCESS) && 2217c478bd9Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 222*25cf1a30Sjl /* 223*25cf1a30Sjl * If we have a really large jump in hrtime, it is most 224*25cf1a30Sjl * probably because we entered the debugger (or OBP, 225*25cf1a30Sjl * in general). So, we adjust the timeout accordingly 226*25cf1a30Sjl * to prevent declaring an interrupt timeout. The 227*25cf1a30Sjl * master-interrupt mechanism in OBP should deliver 228*25cf1a30Sjl * the interrupts properly. 229*25cf1a30Sjl */ 230*25cf1a30Sjl prev = curr; 231*25cf1a30Sjl curr = gethrtime(); 232*25cf1a30Sjl interval = curr - prev; 233*25cf1a30Sjl if (interval > jump) 234*25cf1a30Sjl intr_timeout += interval; 235*25cf1a30Sjl 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; 2967c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 2977c478bd9Sstevel@tonic-gate px_ih_t *ih_lst; 2987c478bd9Sstevel@tonic-gate int32_t dweight = 0; 2997c478bd9Sstevel@tonic-gate int i; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* Redistribute internal interrupts */ 3027c478bd9Sstevel@tonic-gate if (weight == 0) { 3037c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 30401689544Sjchu px_ib_intr_dist_en(dip, intr_dist_cpuid(), 30501689544Sjchu px_p->px_inos[PX_INTR_PEC], B_FALSE); 3067c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 30701689544Sjchu 30801689544Sjchu px_cb_intr_redist(px_p); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* Redistribute device interrupts */ 3127c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) { 3157c478bd9Sstevel@tonic-gate uint32_t orig_cpuid; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 3197c478bd9Sstevel@tonic-gate * share the same ino upon first call marked by 3207c478bd9Sstevel@tonic-gate * (weight == weight_max). 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate if (weight == weight_max) { 3237c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 3247c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3257c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 3267c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3277c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3287c478bd9Sstevel@tonic-gate if (dweight > 0) 3297c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight += dweight; 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 3357c478bd9Sstevel@tonic-gate * nexus redistributes device interrupts and updates 3367c478bd9Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 3377c478bd9Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 3387c478bd9Sstevel@tonic-gate * attention demanding device gains more cpu attention by 3397c478bd9Sstevel@tonic-gate * making itself heavy. 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 3427c478bd9Sstevel@tonic-gate ((weight >= weight_max) && 3437c478bd9Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 3447c478bd9Sstevel@tonic-gate orig_cpuid = ino_p->ino_cpuid; 3457c478bd9Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 3467c478bd9Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* select cpuid to target and mark ino established */ 3497c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 3527c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3537c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 3547c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3577c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight( 3587c478bd9Sstevel@tonic-gate ino_p->ino_cpuid, ih_lst->ih_dip, dweight); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 36169cd775fSschwartz * Different cpus may have different clock 3627c478bd9Sstevel@tonic-gate * speeds. to account for this, whenever an 3637c478bd9Sstevel@tonic-gate * interrupt is moved to a new CPU, we 3647c478bd9Sstevel@tonic-gate * convert the accumulated ticks into nsec, 3657c478bd9Sstevel@tonic-gate * based upon the clock rate of the prior 3667c478bd9Sstevel@tonic-gate * CPU. 3677c478bd9Sstevel@tonic-gate * 3687c478bd9Sstevel@tonic-gate * It is possible that the prior CPU no longer 3697c478bd9Sstevel@tonic-gate * exists. In this case, fall back to using 3707c478bd9Sstevel@tonic-gate * this CPU's clock rate. 3717c478bd9Sstevel@tonic-gate * 3727c478bd9Sstevel@tonic-gate * Note that the value in ih_ticks has already 3737c478bd9Sstevel@tonic-gate * been corrected for any power savings mode 3747c478bd9Sstevel@tonic-gate * which might have been in effect. 3757c478bd9Sstevel@tonic-gate */ 37669cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst, 37769cd775fSschwartz orig_cpuid); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 3817c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 3827c478bd9Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 3907c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 3917c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 3927c478bd9Sstevel@tonic-gate * 3937c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 3947c478bd9Sstevel@tonic-gate * are permanently suspended. 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate static uint_t 3977c478bd9Sstevel@tonic-gate px_ib_intr_reset(void *arg) 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 4047c478bd9Sstevel@tonic-gate return (BF_FATAL); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate return (BF_NONE); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Locate ino_info structure on ib_p->ib_ino_lst according to ino# 4117c478bd9Sstevel@tonic-gate * returns NULL if not found. 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 4147c478bd9Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = ib_p->ib_ino_lst; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate return (ino_p); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 4267c478bd9Sstevel@tonic-gate px_ib_new_ino(px_ib_t *ib_p, devino_t ino_num, px_ih_t *ih_p) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = kmem_alloc(sizeof (px_ib_ino_info_t), 4297c478bd9Sstevel@tonic-gate KM_SLEEP); 4307c478bd9Sstevel@tonic-gate sysino_t sysino; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate ino_p->ino_ino = ino_num; 4337c478bd9Sstevel@tonic-gate ino_p->ino_ib_p = ib_p; 4347c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino_p->ino_ino, 4377c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4387c478bd9Sstevel@tonic-gate return (NULL); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate ino_p->ino_sysino = sysino; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * Cannot disable interrupt since we might share slot 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate ih_p->ih_next = ih_p; 4467c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p; 4477c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 4487c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ih_p; 4497c478bd9Sstevel@tonic-gate ino_p->ino_ih_size = 1; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate ino_p->ino_next = ib_p->ib_ino_lst; 4527c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = ino_p; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate return (ino_p); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * The ino_p is retrieved by previous call to px_ib_locate_ino(). 4597c478bd9Sstevel@tonic-gate */ 4607c478bd9Sstevel@tonic-gate void 4617c478bd9Sstevel@tonic-gate px_ib_delete_ino(px_ib_t *ib_p, px_ib_ino_info_t *ino_p) 4627c478bd9Sstevel@tonic-gate { 4637c478bd9Sstevel@tonic-gate px_ib_ino_info_t *list = ib_p->ib_ino_lst; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (list == ino_p) 4687c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = list->ino_next; 4697c478bd9Sstevel@tonic-gate else { 4707c478bd9Sstevel@tonic-gate for (; list->ino_next != ino_p; list = list->ino_next); 4717c478bd9Sstevel@tonic-gate list->ino_next = ino_p->ino_next; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * Free all ino when we are detaching. 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate void 4797c478bd9Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate px_ib_ino_info_t *tmp = ib_p->ib_ino_lst; 4827c478bd9Sstevel@tonic-gate px_ib_ino_info_t *next = NULL; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate while (tmp) { 4857c478bd9Sstevel@tonic-gate next = tmp->ino_next; 4867c478bd9Sstevel@tonic-gate kmem_free(tmp, sizeof (px_ib_ino_info_t)); 4877c478bd9Sstevel@tonic-gate tmp = next; 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate int 4927c478bd9Sstevel@tonic-gate px_ib_ino_add_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 4957c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 4967c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 4977c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 4987c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 4997c478bd9Sstevel@tonic-gate hrtime_t start_time; 5007c478bd9Sstevel@tonic-gate intr_state_t intr_state; 5017c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 5047c478bd9Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 5097c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 5107c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 5117c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, 5127c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate return (ret); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5207c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5217c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5227c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5237c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5247c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 525b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 5267c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5277c478bd9Sstevel@tonic-gate sysino, ino); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 5307c478bd9Sstevel@tonic-gate break; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 5357c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 5367c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate return (ret); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* Link up px_ispec_t portion of the ppd */ 5427c478bd9Sstevel@tonic-gate ih_p->ih_next = ino_p->ino_ih_head; 5437c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail->ih_next = ih_p; 5447c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 5477c478bd9Sstevel@tonic-gate ino_p->ino_ih_size++; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 5517c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 5527c478bd9Sstevel@tonic-gate * jabber has gone away. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 5557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5567c478bd9Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 5577c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 5607c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 5617c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 5627c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 5637c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_setstate failed\n"); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate return (ret); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* Re-enable interrupt */ 5707c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate return (ret); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Removes px_ispec_t from the ino's link list. 5777c478bd9Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 5787c478bd9Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 5797c478bd9Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 5807c478bd9Sstevel@tonic-gate * to turn it back on. 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate int 5837c478bd9Sstevel@tonic-gate px_ib_ino_rem_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 5847c478bd9Sstevel@tonic-gate { 5857c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 5867c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 5877c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 5887c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 5897c478bd9Sstevel@tonic-gate hrtime_t start_time; 5907c478bd9Sstevel@tonic-gate intr_state_t intr_state; 5917c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 5967c478bd9Sstevel@tonic-gate ino_p->ino_ino); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 5997c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_size == 1) { 6027c478bd9Sstevel@tonic-gate if (ih_lst != ih_p) 6037c478bd9Sstevel@tonic-gate goto not_found; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 6067c478bd9Sstevel@tonic-gate goto reset; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 6107c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 6117c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 6127c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 6137c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 6147c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 615b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 6167c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 6177c478bd9Sstevel@tonic-gate sysino, ino); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 6207c478bd9Sstevel@tonic-gate break; 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6257c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 6267c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate return (ret); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6337c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6347c478bd9Sstevel@tonic-gate * jabber has gone away. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 6377c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 6387c478bd9Sstevel@tonic-gate "ino 0x%x has been unblocked", 6397c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 6427c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 6437c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 6447c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 6457c478bd9Sstevel@tonic-gate "px_ib_ino_rem_intr px_intr_setstate failed\n"); 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate return (ret); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* Search the link list for ih_p */ 6527c478bd9Sstevel@tonic-gate for (i = 0; (i < ino_p->ino_ih_size) && 6537c478bd9Sstevel@tonic-gate (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next); 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 6567c478bd9Sstevel@tonic-gate goto not_found; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 6597c478bd9Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_head == ih_p) 6627c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p->ih_next; 6637c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_tail == ih_p) 6647c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_lst; 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate reset: 6697c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 6707c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 6717c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 6727c478bd9Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 6757c478bd9Sstevel@tonic-gate ino_p->ino_ih_size--; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate return (ret); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate not_found: 6807c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 6817c478bd9Sstevel@tonic-gate "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate px_ih_t * 6877c478bd9Sstevel@tonic-gate px_ib_ino_locate_intr(px_ib_ino_info_t *ino_p, dev_info_t *rdip, 6887c478bd9Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 6917c478bd9Sstevel@tonic-gate int i; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_lst = ih_lst->ih_next) { 6947c478bd9Sstevel@tonic-gate if ((ih_lst->ih_dip == rdip) && (ih_lst->ih_inum == inum) && 6957c478bd9Sstevel@tonic-gate (ih_lst->ih_rec_type == rec_type) && 6967c478bd9Sstevel@tonic-gate (ih_lst->ih_msg_code == msg_code)) 6977c478bd9Sstevel@tonic-gate return (ih_lst); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate return ((px_ih_t *)NULL); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate px_ih_t * 7047c478bd9Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 7057c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 7067c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 7077c478bd9Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 7127c478bd9Sstevel@tonic-gate ih_p->ih_dip = rdip; 7137c478bd9Sstevel@tonic-gate ih_p->ih_inum = inum; 7147c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 7157c478bd9Sstevel@tonic-gate ih_p->ih_handler = int_handler; 7167c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 7177c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 7187c478bd9Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 7197c478bd9Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 7207c478bd9Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 7217c478bd9Sstevel@tonic-gate ih_p->ih_nsec = 0; 7227c478bd9Sstevel@tonic-gate ih_p->ih_ticks = 0; 7237c478bd9Sstevel@tonic-gate ih_p->ih_ksp = NULL; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate return (ih_p); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate int 7297c478bd9Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 73036fe4a92Segillett uint_t inum, devino_t ino, uint_t new_intr_state, 73136fe4a92Segillett msiq_rec_type_t rec_type, msgcode_t msg_code) 7327c478bd9Sstevel@tonic-gate { 7337c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 7347c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 7357c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 7367c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "ib_update_intr_state: %s%d " 7397c478bd9Sstevel@tonic-gate "inum %x devino %x state %x\n", ddi_driver_name(rdip), 7407c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), inum, ino, new_intr_state); 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { 74536fe4a92Segillett if (ih_p = px_ib_ino_locate_intr(ino_p, rdip, inum, rec_type, 74636fe4a92Segillett msg_code)) { 7477c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 7487c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 7537c478bd9Sstevel@tonic-gate return (ret); 7547c478bd9Sstevel@tonic-gate } 75569cd775fSschwartz 75669cd775fSschwartz 75769cd775fSschwartz static void 75869cd775fSschwartz px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 75969cd775fSschwartz char *path_name, int instance) 76069cd775fSschwartz { 76169cd775fSschwartz (void) strncpy(dev->driver_name, driver_name, MAXMODCONFNAME-1); 76269cd775fSschwartz dev->driver_name[MAXMODCONFNAME] = '\0'; 76369cd775fSschwartz (void) strncpy(dev->path, path_name, MAXPATHLEN-1); 76469cd775fSschwartz dev->dev_inst = instance; 76569cd775fSschwartz } 76669cd775fSschwartz 76769cd775fSschwartz 76869cd775fSschwartz /* 76969cd775fSschwartz * Return the dips or number of dips associated with a given interrupt block. 77069cd775fSschwartz * Size of dips array arg is passed in as dips_ret arg. 77169cd775fSschwartz * Number of dips returned is returned in dips_ret arg. 77269cd775fSschwartz * Array of dips gets returned in the dips argument. 77369cd775fSschwartz * Function returns number of dips existing for the given interrupt block. 77469cd775fSschwartz * 77569cd775fSschwartz * Note: this function assumes an enabled/valid INO, which is why it returns 77669cd775fSschwartz * the px node and (Internal) when it finds no other devices (and *devs_ret > 0) 77769cd775fSschwartz */ 77869cd775fSschwartz uint8_t 77969cd775fSschwartz pxtool_ib_get_ino_devs( 78069cd775fSschwartz px_t *px_p, uint32_t ino, uint8_t *devs_ret, pcitool_intr_dev_t *devs) 78169cd775fSschwartz { 78269cd775fSschwartz px_ib_t *ib_p = px_p->px_ib_p; 78369cd775fSschwartz px_ib_ino_info_t *ino_p; 78469cd775fSschwartz px_ih_t *ih_p; 78569cd775fSschwartz uint32_t num_devs = 0; 78669cd775fSschwartz char pathname[MAXPATHLEN]; 78769cd775fSschwartz int i; 78869cd775fSschwartz 78969cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 79069cd775fSschwartz ino_p = px_ib_locate_ino(ib_p, ino); 79169cd775fSschwartz if (ino_p != NULL) { 79269cd775fSschwartz num_devs = ino_p->ino_ih_size; 79369cd775fSschwartz for (i = 0, ih_p = ino_p->ino_ih_head; 79469cd775fSschwartz ((i < ino_p->ino_ih_size) && (i < *devs_ret)); 79569cd775fSschwartz i++, ih_p = ih_p->ih_next) { 79669cd775fSschwartz (void) ddi_pathname(ih_p->ih_dip, pathname); 79769cd775fSschwartz px_fill_in_intr_devs(&devs[i], 79869cd775fSschwartz (char *)ddi_driver_name(ih_p->ih_dip), pathname, 79969cd775fSschwartz ddi_get_instance(ih_p->ih_dip)); 80069cd775fSschwartz } 80169cd775fSschwartz *devs_ret = i; 80269cd775fSschwartz 80369cd775fSschwartz } else if (*devs_ret > 0) { 80469cd775fSschwartz (void) ddi_pathname(px_p->px_dip, pathname); 80569cd775fSschwartz strcat(pathname, " (Internal)"); 80669cd775fSschwartz px_fill_in_intr_devs(&devs[0], 80769cd775fSschwartz (char *)ddi_driver_name(px_p->px_dip), pathname, 80869cd775fSschwartz ddi_get_instance(px_p->px_dip)); 80969cd775fSschwartz num_devs = *devs_ret = 1; 81069cd775fSschwartz } 81169cd775fSschwartz 81269cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 81369cd775fSschwartz 81469cd775fSschwartz return (num_devs); 81569cd775fSschwartz } 81669cd775fSschwartz 81769cd775fSschwartz 81844bb982bSgovinda void 81944bb982bSgovinda px_ib_log_new_cpu(px_ib_t *ib_p, uint32_t old_cpu_id, uint32_t new_cpu_id, 82069cd775fSschwartz uint32_t ino) 82169cd775fSschwartz { 82269cd775fSschwartz px_ib_ino_info_t *ino_p; 82369cd775fSschwartz 82469cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 82569cd775fSschwartz 82669cd775fSschwartz /* Log in OS data structures the new CPU. */ 82769cd775fSschwartz ino_p = px_ib_locate_ino(ib_p, ino); 82869cd775fSschwartz if (ino_p != NULL) { 82969cd775fSschwartz 83069cd775fSschwartz /* Log in OS data structures the new CPU. */ 83169cd775fSschwartz ino_p->ino_cpuid = new_cpu_id; 83269cd775fSschwartz 83369cd775fSschwartz /* Account for any residual time to be logged for old cpu. */ 83469cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(ib_p, ino_p->ino_ih_head, 83569cd775fSschwartz old_cpu_id); 83669cd775fSschwartz } 83769cd775fSschwartz 83869cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 83969cd775fSschwartz } 840