1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * PX Interrupt Block implementation 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/async.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> /* panicstr */ 37*7c478bd9Sstevel@tonic-gate #include <sys/spl.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* intr_dist_add */ 40*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 42*7c478bd9Sstevel@tonic-gate #include "px_obj.h" 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate static void px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight); 47*7c478bd9Sstevel@tonic-gate static void px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 48*7c478bd9Sstevel@tonic-gate boolean_t wait_flag); 49*7c478bd9Sstevel@tonic-gate static uint_t px_ib_intr_reset(void *arg); 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate int 52*7c478bd9Sstevel@tonic-gate px_ib_attach(px_t *px_p) 53*7c478bd9Sstevel@tonic-gate { 54*7c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 55*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p; 56*7c478bd9Sstevel@tonic-gate sysino_t sysino; 57*7c478bd9Sstevel@tonic-gate px_fault_t *fault_p = &px_p->px_fault; 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_attach\n"); 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, 62*7c478bd9Sstevel@tonic-gate px_p->px_inos[PX_FAULT_PEC], &sysino) != DDI_SUCCESS) 63*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* 66*7c478bd9Sstevel@tonic-gate * Allocate interrupt block state structure and link it to 67*7c478bd9Sstevel@tonic-gate * the px state structure. 68*7c478bd9Sstevel@tonic-gate */ 69*7c478bd9Sstevel@tonic-gate ib_p = kmem_zalloc(sizeof (px_ib_t), KM_SLEEP); 70*7c478bd9Sstevel@tonic-gate px_p->px_ib_p = ib_p; 71*7c478bd9Sstevel@tonic-gate ib_p->ib_px_p = px_p; 72*7c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = (px_ib_ino_info_t *)NULL; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_intr_lock, NULL, MUTEX_DRIVER, NULL); 75*7c478bd9Sstevel@tonic-gate mutex_init(&ib_p->ib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate intr_dist_add_weighted(px_ib_intr_redist, ib_p); 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * Initialize PEC fault data structure 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate fault_p->px_fh_dip = dip; 85*7c478bd9Sstevel@tonic-gate fault_p->px_fh_sysino = sysino; 86*7c478bd9Sstevel@tonic-gate fault_p->px_fh_lst = NULL; 87*7c478bd9Sstevel@tonic-gate mutex_init(&fault_p->px_fh_lock, NULL, MUTEX_DRIVER, NULL); 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* Register IMU error */ 90*7c478bd9Sstevel@tonic-gate px_err_add_fh(fault_p, PX_ERR_IMU, 91*7c478bd9Sstevel@tonic-gate (caddr_t)px_p->px_address[PX_REG_CSR]); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 94*7c478bd9Sstevel@tonic-gate } 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate void 97*7c478bd9Sstevel@tonic-gate px_ib_detach(px_t *px_p) 98*7c478bd9Sstevel@tonic-gate { 99*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 100*7c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_detach\n"); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate px_err_rem(&px_p->px_fault, PX_FAULT_PEC); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, px_ib_intr_reset, ib_p); 107*7c478bd9Sstevel@tonic-gate intr_dist_rem_weighted(px_ib_intr_redist, ib_p); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_ino_lst_mutex); 110*7c478bd9Sstevel@tonic-gate mutex_destroy(&ib_p->ib_intr_lock); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate px_ib_free_ino_all(ib_p); 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate px_p->px_ib_p = NULL; 115*7c478bd9Sstevel@tonic-gate kmem_free(ib_p, sizeof (px_ib_t)); 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate static struct { 119*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_name; 120*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_type; 121*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_cpu; 122*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_pil; 123*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_time; 124*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_ino; 125*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_cookie; 126*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_devpath; 127*7c478bd9Sstevel@tonic-gate kstat_named_t ihks_buspath; 128*7c478bd9Sstevel@tonic-gate } px_ih_ks_template = { 129*7c478bd9Sstevel@tonic-gate { "name", KSTAT_DATA_CHAR }, 130*7c478bd9Sstevel@tonic-gate { "type", KSTAT_DATA_CHAR }, 131*7c478bd9Sstevel@tonic-gate { "cpu", KSTAT_DATA_UINT64 }, 132*7c478bd9Sstevel@tonic-gate { "pil", KSTAT_DATA_UINT64 }, 133*7c478bd9Sstevel@tonic-gate { "time", KSTAT_DATA_UINT64 }, 134*7c478bd9Sstevel@tonic-gate { "ino", KSTAT_DATA_UINT64 }, 135*7c478bd9Sstevel@tonic-gate { "cookie", KSTAT_DATA_UINT64 }, 136*7c478bd9Sstevel@tonic-gate { "devpath", KSTAT_DATA_STRING }, 137*7c478bd9Sstevel@tonic-gate { "buspath", KSTAT_DATA_STRING }, 138*7c478bd9Sstevel@tonic-gate }; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate static uint32_t ih_instance; 141*7c478bd9Sstevel@tonic-gate static kmutex_t ih_ks_template_lock; 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate int 144*7c478bd9Sstevel@tonic-gate ih_ks_update(kstat_t *ksp, int rw) 145*7c478bd9Sstevel@tonic-gate { 146*7c478bd9Sstevel@tonic-gate px_ih_t *ih_p = ksp->ks_private; 147*7c478bd9Sstevel@tonic-gate int maxlen = sizeof (px_ih_ks_template.ihks_name.value.c); 148*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ih_p->ih_ino_p->ino_ib_p; 149*7c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 150*7c478bd9Sstevel@tonic-gate devino_t ino; 151*7c478bd9Sstevel@tonic-gate sysino_t sysino; 152*7c478bd9Sstevel@tonic-gate char ih_devpath[MAXPATHLEN]; 153*7c478bd9Sstevel@tonic-gate char ih_buspath[MAXPATHLEN]; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate ino = ih_p->ih_ino_p->ino_ino; 156*7c478bd9Sstevel@tonic-gate (void) px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino); 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate (void) snprintf(px_ih_ks_template.ihks_name.value.c, maxlen, "%s%d", 159*7c478bd9Sstevel@tonic-gate ddi_driver_name(ih_p->ih_dip), 160*7c478bd9Sstevel@tonic-gate ddi_get_instance(ih_p->ih_dip)); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate (void) strcpy(px_ih_ks_template.ihks_type.value.c, 163*7c478bd9Sstevel@tonic-gate (ih_p->ih_rec_type == 0) ? "fixed" : "msi"); 164*7c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_cpu.value.ui64 = ih_p->ih_ino_p->ino_cpuid; 165*7c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_pil.value.ui64 = ih_p->ih_ino_p->ino_pil; 166*7c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_time.value.ui64 = ih_p->ih_nsec + (uint64_t) 167*7c478bd9Sstevel@tonic-gate tick2ns((hrtime_t)ih_p->ih_ticks, ih_p->ih_ino_p->ino_cpuid); 168*7c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_ino.value.ui64 = ino; 169*7c478bd9Sstevel@tonic-gate px_ih_ks_template.ihks_cookie.value.ui64 = sysino; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 172*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(px_p->px_dip, ih_buspath); 173*7c478bd9Sstevel@tonic-gate kstat_named_setstr(&px_ih_ks_template.ihks_devpath, ih_devpath); 174*7c478bd9Sstevel@tonic-gate kstat_named_setstr(&px_ih_ks_template.ihks_buspath, ih_buspath); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate return (0); 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate void 180*7c478bd9Sstevel@tonic-gate px_ib_intr_enable(px_t *px_p, cpuid_t cpu_id, devino_t ino) 181*7c478bd9Sstevel@tonic-gate { 182*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 183*7c478bd9Sstevel@tonic-gate sysino_t sysino; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * Determine the cpu for the interrupt 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 191*7c478bd9Sstevel@tonic-gate "px_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(px_p->px_dip, ino, 194*7c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 195*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 196*7c478bd9Sstevel@tonic-gate "px_ib_intr_enable: px_intr_devino_to_sysino() failed\n"); 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 199*7c478bd9Sstevel@tonic-gate return; 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(px_p->px_dip, sysino, cpu_id); 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 205*7c478bd9Sstevel@tonic-gate } 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 208*7c478bd9Sstevel@tonic-gate void 209*7c478bd9Sstevel@tonic-gate px_ib_intr_disable(px_ib_t *ib_p, devino_t ino, int wait) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate sysino_t sysino; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_disable: ino=%x\n", ino); 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 218*7c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino, 219*7c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) { 220*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, 221*7c478bd9Sstevel@tonic-gate "px_ib_intr_disable: px_intr_devino_to_sysino() failed\n"); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 224*7c478bd9Sstevel@tonic-gate return; 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(ib_p->ib_px_p->px_dip, sysino); 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate static void 234*7c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, 235*7c478bd9Sstevel@tonic-gate boolean_t wait_flag) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate uint32_t old_cpu_id; 238*7c478bd9Sstevel@tonic-gate sysino_t sysino; 239*7c478bd9Sstevel@tonic-gate intr_valid_state_t enabled = 0; 240*7c478bd9Sstevel@tonic-gate hrtime_t start_time; 241*7c478bd9Sstevel@tonic-gate intr_state_t intr_state; 242*7c478bd9Sstevel@tonic-gate int e; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: ino=0x%x\n", ino); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, &sysino) != DDI_SUCCESS) { 247*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 248*7c478bd9Sstevel@tonic-gate "px_intr_devino_to_sysino() failed, ino 0x%x\n", ino); 249*7c478bd9Sstevel@tonic-gate return; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* Skip enabling disabled interrupts */ 253*7c478bd9Sstevel@tonic-gate if (px_lib_intr_getvalid(dip, sysino, &enabled) != DDI_SUCCESS) { 254*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: px_intr_getvalid() " 255*7c478bd9Sstevel@tonic-gate "failed, sysino 0x%x\n", sysino); 256*7c478bd9Sstevel@tonic-gate return; 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate if (!enabled) 259*7c478bd9Sstevel@tonic-gate return; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate /* Done if redistributed onto the same cpuid */ 262*7c478bd9Sstevel@tonic-gate if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) != DDI_SUCCESS) { 263*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: " 264*7c478bd9Sstevel@tonic-gate "px_intr_gettarget() failed\n"); 265*7c478bd9Sstevel@tonic-gate return; 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate if (cpu_id == old_cpu_id) 268*7c478bd9Sstevel@tonic-gate return; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate if (!wait_flag) 271*7c478bd9Sstevel@tonic-gate goto done; 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupts */ 274*7c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 277*7c478bd9Sstevel@tonic-gate ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == 278*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) && 279*7c478bd9Sstevel@tonic-gate (intr_state == INTR_DELIVERED_STATE); /* */) { 280*7c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 281*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 282*7c478bd9Sstevel@tonic-gate "%s%d: px_ib_intr_dist_en: sysino 0x%x(ino 0x%x) " 283*7c478bd9Sstevel@tonic-gate "from cpu id 0x%x to 0x%x timeout", 284*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 285*7c478bd9Sstevel@tonic-gate sysino, ino, old_cpu_id, cpu_id); 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate e = DDI_FAILURE; 288*7c478bd9Sstevel@tonic-gate break; 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate if (e != DDI_SUCCESS) 293*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_intr_dist_en: failed, " 294*7c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate done: 297*7c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, cpu_id); 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* 302*7c478bd9Sstevel@tonic-gate * Redistribute interrupts of the specified weight. The first call has a weight 303*7c478bd9Sstevel@tonic-gate * of weight_max, which can be used to trigger initialization for 304*7c478bd9Sstevel@tonic-gate * redistribution. The inos with weight [weight_max, inf.) should be processed 305*7c478bd9Sstevel@tonic-gate * on the "weight == weight_max" call. This first call is followed by calls 306*7c478bd9Sstevel@tonic-gate * of decreasing weights, inos of that weight should be processed. The final 307*7c478bd9Sstevel@tonic-gate * call specifies a weight of zero, this can be used to trigger processing of 308*7c478bd9Sstevel@tonic-gate * stragglers. 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate static void 311*7c478bd9Sstevel@tonic-gate px_ib_intr_redist(void *arg, int32_t weight_max, int32_t weight) 312*7c478bd9Sstevel@tonic-gate { 313*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 314*7c478bd9Sstevel@tonic-gate px_t *px_p = ib_p->ib_px_p; 315*7c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 316*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 317*7c478bd9Sstevel@tonic-gate px_ih_t *ih_lst; 318*7c478bd9Sstevel@tonic-gate int32_t dweight = 0; 319*7c478bd9Sstevel@tonic-gate int i; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* Redistribute internal interrupts */ 322*7c478bd9Sstevel@tonic-gate if (weight == 0) { 323*7c478bd9Sstevel@tonic-gate devino_t ino_pec = px_p->px_inos[PX_INTR_PEC]; 324*7c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock); 325*7c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, intr_dist_cpuid(), ino_pec, B_FALSE); 326*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* Redistribute device interrupts */ 330*7c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) { 333*7c478bd9Sstevel@tonic-gate uint32_t orig_cpuid; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * Recomputes the sum of interrupt weights of devices that 337*7c478bd9Sstevel@tonic-gate * share the same ino upon first call marked by 338*7c478bd9Sstevel@tonic-gate * (weight == weight_max). 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate if (weight == weight_max) { 341*7c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight = 0; 342*7c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 343*7c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 344*7c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 345*7c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 346*7c478bd9Sstevel@tonic-gate if (dweight > 0) 347*7c478bd9Sstevel@tonic-gate ino_p->ino_intr_weight += dweight; 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * As part of redistributing weighted interrupts over cpus, 353*7c478bd9Sstevel@tonic-gate * nexus redistributes device interrupts and updates 354*7c478bd9Sstevel@tonic-gate * cpu weight. The purpose is for the most light weighted 355*7c478bd9Sstevel@tonic-gate * cpu to take the next interrupt and gain weight, therefore 356*7c478bd9Sstevel@tonic-gate * attention demanding device gains more cpu attention by 357*7c478bd9Sstevel@tonic-gate * making itself heavy. 358*7c478bd9Sstevel@tonic-gate */ 359*7c478bd9Sstevel@tonic-gate if ((weight == ino_p->ino_intr_weight) || 360*7c478bd9Sstevel@tonic-gate ((weight >= weight_max) && 361*7c478bd9Sstevel@tonic-gate (ino_p->ino_intr_weight >= weight_max))) { 362*7c478bd9Sstevel@tonic-gate orig_cpuid = ino_p->ino_cpuid; 363*7c478bd9Sstevel@tonic-gate if (cpu[orig_cpuid] == NULL) 364*7c478bd9Sstevel@tonic-gate orig_cpuid = CPU->cpu_id; 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* select cpuid to target and mark ino established */ 367*7c478bd9Sstevel@tonic-gate ino_p->ino_cpuid = intr_dist_cpuid(); 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate /* Add device weight to targeted cpu. */ 370*7c478bd9Sstevel@tonic-gate for (i = 0, ih_lst = ino_p->ino_ih_head; 371*7c478bd9Sstevel@tonic-gate i < ino_p->ino_ih_size; 372*7c478bd9Sstevel@tonic-gate i++, ih_lst = ih_lst->ih_next) { 373*7c478bd9Sstevel@tonic-gate hrtime_t ticks; 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); 376*7c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight( 377*7c478bd9Sstevel@tonic-gate ino_p->ino_cpuid, ih_lst->ih_dip, dweight); 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /* 380*7c478bd9Sstevel@tonic-gate * different cpus may have different clock 381*7c478bd9Sstevel@tonic-gate * speeds. to account for this, whenever an 382*7c478bd9Sstevel@tonic-gate * interrupt is moved to a new CPU, we 383*7c478bd9Sstevel@tonic-gate * convert the accumulated ticks into nsec, 384*7c478bd9Sstevel@tonic-gate * based upon the clock rate of the prior 385*7c478bd9Sstevel@tonic-gate * CPU. 386*7c478bd9Sstevel@tonic-gate * 387*7c478bd9Sstevel@tonic-gate * It is possible that the prior CPU no longer 388*7c478bd9Sstevel@tonic-gate * exists. In this case, fall back to using 389*7c478bd9Sstevel@tonic-gate * this CPU's clock rate. 390*7c478bd9Sstevel@tonic-gate * 391*7c478bd9Sstevel@tonic-gate * Note that the value in ih_ticks has already 392*7c478bd9Sstevel@tonic-gate * been corrected for any power savings mode 393*7c478bd9Sstevel@tonic-gate * which might have been in effect. 394*7c478bd9Sstevel@tonic-gate * 395*7c478bd9Sstevel@tonic-gate * because we are updating two fields in 396*7c478bd9Sstevel@tonic-gate * ih_t we must lock ih_ks_template_lock to 397*7c478bd9Sstevel@tonic-gate * prevent someone from reading the kstats 398*7c478bd9Sstevel@tonic-gate * after we set ih_ticks to 0 and before we 399*7c478bd9Sstevel@tonic-gate * increment ih_nsec to compensate. 400*7c478bd9Sstevel@tonic-gate * 401*7c478bd9Sstevel@tonic-gate * we must also protect against the interrupt 402*7c478bd9Sstevel@tonic-gate * arriving and incrementing ih_ticks between 403*7c478bd9Sstevel@tonic-gate * the time we read it and when we reset it 404*7c478bd9Sstevel@tonic-gate * to 0. To do this we use atomic_swap. 405*7c478bd9Sstevel@tonic-gate */ 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate mutex_enter(&ih_ks_template_lock); 408*7c478bd9Sstevel@tonic-gate ticks = atomic_swap_64(&ih_lst->ih_ticks, 0); 409*7c478bd9Sstevel@tonic-gate ih_lst->ih_nsec += (uint64_t) 410*7c478bd9Sstevel@tonic-gate tick2ns(ticks, orig_cpuid); 411*7c478bd9Sstevel@tonic-gate mutex_exit(&ih_ks_template_lock); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate /* enable interrupt on new targeted cpu */ 415*7c478bd9Sstevel@tonic-gate px_ib_intr_dist_en(dip, ino_p->ino_cpuid, 416*7c478bd9Sstevel@tonic-gate ino_p->ino_ino, B_TRUE); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate /* 423*7c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 424*7c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 425*7c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 426*7c478bd9Sstevel@tonic-gate * 427*7c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 428*7c478bd9Sstevel@tonic-gate * are permanently suspended. 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate static uint_t 431*7c478bd9Sstevel@tonic-gate px_ib_intr_reset(void *arg) 432*7c478bd9Sstevel@tonic-gate { 433*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = (px_ib_t *)arg; 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, ib_p->ib_px_p->px_dip, "px_ib_intr_reset\n"); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate if (px_lib_intr_reset(ib_p->ib_px_p->px_dip) != DDI_SUCCESS) 438*7c478bd9Sstevel@tonic-gate return (BF_FATAL); 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate return (BF_NONE); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * Locate ino_info structure on ib_p->ib_ino_lst according to ino# 445*7c478bd9Sstevel@tonic-gate * returns NULL if not found. 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 448*7c478bd9Sstevel@tonic-gate px_ib_locate_ino(px_ib_t *ib_p, devino_t ino_num) 449*7c478bd9Sstevel@tonic-gate { 450*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = ib_p->ib_ino_lst; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate for (; ino_p && ino_p->ino_ino != ino_num; ino_p = ino_p->ino_next); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate return (ino_p); 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t * 460*7c478bd9Sstevel@tonic-gate px_ib_new_ino(px_ib_t *ib_p, devino_t ino_num, px_ih_t *ih_p) 461*7c478bd9Sstevel@tonic-gate { 462*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p = kmem_alloc(sizeof (px_ib_ino_info_t), 463*7c478bd9Sstevel@tonic-gate KM_SLEEP); 464*7c478bd9Sstevel@tonic-gate sysino_t sysino; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate ino_p->ino_ino = ino_num; 467*7c478bd9Sstevel@tonic-gate ino_p->ino_ib_p = ib_p; 468*7c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(ib_p->ib_px_p->px_dip, ino_p->ino_ino, 471*7c478bd9Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 472*7c478bd9Sstevel@tonic-gate return (NULL); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate ino_p->ino_sysino = sysino; 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate /* 477*7c478bd9Sstevel@tonic-gate * Cannot disable interrupt since we might share slot 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate ih_p->ih_next = ih_p; 480*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p; 481*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 482*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ih_p; 483*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_size = 1; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate ino_p->ino_next = ib_p->ib_ino_lst; 486*7c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = ino_p; 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate return (ino_p); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate /* 492*7c478bd9Sstevel@tonic-gate * The ino_p is retrieved by previous call to px_ib_locate_ino(). 493*7c478bd9Sstevel@tonic-gate */ 494*7c478bd9Sstevel@tonic-gate void 495*7c478bd9Sstevel@tonic-gate px_ib_delete_ino(px_ib_t *ib_p, px_ib_ino_info_t *ino_p) 496*7c478bd9Sstevel@tonic-gate { 497*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *list = ib_p->ib_ino_lst; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate if (list == ino_p) 502*7c478bd9Sstevel@tonic-gate ib_p->ib_ino_lst = list->ino_next; 503*7c478bd9Sstevel@tonic-gate else { 504*7c478bd9Sstevel@tonic-gate for (; list->ino_next != ino_p; list = list->ino_next); 505*7c478bd9Sstevel@tonic-gate list->ino_next = ino_p->ino_next; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate /* 510*7c478bd9Sstevel@tonic-gate * Free all ino when we are detaching. 511*7c478bd9Sstevel@tonic-gate */ 512*7c478bd9Sstevel@tonic-gate void 513*7c478bd9Sstevel@tonic-gate px_ib_free_ino_all(px_ib_t *ib_p) 514*7c478bd9Sstevel@tonic-gate { 515*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *tmp = ib_p->ib_ino_lst; 516*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *next = NULL; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate while (tmp) { 519*7c478bd9Sstevel@tonic-gate next = tmp->ino_next; 520*7c478bd9Sstevel@tonic-gate kmem_free(tmp, sizeof (px_ib_ino_info_t)); 521*7c478bd9Sstevel@tonic-gate tmp = next; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate int 526*7c478bd9Sstevel@tonic-gate px_ib_ino_add_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 527*7c478bd9Sstevel@tonic-gate { 528*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = ino_p->ino_ib_p; 529*7c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 530*7c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 531*7c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 532*7c478bd9Sstevel@tonic-gate cpuid_t curr_cpu; 533*7c478bd9Sstevel@tonic-gate hrtime_t start_time; 534*7c478bd9Sstevel@tonic-gate intr_state_t intr_state; 535*7c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 538*7c478bd9Sstevel@tonic-gate ASSERT(ib_p == px_p->px_ib_p); 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr ino=%x\n", ino_p->ino_ino); 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 543*7c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_gettarget(dip, sysino, 544*7c478bd9Sstevel@tonic-gate &curr_cpu)) != DDI_SUCCESS) { 545*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, 546*7c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_gettarget() failed\n"); 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate return (ret); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(dip, sysino); 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 554*7c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 555*7c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 556*7c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 557*7c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 558*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_add_intr: pending " 559*7c478bd9Sstevel@tonic-gate "sysino 0x%x(ino 0x%x) timeout", 560*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 561*7c478bd9Sstevel@tonic-gate sysino, ino); 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 564*7c478bd9Sstevel@tonic-gate break; 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 569*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_add_intr: failed, " 570*7c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate return (ret); 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate /* Link up px_ispec_t portion of the ppd */ 576*7c478bd9Sstevel@tonic-gate ih_p->ih_next = ino_p->ino_ih_head; 577*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail->ih_next = ih_p; 578*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_p; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 581*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_size++; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate /* 584*7c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 585*7c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 586*7c478bd9Sstevel@tonic-gate * jabber has gone away. 587*7c478bd9Sstevel@tonic-gate */ 588*7c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 589*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 590*7c478bd9Sstevel@tonic-gate "%s%d: px_ib_ino_add_intr: ino 0x%x has been unblocked", 591*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 594*7c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 595*7c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 596*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 597*7c478bd9Sstevel@tonic-gate "px_ib_ino_add_intr px_intr_setstate failed\n"); 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate return (ret); 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* Re-enable interrupt */ 604*7c478bd9Sstevel@tonic-gate PX_INTR_ENABLE(dip, sysino, curr_cpu); 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate return (ret); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate /* 610*7c478bd9Sstevel@tonic-gate * Removes px_ispec_t from the ino's link list. 611*7c478bd9Sstevel@tonic-gate * uses hardware mutex to lock out interrupt threads. 612*7c478bd9Sstevel@tonic-gate * Side effects: interrupt belongs to that ino is turned off on return. 613*7c478bd9Sstevel@tonic-gate * if we are sharing PX slot with other inos, the caller needs 614*7c478bd9Sstevel@tonic-gate * to turn it back on. 615*7c478bd9Sstevel@tonic-gate */ 616*7c478bd9Sstevel@tonic-gate int 617*7c478bd9Sstevel@tonic-gate px_ib_ino_rem_intr(px_t *px_p, px_ib_ino_info_t *ino_p, px_ih_t *ih_p) 618*7c478bd9Sstevel@tonic-gate { 619*7c478bd9Sstevel@tonic-gate devino_t ino = ino_p->ino_ino; 620*7c478bd9Sstevel@tonic-gate sysino_t sysino = ino_p->ino_sysino; 621*7c478bd9Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 622*7c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 623*7c478bd9Sstevel@tonic-gate hrtime_t start_time; 624*7c478bd9Sstevel@tonic-gate intr_state_t intr_state; 625*7c478bd9Sstevel@tonic-gate int i, ret = DDI_SUCCESS; 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ino_p->ino_ib_p->ib_ino_lst_mutex)); 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "px_ib_ino_rem_intr ino=%x\n", 630*7c478bd9Sstevel@tonic-gate ino_p->ino_ino); 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* Disable the interrupt */ 633*7c478bd9Sstevel@tonic-gate PX_INTR_DISABLE(px_p->px_dip, sysino); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_size == 1) { 636*7c478bd9Sstevel@tonic-gate if (ih_lst != ih_p) 637*7c478bd9Sstevel@tonic-gate goto not_found; 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate /* No need to set head/tail as ino_p will be freed */ 640*7c478bd9Sstevel@tonic-gate goto reset; 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* Busy wait on pending interrupt */ 644*7c478bd9Sstevel@tonic-gate for (start_time = gethrtime(); !panicstr && 645*7c478bd9Sstevel@tonic-gate ((ret = px_lib_intr_getstate(dip, sysino, &intr_state)) 646*7c478bd9Sstevel@tonic-gate == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { 647*7c478bd9Sstevel@tonic-gate if (gethrtime() - start_time > px_intrpend_timeout) { 648*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: pending " 649*7c478bd9Sstevel@tonic-gate "sysino 0x%x(ino 0x%x) timeout", 650*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 651*7c478bd9Sstevel@tonic-gate sysino, ino); 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 654*7c478bd9Sstevel@tonic-gate break; 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 659*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, dip, "px_ib_ino_rem_intr: failed, " 660*7c478bd9Sstevel@tonic-gate "ino 0x%x sysino 0x%x\n", ino, sysino); 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate return (ret); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate /* 666*7c478bd9Sstevel@tonic-gate * If the interrupt was previously blocked (left in pending state) 667*7c478bd9Sstevel@tonic-gate * because of jabber we need to clear the pending state in case the 668*7c478bd9Sstevel@tonic-gate * jabber has gone away. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate if (ino_p->ino_unclaimed > px_unclaimed_intr_max) { 671*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_ib_ino_rem_intr: " 672*7c478bd9Sstevel@tonic-gate "ino 0x%x has been unblocked", 673*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino); 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate ino_p->ino_unclaimed = 0; 676*7c478bd9Sstevel@tonic-gate if ((ret = px_lib_intr_setstate(dip, sysino, 677*7c478bd9Sstevel@tonic-gate INTR_IDLE_STATE)) != DDI_SUCCESS) { 678*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, 679*7c478bd9Sstevel@tonic-gate "px_ib_ino_rem_intr px_intr_setstate failed\n"); 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate return (ret); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* Search the link list for ih_p */ 686*7c478bd9Sstevel@tonic-gate for (i = 0; (i < ino_p->ino_ih_size) && 687*7c478bd9Sstevel@tonic-gate (ih_lst->ih_next != ih_p); i++, ih_lst = ih_lst->ih_next); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate if (ih_lst->ih_next != ih_p) 690*7c478bd9Sstevel@tonic-gate goto not_found; 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* Remove ih_p from the link list and maintain the head/tail */ 693*7c478bd9Sstevel@tonic-gate ih_lst->ih_next = ih_p->ih_next; 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_head == ih_p) 696*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_head = ih_p->ih_next; 697*7c478bd9Sstevel@tonic-gate if (ino_p->ino_ih_tail == ih_p) 698*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_tail = ih_lst; 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_start = ino_p->ino_ih_head; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate reset: 703*7c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle) 704*7c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle); 705*7c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) 706*7c478bd9Sstevel@tonic-gate kstat_delete(ih_p->ih_ksp); 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (px_ih_t)); 709*7c478bd9Sstevel@tonic-gate ino_p->ino_ih_size--; 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate return (ret); 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate not_found: 714*7c478bd9Sstevel@tonic-gate DBG(DBG_R_INTX, ino_p->ino_ib_p->ib_px_p->px_dip, 715*7c478bd9Sstevel@tonic-gate "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate px_ih_t * 721*7c478bd9Sstevel@tonic-gate px_ib_ino_locate_intr(px_ib_ino_info_t *ino_p, dev_info_t *rdip, 722*7c478bd9Sstevel@tonic-gate uint32_t inum, msiq_rec_type_t rec_type, msgcode_t msg_code) 723*7c478bd9Sstevel@tonic-gate { 724*7c478bd9Sstevel@tonic-gate px_ih_t *ih_lst = ino_p->ino_ih_head; 725*7c478bd9Sstevel@tonic-gate int i; 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate for (i = 0; i < ino_p->ino_ih_size; i++, ih_lst = ih_lst->ih_next) { 728*7c478bd9Sstevel@tonic-gate if ((ih_lst->ih_dip == rdip) && (ih_lst->ih_inum == inum) && 729*7c478bd9Sstevel@tonic-gate (ih_lst->ih_rec_type == rec_type) && 730*7c478bd9Sstevel@tonic-gate (ih_lst->ih_msg_code == msg_code)) 731*7c478bd9Sstevel@tonic-gate return (ih_lst); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate return ((px_ih_t *)NULL); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate px_ih_t * 738*7c478bd9Sstevel@tonic-gate px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, 739*7c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), 740*7c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1, caddr_t int_handler_arg2, 741*7c478bd9Sstevel@tonic-gate msiq_rec_type_t rec_type, msgcode_t msg_code) 742*7c478bd9Sstevel@tonic-gate { 743*7c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate ih_p = kmem_alloc(sizeof (px_ih_t), KM_SLEEP); 746*7c478bd9Sstevel@tonic-gate ih_p->ih_dip = rdip; 747*7c478bd9Sstevel@tonic-gate ih_p->ih_inum = inum; 748*7c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = PX_INTR_STATE_DISABLE; 749*7c478bd9Sstevel@tonic-gate ih_p->ih_handler = int_handler; 750*7c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1 = int_handler_arg1; 751*7c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg2 = int_handler_arg2; 752*7c478bd9Sstevel@tonic-gate ih_p->ih_config_handle = NULL; 753*7c478bd9Sstevel@tonic-gate ih_p->ih_rec_type = rec_type; 754*7c478bd9Sstevel@tonic-gate ih_p->ih_msg_code = msg_code; 755*7c478bd9Sstevel@tonic-gate ih_p->ih_nsec = 0; 756*7c478bd9Sstevel@tonic-gate ih_p->ih_ticks = 0; 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* 759*7c478bd9Sstevel@tonic-gate * Create pci_intrs::: kstats for all ih types except messages, 760*7c478bd9Sstevel@tonic-gate * which represent unusual conditions and don't need to be tracked. 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp = NULL; 763*7c478bd9Sstevel@tonic-gate if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 764*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp = kstat_create("pci_intrs", 765*7c478bd9Sstevel@tonic-gate atomic_inc_32_nv(&ih_instance), "config", "interrupts", 766*7c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 767*7c478bd9Sstevel@tonic-gate sizeof (px_ih_ks_template) / sizeof (kstat_named_t), 768*7c478bd9Sstevel@tonic-gate KSTAT_FLAG_VIRTUAL); 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate if (ih_p->ih_ksp != NULL) { 771*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 772*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_lock = &ih_ks_template_lock; 773*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_data = &px_ih_ks_template; 774*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_private = ih_p; 775*7c478bd9Sstevel@tonic-gate ih_p->ih_ksp->ks_update = ih_ks_update; 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate return (ih_p); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate /* 782*7c478bd9Sstevel@tonic-gate * Only used for fixed or legacy interrupts. 783*7c478bd9Sstevel@tonic-gate */ 784*7c478bd9Sstevel@tonic-gate int 785*7c478bd9Sstevel@tonic-gate px_ib_update_intr_state(px_t *px_p, dev_info_t *rdip, 786*7c478bd9Sstevel@tonic-gate uint_t inum, devino_t ino, uint_t new_intr_state) 787*7c478bd9Sstevel@tonic-gate { 788*7c478bd9Sstevel@tonic-gate px_ib_t *ib_p = px_p->px_ib_p; 789*7c478bd9Sstevel@tonic-gate px_ib_ino_info_t *ino_p; 790*7c478bd9Sstevel@tonic-gate px_ih_t *ih_p; 791*7c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate DBG(DBG_IB, px_p->px_dip, "ib_update_intr_state: %s%d " 794*7c478bd9Sstevel@tonic-gate "inum %x devino %x state %x\n", ddi_driver_name(rdip), 795*7c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), inum, ino, new_intr_state); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex); 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate if (ino_p = px_ib_locate_ino(ib_p, ino)) { 800*7c478bd9Sstevel@tonic-gate if (ih_p = px_ib_ino_locate_intr(ino_p, rdip, inum, 0, 0)) { 801*7c478bd9Sstevel@tonic-gate ih_p->ih_intr_state = new_intr_state; 802*7c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex); 807*7c478bd9Sstevel@tonic-gate return (ret); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate int 811*7c478bd9Sstevel@tonic-gate px_imu_intr(dev_info_t *dip, px_fh_t *fh_p) 812*7c478bd9Sstevel@tonic-gate { 813*7c478bd9Sstevel@tonic-gate uint32_t offset = px_fhd_tbl[fh_p->fh_err_id].fhd_st; 814*7c478bd9Sstevel@tonic-gate uint64_t stat = fh_p->fh_stat; 815*7c478bd9Sstevel@tonic-gate if (stat) 816*7c478bd9Sstevel@tonic-gate LOG(DBG_ERR_INTR, dip, "[%x]=%16llx imu stat\n", offset, stat); 817*7c478bd9Sstevel@tonic-gate return (stat ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 818*7c478bd9Sstevel@tonic-gate } 819