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