1855e49f3SAlexander Motin /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3855e49f3SAlexander Motin *
4855e49f3SAlexander Motin * Copyright (c) 2020 Alexander Motin <mav@FreeBSD.org>
5855e49f3SAlexander Motin *
6855e49f3SAlexander Motin * Redistribution and use in source and binary forms, with or without
7855e49f3SAlexander Motin * modification, are permitted provided that the following conditions
8855e49f3SAlexander Motin * are met:
9855e49f3SAlexander Motin * 1. Redistributions of source code must retain the above copyright
10855e49f3SAlexander Motin * notice, this list of conditions and the following disclaimer.
11855e49f3SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright
12855e49f3SAlexander Motin * notice, this list of conditions and the following disclaimer in the
13855e49f3SAlexander Motin * documentation and/or other materials provided with the distribution.
14855e49f3SAlexander Motin *
15855e49f3SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16855e49f3SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17855e49f3SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18855e49f3SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19855e49f3SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20855e49f3SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21855e49f3SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22855e49f3SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23855e49f3SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24855e49f3SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25855e49f3SAlexander Motin * SUCH DAMAGE.
26855e49f3SAlexander Motin */
27855e49f3SAlexander Motin
28855e49f3SAlexander Motin #include <sys/cdefs.h>
29855e49f3SAlexander Motin #include "opt_acpi.h"
309f91d464SAlexander Motin #include "opt_pci.h"
31855e49f3SAlexander Motin
32855e49f3SAlexander Motin #include <sys/param.h>
33855e49f3SAlexander Motin #include <sys/systm.h>
34855e49f3SAlexander Motin #include <sys/bus.h>
35855e49f3SAlexander Motin #include <sys/callout.h>
36855e49f3SAlexander Motin #include <sys/interrupt.h>
37855e49f3SAlexander Motin #include <sys/kernel.h>
38855e49f3SAlexander Motin #include <sys/malloc.h>
39855e49f3SAlexander Motin #include <sys/module.h>
40855e49f3SAlexander Motin #include <sys/queue.h>
41855e49f3SAlexander Motin #include <sys/rman.h>
42855e49f3SAlexander Motin #include <vm/vm.h>
43855e49f3SAlexander Motin #include <vm/pmap.h>
44855e49f3SAlexander Motin
45855e49f3SAlexander Motin #include <contrib/dev/acpica/include/acpi.h>
46855e49f3SAlexander Motin #include <contrib/dev/acpica/include/accommon.h>
47855e49f3SAlexander Motin #include <contrib/dev/acpica/include/aclocal.h>
48855e49f3SAlexander Motin #include <contrib/dev/acpica/include/actables.h>
49855e49f3SAlexander Motin
50855e49f3SAlexander Motin #include <dev/acpica/acpivar.h>
51855e49f3SAlexander Motin #include <dev/pci/pcireg.h>
52855e49f3SAlexander Motin #include <dev/pci/pcivar.h>
53855e49f3SAlexander Motin
54855e49f3SAlexander Motin struct apei_ge {
55855e49f3SAlexander Motin union {
56855e49f3SAlexander Motin ACPI_HEST_GENERIC v1;
57855e49f3SAlexander Motin ACPI_HEST_GENERIC_V2 v2;
58855e49f3SAlexander Motin };
59855e49f3SAlexander Motin int res_type;
60855e49f3SAlexander Motin int res_rid;
61855e49f3SAlexander Motin struct resource *res;
62855e49f3SAlexander Motin int res2_type;
63855e49f3SAlexander Motin int res2_rid;
64855e49f3SAlexander Motin struct resource *res2;
65855e49f3SAlexander Motin uint8_t *buf, *copybuf;
66855e49f3SAlexander Motin TAILQ_ENTRY(apei_ge) link;
672dfc1f73SAlexander Motin TAILQ_ENTRY(apei_ge) nlink;
682dfc1f73SAlexander Motin };
692dfc1f73SAlexander Motin
702dfc1f73SAlexander Motin /* NMI */
712dfc1f73SAlexander Motin struct apei_nges {
72855e49f3SAlexander Motin void *swi_ih;
732dfc1f73SAlexander Motin TAILQ_HEAD(, apei_ge) ges;
742dfc1f73SAlexander Motin } *apei_nmi_nges;
752dfc1f73SAlexander Motin
762dfc1f73SAlexander Motin /* Interrupt */
772dfc1f73SAlexander Motin struct apei_iges {
782dfc1f73SAlexander Motin TAILQ_HEAD(, apei_ge) ges;
792dfc1f73SAlexander Motin };
802dfc1f73SAlexander Motin
812dfc1f73SAlexander Motin /* Polling */
822dfc1f73SAlexander Motin struct apei_pges {
832dfc1f73SAlexander Motin sbintime_t interval;
842dfc1f73SAlexander Motin struct callout poll;
852dfc1f73SAlexander Motin TAILQ_HEAD(, apei_ge) ges;
862dfc1f73SAlexander Motin };
87855e49f3SAlexander Motin
88855e49f3SAlexander Motin struct apei_softc {
89855e49f3SAlexander Motin ACPI_TABLE_HEST *hest;
90855e49f3SAlexander Motin TAILQ_HEAD(, apei_ge) ges;
912dfc1f73SAlexander Motin struct apei_nges nges;
922dfc1f73SAlexander Motin struct apei_iges iges;
932dfc1f73SAlexander Motin struct apei_pges pges[32];
94855e49f3SAlexander Motin };
95855e49f3SAlexander Motin
96855e49f3SAlexander Motin struct apei_mem_error {
97855e49f3SAlexander Motin uint64_t ValidationBits;
98855e49f3SAlexander Motin uint64_t ErrorStatus;
99855e49f3SAlexander Motin uint64_t PhysicalAddress;
100855e49f3SAlexander Motin uint64_t PhysicalAddressMask;
101855e49f3SAlexander Motin uint16_t Node;
102855e49f3SAlexander Motin uint16_t Card;
103855e49f3SAlexander Motin uint16_t Module;
104855e49f3SAlexander Motin uint16_t Bank;
105855e49f3SAlexander Motin uint16_t Device;
106855e49f3SAlexander Motin uint16_t Row;
107855e49f3SAlexander Motin uint16_t Column;
108855e49f3SAlexander Motin uint16_t BitPosition;
109855e49f3SAlexander Motin uint64_t RequesterID;
110855e49f3SAlexander Motin uint64_t ResponderID;
111855e49f3SAlexander Motin uint64_t TargetID;
112855e49f3SAlexander Motin uint8_t MemoryErrorType;
113855e49f3SAlexander Motin uint8_t Extended;
114855e49f3SAlexander Motin uint16_t RankNumber;
115855e49f3SAlexander Motin uint16_t CardHandle;
116855e49f3SAlexander Motin uint16_t ModuleHandle;
117855e49f3SAlexander Motin };
118855e49f3SAlexander Motin
119855e49f3SAlexander Motin struct apei_pcie_error {
120855e49f3SAlexander Motin uint64_t ValidationBits;
121855e49f3SAlexander Motin uint32_t PortType;
122855e49f3SAlexander Motin uint32_t Version;
123855e49f3SAlexander Motin uint32_t CommandStatus;
124855e49f3SAlexander Motin uint32_t Reserved;
125855e49f3SAlexander Motin uint8_t DeviceID[16];
126855e49f3SAlexander Motin uint8_t DeviceSerialNumber[8];
127855e49f3SAlexander Motin uint8_t BridgeControlStatus[4];
128855e49f3SAlexander Motin uint8_t CapabilityStructure[60];
129855e49f3SAlexander Motin uint8_t AERInfo[96];
130855e49f3SAlexander Motin };
131855e49f3SAlexander Motin
132855e49f3SAlexander Motin #ifdef __i386__
133855e49f3SAlexander Motin static __inline uint64_t
apei_bus_read_8(struct resource * res,bus_size_t offset)134855e49f3SAlexander Motin apei_bus_read_8(struct resource *res, bus_size_t offset)
135855e49f3SAlexander Motin {
136855e49f3SAlexander Motin return (bus_read_4(res, offset) |
137855e49f3SAlexander Motin ((uint64_t)bus_read_4(res, offset + 4)) << 32);
138855e49f3SAlexander Motin }
139855e49f3SAlexander Motin static __inline void
apei_bus_write_8(struct resource * res,bus_size_t offset,uint64_t val)140855e49f3SAlexander Motin apei_bus_write_8(struct resource *res, bus_size_t offset, uint64_t val)
141855e49f3SAlexander Motin {
142855e49f3SAlexander Motin bus_write_4(res, offset, val);
143855e49f3SAlexander Motin bus_write_4(res, offset + 4, val >> 32);
144855e49f3SAlexander Motin }
145855e49f3SAlexander Motin #define READ8(r, o) apei_bus_read_8((r), (o))
146855e49f3SAlexander Motin #define WRITE8(r, o, v) apei_bus_write_8((r), (o), (v))
147855e49f3SAlexander Motin #else
148855e49f3SAlexander Motin #define READ8(r, o) bus_read_8((r), (o))
149855e49f3SAlexander Motin #define WRITE8(r, o, v) bus_write_8((r), (o), (v))
150855e49f3SAlexander Motin #endif
151855e49f3SAlexander Motin
152ba83762aSAlexander Motin #define GED_SIZE(ged) ((ged)->Revision >= 0x300 ? \
153ba83762aSAlexander Motin sizeof(ACPI_HEST_GENERIC_DATA_V300) : sizeof(ACPI_HEST_GENERIC_DATA))
154ba83762aSAlexander Motin #define GED_DATA(ged) ((uint8_t *)(ged) + GED_SIZE(ged))
155ba83762aSAlexander Motin
1562dfc1f73SAlexander Motin #define PGE_ID(ge) (fls(MAX(1, (ge)->v1.Notify.PollInterval)) - 1)
1572dfc1f73SAlexander Motin
15852a54b96SAlexander Motin static struct sysctl_ctx_list apei_sysctl_ctx;
15952a54b96SAlexander Motin static struct sysctl_oid *apei_sysctl_tree;
16052a54b96SAlexander Motin static int log_corrected = 1;
16152a54b96SAlexander Motin
162855e49f3SAlexander Motin int apei_nmi_handler(void);
163855e49f3SAlexander Motin
164855e49f3SAlexander Motin static const char *
apei_severity(uint32_t s)165855e49f3SAlexander Motin apei_severity(uint32_t s)
166855e49f3SAlexander Motin {
167855e49f3SAlexander Motin switch (s) {
168855e49f3SAlexander Motin case ACPI_HEST_GEN_ERROR_RECOVERABLE:
169855e49f3SAlexander Motin return ("Recoverable");
170855e49f3SAlexander Motin case ACPI_HEST_GEN_ERROR_FATAL:
171855e49f3SAlexander Motin return ("Fatal");
172855e49f3SAlexander Motin case ACPI_HEST_GEN_ERROR_CORRECTED:
173855e49f3SAlexander Motin return ("Corrected");
174855e49f3SAlexander Motin case ACPI_HEST_GEN_ERROR_NONE:
175855e49f3SAlexander Motin return ("Informational");
176855e49f3SAlexander Motin }
177855e49f3SAlexander Motin return ("???");
178855e49f3SAlexander Motin }
179855e49f3SAlexander Motin
180855e49f3SAlexander Motin static int
apei_mem_handler(ACPI_HEST_GENERIC_DATA * ged)181855e49f3SAlexander Motin apei_mem_handler(ACPI_HEST_GENERIC_DATA *ged)
182855e49f3SAlexander Motin {
183ba83762aSAlexander Motin struct apei_mem_error *p = (struct apei_mem_error *)GED_DATA(ged);
184855e49f3SAlexander Motin
18552a54b96SAlexander Motin if (!log_corrected &&
18652a54b96SAlexander Motin (ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_CORRECTED ||
18752a54b96SAlexander Motin ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_NONE))
18852a54b96SAlexander Motin return (1);
18952a54b96SAlexander Motin
190855e49f3SAlexander Motin printf("APEI %s Memory Error:\n", apei_severity(ged->ErrorSeverity));
191855e49f3SAlexander Motin if (p->ValidationBits & 0x01)
192855e49f3SAlexander Motin printf(" Error Status: 0x%jx\n", p->ErrorStatus);
193855e49f3SAlexander Motin if (p->ValidationBits & 0x02)
194855e49f3SAlexander Motin printf(" Physical Address: 0x%jx\n", p->PhysicalAddress);
195855e49f3SAlexander Motin if (p->ValidationBits & 0x04)
196855e49f3SAlexander Motin printf(" Physical Address Mask: 0x%jx\n", p->PhysicalAddressMask);
197855e49f3SAlexander Motin if (p->ValidationBits & 0x08)
198855e49f3SAlexander Motin printf(" Node: %u\n", p->Node);
199855e49f3SAlexander Motin if (p->ValidationBits & 0x10)
200855e49f3SAlexander Motin printf(" Card: %u\n", p->Card);
201855e49f3SAlexander Motin if (p->ValidationBits & 0x20)
202855e49f3SAlexander Motin printf(" Module: %u\n", p->Module);
203855e49f3SAlexander Motin if (p->ValidationBits & 0x40)
204855e49f3SAlexander Motin printf(" Bank: %u\n", p->Bank);
205855e49f3SAlexander Motin if (p->ValidationBits & 0x80)
206855e49f3SAlexander Motin printf(" Device: %u\n", p->Device);
207855e49f3SAlexander Motin if (p->ValidationBits & 0x100)
208855e49f3SAlexander Motin printf(" Row: %u\n", p->Row);
209855e49f3SAlexander Motin if (p->ValidationBits & 0x200)
210855e49f3SAlexander Motin printf(" Column: %u\n", p->Column);
211855e49f3SAlexander Motin if (p->ValidationBits & 0x400)
212855e49f3SAlexander Motin printf(" Bit Position: %u\n", p->BitPosition);
213855e49f3SAlexander Motin if (p->ValidationBits & 0x800)
214855e49f3SAlexander Motin printf(" Requester ID: 0x%jx\n", p->RequesterID);
215855e49f3SAlexander Motin if (p->ValidationBits & 0x1000)
216855e49f3SAlexander Motin printf(" Responder ID: 0x%jx\n", p->ResponderID);
217855e49f3SAlexander Motin if (p->ValidationBits & 0x2000)
218855e49f3SAlexander Motin printf(" Target ID: 0x%jx\n", p->TargetID);
219855e49f3SAlexander Motin if (p->ValidationBits & 0x4000)
220855e49f3SAlexander Motin printf(" Memory Error Type: %u\n", p->MemoryErrorType);
221855e49f3SAlexander Motin if (p->ValidationBits & 0x8000)
222855e49f3SAlexander Motin printf(" Rank Number: %u\n", p->RankNumber);
223855e49f3SAlexander Motin if (p->ValidationBits & 0x10000)
224855e49f3SAlexander Motin printf(" Card Handle: 0x%x\n", p->CardHandle);
225855e49f3SAlexander Motin if (p->ValidationBits & 0x20000)
226855e49f3SAlexander Motin printf(" Module Handle: 0x%x\n", p->ModuleHandle);
227855e49f3SAlexander Motin if (p->ValidationBits & 0x40000)
228855e49f3SAlexander Motin printf(" Extended Row: %u\n",
229855e49f3SAlexander Motin (uint32_t)(p->Extended & 0x3) << 16 | p->Row);
230855e49f3SAlexander Motin if (p->ValidationBits & 0x80000)
231855e49f3SAlexander Motin printf(" Bank Group: %u\n", p->Bank >> 8);
232855e49f3SAlexander Motin if (p->ValidationBits & 0x100000)
233855e49f3SAlexander Motin printf(" Bank Address: %u\n", p->Bank & 0xff);
234855e49f3SAlexander Motin if (p->ValidationBits & 0x200000)
235855e49f3SAlexander Motin printf(" Chip Identification: %u\n", (p->Extended >> 5) & 0x7);
236855e49f3SAlexander Motin
237855e49f3SAlexander Motin return (0);
238855e49f3SAlexander Motin }
239855e49f3SAlexander Motin
240855e49f3SAlexander Motin static int
apei_pcie_handler(ACPI_HEST_GENERIC_DATA * ged)241855e49f3SAlexander Motin apei_pcie_handler(ACPI_HEST_GENERIC_DATA *ged)
242855e49f3SAlexander Motin {
243ba83762aSAlexander Motin struct apei_pcie_error *p = (struct apei_pcie_error *)GED_DATA(ged);
24452a54b96SAlexander Motin int off;
2459f91d464SAlexander Motin #ifdef DEV_PCI
246855e49f3SAlexander Motin device_t dev;
24752a54b96SAlexander Motin int h = 0, sev;
248855e49f3SAlexander Motin
249855e49f3SAlexander Motin if ((p->ValidationBits & 0x8) == 0x8) {
250855e49f3SAlexander Motin mtx_lock(&Giant);
251855e49f3SAlexander Motin dev = pci_find_dbsf((uint32_t)p->DeviceID[10] << 8 |
252855e49f3SAlexander Motin p->DeviceID[9], p->DeviceID[11], p->DeviceID[8],
253855e49f3SAlexander Motin p->DeviceID[7]);
254855e49f3SAlexander Motin if (dev != NULL) {
255855e49f3SAlexander Motin switch (ged->ErrorSeverity) {
256855e49f3SAlexander Motin case ACPI_HEST_GEN_ERROR_FATAL:
257855e49f3SAlexander Motin sev = PCIEM_STA_FATAL_ERROR;
258855e49f3SAlexander Motin break;
259855e49f3SAlexander Motin case ACPI_HEST_GEN_ERROR_RECOVERABLE:
260855e49f3SAlexander Motin sev = PCIEM_STA_NON_FATAL_ERROR;
261855e49f3SAlexander Motin break;
262855e49f3SAlexander Motin default:
263855e49f3SAlexander Motin sev = PCIEM_STA_CORRECTABLE_ERROR;
264855e49f3SAlexander Motin break;
265855e49f3SAlexander Motin }
266855e49f3SAlexander Motin pcie_apei_error(dev, sev,
267855e49f3SAlexander Motin (p->ValidationBits & 0x80) ? p->AERInfo : NULL);
268855e49f3SAlexander Motin h = 1;
269855e49f3SAlexander Motin }
270855e49f3SAlexander Motin mtx_unlock(&Giant);
271855e49f3SAlexander Motin }
272855e49f3SAlexander Motin if (h)
273855e49f3SAlexander Motin return (h);
2749f91d464SAlexander Motin #endif
275855e49f3SAlexander Motin
27652a54b96SAlexander Motin if (!log_corrected &&
27752a54b96SAlexander Motin (ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_CORRECTED ||
27852a54b96SAlexander Motin ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_NONE))
27952a54b96SAlexander Motin return (1);
28052a54b96SAlexander Motin
281855e49f3SAlexander Motin printf("APEI %s PCIe Error:\n", apei_severity(ged->ErrorSeverity));
282855e49f3SAlexander Motin if (p->ValidationBits & 0x01)
283855e49f3SAlexander Motin printf(" Port Type: %u\n", p->PortType);
284855e49f3SAlexander Motin if (p->ValidationBits & 0x02)
285855e49f3SAlexander Motin printf(" Version: %x\n", p->Version);
286855e49f3SAlexander Motin if (p->ValidationBits & 0x04)
287855e49f3SAlexander Motin printf(" Command Status: 0x%08x\n", p->CommandStatus);
288855e49f3SAlexander Motin if (p->ValidationBits & 0x08) {
289855e49f3SAlexander Motin printf(" DeviceID:");
290855e49f3SAlexander Motin for (off = 0; off < sizeof(p->DeviceID); off++)
291855e49f3SAlexander Motin printf(" %02x", p->DeviceID[off]);
292855e49f3SAlexander Motin printf("\n");
293855e49f3SAlexander Motin }
294855e49f3SAlexander Motin if (p->ValidationBits & 0x10) {
295855e49f3SAlexander Motin printf(" Device Serial Number:");
296855e49f3SAlexander Motin for (off = 0; off < sizeof(p->DeviceSerialNumber); off++)
297855e49f3SAlexander Motin printf(" %02x", p->DeviceSerialNumber[off]);
298855e49f3SAlexander Motin printf("\n");
299855e49f3SAlexander Motin }
300855e49f3SAlexander Motin if (p->ValidationBits & 0x20) {
301855e49f3SAlexander Motin printf(" Bridge Control Status:");
302855e49f3SAlexander Motin for (off = 0; off < sizeof(p->BridgeControlStatus); off++)
303855e49f3SAlexander Motin printf(" %02x", p->BridgeControlStatus[off]);
304855e49f3SAlexander Motin printf("\n");
305855e49f3SAlexander Motin }
306855e49f3SAlexander Motin if (p->ValidationBits & 0x40) {
307855e49f3SAlexander Motin printf(" Capability Structure:\n");
308855e49f3SAlexander Motin for (off = 0; off < sizeof(p->CapabilityStructure); off++) {
309855e49f3SAlexander Motin printf(" %02x", p->CapabilityStructure[off]);
310855e49f3SAlexander Motin if ((off % 16) == 15 ||
311855e49f3SAlexander Motin off + 1 == sizeof(p->CapabilityStructure))
312855e49f3SAlexander Motin printf("\n");
313855e49f3SAlexander Motin }
314855e49f3SAlexander Motin }
315855e49f3SAlexander Motin if (p->ValidationBits & 0x80) {
316855e49f3SAlexander Motin printf(" AER Info:\n");
317855e49f3SAlexander Motin for (off = 0; off < sizeof(p->AERInfo); off++) {
318855e49f3SAlexander Motin printf(" %02x", p->AERInfo[off]);
319855e49f3SAlexander Motin if ((off % 16) == 15 || off + 1 == sizeof(p->AERInfo))
320855e49f3SAlexander Motin printf("\n");
321855e49f3SAlexander Motin }
322855e49f3SAlexander Motin }
32352a54b96SAlexander Motin return (0);
324855e49f3SAlexander Motin }
325855e49f3SAlexander Motin
326855e49f3SAlexander Motin static void
apei_ged_handler(ACPI_HEST_GENERIC_DATA * ged)327855e49f3SAlexander Motin apei_ged_handler(ACPI_HEST_GENERIC_DATA *ged)
328855e49f3SAlexander Motin {
329855e49f3SAlexander Motin ACPI_HEST_GENERIC_DATA_V300 *ged3 = (ACPI_HEST_GENERIC_DATA_V300 *)ged;
330855e49f3SAlexander Motin /* A5BC1114-6F64-4EDE-B863-3E83ED7C83B1 */
331855e49f3SAlexander Motin static uint8_t mem_uuid[ACPI_UUID_LENGTH] = {
332855e49f3SAlexander Motin 0x14, 0x11, 0xBC, 0xA5, 0x64, 0x6F, 0xDE, 0x4E,
333855e49f3SAlexander Motin 0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83, 0xB1
334855e49f3SAlexander Motin };
335855e49f3SAlexander Motin /* D995E954-BBC1-430F-AD91-B44DCB3C6F35 */
336855e49f3SAlexander Motin static uint8_t pcie_uuid[ACPI_UUID_LENGTH] = {
337855e49f3SAlexander Motin 0x54, 0xE9, 0x95, 0xD9, 0xC1, 0xBB, 0x0F, 0x43,
338855e49f3SAlexander Motin 0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35
339855e49f3SAlexander Motin };
340855e49f3SAlexander Motin uint8_t *t;
341855e49f3SAlexander Motin int h = 0, off;
342855e49f3SAlexander Motin
343855e49f3SAlexander Motin if (memcmp(mem_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
344855e49f3SAlexander Motin h = apei_mem_handler(ged);
345855e49f3SAlexander Motin } else if (memcmp(pcie_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
346855e49f3SAlexander Motin h = apei_pcie_handler(ged);
347855e49f3SAlexander Motin } else {
34852a54b96SAlexander Motin if (!log_corrected &&
34952a54b96SAlexander Motin (ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_CORRECTED ||
35052a54b96SAlexander Motin ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_NONE))
35152a54b96SAlexander Motin return;
35252a54b96SAlexander Motin
353855e49f3SAlexander Motin t = ged->SectionType;
354855e49f3SAlexander Motin printf("APEI %s Error %02x%02x%02x%02x-%02x%02x-"
355855e49f3SAlexander Motin "%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x:\n",
356855e49f3SAlexander Motin apei_severity(ged->ErrorSeverity),
357855e49f3SAlexander Motin t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
358855e49f3SAlexander Motin t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
359855e49f3SAlexander Motin printf(" Error Data:\n");
360ba83762aSAlexander Motin t = (uint8_t *)GED_DATA(ged);
361855e49f3SAlexander Motin for (off = 0; off < ged->ErrorDataLength; off++) {
362855e49f3SAlexander Motin printf(" %02x", t[off]);
363855e49f3SAlexander Motin if ((off % 16) == 15 || off + 1 == ged->ErrorDataLength)
364855e49f3SAlexander Motin printf("\n");
365855e49f3SAlexander Motin }
366855e49f3SAlexander Motin }
367855e49f3SAlexander Motin if (h)
368855e49f3SAlexander Motin return;
369855e49f3SAlexander Motin
370855e49f3SAlexander Motin printf(" Flags: 0x%x\n", ged->Flags);
371855e49f3SAlexander Motin if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) {
372855e49f3SAlexander Motin t = ged->FruId;
373855e49f3SAlexander Motin printf(" FRU Id: %02x%02x%02x%02x-%02x%02x-%02x%02x-"
374855e49f3SAlexander Motin "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
375855e49f3SAlexander Motin t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
376855e49f3SAlexander Motin t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
377855e49f3SAlexander Motin }
378855e49f3SAlexander Motin if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING)
3798fee65d0SAlexander Motin printf(" FRU Text: %.20s\n", ged->FruText);
380ba83762aSAlexander Motin if (ged->Revision >= 0x300 &&
381855e49f3SAlexander Motin ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP)
3828fee65d0SAlexander Motin printf(" Timestamp: %016jx\n", ged3->TimeStamp);
383855e49f3SAlexander Motin }
384855e49f3SAlexander Motin
385855e49f3SAlexander Motin static int
apei_ge_handler(struct apei_ge * ge,bool copy)386855e49f3SAlexander Motin apei_ge_handler(struct apei_ge *ge, bool copy)
387855e49f3SAlexander Motin {
388855e49f3SAlexander Motin uint8_t *buf = copy ? ge->copybuf : ge->buf;
389855e49f3SAlexander Motin ACPI_HEST_GENERIC_STATUS *ges = (ACPI_HEST_GENERIC_STATUS *)buf;
390855e49f3SAlexander Motin ACPI_HEST_GENERIC_DATA *ged;
3913b248a21SAlexander Motin size_t off, len;
392855e49f3SAlexander Motin uint32_t sev;
3933b248a21SAlexander Motin int i, c;
394855e49f3SAlexander Motin
395a4566383SAlexander Motin if (ges == NULL || ges->BlockStatus == 0)
396855e49f3SAlexander Motin return (0);
397855e49f3SAlexander Motin
398855e49f3SAlexander Motin c = (ges->BlockStatus >> 4) & 0x3ff;
399855e49f3SAlexander Motin sev = ges->ErrorSeverity;
400855e49f3SAlexander Motin
401855e49f3SAlexander Motin /* Process error entries. */
4023b248a21SAlexander Motin len = MIN(ge->v1.ErrorBlockLength - sizeof(*ges), ges->DataLength);
4033b248a21SAlexander Motin for (off = i = 0; i < c && off + sizeof(*ged) <= len; i++) {
404855e49f3SAlexander Motin ged = (ACPI_HEST_GENERIC_DATA *)&buf[sizeof(*ges) + off];
4053b248a21SAlexander Motin if ((uint64_t)GED_SIZE(ged) + ged->ErrorDataLength > len - off)
4063b248a21SAlexander Motin break;
407855e49f3SAlexander Motin apei_ged_handler(ged);
408ba83762aSAlexander Motin off += GED_SIZE(ged) + ged->ErrorDataLength;
409855e49f3SAlexander Motin }
410855e49f3SAlexander Motin
411855e49f3SAlexander Motin /* Acknowledge the error has been processed. */
412855e49f3SAlexander Motin ges->BlockStatus = 0;
413a4566383SAlexander Motin if (!copy && ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 &&
414a4566383SAlexander Motin ge->res2) {
415855e49f3SAlexander Motin uint64_t val = READ8(ge->res2, 0);
416855e49f3SAlexander Motin val &= ge->v2.ReadAckPreserve;
417855e49f3SAlexander Motin val |= ge->v2.ReadAckWrite;
418855e49f3SAlexander Motin WRITE8(ge->res2, 0, val);
419855e49f3SAlexander Motin }
420855e49f3SAlexander Motin
421855e49f3SAlexander Motin /* If ACPI told the error is fatal -- make it so. */
422855e49f3SAlexander Motin if (sev == ACPI_HEST_GEN_ERROR_FATAL)
423855e49f3SAlexander Motin panic("APEI Fatal Hardware Error!");
424855e49f3SAlexander Motin
425855e49f3SAlexander Motin return (1);
426855e49f3SAlexander Motin }
427855e49f3SAlexander Motin
428855e49f3SAlexander Motin static void
apei_nmi_swi(void * arg)429855e49f3SAlexander Motin apei_nmi_swi(void *arg)
430855e49f3SAlexander Motin {
4312dfc1f73SAlexander Motin struct apei_nges *nges = arg;
4322dfc1f73SAlexander Motin struct apei_ge *ge;
433855e49f3SAlexander Motin
4342dfc1f73SAlexander Motin TAILQ_FOREACH(ge, &nges->ges, nlink)
435855e49f3SAlexander Motin apei_ge_handler(ge, true);
436855e49f3SAlexander Motin }
437855e49f3SAlexander Motin
438855e49f3SAlexander Motin int
apei_nmi_handler(void)439855e49f3SAlexander Motin apei_nmi_handler(void)
440855e49f3SAlexander Motin {
4412dfc1f73SAlexander Motin struct apei_nges *nges = apei_nmi_nges;
4422dfc1f73SAlexander Motin struct apei_ge *ge;
443855e49f3SAlexander Motin ACPI_HEST_GENERIC_STATUS *ges, *gesc;
4442dfc1f73SAlexander Motin int handled = 0;
445855e49f3SAlexander Motin
4462dfc1f73SAlexander Motin if (nges == NULL)
447855e49f3SAlexander Motin return (0);
448855e49f3SAlexander Motin
4492dfc1f73SAlexander Motin TAILQ_FOREACH(ge, &nges->ges, nlink) {
450855e49f3SAlexander Motin ges = (ACPI_HEST_GENERIC_STATUS *)ge->buf;
451a4566383SAlexander Motin if (ges == NULL || ges->BlockStatus == 0)
4522dfc1f73SAlexander Motin continue;
453855e49f3SAlexander Motin
454855e49f3SAlexander Motin /* If ACPI told the error is fatal -- make it so. */
455855e49f3SAlexander Motin if (ges->ErrorSeverity == ACPI_HEST_GEN_ERROR_FATAL)
456855e49f3SAlexander Motin panic("APEI Fatal Hardware Error!");
457855e49f3SAlexander Motin
458855e49f3SAlexander Motin /* Copy the buffer for later processing. */
459855e49f3SAlexander Motin gesc = (ACPI_HEST_GENERIC_STATUS *)ge->copybuf;
460855e49f3SAlexander Motin if (gesc->BlockStatus == 0)
461855e49f3SAlexander Motin memcpy(ge->copybuf, ge->buf, ge->v1.ErrorBlockLength);
462855e49f3SAlexander Motin
463855e49f3SAlexander Motin /* Acknowledge the error has been processed. */
464855e49f3SAlexander Motin ges->BlockStatus = 0;
465a4566383SAlexander Motin if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 &&
466a4566383SAlexander Motin ge->res2) {
467855e49f3SAlexander Motin uint64_t val = READ8(ge->res2, 0);
468855e49f3SAlexander Motin val &= ge->v2.ReadAckPreserve;
469855e49f3SAlexander Motin val |= ge->v2.ReadAckWrite;
470855e49f3SAlexander Motin WRITE8(ge->res2, 0, val);
471855e49f3SAlexander Motin }
4722dfc1f73SAlexander Motin handled = 1;
4732dfc1f73SAlexander Motin }
474855e49f3SAlexander Motin
475855e49f3SAlexander Motin /* Schedule SWI for real handling. */
4762dfc1f73SAlexander Motin if (handled)
4772dfc1f73SAlexander Motin swi_sched(nges->swi_ih, SWI_FROMNMI);
478855e49f3SAlexander Motin
4792dfc1f73SAlexander Motin return (handled);
480855e49f3SAlexander Motin }
481855e49f3SAlexander Motin
482855e49f3SAlexander Motin static void
apei_callout_handler(void * context)483855e49f3SAlexander Motin apei_callout_handler(void *context)
484855e49f3SAlexander Motin {
4852dfc1f73SAlexander Motin struct apei_pges *pges = context;
4862dfc1f73SAlexander Motin struct apei_ge *ge;
487855e49f3SAlexander Motin
4882dfc1f73SAlexander Motin TAILQ_FOREACH(ge, &pges->ges, nlink)
489855e49f3SAlexander Motin apei_ge_handler(ge, false);
4902dfc1f73SAlexander Motin callout_schedule_sbt(&pges->poll, pges->interval, pges->interval, 0);
491855e49f3SAlexander Motin }
492855e49f3SAlexander Motin
493855e49f3SAlexander Motin static void
apei_notify_handler(ACPI_HANDLE h,UINT32 notify,void * context)494855e49f3SAlexander Motin apei_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
495855e49f3SAlexander Motin {
496855e49f3SAlexander Motin device_t dev = context;
497855e49f3SAlexander Motin struct apei_softc *sc = device_get_softc(dev);
498855e49f3SAlexander Motin struct apei_ge *ge;
499855e49f3SAlexander Motin
5002dfc1f73SAlexander Motin TAILQ_FOREACH(ge, &sc->iges.ges, nlink)
501855e49f3SAlexander Motin apei_ge_handler(ge, false);
502855e49f3SAlexander Motin }
503855e49f3SAlexander Motin
504855e49f3SAlexander Motin static int
hest_parse_structure(struct apei_softc * sc,void * addr,int remaining)505855e49f3SAlexander Motin hest_parse_structure(struct apei_softc *sc, void *addr, int remaining)
506855e49f3SAlexander Motin {
507855e49f3SAlexander Motin ACPI_HEST_HEADER *hdr = addr;
508855e49f3SAlexander Motin struct apei_ge *ge;
509855e49f3SAlexander Motin
510855e49f3SAlexander Motin if (remaining < (int)sizeof(ACPI_HEST_HEADER))
511855e49f3SAlexander Motin return (-1);
512855e49f3SAlexander Motin
513855e49f3SAlexander Motin switch (hdr->Type) {
514855e49f3SAlexander Motin case ACPI_HEST_TYPE_IA32_CHECK: {
515855e49f3SAlexander Motin ACPI_HEST_IA_MACHINE_CHECK *s = addr;
516855e49f3SAlexander Motin return (sizeof(*s) + s->NumHardwareBanks *
517855e49f3SAlexander Motin sizeof(ACPI_HEST_IA_ERROR_BANK));
518855e49f3SAlexander Motin }
519855e49f3SAlexander Motin case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: {
520855e49f3SAlexander Motin ACPI_HEST_IA_CORRECTED *s = addr;
521855e49f3SAlexander Motin return (sizeof(*s) + s->NumHardwareBanks *
522855e49f3SAlexander Motin sizeof(ACPI_HEST_IA_ERROR_BANK));
523855e49f3SAlexander Motin }
524855e49f3SAlexander Motin case ACPI_HEST_TYPE_IA32_NMI: {
525855e49f3SAlexander Motin ACPI_HEST_IA_NMI *s = addr;
526855e49f3SAlexander Motin return (sizeof(*s));
527855e49f3SAlexander Motin }
528855e49f3SAlexander Motin case ACPI_HEST_TYPE_AER_ROOT_PORT: {
529855e49f3SAlexander Motin ACPI_HEST_AER_ROOT *s = addr;
530855e49f3SAlexander Motin return (sizeof(*s));
531855e49f3SAlexander Motin }
532855e49f3SAlexander Motin case ACPI_HEST_TYPE_AER_ENDPOINT: {
533855e49f3SAlexander Motin ACPI_HEST_AER *s = addr;
534855e49f3SAlexander Motin return (sizeof(*s));
535855e49f3SAlexander Motin }
536855e49f3SAlexander Motin case ACPI_HEST_TYPE_AER_BRIDGE: {
537855e49f3SAlexander Motin ACPI_HEST_AER_BRIDGE *s = addr;
538855e49f3SAlexander Motin return (sizeof(*s));
539855e49f3SAlexander Motin }
540855e49f3SAlexander Motin case ACPI_HEST_TYPE_GENERIC_ERROR: {
541855e49f3SAlexander Motin ACPI_HEST_GENERIC *s = addr;
542855e49f3SAlexander Motin ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
543855e49f3SAlexander Motin ge->v1 = *s;
544855e49f3SAlexander Motin TAILQ_INSERT_TAIL(&sc->ges, ge, link);
545855e49f3SAlexander Motin return (sizeof(*s));
546855e49f3SAlexander Motin }
547855e49f3SAlexander Motin case ACPI_HEST_TYPE_GENERIC_ERROR_V2: {
548855e49f3SAlexander Motin ACPI_HEST_GENERIC_V2 *s = addr;
549855e49f3SAlexander Motin ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
550855e49f3SAlexander Motin ge->v2 = *s;
551855e49f3SAlexander Motin TAILQ_INSERT_TAIL(&sc->ges, ge, link);
552855e49f3SAlexander Motin return (sizeof(*s));
553855e49f3SAlexander Motin }
554855e49f3SAlexander Motin case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: {
555855e49f3SAlexander Motin ACPI_HEST_IA_DEFERRED_CHECK *s = addr;
556855e49f3SAlexander Motin return (sizeof(*s) + s->NumHardwareBanks *
557855e49f3SAlexander Motin sizeof(ACPI_HEST_IA_ERROR_BANK));
558855e49f3SAlexander Motin }
559855e49f3SAlexander Motin default:
560855e49f3SAlexander Motin return (-1);
561855e49f3SAlexander Motin }
562855e49f3SAlexander Motin }
563855e49f3SAlexander Motin
564855e49f3SAlexander Motin static void
hest_parse_table(struct apei_softc * sc)565855e49f3SAlexander Motin hest_parse_table(struct apei_softc *sc)
566855e49f3SAlexander Motin {
567855e49f3SAlexander Motin ACPI_TABLE_HEST *hest = sc->hest;
568855e49f3SAlexander Motin char *cp;
569855e49f3SAlexander Motin int remaining, consumed;
570855e49f3SAlexander Motin
571855e49f3SAlexander Motin remaining = hest->Header.Length - sizeof(ACPI_TABLE_HEST);
572855e49f3SAlexander Motin while (remaining > 0) {
573855e49f3SAlexander Motin cp = (char *)hest + hest->Header.Length - remaining;
574855e49f3SAlexander Motin consumed = hest_parse_structure(sc, cp, remaining);
575855e49f3SAlexander Motin if (consumed <= 0)
576855e49f3SAlexander Motin break;
577855e49f3SAlexander Motin else
578855e49f3SAlexander Motin remaining -= consumed;
579855e49f3SAlexander Motin }
580855e49f3SAlexander Motin }
581855e49f3SAlexander Motin
582855e49f3SAlexander Motin static char *apei_ids[] = { "PNP0C33", NULL };
583855e49f3SAlexander Motin
584855e49f3SAlexander Motin static ACPI_STATUS
apei_find(ACPI_HANDLE handle,UINT32 level,void * context,void ** status)585855e49f3SAlexander Motin apei_find(ACPI_HANDLE handle, UINT32 level, void *context,
586855e49f3SAlexander Motin void **status)
587855e49f3SAlexander Motin {
588855e49f3SAlexander Motin int *found = (int *)status;
589855e49f3SAlexander Motin char **ids;
590855e49f3SAlexander Motin
591855e49f3SAlexander Motin for (ids = apei_ids; *ids != NULL; ids++) {
592855e49f3SAlexander Motin if (acpi_MatchHid(handle, *ids)) {
593855e49f3SAlexander Motin *found = 1;
594855e49f3SAlexander Motin break;
595855e49f3SAlexander Motin }
596855e49f3SAlexander Motin }
597855e49f3SAlexander Motin return (AE_OK);
598855e49f3SAlexander Motin }
599855e49f3SAlexander Motin
600855e49f3SAlexander Motin static void
apei_identify(driver_t * driver,device_t parent)601855e49f3SAlexander Motin apei_identify(driver_t *driver, device_t parent)
602855e49f3SAlexander Motin {
603855e49f3SAlexander Motin device_t child;
604855e49f3SAlexander Motin int found;
6053b580150SAlexander Motin ACPI_TABLE_HEADER *hest;
6063b580150SAlexander Motin ACPI_STATUS status;
607855e49f3SAlexander Motin
608855e49f3SAlexander Motin if (acpi_disabled("apei"))
609855e49f3SAlexander Motin return;
6103b580150SAlexander Motin
6113b580150SAlexander Motin /* Without HEST table we have nothing to do. */
6123b580150SAlexander Motin status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest);
6133b580150SAlexander Motin if (ACPI_FAILURE(status))
614855e49f3SAlexander Motin return;
6153b580150SAlexander Motin AcpiPutTable(hest);
6163b580150SAlexander Motin
617855e49f3SAlexander Motin /* Only one APEI device can exist. */
6183730d6aaSJohn Baldwin if (devclass_get_device(devclass_find("apei"), 0))
619855e49f3SAlexander Motin return;
6203b580150SAlexander Motin
621855e49f3SAlexander Motin /* Search for ACPI error device to be used. */
622855e49f3SAlexander Motin found = 0;
623855e49f3SAlexander Motin AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
624855e49f3SAlexander Motin 100, apei_find, NULL, NULL, (void *)&found);
625855e49f3SAlexander Motin if (found)
626855e49f3SAlexander Motin return;
6273b580150SAlexander Motin
628855e49f3SAlexander Motin /* If not found - create a fake one. */
629855e49f3SAlexander Motin child = BUS_ADD_CHILD(parent, 2, "apei", 0);
630855e49f3SAlexander Motin if (child == NULL)
631855e49f3SAlexander Motin printf("%s: can't add child\n", __func__);
632855e49f3SAlexander Motin }
633855e49f3SAlexander Motin
634855e49f3SAlexander Motin static int
apei_probe(device_t dev)635855e49f3SAlexander Motin apei_probe(device_t dev)
636855e49f3SAlexander Motin {
6373b580150SAlexander Motin ACPI_TABLE_HEADER *hest;
6383b580150SAlexander Motin ACPI_STATUS status;
639855e49f3SAlexander Motin int rv;
640855e49f3SAlexander Motin
641855e49f3SAlexander Motin if (acpi_disabled("apei"))
642855e49f3SAlexander Motin return (ENXIO);
6433b580150SAlexander Motin
6443b580150SAlexander Motin if (acpi_get_handle(dev) != NULL) {
645855e49f3SAlexander Motin rv = ACPI_ID_PROBE(device_get_parent(dev), dev, apei_ids, NULL);
6463b580150SAlexander Motin if (rv > 0)
6473b580150SAlexander Motin return (rv);
6483b580150SAlexander Motin } else
649855e49f3SAlexander Motin rv = 0;
6503b580150SAlexander Motin
6513b580150SAlexander Motin /* Without HEST table we have nothing to do. */
6523b580150SAlexander Motin status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest);
6533b580150SAlexander Motin if (ACPI_FAILURE(status))
6543b580150SAlexander Motin return (ENXIO);
6553b580150SAlexander Motin AcpiPutTable(hest);
6563b580150SAlexander Motin
6573b580150SAlexander Motin device_set_desc(dev, "ACPI Platform Error Interface");
658855e49f3SAlexander Motin return (rv);
659855e49f3SAlexander Motin }
660855e49f3SAlexander Motin
661855e49f3SAlexander Motin static int
apei_attach(device_t dev)662855e49f3SAlexander Motin apei_attach(device_t dev)
663855e49f3SAlexander Motin {
664855e49f3SAlexander Motin struct apei_softc *sc = device_get_softc(dev);
66552a54b96SAlexander Motin struct acpi_softc *acpi_sc;
6662dfc1f73SAlexander Motin struct apei_pges *pges;
667855e49f3SAlexander Motin struct apei_ge *ge;
668855e49f3SAlexander Motin ACPI_STATUS status;
669855e49f3SAlexander Motin int rid;
670855e49f3SAlexander Motin
67152a54b96SAlexander Motin if (!apei_sysctl_tree) {
67252a54b96SAlexander Motin /* Install hw.acpi.apei sysctl tree */
67352a54b96SAlexander Motin acpi_sc = acpi_device_get_parent_softc(dev);
67452a54b96SAlexander Motin apei_sysctl_tree = SYSCTL_ADD_NODE(&apei_sysctl_ctx,
67552a54b96SAlexander Motin SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO,
67652a54b96SAlexander Motin "apei", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
67752a54b96SAlexander Motin "ACPI Platform Error Interface");
67852a54b96SAlexander Motin SYSCTL_ADD_INT(&apei_sysctl_ctx, SYSCTL_CHILDREN(apei_sysctl_tree),
67952a54b96SAlexander Motin OID_AUTO, "log_corrected", CTLFLAG_RWTUN, &log_corrected, 0,
68052a54b96SAlexander Motin "Log corrected errors to the console");
68152a54b96SAlexander Motin }
68252a54b96SAlexander Motin
683855e49f3SAlexander Motin TAILQ_INIT(&sc->ges);
6842dfc1f73SAlexander Motin TAILQ_INIT(&sc->nges.ges);
6852dfc1f73SAlexander Motin TAILQ_INIT(&sc->iges.ges);
6862dfc1f73SAlexander Motin for (int i = 0; i < nitems(sc->pges); i++) {
6872dfc1f73SAlexander Motin pges = &sc->pges[i];
6882dfc1f73SAlexander Motin pges->interval = SBT_1MS << i;
6892dfc1f73SAlexander Motin callout_init(&pges->poll, 1);
6902dfc1f73SAlexander Motin TAILQ_INIT(&pges->ges);
6912dfc1f73SAlexander Motin }
692855e49f3SAlexander Motin
693855e49f3SAlexander Motin /* Search and parse HEST table. */
694855e49f3SAlexander Motin status = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&sc->hest);
695855e49f3SAlexander Motin if (ACPI_FAILURE(status))
696855e49f3SAlexander Motin return (ENXIO);
697855e49f3SAlexander Motin hest_parse_table(sc);
698855e49f3SAlexander Motin AcpiPutTable((ACPI_TABLE_HEADER *)sc->hest);
699855e49f3SAlexander Motin
700855e49f3SAlexander Motin rid = 0;
701855e49f3SAlexander Motin TAILQ_FOREACH(ge, &sc->ges, link) {
702855e49f3SAlexander Motin ge->res_rid = rid++;
703855e49f3SAlexander Motin acpi_bus_alloc_gas(dev, &ge->res_type, &ge->res_rid,
704855e49f3SAlexander Motin &ge->v1.ErrorStatusAddress, &ge->res, 0);
705a4566383SAlexander Motin if (ge->res) {
706a4566383SAlexander Motin ge->buf = pmap_mapdev_attr(READ8(ge->res, 0),
707a4566383SAlexander Motin ge->v1.ErrorBlockLength, VM_MEMATTR_WRITE_COMBINING);
708a4566383SAlexander Motin } else {
709a4566383SAlexander Motin device_printf(dev, "Can't allocate status resource.\n");
710a4566383SAlexander Motin }
711855e49f3SAlexander Motin if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
712855e49f3SAlexander Motin ge->res2_rid = rid++;
713855e49f3SAlexander Motin acpi_bus_alloc_gas(dev, &ge->res2_type, &ge->res2_rid,
714*5cd08d9eSAndrew Gallatin &ge->v2.ReadAckRegister, &ge->res2, RF_SHAREABLE);
715a4566383SAlexander Motin if (ge->res2 == NULL)
716a4566383SAlexander Motin device_printf(dev, "Can't allocate ack resource.\n");
717855e49f3SAlexander Motin }
718855e49f3SAlexander Motin if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
7192dfc1f73SAlexander Motin pges = &sc->pges[PGE_ID(ge)];
7202dfc1f73SAlexander Motin TAILQ_INSERT_TAIL(&sc->pges[PGE_ID(ge)].ges, ge, nlink);
7212dfc1f73SAlexander Motin callout_reset_sbt(&pges->poll, pges->interval, pges->interval,
7222dfc1f73SAlexander Motin apei_callout_handler, pges, 0);
7232dfc1f73SAlexander Motin } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
7242dfc1f73SAlexander Motin ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
7252dfc1f73SAlexander Motin ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) {
7262dfc1f73SAlexander Motin TAILQ_INSERT_TAIL(&sc->iges.ges, ge, nlink);
727855e49f3SAlexander Motin } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
728855e49f3SAlexander Motin ge->copybuf = malloc(ge->v1.ErrorBlockLength,
729855e49f3SAlexander Motin M_DEVBUF, M_WAITOK | M_ZERO);
7302dfc1f73SAlexander Motin TAILQ_INSERT_TAIL(&sc->nges.ges, ge, nlink);
7312dfc1f73SAlexander Motin if (sc->nges.swi_ih == NULL) {
7322dfc1f73SAlexander Motin swi_add(&clk_intr_event, "apei", apei_nmi_swi,
7332dfc1f73SAlexander Motin &sc->nges, SWI_CLOCK, INTR_MPSAFE,
7342dfc1f73SAlexander Motin &sc->nges.swi_ih);
7352dfc1f73SAlexander Motin apei_nmi_nges = &sc->nges;
736855e49f3SAlexander Motin apei_nmi = apei_nmi_handler;
737855e49f3SAlexander Motin }
738855e49f3SAlexander Motin }
7392dfc1f73SAlexander Motin }
740855e49f3SAlexander Motin
741855e49f3SAlexander Motin if (acpi_get_handle(dev) != NULL) {
742855e49f3SAlexander Motin AcpiInstallNotifyHandler(acpi_get_handle(dev),
743855e49f3SAlexander Motin ACPI_DEVICE_NOTIFY, apei_notify_handler, dev);
744855e49f3SAlexander Motin }
745855e49f3SAlexander Motin return (0);
746855e49f3SAlexander Motin }
747855e49f3SAlexander Motin
748855e49f3SAlexander Motin static int
apei_detach(device_t dev)749855e49f3SAlexander Motin apei_detach(device_t dev)
750855e49f3SAlexander Motin {
751855e49f3SAlexander Motin struct apei_softc *sc = device_get_softc(dev);
752855e49f3SAlexander Motin struct apei_ge *ge;
753855e49f3SAlexander Motin
754855e49f3SAlexander Motin apei_nmi = NULL;
7552dfc1f73SAlexander Motin apei_nmi_nges = NULL;
7562dfc1f73SAlexander Motin if (sc->nges.swi_ih != NULL) {
7572dfc1f73SAlexander Motin swi_remove(&sc->nges.swi_ih);
7582dfc1f73SAlexander Motin sc->nges.swi_ih = NULL;
7592dfc1f73SAlexander Motin }
760855e49f3SAlexander Motin if (acpi_get_handle(dev) != NULL) {
761855e49f3SAlexander Motin AcpiRemoveNotifyHandler(acpi_get_handle(dev),
762855e49f3SAlexander Motin ACPI_DEVICE_NOTIFY, apei_notify_handler);
763855e49f3SAlexander Motin }
7642dfc1f73SAlexander Motin for (int i = 0; i < nitems(sc->pges); i++)
7652dfc1f73SAlexander Motin callout_drain(&sc->pges[i].poll);
766855e49f3SAlexander Motin
767855e49f3SAlexander Motin while ((ge = TAILQ_FIRST(&sc->ges)) != NULL) {
768855e49f3SAlexander Motin TAILQ_REMOVE(&sc->ges, ge, link);
769a4566383SAlexander Motin if (ge->res) {
770a4566383SAlexander Motin bus_release_resource(dev, ge->res_type,
771a4566383SAlexander Motin ge->res_rid, ge->res);
772a4566383SAlexander Motin }
773855e49f3SAlexander Motin if (ge->res2) {
774855e49f3SAlexander Motin bus_release_resource(dev, ge->res2_type,
775855e49f3SAlexander Motin ge->res2_rid, ge->res2);
776855e49f3SAlexander Motin }
777855e49f3SAlexander Motin if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
7782dfc1f73SAlexander Motin TAILQ_REMOVE(&sc->pges[PGE_ID(ge)].ges, ge, nlink);
7792dfc1f73SAlexander Motin } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
7802dfc1f73SAlexander Motin ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
7812dfc1f73SAlexander Motin ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) {
7822dfc1f73SAlexander Motin TAILQ_REMOVE(&sc->iges.ges, ge, nlink);
783855e49f3SAlexander Motin } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
7842dfc1f73SAlexander Motin TAILQ_REMOVE(&sc->nges.ges, ge, nlink);
785855e49f3SAlexander Motin free(ge->copybuf, M_DEVBUF);
786855e49f3SAlexander Motin }
787a4566383SAlexander Motin if (ge->buf) {
7887ae99f80SJohn Baldwin pmap_unmapdev(ge->buf, ge->v1.ErrorBlockLength);
789a4566383SAlexander Motin }
790855e49f3SAlexander Motin free(ge, M_DEVBUF);
791855e49f3SAlexander Motin }
792855e49f3SAlexander Motin return (0);
793855e49f3SAlexander Motin }
794855e49f3SAlexander Motin
795855e49f3SAlexander Motin static device_method_t apei_methods[] = {
796855e49f3SAlexander Motin /* Device interface */
797855e49f3SAlexander Motin DEVMETHOD(device_identify, apei_identify),
798855e49f3SAlexander Motin DEVMETHOD(device_probe, apei_probe),
799855e49f3SAlexander Motin DEVMETHOD(device_attach, apei_attach),
800855e49f3SAlexander Motin DEVMETHOD(device_detach, apei_detach),
801855e49f3SAlexander Motin DEVMETHOD_END
802855e49f3SAlexander Motin };
803855e49f3SAlexander Motin
804855e49f3SAlexander Motin static driver_t apei_driver = {
805855e49f3SAlexander Motin "apei",
806855e49f3SAlexander Motin apei_methods,
807855e49f3SAlexander Motin sizeof(struct apei_softc),
808855e49f3SAlexander Motin };
809855e49f3SAlexander Motin
81052a54b96SAlexander Motin static int
apei_modevent(struct module * mod __unused,int evt,void * cookie __unused)81152a54b96SAlexander Motin apei_modevent(struct module *mod __unused, int evt, void *cookie __unused)
81252a54b96SAlexander Motin {
81352a54b96SAlexander Motin int err = 0;
81452a54b96SAlexander Motin
81552a54b96SAlexander Motin switch (evt) {
81652a54b96SAlexander Motin case MOD_LOAD:
81752a54b96SAlexander Motin sysctl_ctx_init(&apei_sysctl_ctx);
81852a54b96SAlexander Motin break;
81952a54b96SAlexander Motin case MOD_UNLOAD:
82052a54b96SAlexander Motin sysctl_ctx_free(&apei_sysctl_ctx);
82152a54b96SAlexander Motin break;
82252a54b96SAlexander Motin default:
82352a54b96SAlexander Motin err = EINVAL;
82452a54b96SAlexander Motin }
82552a54b96SAlexander Motin return (err);
82652a54b96SAlexander Motin }
82752a54b96SAlexander Motin
82852a54b96SAlexander Motin DRIVER_MODULE(apei, acpi, apei_driver, apei_modevent, 0);
829855e49f3SAlexander Motin MODULE_DEPEND(apei, acpi, 1, 1, 1);
830