root/sys/dev/acpi/apei_cper.h
/*      $NetBSD: apei_cper.h,v 1.5 2024/10/27 12:59:08 riastradh Exp $  */

/*-
 * Copyright (c) 2024 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * UEFI Common Platform Error Record
 *
 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html
 */

#ifndef _SYS_DEV_ACPI_APEI_CPER_H_
#define _SYS_DEV_ACPI_APEI_CPER_H_

#include <sys/types.h>

#include <sys/cdefs.h>

/*
 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header
 */
struct cper_header {
        char            SignatureStart[4];      /* `CPER' */
        uint16_t        Revision;
        uint32_t        SignatureEnd;           /* 0xffffffff */
        uint16_t        SectionCount;
        uint32_t        ErrorSeverity;
        uint32_t        ValidationBits;
        uint32_t        RecordLength;
        uint64_t        Timestamp;
        uint8_t         PlatformId[16];
        uint8_t         PartitionId[16];
        uint8_t         CreatorId[16];
        uint8_t         NotificationType[16];
        uint64_t        RecordId;
        uint32_t        Flags;
        uint64_t        PersistenceInfo;
        uint8_t         Reserved[12];
} __packed;
__CTASSERT(sizeof(struct cper_header) == 128);

enum {                          /* struct cper_header::ErrorSeverity */
        CPER_ERROR_SEVERITY_RECOVERABLE         = 0,
        CPER_ERROR_SEVERITY_FATAL               = 1,
        CPER_ERROR_SEVERITY_CORRECTED           = 2,
        CPER_ERROR_SEVERITY_INFORMATIONAL       = 3,
};

enum {                          /* struct cper_header::ValidationBits */
        CPER_VALID_PLATFORM_ID          = __BIT(0),
        CPER_VALID_TIMESTAMP            = __BIT(1),
        CPER_VALID_PARTITION_ID         = __BIT(2),
};

/*
 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#error-record-header-flags
 */
enum {                          /* struct cper_header::Flags */
        CPER_HW_ERROR_FLAG_RECOVERED    = __BIT(0),
        CPER_HW_ERROR_FLAG_PREVERR      = __BIT(1),
        CPER_HW_ERROR_FLAG_SIMULATED    = __BIT(2),
};

/*
 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#section-descriptor-format
 */
enum {
        CPER_SECTION_FLAG_PRIMARY                       = __BIT(0),
        CPER_SECTION_FLAG_CONTAINMENT_WARNING           = __BIT(1),
        CPER_SECTION_FLAG_RESET                         = __BIT(2),
        CPER_SECTION_FLAG_ERROR_THRESHOLD_EXCEEDED      = __BIT(3),
        CPER_SECTION_FLAG_RESOURCE_NOT_ACCESSIBLE       = __BIT(4),
        CPER_SECTION_FLAG_LATENT_ERROR                  = __BIT(5),
        CPER_SECTION_FLAG_PROPAGATED                    = __BIT(6),
        CPER_SECTION_FLAG_OVERFLOW                      = __BIT(7),
};

#define CPER_SECTION_FLAGS_FMT  "\177\020"                                    \
        "b\000" "PRIMARY\0"                                                   \
        "b\001" "CONTAINMENT_WARNING\0"                                       \
        "b\002" "RESET\0"                                                     \
        "b\003" "ERROR_THRESHOLD_EXCEEDED\0"                                  \
        "b\004" "RESOURCE_NOT_ACCESSIBLE\0"                                   \
        "b\005" "LATENT_ERROR\0"                                              \
        "b\006" "PROPAGATED\0"                                                \
        "b\007" "OVERFLOW\0"                                                  \
        "\0"

/*
 * N.2.5. Memory Error Section
 *
 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#memory-error-section
 *
 * Type: {0xa5bc1114,0x6f64,0x4ede,{0xb8,0x63,0x3e,0x83,0xed,0x7c,0x83,0xb1}}
 */

struct cper_memory_error {
        uint64_t        ValidationBits;
        uint64_t        ErrorStatus;
        uint64_t        PhysicalAddress;
        uint64_t        PhysicalAddressMask;
        uint16_t        Node;
        uint16_t        Card;
        uint16_t        Module;
        uint16_t        Bank;
        uint16_t        Device;
        uint16_t        Row;
        uint16_t        Column;
        uint16_t        BitPosition;
        uint64_t        RequestorId;
        uint64_t        ResponderId;
        uint64_t        TargetId;
        uint8_t         MemoryErrorType;
} __packed;
__CTASSERT(sizeof(struct cper_memory_error) == 73);

struct cper_memory_error_ext {
        struct cper_memory_error        Base;
        uint8_t         Extended;
        uint16_t        RankNumber;
        uint16_t        CardHandle;
        uint16_t        ModuleHandle;
} __packed;
__CTASSERT(sizeof(struct cper_memory_error_ext) == 80);

enum {                          /* struct cper_memory_error::ValidationBits */
        CPER_MEMORY_ERROR_VALID_ERROR_STATUS            = __BIT(0),
        CPER_MEMORY_ERROR_VALID_PHYSICAL_ADDRESS        = __BIT(1),
        CPER_MEMORY_ERROR_VALID_PHYSICAL_ADDRESS_MASK   = __BIT(2),
        CPER_MEMORY_ERROR_VALID_NODE                    = __BIT(3),
        CPER_MEMORY_ERROR_VALID_CARD                    = __BIT(4),
        CPER_MEMORY_ERROR_VALID_MODULE                  = __BIT(5),
        CPER_MEMORY_ERROR_VALID_BANK                    = __BIT(6),
        CPER_MEMORY_ERROR_VALID_DEVICE                  = __BIT(7),
        CPER_MEMORY_ERROR_VALID_ROW                     = __BIT(8),
        CPER_MEMORY_ERROR_VALID_COLUMN                  = __BIT(9),
        CPER_MEMORY_ERROR_VALID_BIT_POSITION            = __BIT(10),
        CPER_MEMORY_ERROR_VALID_REQUESTOR_ID            = __BIT(11),
        CPER_MEMORY_ERROR_VALID_RESPONDER_ID            = __BIT(12),
        CPER_MEMORY_ERROR_VALID_TARGET_ID               = __BIT(13),
        CPER_MEMORY_ERROR_VALID_MEMORY_ERROR_TYPE       = __BIT(14),
        CPER_MEMORY_ERROR_VALID_RANK_NUMBER             = __BIT(15),
        CPER_MEMORY_ERROR_VALID_CARD_HANDLE             = __BIT(16),
        CPER_MEMORY_ERROR_VALID_MODULE_HANDLE           = __BIT(17),
        CPER_MEMORY_ERROR_VALID_EXTENDED_ROW            = __BIT(18),
        CPER_MEMORY_ERROR_VALID_BANK_GROUP              = __BIT(19),
        CPER_MEMORY_ERROR_VALID_BANK_ADDRESS            = __BIT(20),
        CPER_MEMORY_ERROR_VALID_CHIP_ID                 = __BIT(21),
};

#define CPER_MEMORY_ERROR_VALIDATION_BITS_FMT   "\177\020"                    \
        "b\000" "ERROR_STATUS\0"                                              \
        "b\001" "PHYSICAL_ADDRESS\0"                                          \
        "b\002" "PHYSICAL_ADDRESS_MASK\0"                                     \
        "b\003" "NODE\0"                                                      \
        "b\004" "CARD\0"                                                      \
        "b\005" "MODULE\0"                                                    \
        "b\006" "BANK\0"                                                      \
        "b\007" "DEVICE\0"                                                    \
        "b\010" "ROW\0"                                                       \
        "b\011" "COLUMN\0"                                                    \
        "b\012" "BIT_POSITION\0"                                              \
        "b\013" "REQUESTOR_ID\0"                                              \
        "b\014" "RESPONDER_ID\0"                                              \
        "b\015" "TARGET_ID\0"                                                 \
        "b\016" "MEMORY_ERROR_TYPE\0"                                         \
        "b\017" "RANK_NUMBER\0"                                               \
        "b\020" "CARD_HANDLE\0"                                               \
        "b\021" "MODULE_HANDLE\0"                                             \
        "b\022" "EXTENDED_ROW\0"                                              \
        "b\023" "BANK_GROUP\0"                                                \
        "b\024" "BANK_ADDRESS\0"                                              \
        "b\025" "CHIP_ID\0"                                                   \
        "\0"

enum {                          /* struct cper_memory_error::Bank */
        CPER_MEMORY_ERROR_BANK_ADDRESS  = __BITS(7,0),
        CPER_MEMORY_ERROR_BANK_GROUP    = __BITS(15,8),
};

#define CPER_MEMORY_ERROR_TYPES(F)                                            \
        F(CPER_MEMORY_ERROR_UNKNOWN, UNKNOWN, 0)                              \
        F(CPER_MEMORY_ERROR_NO_ERROR, NO_ERROR, 1)                            \
        F(CPER_MEMORY_ERROR_SINGLEBIT_ECC, SINGLEBIT_ECC, 2)                  \
        F(CPER_MEMORY_ERROR_MULTIBIT_ECC, MULTIBIT_ECC, 3)                    \
        F(CPER_MEMORY_ERROR_SINGLESYM_CHIPKILL_ECC, SINGLESYM_CHIPKILL_ECC, 4)\
        F(CPER_MEMORY_ERROR_MULTISYM_CHIPKILL_ECC, MULTISYM_CHIPKILL_ECC, 5)  \
        F(CPER_MEMORY_ERROR_MASTER_ABORT, MASTER_ABORT, 6)                    \
        F(CPER_MEMORY_ERROR_TARGET_ABORT, TARGET_ABORT, 7)                    \
        F(CPER_MEMORY_ERROR_PARITY_ERROR, PARITY_ERROR, 8)                    \
        F(CPER_MEMORY_ERROR_WATCHDOG_TIMEOUT, WATCHDOG_TIMEOUT, 9)            \
        F(CPER_MEMORY_ERROR_INVALID_ADDRESS, INVALID_ADDRESS, 10)             \
        F(CPER_MEMORY_ERROR_MIRROR_BROKEN, MIRROR_BROKEN, 11)                 \
        F(CPER_MEMORY_ERROR_MEMORY_SPARING, MEMORY_SPARING, 12)               \
        F(CPER_MEMORY_ERROR_SCRUB_CORRECTED_ERROR, SCRUB_CORRECTED_ERROR, 13) \
        F(CPER_MEMORY_ERROR_SCRUB_UNCORRECTED_ERROR, SCRUB_UNCORRECTED_ERROR, \
            14)                                                               \
        F(CPER_MEMORY_ERROR_PHYSMEM_MAPOUT_EVENT, PHYSMEM_MAPOUT_EVENT, 15)   \
        /* end of CPER_MEMORY_ERROR_TYPES */

enum cper_memory_error_type { /* struct cper_memory_error::MemoryErrorType */
#define CPER_MEMORY_ERROR_TYPE_DEF(LN, SN, V)   LN = V,
        CPER_MEMORY_ERROR_TYPES(CPER_MEMORY_ERROR_TYPE_DEF)
#undef  CPER_MEMORY_ERROR_TYPE_DEF
};

enum {                          /* struct cper_memory_error_ext::Extended */
        CPER_MEMORY_ERROR_EXTENDED_ROWBIT16             = __BIT(0),
        CPER_MEMORY_ERROR_EXTENDED_ROWBIT17             = __BIT(1),
        CPER_MEMORY_ERROR_EXTENDED_CHIPID               = __BITS(7,5),
};

/*
 * N.2.7. PCI Express Error Section
 *
 * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#pci-express-error-section
 *
 * Type: {0xd995e954,0xbbc1,0x430f,{0xad,0x91,0xb4,0x4d,0xcb,0x3c,0x6f,0x35}}
 */

struct cper_pcie_error {
        uint64_t        ValidationBits;
        uint32_t        PortType;
        uint32_t        Version;
        uint32_t        CommandStatus;
        uint32_t        Reserved0;
        struct {
                uint8_t         VendorID[2];
                uint8_t         DeviceID[2]; /* product */
                uint8_t         ClassCode[3];
                uint8_t         Function;
                uint8_t         Device;
                uint8_t         Segment[2];
                uint8_t         Bus;
                uint8_t         SecondaryBus;
                uint8_t         Slot[2]; /* bits 0:2 resv, bits 3:15 slot */
                uint8_t         Reserved0;
        }               DeviceID;
        uint64_t        DeviceSerial;
        uint32_t        BridgeControlStatus;
        uint8_t         CapabilityStructure[60];
        uint8_t         AERInfo[96];
} __packed;
__CTASSERT(sizeof(struct cper_pcie_error) == 208);

enum {                          /* struct cper_pcie_error::ValidationBits */
        CPER_PCIE_ERROR_VALID_PORT_TYPE                 = __BIT(0),
        CPER_PCIE_ERROR_VALID_VERSION                   = __BIT(1),
        CPER_PCIE_ERROR_VALID_COMMAND_STATUS            = __BIT(2),
        CPER_PCIE_ERROR_VALID_DEVICE_ID                 = __BIT(3),
        CPER_PCIE_ERROR_VALID_DEVICE_SERIAL             = __BIT(4),
        CPER_PCIE_ERROR_VALID_BRIDGE_CONTROL_STATUS     = __BIT(5),
        CPER_PCIE_ERROR_VALID_CAPABILITY_STRUCTURE      = __BIT(6),
        CPER_PCIE_ERROR_VALID_AER_INFO                  = __BIT(7),
};

#define CPER_PCIE_ERROR_VALIDATION_BITS_FMT     "\177\020"                    \
        "b\000" "PORT_TYPE\0"                                                 \
        "b\001" "VERSION\0"                                                   \
        "b\002" "COMMAND_STATUS\0"                                            \
        "b\003" "DEVICE_ID\0"                                                 \
        "b\004" "DEVICE_SERIAL\0"                                             \
        "b\005" "BRIDGE_CONTROL_STATUS\0"                                     \
        "b\006" "CAPABILITY_STRUCTURE\0"                                      \
        "b\007" "AER_INFO\0"                                                  \
        "\0"

#define CPER_PCIE_ERROR_PORT_TYPES(F)                                         \
        F(CPER_PCIE_ERROR_PORT_TYPE_PCIE_ENDPOINT, PCIE_ENDPOINT, 0)          \
        F(CPER_PCIE_ERROR_PORT_TYPE_LEGACY_PCI_ENDPOINT, LEGACY_PCI_ENDPOINT, \
            1)                                                                \
        F(CPER_PCIE_ERROR_PORT_TYPE_ROOTPORT5_UPSTREAMSWITCH,                 \
            ROOTPORT5_UPSTREAMSWITCH, 4)                                      \
        F(CPER_PCIE_ERROR_PORT_TYPE_DOWNSTREAMSWITCH, DOWNSTREAMSWITCH, 6)    \
        F(CPER_PCIE_ERROR_PORT_TYPE_PCIE_PCI_BRIDGE, PCIE_PCI_BRIDGE, 7)      \
        F(CPER_PCIE_ERROR_PORT_TYPE_PCI_PCIE_BRIDGE, PCI_PCIE_BRIDGE, 8)      \
        F(CPER_PCIE_ERROR_PORT_TYPE_RCIEP_DEV, RCIEP_DEV, 9)                  \
                /* Root Complex Integrated Endpoint Device */                 \
        F(CPER_PCIE_ERROR_PORT_TYPE_RCEC, RCEC, 10)                           \
                /* Root Complex Event Collector */                            \
        /* end of CPER_PCIE_ERROR_PORT_TYPES */

enum cper_pcie_error_port_type { /* struct cper_pcie_error::PortType */
#define CPER_PCIE_ERROR_PORT_TYPE_DEF(LN, SN, V)        LN = V,
        CPER_PCIE_ERROR_PORT_TYPES(CPER_PCIE_ERROR_PORT_TYPE_DEF)
#undef  CPER_PCIE_ERROR_PORT_TYPE_DEF
};

#endif  /* _SYS_DEV_ACPI_APEI_CPER_H_ */