1*25cf1a30Sjl /* 2*25cf1a30Sjl * CDDL HEADER START 3*25cf1a30Sjl * 4*25cf1a30Sjl * The contents of this file are subject to the terms of the 5*25cf1a30Sjl * Common Development and Distribution License (the "License"). 6*25cf1a30Sjl * You may not use this file except in compliance with the License. 7*25cf1a30Sjl * 8*25cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*25cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 10*25cf1a30Sjl * See the License for the specific language governing permissions 11*25cf1a30Sjl * and limitations under the License. 12*25cf1a30Sjl * 13*25cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 14*25cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*25cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 16*25cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 17*25cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*25cf1a30Sjl * 19*25cf1a30Sjl * CDDL HEADER END 20*25cf1a30Sjl */ 21*25cf1a30Sjl /* 22*25cf1a30Sjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*25cf1a30Sjl * Use is subject to license terms. 24*25cf1a30Sjl */ 25*25cf1a30Sjl 26*25cf1a30Sjl #pragma ident "%Z%%M% %I% %E% SMI" 27*25cf1a30Sjl 28*25cf1a30Sjl /* 29*25cf1a30Sjl * CMU-CH PBM implementation: 30*25cf1a30Sjl * initialization 31*25cf1a30Sjl * Bus error interrupt handler 32*25cf1a30Sjl */ 33*25cf1a30Sjl 34*25cf1a30Sjl #include <sys/types.h> 35*25cf1a30Sjl #include <sys/kmem.h> 36*25cf1a30Sjl #include <sys/spl.h> 37*25cf1a30Sjl #include <sys/sysmacros.h> 38*25cf1a30Sjl #include <sys/sunddi.h> 39*25cf1a30Sjl #include <sys/fm/protocol.h> 40*25cf1a30Sjl #include <sys/fm/util.h> 41*25cf1a30Sjl #include <sys/machsystm.h> 42*25cf1a30Sjl #include <sys/async.h> 43*25cf1a30Sjl #include <sys/ddi_impldefs.h> 44*25cf1a30Sjl #include <sys/ontrap.h> 45*25cf1a30Sjl #include <sys/pcicmu/pcicmu.h> 46*25cf1a30Sjl #include <sys/membar.h> 47*25cf1a30Sjl #include <sys/ivintr.h> 48*25cf1a30Sjl 49*25cf1a30Sjl /*LINTLIBRARY*/ 50*25cf1a30Sjl 51*25cf1a30Sjl static uint_t pcmu_pbm_error_intr(caddr_t a); 52*25cf1a30Sjl 53*25cf1a30Sjl /* The nexus interrupt priority values */ 54*25cf1a30Sjl int pcmu_pil[] = {14, 14, 14, 14, 14, 14}; 55*25cf1a30Sjl 56*25cf1a30Sjl void 57*25cf1a30Sjl pcmu_pbm_create(pcmu_t *pcmu_p) 58*25cf1a30Sjl { 59*25cf1a30Sjl pcmu_pbm_t *pcbm_p; 60*25cf1a30Sjl int len; 61*25cf1a30Sjl dev_info_t *dip = pcmu_p->pcmu_dip; 62*25cf1a30Sjl 63*25cf1a30Sjl /* 64*25cf1a30Sjl * Allocate a state structure for the PBM and cross-link it 65*25cf1a30Sjl * to its per pci node state structure. 66*25cf1a30Sjl */ 67*25cf1a30Sjl pcbm_p = (pcmu_pbm_t *)kmem_zalloc(sizeof (pcmu_pbm_t), KM_SLEEP); 68*25cf1a30Sjl pcmu_p->pcmu_pcbm_p = pcbm_p; 69*25cf1a30Sjl pcbm_p->pcbm_pcmu_p = pcmu_p; 70*25cf1a30Sjl 71*25cf1a30Sjl len = snprintf(pcbm_p->pcbm_nameinst_str, 72*25cf1a30Sjl sizeof (pcbm_p->pcbm_nameinst_str), "%s%d", NAMEINST(dip)); 73*25cf1a30Sjl pcbm_p->pcbm_nameaddr_str = pcbm_p->pcbm_nameinst_str + ++len; 74*25cf1a30Sjl (void) snprintf(pcbm_p->pcbm_nameaddr_str, 75*25cf1a30Sjl sizeof (pcbm_p->pcbm_nameinst_str) - len, "%s@%s", NAMEADDR(dip)); 76*25cf1a30Sjl 77*25cf1a30Sjl pcmu_pbm_setup(pcbm_p); 78*25cf1a30Sjl 79*25cf1a30Sjl PCMU_DBG4(PCMU_DBG_ATTACH, dip, 80*25cf1a30Sjl "pcmu_pbm_create: ctrl=%x, afsr=%x, afar=%x, diag=%x\n", 81*25cf1a30Sjl pcbm_p->pcbm_ctrl_reg, pcbm_p->pcbm_async_flt_status_reg, 82*25cf1a30Sjl pcbm_p->pcbm_async_flt_addr_reg, pcbm_p->pcbm_diag_reg); 83*25cf1a30Sjl PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: conf=%x\n", 84*25cf1a30Sjl pcbm_p->pcbm_config_header); 85*25cf1a30Sjl 86*25cf1a30Sjl /* 87*25cf1a30Sjl * Register a function to disable pbm error interrupts during a panic. 88*25cf1a30Sjl */ 89*25cf1a30Sjl bus_func_register(BF_TYPE_ERRDIS, 90*25cf1a30Sjl (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); 91*25cf1a30Sjl 92*25cf1a30Sjl /* 93*25cf1a30Sjl * create the interrupt-priorities property if it doesn't 94*25cf1a30Sjl * already exist to provide a hint as to the PIL level for 95*25cf1a30Sjl * our interrupt. 96*25cf1a30Sjl */ 97*25cf1a30Sjl if (ddi_getproplen(DDI_DEV_T_ANY, dip, 98*25cf1a30Sjl DDI_PROP_DONTPASS, "interrupt-priorities", 99*25cf1a30Sjl &len) != DDI_PROP_SUCCESS) { 100*25cf1a30Sjl /* Create the interrupt-priorities property. */ 101*25cf1a30Sjl (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 102*25cf1a30Sjl DDI_PROP_CANSLEEP, "interrupt-priorities", 103*25cf1a30Sjl (caddr_t)pcmu_pil, sizeof (pcmu_pil)); 104*25cf1a30Sjl } 105*25cf1a30Sjl pcmu_pbm_configure(pcbm_p); 106*25cf1a30Sjl } 107*25cf1a30Sjl 108*25cf1a30Sjl int 109*25cf1a30Sjl pcmu_pbm_register_intr(pcmu_pbm_t *pcbm_p) 110*25cf1a30Sjl { 111*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 112*25cf1a30Sjl uint32_t mondo; 113*25cf1a30Sjl int r = DDI_SUCCESS; 114*25cf1a30Sjl 115*25cf1a30Sjl pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 116*25cf1a30Sjl 117*25cf1a30Sjl /* 118*25cf1a30Sjl * Install the PCI error interrupt handler. 119*25cf1a30Sjl */ 120*25cf1a30Sjl mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, 121*25cf1a30Sjl pcmu_p->pcmu_inos[CBNINTR_PBM]); 122*25cf1a30Sjl 123*25cf1a30Sjl VERIFY(add_ivintr(mondo, pcmu_pil[CBNINTR_PBM], pcmu_pbm_error_intr, 124*25cf1a30Sjl (caddr_t)pcmu_p, NULL) == 0); 125*25cf1a30Sjl 126*25cf1a30Sjl pcbm_p->pcbm_iblock_cookie = (void *)(uintptr_t)pcmu_pil[CBNINTR_PBM]; 127*25cf1a30Sjl 128*25cf1a30Sjl /* 129*25cf1a30Sjl * Create the pokefault mutex at the PIL below the error interrupt. 130*25cf1a30Sjl */ 131*25cf1a30Sjl 132*25cf1a30Sjl mutex_init(&pcbm_p->pcbm_pokeflt_mutex, NULL, MUTEX_DRIVER, 133*25cf1a30Sjl (void *)(uintptr_t)ipltospl(spltoipl( 134*25cf1a30Sjl (int)(uintptr_t)pcbm_p->pcbm_iblock_cookie) - 1)); 135*25cf1a30Sjl 136*25cf1a30Sjl return (PCMU_ATTACH_RETCODE(PCMU_PBM_OBJ, PCMU_OBJ_INTR_ADD, r)); 137*25cf1a30Sjl } 138*25cf1a30Sjl 139*25cf1a30Sjl void 140*25cf1a30Sjl pcmu_pbm_destroy(pcmu_t *pcmu_p) 141*25cf1a30Sjl { 142*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 143*25cf1a30Sjl pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 144*25cf1a30Sjl uint32_t mondo; 145*25cf1a30Sjl 146*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_DETACH, pcmu_p->pcmu_dip, "pcmu_pbm_destroy:\n"); 147*25cf1a30Sjl 148*25cf1a30Sjl mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, 149*25cf1a30Sjl pcmu_p->pcmu_inos[CBNINTR_PBM]); 150*25cf1a30Sjl 151*25cf1a30Sjl /* 152*25cf1a30Sjl * Free the pokefault mutex. 153*25cf1a30Sjl */ 154*25cf1a30Sjl mutex_destroy(&pcbm_p->pcbm_pokeflt_mutex); 155*25cf1a30Sjl 156*25cf1a30Sjl /* 157*25cf1a30Sjl * Remove the error interrupt. 158*25cf1a30Sjl */ 159*25cf1a30Sjl intr_dist_rem(pcmu_pbm_intr_dist, pcbm_p); 160*25cf1a30Sjl pcmu_ib_intr_disable(pib_p, 161*25cf1a30Sjl pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_WAIT); 162*25cf1a30Sjl rem_ivintr(mondo, NULL); 163*25cf1a30Sjl 164*25cf1a30Sjl /* 165*25cf1a30Sjl * Remove the error disable function. 166*25cf1a30Sjl */ 167*25cf1a30Sjl bus_func_unregister(BF_TYPE_ERRDIS, 168*25cf1a30Sjl (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); 169*25cf1a30Sjl 170*25cf1a30Sjl pcmu_pbm_teardown(pcbm_p); 171*25cf1a30Sjl 172*25cf1a30Sjl /* 173*25cf1a30Sjl * Free the pbm state structure. 174*25cf1a30Sjl */ 175*25cf1a30Sjl kmem_free(pcbm_p, sizeof (pcmu_pbm_t)); 176*25cf1a30Sjl pcmu_p->pcmu_pcbm_p = NULL; 177*25cf1a30Sjl } 178*25cf1a30Sjl 179*25cf1a30Sjl static uint_t 180*25cf1a30Sjl pcmu_pbm_error_intr(caddr_t a) 181*25cf1a30Sjl { 182*25cf1a30Sjl pcmu_t *pcmu_p = (pcmu_t *)a; 183*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 184*25cf1a30Sjl ddi_fm_error_t derr; 185*25cf1a30Sjl int err = DDI_FM_OK; 186*25cf1a30Sjl on_trap_data_t *otp = pcbm_p->pcbm_ontrap_data; 187*25cf1a30Sjl 188*25cf1a30Sjl bzero(&derr, sizeof (ddi_fm_error_t)); 189*25cf1a30Sjl derr.fme_version = DDI_FME_VERSION; 190*25cf1a30Sjl mutex_enter(&pcmu_p->pcmu_err_mutex); 191*25cf1a30Sjl if ((otp != NULL) && (otp->ot_prot & OT_DATA_ACCESS)) { 192*25cf1a30Sjl /* 193*25cf1a30Sjl * ddi_poke protection, check nexus and children for 194*25cf1a30Sjl * expected errors. 195*25cf1a30Sjl */ 196*25cf1a30Sjl otp->ot_trap |= OT_DATA_ACCESS; 197*25cf1a30Sjl membar_sync(); 198*25cf1a30Sjl derr.fme_flag = DDI_FM_ERR_POKE; 199*25cf1a30Sjl err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, 200*25cf1a30Sjl (void *)pcmu_p, PCI_INTR_CALL); 201*25cf1a30Sjl } else if (pcmu_check_error(pcmu_p) != 0) { 202*25cf1a30Sjl /* 203*25cf1a30Sjl * unprotected error, check for all errors. 204*25cf1a30Sjl */ 205*25cf1a30Sjl if (pcmu_errtrig_pa) { 206*25cf1a30Sjl (void) ldphysio(pcmu_errtrig_pa); 207*25cf1a30Sjl } 208*25cf1a30Sjl derr.fme_flag = DDI_FM_ERR_UNEXPECTED; 209*25cf1a30Sjl err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, 210*25cf1a30Sjl (void *)pcmu_p, PCI_INTR_CALL); 211*25cf1a30Sjl } 212*25cf1a30Sjl 213*25cf1a30Sjl if (err == DDI_FM_FATAL) { 214*25cf1a30Sjl if (pcmu_panic_on_fatal_errors) { 215*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_err_mutex); 216*25cf1a30Sjl cmn_err(CE_PANIC, "%s-%d: Fatal PCI bus error(s)\n", 217*25cf1a30Sjl ddi_driver_name(pcmu_p->pcmu_dip), 218*25cf1a30Sjl ddi_get_instance(pcmu_p->pcmu_dip)); 219*25cf1a30Sjl } 220*25cf1a30Sjl } 221*25cf1a30Sjl 222*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_err_mutex); 223*25cf1a30Sjl pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 224*25cf1a30Sjl return (DDI_INTR_CLAIMED); 225*25cf1a30Sjl } 226*25cf1a30Sjl 227*25cf1a30Sjl void 228*25cf1a30Sjl pcmu_pbm_suspend(pcmu_pbm_t *pcbm_p) 229*25cf1a30Sjl { 230*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 231*25cf1a30Sjl pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; 232*25cf1a30Sjl pcbm_p->pcbm_imr_save = *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino); 233*25cf1a30Sjl } 234*25cf1a30Sjl 235*25cf1a30Sjl void 236*25cf1a30Sjl pcmu_pbm_resume(pcmu_pbm_t *pcbm_p) 237*25cf1a30Sjl { 238*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 239*25cf1a30Sjl pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; 240*25cf1a30Sjl 241*25cf1a30Sjl pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, ino); 242*25cf1a30Sjl *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino) = pcbm_p->pcbm_imr_save; 243*25cf1a30Sjl } 244*25cf1a30Sjl 245*25cf1a30Sjl void 246*25cf1a30Sjl pcmu_pbm_intr_dist(void *arg) 247*25cf1a30Sjl { 248*25cf1a30Sjl pcmu_pbm_t *pcbm_p = (pcmu_pbm_t *)arg; 249*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 250*25cf1a30Sjl pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 251*25cf1a30Sjl pcmu_ib_ino_t ino = 252*25cf1a30Sjl PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[CBNINTR_PBM]); 253*25cf1a30Sjl mutex_enter(&pib_p->pib_intr_lock); 254*25cf1a30Sjl pcmu_ib_intr_dist_nintr(pib_p, ino, ib_intr_map_reg_addr(pib_p, ino)); 255*25cf1a30Sjl mutex_exit(&pib_p->pib_intr_lock); 256*25cf1a30Sjl } 257*25cf1a30Sjl 258*25cf1a30Sjl /* 259*25cf1a30Sjl * Function used to log PBM AFSR register bits and to lookup and fault 260*25cf1a30Sjl * handle associated with PBM AFAR register. Called by 261*25cf1a30Sjl * pcmu_pbm_err_handler with pcmu_err_mutex held. 262*25cf1a30Sjl */ 263*25cf1a30Sjl int 264*25cf1a30Sjl pcmu_pbm_afsr_report(dev_info_t *dip, uint64_t fme_ena, 265*25cf1a30Sjl pcmu_pbm_errstate_t *pbm_err_p) 266*25cf1a30Sjl { 267*25cf1a30Sjl int fatal = 0; 268*25cf1a30Sjl /* LINTED variable */ 269*25cf1a30Sjl pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 270*25cf1a30Sjl 271*25cf1a30Sjl ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 272*25cf1a30Sjl 273*25cf1a30Sjl pbm_err_p->pcbm_pri = PBM_PRIMARY; 274*25cf1a30Sjl (void) pcmu_pbm_classify(pbm_err_p); 275*25cf1a30Sjl 276*25cf1a30Sjl /* 277*25cf1a30Sjl * We are currently not dealing with the multiple error 278*25cf1a30Sjl * case, for any secondary errors we will panic. 279*25cf1a30Sjl */ 280*25cf1a30Sjl pbm_err_p->pcbm_pri = PBM_SECONDARY; 281*25cf1a30Sjl if (pcmu_pbm_classify(pbm_err_p)) { 282*25cf1a30Sjl fatal++; 283*25cf1a30Sjl pcmu_pbm_ereport_post(dip, fme_ena, pbm_err_p); 284*25cf1a30Sjl } 285*25cf1a30Sjl 286*25cf1a30Sjl if (fatal) { 287*25cf1a30Sjl return (DDI_FM_FATAL); 288*25cf1a30Sjl } 289*25cf1a30Sjl return (DDI_FM_NONFATAL); 290*25cf1a30Sjl } 291