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], pcmu_pbm_error_intr, 122 (caddr_t)pcmu_p, 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 rem_ivintr(mondo, NULL); 161 162 /* 163 * Remove the error disable function. 164 */ 165 bus_func_unregister(BF_TYPE_ERRDIS, 166 (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); 167 168 pcmu_pbm_teardown(pcbm_p); 169 170 /* 171 * Free the pbm state structure. 172 */ 173 kmem_free(pcbm_p, sizeof (pcmu_pbm_t)); 174 pcmu_p->pcmu_pcbm_p = NULL; 175 } 176 177 static uint_t 178 pcmu_pbm_error_intr(caddr_t a) 179 { 180 pcmu_t *pcmu_p = (pcmu_t *)a; 181 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 182 ddi_fm_error_t derr; 183 int err = DDI_FM_OK; 184 on_trap_data_t *otp = pcbm_p->pcbm_ontrap_data; 185 186 bzero(&derr, sizeof (ddi_fm_error_t)); 187 derr.fme_version = DDI_FME_VERSION; 188 mutex_enter(&pcmu_p->pcmu_err_mutex); 189 if ((otp != NULL) && (otp->ot_prot & OT_DATA_ACCESS)) { 190 /* 191 * ddi_poke protection, check nexus and children for 192 * expected errors. 193 */ 194 otp->ot_trap |= OT_DATA_ACCESS; 195 membar_sync(); 196 derr.fme_flag = DDI_FM_ERR_POKE; 197 err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, 198 (void *)pcmu_p, PCI_INTR_CALL); 199 } else if (pcmu_check_error(pcmu_p) != 0) { 200 /* 201 * unprotected error, check for all errors. 202 */ 203 if (pcmu_errtrig_pa) { 204 (void) ldphysio(pcmu_errtrig_pa); 205 } 206 derr.fme_flag = DDI_FM_ERR_UNEXPECTED; 207 err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, 208 (void *)pcmu_p, PCI_INTR_CALL); 209 } 210 211 if (err == DDI_FM_FATAL) { 212 if (pcmu_panic_on_fatal_errors) { 213 mutex_exit(&pcmu_p->pcmu_err_mutex); 214 cmn_err(CE_PANIC, "%s-%d: Fatal PCI bus error(s)\n", 215 ddi_driver_name(pcmu_p->pcmu_dip), 216 ddi_get_instance(pcmu_p->pcmu_dip)); 217 } 218 } 219 220 mutex_exit(&pcmu_p->pcmu_err_mutex); 221 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 222 return (DDI_INTR_CLAIMED); 223 } 224 225 void 226 pcmu_pbm_suspend(pcmu_pbm_t *pcbm_p) 227 { 228 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 229 pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; 230 pcbm_p->pcbm_imr_save = *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino); 231 } 232 233 void 234 pcmu_pbm_resume(pcmu_pbm_t *pcbm_p) 235 { 236 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 237 pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; 238 239 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, ino); 240 *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino) = pcbm_p->pcbm_imr_save; 241 } 242 243 void 244 pcmu_pbm_intr_dist(void *arg) 245 { 246 pcmu_pbm_t *pcbm_p = (pcmu_pbm_t *)arg; 247 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 248 pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 249 pcmu_ib_ino_t ino = 250 PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[CBNINTR_PBM]); 251 mutex_enter(&pib_p->pib_intr_lock); 252 pcmu_ib_intr_dist_nintr(pib_p, ino, ib_intr_map_reg_addr(pib_p, ino)); 253 mutex_exit(&pib_p->pib_intr_lock); 254 } 255 256 /* 257 * Function used to log PBM AFSR register bits and to lookup and fault 258 * handle associated with PBM AFAR register. Called by 259 * pcmu_pbm_err_handler with pcmu_err_mutex held. 260 */ 261 int 262 pcmu_pbm_afsr_report(dev_info_t *dip, uint64_t fme_ena, 263 pcmu_pbm_errstate_t *pbm_err_p) 264 { 265 int fatal = 0; 266 /* LINTED variable */ 267 pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 268 269 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 270 271 pbm_err_p->pcbm_pri = PBM_PRIMARY; 272 (void) pcmu_pbm_classify(pbm_err_p); 273 274 /* 275 * We are currently not dealing with the multiple error 276 * case, for any secondary errors we will panic. 277 */ 278 pbm_err_p->pcbm_pri = PBM_SECONDARY; 279 if (pcmu_pbm_classify(pbm_err_p)) { 280 fatal++; 281 pcmu_pbm_ereport_post(dip, fme_ena, pbm_err_p); 282 } 283 284 if (fatal) { 285 return (DDI_FM_FATAL); 286 } 287 return (DDI_FM_NONFATAL); 288 } 289