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