Home | History | Annotate | Line # | Download | only in acpi
      1  1.9  riastrad /*	$NetBSD: apei.c,v 1.9 2024/10/27 21:28:54 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*-
      4  1.1  riastrad  * Copyright (c) 2024 The NetBSD Foundation, Inc.
      5  1.1  riastrad  * All rights reserved.
      6  1.1  riastrad  *
      7  1.1  riastrad  * Redistribution and use in source and binary forms, with or without
      8  1.1  riastrad  * modification, are permitted provided that the following conditions
      9  1.1  riastrad  * are met:
     10  1.1  riastrad  * 1. Redistributions of source code must retain the above copyright
     11  1.1  riastrad  *    notice, this list of conditions and the following disclaimer.
     12  1.1  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  riastrad  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  riastrad  *    documentation and/or other materials provided with the distribution.
     15  1.1  riastrad  *
     16  1.1  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1  riastrad  */
     28  1.1  riastrad 
     29  1.1  riastrad /*
     30  1.1  riastrad  * APEI: ACPI Platform Error Interface
     31  1.1  riastrad  *
     32  1.1  riastrad  * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html
     33  1.1  riastrad  *
     34  1.1  riastrad  * XXX dtrace probes
     35  1.1  riastrad  *
     36  1.1  riastrad  * XXX call _OSC appropriately to announce to the platform that we, the
     37  1.1  riastrad  * OSPM, support APEI
     38  1.1  riastrad  */
     39  1.1  riastrad 
     40  1.1  riastrad #include <sys/cdefs.h>
     41  1.9  riastrad __KERNEL_RCSID(0, "$NetBSD: apei.c,v 1.9 2024/10/27 21:28:54 riastradh Exp $");
     42  1.1  riastrad 
     43  1.1  riastrad #include <sys/param.h>
     44  1.1  riastrad #include <sys/types.h>
     45  1.1  riastrad 
     46  1.1  riastrad #include <sys/atomic.h>
     47  1.7  riastrad #include <sys/endian.h>
     48  1.1  riastrad #include <sys/device.h>
     49  1.1  riastrad #include <sys/module.h>
     50  1.1  riastrad #include <sys/sysctl.h>
     51  1.1  riastrad #include <sys/uuid.h>
     52  1.1  riastrad 
     53  1.1  riastrad #include <dev/acpi/acpireg.h>
     54  1.1  riastrad #include <dev/acpi/acpivar.h>
     55  1.1  riastrad #include <dev/acpi/apei_bertvar.h>
     56  1.1  riastrad #include <dev/acpi/apei_cper.h>
     57  1.1  riastrad #include <dev/acpi/apei_einjvar.h>
     58  1.1  riastrad #include <dev/acpi/apei_erstvar.h>
     59  1.1  riastrad #include <dev/acpi/apei_hestvar.h>
     60  1.1  riastrad #include <dev/acpi/apei_interp.h>
     61  1.1  riastrad #include <dev/acpi/apeivar.h>
     62  1.7  riastrad #include <dev/pci/pcireg.h>
     63  1.1  riastrad 
     64  1.1  riastrad #define	_COMPONENT	ACPI_RESOURCE_COMPONENT
     65  1.1  riastrad ACPI_MODULE_NAME	("apei")
     66  1.1  riastrad 
     67  1.1  riastrad static int apei_match(device_t, cfdata_t, void *);
     68  1.1  riastrad static void apei_attach(device_t, device_t, void *);
     69  1.1  riastrad static int apei_detach(device_t, int);
     70  1.1  riastrad 
     71  1.1  riastrad static void apei_get_tables(struct apei_tab *);
     72  1.1  riastrad static void apei_put_tables(struct apei_tab *);
     73  1.1  riastrad 
     74  1.1  riastrad static void apei_identify(struct apei_softc *, const char *,
     75  1.1  riastrad     const ACPI_TABLE_HEADER *);
     76  1.1  riastrad 
     77  1.1  riastrad CFATTACH_DECL_NEW(apei, sizeof(struct apei_softc),
     78  1.1  riastrad     apei_match, apei_attach, apei_detach, NULL);
     79  1.1  riastrad 
     80  1.1  riastrad static int
     81  1.1  riastrad apei_match(device_t parent, cfdata_t match, void *aux)
     82  1.1  riastrad {
     83  1.1  riastrad 	struct apei_tab tab;
     84  1.1  riastrad 	int prio = 0;
     85  1.1  riastrad 
     86  1.1  riastrad 	/*
     87  1.1  riastrad 	 * If we have any of the APEI tables, match.
     88  1.1  riastrad 	 */
     89  1.1  riastrad 	apei_get_tables(&tab);
     90  1.1  riastrad 	if (tab.bert || tab.einj || tab.erst || tab.hest)
     91  1.1  riastrad 		prio = 1;
     92  1.1  riastrad 	apei_put_tables(&tab);
     93  1.1  riastrad 
     94  1.1  riastrad 	return prio;
     95  1.1  riastrad }
     96  1.1  riastrad 
     97  1.1  riastrad static void
     98  1.1  riastrad apei_attach(device_t parent, device_t self, void *aux)
     99  1.1  riastrad {
    100  1.1  riastrad 	struct apei_softc *sc = device_private(self);
    101  1.1  riastrad 	const struct sysctlnode *sysctl_hw_acpi;
    102  1.1  riastrad 	int error;
    103  1.1  riastrad 
    104  1.1  riastrad 	aprint_naive("\n");
    105  1.1  riastrad 	aprint_normal(": ACPI Platform Error Interface\n");
    106  1.1  riastrad 
    107  1.1  riastrad 	pmf_device_register(self, NULL, NULL);
    108  1.1  riastrad 
    109  1.1  riastrad 	sc->sc_dev = self;
    110  1.1  riastrad 	apei_get_tables(&sc->sc_tab);
    111  1.1  riastrad 
    112  1.1  riastrad 	/*
    113  1.1  riastrad 	 * Get the sysctl hw.acpi node.  This should already be created
    114  1.1  riastrad 	 * but I don't see an easy way to get at it.  If this fails,
    115  1.1  riastrad 	 * something is seriously wrong, so let's stop here.
    116  1.1  riastrad 	 */
    117  1.1  riastrad 	error = sysctl_createv(&sc->sc_sysctllog, 0,
    118  1.1  riastrad 	    NULL, &sysctl_hw_acpi, 0,
    119  1.1  riastrad 	    CTLTYPE_NODE, "acpi", NULL, NULL, 0, NULL, 0,
    120  1.1  riastrad 	    CTL_HW, CTL_CREATE, CTL_EOL);
    121  1.1  riastrad 	if (error) {
    122  1.1  riastrad 		aprint_error_dev(sc->sc_dev,
    123  1.1  riastrad 		    "failed to create sysctl hw.acpi: %d\n", error);
    124  1.1  riastrad 		return;
    125  1.1  riastrad 	}
    126  1.1  riastrad 
    127  1.1  riastrad 	/*
    128  1.1  riastrad 	 * Create sysctl hw.acpi.apei.
    129  1.1  riastrad 	 */
    130  1.1  riastrad 	error = sysctl_createv(&sc->sc_sysctllog, 0,
    131  1.1  riastrad 	    &sysctl_hw_acpi, &sc->sc_sysctlroot, 0,
    132  1.1  riastrad 	    CTLTYPE_NODE, "apei",
    133  1.1  riastrad 	    SYSCTL_DESCR("ACPI Platform Error Interface"),
    134  1.1  riastrad 	    NULL, 0, NULL, 0,
    135  1.1  riastrad 	    CTL_CREATE, CTL_EOL);
    136  1.1  riastrad 	if (error) {
    137  1.1  riastrad 		aprint_error_dev(sc->sc_dev,
    138  1.1  riastrad 		    "failed to create sysctl hw.acpi.apei: %d\n", error);
    139  1.1  riastrad 		return;
    140  1.1  riastrad 	}
    141  1.1  riastrad 
    142  1.1  riastrad 	/*
    143  1.1  riastrad 	 * Set up BERT, EINJ, ERST, and HEST.
    144  1.1  riastrad 	 */
    145  1.1  riastrad 	if (sc->sc_tab.bert) {
    146  1.1  riastrad 		apei_identify(sc, "BERT", &sc->sc_tab.bert->Header);
    147  1.1  riastrad 		apei_bert_attach(sc);
    148  1.1  riastrad 	}
    149  1.1  riastrad 	if (sc->sc_tab.einj) {
    150  1.1  riastrad 		apei_identify(sc, "EINJ", &sc->sc_tab.einj->Header);
    151  1.1  riastrad 		apei_einj_attach(sc);
    152  1.1  riastrad 	}
    153  1.1  riastrad 	if (sc->sc_tab.erst) {
    154  1.1  riastrad 		apei_identify(sc, "ERST", &sc->sc_tab.erst->Header);
    155  1.1  riastrad 		apei_erst_attach(sc);
    156  1.1  riastrad 	}
    157  1.1  riastrad 	if (sc->sc_tab.hest) {
    158  1.1  riastrad 		apei_identify(sc, "HEST", &sc->sc_tab.hest->Header);
    159  1.1  riastrad 		apei_hest_attach(sc);
    160  1.1  riastrad 	}
    161  1.1  riastrad }
    162  1.1  riastrad 
    163  1.1  riastrad static int
    164  1.1  riastrad apei_detach(device_t self, int flags)
    165  1.1  riastrad {
    166  1.1  riastrad 	struct apei_softc *sc = device_private(self);
    167  1.1  riastrad 	int error;
    168  1.1  riastrad 
    169  1.1  riastrad 	/*
    170  1.1  riastrad 	 * Detach children.  We don't currently have any but this is
    171  1.1  riastrad 	 * harmless without children and mandatory if we ever sprouted
    172  1.1  riastrad 	 * them, so let's just leave it here for good measure.
    173  1.1  riastrad 	 *
    174  1.1  riastrad 	 * After this point, we are committed to detaching; failure is
    175  1.1  riastrad 	 * forbidden.
    176  1.1  riastrad 	 */
    177  1.1  riastrad 	error = config_detach_children(self, flags);
    178  1.1  riastrad 	if (error)
    179  1.1  riastrad 		return error;
    180  1.1  riastrad 
    181  1.1  riastrad 	/*
    182  1.1  riastrad 	 * Tear down all the sysctl nodes first, before the software
    183  1.1  riastrad 	 * state backing them goes away.
    184  1.1  riastrad 	 */
    185  1.1  riastrad 	sysctl_teardown(&sc->sc_sysctllog);
    186  1.1  riastrad 	sc->sc_sysctlroot = NULL;
    187  1.1  riastrad 
    188  1.1  riastrad 	/*
    189  1.1  riastrad 	 * Detach the software state for the APEI tables.
    190  1.1  riastrad 	 */
    191  1.1  riastrad 	if (sc->sc_tab.hest)
    192  1.1  riastrad 		apei_hest_detach(sc);
    193  1.1  riastrad 	if (sc->sc_tab.erst)
    194  1.1  riastrad 		apei_erst_detach(sc);
    195  1.1  riastrad 	if (sc->sc_tab.einj)
    196  1.1  riastrad 		apei_einj_detach(sc);
    197  1.1  riastrad 	if (sc->sc_tab.bert)
    198  1.1  riastrad 		apei_bert_detach(sc);
    199  1.1  riastrad 
    200  1.1  riastrad 	/*
    201  1.1  riastrad 	 * Release the APEI tables and we're done.
    202  1.1  riastrad 	 */
    203  1.1  riastrad 	apei_put_tables(&sc->sc_tab);
    204  1.1  riastrad 	pmf_device_deregister(self);
    205  1.1  riastrad 	return 0;
    206  1.1  riastrad }
    207  1.1  riastrad 
    208  1.1  riastrad /*
    209  1.1  riastrad  * apei_get_tables(tab)
    210  1.1  riastrad  *
    211  1.1  riastrad  *	Get references to whichever APEI-related tables -- BERT, EINJ,
    212  1.1  riastrad  *	ERST, HEST -- are available in the system.
    213  1.1  riastrad  */
    214  1.1  riastrad static void
    215  1.1  riastrad apei_get_tables(struct apei_tab *tab)
    216  1.1  riastrad {
    217  1.1  riastrad 	ACPI_STATUS rv;
    218  1.1  riastrad 
    219  1.1  riastrad 	/*
    220  1.1  riastrad 	 * Probe the BERT -- Boot Error Record Table.
    221  1.1  riastrad 	 */
    222  1.1  riastrad 	rv = AcpiGetTable(ACPI_SIG_BERT, 0, (ACPI_TABLE_HEADER **)&tab->bert);
    223  1.1  riastrad 	if (ACPI_FAILURE(rv))
    224  1.1  riastrad 		tab->bert = NULL;
    225  1.1  riastrad 
    226  1.1  riastrad 	/*
    227  1.1  riastrad 	 * Probe the EINJ -- Error Injection Table.
    228  1.1  riastrad 	 */
    229  1.1  riastrad 	rv = AcpiGetTable(ACPI_SIG_EINJ, 0, (ACPI_TABLE_HEADER **)&tab->einj);
    230  1.1  riastrad 	if (ACPI_FAILURE(rv))
    231  1.1  riastrad 		tab->einj = NULL;
    232  1.1  riastrad 
    233  1.1  riastrad 	/*
    234  1.1  riastrad 	 * Probe the ERST -- Error Record Serialization Table.
    235  1.1  riastrad 	 */
    236  1.1  riastrad 	rv = AcpiGetTable(ACPI_SIG_ERST, 0, (ACPI_TABLE_HEADER **)&tab->erst);
    237  1.1  riastrad 	if (ACPI_FAILURE(rv))
    238  1.1  riastrad 		tab->erst = NULL;
    239  1.1  riastrad 
    240  1.1  riastrad 	/*
    241  1.1  riastrad 	 * Probe the HEST -- Hardware Error Source Table.
    242  1.1  riastrad 	 */
    243  1.1  riastrad 	rv = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&tab->hest);
    244  1.1  riastrad 	if (ACPI_FAILURE(rv))
    245  1.1  riastrad 		tab->hest = NULL;
    246  1.1  riastrad }
    247  1.1  riastrad 
    248  1.1  riastrad /*
    249  1.1  riastrad  * apei_put_tables(tab)
    250  1.1  riastrad  *
    251  1.1  riastrad  *	Release the tables acquired by apei_get_tables.
    252  1.1  riastrad  */
    253  1.1  riastrad static void
    254  1.1  riastrad apei_put_tables(struct apei_tab *tab)
    255  1.1  riastrad {
    256  1.1  riastrad 
    257  1.1  riastrad 	if (tab->bert != NULL) {
    258  1.1  riastrad 		AcpiPutTable(&tab->bert->Header);
    259  1.1  riastrad 		tab->bert = NULL;
    260  1.1  riastrad 	}
    261  1.1  riastrad 	if (tab->einj != NULL) {
    262  1.1  riastrad 		AcpiPutTable(&tab->einj->Header);
    263  1.1  riastrad 		tab->einj = NULL;
    264  1.1  riastrad 	}
    265  1.1  riastrad 	if (tab->erst != NULL) {
    266  1.1  riastrad 		AcpiPutTable(&tab->erst->Header);
    267  1.1  riastrad 		tab->erst = NULL;
    268  1.1  riastrad 	}
    269  1.1  riastrad 	if (tab->hest != NULL) {
    270  1.1  riastrad 		AcpiPutTable(&tab->hest->Header);
    271  1.1  riastrad 		tab->hest = NULL;
    272  1.1  riastrad 	}
    273  1.1  riastrad }
    274  1.1  riastrad 
    275  1.1  riastrad /*
    276  1.1  riastrad  * apei_identify(sc, name, header)
    277  1.1  riastrad  *
    278  1.1  riastrad  *	Identify the APEI-related table header for dmesg.
    279  1.1  riastrad  */
    280  1.1  riastrad static void
    281  1.1  riastrad apei_identify(struct apei_softc *sc, const char *name,
    282  1.1  riastrad     const ACPI_TABLE_HEADER *h)
    283  1.1  riastrad {
    284  1.1  riastrad 
    285  1.1  riastrad 	aprint_normal_dev(sc->sc_dev, "%s:"
    286  1.1  riastrad 	    " OemId <%6.6s,%8.8s,%08x>"
    287  1.1  riastrad 	    " AslId <%4.4s,%08x>\n",
    288  1.1  riastrad 	    name,
    289  1.1  riastrad 	    h->OemId, h->OemTableId, h->OemRevision,
    290  1.1  riastrad 	    h->AslCompilerId, h->AslCompilerRevision);
    291  1.1  riastrad }
    292  1.1  riastrad 
    293  1.1  riastrad /*
    294  1.1  riastrad  * apei_cper_guid_dec(buf, uuid)
    295  1.1  riastrad  *
    296  1.1  riastrad  *	Decode a Common Platform Error Record UUID/GUID from an ACPI
    297  1.1  riastrad  *	table at buf into a sys/uuid.h struct uuid.
    298  1.1  riastrad  */
    299  1.1  riastrad static void
    300  1.1  riastrad apei_cper_guid_dec(const uint8_t buf[static 16], struct uuid *uuid)
    301  1.1  riastrad {
    302  1.1  riastrad 
    303  1.1  riastrad 	uuid_dec_le(buf, uuid);
    304  1.1  riastrad }
    305  1.1  riastrad 
    306  1.1  riastrad /*
    307  1.1  riastrad  * apei_format_guid(uuid, s)
    308  1.1  riastrad  *
    309  1.1  riastrad  *	Format a UUID as a string.  This uses C initializer notation,
    310  1.3    rillig  *	not UUID notation, in order to match the text in the UEFI
    311  1.1  riastrad  *	specification.
    312  1.1  riastrad  */
    313  1.1  riastrad static void
    314  1.1  riastrad apei_format_guid(const struct uuid *uuid, char guidstr[static 69])
    315  1.1  riastrad {
    316  1.1  riastrad 
    317  1.1  riastrad 	snprintf(guidstr, 69, "{0x%08x,0x%04x,0x%04x,"
    318  1.4  riastrad 	    "{0x%02x,%02x,"
    319  1.4  riastrad 	    "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}}",
    320  1.1  riastrad 	    uuid->time_low, uuid->time_mid, uuid->time_hi_and_version,
    321  1.4  riastrad 	    uuid->clock_seq_hi_and_reserved, uuid->clock_seq_low,
    322  1.1  riastrad 	    uuid->node[0], uuid->node[1], uuid->node[2],
    323  1.1  riastrad 	    uuid->node[3], uuid->node[4], uuid->node[5]);
    324  1.1  riastrad }
    325  1.1  riastrad 
    326  1.1  riastrad /*
    327  1.1  riastrad  * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#memory-error-section
    328  1.1  riastrad  */
    329  1.1  riastrad 
    330  1.1  riastrad static const char *const cper_memory_error_type[] = {
    331  1.1  riastrad #define	F(LN, SN, V)	[LN] = #SN,
    332  1.1  riastrad 	CPER_MEMORY_ERROR_TYPES(F)
    333  1.1  riastrad #undef	F
    334  1.1  riastrad };
    335  1.1  riastrad 
    336  1.1  riastrad /*
    337  1.1  riastrad  * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#generic-error-status-block
    338  1.1  riastrad  *
    339  1.1  riastrad  * The acpica names ACPI_HEST_GEN_ERROR_* appear to coincide with this
    340  1.1  riastrad  * but are designated as being intended for Generic Error Data Entries
    341  1.1  riastrad  * rather than Generic Error Status Blocks.
    342  1.1  riastrad  */
    343  1.1  riastrad static const char *const apei_gesb_severity[] = {
    344  1.1  riastrad 	[0] = "recoverable",
    345  1.1  riastrad 	[1] = "fatal",
    346  1.1  riastrad 	[2] = "corrected",
    347  1.1  riastrad 	[3] = "none",
    348  1.1  riastrad };
    349  1.1  riastrad 
    350  1.1  riastrad /*
    351  1.1  riastrad  * https://uefi.org/specs/ACPI/6.5/18_Platform_Error_Interfaces.html#generic-error-data-entry
    352  1.1  riastrad  */
    353  1.1  riastrad static const char *const apei_gede_severity[] = {
    354  1.1  riastrad 	[ACPI_HEST_GEN_ERROR_RECOVERABLE] = "recoverable",
    355  1.1  riastrad 	[ACPI_HEST_GEN_ERROR_FATAL] = "fatal",
    356  1.1  riastrad 	[ACPI_HEST_GEN_ERROR_CORRECTED] = "corrected",
    357  1.1  riastrad 	[ACPI_HEST_GEN_ERROR_NONE] = "none",
    358  1.1  riastrad };
    359  1.1  riastrad 
    360  1.1  riastrad /*
    361  1.6  riastrad  * N.2.5. Memory Error Section
    362  1.6  riastrad  *
    363  1.1  riastrad  * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#memory-error-section
    364  1.1  riastrad  */
    365  1.1  riastrad static const struct uuid CPER_MEMORY_ERROR_SECTION =
    366  1.1  riastrad     {0xa5bc1114,0x6f64,0x4ede,0xb8,0x63,{0x3e,0x83,0xed,0x7c,0x83,0xb1}};
    367  1.1  riastrad 
    368  1.1  riastrad static void
    369  1.1  riastrad apei_cper_memory_error_report(struct apei_softc *sc, const void *buf,
    370  1.5  riastrad     size_t len, const char *ctx, bool ratelimitok)
    371  1.1  riastrad {
    372  1.1  riastrad 	const struct cper_memory_error *ME = buf;
    373  1.1  riastrad 	char bitbuf[1024];
    374  1.1  riastrad 
    375  1.5  riastrad 	/*
    376  1.5  riastrad 	 * If we've hit the rate limit, skip printing the error.
    377  1.5  riastrad 	 */
    378  1.5  riastrad 	if (!ratelimitok)
    379  1.5  riastrad 		goto out;
    380  1.5  riastrad 
    381  1.1  riastrad 	snprintb(bitbuf, sizeof(bitbuf),
    382  1.1  riastrad 	    CPER_MEMORY_ERROR_VALIDATION_BITS_FMT, ME->ValidationBits);
    383  1.1  riastrad 	aprint_debug_dev(sc->sc_dev, "%s: ValidationBits=%s\n", ctx, bitbuf);
    384  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_ERROR_STATUS) {
    385  1.1  riastrad 		/*
    386  1.1  riastrad 		 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#error-status
    387  1.1  riastrad 		 */
    388  1.1  riastrad 		/* XXX define this format somewhere */
    389  1.1  riastrad 		snprintb(bitbuf, sizeof(bitbuf), "\177\020"
    390  1.1  riastrad 		    "f\010\010"	"ErrorType\0"
    391  1.1  riastrad 			"=\001"		"ERR_INTERNAL\0"
    392  1.1  riastrad 			"=\004"		"ERR_MEM\0"
    393  1.1  riastrad 			"=\005"		"ERR_TLB\0"
    394  1.1  riastrad 			"=\006"		"ERR_CACHE\0"
    395  1.1  riastrad 			"=\007"		"ERR_FUNCTION\0"
    396  1.1  riastrad 			"=\010"		"ERR_SELFTEST\0"
    397  1.1  riastrad 			"=\011"		"ERR_FLOW\0"
    398  1.1  riastrad 			"=\020"		"ERR_BUS\0"
    399  1.1  riastrad 			"=\021"		"ERR_MAP\0"
    400  1.1  riastrad 			"=\022"		"ERR_IMPROPER\0"
    401  1.1  riastrad 			"=\023"		"ERR_UNIMPL\0"
    402  1.1  riastrad 			"=\024"		"ERR_LOL\0"
    403  1.1  riastrad 			"=\025"		"ERR_RESPONSE\0"
    404  1.1  riastrad 			"=\026"		"ERR_PARITY\0"
    405  1.1  riastrad 			"=\027"		"ERR_PROTOCOL\0"
    406  1.1  riastrad 			"=\030"		"ERR_ERROR\0"
    407  1.1  riastrad 			"=\031"		"ERR_TIMEOUT\0"
    408  1.1  riastrad 			"=\032"		"ERR_POISONED\0"
    409  1.1  riastrad 		    "b\020"	"AddressError\0"
    410  1.1  riastrad 		    "b\021"	"ControlError\0"
    411  1.1  riastrad 		    "b\022"	"DataError\0"
    412  1.1  riastrad 		    "b\023"	"ResponderDetected\0"
    413  1.1  riastrad 		    "b\024"	"RequesterDetected\0"
    414  1.1  riastrad 		    "b\025"	"FirstError\0"
    415  1.1  riastrad 		    "b\026"	"Overflow\0"
    416  1.1  riastrad 		    "\0", ME->ErrorStatus);
    417  1.1  riastrad 		device_printf(sc->sc_dev, "%s: ErrorStatus=%s\n", ctx, bitbuf);
    418  1.1  riastrad 	}
    419  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_PHYSICAL_ADDRESS) {
    420  1.1  riastrad 		device_printf(sc->sc_dev, "%s: PhysicalAddress=0x%"PRIx64"\n",
    421  1.1  riastrad 		    ctx, ME->PhysicalAddress);
    422  1.1  riastrad 	}
    423  1.1  riastrad 	if (ME->ValidationBits &
    424  1.1  riastrad 	    CPER_MEMORY_ERROR_VALID_PHYSICAL_ADDRESS_MASK) {
    425  1.1  riastrad 		device_printf(sc->sc_dev, "%s: PhysicalAddressMask=0x%"PRIx64
    426  1.1  riastrad 		    "\n", ctx, ME->PhysicalAddressMask);
    427  1.1  riastrad 	}
    428  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_NODE) {
    429  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Node=0x%"PRIx16"\n", ctx,
    430  1.1  riastrad 		    ME->Node);
    431  1.1  riastrad 	}
    432  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_CARD) {
    433  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Card=0x%"PRIx16"\n", ctx,
    434  1.1  riastrad 		    ME->Card);
    435  1.1  riastrad 	}
    436  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_MODULE) {
    437  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Module=0x%"PRIx16"\n", ctx,
    438  1.1  riastrad 		    ME->Module);
    439  1.1  riastrad 	}
    440  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_BANK) {
    441  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Bank=0x%"PRIx16"\n", ctx,
    442  1.1  riastrad 		    ME->Bank);
    443  1.1  riastrad 	}
    444  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_DEVICE) {
    445  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Device=0x%"PRIx16"\n", ctx,
    446  1.1  riastrad 		    ME->Device);
    447  1.1  riastrad 	}
    448  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_ROW) {
    449  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Row=0x%"PRIx16"\n", ctx,
    450  1.1  riastrad 		    ME->Row);
    451  1.1  riastrad 	}
    452  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_COLUMN) {
    453  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Column=0x%"PRIx16"\n", ctx,
    454  1.1  riastrad 		    ME->Column);
    455  1.1  riastrad 	}
    456  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_BIT_POSITION) {
    457  1.1  riastrad 		device_printf(sc->sc_dev, "%s: BitPosition=0x%"PRIx16"\n",
    458  1.1  riastrad 		    ctx, ME->BitPosition);
    459  1.1  riastrad 	}
    460  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_REQUESTOR_ID) {
    461  1.1  riastrad 		device_printf(sc->sc_dev, "%s: RequestorId=0x%"PRIx64"\n",
    462  1.1  riastrad 		    ctx, ME->RequestorId);
    463  1.1  riastrad 	}
    464  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_RESPONDER_ID) {
    465  1.1  riastrad 		device_printf(sc->sc_dev, "%s: ResponderId=0x%"PRIx64"\n",
    466  1.1  riastrad 		    ctx, ME->ResponderId);
    467  1.1  riastrad 	}
    468  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_TARGET_ID) {
    469  1.1  riastrad 		device_printf(sc->sc_dev, "%s: TargetId=0x%"PRIx64"\n",
    470  1.1  riastrad 		    ctx, ME->TargetId);
    471  1.1  riastrad 	}
    472  1.1  riastrad 	if (ME->ValidationBits & CPER_MEMORY_ERROR_VALID_MEMORY_ERROR_TYPE) {
    473  1.1  riastrad 		const uint8_t t = ME->MemoryErrorType;
    474  1.1  riastrad 		const char *n = t < __arraycount(cper_memory_error_type)
    475  1.1  riastrad 		    ? cper_memory_error_type[t] : NULL;
    476  1.1  riastrad 
    477  1.1  riastrad 		if (n) {
    478  1.1  riastrad 			device_printf(sc->sc_dev, "%s: MemoryErrorType=%d"
    479  1.1  riastrad 			    " (%s)\n", ctx, t, n);
    480  1.1  riastrad 		} else {
    481  1.1  riastrad 			device_printf(sc->sc_dev, "%s: MemoryErrorType=%d\n",
    482  1.1  riastrad 			    ctx, t);
    483  1.1  riastrad 		}
    484  1.1  riastrad 	}
    485  1.5  riastrad 
    486  1.5  riastrad out:	/*
    487  1.5  riastrad 	 * XXX pass this through to uvm(9) or userland for decisions
    488  1.5  riastrad 	 * like page retirement
    489  1.5  riastrad 	 */
    490  1.5  riastrad 	return;
    491  1.1  riastrad }
    492  1.1  riastrad 
    493  1.1  riastrad /*
    494  1.7  riastrad  * N.2.7. PCI Express Error Section
    495  1.7  riastrad  *
    496  1.7  riastrad  * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#pci-express-error-section
    497  1.7  riastrad  */
    498  1.7  riastrad static const struct uuid CPER_PCIE_ERROR_SECTION =
    499  1.7  riastrad     {0xd995e954,0xbbc1,0x430f,0xad,0x91,{0xb4,0x4d,0xcb,0x3c,0x6f,0x35}};
    500  1.7  riastrad 
    501  1.7  riastrad static const char *const cper_pcie_error_port_type[] = {
    502  1.7  riastrad #define	F(LN, SN, V)	[LN] = #SN,
    503  1.7  riastrad 	CPER_PCIE_ERROR_PORT_TYPES(F)
    504  1.7  riastrad #undef	F
    505  1.7  riastrad };
    506  1.7  riastrad 
    507  1.7  riastrad static void
    508  1.7  riastrad apei_cper_pcie_error_report(struct apei_softc *sc, const void *buf, size_t len,
    509  1.7  riastrad     const char *ctx, bool ratelimitok)
    510  1.7  riastrad {
    511  1.7  riastrad 	const struct cper_pcie_error *PE = buf;
    512  1.7  riastrad 	char bitbuf[1024];
    513  1.7  riastrad 
    514  1.7  riastrad 	/*
    515  1.7  riastrad 	 * If we've hit the rate limit, skip printing the error.
    516  1.7  riastrad 	 */
    517  1.7  riastrad 	if (!ratelimitok)
    518  1.7  riastrad 		goto out;
    519  1.7  riastrad 
    520  1.7  riastrad 	snprintb(bitbuf, sizeof(bitbuf),
    521  1.7  riastrad 	    CPER_PCIE_ERROR_VALIDATION_BITS_FMT, PE->ValidationBits);
    522  1.7  riastrad 	aprint_debug_dev(sc->sc_dev, "%s: ValidationBits=%s\n", ctx, bitbuf);
    523  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_PORT_TYPE) {
    524  1.7  riastrad 		const uint32_t t = PE->PortType;
    525  1.7  riastrad 		const char *n = t < __arraycount(cper_pcie_error_port_type)
    526  1.7  riastrad 		    ? cper_pcie_error_port_type[t] : NULL;
    527  1.7  riastrad 
    528  1.7  riastrad 		if (n) {
    529  1.7  riastrad 			device_printf(sc->sc_dev, "%s: PortType=%"PRIu32
    530  1.7  riastrad 			    " (%s)\n", ctx, t, n);
    531  1.7  riastrad 		} else {
    532  1.7  riastrad 			device_printf(sc->sc_dev, "%s: PortType=%"PRIu32"\n",
    533  1.7  riastrad 			    ctx, t);
    534  1.7  riastrad 		}
    535  1.7  riastrad 	}
    536  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_VERSION) {
    537  1.7  riastrad 		/* XXX BCD */
    538  1.7  riastrad 		device_printf(sc->sc_dev, "%s: Version=0x08%"PRIx32"\n",
    539  1.7  riastrad 		    ctx, PE->Version);
    540  1.7  riastrad 	}
    541  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_COMMAND_STATUS) {
    542  1.7  riastrad 		/* XXX move me to pcireg.h */
    543  1.7  riastrad 		snprintb(bitbuf, sizeof(bitbuf), "\177\020"
    544  1.7  riastrad 			/* command */
    545  1.7  riastrad 		    "b\000"	"IO_ENABLE\0"
    546  1.7  riastrad 		    "b\001"	"MEM_ENABLE\0"
    547  1.7  riastrad 		    "b\002"	"MASTER_ENABLE\0"
    548  1.7  riastrad 		    "b\003"	"SPECIAL_ENABLE\0"
    549  1.7  riastrad 		    "b\004"	"INVALIDATE_ENABLE\0"
    550  1.7  riastrad 		    "b\005"	"PALETTE_ENABLE\0"
    551  1.7  riastrad 		    "b\006"	"PARITY_ENABLE\0"
    552  1.7  riastrad 		    "b\007"	"STEPPING_ENABLE\0"
    553  1.7  riastrad 		    "b\010"	"SERR_ENABLE\0"
    554  1.7  riastrad 		    "b\011"	"BACKTOBACK_ENABLE\0"
    555  1.7  riastrad 		    "b\012"	"INTERRUPT_DISABLE\0"
    556  1.7  riastrad 			/* status */
    557  1.7  riastrad 		    "b\023"	"INT_STATUS\0"
    558  1.7  riastrad 		    "b\024"	"CAPLIST_SUPPORT\0"
    559  1.7  riastrad 		    "b\025"	"66MHZ_SUPPORT\0"
    560  1.7  riastrad 		    "b\026"	"UDF_SUPPORT\0"
    561  1.7  riastrad 		    "b\027"	"BACKTOBACK_SUPPORT\0"
    562  1.7  riastrad 		    "b\030"	"PARITY_ERROR\0"
    563  1.7  riastrad 		    "f\031\002"	"DEVSEL\0"
    564  1.7  riastrad 			"=\000"		"FAST\0"
    565  1.7  riastrad 			"=\001"		"MEDIUM\0"
    566  1.7  riastrad 			"=\002"		"SLOW\0"
    567  1.7  riastrad 		    "b\033"	"TARGET_TARGET_ABORT\0"
    568  1.7  riastrad 		    "b\034"	"MASTER_TARGET_ABORT\0"
    569  1.7  riastrad 		    "b\035"	"MASTER_ABORT\0"
    570  1.7  riastrad 		    "b\036"	"SPECIAL_ERROR\0"
    571  1.7  riastrad 		    "b\037"	"PARITY_DETECT\0"
    572  1.7  riastrad 		    "\0", PE->CommandStatus);
    573  1.7  riastrad 		device_printf(sc->sc_dev, "%s: CommandStatus=%s\n",
    574  1.7  riastrad 		    ctx, bitbuf);
    575  1.7  riastrad 	}
    576  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_DEVICE_ID) {
    577  1.7  riastrad 		device_printf(sc->sc_dev, "%s: DeviceID:"
    578  1.7  riastrad 		    " VendorID=0x%04"PRIx16
    579  1.7  riastrad 		    " DeviceID=0x%04"PRIx16
    580  1.7  riastrad 		    " ClassCode=0x%06"PRIx32
    581  1.7  riastrad 		    " Function=%"PRIu8
    582  1.7  riastrad 		    " Device=%"PRIu8
    583  1.7  riastrad 		    " Segment=%"PRIu16
    584  1.7  riastrad 		    " Bus=%"PRIu8
    585  1.7  riastrad 		    " SecondaryBus=%"PRIu8
    586  1.7  riastrad 		    " Slot=0x%04"PRIx16
    587  1.7  riastrad 		    " Reserved0=0x%02"PRIx8
    588  1.7  riastrad 		    "\n",
    589  1.7  riastrad 		    ctx,
    590  1.7  riastrad 		    le16dec(PE->DeviceID.VendorID),
    591  1.7  riastrad 		    le16dec(PE->DeviceID.DeviceID),
    592  1.7  riastrad 		    (PE->DeviceID.ClassCode[0] |	/* le24dec */
    593  1.7  riastrad 			((uint32_t)PE->DeviceID.ClassCode[1] << 8) |
    594  1.7  riastrad 			((uint32_t)PE->DeviceID.ClassCode[2] << 16)),
    595  1.7  riastrad 		    PE->DeviceID.Function, PE->DeviceID.Device,
    596  1.7  riastrad 		    le16dec(PE->DeviceID.Segment), PE->DeviceID.Bus,
    597  1.7  riastrad 		    PE->DeviceID.SecondaryBus, le16dec(PE->DeviceID.Slot),
    598  1.7  riastrad 		    PE->DeviceID.Reserved0);
    599  1.7  riastrad 	}
    600  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_DEVICE_SERIAL) {
    601  1.7  riastrad 		device_printf(sc->sc_dev, "%s: DeviceSerial={%016"PRIx64"}\n",
    602  1.7  riastrad 		    ctx, PE->DeviceSerial);
    603  1.7  riastrad 	}
    604  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_BRIDGE_CONTROL_STATUS) {
    605  1.7  riastrad 		/* XXX snprintb */
    606  1.7  riastrad 		device_printf(sc->sc_dev, "%s: BridgeControlStatus=%"PRIx32
    607  1.7  riastrad 		    "\n", ctx, PE->BridgeControlStatus);
    608  1.7  riastrad 	}
    609  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_CAPABILITY_STRUCTURE) {
    610  1.7  riastrad 		uint32_t dcsr, dsr;
    611  1.8  riastrad 		char hex[9*sizeof(PE->CapabilityStructure)/4];
    612  1.7  riastrad 		unsigned i;
    613  1.7  riastrad 
    614  1.8  riastrad 		/*
    615  1.8  riastrad 		 * Display a hex dump of each 32-bit register in the
    616  1.8  riastrad 		 * PCIe capability structure.
    617  1.8  riastrad 		 */
    618  1.8  riastrad 		__CTASSERT(sizeof(PE->CapabilityStructure) % 4 == 0);
    619  1.8  riastrad 		for (i = 0; i < sizeof(PE->CapabilityStructure)/4; i++) {
    620  1.8  riastrad 			snprintf(hex + 9*i, sizeof(hex) - 9*i, "%08"PRIx32" ",
    621  1.8  riastrad 			    le32dec(&PE->CapabilityStructure[4*i]));
    622  1.7  riastrad 		}
    623  1.8  riastrad 		hex[sizeof(hex) - 1] = '\0';
    624  1.7  riastrad 		device_printf(sc->sc_dev, "%s: CapabilityStructure={%s}\n",
    625  1.7  riastrad 		    ctx, hex);
    626  1.7  riastrad 
    627  1.8  riastrad 		/*
    628  1.8  riastrad 		 * If the Device Status Register has any bits set,
    629  1.8  riastrad 		 * highlight it in particular -- these are probably
    630  1.8  riastrad 		 * error bits.
    631  1.8  riastrad 		 */
    632  1.7  riastrad 		dcsr = le32dec(&PE->CapabilityStructure[PCIE_DCSR]);
    633  1.7  riastrad 		dsr = __SHIFTOUT(dcsr, __BITS(31,16));
    634  1.7  riastrad 		if (dsr != 0) {
    635  1.7  riastrad 			/*
    636  1.7  riastrad 			 * XXX move me to pcireg.h; note: high
    637  1.7  riastrad 			 * half of DCSR
    638  1.7  riastrad 			 */
    639  1.7  riastrad 			snprintb(bitbuf, sizeof(bitbuf), "\177\020"
    640  1.7  riastrad 			    "b\000"	"CORRECTABLE_ERROR\0"
    641  1.7  riastrad 			    "b\001"	"NONFATAL_UNCORRECTABLE_ERROR\0"
    642  1.7  riastrad 			    "b\002"	"FATAL_ERROR\0"
    643  1.7  riastrad 			    "b\003"	"UNSUPPORTED_REQUEST\0"
    644  1.7  riastrad 			    "b\004"	"AUX_POWER\0"
    645  1.7  riastrad 			    "b\005"	"TRANSACTIONS_PENDING\0"
    646  1.7  riastrad 			    "\0", dsr);
    647  1.7  riastrad 			device_printf(sc->sc_dev, "%s: PCIe Device Status:"
    648  1.7  riastrad 			    " %s\n",
    649  1.7  riastrad 			    ctx, bitbuf);
    650  1.7  riastrad 		}
    651  1.7  riastrad 	}
    652  1.7  riastrad 	if (PE->ValidationBits & CPER_PCIE_ERROR_VALID_AER_INFO) {
    653  1.7  riastrad 		uint32_t uc_status, uc_sev;
    654  1.7  riastrad 		uint32_t cor_status;
    655  1.7  riastrad 		uint32_t control;
    656  1.8  riastrad 		char hex[9*sizeof(PE->AERInfo)/4];
    657  1.7  riastrad 		unsigned i;
    658  1.7  riastrad 
    659  1.8  riastrad 		/*
    660  1.8  riastrad 		 * Display a hex dump of each 32-bit register in the
    661  1.8  riastrad 		 * PCIe Advanced Error Reporting extended capability
    662  1.8  riastrad 		 * structure.
    663  1.8  riastrad 		 */
    664  1.8  riastrad 		__CTASSERT(sizeof(PE->AERInfo) % 4 == 0);
    665  1.8  riastrad 		for (i = 0; i < sizeof(PE->AERInfo)/4; i++) {
    666  1.8  riastrad 			snprintf(hex + 9*i, sizeof(hex) - 9*i, "%08"PRIx32" ",
    667  1.8  riastrad 			    le32dec(&PE->AERInfo[4*i]));
    668  1.7  riastrad 		}
    669  1.8  riastrad 		hex[sizeof(hex) - 1] = '\0';
    670  1.7  riastrad 		device_printf(sc->sc_dev, "%s: AERInfo={%s}\n", ctx, hex);
    671  1.7  riastrad 
    672  1.7  riastrad 			/* XXX move me to pcireg.h */
    673  1.7  riastrad #define	PCI_AER_UC_STATUS_FMT	"\177\020"				      \
    674  1.7  riastrad 	"b\000"	"UNDEFINED\0"						      \
    675  1.7  riastrad 	"b\004"	"DL_PROTOCOL_ERROR\0"					      \
    676  1.7  riastrad 	"b\005"	"SURPRISE_DOWN_ERROR\0"					      \
    677  1.7  riastrad 	"b\014"	"POISONED_TLP\0"					      \
    678  1.7  riastrad 	"b\015"	"FC_PROTOCOL_ERROR\0"					      \
    679  1.7  riastrad 	"b\016"	"COMPLETION_TIMEOUT\0"					      \
    680  1.7  riastrad 	"b\017"	"COMPLETION_ABORT\0"					      \
    681  1.7  riastrad 	"b\020"	"UNEXPECTED_COMPLETION\0"				      \
    682  1.7  riastrad 	"b\021"	"RECEIVER_OVERFLOW\0"					      \
    683  1.7  riastrad 	"b\022"	"MALFORMED_TLP\0"					      \
    684  1.7  riastrad 	"b\023"	"ECRC_ERROR\0"						      \
    685  1.7  riastrad 	"b\024"	"UNSUPPORTED_REQUEST_ERROR\0"				      \
    686  1.7  riastrad 	"b\025"	"ACS_VIOLATION\0"					      \
    687  1.7  riastrad 	"b\026"	"INTERNAL_ERROR\0"					      \
    688  1.7  riastrad 	"b\027"	"MC_BLOCKED_TLP\0"					      \
    689  1.7  riastrad 	"b\030"	"ATOMIC_OP_EGRESS_BLOCKED\0"				      \
    690  1.7  riastrad 	"b\031"	"TLP_PREFIX_BLOCKED_ERROR\0"				      \
    691  1.7  riastrad 	"b\032"	"POISONTLP_EGRESS_BLOCKED\0"				      \
    692  1.7  riastrad 	"\0"
    693  1.7  riastrad 
    694  1.8  riastrad 		/*
    695  1.8  riastrad 		 * If there are any hardware error status bits set,
    696  1.8  riastrad 		 * highlight them in particular, in three groups:
    697  1.8  riastrad 		 *
    698  1.8  riastrad 		 * - uncorrectable fatal (UC_STATUS and UC_SEVERITY)
    699  1.8  riastrad 		 * - uncorrectable nonfatal (UC_STATUS but not UC_SEVERITY)
    700  1.8  riastrad 		 * - corrected (COR_STATUS)
    701  1.8  riastrad 		 *
    702  1.8  riastrad 		 * And if there are any uncorrectable errors, show
    703  1.8  riastrad 		 * which one was reported first, according to
    704  1.8  riastrad 		 * CAP_CONTROL.
    705  1.8  riastrad 		 */
    706  1.7  riastrad 		uc_status = le32dec(&PE->AERInfo[PCI_AER_UC_STATUS]);
    707  1.7  riastrad 		uc_sev = le32dec(&PE->AERInfo[PCI_AER_UC_SEVERITY]);
    708  1.7  riastrad 		cor_status = le32dec(&PE->AERInfo[PCI_AER_COR_STATUS]);
    709  1.7  riastrad 		control = le32dec(&PE->AERInfo[PCI_AER_CAP_CONTROL]);
    710  1.7  riastrad 
    711  1.7  riastrad 		if (uc_status & uc_sev) {
    712  1.7  riastrad 			snprintb(bitbuf, sizeof(bitbuf), PCI_AER_UC_STATUS_FMT,
    713  1.7  riastrad 			    uc_status & uc_sev);
    714  1.7  riastrad 			device_printf(sc->sc_dev, "%s:"
    715  1.7  riastrad 			    " AER hardware fatal uncorrectable errors: %s\n",
    716  1.7  riastrad 			    ctx, bitbuf);
    717  1.7  riastrad 		}
    718  1.7  riastrad 		if (uc_status & ~uc_sev) {
    719  1.7  riastrad 			snprintb(bitbuf, sizeof(bitbuf), PCI_AER_UC_STATUS_FMT,
    720  1.9  riastrad 			    uc_status & ~uc_sev);
    721  1.7  riastrad 			device_printf(sc->sc_dev, "%s:"
    722  1.9  riastrad 			    " AER hardware non-fatal uncorrectable errors:"
    723  1.9  riastrad 			    " %s\n",
    724  1.7  riastrad 			    ctx, bitbuf);
    725  1.7  riastrad 		}
    726  1.7  riastrad 		if (uc_status) {
    727  1.7  riastrad 			unsigned first = __SHIFTOUT(control,
    728  1.7  riastrad 			    PCI_AER_FIRST_ERROR_PTR);
    729  1.7  riastrad 			snprintb(bitbuf, sizeof(bitbuf), PCI_AER_UC_STATUS_FMT,
    730  1.7  riastrad 			    (uint32_t)1 << first);
    731  1.7  riastrad 			device_printf(sc->sc_dev, "%s:"
    732  1.7  riastrad 			    " AER hardware first uncorrectable error: %s\n",
    733  1.7  riastrad 			    ctx, bitbuf);
    734  1.7  riastrad 		}
    735  1.7  riastrad 		if (cor_status) {
    736  1.7  riastrad 			/* XXX move me to pcireg.h */
    737  1.7  riastrad 			snprintb(bitbuf, sizeof(bitbuf), "\177\020"
    738  1.7  riastrad 			    "b\000"	"RECEIVER_ERROR\0"
    739  1.7  riastrad 			    "b\006"	"BAD_TLP\0"
    740  1.7  riastrad 			    "b\007"	"BAD_DLLP\0"
    741  1.7  riastrad 			    "b\010"	"REPLAY_NUM_ROLLOVER\0"
    742  1.7  riastrad 			    "b\014"	"REPLAY_TIMER_TIMEOUT\0"
    743  1.7  riastrad 			    "b\015"	"ADVISORY_NF_ERROR\0"
    744  1.7  riastrad 			    "b\016"	"INTERNAL_ERROR\0"
    745  1.7  riastrad 			    "b\017"	"HEADER_LOG_OVERFLOW\0"
    746  1.7  riastrad 			    "\0", cor_status);
    747  1.7  riastrad 			device_printf(sc->sc_dev, "%s:"
    748  1.7  riastrad 			    " AER hardware corrected error: %s\n",
    749  1.7  riastrad 			    ctx, bitbuf);
    750  1.7  riastrad 		}
    751  1.7  riastrad 	}
    752  1.7  riastrad 
    753  1.7  riastrad out:	/*
    754  1.7  riastrad 	 * XXX pass this on to the PCI subsystem to handle
    755  1.7  riastrad 	 */
    756  1.7  riastrad 	return;
    757  1.7  riastrad }
    758  1.7  riastrad 
    759  1.7  riastrad /*
    760  1.1  riastrad  * apei_cper_reports
    761  1.1  riastrad  *
    762  1.1  riastrad  *	Table of known Common Platform Error Record types, symbolic
    763  1.1  riastrad  *	names, minimum data lengths, and functions to report them.
    764  1.1  riastrad  *
    765  1.1  riastrad  *	The section types and corresponding section layouts are listed
    766  1.1  riastrad  *	at:
    767  1.1  riastrad  *
    768  1.1  riastrad  *	https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html
    769  1.1  riastrad  */
    770  1.1  riastrad static const struct apei_cper_report {
    771  1.1  riastrad 	const char *name;
    772  1.1  riastrad 	const struct uuid *type;
    773  1.1  riastrad 	size_t minlength;
    774  1.5  riastrad 	void (*func)(struct apei_softc *, const void *, size_t, const char *,
    775  1.5  riastrad 	    bool);
    776  1.1  riastrad } apei_cper_reports[] = {
    777  1.1  riastrad 	{ "memory", &CPER_MEMORY_ERROR_SECTION,
    778  1.1  riastrad 	  sizeof(struct cper_memory_error),
    779  1.1  riastrad 	  apei_cper_memory_error_report },
    780  1.7  riastrad 	{ "PCIe", &CPER_PCIE_ERROR_SECTION,
    781  1.7  riastrad 	  sizeof(struct cper_pcie_error),
    782  1.7  riastrad 	  apei_cper_pcie_error_report },
    783  1.1  riastrad };
    784  1.1  riastrad 
    785  1.1  riastrad /*
    786  1.5  riastrad  * apei_gede_report_header(sc, gede, ctx, ratelimitok, &headerlen, &report)
    787  1.1  riastrad  *
    788  1.1  riastrad  *	Report the header of the ith Generic Error Data Entry in the
    789  1.5  riastrad  *	given context, if ratelimitok is true.
    790  1.1  riastrad  *
    791  1.1  riastrad  *	Return the actual length of the header in headerlen, or 0 if
    792  1.1  riastrad  *	not known because the revision isn't recognized.
    793  1.1  riastrad  *
    794  1.1  riastrad  *	Return the report type in report, or NULL if not known because
    795  1.1  riastrad  *	the section type isn't recognized.
    796  1.1  riastrad  */
    797  1.1  riastrad static void
    798  1.1  riastrad apei_gede_report_header(struct apei_softc *sc,
    799  1.5  riastrad     const ACPI_HEST_GENERIC_DATA *gede, const char *ctx, bool ratelimitok,
    800  1.1  riastrad     size_t *headerlenp, const struct apei_cper_report **reportp)
    801  1.1  riastrad {
    802  1.1  riastrad 	const ACPI_HEST_GENERIC_DATA_V300 *const gede_v3 = (const void *)gede;
    803  1.1  riastrad 	struct uuid sectype;
    804  1.1  riastrad 	char guidstr[69];
    805  1.1  riastrad 	char buf[128];
    806  1.1  riastrad 	unsigned i;
    807  1.1  riastrad 
    808  1.1  riastrad 	/*
    809  1.1  riastrad 	 * Print the section type as a C initializer.  It would be
    810  1.1  riastrad 	 * prettier to use standard hyphenated UUID notation, but that
    811  1.1  riastrad 	 * notation is slightly ambiguous here (two octets could be
    812  1.1  riastrad 	 * written either way, depending on Microsoft convention --
    813  1.1  riastrad 	 * which influenced ACPI and UEFI -- or internet convention),
    814  1.1  riastrad 	 * and the UEFI spec writes the C initializer notation, so this
    815  1.1  riastrad 	 * makes it easier to search for.
    816  1.1  riastrad 	 *
    817  1.1  riastrad 	 * Also print out a symbolic name, if we know it.
    818  1.1  riastrad 	 */
    819  1.1  riastrad 	apei_cper_guid_dec(gede->SectionType, &sectype);
    820  1.1  riastrad 	apei_format_guid(&sectype, guidstr);
    821  1.1  riastrad 	for (i = 0; i < __arraycount(apei_cper_reports); i++) {
    822  1.1  riastrad 		const struct apei_cper_report *const report =
    823  1.1  riastrad 		    &apei_cper_reports[i];
    824  1.1  riastrad 
    825  1.1  riastrad 		if (memcmp(&sectype, report->type, sizeof(sectype)) != 0)
    826  1.1  riastrad 			continue;
    827  1.5  riastrad 		if (ratelimitok) {
    828  1.5  riastrad 			device_printf(sc->sc_dev, "%s:"
    829  1.5  riastrad 			    " SectionType=%s (%s error)\n",
    830  1.5  riastrad 			    ctx, guidstr, report->name);
    831  1.5  riastrad 		}
    832  1.1  riastrad 		*reportp = report;
    833  1.1  riastrad 		break;
    834  1.1  riastrad 	}
    835  1.1  riastrad 	if (i == __arraycount(apei_cper_reports)) {
    836  1.5  riastrad 		if (ratelimitok) {
    837  1.5  riastrad 			device_printf(sc->sc_dev, "%s: SectionType=%s\n", ctx,
    838  1.5  riastrad 			    guidstr);
    839  1.5  riastrad 		}
    840  1.1  riastrad 		*reportp = NULL;
    841  1.1  riastrad 	}
    842  1.1  riastrad 
    843  1.1  riastrad 	/*
    844  1.1  riastrad 	 * Print the numeric severity and, if we have it, a symbolic
    845  1.1  riastrad 	 * name for it.
    846  1.1  riastrad 	 */
    847  1.5  riastrad 	if (ratelimitok) {
    848  1.5  riastrad 		device_printf(sc->sc_dev, "%s: ErrorSeverity=%"PRIu32" (%s)\n",
    849  1.5  riastrad 		    ctx,
    850  1.5  riastrad 		    gede->ErrorSeverity,
    851  1.5  riastrad 		    (gede->ErrorSeverity < __arraycount(apei_gede_severity)
    852  1.5  riastrad 			? apei_gede_severity[gede->ErrorSeverity]
    853  1.5  riastrad 			: "unknown"));
    854  1.5  riastrad 	}
    855  1.1  riastrad 
    856  1.1  riastrad 	/*
    857  1.1  riastrad 	 * The Revision may not often be useful, but this is only ever
    858  1.1  riastrad 	 * shown at the time of a hardware error report, not something
    859  1.1  riastrad 	 * you can glean at your convenience with acpidump.  So print
    860  1.1  riastrad 	 * it anyway.
    861  1.1  riastrad 	 */
    862  1.5  riastrad 	if (ratelimitok) {
    863  1.5  riastrad 		device_printf(sc->sc_dev, "%s: Revision=0x%"PRIx16"\n", ctx,
    864  1.5  riastrad 		    gede->Revision);
    865  1.5  riastrad 	}
    866  1.1  riastrad 
    867  1.1  riastrad 	/*
    868  1.1  riastrad 	 * Don't touch anything past the Revision until we've
    869  1.1  riastrad 	 * determined we understand it.  Return the header length to
    870  1.1  riastrad 	 * the caller, or return zero -- and stop here -- if we don't
    871  1.1  riastrad 	 * know what the actual header length is.
    872  1.1  riastrad 	 */
    873  1.1  riastrad 	if (gede->Revision < 0x0300) {
    874  1.1  riastrad 		*headerlenp = sizeof(*gede);
    875  1.1  riastrad 	} else if (gede->Revision < 0x0400) {
    876  1.1  riastrad 		*headerlenp = sizeof(*gede_v3);
    877  1.1  riastrad 	} else {
    878  1.1  riastrad 		*headerlenp = 0;
    879  1.1  riastrad 		return;
    880  1.1  riastrad 	}
    881  1.1  riastrad 
    882  1.1  riastrad 	/*
    883  1.1  riastrad 	 * Print the validation bits at debug level.  Only really
    884  1.1  riastrad 	 * helpful if there are bits we _don't_ know about.
    885  1.1  riastrad 	 */
    886  1.5  riastrad 	if (ratelimitok) {
    887  1.5  riastrad 		/* XXX define this format somewhere */
    888  1.5  riastrad 		snprintb(buf, sizeof(buf), "\177\020"
    889  1.5  riastrad 		    "b\000"	"FRU_ID\0"
    890  1.5  riastrad 		    "b\001"	"FRU_TEXT\0" /* `FRU string', sometimes */
    891  1.5  riastrad 		    "b\002"	"TIMESTAMP\0"
    892  1.5  riastrad 		    "\0", gede->ValidationBits);
    893  1.5  riastrad 		aprint_debug_dev(sc->sc_dev, "%s: ValidationBits=%s\n", ctx,
    894  1.5  riastrad 		    buf);
    895  1.5  riastrad 	}
    896  1.1  riastrad 
    897  1.1  riastrad 	/*
    898  1.1  riastrad 	 * Print the CPER section flags.
    899  1.1  riastrad 	 */
    900  1.5  riastrad 	if (ratelimitok) {
    901  1.5  riastrad 		snprintb(buf, sizeof(buf), CPER_SECTION_FLAGS_FMT,
    902  1.5  riastrad 		    gede->Flags);
    903  1.5  riastrad 		device_printf(sc->sc_dev, "%s: Flags=%s\n", ctx, buf);
    904  1.5  riastrad 	}
    905  1.1  riastrad 
    906  1.1  riastrad 	/*
    907  1.1  riastrad 	 * The ErrorDataLength is unlikely to be useful for the log, so
    908  1.1  riastrad 	 * print it at debug level only.
    909  1.1  riastrad 	 */
    910  1.5  riastrad 	if (ratelimitok) {
    911  1.5  riastrad 		aprint_debug_dev(sc->sc_dev, "%s:"
    912  1.5  riastrad 		    " ErrorDataLength=0x%"PRIu32"\n",
    913  1.5  riastrad 		    ctx, gede->ErrorDataLength);
    914  1.5  riastrad 	}
    915  1.1  riastrad 
    916  1.1  riastrad 	/*
    917  1.1  riastrad 	 * Print the FRU Id and text, if available.
    918  1.1  riastrad 	 */
    919  1.5  riastrad 	if (ratelimitok &&
    920  1.5  riastrad 	    (gede->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) != 0) {
    921  1.1  riastrad 		struct uuid fruid;
    922  1.1  riastrad 
    923  1.1  riastrad 		apei_cper_guid_dec(gede->FruId, &fruid);
    924  1.1  riastrad 		apei_format_guid(&fruid, guidstr);
    925  1.1  riastrad 		device_printf(sc->sc_dev, "%s: FruId=%s\n", ctx, guidstr);
    926  1.1  riastrad 	}
    927  1.5  riastrad 	if (ratelimitok &&
    928  1.5  riastrad 	    (gede->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING) != 0) {
    929  1.1  riastrad 		device_printf(sc->sc_dev, "%s: FruText=%.20s\n",
    930  1.1  riastrad 		    ctx, gede->FruText);
    931  1.1  riastrad 	}
    932  1.1  riastrad 
    933  1.1  riastrad 	/*
    934  1.1  riastrad 	 * Print the timestamp, if available by the revision number and
    935  1.1  riastrad 	 * the validation bits.
    936  1.1  riastrad 	 */
    937  1.5  riastrad 	if (ratelimitok &&
    938  1.5  riastrad 	    gede->Revision >= 0x0300 && gede->Revision < 0x0400 &&
    939  1.1  riastrad 	    gede->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
    940  1.1  riastrad 		const uint8_t *const t = (const uint8_t *)&gede_v3->TimeStamp;
    941  1.1  riastrad 		const uint8_t s = t[0];
    942  1.1  riastrad 		const uint8_t m = t[1];
    943  1.1  riastrad 		const uint8_t h = t[2];
    944  1.1  riastrad 		const uint8_t f = t[3];
    945  1.1  riastrad 		const uint8_t D = t[4];
    946  1.1  riastrad 		const uint8_t M = t[5];
    947  1.1  riastrad 		const uint8_t Y = t[6];
    948  1.1  riastrad 		const uint8_t C = t[7];
    949  1.1  riastrad 
    950  1.1  riastrad 		device_printf(sc->sc_dev, "%s: Timestamp=0x%"PRIx64
    951  1.1  riastrad 		    " (%02d%02d-%02d-%02dT%02d:%02d:%02d%s)\n",
    952  1.1  riastrad 		    ctx, gede_v3->TimeStamp,
    953  1.1  riastrad 		    C,Y, M, D, h,m,s,
    954  1.1  riastrad 		    f & __BIT(0) ? " (event time)" : " (collect time)");
    955  1.1  riastrad 	}
    956  1.1  riastrad }
    957  1.1  riastrad 
    958  1.1  riastrad /*
    959  1.5  riastrad  * apei_gesb_ratelimit
    960  1.5  riastrad  *
    961  1.5  riastrad  *	State to limit the rate of console log messages about hardware
    962  1.5  riastrad  *	errors.  For each of the four severity levels in a Generic
    963  1.5  riastrad  *	Error Status Block,
    964  1.5  riastrad  *
    965  1.5  riastrad  *	0 - Recoverable (uncorrectable),
    966  1.5  riastrad  *	1 - Fatal (uncorrectable),
    967  1.5  riastrad  *	2 - Corrected, and
    968  1.5  riastrad  *	3 - None (including ill-formed errors),
    969  1.5  riastrad  *
    970  1.5  riastrad  *	we record the last time it happened, protected by a CPU simple
    971  1.5  riastrad  *	lock that we only try-acquire so it is safe to use in any
    972  1.5  riastrad  *	context, including non-maskable interrupt context.
    973  1.5  riastrad  */
    974  1.5  riastrad 
    975  1.5  riastrad static struct {
    976  1.5  riastrad 	__cpu_simple_lock_t	lock;
    977  1.5  riastrad 	struct timeval		lasttime;
    978  1.5  riastrad 	volatile uint32_t	suppressed;
    979  1.5  riastrad } __aligned(COHERENCY_UNIT) apei_gesb_ratelimit[4] __cacheline_aligned = {
    980  1.5  riastrad 	[ACPI_HEST_GEN_ERROR_RECOVERABLE] = { .lock = __SIMPLELOCK_UNLOCKED },
    981  1.5  riastrad 	[ACPI_HEST_GEN_ERROR_FATAL] = { .lock = __SIMPLELOCK_UNLOCKED },
    982  1.5  riastrad 	[ACPI_HEST_GEN_ERROR_CORRECTED] = { .lock = __SIMPLELOCK_UNLOCKED },
    983  1.5  riastrad 	[ACPI_HEST_GEN_ERROR_NONE] = { .lock = __SIMPLELOCK_UNLOCKED },
    984  1.5  riastrad };
    985  1.5  riastrad 
    986  1.5  riastrad static void
    987  1.5  riastrad atomic_incsat_32(volatile uint32_t *p)
    988  1.5  riastrad {
    989  1.5  riastrad 	uint32_t o, n;
    990  1.5  riastrad 
    991  1.5  riastrad 	do {
    992  1.5  riastrad 		o = atomic_load_relaxed(p);
    993  1.5  riastrad 		if (__predict_false(o == UINT_MAX))
    994  1.5  riastrad 			return;
    995  1.5  riastrad 		n = o + 1;
    996  1.5  riastrad 	} while (__predict_false(atomic_cas_32(p, o, n) != o));
    997  1.5  riastrad }
    998  1.5  riastrad 
    999  1.5  riastrad /*
   1000  1.5  riastrad  * apei_gesb_ratecheck(sc, severity, suppressed)
   1001  1.5  riastrad  *
   1002  1.5  riastrad  *	Check for a rate limit on errors of the specified severity.
   1003  1.5  riastrad  *
   1004  1.5  riastrad  *	=> Return true if the error should be printed, and format into
   1005  1.5  riastrad  *	   the buffer suppressed a message saying how many errors were
   1006  1.5  riastrad  *	   previously suppressed.
   1007  1.5  riastrad  *
   1008  1.5  riastrad  *	=> Return false if the error should be suppressed because the
   1009  1.5  riastrad  *	   last one printed was too recent.
   1010  1.5  riastrad  */
   1011  1.5  riastrad static bool
   1012  1.5  riastrad apei_gesb_ratecheck(struct apei_softc *sc, uint32_t severity,
   1013  1.5  riastrad     char suppressed[static sizeof(" (4294967295 or more errors suppressed)")])
   1014  1.5  riastrad {
   1015  1.5  riastrad 	/* one of each type per minute (XXX worth making configurable?) */
   1016  1.5  riastrad 	const struct timeval mininterval = {60, 0};
   1017  1.5  riastrad 	unsigned i = MIN(severity, ACPI_HEST_GEN_ERROR_NONE); /* paranoia */
   1018  1.5  riastrad 	bool ok = false;
   1019  1.5  riastrad 
   1020  1.5  riastrad 	/*
   1021  1.5  riastrad 	 * If the lock is contended, the rate limit is probably
   1022  1.5  riastrad 	 * exceeded, so it's not OK to print.
   1023  1.5  riastrad 	 *
   1024  1.5  riastrad 	 * Otherwise, with the lock held, ask ratecheck(9) whether it's
   1025  1.5  riastrad 	 * OK to print.
   1026  1.5  riastrad 	 */
   1027  1.5  riastrad 	if (!__cpu_simple_lock_try(&apei_gesb_ratelimit[i].lock))
   1028  1.5  riastrad 		goto out;
   1029  1.5  riastrad 	ok = ratecheck(&apei_gesb_ratelimit[i].lasttime, &mininterval);
   1030  1.5  riastrad 	__cpu_simple_unlock(&apei_gesb_ratelimit[i].lock);
   1031  1.5  riastrad 
   1032  1.5  riastrad out:	/*
   1033  1.5  riastrad 	 * If it's OK to print, report the number of errors that were
   1034  1.5  riastrad 	 * suppressed.  If it's not OK to print, count a suppressed
   1035  1.5  riastrad 	 * error.
   1036  1.5  riastrad 	 */
   1037  1.5  riastrad 	if (ok) {
   1038  1.5  riastrad 		const uint32_t n =
   1039  1.5  riastrad 		    atomic_swap_32(&apei_gesb_ratelimit[i].suppressed, 0);
   1040  1.5  riastrad 
   1041  1.5  riastrad 		if (n == 0) {
   1042  1.5  riastrad 			suppressed[0] = '\0';
   1043  1.5  riastrad 		} else {
   1044  1.5  riastrad 			snprintf(suppressed,
   1045  1.5  riastrad 			    sizeof(" (4294967295 or more errors suppressed)"),
   1046  1.5  riastrad 			    " (%u%s error%s suppressed)",
   1047  1.5  riastrad 			    n,
   1048  1.5  riastrad 			    n == UINT32_MAX ? " or more" : "",
   1049  1.5  riastrad 			    n == 1 ? "" : "s");
   1050  1.5  riastrad 		}
   1051  1.5  riastrad 	} else {
   1052  1.5  riastrad 		atomic_incsat_32(&apei_gesb_ratelimit[i].suppressed);
   1053  1.5  riastrad 		suppressed[0] = '\0';
   1054  1.5  riastrad 	}
   1055  1.5  riastrad 	return ok;
   1056  1.5  riastrad }
   1057  1.5  riastrad 
   1058  1.5  riastrad /*
   1059  1.1  riastrad  * apei_gesb_report(sc, gesb, size, ctx)
   1060  1.1  riastrad  *
   1061  1.1  riastrad  *	Check a Generic Error Status Block, of at most the specified
   1062  1.1  riastrad  *	size in bytes, and report any errors in it.  Return the 32-bit
   1063  1.1  riastrad  *	Block Status in case the caller needs it to acknowledge the
   1064  1.1  riastrad  *	report to firmware.
   1065  1.1  riastrad  */
   1066  1.1  riastrad uint32_t
   1067  1.1  riastrad apei_gesb_report(struct apei_softc *sc, const ACPI_HEST_GENERIC_STATUS *gesb,
   1068  1.1  riastrad     size_t size, const char *ctx, bool *fatalp)
   1069  1.1  riastrad {
   1070  1.1  riastrad 	uint32_t status, unknownstatus, severity, nentries, i;
   1071  1.1  riastrad 	uint32_t datalen, rawdatalen;
   1072  1.1  riastrad 	const ACPI_HEST_GENERIC_DATA *gede0, *gede;
   1073  1.1  riastrad 	const unsigned char *rawdata;
   1074  1.5  riastrad 	bool ratelimitok = false;
   1075  1.5  riastrad 	char suppressed[sizeof(" (4294967295 or more errors suppressed)")];
   1076  1.1  riastrad 	bool fatal = false;
   1077  1.1  riastrad 
   1078  1.1  riastrad 	/*
   1079  1.1  riastrad 	 * Verify the buffer is large enough for a Generic Error Status
   1080  1.1  riastrad 	 * Block before we try to touch anything in it.
   1081  1.1  riastrad 	 */
   1082  1.1  riastrad 	if (size < sizeof(*gesb)) {
   1083  1.5  riastrad 		ratelimitok = apei_gesb_ratecheck(sc, ACPI_HEST_GEN_ERROR_NONE,
   1084  1.5  riastrad 		    suppressed);
   1085  1.5  riastrad 		if (ratelimitok) {
   1086  1.5  riastrad 			device_printf(sc->sc_dev,
   1087  1.5  riastrad 			    "%s: truncated GESB, %zu < %zu%s\n",
   1088  1.5  riastrad 			    ctx, size, sizeof(*gesb), suppressed);
   1089  1.5  riastrad 		}
   1090  1.2  riastrad 		status = 0;
   1091  1.2  riastrad 		goto out;
   1092  1.1  riastrad 	}
   1093  1.1  riastrad 	size -= sizeof(*gesb);
   1094  1.1  riastrad 
   1095  1.1  riastrad 	/*
   1096  1.1  riastrad 	 * Load the status.  Access ordering rules are unclear in the
   1097  1.1  riastrad 	 * ACPI specification; I'm guessing that load-acquire of the
   1098  1.1  riastrad 	 * block status is a good idea before any other access to the
   1099  1.1  riastrad 	 * GESB.
   1100  1.1  riastrad 	 */
   1101  1.1  riastrad 	status = atomic_load_acquire(&gesb->BlockStatus);
   1102  1.1  riastrad 
   1103  1.1  riastrad 	/*
   1104  1.1  riastrad 	 * If there are no status bits set, the rest of the GESB is
   1105  1.1  riastrad 	 * garbage, so stop here.
   1106  1.1  riastrad 	 */
   1107  1.1  riastrad 	if (status == 0) {
   1108  1.1  riastrad 		/* XXX dtrace */
   1109  1.1  riastrad 		/* XXX DPRINTF */
   1110  1.1  riastrad 		goto out;
   1111  1.1  riastrad 	}
   1112  1.1  riastrad 
   1113  1.5  riastrad 	/*
   1114  1.5  riastrad 	 * Read out the severity and get the number of entries in this
   1115  1.5  riastrad 	 * status block.
   1116  1.5  riastrad 	 */
   1117  1.5  riastrad 	severity = gesb->ErrorSeverity;
   1118  1.5  riastrad 	nentries = __SHIFTOUT(status, ACPI_HEST_ERROR_ENTRY_COUNT);
   1119  1.1  riastrad 
   1120  1.1  riastrad 	/*
   1121  1.1  riastrad 	 * Print a message to the console and dmesg about the severity
   1122  1.1  riastrad 	 * of the error.
   1123  1.1  riastrad 	 */
   1124  1.5  riastrad 	ratelimitok = apei_gesb_ratecheck(sc, severity, suppressed);
   1125  1.5  riastrad 	if (ratelimitok) {
   1126  1.5  riastrad 		char statusbuf[128];
   1127  1.5  riastrad 
   1128  1.5  riastrad 		/* XXX define this format somewhere */
   1129  1.5  riastrad 		snprintb(statusbuf, sizeof(statusbuf), "\177\020"
   1130  1.5  riastrad 		    "b\000"	"UE\0"
   1131  1.5  riastrad 		    "b\001"	"CE\0"
   1132  1.5  riastrad 		    "b\002"	"MULTI_UE\0"
   1133  1.5  riastrad 		    "b\003"	"MULTI_CE\0"
   1134  1.5  riastrad 		    "f\004\010"	"GEDE_COUNT\0"
   1135  1.5  riastrad 		    "\0", status);
   1136  1.5  riastrad 
   1137  1.5  riastrad 		if (severity < __arraycount(apei_gesb_severity)) {
   1138  1.5  riastrad 			device_printf(sc->sc_dev, "%s"
   1139  1.5  riastrad 			    " reported hardware error%s:"
   1140  1.5  riastrad 			    " severity=%s nentries=%u status=%s\n",
   1141  1.5  riastrad 			    ctx, suppressed,
   1142  1.5  riastrad 			    apei_gesb_severity[severity], nentries, statusbuf);
   1143  1.5  riastrad 		} else {
   1144  1.5  riastrad 			device_printf(sc->sc_dev, "%s reported error%s:"
   1145  1.5  riastrad 			    " severity=%"PRIu32" nentries=%u status=%s\n",
   1146  1.5  riastrad 			    ctx, suppressed,
   1147  1.5  riastrad 			    severity, nentries, statusbuf);
   1148  1.5  riastrad 		}
   1149  1.1  riastrad 	}
   1150  1.1  riastrad 
   1151  1.1  riastrad 	/*
   1152  1.1  riastrad 	 * Make a determination about whether the error is fatal.
   1153  1.1  riastrad 	 *
   1154  1.1  riastrad 	 * XXX Currently we don't have any mechanism to recover from
   1155  1.1  riastrad 	 * uncorrectable but recoverable errors, so we treat those --
   1156  1.1  riastrad 	 * and anything else we don't recognize -- as fatal.
   1157  1.1  riastrad 	 */
   1158  1.1  riastrad 	switch (severity) {
   1159  1.1  riastrad 	case ACPI_HEST_GEN_ERROR_CORRECTED:
   1160  1.1  riastrad 	case ACPI_HEST_GEN_ERROR_NONE:
   1161  1.1  riastrad 		fatal = false;
   1162  1.1  riastrad 		break;
   1163  1.1  riastrad 	case ACPI_HEST_GEN_ERROR_FATAL:
   1164  1.1  riastrad 	case ACPI_HEST_GEN_ERROR_RECOVERABLE: /* XXX */
   1165  1.1  riastrad 	default:
   1166  1.1  riastrad 		fatal = true;
   1167  1.1  riastrad 		break;
   1168  1.1  riastrad 	}
   1169  1.1  riastrad 
   1170  1.1  riastrad 	/*
   1171  1.1  riastrad 	 * Clear the bits we know about to warn if there's anything
   1172  1.1  riastrad 	 * left we don't understand.
   1173  1.1  riastrad 	 */
   1174  1.1  riastrad 	unknownstatus = status;
   1175  1.1  riastrad 	unknownstatus &= ~ACPI_HEST_UNCORRECTABLE;
   1176  1.1  riastrad 	unknownstatus &= ~ACPI_HEST_MULTIPLE_UNCORRECTABLE;
   1177  1.1  riastrad 	unknownstatus &= ~ACPI_HEST_CORRECTABLE;
   1178  1.1  riastrad 	unknownstatus &= ~ACPI_HEST_MULTIPLE_CORRECTABLE;
   1179  1.1  riastrad 	unknownstatus &= ~ACPI_HEST_ERROR_ENTRY_COUNT;
   1180  1.5  riastrad 	if (ratelimitok && unknownstatus != 0) {
   1181  1.1  riastrad 		/* XXX dtrace */
   1182  1.1  riastrad 		device_printf(sc->sc_dev, "%s: unknown BlockStatus bits:"
   1183  1.1  riastrad 		    " 0x%"PRIx32"\n", ctx, unknownstatus);
   1184  1.1  riastrad 	}
   1185  1.1  riastrad 
   1186  1.1  riastrad 	/*
   1187  1.1  riastrad 	 * Advance past the Generic Error Status Block (GESB) header to
   1188  1.1  riastrad 	 * the Generic Error Data Entries (GEDEs).
   1189  1.1  riastrad 	 */
   1190  1.1  riastrad 	gede0 = gede = (const ACPI_HEST_GENERIC_DATA *)(gesb + 1);
   1191  1.1  riastrad 
   1192  1.1  riastrad 	/*
   1193  1.1  riastrad 	 * Verify that the data length (GEDEs) fits within the size.
   1194  1.1  riastrad 	 * If not, truncate the GEDEs.
   1195  1.1  riastrad 	 */
   1196  1.1  riastrad 	datalen = gesb->DataLength;
   1197  1.1  riastrad 	if (size < datalen) {
   1198  1.5  riastrad 		if (ratelimitok) {
   1199  1.5  riastrad 			device_printf(sc->sc_dev, "%s:"
   1200  1.5  riastrad 			    " GESB DataLength exceeds bounds:"
   1201  1.5  riastrad 			    " %zu < %"PRIu32"\n",
   1202  1.5  riastrad 			    ctx, size, datalen);
   1203  1.5  riastrad 		}
   1204  1.1  riastrad 		datalen = size;
   1205  1.1  riastrad 	}
   1206  1.1  riastrad 	size -= datalen;
   1207  1.1  riastrad 
   1208  1.1  riastrad 	/*
   1209  1.1  riastrad 	 * Report each of the Generic Error Data Entries.
   1210  1.1  riastrad 	 */
   1211  1.1  riastrad 	for (i = 0; i < nentries; i++) {
   1212  1.1  riastrad 		size_t headerlen;
   1213  1.1  riastrad 		const struct apei_cper_report *report;
   1214  1.1  riastrad 		char subctx[128];
   1215  1.1  riastrad 
   1216  1.1  riastrad 		/*
   1217  1.1  riastrad 		 * Format a subcontext to show this numbered entry of
   1218  1.1  riastrad 		 * the GESB.
   1219  1.1  riastrad 		 */
   1220  1.1  riastrad 		snprintf(subctx, sizeof(subctx), "%s entry %"PRIu32, ctx, i);
   1221  1.1  riastrad 
   1222  1.1  riastrad 		/*
   1223  1.1  riastrad 		 * If the remaining GESB data length isn't enough for a
   1224  1.1  riastrad 		 * GEDE header, stop here.
   1225  1.1  riastrad 		 */
   1226  1.1  riastrad 		if (datalen < sizeof(*gede)) {
   1227  1.5  riastrad 			if (ratelimitok) {
   1228  1.5  riastrad 				device_printf(sc->sc_dev, "%s:"
   1229  1.5  riastrad 				    " truncated GEDE: %"PRIu32" < %zu bytes\n",
   1230  1.5  riastrad 				    subctx, datalen, sizeof(*gede));
   1231  1.5  riastrad 			}
   1232  1.1  riastrad 			break;
   1233  1.1  riastrad 		}
   1234  1.1  riastrad 
   1235  1.1  riastrad 		/*
   1236  1.1  riastrad 		 * Print the GEDE header and get the full length (may
   1237  1.1  riastrad 		 * vary from revision to revision of the GEDE) and the
   1238  1.1  riastrad 		 * CPER report function if possible.
   1239  1.1  riastrad 		 */
   1240  1.5  riastrad 		apei_gede_report_header(sc, gede, subctx, ratelimitok,
   1241  1.1  riastrad 		    &headerlen, &report);
   1242  1.1  riastrad 
   1243  1.1  riastrad 		/*
   1244  1.1  riastrad 		 * If we don't know the header length because of an
   1245  1.1  riastrad 		 * unfamiliar revision, stop here.
   1246  1.1  riastrad 		 */
   1247  1.1  riastrad 		if (headerlen == 0) {
   1248  1.5  riastrad 			if (ratelimitok) {
   1249  1.5  riastrad 				device_printf(sc->sc_dev, "%s:"
   1250  1.5  riastrad 				    " unknown revision: 0x%"PRIx16"\n",
   1251  1.5  riastrad 				    subctx, gede->Revision);
   1252  1.5  riastrad 			}
   1253  1.1  riastrad 			break;
   1254  1.1  riastrad 		}
   1255  1.1  riastrad 
   1256  1.1  riastrad 		/*
   1257  1.1  riastrad 		 * Stop here if what we mapped is too small for the
   1258  1.1  riastrad 		 * error data length.
   1259  1.1  riastrad 		 */
   1260  1.1  riastrad 		datalen -= headerlen;
   1261  1.1  riastrad 		if (datalen < gede->ErrorDataLength) {
   1262  1.5  riastrad 			if (ratelimitok) {
   1263  1.5  riastrad 				device_printf(sc->sc_dev, "%s:"
   1264  1.5  riastrad 				    " truncated GEDE payload:"
   1265  1.5  riastrad 				    " %"PRIu32" < %"PRIu32" bytes\n",
   1266  1.5  riastrad 				    subctx, datalen, gede->ErrorDataLength);
   1267  1.5  riastrad 			}
   1268  1.1  riastrad 			break;
   1269  1.1  riastrad 		}
   1270  1.1  riastrad 
   1271  1.1  riastrad 		/*
   1272  1.1  riastrad 		 * Report the Common Platform Error Record appendix to
   1273  1.1  riastrad 		 * this Generic Error Data Entry.
   1274  1.1  riastrad 		 */
   1275  1.1  riastrad 		if (report == NULL) {
   1276  1.5  riastrad 			if (ratelimitok) {
   1277  1.5  riastrad 				device_printf(sc->sc_dev, "%s:"
   1278  1.5  riastrad 				    " [unknown type]\n", ctx);
   1279  1.5  riastrad 			}
   1280  1.1  riastrad 		} else {
   1281  1.5  riastrad 			/* XXX pass ratelimit through */
   1282  1.1  riastrad 			(*report->func)(sc, (const char *)gede + headerlen,
   1283  1.5  riastrad 			    gede->ErrorDataLength, subctx, ratelimitok);
   1284  1.1  riastrad 		}
   1285  1.1  riastrad 
   1286  1.1  riastrad 		/*
   1287  1.1  riastrad 		 * Advance past the GEDE header and CPER data to the
   1288  1.1  riastrad 		 * next GEDE.
   1289  1.1  riastrad 		 */
   1290  1.1  riastrad 		gede = (const ACPI_HEST_GENERIC_DATA *)((const char *)gede +
   1291  1.1  riastrad 		    + headerlen + gede->ErrorDataLength);
   1292  1.1  riastrad 	}
   1293  1.1  riastrad 
   1294  1.1  riastrad 	/*
   1295  1.1  riastrad 	 * Advance past the Generic Error Data Entries (GEDEs) to the
   1296  1.1  riastrad 	 * raw error data.
   1297  1.1  riastrad 	 *
   1298  1.1  riastrad 	 * XXX Provide Max Raw Data Length as a parameter, as found in
   1299  1.1  riastrad 	 * various HEST entry types.
   1300  1.1  riastrad 	 */
   1301  1.1  riastrad 	rawdata = (const unsigned char *)gede0 + datalen;
   1302  1.1  riastrad 
   1303  1.1  riastrad 	/*
   1304  1.1  riastrad 	 * Verify that the raw data length fits within the size.  If
   1305  1.1  riastrad 	 * not, truncate the raw data.
   1306  1.1  riastrad 	 */
   1307  1.1  riastrad 	rawdatalen = gesb->RawDataLength;
   1308  1.1  riastrad 	if (size < rawdatalen) {
   1309  1.5  riastrad 		if (ratelimitok) {
   1310  1.5  riastrad 			device_printf(sc->sc_dev, "%s:"
   1311  1.5  riastrad 			    " GESB RawDataLength exceeds bounds:"
   1312  1.5  riastrad 			    " %zu < %"PRIu32"\n",
   1313  1.5  riastrad 			    ctx, size, rawdatalen);
   1314  1.5  riastrad 		}
   1315  1.1  riastrad 		rawdatalen = size;
   1316  1.1  riastrad 	}
   1317  1.1  riastrad 	size -= rawdatalen;
   1318  1.1  riastrad 
   1319  1.1  riastrad 	/*
   1320  1.1  riastrad 	 * Hexdump the raw data, if any.
   1321  1.1  riastrad 	 */
   1322  1.5  riastrad 	if (ratelimitok && rawdatalen > 0) {
   1323  1.1  riastrad 		char devctx[128];
   1324  1.1  riastrad 
   1325  1.1  riastrad 		snprintf(devctx, sizeof(devctx), "%s: %s: raw data",
   1326  1.1  riastrad 		    device_xname(sc->sc_dev), ctx);
   1327  1.1  riastrad 		hexdump(printf, devctx, rawdata, rawdatalen);
   1328  1.1  riastrad 	}
   1329  1.1  riastrad 
   1330  1.1  riastrad 	/*
   1331  1.1  riastrad 	 * If there's anything left after the raw data, warn.
   1332  1.1  riastrad 	 */
   1333  1.5  riastrad 	if (ratelimitok && size > 0) {
   1334  1.1  riastrad 		device_printf(sc->sc_dev, "%s: excess data: %zu bytes\n",
   1335  1.1  riastrad 		    ctx, size);
   1336  1.1  riastrad 	}
   1337  1.1  riastrad 
   1338  1.1  riastrad 	/*
   1339  1.1  riastrad 	 * Return the status so the caller can ack it, and tell the
   1340  1.1  riastrad 	 * caller whether this error is fatal.
   1341  1.1  riastrad 	 */
   1342  1.1  riastrad out:	*fatalp = fatal;
   1343  1.1  riastrad 	return status;
   1344  1.1  riastrad }
   1345  1.1  riastrad 
   1346  1.1  riastrad MODULE(MODULE_CLASS_DRIVER, apei, NULL);
   1347  1.1  riastrad 
   1348  1.1  riastrad #ifdef _MODULE
   1349  1.1  riastrad #include "ioconf.c"
   1350  1.1  riastrad #endif
   1351  1.1  riastrad 
   1352  1.1  riastrad static int
   1353  1.1  riastrad apei_modcmd(modcmd_t cmd, void *opaque)
   1354  1.1  riastrad {
   1355  1.1  riastrad 	int error = 0;
   1356  1.1  riastrad 
   1357  1.1  riastrad 	switch (cmd) {
   1358  1.1  riastrad 	case MODULE_CMD_INIT:
   1359  1.1  riastrad #ifdef _MODULE
   1360  1.1  riastrad 		error = config_init_component(cfdriver_ioconf_apei,
   1361  1.1  riastrad 		    cfattach_ioconf_apei, cfdata_ioconf_apei);
   1362  1.1  riastrad #endif
   1363  1.1  riastrad 		return error;
   1364  1.1  riastrad 	case MODULE_CMD_FINI:
   1365  1.1  riastrad #ifdef _MODULE
   1366  1.1  riastrad 		error = config_fini_component(cfdriver_ioconf_apei,
   1367  1.1  riastrad 		    cfattach_ioconf_apei, cfdata_ioconf_apei);
   1368  1.1  riastrad #endif
   1369  1.1  riastrad 		return error;
   1370  1.1  riastrad 	default:
   1371  1.1  riastrad 		return ENOTTY;
   1372  1.1  riastrad 	}
   1373  1.1  riastrad }
   1374