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