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