1
2
3
4
5
6
7
8
9
10#ifndef CXL_DEVICE_H
11#define CXL_DEVICE_H
12
13#include "hw/cxl/cxl_component.h"
14#include "hw/pci/pci_device.h"
15#include "hw/register.h"
16#include "hw/cxl/cxl_events.h"
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61#define CXL_DEVICE_CAP_HDR1_OFFSET 0x10
62#define CXL_DEVICE_CAP_REG_SIZE 0x10
63#define CXL_DEVICE_CAPS_MAX 4
64#define CXL_CAPS_SIZE \
65 (CXL_DEVICE_CAP_REG_SIZE * (CXL_DEVICE_CAPS_MAX + 1))
66
67#define CXL_DEVICE_STATUS_REGISTERS_OFFSET 0x80
68#define CXL_DEVICE_STATUS_REGISTERS_LENGTH 0x8
69
70#define CXL_MAILBOX_REGISTERS_OFFSET \
71 (CXL_DEVICE_STATUS_REGISTERS_OFFSET + CXL_DEVICE_STATUS_REGISTERS_LENGTH)
72#define CXL_MAILBOX_REGISTERS_SIZE 0x20
73#define CXL_MAILBOX_PAYLOAD_SHIFT 11
74#define CXL_MAILBOX_MAX_PAYLOAD_SIZE (1 << CXL_MAILBOX_PAYLOAD_SHIFT)
75#define CXL_MAILBOX_REGISTERS_LENGTH \
76 (CXL_MAILBOX_REGISTERS_SIZE + CXL_MAILBOX_MAX_PAYLOAD_SIZE)
77
78#define CXL_MEMORY_DEVICE_REGISTERS_OFFSET \
79 (CXL_MAILBOX_REGISTERS_OFFSET + CXL_MAILBOX_REGISTERS_LENGTH)
80#define CXL_MEMORY_DEVICE_REGISTERS_LENGTH 0x8
81
82#define CXL_MMIO_SIZE \
83 (CXL_DEVICE_CAP_REG_SIZE + CXL_DEVICE_STATUS_REGISTERS_LENGTH + \
84 CXL_MAILBOX_REGISTERS_LENGTH + CXL_MEMORY_DEVICE_REGISTERS_LENGTH)
85
86
87typedef enum {
88 CXL_MBOX_SUCCESS = 0x0,
89 CXL_MBOX_BG_STARTED = 0x1,
90 CXL_MBOX_INVALID_INPUT = 0x2,
91 CXL_MBOX_UNSUPPORTED = 0x3,
92 CXL_MBOX_INTERNAL_ERROR = 0x4,
93 CXL_MBOX_RETRY_REQUIRED = 0x5,
94 CXL_MBOX_BUSY = 0x6,
95 CXL_MBOX_MEDIA_DISABLED = 0x7,
96 CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8,
97 CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9,
98 CXL_MBOX_FW_AUTH_FAILED = 0xa,
99 CXL_MBOX_FW_INVALID_SLOT = 0xb,
100 CXL_MBOX_FW_ROLLEDBACK = 0xc,
101 CXL_MBOX_FW_REST_REQD = 0xd,
102 CXL_MBOX_INVALID_HANDLE = 0xe,
103 CXL_MBOX_INVALID_PA = 0xf,
104 CXL_MBOX_INJECT_POISON_LIMIT = 0x10,
105 CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11,
106 CXL_MBOX_ABORTED = 0x12,
107 CXL_MBOX_INVALID_SECURITY_STATE = 0x13,
108 CXL_MBOX_INCORRECT_PASSPHRASE = 0x14,
109 CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15,
110 CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16,
111 CXL_MBOX_MAX = 0x17
112} CXLRetCode;
113
114typedef struct CXLEvent {
115 CXLEventRecordRaw data;
116 QSIMPLEQ_ENTRY(CXLEvent) node;
117} CXLEvent;
118
119typedef struct CXLEventLog {
120 uint16_t next_handle;
121 uint16_t overflow_err_count;
122 uint64_t first_overflow_timestamp;
123 uint64_t last_overflow_timestamp;
124 bool irq_enabled;
125 int irq_vec;
126 QemuMutex lock;
127 QSIMPLEQ_HEAD(, CXLEvent) events;
128} CXLEventLog;
129
130typedef struct cxl_device_state {
131 MemoryRegion device_registers;
132
133
134 struct {
135 MemoryRegion device;
136 union {
137 uint8_t dev_reg_state[CXL_DEVICE_STATUS_REGISTERS_LENGTH];
138 uint16_t dev_reg_state16[CXL_DEVICE_STATUS_REGISTERS_LENGTH / 2];
139 uint32_t dev_reg_state32[CXL_DEVICE_STATUS_REGISTERS_LENGTH / 4];
140 uint64_t dev_reg_state64[CXL_DEVICE_STATUS_REGISTERS_LENGTH / 8];
141 };
142 uint64_t event_status;
143 };
144 MemoryRegion memory_device;
145 struct {
146 MemoryRegion caps;
147 union {
148 uint32_t caps_reg_state32[CXL_CAPS_SIZE / 4];
149 uint64_t caps_reg_state64[CXL_CAPS_SIZE / 8];
150 };
151 };
152
153
154 struct {
155 MemoryRegion mailbox;
156 uint16_t payload_size;
157 union {
158 uint8_t mbox_reg_state[CXL_MAILBOX_REGISTERS_LENGTH];
159 uint16_t mbox_reg_state16[CXL_MAILBOX_REGISTERS_LENGTH / 2];
160 uint32_t mbox_reg_state32[CXL_MAILBOX_REGISTERS_LENGTH / 4];
161 uint64_t mbox_reg_state64[CXL_MAILBOX_REGISTERS_LENGTH / 8];
162 };
163 struct cel_log {
164 uint16_t opcode;
165 uint16_t effect;
166 } cel_log[1 << 16];
167 size_t cel_size;
168 };
169
170 struct {
171 bool set;
172 uint64_t last_set;
173 uint64_t host_set;
174 } timestamp;
175
176
177 uint64_t mem_size;
178 uint64_t pmem_size;
179 uint64_t vmem_size;
180
181 CXLEventLog event_logs[CXL_EVENT_TYPE_MAX];
182} CXLDeviceState;
183
184
185void cxl_device_register_block_init(Object *obj, CXLDeviceState *dev);
186
187
188void cxl_device_register_init_common(CXLDeviceState *dev);
189
190
191
192
193
194
195REG64(CXL_DEV_CAP_ARRAY, 0)
196 FIELD(CXL_DEV_CAP_ARRAY, CAP_ID, 0, 16)
197 FIELD(CXL_DEV_CAP_ARRAY, CAP_VERSION, 16, 8)
198 FIELD(CXL_DEV_CAP_ARRAY, CAP_COUNT, 32, 16)
199
200void cxl_event_set_status(CXLDeviceState *cxl_dstate, CXLEventLogType log_type,
201 bool available);
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218#define CXL_DEVICE_CAPABILITY_HEADER_REGISTER(n, offset) \
219 REG32(CXL_DEV_##n##_CAP_HDR0, offset) \
220 FIELD(CXL_DEV_##n##_CAP_HDR0, CAP_ID, 0, 16) \
221 FIELD(CXL_DEV_##n##_CAP_HDR0, CAP_VERSION, 16, 8) \
222 REG32(CXL_DEV_##n##_CAP_HDR1, offset + 4) \
223 FIELD(CXL_DEV_##n##_CAP_HDR1, CAP_OFFSET, 0, 32) \
224 REG32(CXL_DEV_##n##_CAP_HDR2, offset + 8) \
225 FIELD(CXL_DEV_##n##_CAP_HDR2, CAP_LENGTH, 0, 32)
226
227CXL_DEVICE_CAPABILITY_HEADER_REGISTER(DEVICE_STATUS, CXL_DEVICE_CAP_HDR1_OFFSET)
228CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MAILBOX, CXL_DEVICE_CAP_HDR1_OFFSET + \
229 CXL_DEVICE_CAP_REG_SIZE)
230CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MEMORY_DEVICE,
231 CXL_DEVICE_CAP_HDR1_OFFSET +
232 CXL_DEVICE_CAP_REG_SIZE * 2)
233
234void cxl_initialize_mailbox(CXLDeviceState *cxl_dstate);
235void cxl_process_mailbox(CXLDeviceState *cxl_dstate);
236
237#define cxl_device_cap_init(dstate, reg, cap_id, ver) \
238 do { \
239 uint32_t *cap_hdrs = dstate->caps_reg_state32; \
240 int which = R_CXL_DEV_##reg##_CAP_HDR0; \
241 cap_hdrs[which] = \
242 FIELD_DP32(cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, \
243 CAP_ID, cap_id); \
244 cap_hdrs[which] = FIELD_DP32( \
245 cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, CAP_VERSION, ver); \
246 cap_hdrs[which + 1] = \
247 FIELD_DP32(cap_hdrs[which + 1], CXL_DEV_##reg##_CAP_HDR1, \
248 CAP_OFFSET, CXL_##reg##_REGISTERS_OFFSET); \
249 cap_hdrs[which + 2] = \
250 FIELD_DP32(cap_hdrs[which + 2], CXL_DEV_##reg##_CAP_HDR2, \
251 CAP_LENGTH, CXL_##reg##_REGISTERS_LENGTH); \
252 } while (0)
253
254
255REG64(CXL_DEV_EVENT_STATUS, 0)
256 FIELD(CXL_DEV_EVENT_STATUS, EVENT_STATUS, 0, 32)
257
258
259REG32(CXL_DEV_MAILBOX_CAP, 0)
260 FIELD(CXL_DEV_MAILBOX_CAP, PAYLOAD_SIZE, 0, 5)
261 FIELD(CXL_DEV_MAILBOX_CAP, INT_CAP, 5, 1)
262 FIELD(CXL_DEV_MAILBOX_CAP, BG_INT_CAP, 6, 1)
263 FIELD(CXL_DEV_MAILBOX_CAP, MSI_N, 7, 4)
264
265
266REG32(CXL_DEV_MAILBOX_CTRL, 4)
267 FIELD(CXL_DEV_MAILBOX_CTRL, DOORBELL, 0, 1)
268 FIELD(CXL_DEV_MAILBOX_CTRL, INT_EN, 1, 1)
269 FIELD(CXL_DEV_MAILBOX_CTRL, BG_INT_EN, 2, 1)
270
271
272REG64(CXL_DEV_MAILBOX_CMD, 8)
273 FIELD(CXL_DEV_MAILBOX_CMD, COMMAND, 0, 8)
274 FIELD(CXL_DEV_MAILBOX_CMD, COMMAND_SET, 8, 8)
275 FIELD(CXL_DEV_MAILBOX_CMD, LENGTH, 16, 20)
276
277
278REG64(CXL_DEV_MAILBOX_STS, 0x10)
279 FIELD(CXL_DEV_MAILBOX_STS, BG_OP, 0, 1)
280 FIELD(CXL_DEV_MAILBOX_STS, ERRNO, 32, 16)
281 FIELD(CXL_DEV_MAILBOX_STS, VENDOR_ERRNO, 48, 16)
282
283
284REG64(CXL_DEV_BG_CMD_STS, 0x18)
285 FIELD(CXL_DEV_BG_CMD_STS, OP, 0, 16)
286 FIELD(CXL_DEV_BG_CMD_STS, PERCENTAGE_COMP, 16, 7)
287 FIELD(CXL_DEV_BG_CMD_STS, RET_CODE, 32, 16)
288 FIELD(CXL_DEV_BG_CMD_STS, VENDOR_RET_CODE, 48, 16)
289
290
291REG32(CXL_DEV_CMD_PAYLOAD, 0x20)
292
293REG64(CXL_MEM_DEV_STS, 0)
294 FIELD(CXL_MEM_DEV_STS, FATAL, 0, 1)
295 FIELD(CXL_MEM_DEV_STS, FW_HALT, 1, 1)
296 FIELD(CXL_MEM_DEV_STS, MEDIA_STATUS, 2, 2)
297 FIELD(CXL_MEM_DEV_STS, MBOX_READY, 4, 1)
298 FIELD(CXL_MEM_DEV_STS, RESET_NEEDED, 5, 3)
299
300typedef struct CXLError {
301 QTAILQ_ENTRY(CXLError) node;
302 int type;
303 uint32_t header[32];
304} CXLError;
305
306typedef QTAILQ_HEAD(, CXLError) CXLErrorList;
307
308typedef struct CXLPoison {
309 uint64_t start, length;
310 uint8_t type;
311#define CXL_POISON_TYPE_EXTERNAL 0x1
312#define CXL_POISON_TYPE_INTERNAL 0x2
313#define CXL_POISON_TYPE_INJECTED 0x3
314 QLIST_ENTRY(CXLPoison) node;
315} CXLPoison;
316
317typedef QLIST_HEAD(, CXLPoison) CXLPoisonList;
318#define CXL_POISON_LIST_LIMIT 256
319
320struct CXLType3Dev {
321
322 PCIDevice parent_obj;
323
324
325 HostMemoryBackend *hostmem;
326 HostMemoryBackend *hostvmem;
327 HostMemoryBackend *hostpmem;
328 HostMemoryBackend *lsa;
329 uint64_t sn;
330
331
332 AddressSpace hostvmem_as;
333 AddressSpace hostpmem_as;
334 CXLComponentState cxl_cstate;
335 CXLDeviceState cxl_dstate;
336
337
338 DOECap doe_cdat;
339
340
341 CXLErrorList error_list;
342
343
344 CXLPoisonList poison_list;
345 unsigned int poison_list_cnt;
346 bool poison_list_overflowed;
347 uint64_t poison_list_overflow_ts;
348};
349
350#define TYPE_CXL_TYPE3 "cxl-type3"
351OBJECT_DECLARE_TYPE(CXLType3Dev, CXLType3Class, CXL_TYPE3)
352
353struct CXLType3Class {
354
355 PCIDeviceClass parent_class;
356
357
358 uint64_t (*get_lsa_size)(CXLType3Dev *ct3d);
359
360 uint64_t (*get_lsa)(CXLType3Dev *ct3d, void *buf, uint64_t size,
361 uint64_t offset);
362 void (*set_lsa)(CXLType3Dev *ct3d, const void *buf, uint64_t size,
363 uint64_t offset);
364 bool (*set_cacheline)(CXLType3Dev *ct3d, uint64_t dpa_offset, uint8_t *data);
365};
366
367MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
368 unsigned size, MemTxAttrs attrs);
369MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
370 unsigned size, MemTxAttrs attrs);
371
372uint64_t cxl_device_get_timestamp(CXLDeviceState *cxlds);
373
374void cxl_event_init(CXLDeviceState *cxlds, int start_msg_num);
375bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type,
376 CXLEventRecordRaw *event);
377CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl,
378 uint8_t log_type, int max_recs,
379 uint16_t *len);
380CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds,
381 CXLClearEventPayload *pl);
382
383void cxl_event_irq_assert(CXLType3Dev *ct3d);
384
385void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d);
386
387#endif
388