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