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> 417c478bd9Sstevel@tonic-gate #include "px_obj.h" 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight); 4669cd775fSschwartz static void px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, 4769cd775fSschwartz uint32_t cpu_id); 487c478bd9Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg); 4969cd775fSschwartz static void px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 5069cd775fSschwartz char *path_name, int instance); 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate int 537c478bd9Sstevel@tonic-gate px_ib_attach(px_t *px_p) 547c478bd9Sstevel@tonic-gate { 557c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 567c478bd9Sstevel@tonic-gate px_ib_t *ib_p; 577c478bd9Sstevel@tonic-gate sysino_t sysino; 587c478bd9Sstevel@tonic-gate px_fault_t *fault_p = &px_p->px_fault; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_attach\n"); 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, 63f8d2de6bSjchu px_p->px_inos[PX_INTR_PEC], &sysino) != DDI_SUCCESS) 647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * Allocate interrupt block state structure and link it to 687c478bd9Sstevel@tonic-gate * the px state structure. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 717c478bd9Sstevel@tonic-gate px_p->px_ib_p = ib_p; 727c478bd9Sstevel@tonic-gate ib_p->ib_px_p = px_p; 737c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = (px_ib_ino_info_t *)NULL; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 767c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate intr_dist_add_weighted(px_ib_intr_redist, ib_p); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * Initialize PEC fault data structure 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate fault_p->px_fh_dip = dip; 867c478bd9Sstevel@tonic-gate fault_p->px_fh_sysino = sysino; 87f8d2de6bSjchu fault_p->px_err_func = px_err_dmc_pec_intr; 88f8d2de6bSjchu fault_p->px_intr_ino = px_p->px_inos[PX_INTR_PEC]; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate void 947c478bd9Sstevel@tonic-gate px_ib_detach(px_t *px_p) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 977c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_detach\n"); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 1027c478bd9Sstevel@tonic-gate intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_ino_lst_mutex); 1057c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_intr_lock); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate px_ib_free_ino_all(ib_p); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate px_p->px_ib_p = NULL; 1107c478bd9Sstevel@tonic-gate kmem_free(ib_p, sizeof (px_ib_t)); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate void 1147c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 1177c478bd9Sstevel@tonic-gate sysino_t sysino; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Determine the cpu for the interrupt 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1257c478bd9Sstevel@tonic-gate "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 1287c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1297c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1307c478bd9Sstevel@tonic-gate "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1337c478bd9Sstevel@tonic-gate return; 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 137a195726fSgovinda px_lib_intr_setstate(px_p->px_dip, sysino, INTR_IDLE_STATE); 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1437c478bd9Sstevel@tonic-gate void 1447c478bd9Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate sysino_t sysino; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 1537c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 1547c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1557c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, 1567c478bd9Sstevel@tonic-gate "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1597c478bd9Sstevel@tonic-gate return; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate 16869cd775fSschwartz void 1697c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 1707c478bd9Sstevel@tonic-gate boolean_t wait_flag) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate uint32_t old_cpu_id; 1737c478bd9Sstevel@tonic-gate sysino_t sysino; 1747c478bd9Sstevel@tonic-gate intr_valid_state_t enabled = 0; 1757c478bd9Sstevel@tonic-gate hrtime_t start_time; 1767c478bd9Sstevel@tonic-gate intr_state_t intr_state; 177f8d2de6bSjchu int e = DDI_SUCCESS; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 1827c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 1837c478bd9Sstevel@tonic-gate "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 1847c478bd9Sstevel@tonic-gate return; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* Skip enabling disabled interrupts */ 1887c478bd9Sstevel@tonic-gate if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 1897c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 1907c478bd9Sstevel@tonic-gate "failed, sysino 0x%x\n", sysino); 1917c478bd9Sstevel@tonic-gate return; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate if (!enabled) 1947c478bd9Sstevel@tonic-gate return; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* Done if redistributed onto the same cpuid */ 1977c478bd9Sstevel@tonic-gate if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 1987c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 1997c478bd9Sstevel@tonic-gate "px_intr_gettarget() failed\n"); 2007c478bd9Sstevel@tonic-gate return; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate if (cpu_id == old_cpu_id) 2037c478bd9Sstevel@tonic-gate return; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if (!wait_flag) 2067c478bd9Sstevel@tonic-gate goto done; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupts */ 2097c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 2127c478bd9Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 2137c478bd9Sstevel@tonic-gate DDI_SUCCESS) && 2147c478bd9Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 2157c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 2167c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 217b40cec45Skrishnae "%s%d: px_ib_intr_dist_en: sysino 0x%lx(ino 0x%x) " 2187c478bd9Sstevel@tonic-gate "from cpu id 0x%x to 0x%x timeout", 2197c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2207c478bd9Sstevel@tonic-gate sysino, ino, old_cpu_id, cpu_id); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate e = DDI_FAILURE; 2237c478bd9Sstevel@tonic-gate break; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (e != DDI_SUCCESS) 2287c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 2297c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate done: 2327c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, cpu_id); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 23569cd775fSschwartz static void 23669cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(px_ib_t *ib_p, px_ih_t *ih_p, uint32_t cpu_id) 23769cd775fSschwartz { 23869cd775fSschwartz extern kmutex_t pxintr_ks_template_lock; 23969cd775fSschwartz hrtime_t ticks; 24069cd775fSschwartz 24169cd775fSschwartz /* 24269cd775fSschwartz * Because we are updating two fields in ih_t we must lock 24369cd775fSschwartz * pxintr_ks_template_lock to prevent someone from reading the 24469cd775fSschwartz * kstats after we set ih_ticks to 0 and before we increment 24569cd775fSschwartz * ih_nsec to compensate. 24669cd775fSschwartz * 24769cd775fSschwartz * We must also protect against the interrupt arriving and incrementing 24869cd775fSschwartz * ih_ticks between the time we read it and when we reset it to 0. 24969cd775fSschwartz * To do this we use atomic_swap. 25069cd775fSschwartz */ 25169cd775fSschwartz 25269cd775fSschwartz ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 25369cd775fSschwartz 25469cd775fSschwartz mutex_enter(&pxintr_ks_template_lock); 25569cd775fSschwartz ticks = atomic_swap_64(&ih_p->ih_ticks, 0); 25669cd775fSschwartz ih_p->ih_nsec += (uint64_t)tick2ns(ticks, cpu_id); 25769cd775fSschwartz mutex_exit(&pxintr_ks_template_lock); 25869cd775fSschwartz } 25969cd775fSschwartz 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * Redistribute interrupts of the specified weight. The first call has a weight 2637c478bd9Sstevel@tonic-gate * of weight_max, which can be used to trigger initialization for 2647c478bd9Sstevel@tonic-gate * redistribution. The inos with weight [weight_max, inf.) should be processed 2657c478bd9Sstevel@tonic-gate * on the "weight == weight_max" call. This first call is followed by calls 2667c478bd9Sstevel@tonic-gate * of decreasing weights, inos of that weight should be processed. The final 2677c478bd9Sstevel@tonic-gate * call specifies a weight of zero, this can be used to trigger processing of 2687c478bd9Sstevel@tonic-gate * stragglers. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate static void 2717c478bd9Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 2727c478bd9Sstevel@tonic-gate { 2737c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 2747c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 2757c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 2767c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 2777c478bd9Sstevel@tonic-gate px_ih_t *ih_lst; 2787c478bd9Sstevel@tonic-gate int32_t dweight = 0; 2797c478bd9Sstevel@tonic-gate int i; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* Redistribute internal interrupts */ 2827c478bd9Sstevel@tonic-gate if (weight == 0) { 2837c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 284*01689544Sjchu px_ib_intr_dist_en(dip, intr_dist_cpuid(), 285*01689544Sjchu px_p->px_inos[PX_INTR_PEC], B_FALSE); 2867c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 287*01689544Sjchu 288*01689544Sjchu px_cb_intr_redist(px_p); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* Redistribute device interrupts */ 2927c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) { 2957c478bd9Sstevel@tonic-gate uint32_t orig_cpuid; 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 2997c478bd9Sstevel@tonic-gate * share the same ino upon first call marked by 3007c478bd9Sstevel@tonic-gate * (weight == weight_max). 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate if (weight == weight_max) { 3037c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 3047c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3057c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 3067c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3077c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3087c478bd9Sstevel@tonic-gate if (dweight > 0) 3097c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight += dweight; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 3157c478bd9Sstevel@tonic-gate * nexus redistributes device interrupts and updates 3167c478bd9Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 3177c478bd9Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 3187c478bd9Sstevel@tonic-gate * attention demanding device gains more cpu attention by 3197c478bd9Sstevel@tonic-gate * making itself heavy. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 3227c478bd9Sstevel@tonic-gate ((weight >= weight_max) && 3237c478bd9Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 3247c478bd9Sstevel@tonic-gate orig_cpuid = ino_p->ino_cpuid; 3257c478bd9Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 3267c478bd9Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* select cpuid to target and mark ino established */ 3297c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 3327c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3337c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 3347c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3377c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight( 3387c478bd9Sstevel@tonic-gate ino_p->ino_cpuid, ih_lst->ih_dip, dweight); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 34169cd775fSschwartz * Different cpus may have different clock 3427c478bd9Sstevel@tonic-gate * speeds. to account for this, whenever an 3437c478bd9Sstevel@tonic-gate * interrupt is moved to a new CPU, we 3447c478bd9Sstevel@tonic-gate * convert the accumulated ticks into nsec, 3457c478bd9Sstevel@tonic-gate * based upon the clock rate of the prior 3467c478bd9Sstevel@tonic-gate * CPU. 3477c478bd9Sstevel@tonic-gate * 3487c478bd9Sstevel@tonic-gate * It is possible that the prior CPU no longer 3497c478bd9Sstevel@tonic-gate * exists. In this case, fall back to using 3507c478bd9Sstevel@tonic-gate * this CPU's clock rate. 3517c478bd9Sstevel@tonic-gate * 3527c478bd9Sstevel@tonic-gate * Note that the value in ih_ticks has already 3537c478bd9Sstevel@tonic-gate * been corrected for any power savings mode 3547c478bd9Sstevel@tonic-gate * which might have been in effect. 3557c478bd9Sstevel@tonic-gate */ 35669cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(ib_p, ih_lst, 35769cd775fSschwartz orig_cpuid); 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 3617c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 3627c478bd9Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 3707c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 3717c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 3727c478bd9Sstevel@tonic-gate * 3737c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 3747c478bd9Sstevel@tonic-gate * are permanently suspended. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate static uint_t 3777c478bd9Sstevel@tonic-gate px_ib_intr_reset(void *arg) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 3847c478bd9Sstevel@tonic-gate return (BF_FATAL); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate return (BF_NONE); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate * Locate ino_info structure on ib_p->ib_ino_lst according to ino# 3917c478bd9Sstevel@tonic-gate * returns NULL if not found. 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 3947c478bd9Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = ib_p->ib_ino_lst; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate return (ino_p); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 4067c478bd9Sstevel@tonic-gate px_ib_new_ino(px_ib_t *ib_p, devino_t ino_num, px_ih_t *ih_p) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = kmem_alloc(sizeof (px_ib_ino_info_t), 4097c478bd9Sstevel@tonic-gate KM_SLEEP); 4107c478bd9Sstevel@tonic-gate sysino_t sysino; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate ino_p->ino_ino = ino_num; 4137c478bd9Sstevel@tonic-gate ino_p->ino_ib_p = ib_p; 4147c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino_p->ino_ino, 4177c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4187c478bd9Sstevel@tonic-gate return (NULL); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate ino_p->ino_sysino = sysino; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Cannot disable interrupt since we might share slot 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate ih_p->ih_next = ih_p; 4267c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p; 4277c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 4287c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ih_p; 4297c478bd9Sstevel@tonic-gate ino_p->ino_ih_size = 1; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate ino_p->ino_next = ib_p->ib_ino_lst; 4327c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = ino_p; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate return (ino_p); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * The ino_p is retrieved by previous call to px_ib_locate_ino(). 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate void 4417c478bd9Sstevel@tonic-gate px_ib_delete_ino(px_ib_t *ib_p, px_ib_ino_info_t *ino_p) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate px_ib_ino_info_t *list = ib_p->ib_ino_lst; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if (list == ino_p) 4487c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = list->ino_next; 4497c478bd9Sstevel@tonic-gate else { 4507c478bd9Sstevel@tonic-gate for (; list->ino_next != ino_p; list = list->ino_next); 4517c478bd9Sstevel@tonic-gate list->ino_next = ino_p->ino_next; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Free all ino when we are detaching. 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate void 4597c478bd9Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 4607c478bd9Sstevel@tonic-gate { 4617c478bd9Sstevel@tonic-gate px_ib_ino_info_t *tmp = ib_p->ib_ino_lst; 4627c478bd9Sstevel@tonic-gate px_ib_ino_info_t *next = NULL; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate while (tmp) { 4657c478bd9Sstevel@tonic-gate next = tmp->ino_next; 4667c478bd9Sstevel@tonic-gate kmem_free(tmp, sizeof (px_ib_ino_info_t)); 4677c478bd9Sstevel@tonic-gate tmp = next; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate int 4727c478bd9Sstevel@tonic-gate px_ib_ino_add_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 4757c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 4767c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 4777c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 4787c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 4797c478bd9Sstevel@tonic-gate hrtime_t start_time; 4807c478bd9Sstevel@tonic-gate intr_state_t intr_state; 4817c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4847c478bd9Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 4897c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 4907c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 4917c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, 4927c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate return (ret); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5007c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5017c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5027c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5037c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5047c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 505b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 5067c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5077c478bd9Sstevel@tonic-gate sysino, ino); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 5157c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 5167c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate return (ret); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* Link up px_ispec_t portion of the ppd */ 5227c478bd9Sstevel@tonic-gate ih_p->ih_next = ino_p->ino_ih_head; 5237c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail->ih_next = ih_p; 5247c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 5277c478bd9Sstevel@tonic-gate ino_p->ino_ih_size++; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 5317c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 5327c478bd9Sstevel@tonic-gate * jabber has gone away. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 5357c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5367c478bd9Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 5377c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 5407c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 5417c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 5427c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 5437c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_setstate failed\n"); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate return (ret); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* Re-enable interrupt */ 5507c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate return (ret); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate /* 5567c478bd9Sstevel@tonic-gate * Removes px_ispec_t from the ino's link list. 5577c478bd9Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 5587c478bd9Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 5597c478bd9Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 5607c478bd9Sstevel@tonic-gate * to turn it back on. 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate int 5637c478bd9Sstevel@tonic-gate px_ib_ino_rem_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 5667c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 5677c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 5687c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 5697c478bd9Sstevel@tonic-gate hrtime_t start_time; 5707c478bd9Sstevel@tonic-gate intr_state_t intr_state; 5717c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 5767c478bd9Sstevel@tonic-gate ino_p->ino_ino); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 5797c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_size == 1) { 5827c478bd9Sstevel@tonic-gate if (ih_lst != ih_p) 5837c478bd9Sstevel@tonic-gate goto not_found; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 5867c478bd9Sstevel@tonic-gate goto reset; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5907c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5917c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5927c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5937c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5947c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 595b40cec45Skrishnae "sysino 0x%lx(ino 0x%x) timeout", 5967c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5977c478bd9Sstevel@tonic-gate sysino, ino); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 6007c478bd9Sstevel@tonic-gate break; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6057c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 6067c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate return (ret); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6137c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6147c478bd9Sstevel@tonic-gate * jabber has gone away. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 6177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 6187c478bd9Sstevel@tonic-gate "ino 0x%x has been unblocked", 6197c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 6227c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 6237c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 6247c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 6257c478bd9Sstevel@tonic-gate "px_ib_ino_rem_intr px_intr_setstate failed\n"); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate return (ret); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* Search the link list for ih_p */ 6327c478bd9Sstevel@tonic-gate for (i = 0; (i < ino_p->ino_ih_size) && 6337c478bd9Sstevel@tonic-gate (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 6367c478bd9Sstevel@tonic-gate goto not_found; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 6397c478bd9Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_head == ih_p) 6427c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p->ih_next; 6437c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_tail == ih_p) 6447c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_lst; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate reset: 6497c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 6507c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 6517c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 6527c478bd9Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 6557c478bd9Sstevel@tonic-gate ino_p->ino_ih_size--; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate return (ret); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate not_found: 6607c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 6617c478bd9Sstevel@tonic-gate "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate px_ih_t * 6677c478bd9Sstevel@tonic-gate px_ib_ino_locate_intr(px_ib_ino_info_t *ino_p, dev_info_t *rdip, 6687c478bd9Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 6697c478bd9Sstevel@tonic-gate { 6707c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 6717c478bd9Sstevel@tonic-gate int i; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_lst = ih_lst->ih_next) { 6747c478bd9Sstevel@tonic-gate if ((ih_lst->ih_dip == rdip) && (ih_lst->ih_inum == inum) && 6757c478bd9Sstevel@tonic-gate (ih_lst->ih_rec_type == rec_type) && 6767c478bd9Sstevel@tonic-gate (ih_lst->ih_msg_code == msg_code)) 6777c478bd9Sstevel@tonic-gate return (ih_lst); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate return ((px_ih_t *)NULL); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate px_ih_t * 6847c478bd9Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 6857c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 6867c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 6877c478bd9Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 6887c478bd9Sstevel@tonic-gate { 6897c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 6927c478bd9Sstevel@tonic-gate ih_p->ih_dip = rdip; 6937c478bd9Sstevel@tonic-gate ih_p->ih_inum = inum; 6947c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 6957c478bd9Sstevel@tonic-gate ih_p->ih_handler = int_handler; 6967c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 6977c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 6987c478bd9Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 6997c478bd9Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 7007c478bd9Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 7017c478bd9Sstevel@tonic-gate ih_p->ih_nsec = 0; 7027c478bd9Sstevel@tonic-gate ih_p->ih_ticks = 0; 7037c478bd9Sstevel@tonic-gate ih_p->ih_ksp = NULL; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate return (ih_p); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate int 7097c478bd9Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 71036fe4a92Segillett uint_t inum, devino_t ino, uint_t new_intr_state, 71136fe4a92Segillett msiq_rec_type_t rec_type, msgcode_t msg_code) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 7147c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 7157c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 7167c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "ib_update_intr_state: %s%d " 7197c478bd9Sstevel@tonic-gate "inum %x devino %x state %x\n", ddi_driver_name(rdip), 7207c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), inum, ino, new_intr_state); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { 72536fe4a92Segillett if (ih_p = px_ib_ino_locate_intr(ino_p, rdip, inum, rec_type, 72636fe4a92Segillett msg_code)) { 7277c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 7287c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 7337c478bd9Sstevel@tonic-gate return (ret); 7347c478bd9Sstevel@tonic-gate } 73569cd775fSschwartz 73669cd775fSschwartz 73769cd775fSschwartz static void 73869cd775fSschwartz px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, 73969cd775fSschwartz char *path_name, int instance) 74069cd775fSschwartz { 74169cd775fSschwartz (void) strncpy(dev->driver_name, driver_name, MAXMODCONFNAME-1); 74269cd775fSschwartz dev->driver_name[MAXMODCONFNAME] = '\0'; 74369cd775fSschwartz (void) strncpy(dev->path, path_name, MAXPATHLEN-1); 74469cd775fSschwartz dev->dev_inst = instance; 74569cd775fSschwartz } 74669cd775fSschwartz 74769cd775fSschwartz 74869cd775fSschwartz /* 74969cd775fSschwartz * Return the dips or number of dips associated with a given interrupt block. 75069cd775fSschwartz * Size of dips array arg is passed in as dips_ret arg. 75169cd775fSschwartz * Number of dips returned is returned in dips_ret arg. 75269cd775fSschwartz * Array of dips gets returned in the dips argument. 75369cd775fSschwartz * Function returns number of dips existing for the given interrupt block. 75469cd775fSschwartz * 75569cd775fSschwartz * Note: this function assumes an enabled/valid INO, which is why it returns 75669cd775fSschwartz * the px node and (Internal) when it finds no other devices (and *devs_ret > 0) 75769cd775fSschwartz */ 75869cd775fSschwartz uint8_t 75969cd775fSschwartz pxtool_ib_get_ino_devs( 76069cd775fSschwartz px_t *px_p, uint32_t ino, uint8_t *devs_ret, pcitool_intr_dev_t *devs) 76169cd775fSschwartz { 76269cd775fSschwartz px_ib_t *ib_p = px_p->px_ib_p; 76369cd775fSschwartz px_ib_ino_info_t *ino_p; 76469cd775fSschwartz px_ih_t *ih_p; 76569cd775fSschwartz uint32_t num_devs = 0; 76669cd775fSschwartz char pathname[MAXPATHLEN]; 76769cd775fSschwartz int i; 76869cd775fSschwartz 76969cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 77069cd775fSschwartz ino_p = px_ib_locate_ino(ib_p, ino); 77169cd775fSschwartz if (ino_p != NULL) { 77269cd775fSschwartz num_devs = ino_p->ino_ih_size; 77369cd775fSschwartz for (i = 0, ih_p = ino_p->ino_ih_head; 77469cd775fSschwartz ((i < ino_p->ino_ih_size) && (i < *devs_ret)); 77569cd775fSschwartz i++, ih_p = ih_p->ih_next) { 77669cd775fSschwartz (void) ddi_pathname(ih_p->ih_dip, pathname); 77769cd775fSschwartz px_fill_in_intr_devs(&devs[i], 77869cd775fSschwartz (char *)ddi_driver_name(ih_p->ih_dip), pathname, 77969cd775fSschwartz ddi_get_instance(ih_p->ih_dip)); 78069cd775fSschwartz } 78169cd775fSschwartz *devs_ret = i; 78269cd775fSschwartz 78369cd775fSschwartz } else if (*devs_ret > 0) { 78469cd775fSschwartz (void) ddi_pathname(px_p->px_dip, pathname); 78569cd775fSschwartz strcat(pathname, " (Internal)"); 78669cd775fSschwartz px_fill_in_intr_devs(&devs[0], 78769cd775fSschwartz (char *)ddi_driver_name(px_p->px_dip), pathname, 78869cd775fSschwartz ddi_get_instance(px_p->px_dip)); 78969cd775fSschwartz num_devs = *devs_ret = 1; 79069cd775fSschwartz } 79169cd775fSschwartz 79269cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 79369cd775fSschwartz 79469cd775fSschwartz return (num_devs); 79569cd775fSschwartz } 79669cd775fSschwartz 79769cd775fSschwartz 79844bb982bSgovinda void 79944bb982bSgovinda px_ib_log_new_cpu(px_ib_t *ib_p, uint32_t old_cpu_id, uint32_t new_cpu_id, 80069cd775fSschwartz uint32_t ino) 80169cd775fSschwartz { 80269cd775fSschwartz px_ib_ino_info_t *ino_p; 80369cd775fSschwartz 80469cd775fSschwartz mutex_enter(&ib_p->ib_ino_lst_mutex); 80569cd775fSschwartz 80669cd775fSschwartz /* Log in OS data structures the new CPU. */ 80769cd775fSschwartz ino_p = px_ib_locate_ino(ib_p, ino); 80869cd775fSschwartz if (ino_p != NULL) { 80969cd775fSschwartz 81069cd775fSschwartz /* Log in OS data structures the new CPU. */ 81169cd775fSschwartz ino_p->ino_cpuid = new_cpu_id; 81269cd775fSschwartz 81369cd775fSschwartz /* Account for any residual time to be logged for old cpu. */ 81469cd775fSschwartz px_ib_cpu_ticks_to_ih_nsec(ib_p, ino_p->ino_ih_head, 81569cd775fSschwartz old_cpu_id); 81669cd775fSschwartz } 81769cd775fSschwartz 81869cd775fSschwartz mutex_exit(&ib_p->ib_ino_lst_mutex); 81969cd775fSschwartz } 820