xref: /freebsd/sys/dev/acpica/acpi_apei.c (revision ebacd8013fe5f7fdf9f6a5b286f6680dd2891036)
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);
832