| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* Copyright(c) 2023 Intel Corporation. */ | |
| #ifndef _LINUX_CXL_EVENT_H | |
| #define _LINUX_CXL_EVENT_H | |
| #include <linux/types.h> | |
| #include <linux/uuid.h> | |
| #include <linux/workqueue_types.h> | |
| /* | |
| * Common Event Record Format | |
| * CXL rev 3.0 section 8.2.9.2.1; Table 8-42 | |
| */ | |
| struct cxl_event_record_hdr { | |
| u8 length; | |
| u8 flags[3]; | |
| __le16 handle; | |
| __le16 related_handle; | |
| __le64 timestamp; | |
| u8 maint_op_class; | |
| u8 maint_op_sub_class; | |
| __le16 ld_id; | |
| u8 head_id; | |
| u8 reserved[11]; | |
| } __packed; | |
| struct cxl_event_media_hdr { | |
| struct cxl_event_record_hdr hdr; | |
| __le64 phys_addr; | |
| u8 descriptor; | |
| u8 type; | |
| u8 transaction_type; | |
| /* | |
| * The meaning of Validity Flags from bit 2 is | |
| * different across DRAM and General Media records | |
| */ | |
| u8 validity_flags[2]; | |
| u8 channel; | |
| u8 rank; | |
| } __packed; | |
| #define CXL_EVENT_RECORD_DATA_LENGTH 0x50 | |
| struct cxl_event_generic { | |
| struct cxl_event_record_hdr hdr; | |
| u8 data[CXL_EVENT_RECORD_DATA_LENGTH]; | |
| } __packed; | |
| /* | |
| * General Media Event Record | |
| * CXL rev 3.1 Section 8.2.9.2.1.1; Table 8-45 | |
| */ | |
| #define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10 | |
| struct cxl_event_gen_media { | |
| struct cxl_event_media_hdr media_hdr; | |
| u8 device[3]; | |
| u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; | |
| u8 cme_threshold_ev_flags; | |
| u8 cme_count[3]; | |
| u8 sub_type; | |
| u8 reserved[41]; | |
| } __packed; | |
| /* | |
| * DRAM Event Record - DER | |
| * CXL rev 3.1 section 8.2.9.2.1.2; Table 8-46 | |
| */ | |
| #define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20 | |
| struct cxl_event_dram { | |
| struct cxl_event_media_hdr media_hdr; | |
| u8 nibble_mask[3]; | |
| u8 bank_group; | |
| u8 bank; | |
| u8 row[3]; | |
| u8 column[2]; | |
| u8 correction_mask[CXL_EVENT_DER_CORRECTION_MASK_SIZE]; | |
| u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; | |
| u8 sub_channel; | |
| u8 cme_threshold_ev_flags; | |
| u8 cvme_count[3]; | |
| u8 sub_type; | |
| u8 reserved; | |
| } __packed; | |
| /* | |
| * Get Health Info Record | |
| * CXL rev 3.1 section 8.2.9.9.3.1; Table 8-133 | |
| */ | |
| struct cxl_get_health_info { | |
| u8 health_status; | |
| u8 media_status; | |
| u8 add_status; | |
| u8 life_used; | |
| u8 device_temp[2]; | |
| u8 dirty_shutdown_cnt[4]; | |
| u8 cor_vol_err_cnt[4]; | |
| u8 cor_per_err_cnt[4]; | |
| } __packed; | |
| /* | |
| * Memory Module Event Record | |
| * CXL rev 3.1 section 8.2.9.2.1.3; Table 8-47 | |
| */ | |
| struct cxl_event_mem_module { | |
| struct cxl_event_record_hdr hdr; | |
| u8 event_type; | |
| struct cxl_get_health_info info; | |
| u8 validity_flags[2]; | |
| u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; | |
| u8 event_sub_type; | |
| u8 reserved[0x2a]; | |
| } __packed; | |
| /* | |
| * Memory Sparing Event Record - MSER | |
| * CXL rev 3.2 section 8.2.10.2.1.4; Table 8-60 | |
| */ | |
| struct cxl_event_mem_sparing { | |
| struct cxl_event_record_hdr hdr; | |
| /* | |
| * The fields maintenance operation class and maintenance operation | |
| * subclass defined in the Memory Sparing Event Record are the | |
| * duplication of the same in the common event record. Thus defined | |
| * as reserved and to be removed after the spec correction. | |
| */ | |
| u8 rsv1; | |
| u8 rsv2; | |
| u8 flags; | |
| u8 result; | |
| __le16 validity_flags; | |
| u8 reserved1[6]; | |
| __le16 res_avail; | |
| u8 channel; | |
| u8 rank; | |
| u8 nibble_mask[3]; | |
| u8 bank_group; | |
| u8 bank; | |
| u8 row[3]; | |
| __le16 column; | |
| u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; | |
| u8 sub_channel; | |
| u8 reserved2[0x25]; | |
| } __packed; | |
| union cxl_event { | |
| struct cxl_event_generic generic; | |
| struct cxl_event_gen_media gen_media; | |
| struct cxl_event_dram dram; | |
| struct cxl_event_mem_module mem_module; | |
| struct cxl_event_mem_sparing mem_sparing; | |
| /* dram & gen_media event header */ | |
| struct cxl_event_media_hdr media_hdr; | |
| } __packed; | |
| /* | |
| * Common Event Record Format; in event logs | |
| * CXL rev 3.0 section 8.2.9.2.1; Table 8-42 | |
| */ | |
| struct cxl_event_record_raw { | |
| uuid_t id; | |
| union cxl_event event; | |
| } __packed; | |
| enum cxl_event_type { | |
| CXL_CPER_EVENT_GENERIC, | |
| CXL_CPER_EVENT_GEN_MEDIA, | |
| CXL_CPER_EVENT_DRAM, | |
| CXL_CPER_EVENT_MEM_MODULE, | |
| CXL_CPER_EVENT_MEM_SPARING, | |
| }; | |
| #define CPER_CXL_DEVICE_ID_VALID BIT(0) | |
| #define CPER_CXL_DEVICE_SN_VALID BIT(1) | |
| #define CPER_CXL_COMP_EVENT_LOG_VALID BIT(2) | |
| struct cxl_cper_event_rec { | |
| struct { | |
| u32 length; | |
| u64 validation_bits; | |
| struct cper_cxl_event_devid { | |
| u16 vendor_id; | |
| u16 device_id; | |
| u8 func_num; | |
| u8 device_num; | |
| u8 bus_num; | |
| u16 segment_num; | |
| u16 slot_num; /* bits 2:0 reserved */ | |
| u8 reserved; | |
| } __packed device_id; | |
| struct cper_cxl_event_sn { | |
| u32 lower_dw; | |
| u32 upper_dw; | |
| } __packed dev_serial_num; | |
| } __packed hdr; | |
| union cxl_event event; | |
| } __packed; | |
| struct cxl_cper_work_data { | |
| enum cxl_event_type event_type; | |
| struct cxl_cper_event_rec rec; | |
| }; | |
| #define PROT_ERR_VALID_AGENT_TYPE BIT_ULL(0) | |
| #define PROT_ERR_VALID_AGENT_ADDRESS BIT_ULL(1) | |
| #define PROT_ERR_VALID_DEVICE_ID BIT_ULL(2) | |
| #define PROT_ERR_VALID_SERIAL_NUMBER BIT_ULL(3) | |
| #define PROT_ERR_VALID_CAPABILITY BIT_ULL(4) | |
| #define PROT_ERR_VALID_DVSEC BIT_ULL(5) | |
| #define PROT_ERR_VALID_ERROR_LOG BIT_ULL(6) | |
| /* | |
| * The layout of the enumeration and the values matches CXL Agent Type | |
| * field in the UEFI 2.10 Section N.2.13, | |
| */ | |
| enum { | |
| RCD, /* Restricted CXL Device */ | |
| RCH_DP, /* Restricted CXL Host Downstream Port */ | |
| DEVICE, /* CXL Device */ | |
| LD, /* CXL Logical Device */ | |
| FMLD, /* CXL Fabric Manager managed Logical Device */ | |
| RP, /* CXL Root Port */ | |
| DSP, /* CXL Downstream Switch Port */ | |
| USP, /* CXL Upstream Switch Port */ | |
| }; | |
| #pragma pack(1) | |
| /* Compute Express Link Protocol Error Section, UEFI v2.10 sec N.2.13 */ | |
| struct cxl_cper_sec_prot_err { | |
| u64 valid_bits; | |
| u8 agent_type; | |
| u8 reserved[7]; | |
| /* | |
| * Except for RCH Downstream Port, all the remaining CXL Agent | |
| * types are uniquely identified by the PCIe compatible SBDF number. | |
| */ | |
| union { | |
| u64 rcrb_base_addr; | |
| struct { | |
| u8 function; | |
| u8 device; | |
| u8 bus; | |
| u16 segment; | |
| u8 reserved_1[3]; | |
| }; | |
| } agent_addr; | |
| struct { | |
| u16 vendor_id; | |
| u16 device_id; | |
| u16 subsystem_vendor_id; | |
| u16 subsystem_id; | |
| u8 class_code[2]; | |
| u16 slot; | |
| u8 reserved_1[4]; | |
| } device_id; | |
| struct { | |
| u32 lower_dw; | |
| u32 upper_dw; | |
| } dev_serial_num; | |
| u8 capability[60]; | |
| u16 dvsec_len; | |
| u16 err_len; | |
| u8 reserved_2[4]; | |
| }; | |
| #pragma pack() | |
| /* CXL RAS Capability Structure, CXL v3.0 sec 8.2.4.16 */ | |
| struct cxl_ras_capability_regs { | |
| u32 uncor_status; | |
| u32 uncor_mask; | |
| u32 uncor_severity; | |
| u32 cor_status; | |
| u32 cor_mask; | |
| u32 cap_control; | |
| u32 header_log[16]; | |
| }; | |
| struct cxl_cper_prot_err_work_data { | |
| struct cxl_cper_sec_prot_err prot_err; | |
| struct cxl_ras_capability_regs ras_cap; | |
| int severity; | |
| }; | |
| #ifdef CONFIG_ACPI_APEI_GHES | |
| int cxl_cper_register_work(struct work_struct *work); | |
| void cxl_cper_unregister_work(struct work_struct *work); | |
| int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd); | |
| void cxl_cper_register_prot_err_work(struct work_struct *work); | |
| void cxl_cper_unregister_prot_err_work(void); | |
| int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd); | |
| #else | |
| static inline int cxl_cper_register_work(struct work_struct *work) | |
| { | |
| return 0; | |
| } | |
| static inline void cxl_cper_unregister_work(struct work_struct *work) { } | |
| static inline int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd) | |
| { | |
| return 0; | |
| } | |
| static inline void cxl_cper_register_prot_err_work(struct work_struct *work) { } | |
| static inline void cxl_cper_unregister_prot_err_work(void) { } | |
| static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd) | |
| { | |
| return 0; | |
| } | |
| #endif | |
| #ifdef CONFIG_ACPI_APEI_PCIEAER | |
| int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err); | |
| int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd, | |
| struct cxl_cper_sec_prot_err *prot_err, | |
| int severity); | |
| #else | |
| static inline int | |
| cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err) | |
| { | |
| return -EOPNOTSUPP; | |
| } | |
| static inline int | |
| cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd, | |
| struct cxl_cper_sec_prot_err *prot_err, | |
| int severity) | |
| { | |
| return -EOPNOTSUPP; | |
| } | |
| #endif | |
| void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *wd); | |
| #endif /* _LINUX_CXL_EVENT_H */ |