]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/acpica/acpi_apei.c
Ensure a minimum packet length before creating a mbuf in if_ure.
[FreeBSD/FreeBSD.git] / sys / dev / acpica / acpi_apei.c
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 int apei_nmi_handler(void);
135
136 static const char *
137 apei_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
152 static int
153 apei_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
207 static int
208 apei_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
288 static void
289 apei_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", ged->FruText);
337         if (ged->Revision == 0x300 &&
338             ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP)
339                 printf(" Timestamp: %016jx", ged3->TimeStamp);
340 }
341
342 static int
343 apei_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
381 static void
382 apei_nmi_swi(void *arg)
383 {
384         struct apei_ge *ge = arg;
385
386         apei_ge_handler(ge, true);
387 }
388
389 int
390 apei_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
427 static void
428 apei_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
436 static void
437 apei_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
451 static int
452 hest_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
511 static void
512 hest_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
529 static char *apei_ids[] = { "PNP0C33", NULL };
530 static devclass_t apei_devclass;
531
532 static ACPI_STATUS
533 apei_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
548 static void
549 apei_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
582 static int
583 apei_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
609 static int
610 apei_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
666 static int
667 apei_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
704 static 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
713 static driver_t apei_driver = {
714         "apei",
715         apei_methods,
716         sizeof(struct apei_softc),
717 };
718
719 DRIVER_MODULE(apei, acpi, apei_driver, apei_devclass, 0, 0);
720 MODULE_DEPEND(apei, acpi, 1, 1, 1);