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 static uint_t pcmu_pbm_error_intr(caddr_t a); 50 51 /* The nexus interrupt priority values */ 52 int pcmu_pil[] = {14, 14, 14, 14, 14, 14}; 53 54 void 55 pcmu_pbm_create(pcmu_t *pcmu_p) 56 { 57 pcmu_pbm_t *pcbm_p; 58 int len; 59 dev_info_t *dip = pcmu_p->pcmu_dip; 60 61 /* 62 * Allocate a state structure for the PBM and cross-link it 63 * to its per pci node state structure. 64 */ 65 pcbm_p = (pcmu_pbm_t *)kmem_zalloc(sizeof (pcmu_pbm_t), KM_SLEEP); 66 pcmu_p->pcmu_pcbm_p = pcbm_p; 67 pcbm_p->pcbm_pcmu_p = pcmu_p; 68 69 len = snprintf(pcbm_p->pcbm_nameinst_str, 70 sizeof (pcbm_p->pcbm_nameinst_str), "%s%d", NAMEINST(dip)); 71 pcbm_p->pcbm_nameaddr_str = pcbm_p->pcbm_nameinst_str + ++len; 72 (void) snprintf(pcbm_p->pcbm_nameaddr_str, 73 sizeof (pcbm_p->pcbm_nameinst_str) - len, "%s@%s", NAMEADDR(dip)); 74 75 pcmu_pbm_setup(pcbm_p); 76 77 PCMU_DBG4(PCMU_DBG_ATTACH, dip, 78 "pcmu_pbm_create: ctrl=%x, afsr=%x, afar=%x, diag=%x\n", 79 pcbm_p->pcbm_ctrl_reg, pcbm_p->pcbm_async_flt_status_reg, 80 pcbm_p->pcbm_async_flt_addr_reg, pcbm_p->pcbm_diag_reg); 81 PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: conf=%x\n", 82 pcbm_p->pcbm_config_header); 83 84 /* 85 * Register a function to disable pbm error interrupts during a panic. 86 */ 87 bus_func_register(BF_TYPE_ERRDIS, 88 (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); 89 90 /* 91 * create the interrupt-priorities property if it doesn't 92 * already exist to provide a hint as to the PIL level for 93 * our interrupt. 94 */ 95 if (ddi_getproplen(DDI_DEV_T_ANY, dip, 96 DDI_PROP_DONTPASS, "interrupt-priorities", 97 &len) != DDI_PROP_SUCCESS) { 98 /* Create the interrupt-priorities property. */ 99 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 100 DDI_PROP_CANSLEEP, "interrupt-priorities", 101 (caddr_t)pcmu_pil, sizeof (pcmu_pil)); 102 } 103 pcmu_pbm_configure(pcbm_p); 104 } 105 106 int 107 pcmu_pbm_register_intr(pcmu_pbm_t *pcbm_p) 108 { 109 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 110 uint32_t mondo; 111 int r = DDI_SUCCESS; 112 113 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 114 115 /* 116 * Install the PCI error interrupt handler. 117 */ 118 mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, 119 pcmu_p->pcmu_inos[CBNINTR_PBM]); 120 121 VERIFY(add_ivintr(mondo, pcmu_pil[CBNINTR_PBM], 122 (intrfunc)pcmu_pbm_error_intr, (caddr_t)pcmu_p, NULL, NULL) == 0); 123 124 pcbm_p->pcbm_iblock_cookie = (void *)(uintptr_t)pcmu_pil[CBNINTR_PBM]; 125 126 /* 127 * Create the pokefault mutex at the PIL below the error interrupt. 128 */ 129 130 mutex_init(&pcbm_p->pcbm_pokeflt_mutex, NULL, MUTEX_DRIVER, 131 (void *)(uintptr_t)ipltospl(spltoipl( 132 (int)(uintptr_t)pcbm_p->pcbm_iblock_cookie) - 1)); 133 134 return (PCMU_ATTACH_RETCODE(PCMU_PBM_OBJ, PCMU_OBJ_INTR_ADD, r)); 135 } 136 137 void 138 pcmu_pbm_destroy(pcmu_t *pcmu_p) 139 { 140 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 141 pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 142 uint32_t mondo; 143 144 PCMU_DBG0(PCMU_DBG_DETACH, pcmu_p->pcmu_dip, "pcmu_pbm_destroy:\n"); 145 146 mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, 147 pcmu_p->pcmu_inos[CBNINTR_PBM]); 148 149 /* 150 * Free the pokefault mutex. 151 */ 152 mutex_destroy(&pcbm_p->pcbm_pokeflt_mutex); 153 154 /* 155 * Remove the error interrupt. 156 */ 157 intr_dist_rem(pcmu_pbm_intr_dist, pcbm_p); 158 pcmu_ib_intr_disable(pib_p, 159 pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_WAIT); 160 161 VERIFY(rem_ivintr(mondo, pcmu_pil[CBNINTR_PBM]) == 0); 162 163 /* 164 * Remove the error disable function. 165 */ 166 bus_func_unregister(BF_TYPE_ERRDIS, 167 (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); 168 169 pcmu_pbm_teardown(pcbm_p); 170 171 /* 172 * Free the pbm state structure. 173 */ 174 kmem_free(pcbm_p, sizeof (pcmu_pbm_t)); 175 pcmu_p->pcmu_pcbm_p = NULL; 176 } 177 178 static uint_t 179 pcmu_pbm_error_intr(caddr_t a) 180 { 181 pcmu_t *pcmu_p = (pcmu_t *)a; 182 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 183 ddi_fm_error_t derr; 184 int err = DDI_FM_OK; 185 on_trap_data_t *otp = pcbm_p->pcbm_ontrap_data; 186 187 bzero(&derr, sizeof (ddi_fm_error_t)); 188 derr.fme_version = DDI_FME_VERSION; 189 mutex_enter(&pcmu_p->pcmu_err_mutex); 190 if ((otp != NULL) && (otp->ot_prot & OT_DATA_ACCESS)) { 191 /* 192 * ddi_poke protection, check nexus and children for 193 * expected errors. 194 */ 195 otp->ot_trap |= OT_DATA_ACCESS; 196 membar_sync(); 197 derr.fme_flag = DDI_FM_ERR_POKE; 198 err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, 199 (void *)pcmu_p, PCI_INTR_CALL); 200 } else if (pcmu_check_error(pcmu_p) != 0) { 201 /* 202 * unprotected error, check for all errors. 203 */ 204 if (pcmu_errtrig_pa) { 205 (void) ldphysio(pcmu_errtrig_pa); 206 } 207 derr.fme_flag = DDI_FM_ERR_UNEXPECTED; 208 err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, 209 (void *)pcmu_p, PCI_INTR_CALL); 210 } 211 212 if (err == DDI_FM_FATAL) { 213 if (pcmu_panic_on_fatal_errors) { 214 mutex_exit(&pcmu_p->pcmu_err_mutex); 215 cmn_err(CE_PANIC, "%s-%d: Fatal PCI bus error(s)\n", 216 ddi_driver_name(pcmu_p->pcmu_dip), 217 ddi_get_instance(pcmu_p->pcmu_dip)); 218 } 219 } 220 221 mutex_exit(&pcmu_p->pcmu_err_mutex); 222 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 223 return (DDI_INTR_CLAIMED); 224 } 225 226 void 227 pcmu_pbm_suspend(pcmu_pbm_t *pcbm_p) 228 { 229 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 230 pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; 231 pcbm_p->pcbm_imr_save = *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino); 232 } 233 234 void 235 pcmu_pbm_resume(pcmu_pbm_t *pcbm_p) 236 { 237 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 238 pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; 239 240 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, ino); 241 *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino) = pcbm_p->pcbm_imr_save; 242 } 243 244 void 245 pcmu_pbm_intr_dist(void *arg) 246 { 247 pcmu_pbm_t *pcbm_p = (pcmu_pbm_t *)arg; 248 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 249 pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 250 pcmu_ib_ino_t ino = 251 PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[CBNINTR_PBM]); 252 mutex_enter(&pib_p->pib_intr_lock); 253 pcmu_ib_intr_dist_nintr(pib_p, ino, ib_intr_map_reg_addr(pib_p, ino)); 254 mutex_exit(&pib_p->pib_intr_lock); 255 } 256 257 /* 258 * Function used to log PBM AFSR register bits and to lookup and fault 259 * handle associated with PBM AFAR register. Called by 260 * pcmu_pbm_err_handler with pcmu_err_mutex held. 261 */ 262 int 263 pcmu_pbm_afsr_report(dev_info_t *dip, uint64_t fme_ena, 264 pcmu_pbm_errstate_t *pbm_err_p) 265 { 266 int fatal = 0; 267 /* LINTED variable */ 268 pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 269 270 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 271 272 pbm_err_p->pcbm_pri = PBM_PRIMARY; 273 (void) pcmu_pbm_classify(pbm_err_p); 274 275 /* 276 * We are currently not dealing with the multiple error 277 * case, for any secondary errors we will panic. 278 */ 279 pbm_err_p->pcbm_pri = PBM_SECONDARY; 280 if (pcmu_pbm_classify(pbm_err_p)) { 281 fatal++; 282 pcmu_pbm_ereport_post(dip, fme_ena, pbm_err_p); 283 } 284 285 if (fatal) { 286 return (DDI_FM_FATAL); 287 } 288 return (DDI_FM_NONFATAL); 289 } 290