10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51617Sgovinda * Common Development and Distribution License (the "License"). 61617Sgovinda * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221617Sgovinda * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * PX Interrupt Block implementation 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/kmem.h> 340Sstevel@tonic-gate #include <sys/async.h> 350Sstevel@tonic-gate #include <sys/systm.h> /* panicstr */ 360Sstevel@tonic-gate #include <sys/spl.h> 370Sstevel@tonic-gate #include <sys/sunddi.h> 380Sstevel@tonic-gate #include <sys/machsystm.h> /* intr_dist_add */ 390Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 400Sstevel@tonic-gate #include <sys/cpuvar.h> 410Sstevel@tonic-gate #include "px_obj.h" 420Sstevel@tonic-gate 430Sstevel@tonic-gate /*LINTLIBRARY*/ 440Sstevel@tonic-gate 450Sstevel@tonic-gate static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight); 46624Sschwartz static void px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, 47624Sschwartz uint32_t cpu_id); 480Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg); 49624Sschwartz static void px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 50624Sschwartz char *path_name, int instance); 510Sstevel@tonic-gate 520Sstevel@tonic-gate int 530Sstevel@tonic-gate px_ib_attach(px_t *px_p) 540Sstevel@tonic-gate { 550Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 560Sstevel@tonic-gate px_ib_t *ib_p; 570Sstevel@tonic-gate sysino_t sysino; 580Sstevel@tonic-gate px_fault_t *fault_p = &px_p->px_fault; 590Sstevel@tonic-gate 600Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_attach\n"); 610Sstevel@tonic-gate 620Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, 6327Sjchu px_p->px_inos[PX_INTR_PEC], &sysino) != DDI_SUCCESS) 640Sstevel@tonic-gate return (DDI_FAILURE); 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Allocate interrupt block state structure and link it to 680Sstevel@tonic-gate * the px state structure. 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 710Sstevel@tonic-gate px_p->px_ib_p = ib_p; 720Sstevel@tonic-gate ib_p->ib_px_p = px_p; 730Sstevel@tonic-gate ib_p->ib_ino_lst = (px_ib_ino_info_t *)NULL; 740Sstevel@tonic-gate 750Sstevel@tonic-gate mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 760Sstevel@tonic-gate mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 770Sstevel@tonic-gate 780Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 790Sstevel@tonic-gate 800Sstevel@tonic-gate intr_dist_add_weighted(px_ib_intr_redist, ib_p); 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * Initialize PEC fault data structure 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate fault_p->px_fh_dip = dip; 860Sstevel@tonic-gate fault_p->px_fh_sysino = sysino; 8727Sjchu fault_p->px_err_func = px_err_dmc_pec_intr; 8827Sjchu fault_p->px_intr_ino = px_p->px_inos[PX_INTR_PEC]; 890Sstevel@tonic-gate 900Sstevel@tonic-gate return (DDI_SUCCESS); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate void 940Sstevel@tonic-gate px_ib_detach(px_t *px_p) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 970Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 980Sstevel@tonic-gate 990Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_detach\n"); 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 1020Sstevel@tonic-gate intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate mutex_destroy(&ib_p->ib_ino_lst_mutex); 1050Sstevel@tonic-gate mutex_destroy(&ib_p->ib_intr_lock); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate px_ib_free_ino_all(ib_p); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate px_p->px_ib_p = NULL; 1100Sstevel@tonic-gate kmem_free(ib_p, sizeof (px_ib_t)); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate void 1140Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 1150Sstevel@tonic-gate { 1160Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 1170Sstevel@tonic-gate sysino_t sysino; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Determine the cpu for the interrupt 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1250Sstevel@tonic-gate "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 1280Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1290Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1300Sstevel@tonic-gate "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1330Sstevel@tonic-gate return; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 137693Sgovinda px_lib_intr_setstate(px_p->px_dip, sysino, INTR_IDLE_STATE); 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate /*ARGSUSED*/ 1430Sstevel@tonic-gate void 1440Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 1450Sstevel@tonic-gate { 1460Sstevel@tonic-gate sysino_t sysino; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* Disable the interrupt */ 1530Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 1540Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1550Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, 1560Sstevel@tonic-gate "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1590Sstevel@tonic-gate return; 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate 168624Sschwartz void 1690Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 1700Sstevel@tonic-gate boolean_t wait_flag) 1710Sstevel@tonic-gate { 1720Sstevel@tonic-gate uint32_t old_cpu_id; 1730Sstevel@tonic-gate sysino_t sysino; 1740Sstevel@tonic-gate intr_valid_state_t enabled = 0; 1750Sstevel@tonic-gate hrtime_t start_time; 1760Sstevel@tonic-gate intr_state_t intr_state; 17727Sjchu int e = DDI_SUCCESS; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 1820Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 1830Sstevel@tonic-gate "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 1840Sstevel@tonic-gate return; 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* Skip enabling disabled interrupts */ 1880Sstevel@tonic-gate if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 1890Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 1900Sstevel@tonic-gate "failed, sysino 0x%x\n", sysino); 1910Sstevel@tonic-gate return; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate if (!enabled) 1940Sstevel@tonic-gate return; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* Done if redistributed onto the same cpuid */ 1970Sstevel@tonic-gate if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 1980Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 1990Sstevel@tonic-gate "px_intr_gettarget() failed\n"); 2000Sstevel@tonic-gate return; 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate if (cpu_id == old_cpu_id) 2030Sstevel@tonic-gate return; 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate if (!wait_flag) 2060Sstevel@tonic-gate goto done; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* Busy wait on pending interrupts */ 2090Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 2120Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 2130Sstevel@tonic-gate DDI_SUCCESS) && 2140Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 2150Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 2160Sstevel@tonic-gate cmn_err(CE_WARN, 217671Skrishnae "%s%d: px_ib_intr_dist_en: sysino 0x%lx(ino 0x%x) " 2180Sstevel@tonic-gate "from cpu id 0x%x to 0x%x timeout", 2190Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2200Sstevel@tonic-gate sysino, ino, old_cpu_id, cpu_id); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate e = DDI_FAILURE; 2230Sstevel@tonic-gate break; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate if (e != DDI_SUCCESS) 2280Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 2290Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate done: 2320Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, cpu_id); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 235624Sschwartz static void 236624Sschwartz px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, uint32_t cpu_id) 237624Sschwartz { 238624Sschwartz extern kmutex_t pxintr_ks_template_lock; 239624Sschwartz hrtime_t ticks; 240624Sschwartz 241624Sschwartz /* 242624Sschwartz * Because we are updating two fields in ih_t we must lock 243624Sschwartz * pxintr_ks_template_lock to prevent someone from reading the 244624Sschwartz * kstats after we set ih_ticks to 0 and before we increment 245624Sschwartz * ih_nsec to compensate. 246624Sschwartz * 247624Sschwartz * We must also protect against the interrupt arriving and incrementing 248624Sschwartz * ih_ticks between the time we read it and when we reset it to 0. 249624Sschwartz * To do this we use atomic_swap. 250624Sschwartz */ 251624Sschwartz 252624Sschwartz ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 253624Sschwartz 254624Sschwartz mutex_enter(&pxintr_ks_template_lock); 255624Sschwartz ticks = atomic_swap_64(&ih_p->ih_ticks, 0); 256624Sschwartz ih_p->ih_nsec += (uint64_t)tick2ns(ticks, cpu_id); 257624Sschwartz mutex_exit(&pxintr_ks_template_lock); 258624Sschwartz } 259624Sschwartz 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* 2620Sstevel@tonic-gate * Redistribute interrupts of the specified weight. The first call has a weight 2630Sstevel@tonic-gate * of weight_max, which can be used to trigger initialization for 2640Sstevel@tonic-gate * redistribution. The inos with weight [weight_max, inf.) should be processed 2650Sstevel@tonic-gate * on the "weight == weight_max" call. This first call is followed by calls 2660Sstevel@tonic-gate * of decreasing weights, inos of that weight should be processed. The final 2670Sstevel@tonic-gate * call specifies a weight of zero, this can be used to trigger processing of 2680Sstevel@tonic-gate * stragglers. 2690Sstevel@tonic-gate */ 2700Sstevel@tonic-gate static void 2710Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 2720Sstevel@tonic-gate { 2730Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 2740Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 2750Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 2760Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 2770Sstevel@tonic-gate px_ih_t *ih_lst; 2780Sstevel@tonic-gate int32_t dweight = 0; 2790Sstevel@tonic-gate int i; 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /* Redistribute internal interrupts */ 2820Sstevel@tonic-gate if (weight == 0) { 283*1648Sjchu mutex_enter(&ib_p->ib_intr_lock); 284*1648Sjchu px_ib_intr_dist_en(dip, intr_dist_cpuid(), 285*1648Sjchu px_p->px_inos[PX_INTR_PEC], B_FALSE); 286*1648Sjchu mutex_exit(&ib_p->ib_intr_lock); 28727Sjchu 288*1648Sjchu px_cb_intr_redist(px_p); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* Redistribute device interrupts */ 2920Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) { 2950Sstevel@tonic-gate uint32_t orig_cpuid; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 2990Sstevel@tonic-gate * share the same ino upon first call marked by 3000Sstevel@tonic-gate * (weight == weight_max). 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate if (weight == weight_max) { 3030Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 3040Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3050Sstevel@tonic-gate i < ino_p->ino_ih_size; 3060Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3070Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3080Sstevel@tonic-gate if (dweight > 0) 3090Sstevel@tonic-gate ino_p->ino_intr_weight += dweight; 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate /* 3140Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 3150Sstevel@tonic-gate * nexus redistributes device interrupts and updates 3160Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 3170Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 3180Sstevel@tonic-gate * attention demanding device gains more cpu attention by 3190Sstevel@tonic-gate * making itself heavy. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 3220Sstevel@tonic-gate ((weight >= weight_max) && 3230Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 3240Sstevel@tonic-gate orig_cpuid = ino_p->ino_cpuid; 3250Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 3260Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* select cpuid to target and mark ino established */ 3290Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 3320Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3330Sstevel@tonic-gate i < ino_p->ino_ih_size; 3340Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3370Sstevel@tonic-gate intr_dist_cpuid_add_device_weight( 3380Sstevel@tonic-gate ino_p->ino_cpuid, ih_lst->ih_dip, dweight); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate /* 341624Sschwartz * Different cpus may have different clock 3420Sstevel@tonic-gate * speeds. to account for this, whenever an 3430Sstevel@tonic-gate * interrupt is moved to a new CPU, we 3440Sstevel@tonic-gate * convert the accumulated ticks into nsec, 3450Sstevel@tonic-gate * based upon the clock rate of the prior 3460Sstevel@tonic-gate * CPU. 3470Sstevel@tonic-gate * 3480Sstevel@tonic-gate * It is possible that the prior CPU no longer 3490Sstevel@tonic-gate * exists. In this case, fall back to using 3500Sstevel@tonic-gate * this CPU's clock rate. 3510Sstevel@tonic-gate * 3520Sstevel@tonic-gate * Note that the value in ih_ticks has already 3530Sstevel@tonic-gate * been corrected for any power savings mode 3540Sstevel@tonic-gate * which might have been in effect. 3550Sstevel@tonic-gate */ 356624Sschwartz px_ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst, 357624Sschwartz orig_cpuid); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 3610Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 3620Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 3700Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 3710Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 3720Sstevel@tonic-gate * 3730Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 3740Sstevel@tonic-gate * are permanently suspended. 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate static uint_t 3770Sstevel@tonic-gate px_ib_intr_reset(void *arg) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 3840Sstevel@tonic-gate return (BF_FATAL); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate return (BF_NONE); 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * Locate ino_info structure on ib_p->ib_ino_lst according to ino# 3910Sstevel@tonic-gate * returns NULL if not found. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate px_ib_ino_info_t * 3940Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 3950Sstevel@tonic-gate { 3960Sstevel@tonic-gate px_ib_ino_info_t *ino_p = ib_p->ib_ino_lst; 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate return (ino_p); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate px_ib_ino_info_t * 4060Sstevel@tonic-gate px_ib_new_ino(px_ib_t *ib_p, devino_t ino_num, px_ih_t *ih_p) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate px_ib_ino_info_t *ino_p = kmem_alloc(sizeof (px_ib_ino_info_t), 4090Sstevel@tonic-gate KM_SLEEP); 4100Sstevel@tonic-gate sysino_t sysino; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate ino_p->ino_ino = ino_num; 4130Sstevel@tonic-gate ino_p->ino_ib_p = ib_p; 4140Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino_p->ino_ino, 4170Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4180Sstevel@tonic-gate return (NULL); 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate ino_p->ino_sysino = sysino; 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * Cannot disable interrupt since we might share slot 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate ih_p->ih_next = ih_p; 4260Sstevel@tonic-gate ino_p->ino_ih_head = ih_p; 4270Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 4280Sstevel@tonic-gate ino_p->ino_ih_start = ih_p; 4290Sstevel@tonic-gate ino_p->ino_ih_size = 1; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate ino_p->ino_next = ib_p->ib_ino_lst; 4320Sstevel@tonic-gate ib_p->ib_ino_lst = ino_p; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate return (ino_p); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * The ino_p is retrieved by previous call to px_ib_locate_ino(). 4390Sstevel@tonic-gate */ 4400Sstevel@tonic-gate void 4410Sstevel@tonic-gate px_ib_delete_ino(px_ib_t *ib_p, px_ib_ino_info_t *ino_p) 4420Sstevel@tonic-gate { 4430Sstevel@tonic-gate px_ib_ino_info_t *list = ib_p->ib_ino_lst; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (list == ino_p) 4480Sstevel@tonic-gate ib_p->ib_ino_lst = list->ino_next; 4490Sstevel@tonic-gate else { 4500Sstevel@tonic-gate for (; list->ino_next != ino_p; list = list->ino_next); 4510Sstevel@tonic-gate list->ino_next = ino_p->ino_next; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * Free all ino when we are detaching. 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate void 4590Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 4600Sstevel@tonic-gate { 4610Sstevel@tonic-gate px_ib_ino_info_t *tmp = ib_p->ib_ino_lst; 4620Sstevel@tonic-gate px_ib_ino_info_t *next = NULL; 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate while (tmp) { 4650Sstevel@tonic-gate next = tmp->ino_next; 4660Sstevel@tonic-gate kmem_free(tmp, sizeof (px_ib_ino_info_t)); 4670Sstevel@tonic-gate tmp = next; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate int 4720Sstevel@tonic-gate px_ib_ino_add_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 4730Sstevel@tonic-gate { 4740Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 4750Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 4760Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 4770Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 4780Sstevel@tonic-gate cpuid_t curr_cpu; 4790Sstevel@tonic-gate hrtime_t start_time; 4800Sstevel@tonic-gate intr_state_t intr_state; 4810Sstevel@tonic-gate int ret = DDI_SUCCESS; 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4840Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* Disable the interrupt */ 4890Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 4900Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 4910Sstevel@tonic-gate DBG(DBG_IB, dip, 4920Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate return (ret); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5000Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5010Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5020Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5030Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5040Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 505671Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 5060Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5070Sstevel@tonic-gate sysino, ino); 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate ret = DDI_FAILURE; 5100Sstevel@tonic-gate break; 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 5150Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 5160Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate return (ret); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /* Link up px_ispec_t portion of the ppd */ 5220Sstevel@tonic-gate ih_p->ih_next = ino_p->ino_ih_head; 5230Sstevel@tonic-gate ino_p->ino_ih_tail->ih_next = ih_p; 5240Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 5270Sstevel@tonic-gate ino_p->ino_ih_size++; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /* 5300Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 5310Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 5320Sstevel@tonic-gate * jabber has gone away. 5330Sstevel@tonic-gate */ 5340Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 5350Sstevel@tonic-gate cmn_err(CE_WARN, 5360Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 5370Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 5400Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 5410Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 5420Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 5430Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_setstate failed\n"); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate return (ret); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate /* Re-enable interrupt */ 5500Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate return (ret); 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate /* 5560Sstevel@tonic-gate * Removes px_ispec_t from the ino's link list. 5570Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 5580Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 5590Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 5600Sstevel@tonic-gate * to turn it back on. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate int 5630Sstevel@tonic-gate px_ib_ino_rem_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 5640Sstevel@tonic-gate { 5650Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 5660Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 5670Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 5680Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 5690Sstevel@tonic-gate hrtime_t start_time; 5700Sstevel@tonic-gate intr_state_t intr_state; 5710Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 5760Sstevel@tonic-gate ino_p->ino_ino); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* Disable the interrupt */ 5790Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate if (ino_p->ino_ih_size == 1) { 5820Sstevel@tonic-gate if (ih_lst != ih_p) 5830Sstevel@tonic-gate goto not_found; 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 5860Sstevel@tonic-gate goto reset; 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5900Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5910Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5920Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5930Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5940Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 595671Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 5960Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5970Sstevel@tonic-gate sysino, ino); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate ret = DDI_FAILURE; 6000Sstevel@tonic-gate break; 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6050Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 6060Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate return (ret); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* 6120Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6130Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6140Sstevel@tonic-gate * jabber has gone away. 6150Sstevel@tonic-gate */ 6160Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 6170Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 6180Sstevel@tonic-gate "ino 0x%x has been unblocked", 6190Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 6220Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 6230Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 6240Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 6250Sstevel@tonic-gate "px_ib_ino_rem_intr px_intr_setstate failed\n"); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate return (ret); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* Search the link list for ih_p */ 6320Sstevel@tonic-gate for (i = 0; (i < ino_p->ino_ih_size) && 6330Sstevel@tonic-gate (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 6360Sstevel@tonic-gate goto not_found; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 6390Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate if (ino_p->ino_ih_head == ih_p) 6420Sstevel@tonic-gate ino_p->ino_ih_head = ih_p->ih_next; 6430Sstevel@tonic-gate if (ino_p->ino_ih_tail == ih_p) 6440Sstevel@tonic-gate ino_p->ino_ih_tail = ih_lst; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate reset: 6490Sstevel@tonic-gate if (ih_p->ih_config_handle) 6500Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 6510Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 6520Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 6550Sstevel@tonic-gate ino_p->ino_ih_size--; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate return (ret); 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate not_found: 6600Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 6610Sstevel@tonic-gate "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate return (DDI_FAILURE); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate px_ih_t * 6670Sstevel@tonic-gate px_ib_ino_locate_intr(px_ib_ino_info_t *ino_p, dev_info_t *rdip, 6680Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 6690Sstevel@tonic-gate { 6700Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 6710Sstevel@tonic-gate int i; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_lst = ih_lst->ih_next) { 6740Sstevel@tonic-gate if ((ih_lst->ih_dip == rdip) && (ih_lst->ih_inum == inum) && 6750Sstevel@tonic-gate (ih_lst->ih_rec_type == rec_type) && 6760Sstevel@tonic-gate (ih_lst->ih_msg_code == msg_code)) 6770Sstevel@tonic-gate return (ih_lst); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate return ((px_ih_t *)NULL); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate px_ih_t * 6840Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 6850Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 6860Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 6870Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 6880Sstevel@tonic-gate { 6890Sstevel@tonic-gate px_ih_t *ih_p; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 6920Sstevel@tonic-gate ih_p->ih_dip = rdip; 6930Sstevel@tonic-gate ih_p->ih_inum = inum; 6940Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 6950Sstevel@tonic-gate ih_p->ih_handler = int_handler; 6960Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 6970Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 6980Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 6990Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 7000Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 7010Sstevel@tonic-gate ih_p->ih_nsec = 0; 7020Sstevel@tonic-gate ih_p->ih_ticks = 0; 7030Sstevel@tonic-gate ih_p->ih_ksp = NULL; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate return (ih_p); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate int 7090Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 710909Segillett uint_t inum, devino_t ino, uint_t new_intr_state, 711909Segillett msiq_rec_type_t rec_type, msgcode_t msg_code) 7120Sstevel@tonic-gate { 7130Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 7140Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 7150Sstevel@tonic-gate px_ih_t *ih_p; 7160Sstevel@tonic-gate int ret = DDI_FAILURE; 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "ib_update_intr_state: %s%d " 7190Sstevel@tonic-gate "inum %x devino %x state %x\n", ddi_driver_name(rdip), 7200Sstevel@tonic-gate ddi_get_instance(rdip), inum, ino, new_intr_state); 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { 725909Segillett if (ih_p = px_ib_ino_locate_intr(ino_p, rdip, inum, rec_type, 726909Segillett msg_code)) { 7270Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 7280Sstevel@tonic-gate ret = DDI_SUCCESS; 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 7330Sstevel@tonic-gate return (ret); 7340Sstevel@tonic-gate } 735624Sschwartz 736624Sschwartz 737624Sschwartz static void 738624Sschwartz px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 739624Sschwartz char *path_name, int instance) 740624Sschwartz { 741624Sschwartz (void) strncpy(dev->driver_name, driver_name, MAXMODCONFNAME-1); 742624Sschwartz dev->driver_name[MAXMODCONFNAME] = '\0'; 743624Sschwartz (void) strncpy(dev->path, path_name, MAXPATHLEN-1); 744624Sschwartz dev->dev_inst = instance; 745624Sschwartz } 746624Sschwartz 747624Sschwartz 748624Sschwartz /* 749624Sschwartz * Return the dips or number of dips associated with a given interrupt block. 750624Sschwartz * Size of dips array arg is passed in as dips_ret arg. 751624Sschwartz * Number of dips returned is returned in dips_ret arg. 752624Sschwartz * Array of dips gets returned in the dips argument. 753624Sschwartz * Function returns number of dips existing for the given interrupt block. 754624Sschwartz * 755624Sschwartz * Note: this function assumes an enabled/valid INO, which is why it returns 756624Sschwartz * the px node and (Internal) when it finds no other devices (and *devs_ret > 0) 757624Sschwartz */ 758624Sschwartz uint8_t 759624Sschwartz pxtool_ib_get_ino_devs( 760624Sschwartz px_t *px_p, uint32_t ino, uint8_t *devs_ret, pcitool_intr_dev_t *devs) 761624Sschwartz { 762624Sschwartz px_ib_t *ib_p = px_p->px_ib_p; 763624Sschwartz px_ib_ino_info_t *ino_p; 764624Sschwartz px_ih_t *ih_p; 765624Sschwartz uint32_t num_devs = 0; 766624Sschwartz char pathname[MAXPATHLEN]; 767624Sschwartz int i; 768624Sschwartz 769624Sschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 770624Sschwartz ino_p = px_ib_locate_ino(ib_p, ino); 771624Sschwartz if (ino_p != NULL) { 772624Sschwartz num_devs = ino_p->ino_ih_size; 773624Sschwartz for (i = 0, ih_p = ino_p->ino_ih_head; 774624Sschwartz ((i < ino_p->ino_ih_size) && (i < *devs_ret)); 775624Sschwartz i++, ih_p = ih_p->ih_next) { 776624Sschwartz (void) ddi_pathname(ih_p->ih_dip, pathname); 777624Sschwartz px_fill_in_intr_devs(&devs[i], 778624Sschwartz (char *)ddi_driver_name(ih_p->ih_dip), pathname, 779624Sschwartz ddi_get_instance(ih_p->ih_dip)); 780624Sschwartz } 781624Sschwartz *devs_ret = i; 782624Sschwartz 783624Sschwartz } else if (*devs_ret > 0) { 784624Sschwartz (void) ddi_pathname(px_p->px_dip, pathname); 785624Sschwartz strcat(pathname, " (Internal)"); 786624Sschwartz px_fill_in_intr_devs(&devs[0], 787624Sschwartz (char *)ddi_driver_name(px_p->px_dip), pathname, 788624Sschwartz ddi_get_instance(px_p->px_dip)); 789624Sschwartz num_devs = *devs_ret = 1; 790624Sschwartz } 791624Sschwartz 792624Sschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 793624Sschwartz 794624Sschwartz return (num_devs); 795624Sschwartz } 796624Sschwartz 797624Sschwartz 7981617Sgovinda void 7991617Sgovinda px_ib_log_new_cpu(px_ib_t *ib_p, uint32_t old_cpu_id, uint32_t new_cpu_id, 800624Sschwartz uint32_t ino) 801624Sschwartz { 802624Sschwartz px_ib_ino_info_t *ino_p; 803624Sschwartz 804624Sschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 805624Sschwartz 806624Sschwartz /* Log in OS data structures the new CPU. */ 807624Sschwartz ino_p = px_ib_locate_ino(ib_p, ino); 808624Sschwartz if (ino_p != NULL) { 809624Sschwartz 810624Sschwartz /* Log in OS data structures the new CPU. */ 811624Sschwartz ino_p->ino_cpuid = new_cpu_id; 812624Sschwartz 813624Sschwartz /* Account for any residual time to be logged for old cpu. */ 814624Sschwartz px_ib_cpu_ticks_to_ih_nsec(ib_p, ino_p->ino_ih_head, 815624Sschwartz old_cpu_id); 816624Sschwartz } 817624Sschwartz 818624Sschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 819624Sschwartz } 820