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