| 1 | /* |
| 2 | * QEMU CXL Events |
| 3 | * |
| 4 | * Copyright (c) 2022 Intel |
| 5 | * |
| 6 | * This work is licensed under the terms of the GNU GPL, version 2. See the |
| 7 | * COPYING file in the top-level directory. |
| 8 | */ |
| 9 | |
| 10 | #ifndef CXL_EVENTS_H |
| 11 | #define CXL_EVENTS_H |
| 12 | |
| 13 | #include "qemu/uuid.h" |
| 14 | |
| 15 | /* |
| 16 | * CXL r3.1 section 8.2.9.2.2: Get Event Records (Opcode 0100h); Table 8-52 |
| 17 | * |
| 18 | * Define these as the bit position for the event status register for ease of |
| 19 | * setting the status. |
| 20 | */ |
| 21 | typedef enum CXLEventLogType { |
| 22 | CXL_EVENT_TYPE_INFO = 0, |
| 23 | CXL_EVENT_TYPE_WARN = 1, |
| 24 | CXL_EVENT_TYPE_FAIL = 2, |
| 25 | CXL_EVENT_TYPE_FATAL = 3, |
| 26 | CXL_EVENT_TYPE_DYNAMIC_CAP = 4, |
| 27 | CXL_EVENT_TYPE_MAX |
| 28 | } CXLEventLogType; |
| 29 | |
| 30 | /* |
| 31 | * Common Event Record Format |
| 32 | * CXL r3.2 section 8.2.10.2.1: Event Records; Table 8-55 |
| 33 | */ |
| 34 | #define CXL_EVENT_REC_FLAGS_PERMANENT_COND BIT(2) |
| 35 | #define CXL_EVENT_REC_FLAGS_MAINT_NEEDED BIT(3) |
| 36 | #define CXL_EVENT_REC_FLAGS_PERF_DEGRADED BIT(4) |
| 37 | #define CXL_EVENT_REC_FLAGS_HW_REPLACEMENT_NEEDED BIT(5) |
| 38 | #define CXL_EVENT_REC_FLAGS_MAINT_OP_SUBCLASS_VALID BIT(6) |
| 39 | #define CXL_EVENT_REC_FLAGS_LD_ID_VALID BIT(7) |
| 40 | #define CXL_EVENT_REC_FLAGS_HEAD_ID_VALID BIT(8) |
| 41 | typedef struct CXLEventRecordHdr { |
| 42 | QemuUUID id; |
| 43 | uint8_t length; |
| 44 | uint8_t flags[3]; |
| 45 | uint16_t handle; |
| 46 | uint16_t related_handle; |
| 47 | uint64_t timestamp; |
| 48 | uint8_t maint_op_class; |
| 49 | uint8_t maint_op_subclass; |
| 50 | uint16_t ld_id; |
| 51 | uint8_t head_id; |
| 52 | uint8_t reserved[0xb]; |
| 53 | } QEMU_PACKED CXLEventRecordHdr; |
| 54 | |
| 55 | #define CXL_EVENT_RECORD_DATA_LENGTH 0x50 |
| 56 | typedef struct CXLEventRecordRaw { |
| 57 | CXLEventRecordHdr hdr; |
| 58 | uint8_t data[CXL_EVENT_RECORD_DATA_LENGTH]; |
| 59 | } QEMU_PACKED CXLEventRecordRaw; |
| 60 | #define CXL_EVENT_RECORD_SIZE (sizeof(CXLEventRecordRaw)) |
| 61 | |
| 62 | /* |
| 63 | * Get Event Records output payload |
| 64 | * CXL r3.1 section 8.2.9.2.2; Table 8-53 |
| 65 | */ |
| 66 | #define CXL_GET_EVENT_FLAG_OVERFLOW BIT(0) |
| 67 | #define CXL_GET_EVENT_FLAG_MORE_RECORDS BIT(1) |
| 68 | typedef struct CXLGetEventPayload { |
| 69 | uint8_t flags; |
| 70 | uint8_t reserved1; |
| 71 | uint16_t overflow_err_count; |
| 72 | uint64_t first_overflow_timestamp; |
| 73 | uint64_t last_overflow_timestamp; |
| 74 | uint16_t record_count; |
| 75 | uint8_t reserved2[0xa]; |
| 76 | CXLEventRecordRaw records[]; |
| 77 | } QEMU_PACKED CXLGetEventPayload; |
| 78 | #define CXL_EVENT_PAYLOAD_HDR_SIZE (sizeof(CXLGetEventPayload)) |
| 79 | |
| 80 | /* |
| 81 | * Clear Event Records input payload |
| 82 | * CXL r3.1 section 8.2.9.2.3; Table 8-54 |
| 83 | */ |
| 84 | typedef struct CXLClearEventPayload { |
| 85 | uint8_t event_log; /* CXLEventLogType */ |
| 86 | uint8_t clear_flags; |
| 87 | uint8_t nr_recs; |
| 88 | uint8_t reserved[3]; |
| 89 | uint16_t handle[]; |
| 90 | } CXLClearEventPayload; |
| 91 | |
| 92 | /* |
| 93 | * Event Interrupt Policy |
| 94 | * |
| 95 | * CXL r3.1 section 8.2.9.2.4; Table 8-55 |
| 96 | */ |
| 97 | typedef enum CXLEventIntMode { |
| 98 | CXL_INT_NONE = 0x00, |
| 99 | CXL_INT_MSI_MSIX = 0x01, |
| 100 | CXL_INT_FW = 0x02, |
| 101 | CXL_INT_RES = 0x03, |
| 102 | } CXLEventIntMode; |
| 103 | #define CXL_EVENT_INT_MODE_MASK 0x3 |
| 104 | #define CXL_EVENT_INT_SETTING(vector) \ |
| 105 | ((((uint8_t)vector & 0xf) << 4) | CXL_INT_MSI_MSIX) |
| 106 | typedef struct CXLEventInterruptPolicy { |
| 107 | uint8_t info_settings; |
| 108 | uint8_t warn_settings; |
| 109 | uint8_t failure_settings; |
| 110 | uint8_t fatal_settings; |
| 111 | uint8_t dyn_cap_settings; |
| 112 | } QEMU_PACKED CXLEventInterruptPolicy; |
| 113 | /* DCD is optional but other fields are not */ |
| 114 | #define CXL_EVENT_INT_SETTING_MIN_LEN 4 |
| 115 | |
| 116 | /* |
| 117 | * General Media Event Record |
| 118 | * CXL r3.2 Section 8.2.10.2.1.1; Table 8-57 |
| 119 | */ |
| 120 | #define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10 |
| 121 | #define CXL_EVENT_GEN_MED_RES_SIZE 0x29 |
| 122 | typedef struct CXLEventGenMedia { |
| 123 | CXLEventRecordHdr hdr; |
| 124 | uint64_t phys_addr; |
| 125 | uint8_t descriptor; |
| 126 | uint8_t type; |
| 127 | uint8_t transaction_type; |
| 128 | uint16_t validity_flags; |
| 129 | uint8_t channel; |
| 130 | uint8_t rank; |
| 131 | uint8_t device[3]; |
| 132 | uint8_t component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; |
| 133 | uint8_t cme_ev_flags; |
| 134 | uint8_t cme_count[3]; |
| 135 | uint8_t sub_type; |
| 136 | uint8_t reserved[CXL_EVENT_GEN_MED_RES_SIZE]; |
| 137 | } QEMU_PACKED CXLEventGenMedia; |
| 138 | |
| 139 | /* |
| 140 | * DRAM Event Record |
| 141 | * CXL r3.2 Section 8.2.10.2.1.2: Table 8-58 |
| 142 | * All fields little endian. |
| 143 | */ |
| 144 | typedef struct CXLEventDram { |
| 145 | CXLEventRecordHdr hdr; |
| 146 | uint64_t phys_addr; |
| 147 | uint8_t descriptor; |
| 148 | uint8_t type; |
| 149 | uint8_t transaction_type; |
| 150 | uint16_t validity_flags; |
| 151 | uint8_t channel; |
| 152 | uint8_t rank; |
| 153 | uint8_t nibble_mask[3]; |
| 154 | uint8_t bank_group; |
| 155 | uint8_t bank; |
| 156 | uint8_t row[3]; |
| 157 | uint16_t column; |
| 158 | uint64_t correction_mask[4]; |
| 159 | uint8_t component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; |
| 160 | uint8_t sub_channel; |
| 161 | uint8_t cme_ev_flags; |
| 162 | uint8_t cvme_count[3]; |
| 163 | uint8_t sub_type; |
| 164 | uint8_t reserved; |
| 165 | } QEMU_PACKED CXLEventDram; |
| 166 | |
| 167 | /* |
| 168 | * Memory Module Event Record |
| 169 | * CXL r3.2 Section 8.2.10.2.1.3: Table 8-59 |
| 170 | * All fields little endian. |
| 171 | */ |
| 172 | typedef struct CXLEventMemoryModule { |
| 173 | CXLEventRecordHdr hdr; |
| 174 | uint8_t type; |
| 175 | uint8_t health_status; |
| 176 | uint8_t media_status; |
| 177 | uint8_t additional_status; |
| 178 | uint8_t life_used; |
| 179 | int16_t temperature; |
| 180 | uint32_t dirty_shutdown_count; |
| 181 | uint32_t corrected_volatile_error_count; |
| 182 | uint32_t corrected_persistent_error_count; |
| 183 | uint16_t validity_flags; |
| 184 | uint8_t component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; |
| 185 | uint8_t sub_type; |
| 186 | uint8_t reserved[0x2a]; |
| 187 | } QEMU_PACKED CXLEventMemoryModule; |
| 188 | |
| 189 | /* |
| 190 | * CXL r3.1 section Table 8-50: Dynamic Capacity Event Record |
| 191 | * All fields little endian. |
| 192 | */ |
| 193 | typedef struct CXLEventDynamicCapacity { |
| 194 | CXLEventRecordHdr hdr; |
| 195 | uint8_t type; |
| 196 | uint8_t validity_flags; |
| 197 | uint16_t host_id; |
| 198 | uint8_t updated_region_id; |
| 199 | uint8_t flags; |
| 200 | uint8_t reserved2[2]; |
| 201 | uint8_t dynamic_capacity_extent[0x28]; /* defined in cxl_device.h */ |
| 202 | uint8_t reserved[0x18]; |
| 203 | uint32_t extents_avail; |
| 204 | uint32_t tags_avail; |
| 205 | } QEMU_PACKED CXLEventDynamicCapacity; |
| 206 | |
| 207 | /* CXL r3.1 Table 8-50: Dynamic Capacity Event Record */ |
| 208 | static const QemuUUID dynamic_capacity_uuid = { |
| 209 | .data = UUID(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f, |
| 210 | 0x95, 0x26, 0x8e, 0x10, 0x1a, 0x2a), |
| 211 | }; |
| 212 | |
| 213 | typedef enum CXLDCEventType { |
| 214 | DC_EVENT_ADD_CAPACITY = 0x0, |
| 215 | DC_EVENT_RELEASE_CAPACITY = 0x1, |
| 216 | DC_EVENT_FORCED_RELEASE_CAPACITY = 0x2, |
| 217 | DC_EVENT_REGION_CONFIG_UPDATED = 0x3, |
| 218 | DC_EVENT_ADD_CAPACITY_RSP = 0x4, |
| 219 | DC_EVENT_CAPACITY_RELEASED = 0x5, |
| 220 | } CXLDCEventType; |
| 221 | |
| 222 | /* |
| 223 | * CXL r3.2 section Table 8-60: Memory Sparing Event Record |
| 224 | * All fields little endian. |
| 225 | */ |
| 226 | |
| 227 | #define CXL_MSER_FLAGS_QUERY_RESOURCES BIT(0) |
| 228 | #define CXL_MSER_FLAGS_HARD_SPARING BIT(1) |
| 229 | #define CXL_MSER_FLAGS_DEV_INITIATED BIT(2) |
| 230 | |
| 231 | #define CXL_MSER_VALID_CHANNEL BIT(0) |
| 232 | #define CXL_MSER_VALID_RANK BIT(1) |
| 233 | #define CXL_MSER_VALID_NIB_MASK BIT(2) |
| 234 | #define CXL_MSER_VALID_BANK_GROUP BIT(3) |
| 235 | #define CXL_MSER_VALID_BANK BIT(4) |
| 236 | #define CXL_MSER_VALID_ROW BIT(5) |
| 237 | #define CXL_MSER_VALID_COLUMN BIT(6) |
| 238 | #define CXL_MSER_VALID_COMP_ID BIT(7) |
| 239 | #define CXL_MSER_VALID_COMP_ID_FORMAT BIT(8) |
| 240 | #define CXL_MSER_VALID_SUB_CHANNEL BIT(9) |
| 241 | |
| 242 | typedef struct CXLEventSparing { |
| 243 | CXLEventRecordHdr hdr; |
| 244 | uint8_t maint_op_class; |
| 245 | uint8_t maint_op_subclass; |
| 246 | uint8_t flags; |
| 247 | uint8_t result; |
| 248 | uint16_t validity_flags; |
| 249 | uint8_t reserved1[6]; |
| 250 | uint16_t res_avail; |
| 251 | uint8_t channel; |
| 252 | uint8_t rank; |
| 253 | uint8_t nibble_mask[3]; |
| 254 | uint8_t bank_group; |
| 255 | uint8_t bank; |
| 256 | uint8_t row[3]; |
| 257 | uint16_t column; |
| 258 | uint8_t component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; |
| 259 | uint8_t sub_channel; |
| 260 | uint8_t reserved2[0x25]; |
| 261 | } QEMU_PACKED CXLEventSparing; |
| 262 | |
| 263 | /* CXL r3.2 Table 8-60: Memory Sparing Event Record */ |
| 264 | static const QemuUUID sparing_uuid = { |
| 265 | .data = UUID(0xe71f3a40, 0x2d29, 0x4092, 0x8a, 0x39, |
| 266 | 0x4d, 0x1c, 0x96, 0x6c, 0x7c, 0x65), |
| 267 | }; |
| 268 | |
| 269 | #endif /* CXL_EVENTS_H */ |