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 * PX Fault Management Architecture 30 */ 31 #include <sys/types.h> 32 #include <sys/sunndi.h> 33 #include <sys/sunddi.h> 34 #include <sys/fm/protocol.h> 35 #include <sys/fm/util.h> 36 #include <sys/membar.h> 37 #include "px_obj.h" 38 39 typedef struct px_fabric_cfgspace { 40 /* Error information */ 41 msgcode_t msg_code; 42 pcie_req_id_t rid; 43 44 /* Config space header and device type */ 45 uint8_t hdr_type; 46 uint16_t dev_type; 47 48 /* Register pointers */ 49 uint16_t cap_off; 50 uint16_t aer_off; 51 52 /* PCI register values */ 53 uint32_t sts_reg; 54 uint32_t sts_sreg; 55 56 /* PCIE register values */ 57 uint32_t dev_sts_reg; 58 uint32_t aer_ce_reg; 59 uint32_t aer_ue_reg; 60 uint32_t aer_sev_reg; 61 uint32_t aer_ue_sreg; 62 uint32_t aer_sev_sreg; 63 64 /* PCIE Header Log Registers */ 65 uint32_t aer_h1; 66 uint32_t aer_h2; 67 uint32_t aer_h3; 68 uint32_t aer_h4; 69 uint32_t aer_sh1; 70 uint32_t aer_sh2; 71 uint32_t aer_sh3; 72 uint32_t aer_sh4; 73 } px_fabric_cfgspace_t; 74 75 static uint16_t px_fabric_get_aer(px_t *px_p, pcie_req_id_t rid); 76 static uint16_t px_fabric_get_pciecap(px_t *px_p, pcie_req_id_t rid); 77 static int px_fabric_handle_psts(px_fabric_cfgspace_t *cs); 78 static int px_fabric_handle_ssts(px_fabric_cfgspace_t *cs); 79 static int px_fabric_handle_paer(px_t *px_p, px_fabric_cfgspace_t *cs); 80 static int px_fabric_handle_saer(px_t *px_p, px_fabric_cfgspace_t *cs); 81 static int px_fabric_handle(px_t *px_p, px_fabric_cfgspace_t *cs); 82 static void px_fabric_fill_cs(px_t *px_p, px_fabric_cfgspace_t *cs); 83 static uint_t px_fabric_check(px_t *px_p, msgcode_t msg_code, 84 pcie_req_id_t rid, ddi_fm_error_t *derr); 85 86 /* 87 * Initialize px FMA support 88 */ 89 int 90 px_fm_attach(px_t *px_p) 91 { 92 px_p->px_fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE | 93 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 94 95 /* 96 * Initialize pci_target_queue for FMA handling of 97 * pci errors. 98 */ 99 pci_targetq_init(); 100 101 /* 102 * check parents' capability 103 */ 104 ddi_fm_init(px_p->px_dip, &px_p->px_fm_cap, &px_p->px_fm_ibc); 105 106 /* 107 * parents need to be ereport and error handling capable 108 */ 109 ASSERT(px_p->px_fm_cap && 110 (DDI_FM_ERRCB_CAPABLE | DDI_FM_EREPORT_CAPABLE)); 111 112 /* 113 * Initialize lock to synchronize fabric error handling 114 */ 115 mutex_init(&px_p->px_fm_mutex, NULL, MUTEX_DRIVER, 116 (void *)px_p->px_fm_ibc); 117 118 /* 119 * register error callback in parent 120 */ 121 ddi_fm_handler_register(px_p->px_dip, px_fm_callback, px_p); 122 123 return (DDI_SUCCESS); 124 } 125 126 /* 127 * Deregister FMA 128 */ 129 void 130 px_fm_detach(px_t *px_p) 131 { 132 ddi_fm_handler_unregister(px_p->px_dip); 133 mutex_destroy(&px_p->px_fm_mutex); 134 ddi_fm_fini(px_p->px_dip); 135 } 136 137 /* 138 * Function used to setup access functions depending on level of desired 139 * protection. 140 */ 141 void 142 px_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip) 143 { 144 uchar_t fflag; 145 ddi_acc_hdl_t *hp; 146 ddi_acc_impl_t *ap; 147 148 hp = mp->map_handlep; 149 ap = (ddi_acc_impl_t *)hp->ah_platform_private; 150 fflag = ap->ahi_common.ah_acc.devacc_attr_access; 151 152 if (mp->map_op == DDI_MO_MAP_LOCKED) { 153 ndi_fmc_insert(rdip, ACC_HANDLE, (void *)hp, NULL); 154 switch (fflag) { 155 case DDI_FLAGERR_ACC: 156 ap->ahi_get8 = i_ddi_prot_get8; 157 ap->ahi_get16 = i_ddi_prot_get16; 158 ap->ahi_get32 = i_ddi_prot_get32; 159 ap->ahi_get64 = i_ddi_prot_get64; 160 ap->ahi_put8 = i_ddi_prot_put8; 161 ap->ahi_put16 = i_ddi_prot_put16; 162 ap->ahi_put32 = i_ddi_prot_put32; 163 ap->ahi_put64 = i_ddi_prot_put64; 164 ap->ahi_rep_get8 = i_ddi_prot_rep_get8; 165 ap->ahi_rep_get16 = i_ddi_prot_rep_get16; 166 ap->ahi_rep_get32 = i_ddi_prot_rep_get32; 167 ap->ahi_rep_get64 = i_ddi_prot_rep_get64; 168 ap->ahi_rep_put8 = i_ddi_prot_rep_put8; 169 ap->ahi_rep_put16 = i_ddi_prot_rep_put16; 170 ap->ahi_rep_put32 = i_ddi_prot_rep_put32; 171 ap->ahi_rep_put64 = i_ddi_prot_rep_put64; 172 break; 173 case DDI_CAUTIOUS_ACC : 174 ap->ahi_get8 = i_ddi_caut_get8; 175 ap->ahi_get16 = i_ddi_caut_get16; 176 ap->ahi_get32 = i_ddi_caut_get32; 177 ap->ahi_get64 = i_ddi_caut_get64; 178 ap->ahi_put8 = i_ddi_caut_put8; 179 ap->ahi_put16 = i_ddi_caut_put16; 180 ap->ahi_put32 = i_ddi_caut_put32; 181 ap->ahi_put64 = i_ddi_caut_put64; 182 ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 183 ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 184 ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 185 ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 186 ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 187 ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 188 ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 189 ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 190 break; 191 default: 192 break; 193 } 194 } else if (mp->map_op == DDI_MO_UNMAP) { 195 ndi_fmc_remove(rdip, ACC_HANDLE, (void *)hp); 196 } 197 } 198 199 /* 200 * Function used by PCI error handlers to check if captured address is stored 201 * in the DMA or ACC handle caches. 202 */ 203 int 204 px_handle_lookup(dev_info_t *dip, int type, uint64_t fme_ena, void *afar) 205 { 206 int ret = ndi_fmc_error(dip, NULL, type, fme_ena, afar); 207 return (ret == DDI_FM_UNKNOWN ? DDI_FM_FATAL : ret); 208 } 209 210 /* 211 * Function used to initialize FMA for our children nodes. Called 212 * through pci busops when child node calls ddi_fm_init. 213 */ 214 /*ARGSUSED*/ 215 int 216 px_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap, 217 ddi_iblock_cookie_t *ibc_p) 218 { 219 px_t *px_p = DIP_TO_STATE(dip); 220 221 ASSERT(ibc_p != NULL); 222 *ibc_p = px_p->px_fm_ibc; 223 224 return (px_p->px_fm_cap); 225 } 226 227 /* 228 * lock access for exclusive PCIe access 229 */ 230 void 231 px_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle) 232 { 233 px_pec_t *pec_p = ((px_t *)DIP_TO_STATE(dip))->px_pec_p; 234 235 /* 236 * Exclusive access has been used for cautious put/get, 237 * Both utilize i_ddi_ontrap which, on sparcv9, implements 238 * similar protection as what on_trap() does, and which calls 239 * membar #Sync to flush out all cpu deferred errors 240 * prior to get/put operation, so here we're not calling 241 * membar #Sync - a difference from what's in pci_bus_enter(). 242 */ 243 mutex_enter(&pec_p->pec_pokefault_mutex); 244 pec_p->pec_acc_hdl = handle; 245 } 246 247 /* 248 * unlock access for exclusive PCIe access 249 */ 250 /* ARGSUSED */ 251 void 252 px_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle) 253 { 254 px_t *px_p = DIP_TO_STATE(dip); 255 px_pec_t *pec_p = px_p->px_pec_p; 256 257 pec_p->pec_acc_hdl = NULL; 258 mutex_exit(&pec_p->pec_pokefault_mutex); 259 } 260 261 262 /* 263 * PCI error callback which is registered with our parent to call 264 * for PCIe logging when the CPU traps due to PCIe Uncorrectable Errors 265 * and PCI BERR/TO/UE 266 * 267 * Dispatch on all known leaves of this fire device because we cannot tell 268 * which side the error came from. 269 */ 270 /*ARGSUSED*/ 271 int 272 px_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data) 273 { 274 px_t *px_p = (px_t *)impl_data; 275 int err = PX_OK; 276 int fatal = 0; 277 int nonfatal = 0; 278 int unknown = 0; 279 int ret = DDI_FM_OK; 280 281 mutex_enter(&px_p->px_fm_mutex); 282 283 err = px_err_handle(px_p, derr, PX_TRAP_CALL, B_TRUE); 284 ret = ndi_fm_handler_dispatch(px_p->px_dip, NULL, derr); 285 286 mutex_exit(&px_p->px_fm_mutex); 287 288 switch (ret) { 289 case DDI_FM_FATAL: 290 fatal++; 291 break; 292 case DDI_FM_NONFATAL: 293 nonfatal++; 294 break; 295 case DDI_FM_UNKNOWN: 296 unknown++; 297 break; 298 default: 299 break; 300 } 301 302 ret = (fatal != 0) ? DDI_FM_FATAL : 303 ((nonfatal != 0) ? DDI_FM_NONFATAL : 304 (((unknown != 0) ? DDI_FM_UNKNOWN : DDI_FM_OK))); 305 306 /* fire fatal error overrides device error */ 307 if (err & (PX_FATAL_GOS | PX_FATAL_SW)) 308 ret = DDI_FM_FATAL; 309 /* if fire encounts no error, then take whatever device error */ 310 else if ((err != PX_OK) && (ret != DDI_FM_FATAL)) 311 ret = DDI_FM_NONFATAL; 312 313 return (ret); 314 } 315 316 static uint16_t 317 px_fabric_get_aer(px_t *px_p, pcie_req_id_t rid) 318 { 319 uint32_t hdr, hdr_next_ptr, hdr_cap_id; 320 uint16_t offset = PCIE_EXT_CAP; 321 int deadcount = 0; 322 323 /* Find the Advanced Error Register */ 324 hdr = px_fab_get(px_p, rid, offset); 325 hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 326 PCIE_EXT_CAP_NEXT_PTR_MASK; 327 hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & 328 PCIE_EXT_CAP_ID_MASK; 329 330 while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) && 331 (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) { 332 offset = hdr_next_ptr; 333 hdr = px_fab_get(px_p, rid, offset); 334 hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 335 PCIE_EXT_CAP_NEXT_PTR_MASK; 336 hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & 337 PCIE_EXT_CAP_ID_MASK; 338 339 if (deadcount++ > 100) 340 break; 341 } 342 343 if (hdr_cap_id == PCIE_EXT_CAP_ID_AER) 344 return (offset); 345 346 return (0); 347 } 348 349 static uint16_t 350 px_fabric_get_pciecap(px_t *px_p, pcie_req_id_t rid) 351 { 352 uint32_t hdr, hdr_next_ptr, hdr_cap_id; 353 uint16_t offset = PCI_CONF_STAT; 354 int deadcount = 0; 355 356 hdr = px_fab_get(px_p, rid, PCI_CONF_COMM) >> 16; 357 if (!(hdr & PCI_STAT_CAP)) { 358 /* This is not a PCIE device */ 359 return (0); 360 } 361 362 hdr = px_fab_get(px_p, rid, PCI_CONF_CAP_PTR); 363 hdr_next_ptr = hdr & 0xFF; 364 hdr_cap_id = 0; 365 366 while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) && 367 (hdr_cap_id != PCI_CAP_ID_PCI_E)) { 368 offset = hdr_next_ptr; 369 370 if (hdr_next_ptr < 0x40) { 371 break; 372 } 373 374 hdr = px_fab_get(px_p, rid, hdr_next_ptr); 375 hdr_next_ptr = (hdr >> 8) & 0xFF; 376 hdr_cap_id = hdr & 0xFF; 377 378 if (deadcount++ > 100) 379 break; 380 } 381 382 if (hdr_cap_id == PCI_CAP_ID_PCI_E) 383 return (offset); 384 385 return (0); 386 } 387 388 /* 389 * This function checks the primary status registers. 390 * Take the PCI status register and translate it to PCIe equivalent. 391 */ 392 static int 393 px_fabric_handle_psts(px_fabric_cfgspace_t *cs) { 394 uint16_t sts_reg = cs->sts_reg >> 16; 395 uint16_t pci_status; 396 uint32_t pcie_status; 397 int ret = PX_NONFATAL; 398 399 /* Parity Err == Send/Recv Poisoned TLP */ 400 pci_status = PCI_STAT_S_PERROR | PCI_STAT_PERROR; 401 pcie_status = PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC; 402 if (sts_reg & pci_status) 403 ret |= PX_FABRIC_ERR_SEV(pcie_status, 404 px_fabric_die_ue, px_fabric_die_ue_gos); 405 406 /* Target Abort == Completer Abort */ 407 pci_status = PCI_STAT_S_TARG_AB | PCI_STAT_R_TARG_AB; 408 pcie_status = PCIE_AER_UCE_CA; 409 if (sts_reg & pci_status) 410 ret |= PX_FABRIC_ERR_SEV(pcie_status, 411 px_fabric_die_ue, px_fabric_die_ue_gos); 412 413 /* Master Abort == Unsupport Request */ 414 pci_status = PCI_STAT_R_MAST_AB; 415 pcie_status = PCIE_AER_UCE_UR; 416 if (sts_reg & pci_status) 417 ret |= PX_FABRIC_ERR_SEV(pcie_status, 418 px_fabric_die_ue, px_fabric_die_ue_gos); 419 420 /* System Error == Uncorrectable Error */ 421 pci_status = PCI_STAT_S_SYSERR; 422 pcie_status = -1; 423 if (sts_reg & pci_status) 424 ret |= PX_FABRIC_ERR_SEV(pcie_status, 425 px_fabric_die_ue, px_fabric_die_ue_gos); 426 427 return (ret); 428 } 429 430 /* 431 * This function checks the secondary status registers. 432 * Switches and Bridges have a different behavior. 433 */ 434 static int 435 px_fabric_handle_ssts(px_fabric_cfgspace_t *cs) { 436 uint16_t sts_reg = cs->sts_sreg >> 16; 437 int ret = PX_NONFATAL; 438 439 if (cs->dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) { 440 /* 441 * This is a PCIE-PCI bridge, but only check the severity 442 * if this device doesn't support AERs. 443 */ 444 if (!cs->aer_off) 445 ret |= PX_FABRIC_ERR_SEV(sts_reg, px_fabric_die_bdg_sts, 446 px_fabric_die_bdg_sts_gos); 447 } else { 448 /* This is most likely a PCIE switch */ 449 ret |= PX_FABRIC_ERR_SEV(sts_reg, px_fabric_die_sw_sts, 450 px_fabric_die_sw_sts_gos); 451 } 452 453 return (ret); 454 } 455 456 /* 457 * This function checks and clears the primary AER. 458 */ 459 static int 460 px_fabric_handle_paer(px_t *px_p, px_fabric_cfgspace_t *cs) { 461 uint32_t chk_reg, chk_reg_gos, off_reg, reg; 462 int ret = PX_NONFATAL; 463 464 /* Determine severity and clear the AER */ 465 switch (cs->msg_code) { 466 case PCIE_MSG_CODE_ERR_COR: 467 off_reg = PCIE_AER_CE_STS; 468 chk_reg = px_fabric_die_ce; 469 chk_reg_gos = px_fabric_die_ce_gos; 470 reg = cs->aer_ce_reg; 471 break; 472 case PCIE_MSG_CODE_ERR_NONFATAL: 473 off_reg = PCIE_AER_UCE_STS; 474 chk_reg = px_fabric_die_ue; 475 chk_reg_gos = px_fabric_die_ue_gos; 476 reg = cs->aer_ue_reg & ~(cs->aer_sev_reg); 477 break; 478 case PCIE_MSG_CODE_ERR_FATAL: 479 off_reg = PCIE_AER_UCE_STS; 480 chk_reg = px_fabric_die_ue; 481 chk_reg_gos = px_fabric_die_ue_gos; 482 reg = cs->aer_ue_reg & cs->aer_sev_reg; 483 break; 484 default: 485 /* Major error force a panic */ 486 return (PX_FATAL_GOS); 487 } 488 px_fab_set(px_p, cs->rid, cs->aer_off + off_reg, reg); 489 ret |= PX_FABRIC_ERR_SEV(reg, chk_reg, chk_reg_gos); 490 491 return (ret); 492 } 493 494 /* 495 * This function checks and clears the secondary AER. 496 */ 497 static int 498 px_fabric_handle_saer(px_t *px_p, px_fabric_cfgspace_t *cs) { 499 uint32_t chk_reg, chk_reg_gos, off_reg, reg; 500 uint32_t sev; 501 int ret = PX_NONFATAL; 502 503 /* Determine severity and clear the AER */ 504 switch (cs->msg_code) { 505 case PCIE_MSG_CODE_ERR_COR: 506 /* Ignore Correctable Errors */ 507 sev = 0; 508 break; 509 case PCIE_MSG_CODE_ERR_NONFATAL: 510 sev = ~(cs->aer_sev_sreg); 511 break; 512 case PCIE_MSG_CODE_ERR_FATAL: 513 sev = cs->aer_sev_sreg; 514 break; 515 default: 516 /* Major error force a panic */ 517 return (DDI_FM_FATAL); 518 } 519 off_reg = PCIE_AER_SUCE_STS; 520 chk_reg = px_fabric_die_sue; 521 chk_reg_gos = px_fabric_die_sue_gos; 522 reg = cs->aer_ue_sreg & sev; 523 px_fab_set(px_p, cs->rid, cs->aer_off + off_reg, reg); 524 ret |= PX_FABRIC_ERR_SEV(reg, chk_reg, chk_reg_gos); 525 526 return (ret); 527 } 528 529 static int 530 px_fabric_handle(px_t *px_p, px_fabric_cfgspace_t *cs) 531 { 532 pcie_req_id_t rid = cs->rid; 533 uint16_t cap_off = cs->cap_off; 534 uint16_t aer_off = cs->aer_off; 535 uint8_t hdr_type = cs->hdr_type; 536 uint16_t dev_type = cs->dev_type; 537 int ret = PX_NONFATAL; 538 539 if (hdr_type == PCI_HEADER_PPB) { 540 ret |= px_fabric_handle_ssts(cs); 541 } 542 543 if (!aer_off) { 544 ret |= px_fabric_handle_psts(cs); 545 } 546 547 if (aer_off) { 548 ret |= px_fabric_handle_paer(px_p, cs); 549 } 550 551 if (aer_off && (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI)) { 552 ret |= px_fabric_handle_saer(px_p, cs); 553 } 554 555 /* Clear the standard PCIe error registers */ 556 px_fab_set(px_p, rid, cap_off + PCIE_DEVCTL, cs->dev_sts_reg); 557 558 /* Clear the legacy error registers */ 559 px_fab_set(px_p, rid, PCI_CONF_COMM, cs->sts_reg); 560 561 /* Clear the legacy secondary error registers */ 562 if (hdr_type == PCI_HEADER_PPB) { 563 px_fab_set(px_p, rid, PCI_BCNF_IO_BASE_LOW, 564 cs->sts_sreg); 565 } 566 567 return (ret); 568 } 569 570 static void 571 px_fabric_fill_cs(px_t *px_p, px_fabric_cfgspace_t *cs) 572 { 573 uint16_t cap_off, aer_off; 574 pcie_req_id_t rid = cs->rid; 575 576 /* Gather Basic Device Information */ 577 cs->hdr_type = (px_fab_get(px_p, rid, 578 PCI_CONF_CACHE_LINESZ) >> 16) & 0xFF; 579 580 cs->cap_off = px_fabric_get_pciecap(px_p, rid); 581 cap_off = cs->cap_off; 582 if (!cap_off) 583 return; 584 585 cs->aer_off = px_fabric_get_aer(px_p, rid); 586 aer_off = cs->aer_off; 587 588 cs->dev_type = px_fab_get(px_p, rid, cap_off) >> 16; 589 cs->dev_type &= PCIE_PCIECAP_DEV_TYPE_MASK; 590 591 /* Get the Primary Sts Reg */ 592 cs->sts_reg = px_fab_get(px_p, rid, PCI_CONF_COMM); 593 594 /* If it is a bridge/switch get the Secondary Sts Reg */ 595 if (cs->hdr_type == PCI_HEADER_PPB) 596 cs->sts_sreg = px_fab_get(px_p, rid, 597 PCI_BCNF_IO_BASE_LOW); 598 599 /* Get the PCIe Dev Sts Reg */ 600 cs->dev_sts_reg = px_fab_get(px_p, rid, 601 cap_off + PCIE_DEVCTL); 602 603 if (!aer_off) 604 return; 605 606 /* Get the AER register information */ 607 cs->aer_ce_reg = px_fab_get(px_p, rid, aer_off + PCIE_AER_CE_STS); 608 cs->aer_ue_reg = px_fab_get(px_p, rid, aer_off + PCIE_AER_UCE_STS); 609 cs->aer_sev_reg = px_fab_get(px_p, rid, aer_off + PCIE_AER_UCE_SERV); 610 cs->aer_h1 = px_fab_get(px_p, rid, aer_off + PCIE_AER_HDR_LOG + 0x0); 611 cs->aer_h2 = px_fab_get(px_p, rid, aer_off + PCIE_AER_HDR_LOG + 0x4); 612 cs->aer_h3 = px_fab_get(px_p, rid, aer_off + PCIE_AER_HDR_LOG + 0x8); 613 cs->aer_h4 = px_fab_get(px_p, rid, aer_off + PCIE_AER_HDR_LOG + 0xC); 614 615 if (cs->dev_type != PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) 616 return; 617 618 /* If this is a bridge check secondary aer */ 619 cs->aer_ue_sreg = px_fab_get(px_p, rid, aer_off + PCIE_AER_SUCE_STS); 620 cs->aer_sev_sreg = px_fab_get(px_p, rid, aer_off + PCIE_AER_SUCE_SERV); 621 cs->aer_sh1 = px_fab_get(px_p, rid, aer_off + PCIE_AER_SHDR_LOG + 0x0); 622 cs->aer_sh2 = px_fab_get(px_p, rid, aer_off + PCIE_AER_SHDR_LOG + 0x4); 623 cs->aer_sh3 = px_fab_get(px_p, rid, aer_off + PCIE_AER_SHDR_LOG + 0x8); 624 cs->aer_sh4 = px_fab_get(px_p, rid, aer_off + PCIE_AER_SHDR_LOG + 0xC); 625 } 626 627 /* 628 * If a fabric intr occurs, query and clear the error registers on that device. 629 * Based on the error found return DDI_FM_OK or DDI_FM_FATAL. 630 */ 631 static uint_t 632 px_fabric_check(px_t *px_p, msgcode_t msg_code, 633 pcie_req_id_t rid, ddi_fm_error_t *derr) 634 { 635 dev_info_t *dip = px_p->px_dip; 636 char buf[FM_MAX_CLASS]; 637 px_fabric_cfgspace_t cs; 638 int ret; 639 640 /* clear cs */ 641 bzero(&cs, sizeof (px_fabric_cfgspace_t)); 642 643 cs.msg_code = msg_code; 644 cs.rid = rid; 645 646 px_fabric_fill_cs(px_p, &cs); 647 if (cs.cap_off) 648 ret = px_fabric_handle(px_p, &cs); 649 else 650 ret = PX_FATAL_GOS; 651 652 (void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_FABRIC_CLASS); 653 ddi_fm_ereport_post(dip, buf, derr->fme_ena, 654 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 655 PX_FM_FABRIC_MSG_CODE, DATA_TYPE_UINT8, msg_code, 656 PX_FM_FABRIC_REQ_ID, DATA_TYPE_UINT16, rid, 657 "cap_off", DATA_TYPE_UINT16, cs.cap_off, 658 "aer_off", DATA_TYPE_UINT16, cs.aer_off, 659 "sts_reg", DATA_TYPE_UINT16, cs.sts_reg >> 16, 660 "sts_sreg", DATA_TYPE_UINT16, cs.sts_sreg >> 16, 661 "dev_sts_reg", DATA_TYPE_UINT16, cs.dev_sts_reg >> 16, 662 "aer_ce", DATA_TYPE_UINT32, cs.aer_ce_reg, 663 "aer_ue", DATA_TYPE_UINT32, cs.aer_ue_reg, 664 "aer_sev", DATA_TYPE_UINT32, cs.aer_sev_reg, 665 "aer_h1", DATA_TYPE_UINT32, cs.aer_h1, 666 "aer_h2", DATA_TYPE_UINT32, cs.aer_h2, 667 "aer_h3", DATA_TYPE_UINT32, cs.aer_h3, 668 "aer_h4", DATA_TYPE_UINT32, cs.aer_h4, 669 "saer_ue", DATA_TYPE_UINT32, cs.aer_ue_sreg, 670 "saer_sev", DATA_TYPE_UINT32, cs.aer_sev_sreg, 671 "saer_h1", DATA_TYPE_UINT32, cs.aer_sh1, 672 "saer_h2", DATA_TYPE_UINT32, cs.aer_sh2, 673 "saer_h3", DATA_TYPE_UINT32, cs.aer_sh3, 674 "saer_h4", DATA_TYPE_UINT32, cs.aer_sh4, 675 "severity", DATA_TYPE_UINT32, ret, 676 NULL); 677 678 /* Check for protected access */ 679 switch (derr->fme_flag) { 680 case DDI_FM_ERR_EXPECTED: 681 case DDI_FM_ERR_PEEK: 682 case DDI_FM_ERR_POKE: 683 ret &= PX_FATAL_GOS; 684 break; 685 } 686 687 688 if (px_fabric_die && 689 (ret & (PX_FATAL_GOS | PX_FATAL_SW))) 690 ret = DDI_FM_FATAL; 691 return (ret); 692 } 693 694 /* 695 * px_err_fabric_intr: 696 * Interrupt handler for PCIE fabric block. 697 * o lock 698 * o create derr 699 * o px_err_handle(leaf, with jbc) 700 * o send ereport(fire fmri, derr, payload = BDF) 701 * o dispatch (leaf) 702 * o unlock 703 * o handle error: fatal? fm_panic() : return INTR_CLAIMED) 704 */ 705 /* ARGSUSED */ 706 uint_t 707 px_err_fabric_intr(px_t *px_p, msgcode_t msg_code, 708 pcie_req_id_t rid) 709 { 710 dev_info_t *rpdip = px_p->px_dip; 711 int err = PX_OK, ret = DDI_FM_OK, fab_err = DDI_FM_OK; 712 ddi_fm_error_t derr; 713 714 mutex_enter(&px_p->px_fm_mutex); 715 716 /* Create the derr */ 717 bzero(&derr, sizeof (ddi_fm_error_t)); 718 derr.fme_version = DDI_FME_VERSION; 719 derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 720 derr.fme_flag = DDI_FM_ERR_UNEXPECTED; 721 722 /* send ereport/handle/clear fire registers */ 723 err |= px_err_handle(px_p, &derr, PX_INTR_CALL, B_TRUE); 724 725 /* Check and clear the fabric error */ 726 fab_err = px_fabric_check(px_p, msg_code, rid, &derr); 727 728 /* Check all child devices for errors */ 729 ret = ndi_fm_handler_dispatch(rpdip, NULL, &derr); 730 731 mutex_exit(&px_p->px_fm_mutex); 732 733 /* 734 * PX_FATAL_HW indicates a condition recovered from Fatal-Reset, 735 * therefore it does not cause panic. 736 */ 737 if ((err & (PX_FATAL_GOS | PX_FATAL_SW)) || 738 (ret == DDI_FM_FATAL) || (fab_err == DDI_FM_FATAL)) 739 PX_FM_PANIC("%s#%d: Fatal PCIe Fabric Error has occurred" 740 "(%x,%x,%x)\n", ddi_driver_name(rpdip), 741 ddi_get_instance(rpdip), err, fab_err, ret); 742 743 return (DDI_INTR_CLAIMED); 744 } 745 746 /* 747 * px_err_safeacc_check: 748 * Check to see if a peek/poke and cautious access is currently being 749 * done on a particular leaf. 750 * 751 * Safe access reads induced fire errors will be handled by cpu trap handler 752 * which will call px_fm_callback() which calls this function. In that 753 * case, the derr fields will be set by trap handler with the correct values. 754 * 755 * Safe access writes induced errors will be handled by px interrupt 756 * handlers, this function will fill in the derr fields. 757 * 758 * If a cpu trap does occur, it will quiesce all other interrupts allowing 759 * the cpu trap error handling to finish before Fire receives an interrupt. 760 * 761 * If fire does indeed have an error when a cpu trap occurs as a result of 762 * a safe access, a trap followed by a Mondo/Fabric interrupt will occur. 763 * In which case derr will be initialized as "UNEXPECTED" by the interrupt 764 * handler and this function will need to find if this error occured in the 765 * middle of a safe access operation. 766 * 767 * @param px_p leaf in which to check access 768 * @param derr fm err data structure to be updated 769 */ 770 void 771 px_err_safeacc_check(px_t *px_p, ddi_fm_error_t *derr) 772 { 773 px_pec_t *pec_p = px_p->px_pec_p; 774 int acctype = pec_p->pec_safeacc_type; 775 776 ASSERT(MUTEX_HELD(&px_p->px_fm_mutex)); 777 778 if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) { 779 return; 780 } 781 782 /* safe access checking */ 783 switch (acctype) { 784 case DDI_FM_ERR_EXPECTED: 785 /* 786 * cautious access protection, protected from all err. 787 */ 788 ASSERT(MUTEX_HELD(&pec_p->pec_pokefault_mutex)); 789 ddi_fm_acc_err_get(pec_p->pec_acc_hdl, derr, 790 DDI_FME_VERSION); 791 derr->fme_flag = acctype; 792 derr->fme_acc_handle = pec_p->pec_acc_hdl; 793 break; 794 case DDI_FM_ERR_POKE: 795 /* 796 * ddi_poke protection, check nexus and children for 797 * expected errors. 798 */ 799 ASSERT(MUTEX_HELD(&pec_p->pec_pokefault_mutex)); 800 membar_sync(); 801 derr->fme_flag = acctype; 802 break; 803 case DDI_FM_ERR_PEEK: 804 derr->fme_flag = acctype; 805 break; 806 } 807 } 808