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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * PX Interrupt Block implementation 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/async.h> 367c478bd9Sstevel@tonic-gate #include <sys/systm.h> /* panicstr */ 377c478bd9Sstevel@tonic-gate #include <sys/spl.h> 387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 397c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* intr_dist_add */ 407c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 417c478bd9Sstevel@tonic-gate #include <sys/cpuvar.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); 477c478bd9Sstevel@tonic-gate static void px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 487c478bd9Sstevel@tonic-gate boolean_t wait_flag); 497c478bd9Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate int 527c478bd9Sstevel@tonic-gate px_ib_attach(px_t *px_p) 537c478bd9Sstevel@tonic-gate { 547c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 557c478bd9Sstevel@tonic-gate px_ib_t *ib_p; 567c478bd9Sstevel@tonic-gate sysino_t sysino; 577c478bd9Sstevel@tonic-gate px_fault_t *fault_p = &px_p->px_fault; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_attach\n"); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, 62*f8d2de6bSjchu px_p->px_inos[PX_INTR_PEC], &sysino) != DDI_SUCCESS) 637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Allocate interrupt block state structure and link it to 677c478bd9Sstevel@tonic-gate * the px state structure. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 707c478bd9Sstevel@tonic-gate px_p->px_ib_p = ib_p; 717c478bd9Sstevel@tonic-gate ib_p->ib_px_p = px_p; 727c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = (px_ib_ino_info_t *)NULL; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 757c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate intr_dist_add_weighted(px_ib_intr_redist, ib_p); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Initialize PEC fault data structure 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate fault_p->px_fh_dip = dip; 857c478bd9Sstevel@tonic-gate fault_p->px_fh_sysino = sysino; 86*f8d2de6bSjchu fault_p->px_err_func = px_err_dmc_pec_intr; 87*f8d2de6bSjchu fault_p->px_intr_ino = px_p->px_inos[PX_INTR_PEC]; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate void 937c478bd9Sstevel@tonic-gate px_ib_detach(px_t *px_p) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 967c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_detach\n"); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 1017c478bd9Sstevel@tonic-gate intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_ino_lst_mutex); 1047c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_intr_lock); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate px_ib_free_ino_all(ib_p); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate px_p->px_ib_p = NULL; 1097c478bd9Sstevel@tonic-gate kmem_free(ib_p, sizeof (px_ib_t)); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate static struct { 1137c478bd9Sstevel@tonic-gate kstat_named_t ihks_name; 1147c478bd9Sstevel@tonic-gate kstat_named_t ihks_type; 1157c478bd9Sstevel@tonic-gate kstat_named_t ihks_cpu; 1167c478bd9Sstevel@tonic-gate kstat_named_t ihks_pil; 1177c478bd9Sstevel@tonic-gate kstat_named_t ihks_time; 1187c478bd9Sstevel@tonic-gate kstat_named_t ihks_ino; 1197c478bd9Sstevel@tonic-gate kstat_named_t ihks_cookie; 1207c478bd9Sstevel@tonic-gate kstat_named_t ihks_devpath; 1217c478bd9Sstevel@tonic-gate kstat_named_t ihks_buspath; 1227c478bd9Sstevel@tonic-gate } px_ih_ks_template = { 1237c478bd9Sstevel@tonic-gate { "name", KSTAT_DATA_CHAR }, 1247c478bd9Sstevel@tonic-gate { "type", KSTAT_DATA_CHAR }, 1257c478bd9Sstevel@tonic-gate { "cpu", KSTAT_DATA_UINT64 }, 1267c478bd9Sstevel@tonic-gate { "pil", KSTAT_DATA_UINT64 }, 1277c478bd9Sstevel@tonic-gate { "time", KSTAT_DATA_UINT64 }, 1287c478bd9Sstevel@tonic-gate { "ino", KSTAT_DATA_UINT64 }, 1297c478bd9Sstevel@tonic-gate { "cookie", KSTAT_DATA_UINT64 }, 1307c478bd9Sstevel@tonic-gate { "devpath", KSTAT_DATA_STRING }, 1317c478bd9Sstevel@tonic-gate { "buspath", KSTAT_DATA_STRING }, 1327c478bd9Sstevel@tonic-gate }; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate static uint32_t ih_instance; 1357c478bd9Sstevel@tonic-gate static kmutex_t ih_ks_template_lock; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate int 1387c478bd9Sstevel@tonic-gate ih_ks_update(kstat_t *ksp, int rw) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate px_ih_t *ih_p = ksp->ks_private; 1417c478bd9Sstevel@tonic-gate int maxlen = sizeof (px_ih_ks_template.ihks_name.value.c); 1427c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ih_p->ih_ino_p->ino_ib_p; 1437c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 1447c478bd9Sstevel@tonic-gate devino_t ino; 1457c478bd9Sstevel@tonic-gate sysino_t sysino; 1467c478bd9Sstevel@tonic-gate char ih_devpath[MAXPATHLEN]; 1477c478bd9Sstevel@tonic-gate char ih_buspath[MAXPATHLEN]; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate ino = ih_p->ih_ino_p->ino_ino; 1507c478bd9Sstevel@tonic-gate (void) px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate (void) snprintf(px_ih_ks_template.ihks_name.value.c, maxlen, "%s%d", 1537c478bd9Sstevel@tonic-gate ddi_driver_name(ih_p->ih_dip), 1547c478bd9Sstevel@tonic-gate ddi_get_instance(ih_p->ih_dip)); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate (void) strcpy(px_ih_ks_template.ihks_type.value.c, 1577c478bd9Sstevel@tonic-gate (ih_p->ih_rec_type == 0) ? "fixed" : "msi"); 1587c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_cpu.value.ui64 = ih_p->ih_ino_p->ino_cpuid; 1597c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_pil.value.ui64 = ih_p->ih_ino_p->ino_pil; 1607c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_time.value.ui64 = ih_p->ih_nsec + (uint64_t) 1617c478bd9Sstevel@tonic-gate tick2ns((hrtime_t)ih_p->ih_ticks, ih_p->ih_ino_p->ino_cpuid); 1627c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_ino.value.ui64 = ino; 1637c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_cookie.value.ui64 = sysino; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 1667c478bd9Sstevel@tonic-gate (void) ddi_pathname(px_p->px_dip, ih_buspath); 1677c478bd9Sstevel@tonic-gate kstat_named_setstr(&px_ih_ks_template.ihks_devpath, ih_devpath); 1687c478bd9Sstevel@tonic-gate kstat_named_setstr(&px_ih_ks_template.ihks_buspath, ih_buspath); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate return (0); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate void 1747c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 1757c478bd9Sstevel@tonic-gate { 1767c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 1777c478bd9Sstevel@tonic-gate sysino_t sysino; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Determine the cpu for the interrupt 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1857c478bd9Sstevel@tonic-gate "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 1887c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 1897c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 1907c478bd9Sstevel@tonic-gate "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1937c478bd9Sstevel@tonic-gate return; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2027c478bd9Sstevel@tonic-gate void 2037c478bd9Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate sysino_t sysino; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 2127c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 2137c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 2147c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, 2157c478bd9Sstevel@tonic-gate "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 2187c478bd9Sstevel@tonic-gate return; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static void 2287c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 2297c478bd9Sstevel@tonic-gate boolean_t wait_flag) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate uint32_t old_cpu_id; 2327c478bd9Sstevel@tonic-gate sysino_t sysino; 2337c478bd9Sstevel@tonic-gate intr_valid_state_t enabled = 0; 2347c478bd9Sstevel@tonic-gate hrtime_t start_time; 2357c478bd9Sstevel@tonic-gate intr_state_t intr_state; 236*f8d2de6bSjchu int e = DDI_SUCCESS; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 2417c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 2427c478bd9Sstevel@tonic-gate "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 2437c478bd9Sstevel@tonic-gate return; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* Skip enabling disabled interrupts */ 2477c478bd9Sstevel@tonic-gate if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 2487c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 2497c478bd9Sstevel@tonic-gate "failed, sysino 0x%x\n", sysino); 2507c478bd9Sstevel@tonic-gate return; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate if (!enabled) 2537c478bd9Sstevel@tonic-gate return; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* Done if redistributed onto the same cpuid */ 2567c478bd9Sstevel@tonic-gate if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 2577c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 2587c478bd9Sstevel@tonic-gate "px_intr_gettarget() failed\n"); 2597c478bd9Sstevel@tonic-gate return; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate if (cpu_id == old_cpu_id) 2627c478bd9Sstevel@tonic-gate return; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate if (!wait_flag) 2657c478bd9Sstevel@tonic-gate goto done; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupts */ 2687c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 2717c478bd9Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 2727c478bd9Sstevel@tonic-gate DDI_SUCCESS) && 2737c478bd9Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 2747c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 2757c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2767c478bd9Sstevel@tonic-gate "%s%d: px_ib_intr_dist_en: sysino 0x%x(ino 0x%x) " 2777c478bd9Sstevel@tonic-gate "from cpu id 0x%x to 0x%x timeout", 2787c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2797c478bd9Sstevel@tonic-gate sysino, ino, old_cpu_id, cpu_id); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate e = DDI_FAILURE; 2827c478bd9Sstevel@tonic-gate break; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate if (e != DDI_SUCCESS) 2877c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 2887c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate done: 2917c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, cpu_id); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * Redistribute interrupts of the specified weight. The first call has a weight 2977c478bd9Sstevel@tonic-gate * of weight_max, which can be used to trigger initialization for 2987c478bd9Sstevel@tonic-gate * redistribution. The inos with weight [weight_max, inf.) should be processed 2997c478bd9Sstevel@tonic-gate * on the "weight == weight_max" call. This first call is followed by calls 3007c478bd9Sstevel@tonic-gate * of decreasing weights, inos of that weight should be processed. The final 3017c478bd9Sstevel@tonic-gate * call specifies a weight of zero, this can be used to trigger processing of 3027c478bd9Sstevel@tonic-gate * stragglers. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate static void 3057c478bd9Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 3087c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 3097c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 3107c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 3117c478bd9Sstevel@tonic-gate px_ih_t *ih_lst; 3127c478bd9Sstevel@tonic-gate int32_t dweight = 0; 3137c478bd9Sstevel@tonic-gate int i; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* Redistribute internal interrupts */ 3167c478bd9Sstevel@tonic-gate if (weight == 0) { 3177c478bd9Sstevel@tonic-gate devino_t ino_pec = px_p->px_inos[PX_INTR_PEC]; 318*f8d2de6bSjchu 3197c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 3207c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, intr_dist_cpuid(), ino_pec, B_FALSE); 3217c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate /* Redistribute device interrupts */ 3257c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) { 3287c478bd9Sstevel@tonic-gate uint32_t orig_cpuid; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 3327c478bd9Sstevel@tonic-gate * share the same ino upon first call marked by 3337c478bd9Sstevel@tonic-gate * (weight == weight_max). 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate if (weight == weight_max) { 3367c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 3377c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3387c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 3397c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3407c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3417c478bd9Sstevel@tonic-gate if (dweight > 0) 3427c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight += dweight; 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 3487c478bd9Sstevel@tonic-gate * nexus redistributes device interrupts and updates 3497c478bd9Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 3507c478bd9Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 3517c478bd9Sstevel@tonic-gate * attention demanding device gains more cpu attention by 3527c478bd9Sstevel@tonic-gate * making itself heavy. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 3557c478bd9Sstevel@tonic-gate ((weight >= weight_max) && 3567c478bd9Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 3577c478bd9Sstevel@tonic-gate orig_cpuid = ino_p->ino_cpuid; 3587c478bd9Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 3597c478bd9Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* select cpuid to target and mark ino established */ 3627c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 3657c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 3667c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 3677c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 3687c478bd9Sstevel@tonic-gate hrtime_t ticks; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 3717c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight( 3727c478bd9Sstevel@tonic-gate ino_p->ino_cpuid, ih_lst->ih_dip, dweight); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * different cpus may have different clock 3767c478bd9Sstevel@tonic-gate * speeds. to account for this, whenever an 3777c478bd9Sstevel@tonic-gate * interrupt is moved to a new CPU, we 3787c478bd9Sstevel@tonic-gate * convert the accumulated ticks into nsec, 3797c478bd9Sstevel@tonic-gate * based upon the clock rate of the prior 3807c478bd9Sstevel@tonic-gate * CPU. 3817c478bd9Sstevel@tonic-gate * 3827c478bd9Sstevel@tonic-gate * It is possible that the prior CPU no longer 3837c478bd9Sstevel@tonic-gate * exists. In this case, fall back to using 3847c478bd9Sstevel@tonic-gate * this CPU's clock rate. 3857c478bd9Sstevel@tonic-gate * 3867c478bd9Sstevel@tonic-gate * Note that the value in ih_ticks has already 3877c478bd9Sstevel@tonic-gate * been corrected for any power savings mode 3887c478bd9Sstevel@tonic-gate * which might have been in effect. 3897c478bd9Sstevel@tonic-gate * 3907c478bd9Sstevel@tonic-gate * because we are updating two fields in 3917c478bd9Sstevel@tonic-gate * ih_t we must lock ih_ks_template_lock to 3927c478bd9Sstevel@tonic-gate * prevent someone from reading the kstats 3937c478bd9Sstevel@tonic-gate * after we set ih_ticks to 0 and before we 3947c478bd9Sstevel@tonic-gate * increment ih_nsec to compensate. 3957c478bd9Sstevel@tonic-gate * 3967c478bd9Sstevel@tonic-gate * we must also protect against the interrupt 3977c478bd9Sstevel@tonic-gate * arriving and incrementing ih_ticks between 3987c478bd9Sstevel@tonic-gate * the time we read it and when we reset it 3997c478bd9Sstevel@tonic-gate * to 0. To do this we use atomic_swap. 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate mutex_enter(&ih_ks_template_lock); 4037c478bd9Sstevel@tonic-gate ticks = atomic_swap_64(&ih_lst->ih_ticks, 0); 4047c478bd9Sstevel@tonic-gate ih_lst->ih_nsec += (uint64_t) 4057c478bd9Sstevel@tonic-gate tick2ns(ticks, orig_cpuid); 4067c478bd9Sstevel@tonic-gate mutex_exit(&ih_ks_template_lock); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 4107c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 4117c478bd9Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 4197c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 4207c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 4217c478bd9Sstevel@tonic-gate * 4227c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 4237c478bd9Sstevel@tonic-gate * are permanently suspended. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate static uint_t 4267c478bd9Sstevel@tonic-gate px_ib_intr_reset(void *arg) 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 4337c478bd9Sstevel@tonic-gate return (BF_FATAL); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate return (BF_NONE); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * Locate ino_info structure on ib_p->ib_ino_lst according to ino# 4407c478bd9Sstevel@tonic-gate * returns NULL if not found. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 4437c478bd9Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = ib_p->ib_ino_lst; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate return (ino_p); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 4557c478bd9Sstevel@tonic-gate px_ib_new_ino(px_ib_t *ib_p, devino_t ino_num, px_ih_t *ih_p) 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = kmem_alloc(sizeof (px_ib_ino_info_t), 4587c478bd9Sstevel@tonic-gate KM_SLEEP); 4597c478bd9Sstevel@tonic-gate sysino_t sysino; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate ino_p->ino_ino = ino_num; 4627c478bd9Sstevel@tonic-gate ino_p->ino_ib_p = ib_p; 4637c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino_p->ino_ino, 4667c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4677c478bd9Sstevel@tonic-gate return (NULL); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate ino_p->ino_sysino = sysino; 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* 4727c478bd9Sstevel@tonic-gate * Cannot disable interrupt since we might share slot 4737c478bd9Sstevel@tonic-gate */ 4747c478bd9Sstevel@tonic-gate ih_p->ih_next = ih_p; 4757c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p; 4767c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 4777c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ih_p; 4787c478bd9Sstevel@tonic-gate ino_p->ino_ih_size = 1; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate ino_p->ino_next = ib_p->ib_ino_lst; 4817c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = ino_p; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate return (ino_p); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * The ino_p is retrieved by previous call to px_ib_locate_ino(). 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate void 4907c478bd9Sstevel@tonic-gate px_ib_delete_ino(px_ib_t *ib_p, px_ib_ino_info_t *ino_p) 4917c478bd9Sstevel@tonic-gate { 4927c478bd9Sstevel@tonic-gate px_ib_ino_info_t *list = ib_p->ib_ino_lst; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if (list == ino_p) 4977c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = list->ino_next; 4987c478bd9Sstevel@tonic-gate else { 4997c478bd9Sstevel@tonic-gate for (; list->ino_next != ino_p; list = list->ino_next); 5007c478bd9Sstevel@tonic-gate list->ino_next = ino_p->ino_next; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* 5057c478bd9Sstevel@tonic-gate * Free all ino when we are detaching. 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate void 5087c478bd9Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate px_ib_ino_info_t *tmp = ib_p->ib_ino_lst; 5117c478bd9Sstevel@tonic-gate px_ib_ino_info_t *next = NULL; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate while (tmp) { 5147c478bd9Sstevel@tonic-gate next = tmp->ino_next; 5157c478bd9Sstevel@tonic-gate kmem_free(tmp, sizeof (px_ib_ino_info_t)); 5167c478bd9Sstevel@tonic-gate tmp = next; 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate int 5217c478bd9Sstevel@tonic-gate px_ib_ino_add_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 5247c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 5257c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 5267c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 5277c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 5287c478bd9Sstevel@tonic-gate hrtime_t start_time; 5297c478bd9Sstevel@tonic-gate intr_state_t intr_state; 5307c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 5337c478bd9Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 5387c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 5397c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 5407c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, 5417c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate return (ret); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 5497c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 5507c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 5517c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 5527c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 5537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 5547c478bd9Sstevel@tonic-gate "sysino 0x%x(ino 0x%x) timeout", 5557c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 5567c478bd9Sstevel@tonic-gate sysino, ino); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 5597c478bd9Sstevel@tonic-gate break; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 5647c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 5657c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate return (ret); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* Link up px_ispec_t portion of the ppd */ 5717c478bd9Sstevel@tonic-gate ih_p->ih_next = ino_p->ino_ih_head; 5727c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail->ih_next = ih_p; 5737c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 5767c478bd9Sstevel@tonic-gate ino_p->ino_ih_size++; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 5807c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 5817c478bd9Sstevel@tonic-gate * jabber has gone away. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 5847c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5857c478bd9Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 5867c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 5897c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 5907c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 5917c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 5927c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_setstate failed\n"); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate return (ret); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* Re-enable interrupt */ 5997c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate return (ret); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Removes px_ispec_t from the ino's link list. 6067c478bd9Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 6077c478bd9Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 6087c478bd9Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 6097c478bd9Sstevel@tonic-gate * to turn it back on. 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate int 6127c478bd9Sstevel@tonic-gate px_ib_ino_rem_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 6137c478bd9Sstevel@tonic-gate { 6147c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 6157c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 6167c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 6177c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 6187c478bd9Sstevel@tonic-gate hrtime_t start_time; 6197c478bd9Sstevel@tonic-gate intr_state_t intr_state; 6207c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 6257c478bd9Sstevel@tonic-gate ino_p->ino_ino); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 6287c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_size == 1) { 6317c478bd9Sstevel@tonic-gate if (ih_lst != ih_p) 6327c478bd9Sstevel@tonic-gate goto not_found; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 6357c478bd9Sstevel@tonic-gate goto reset; 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 6397c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 6407c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 6417c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 6427c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 6437c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 6447c478bd9Sstevel@tonic-gate "sysino 0x%x(ino 0x%x) timeout", 6457c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 6467c478bd9Sstevel@tonic-gate sysino, ino); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 6497c478bd9Sstevel@tonic-gate break; 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6547c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 6557c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate return (ret); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* 6617c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 6627c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 6637c478bd9Sstevel@tonic-gate * jabber has gone away. 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 6667c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 6677c478bd9Sstevel@tonic-gate "ino 0x%x has been unblocked", 6687c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 6717c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 6727c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 6737c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 6747c478bd9Sstevel@tonic-gate "px_ib_ino_rem_intr px_intr_setstate failed\n"); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate return (ret); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* Search the link list for ih_p */ 6817c478bd9Sstevel@tonic-gate for (i = 0; (i < ino_p->ino_ih_size) && 6827c478bd9Sstevel@tonic-gate (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 6857c478bd9Sstevel@tonic-gate goto not_found; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 6887c478bd9Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_head == ih_p) 6917c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p->ih_next; 6927c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_tail == ih_p) 6937c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_lst; 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate reset: 6987c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 6997c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 7007c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 7017c478bd9Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 7047c478bd9Sstevel@tonic-gate ino_p->ino_ih_size--; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate return (ret); 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate not_found: 7097c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 7107c478bd9Sstevel@tonic-gate "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate px_ih_t * 7167c478bd9Sstevel@tonic-gate px_ib_ino_locate_intr(px_ib_ino_info_t *ino_p, dev_info_t *rdip, 7177c478bd9Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 7187c478bd9Sstevel@tonic-gate { 7197c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 7207c478bd9Sstevel@tonic-gate int i; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_lst = ih_lst->ih_next) { 7237c478bd9Sstevel@tonic-gate if ((ih_lst->ih_dip == rdip) && (ih_lst->ih_inum == inum) && 7247c478bd9Sstevel@tonic-gate (ih_lst->ih_rec_type == rec_type) && 7257c478bd9Sstevel@tonic-gate (ih_lst->ih_msg_code == msg_code)) 7267c478bd9Sstevel@tonic-gate return (ih_lst); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate return ((px_ih_t *)NULL); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate px_ih_t * 7337c478bd9Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 7347c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 7357c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 7367c478bd9Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 7377c478bd9Sstevel@tonic-gate { 7387c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 7417c478bd9Sstevel@tonic-gate ih_p->ih_dip = rdip; 7427c478bd9Sstevel@tonic-gate ih_p->ih_inum = inum; 7437c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 7447c478bd9Sstevel@tonic-gate ih_p->ih_handler = int_handler; 7457c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 7467c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 7477c478bd9Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 7487c478bd9Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 7497c478bd9Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 7507c478bd9Sstevel@tonic-gate ih_p->ih_nsec = 0; 7517c478bd9Sstevel@tonic-gate ih_p->ih_ticks = 0; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * Create pci_intrs::: kstats for all ih types except messages, 7557c478bd9Sstevel@tonic-gate * which represent unusual conditions and don't need to be tracked. 7567c478bd9Sstevel@tonic-gate */ 7577c478bd9Sstevel@tonic-gate ih_p->ih_ksp = NULL; 7587c478bd9Sstevel@tonic-gate if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 7597c478bd9Sstevel@tonic-gate ih_p->ih_ksp = kstat_create("pci_intrs", 7607c478bd9Sstevel@tonic-gate atomic_inc_32_nv(&ih_instance), "config", "interrupts", 7617c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 7627c478bd9Sstevel@tonic-gate sizeof (px_ih_ks_template) / sizeof (kstat_named_t), 7637c478bd9Sstevel@tonic-gate KSTAT_FLAG_VIRTUAL); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) { 7667c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 7677c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_lock = &ih_ks_template_lock; 7687c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_data = &px_ih_ks_template; 7697c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_private = ih_p; 7707c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_update = ih_ks_update; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate return (ih_p); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * Only used for fixed or legacy interrupts. 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate int 7807c478bd9Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 7817c478bd9Sstevel@tonic-gate uint_t inum, devino_t ino, uint_t new_intr_state) 7827c478bd9Sstevel@tonic-gate { 7837c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 7847c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 7857c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 7867c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "ib_update_intr_state: %s%d " 7897c478bd9Sstevel@tonic-gate "inum %x devino %x state %x\n", ddi_driver_name(rdip), 7907c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), inum, ino, new_intr_state); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { 7957c478bd9Sstevel@tonic-gate if (ih_p = px_ib_ino_locate_intr(ino_p, rdip, inum, 0, 0)) { 7967c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 7977c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 8027c478bd9Sstevel@tonic-gate return (ret); 8037c478bd9Sstevel@tonic-gate } 804