1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Alexander Motin <mav@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_acpi.h" 32 #include "opt_pci.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 #include <sys/callout.h> 38 #include <sys/interrupt.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 #include <sys/queue.h> 43 #include <sys/rman.h> 44 #include <vm/vm.h> 45 #include <vm/pmap.h> 46 47 #include <contrib/dev/acpica/include/acpi.h> 48 #include <contrib/dev/acpica/include/accommon.h> 49 #include <contrib/dev/acpica/include/aclocal.h> 50 #include <contrib/dev/acpica/include/actables.h> 51 52 #include <dev/acpica/acpivar.h> 53 #include <dev/pci/pcireg.h> 54 #include <dev/pci/pcivar.h> 55 56 struct apei_ge { 57 union { 58 ACPI_HEST_GENERIC v1; 59 ACPI_HEST_GENERIC_V2 v2; 60 }; 61 int res_type; 62 int res_rid; 63 struct resource *res; 64 int res2_type; 65 int res2_rid; 66 struct resource *res2; 67 uint8_t *buf, *copybuf; 68 TAILQ_ENTRY(apei_ge) link; 69 struct callout poll; 70 void *swi_ih; 71 } *apei_nmi_ge; 72 73 struct apei_softc { 74 ACPI_TABLE_HEST *hest; 75 TAILQ_HEAD(, apei_ge) ges; 76 }; 77 78 struct apei_mem_error { 79 uint64_t ValidationBits; 80 uint64_t ErrorStatus; 81 uint64_t PhysicalAddress; 82 uint64_t PhysicalAddressMask; 83 uint16_t Node; 84 uint16_t Card; 85 uint16_t Module; 86 uint16_t Bank; 87 uint16_t Device; 88 uint16_t Row; 89 uint16_t Column; 90 uint16_t BitPosition; 91 uint64_t RequesterID; 92 uint64_t ResponderID; 93 uint64_t TargetID; 94 uint8_t MemoryErrorType; 95 uint8_t Extended; 96 uint16_t RankNumber; 97 uint16_t CardHandle; 98 uint16_t ModuleHandle; 99 }; 100 101 struct apei_pcie_error { 102 uint64_t ValidationBits; 103 uint32_t PortType; 104 uint32_t Version; 105 uint32_t CommandStatus; 106 uint32_t Reserved; 107 uint8_t DeviceID[16]; 108 uint8_t DeviceSerialNumber[8]; 109 uint8_t BridgeControlStatus[4]; 110 uint8_t CapabilityStructure[60]; 111 uint8_t AERInfo[96]; 112 }; 113 114 #ifdef __i386__ 115 static __inline uint64_t 116 apei_bus_read_8(struct resource *res, bus_size_t offset) 117 { 118 return (bus_read_4(res, offset) | 119 ((uint64_t)bus_read_4(res, offset + 4)) << 32); 120 } 121 static __inline void 122 apei_bus_write_8(struct resource *res, bus_size_t offset, uint64_t val) 123 { 124 bus_write_4(res, offset, val); 125 bus_write_4(res, offset + 4, val >> 32); 126 } 127 #define READ8(r, o) apei_bus_read_8((r), (o)) 128 #define WRITE8(r, o, v) apei_bus_write_8((r), (o), (v)) 129 #else 130 #define READ8(r, o) bus_read_8((r), (o)) 131 #define WRITE8(r, o, v) bus_write_8((r), (o), (v)) 132 #endif 133 134 int apei_nmi_handler(void); 135 136 static const char * 137 apei_severity(uint32_t s) 138 { 139 switch (s) { 140 case ACPI_HEST_GEN_ERROR_RECOVERABLE: 141 return ("Recoverable"); 142 case ACPI_HEST_GEN_ERROR_FATAL: 143 return ("Fatal"); 144 case ACPI_HEST_GEN_ERROR_CORRECTED: 145 return ("Corrected"); 146 case ACPI_HEST_GEN_ERROR_NONE: 147 return ("Informational"); 148 } 149 return ("???"); 150 } 151 152 static int 153 apei_mem_handler(ACPI_HEST_GENERIC_DATA *ged) 154 { 155 struct apei_mem_error *p = (struct apei_mem_error *)(ged + 1); 156 157 printf("APEI %s Memory Error:\n", apei_severity(ged->ErrorSeverity)); 158 if (p->ValidationBits & 0x01) 159 printf(" Error Status: 0x%jx\n", p->ErrorStatus); 160 if (p->ValidationBits & 0x02) 161 printf(" Physical Address: 0x%jx\n", p->PhysicalAddress); 162 if (p->ValidationBits & 0x04) 163 printf(" Physical Address Mask: 0x%jx\n", p->PhysicalAddressMask); 164 if (p->ValidationBits & 0x08) 165 printf(" Node: %u\n", p->Node); 166 if (p->ValidationBits & 0x10) 167 printf(" Card: %u\n", p->Card); 168 if (p->ValidationBits & 0x20) 169 printf(" Module: %u\n", p->Module); 170 if (p->ValidationBits & 0x40) 171 printf(" Bank: %u\n", p->Bank); 172 if (p->ValidationBits & 0x80) 173 printf(" Device: %u\n", p->Device); 174 if (p->ValidationBits & 0x100) 175 printf(" Row: %u\n", p->Row); 176 if (p->ValidationBits & 0x200) 177 printf(" Column: %u\n", p->Column); 178 if (p->ValidationBits & 0x400) 179 printf(" Bit Position: %u\n", p->BitPosition); 180 if (p->ValidationBits & 0x800) 181 printf(" Requester ID: 0x%jx\n", p->RequesterID); 182 if (p->ValidationBits & 0x1000) 183 printf(" Responder ID: 0x%jx\n", p->ResponderID); 184 if (p->ValidationBits & 0x2000) 185 printf(" Target ID: 0x%jx\n", p->TargetID); 186 if (p->ValidationBits & 0x4000) 187 printf(" Memory Error Type: %u\n", p->MemoryErrorType); 188 if (p->ValidationBits & 0x8000) 189 printf(" Rank Number: %u\n", p->RankNumber); 190 if (p->ValidationBits & 0x10000) 191 printf(" Card Handle: 0x%x\n", p->CardHandle); 192 if (p->ValidationBits & 0x20000) 193 printf(" Module Handle: 0x%x\n", p->ModuleHandle); 194 if (p->ValidationBits & 0x40000) 195 printf(" Extended Row: %u\n", 196 (uint32_t)(p->Extended & 0x3) << 16 | p->Row); 197 if (p->ValidationBits & 0x80000) 198 printf(" Bank Group: %u\n", p->Bank >> 8); 199 if (p->ValidationBits & 0x100000) 200 printf(" Bank Address: %u\n", p->Bank & 0xff); 201 if (p->ValidationBits & 0x200000) 202 printf(" Chip Identification: %u\n", (p->Extended >> 5) & 0x7); 203 204 return (0); 205 } 206 207 static int 208 apei_pcie_handler(ACPI_HEST_GENERIC_DATA *ged) 209 { 210 struct apei_pcie_error *p = (struct apei_pcie_error *)(ged + 1); 211 int h = 0, off; 212 #ifdef DEV_PCI 213 device_t dev; 214 int sev; 215 216 if ((p->ValidationBits & 0x8) == 0x8) { 217 mtx_lock(&Giant); 218 dev = pci_find_dbsf((uint32_t)p->DeviceID[10] << 8 | 219 p->DeviceID[9], p->DeviceID[11], p->DeviceID[8], 220 p->DeviceID[7]); 221 if (dev != NULL) { 222 switch (ged->ErrorSeverity) { 223 case ACPI_HEST_GEN_ERROR_FATAL: 224 sev = PCIEM_STA_FATAL_ERROR; 225 break; 226 case ACPI_HEST_GEN_ERROR_RECOVERABLE: 227 sev = PCIEM_STA_NON_FATAL_ERROR; 228 break; 229 default: 230 sev = PCIEM_STA_CORRECTABLE_ERROR; 231 break; 232 } 233 pcie_apei_error(dev, sev, 234 (p->ValidationBits & 0x80) ? p->AERInfo : NULL); 235 h = 1; 236 } 237 mtx_unlock(&Giant); 238 } 239 if (h) 240 return (h); 241 #endif 242 243 printf("APEI %s PCIe Error:\n", apei_severity(ged->ErrorSeverity)); 244 if (p->ValidationBits & 0x01) 245 printf(" Port Type: %u\n", p->PortType); 246 if (p->ValidationBits & 0x02) 247 printf(" Version: %x\n", p->Version); 248 if (p->ValidationBits & 0x04) 249 printf(" Command Status: 0x%08x\n", p->CommandStatus); 250 if (p->ValidationBits & 0x08) { 251 printf(" DeviceID:"); 252 for (off = 0; off < sizeof(p->DeviceID); off++) 253 printf(" %02x", p->DeviceID[off]); 254 printf("\n"); 255 } 256 if (p->ValidationBits & 0x10) { 257 printf(" Device Serial Number:"); 258 for (off = 0; off < sizeof(p->DeviceSerialNumber); off++) 259 printf(" %02x", p->DeviceSerialNumber[off]); 260 printf("\n"); 261 } 262 if (p->ValidationBits & 0x20) { 263 printf(" Bridge Control Status:"); 264 for (off = 0; off < sizeof(p->BridgeControlStatus); off++) 265 printf(" %02x", p->BridgeControlStatus[off]); 266 printf("\n"); 267 } 268 if (p->ValidationBits & 0x40) { 269 printf(" Capability Structure:\n"); 270 for (off = 0; off < sizeof(p->CapabilityStructure); off++) { 271 printf(" %02x", p->CapabilityStructure[off]); 272 if ((off % 16) == 15 || 273 off + 1 == sizeof(p->CapabilityStructure)) 274 printf("\n"); 275 } 276 } 277 if (p->ValidationBits & 0x80) { 278 printf(" AER Info:\n"); 279 for (off = 0; off < sizeof(p->AERInfo); off++) { 280 printf(" %02x", p->AERInfo[off]); 281 if ((off % 16) == 15 || off + 1 == sizeof(p->AERInfo)) 282 printf("\n"); 283 } 284 } 285 return (h); 286 } 287 288 static void 289 apei_ged_handler(ACPI_HEST_GENERIC_DATA *ged) 290 { 291 ACPI_HEST_GENERIC_DATA_V300 *ged3 = (ACPI_HEST_GENERIC_DATA_V300 *)ged; 292 /* A5BC1114-6F64-4EDE-B863-3E83ED7C83B1 */ 293 static uint8_t mem_uuid[ACPI_UUID_LENGTH] = { 294 0x14, 0x11, 0xBC, 0xA5, 0x64, 0x6F, 0xDE, 0x4E, 295 0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83, 0xB1 296 }; 297 /* D995E954-BBC1-430F-AD91-B44DCB3C6F35 */ 298 static uint8_t pcie_uuid[ACPI_UUID_LENGTH] = { 299 0x54, 0xE9, 0x95, 0xD9, 0xC1, 0xBB, 0x0F, 0x43, 300 0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35 301 }; 302 uint8_t *t; 303 int h = 0, off; 304 305 if (memcmp(mem_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) { 306 h = apei_mem_handler(ged); 307 } else if (memcmp(pcie_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) { 308 h = apei_pcie_handler(ged); 309 } else { 310 t = ged->SectionType; 311 printf("APEI %s Error %02x%02x%02x%02x-%02x%02x-" 312 "%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x:\n", 313 apei_severity(ged->ErrorSeverity), 314 t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6], 315 t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]); 316 printf(" Error Data:\n"); 317 t = (uint8_t *)(ged + 1); 318 for (off = 0; off < ged->ErrorDataLength; off++) { 319 printf(" %02x", t[off]); 320 if ((off % 16) == 15 || off + 1 == ged->ErrorDataLength) 321 printf("\n"); 322 } 323 } 324 if (h) 325 return; 326 327 printf(" Flags: 0x%x\n", ged->Flags); 328 if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) { 329 t = ged->FruId; 330 printf(" FRU Id: %02x%02x%02x%02x-%02x%02x-%02x%02x-" 331 "%02x%02x-%02x%02x%02x%02x%02x%02x\n", 332 t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6], 333 t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]); 334 } 335 if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING) 336 printf(" FRU Text: %.20s", ged->FruText); 337 if (ged->Revision == 0x300 && 338 ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP) 339 printf(" Timestamp: %016jx", ged3->TimeStamp); 340 } 341 342 static int 343 apei_ge_handler(struct apei_ge *ge, bool copy) 344 { 345 uint8_t *buf = copy ? ge->copybuf : ge->buf; 346 ACPI_HEST_GENERIC_STATUS *ges = (ACPI_HEST_GENERIC_STATUS *)buf; 347 ACPI_HEST_GENERIC_DATA *ged; 348 uint32_t sev; 349 int i, c, off; 350 351 if (ges == NULL || ges->BlockStatus == 0) 352 return (0); 353 354 c = (ges->BlockStatus >> 4) & 0x3ff; 355 sev = ges->ErrorSeverity; 356 357 /* Process error entries. */ 358 for (off = i = 0; i < c && off + sizeof(*ged) <= ges->DataLength; i++) { 359 ged = (ACPI_HEST_GENERIC_DATA *)&buf[sizeof(*ges) + off]; 360 apei_ged_handler(ged); 361 off += sizeof(*ged) + ged->ErrorDataLength; 362 } 363 364 /* Acknowledge the error has been processed. */ 365 ges->BlockStatus = 0; 366 if (!copy && ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 && 367 ge->res2) { 368 uint64_t val = READ8(ge->res2, 0); 369 val &= ge->v2.ReadAckPreserve; 370 val |= ge->v2.ReadAckWrite; 371 WRITE8(ge->res2, 0, val); 372 } 373 374 /* If ACPI told the error is fatal -- make it so. */ 375 if (sev == ACPI_HEST_GEN_ERROR_FATAL) 376 panic("APEI Fatal Hardware Error!"); 377 378 return (1); 379 } 380 381 static void 382 apei_nmi_swi(void *arg) 383 { 384 struct apei_ge *ge = arg; 385 386 apei_ge_handler(ge, true); 387 } 388 389 int 390 apei_nmi_handler(void) 391 { 392 struct apei_ge *ge = apei_nmi_ge; 393 ACPI_HEST_GENERIC_STATUS *ges, *gesc; 394 395 if (ge == NULL) 396 return (0); 397 398 ges = (ACPI_HEST_GENERIC_STATUS *)ge->buf; 399 if (ges == NULL || ges->BlockStatus == 0) 400 return (0); 401 402 /* If ACPI told the error is fatal -- make it so. */ 403 if (ges->ErrorSeverity == ACPI_HEST_GEN_ERROR_FATAL) 404 panic("APEI Fatal Hardware Error!"); 405 406 /* Copy the buffer for later processing. */ 407 gesc = (ACPI_HEST_GENERIC_STATUS *)ge->copybuf; 408 if (gesc->BlockStatus == 0) 409 memcpy(ge->copybuf, ge->buf, ge->v1.ErrorBlockLength); 410 411 /* Acknowledge the error has been processed. */ 412 ges->BlockStatus = 0; 413 if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 && 414 ge->res2) { 415 uint64_t val = READ8(ge->res2, 0); 416 val &= ge->v2.ReadAckPreserve; 417 val |= ge->v2.ReadAckWrite; 418 WRITE8(ge->res2, 0, val); 419 } 420 421 /* Schedule SWI for real handling. */ 422 swi_sched(ge->swi_ih, SWI_FROMNMI); 423 424 return (1); 425 } 426 427 static void 428 apei_callout_handler(void *context) 429 { 430 struct apei_ge *ge = context; 431 432 apei_ge_handler(ge, false); 433 callout_schedule(&ge->poll, ge->v1.Notify.PollInterval * hz / 1000); 434 } 435 436 static void 437 apei_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 438 { 439 device_t dev = context; 440 struct apei_softc *sc = device_get_softc(dev); 441 struct apei_ge *ge; 442 443 TAILQ_FOREACH(ge, &sc->ges, link) { 444 if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI || 445 ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO || 446 ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) 447 apei_ge_handler(ge, false); 448 } 449 } 450 451 static int 452 hest_parse_structure(struct apei_softc *sc, void *addr, int remaining) 453 { 454 ACPI_HEST_HEADER *hdr = addr; 455 struct apei_ge *ge; 456 457 if (remaining < (int)sizeof(ACPI_HEST_HEADER)) 458 return (-1); 459 460 switch (hdr->Type) { 461 case ACPI_HEST_TYPE_IA32_CHECK: { 462 ACPI_HEST_IA_MACHINE_CHECK *s = addr; 463 return (sizeof(*s) + s->NumHardwareBanks * 464 sizeof(ACPI_HEST_IA_ERROR_BANK)); 465 } 466 case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: { 467 ACPI_HEST_IA_CORRECTED *s = addr; 468 return (sizeof(*s) + s->NumHardwareBanks * 469 sizeof(ACPI_HEST_IA_ERROR_BANK)); 470 } 471 case ACPI_HEST_TYPE_IA32_NMI: { 472 ACPI_HEST_IA_NMI *s = addr; 473 return (sizeof(*s)); 474 } 475 case ACPI_HEST_TYPE_AER_ROOT_PORT: { 476 ACPI_HEST_AER_ROOT *s = addr; 477 return (sizeof(*s)); 478 } 479 case ACPI_HEST_TYPE_AER_ENDPOINT: { 480 ACPI_HEST_AER *s = addr; 481 return (sizeof(*s)); 482 } 483 case ACPI_HEST_TYPE_AER_BRIDGE: { 484 ACPI_HEST_AER_BRIDGE *s = addr; 485 return (sizeof(*s)); 486 } 487 case ACPI_HEST_TYPE_GENERIC_ERROR: { 488 ACPI_HEST_GENERIC *s = addr; 489 ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO); 490 ge->v1 = *s; 491 TAILQ_INSERT_TAIL(&sc->ges, ge, link); 492 return (sizeof(*s)); 493 } 494 case ACPI_HEST_TYPE_GENERIC_ERROR_V2: { 495 ACPI_HEST_GENERIC_V2 *s = addr; 496 ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO); 497 ge->v2 = *s; 498 TAILQ_INSERT_TAIL(&sc->ges, ge, link); 499 return (sizeof(*s)); 500 } 501 case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: { 502 ACPI_HEST_IA_DEFERRED_CHECK *s = addr; 503 return (sizeof(*s) + s->NumHardwareBanks * 504 sizeof(ACPI_HEST_IA_ERROR_BANK)); 505 } 506 default: 507 return (-1); 508 } 509 } 510 511 static void 512 hest_parse_table(struct apei_softc *sc) 513 { 514 ACPI_TABLE_HEST *hest = sc->hest; 515 char *cp; 516 int remaining, consumed; 517 518 remaining = hest->Header.Length - sizeof(ACPI_TABLE_HEST); 519 while (remaining > 0) { 520 cp = (char *)hest + hest->Header.Length - remaining; 521 consumed = hest_parse_structure(sc, cp, remaining); 522 if (consumed <= 0) 523 break; 524 else 525 remaining -= consumed; 526 } 527 } 528 529 static char *apei_ids[] = { "PNP0C33", NULL }; 530 static devclass_t apei_devclass; 531 532 static ACPI_STATUS 533 apei_find(ACPI_HANDLE handle, UINT32 level, void *context, 534 void **status) 535 { 536 int *found = (int *)status; 537 char **ids; 538 539 for (ids = apei_ids; *ids != NULL; ids++) { 540 if (acpi_MatchHid(handle, *ids)) { 541 *found = 1; 542 break; 543 } 544 } 545 return (AE_OK); 546 } 547 548 static void 549 apei_identify(driver_t *driver, device_t parent) 550 { 551 device_t child; 552 int found; 553 ACPI_TABLE_HEADER *hest; 554 ACPI_STATUS status; 555 556 if (acpi_disabled("apei")) 557 return; 558 559 /* Without HEST table we have nothing to do. */ 560 status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest); 561 if (ACPI_FAILURE(status)) 562 return; 563 AcpiPutTable(hest); 564 565 /* Only one APEI device can exist. */ 566 if (devclass_get_device(apei_devclass, 0)) 567 return; 568 569 /* Search for ACPI error device to be used. */ 570 found = 0; 571 AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 572 100, apei_find, NULL, NULL, (void *)&found); 573 if (found) 574 return; 575 576 /* If not found - create a fake one. */ 577 child = BUS_ADD_CHILD(parent, 2, "apei", 0); 578 if (child == NULL) 579 printf("%s: can't add child\n", __func__); 580 } 581 582 static int 583 apei_probe(device_t dev) 584 { 585 ACPI_TABLE_HEADER *hest; 586 ACPI_STATUS status; 587 int rv; 588 589 if (acpi_disabled("apei")) 590 return (ENXIO); 591 592 if (acpi_get_handle(dev) != NULL) { 593 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, apei_ids, NULL); 594 if (rv > 0) 595 return (rv); 596 } else 597 rv = 0; 598 599 /* Without HEST table we have nothing to do. */ 600 status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest); 601 if (ACPI_FAILURE(status)) 602 return (ENXIO); 603 AcpiPutTable(hest); 604 605 device_set_desc(dev, "ACPI Platform Error Interface"); 606 return (rv); 607 } 608 609 static int 610 apei_attach(device_t dev) 611 { 612 struct apei_softc *sc = device_get_softc(dev); 613 struct apei_ge *ge; 614 ACPI_STATUS status; 615 int rid; 616 617 TAILQ_INIT(&sc->ges); 618 619 /* Search and parse HEST table. */ 620 status = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&sc->hest); 621 if (ACPI_FAILURE(status)) 622 return (ENXIO); 623 hest_parse_table(sc); 624 AcpiPutTable((ACPI_TABLE_HEADER *)sc->hest); 625 626 rid = 0; 627 TAILQ_FOREACH(ge, &sc->ges, link) { 628 ge->res_rid = rid++; 629 acpi_bus_alloc_gas(dev, &ge->res_type, &ge->res_rid, 630 &ge->v1.ErrorStatusAddress, &ge->res, 0); 631 if (ge->res) { 632 ge->buf = pmap_mapdev_attr(READ8(ge->res, 0), 633 ge->v1.ErrorBlockLength, VM_MEMATTR_WRITE_COMBINING); 634 } else { 635 device_printf(dev, "Can't allocate status resource.\n"); 636 } 637 if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) { 638 ge->res2_rid = rid++; 639 acpi_bus_alloc_gas(dev, &ge->res2_type, &ge->res2_rid, 640 &ge->v2.ReadAckRegister, &ge->res2, 0); 641 if (ge->res2 == NULL) 642 device_printf(dev, "Can't allocate ack resource.\n"); 643 } 644 if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) { 645 callout_init(&ge->poll, 1); 646 callout_reset(&ge->poll, 647 ge->v1.Notify.PollInterval * hz / 1000, 648 apei_callout_handler, ge); 649 } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) { 650 ge->copybuf = malloc(ge->v1.ErrorBlockLength, 651 M_DEVBUF, M_WAITOK | M_ZERO); 652 swi_add(&clk_intr_event, "apei", apei_nmi_swi, ge, 653 SWI_CLOCK, INTR_MPSAFE, &ge->swi_ih); 654 apei_nmi_ge = ge; 655 apei_nmi = apei_nmi_handler; 656 } 657 } 658 659 if (acpi_get_handle(dev) != NULL) { 660 AcpiInstallNotifyHandler(acpi_get_handle(dev), 661 ACPI_DEVICE_NOTIFY, apei_notify_handler, dev); 662 } 663 return (0); 664 } 665 666 static int 667 apei_detach(device_t dev) 668 { 669 struct apei_softc *sc = device_get_softc(dev); 670 struct apei_ge *ge; 671 672 apei_nmi = NULL; 673 apei_nmi_ge = NULL; 674 if (acpi_get_handle(dev) != NULL) { 675 AcpiRemoveNotifyHandler(acpi_get_handle(dev), 676 ACPI_DEVICE_NOTIFY, apei_notify_handler); 677 } 678 679 while ((ge = TAILQ_FIRST(&sc->ges)) != NULL) { 680 TAILQ_REMOVE(&sc->ges, ge, link); 681 if (ge->res) { 682 bus_release_resource(dev, ge->res_type, 683 ge->res_rid, ge->res); 684 } 685 if (ge->res2) { 686 bus_release_resource(dev, ge->res2_type, 687 ge->res2_rid, ge->res2); 688 } 689 if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) { 690 callout_drain(&ge->poll); 691 } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) { 692 swi_remove(&ge->swi_ih); 693 free(ge->copybuf, M_DEVBUF); 694 } 695 if (ge->buf) { 696 pmap_unmapdev((vm_offset_t)ge->buf, 697 ge->v1.ErrorBlockLength); 698 } 699 free(ge, M_DEVBUF); 700 } 701 return (0); 702 } 703 704 static device_method_t apei_methods[] = { 705 /* Device interface */ 706 DEVMETHOD(device_identify, apei_identify), 707 DEVMETHOD(device_probe, apei_probe), 708 DEVMETHOD(device_attach, apei_attach), 709 DEVMETHOD(device_detach, apei_detach), 710 DEVMETHOD_END 711 }; 712 713 static driver_t apei_driver = { 714 "apei", 715 apei_methods, 716 sizeof(struct apei_softc), 717 }; 718 719 DRIVER_MODULE(apei, acpi, apei_driver, apei_devclass, 0, 0); 720 MODULE_DEPEND(apei, acpi, 1, 1, 1); 721