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