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