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