xref: /openbmc/qemu/hw/cxl/cxl-device-utils.c (revision bdd3159ad724e4e0aad571b4352b288b8f947ddd)
16364adacSBen Widawsky /*
26364adacSBen Widawsky  * CXL Utility library for devices
36364adacSBen Widawsky  *
46364adacSBen Widawsky  * Copyright(C) 2020 Intel Corporation.
56364adacSBen Widawsky  *
66364adacSBen Widawsky  * This work is licensed under the terms of the GNU GPL, version 2. See the
76364adacSBen Widawsky  * COPYING file in the top-level directory.
86364adacSBen Widawsky  */
96364adacSBen Widawsky 
106364adacSBen Widawsky #include "qemu/osdep.h"
116364adacSBen Widawsky #include "qemu/log.h"
126364adacSBen Widawsky #include "hw/cxl/cxl.h"
136364adacSBen Widawsky 
146364adacSBen Widawsky /*
156364adacSBen Widawsky  * Device registers have no restrictions per the spec, and so fall back to the
166364adacSBen Widawsky  * default memory mapped register rules in CXL r3.1 Section 8.2:
176364adacSBen Widawsky  *   Software shall use CXL.io Memory Read and Write to access memory mapped
186364adacSBen Widawsky  *   register defined in this section. Unless otherwise specified, software
196364adacSBen Widawsky  *   shall restrict the accesses width based on the following:
206364adacSBen Widawsky  *   • A 32 bit register shall be accessed as a 1 Byte, 2 Bytes or 4 Bytes
216364adacSBen Widawsky  *     quantity.
226364adacSBen Widawsky  *   • A 64 bit register shall be accessed as a 1 Byte, 2 Bytes, 4 Bytes or 8
236364adacSBen Widawsky  *     Bytes
246364adacSBen Widawsky  *   • The address shall be a multiple of the access width, e.g. when
256364adacSBen Widawsky  *     accessing a register as a 4 Byte quantity, the address shall be
266364adacSBen Widawsky  *     multiple of 4.
276364adacSBen Widawsky  *   • The accesses shall map to contiguous bytes.If these rules are not
286364adacSBen Widawsky  *     followed, the behavior is undefined
296364adacSBen Widawsky  */
306364adacSBen Widawsky 
caps_reg_read(void * opaque,hwaddr offset,unsigned size)316364adacSBen Widawsky static uint64_t caps_reg_read(void *opaque, hwaddr offset, unsigned size)
326364adacSBen Widawsky {
336364adacSBen Widawsky     CXLDeviceState *cxl_dstate = opaque;
346364adacSBen Widawsky 
35629df5ccSJonathan Cameron     switch (size) {
36629df5ccSJonathan Cameron     case 4:
37629df5ccSJonathan Cameron         return cxl_dstate->caps_reg_state32[offset / size];
38629df5ccSJonathan Cameron     case 8:
39629df5ccSJonathan Cameron         return cxl_dstate->caps_reg_state64[offset / size];
40629df5ccSJonathan Cameron     default:
41629df5ccSJonathan Cameron         g_assert_not_reached();
426364adacSBen Widawsky     }
436364adacSBen Widawsky }
446364adacSBen Widawsky 
dev_reg_read(void * opaque,hwaddr offset,unsigned size)456364adacSBen Widawsky static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size)
466364adacSBen Widawsky {
47d7b84ddcSIra Weiny     CXLDeviceState *cxl_dstate = opaque;
48d7b84ddcSIra Weiny 
49d7b84ddcSIra Weiny     switch (size) {
50d7b84ddcSIra Weiny     case 1:
51d7b84ddcSIra Weiny         return cxl_dstate->dev_reg_state[offset];
52d7b84ddcSIra Weiny     case 2:
53d7b84ddcSIra Weiny         return cxl_dstate->dev_reg_state16[offset / size];
54d7b84ddcSIra Weiny     case 4:
55d7b84ddcSIra Weiny         return cxl_dstate->dev_reg_state32[offset / size];
56d7b84ddcSIra Weiny     case 8:
57d7b84ddcSIra Weiny         return cxl_dstate->dev_reg_state64[offset / size];
58d7b84ddcSIra Weiny     default:
59d7b84ddcSIra Weiny         g_assert_not_reached();
60d7b84ddcSIra Weiny     }
616364adacSBen Widawsky }
626364adacSBen Widawsky 
mailbox_reg_read(void * opaque,hwaddr offset,unsigned size)63464e14acSBen Widawsky static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size)
64464e14acSBen Widawsky {
65cac36a8fSJonathan Cameron     CXLDeviceState *cxl_dstate;
66cac36a8fSJonathan Cameron     CXLCCI *cci = opaque;
67cac36a8fSJonathan Cameron 
68cac36a8fSJonathan Cameron     if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) {
69cac36a8fSJonathan Cameron         cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate;
704a583303SJonathan Cameron     } else if (object_dynamic_cast(OBJECT(cci->intf),
714a583303SJonathan Cameron                                    TYPE_CXL_SWITCH_MAILBOX_CCI)) {
724a583303SJonathan Cameron         cxl_dstate = &CXL_SWITCH_MAILBOX_CCI(cci->intf)->cxl_dstate;
73cac36a8fSJonathan Cameron     } else {
74cac36a8fSJonathan Cameron         return 0;
75cac36a8fSJonathan Cameron     }
76464e14acSBen Widawsky 
77464e14acSBen Widawsky     switch (size) {
78464e14acSBen Widawsky     case 1:
79464e14acSBen Widawsky         return cxl_dstate->mbox_reg_state[offset];
80464e14acSBen Widawsky     case 2:
81464e14acSBen Widawsky         return cxl_dstate->mbox_reg_state16[offset / size];
82464e14acSBen Widawsky     case 4:
83464e14acSBen Widawsky         return cxl_dstate->mbox_reg_state32[offset / size];
84464e14acSBen Widawsky     case 8:
85221d2cfbSDavidlohr Bueso         if (offset == A_CXL_DEV_BG_CMD_STS) {
86221d2cfbSDavidlohr Bueso             uint64_t bg_status_reg;
87221d2cfbSDavidlohr Bueso             bg_status_reg = FIELD_DP64(0, CXL_DEV_BG_CMD_STS, OP,
88221d2cfbSDavidlohr Bueso                                        cci->bg.opcode);
89221d2cfbSDavidlohr Bueso             bg_status_reg = FIELD_DP64(bg_status_reg, CXL_DEV_BG_CMD_STS,
90221d2cfbSDavidlohr Bueso                                        PERCENTAGE_COMP, cci->bg.complete_pct);
91221d2cfbSDavidlohr Bueso             bg_status_reg = FIELD_DP64(bg_status_reg, CXL_DEV_BG_CMD_STS,
92221d2cfbSDavidlohr Bueso                                        RET_CODE, cci->bg.ret_code);
93221d2cfbSDavidlohr Bueso             /* endian? */
94221d2cfbSDavidlohr Bueso             cxl_dstate->mbox_reg_state64[offset / size] = bg_status_reg;
95221d2cfbSDavidlohr Bueso         }
96221d2cfbSDavidlohr Bueso         if (offset == A_CXL_DEV_MAILBOX_STS) {
97221d2cfbSDavidlohr Bueso             uint64_t status_reg = cxl_dstate->mbox_reg_state64[offset / size];
98221d2cfbSDavidlohr Bueso             if (cci->bg.complete_pct) {
99221d2cfbSDavidlohr Bueso                 status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, BG_OP,
100221d2cfbSDavidlohr Bueso                                         0);
101221d2cfbSDavidlohr Bueso                 cxl_dstate->mbox_reg_state64[offset / size] = status_reg;
102221d2cfbSDavidlohr Bueso             }
103221d2cfbSDavidlohr Bueso         }
104464e14acSBen Widawsky         return cxl_dstate->mbox_reg_state64[offset / size];
105464e14acSBen Widawsky     default:
106464e14acSBen Widawsky         g_assert_not_reached();
107464e14acSBen Widawsky     }
108464e14acSBen Widawsky }
109464e14acSBen Widawsky 
mailbox_mem_writel(uint32_t * reg_state,hwaddr offset,uint64_t value)110464e14acSBen Widawsky static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset,
111464e14acSBen Widawsky                                uint64_t value)
112464e14acSBen Widawsky {
113464e14acSBen Widawsky     switch (offset) {
114464e14acSBen Widawsky     case A_CXL_DEV_MAILBOX_CTRL:
115464e14acSBen Widawsky         /* fallthrough */
116464e14acSBen Widawsky     case A_CXL_DEV_MAILBOX_CAP:
117464e14acSBen Widawsky         /* RO register */
118464e14acSBen Widawsky         break;
119464e14acSBen Widawsky     default:
120464e14acSBen Widawsky         qemu_log_mask(LOG_UNIMP,
121464e14acSBen Widawsky                       "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n",
122464e14acSBen Widawsky                       __func__, offset);
123464e14acSBen Widawsky         return;
124464e14acSBen Widawsky     }
125464e14acSBen Widawsky 
126464e14acSBen Widawsky     reg_state[offset / sizeof(*reg_state)] = value;
127464e14acSBen Widawsky }
128464e14acSBen Widawsky 
mailbox_mem_writeq(uint64_t * reg_state,hwaddr offset,uint64_t value)129464e14acSBen Widawsky static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset,
130464e14acSBen Widawsky                                uint64_t value)
131464e14acSBen Widawsky {
132464e14acSBen Widawsky     switch (offset) {
133464e14acSBen Widawsky     case A_CXL_DEV_MAILBOX_CMD:
134464e14acSBen Widawsky         break;
135464e14acSBen Widawsky     case A_CXL_DEV_BG_CMD_STS:
136221d2cfbSDavidlohr Bueso         break;
137464e14acSBen Widawsky     case A_CXL_DEV_MAILBOX_STS:
138464e14acSBen Widawsky         /* Read only register, will get updated by the state machine */
139464e14acSBen Widawsky         return;
140464e14acSBen Widawsky     default:
141464e14acSBen Widawsky         qemu_log_mask(LOG_UNIMP,
142464e14acSBen Widawsky                       "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n",
143464e14acSBen Widawsky                       __func__, offset);
144464e14acSBen Widawsky         return;
145464e14acSBen Widawsky     }
146464e14acSBen Widawsky 
147464e14acSBen Widawsky 
148464e14acSBen Widawsky     reg_state[offset / sizeof(*reg_state)] = value;
149464e14acSBen Widawsky }
150464e14acSBen Widawsky 
mailbox_reg_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)151464e14acSBen Widawsky static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value,
152464e14acSBen Widawsky                               unsigned size)
153464e14acSBen Widawsky {
154cac36a8fSJonathan Cameron     CXLDeviceState *cxl_dstate;
155cac36a8fSJonathan Cameron     CXLCCI *cci = opaque;
156cac36a8fSJonathan Cameron 
157cac36a8fSJonathan Cameron     if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) {
158cac36a8fSJonathan Cameron         cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate;
1594a583303SJonathan Cameron     } else if (object_dynamic_cast(OBJECT(cci->intf),
1604a583303SJonathan Cameron                                    TYPE_CXL_SWITCH_MAILBOX_CCI)) {
1614a583303SJonathan Cameron         cxl_dstate = &CXL_SWITCH_MAILBOX_CCI(cci->intf)->cxl_dstate;
162cac36a8fSJonathan Cameron     } else {
163cac36a8fSJonathan Cameron         return;
164cac36a8fSJonathan Cameron     }
165464e14acSBen Widawsky 
166464e14acSBen Widawsky     if (offset >= A_CXL_DEV_CMD_PAYLOAD) {
167464e14acSBen Widawsky         memcpy(cxl_dstate->mbox_reg_state + offset, &value, size);
168464e14acSBen Widawsky         return;
169464e14acSBen Widawsky     }
170464e14acSBen Widawsky 
171464e14acSBen Widawsky     switch (size) {
172464e14acSBen Widawsky     case 4:
173464e14acSBen Widawsky         mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value);
174464e14acSBen Widawsky         break;
175464e14acSBen Widawsky     case 8:
176464e14acSBen Widawsky         mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value);
177464e14acSBen Widawsky         break;
178464e14acSBen Widawsky     default:
179464e14acSBen Widawsky         g_assert_not_reached();
180464e14acSBen Widawsky     }
181464e14acSBen Widawsky 
182464e14acSBen Widawsky     if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL,
183464e14acSBen Widawsky                          DOORBELL)) {
184c9460561SJonathan Cameron         uint64_t command_reg =
185c9460561SJonathan Cameron             cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD];
186c9460561SJonathan Cameron         uint8_t cmd_set = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD,
187c9460561SJonathan Cameron                                      COMMAND_SET);
188c9460561SJonathan Cameron         uint8_t cmd = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND);
189c9460561SJonathan Cameron         size_t len_in = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH);
190c9460561SJonathan Cameron         uint8_t *pl = cxl_dstate->mbox_reg_state + A_CXL_DEV_CMD_PAYLOAD;
191c9460561SJonathan Cameron         /*
192c9460561SJonathan Cameron          * Copy taken to avoid need for individual command handlers to care
193c9460561SJonathan Cameron          * about aliasing.
194c9460561SJonathan Cameron          */
195c9460561SJonathan Cameron         g_autofree uint8_t *pl_in_copy = NULL;
196c9460561SJonathan Cameron         size_t len_out = 0;
197c9460561SJonathan Cameron         uint64_t status_reg;
198c9460561SJonathan Cameron         bool bg_started = false;
199c9460561SJonathan Cameron         int rc;
200c9460561SJonathan Cameron 
201c9460561SJonathan Cameron         pl_in_copy = g_memdup2(pl, len_in);
202c9460561SJonathan Cameron         if (len_in == 0 || pl_in_copy) {
203c9460561SJonathan Cameron             /* Avoid stale data  - including from earlier cmds */
204c9460561SJonathan Cameron             memset(pl, 0, CXL_MAILBOX_MAX_PAYLOAD_SIZE);
205c9460561SJonathan Cameron             rc = cxl_process_cci_message(cci, cmd_set, cmd, len_in, pl_in_copy,
206c9460561SJonathan Cameron                                          &len_out, pl, &bg_started);
207c9460561SJonathan Cameron         } else {
208c9460561SJonathan Cameron             rc = CXL_MBOX_INTERNAL_ERROR;
209c9460561SJonathan Cameron         }
210c9460561SJonathan Cameron 
211c9460561SJonathan Cameron         /* Set bg and the return code */
212c9460561SJonathan Cameron         status_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_STS, BG_OP,
213c9460561SJonathan Cameron                                 bg_started ? 1 : 0);
214c9460561SJonathan Cameron         status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, ERRNO, rc);
215c9460561SJonathan Cameron         /* Set the return length */
216c9460561SJonathan Cameron         command_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_CMD, COMMAND_SET, cmd_set);
217c9460561SJonathan Cameron         command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD,
218c9460561SJonathan Cameron                                  COMMAND, cmd);
219c9460561SJonathan Cameron         command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD,
220c9460561SJonathan Cameron                                  LENGTH, len_out);
221c9460561SJonathan Cameron 
222c9460561SJonathan Cameron         cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD] = command_reg;
223c9460561SJonathan Cameron         cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_STS] = status_reg;
224c9460561SJonathan Cameron         /* Tell the host we're done */
225c9460561SJonathan Cameron         ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL,
226c9460561SJonathan Cameron                          DOORBELL, 0);
227464e14acSBen Widawsky     }
228464e14acSBen Widawsky }
229464e14acSBen Widawsky 
mdev_reg_read(void * opaque,hwaddr offset,unsigned size)230ce3b4e5cSBen Widawsky static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size)
231ce3b4e5cSBen Widawsky {
232*bdd3159aSHyeonggon Yoo     CXLDeviceState *cxl_dstate = opaque;
233ce3b4e5cSBen Widawsky 
234*bdd3159aSHyeonggon Yoo     return cxl_dstate->memdev_status;
235ce3b4e5cSBen Widawsky }
236ce3b4e5cSBen Widawsky 
ro_reg_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)23729d1fbc6SJonathan Cameron static void ro_reg_write(void *opaque, hwaddr offset, uint64_t value,
23829d1fbc6SJonathan Cameron                            unsigned size)
23929d1fbc6SJonathan Cameron {
24029d1fbc6SJonathan Cameron     /* Many register sets are read only */
24129d1fbc6SJonathan Cameron }
24229d1fbc6SJonathan Cameron 
243ce3b4e5cSBen Widawsky static const MemoryRegionOps mdev_ops = {
244ce3b4e5cSBen Widawsky     .read = mdev_reg_read,
24529d1fbc6SJonathan Cameron     .write = ro_reg_write,
246ce3b4e5cSBen Widawsky     .endianness = DEVICE_LITTLE_ENDIAN,
247ce3b4e5cSBen Widawsky     .valid = {
248ce3b4e5cSBen Widawsky         .min_access_size = 1,
249ce3b4e5cSBen Widawsky         .max_access_size = 8,
250ce3b4e5cSBen Widawsky         .unaligned = false,
251ce3b4e5cSBen Widawsky     },
252ce3b4e5cSBen Widawsky     .impl = {
253ce3b4e5cSBen Widawsky         .min_access_size = 8,
254ce3b4e5cSBen Widawsky         .max_access_size = 8,
255ce3b4e5cSBen Widawsky     },
256ce3b4e5cSBen Widawsky };
257ce3b4e5cSBen Widawsky 
258464e14acSBen Widawsky static const MemoryRegionOps mailbox_ops = {
259464e14acSBen Widawsky     .read = mailbox_reg_read,
260464e14acSBen Widawsky     .write = mailbox_reg_write,
261464e14acSBen Widawsky     .endianness = DEVICE_LITTLE_ENDIAN,
262464e14acSBen Widawsky     .valid = {
263464e14acSBen Widawsky         .min_access_size = 1,
264464e14acSBen Widawsky         .max_access_size = 8,
265464e14acSBen Widawsky         .unaligned = false,
266464e14acSBen Widawsky     },
267464e14acSBen Widawsky     .impl = {
268464e14acSBen Widawsky         .min_access_size = 1,
269464e14acSBen Widawsky         .max_access_size = 8,
270464e14acSBen Widawsky     },
271464e14acSBen Widawsky };
272464e14acSBen Widawsky 
2736364adacSBen Widawsky static const MemoryRegionOps dev_ops = {
2746364adacSBen Widawsky     .read = dev_reg_read,
27529d1fbc6SJonathan Cameron     .write = ro_reg_write,
2766364adacSBen Widawsky     .endianness = DEVICE_LITTLE_ENDIAN,
2776364adacSBen Widawsky     .valid = {
2786364adacSBen Widawsky         .min_access_size = 1,
2796364adacSBen Widawsky         .max_access_size = 8,
2806364adacSBen Widawsky         .unaligned = false,
2816364adacSBen Widawsky     },
2826364adacSBen Widawsky     .impl = {
2836364adacSBen Widawsky         .min_access_size = 1,
2846364adacSBen Widawsky         .max_access_size = 8,
2856364adacSBen Widawsky     },
2866364adacSBen Widawsky };
2876364adacSBen Widawsky 
2886364adacSBen Widawsky static const MemoryRegionOps caps_ops = {
2896364adacSBen Widawsky     .read = caps_reg_read,
29029d1fbc6SJonathan Cameron     .write = ro_reg_write,
2916364adacSBen Widawsky     .endianness = DEVICE_LITTLE_ENDIAN,
2926364adacSBen Widawsky     .valid = {
2936364adacSBen Widawsky         .min_access_size = 1,
2946364adacSBen Widawsky         .max_access_size = 8,
2956364adacSBen Widawsky         .unaligned = false,
2966364adacSBen Widawsky     },
2976364adacSBen Widawsky     .impl = {
2986364adacSBen Widawsky         .min_access_size = 4,
2996364adacSBen Widawsky         .max_access_size = 8,
3006364adacSBen Widawsky     },
3016364adacSBen Widawsky };
3026364adacSBen Widawsky 
cxl_device_register_block_init(Object * obj,CXLDeviceState * cxl_dstate,CXLCCI * cci)303cac36a8fSJonathan Cameron void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate,
304cac36a8fSJonathan Cameron                                     CXLCCI *cci)
3056364adacSBen Widawsky {
3066364adacSBen Widawsky     /* This will be a BAR, so needs to be rounded up to pow2 for PCI spec */
3076364adacSBen Widawsky     memory_region_init(&cxl_dstate->device_registers, obj, "device-registers",
3086364adacSBen Widawsky                        pow2ceil(CXL_MMIO_SIZE));
3096364adacSBen Widawsky 
3106364adacSBen Widawsky     memory_region_init_io(&cxl_dstate->caps, obj, &caps_ops, cxl_dstate,
3116364adacSBen Widawsky                           "cap-array", CXL_CAPS_SIZE);
3126364adacSBen Widawsky     memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate,
3136364adacSBen Widawsky                           "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH);
314cac36a8fSJonathan Cameron     memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cci,
315464e14acSBen Widawsky                           "mailbox", CXL_MAILBOX_REGISTERS_LENGTH);
316ce3b4e5cSBen Widawsky     memory_region_init_io(&cxl_dstate->memory_device, obj, &mdev_ops,
317ce3b4e5cSBen Widawsky                           cxl_dstate, "memory device caps",
318ce3b4e5cSBen Widawsky                           CXL_MEMORY_DEVICE_REGISTERS_LENGTH);
3196364adacSBen Widawsky 
3206364adacSBen Widawsky     memory_region_add_subregion(&cxl_dstate->device_registers, 0,
3216364adacSBen Widawsky                                 &cxl_dstate->caps);
3226364adacSBen Widawsky     memory_region_add_subregion(&cxl_dstate->device_registers,
3236364adacSBen Widawsky                                 CXL_DEVICE_STATUS_REGISTERS_OFFSET,
3246364adacSBen Widawsky                                 &cxl_dstate->device);
325464e14acSBen Widawsky     memory_region_add_subregion(&cxl_dstate->device_registers,
326464e14acSBen Widawsky                                 CXL_MAILBOX_REGISTERS_OFFSET,
327464e14acSBen Widawsky                                 &cxl_dstate->mailbox);
328ce3b4e5cSBen Widawsky     memory_region_add_subregion(&cxl_dstate->device_registers,
329ce3b4e5cSBen Widawsky                                 CXL_MEMORY_DEVICE_REGISTERS_OFFSET,
330ce3b4e5cSBen Widawsky                                 &cxl_dstate->memory_device);
3316364adacSBen Widawsky }
3326364adacSBen Widawsky 
cxl_event_set_status(CXLDeviceState * cxl_dstate,CXLEventLogType log_type,bool available)333d7b84ddcSIra Weiny void cxl_event_set_status(CXLDeviceState *cxl_dstate, CXLEventLogType log_type,
334d7b84ddcSIra Weiny                           bool available)
335d7b84ddcSIra Weiny {
336d7b84ddcSIra Weiny     if (available) {
337d7b84ddcSIra Weiny         cxl_dstate->event_status |= (1 << log_type);
338d7b84ddcSIra Weiny     } else {
339d7b84ddcSIra Weiny         cxl_dstate->event_status &= ~(1 << log_type);
340d7b84ddcSIra Weiny     }
341d7b84ddcSIra Weiny 
342d7b84ddcSIra Weiny     ARRAY_FIELD_DP64(cxl_dstate->dev_reg_state64, CXL_DEV_EVENT_STATUS,
343d7b84ddcSIra Weiny                      EVENT_STATUS, cxl_dstate->event_status);
344d7b84ddcSIra Weiny }
345d7b84ddcSIra Weiny 
device_reg_init_common(CXLDeviceState * cxl_dstate)346d7b84ddcSIra Weiny static void device_reg_init_common(CXLDeviceState *cxl_dstate)
347d7b84ddcSIra Weiny {
348d7b84ddcSIra Weiny     CXLEventLogType log;
349d7b84ddcSIra Weiny 
350d7b84ddcSIra Weiny     for (log = 0; log < CXL_EVENT_TYPE_MAX; log++) {
351d7b84ddcSIra Weiny         cxl_event_set_status(cxl_dstate, log, false);
352d7b84ddcSIra Weiny     }
353d7b84ddcSIra Weiny }
3546364adacSBen Widawsky 
mailbox_reg_init_common(CXLDeviceState * cxl_dstate)355464e14acSBen Widawsky static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate)
356464e14acSBen Widawsky {
35743efb0bfSDavidlohr Bueso     const uint8_t msi_n = 9;
35843efb0bfSDavidlohr Bueso 
35943efb0bfSDavidlohr Bueso     /* 2048 payload size */
360464e14acSBen Widawsky     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
361464e14acSBen Widawsky                      PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT);
362464e14acSBen Widawsky     cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE;
36343efb0bfSDavidlohr Bueso     /* irq support */
36443efb0bfSDavidlohr Bueso     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
36543efb0bfSDavidlohr Bueso                      BG_INT_CAP, 1);
36643efb0bfSDavidlohr Bueso     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
36743efb0bfSDavidlohr Bueso                      MSI_N, msi_n);
36843efb0bfSDavidlohr Bueso     cxl_dstate->mbox_msi_n = msi_n;
369464e14acSBen Widawsky     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
370464e14acSBen Widawsky                      MBOX_READY_TIME, 0); /* Not reported */
371*bdd3159aSHyeonggon Yoo     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
372*bdd3159aSHyeonggon Yoo                      TYPE, 0); /* Inferred from class code */
373*bdd3159aSHyeonggon Yoo }
374*bdd3159aSHyeonggon Yoo 
memdev_reg_init_common(CXLDeviceState * cxl_dstate)375*bdd3159aSHyeonggon Yoo static void memdev_reg_init_common(CXLDeviceState *cxl_dstate)
376*bdd3159aSHyeonggon Yoo {
377*bdd3159aSHyeonggon Yoo     uint64_t memdev_status_reg;
378*bdd3159aSHyeonggon Yoo 
379*bdd3159aSHyeonggon Yoo     memdev_status_reg = FIELD_DP64(0, CXL_MEM_DEV_STS, MEDIA_STATUS, 1);
380ce3b4e5cSBen Widawsky     memdev_status_reg = FIELD_DP64(memdev_status_reg, CXL_MEM_DEV_STS,
381cac36a8fSJonathan Cameron                                    MBOX_READY, 1);
3826364adacSBen Widawsky     cxl_dstate->memdev_status = memdev_status_reg;
383cac36a8fSJonathan Cameron }
384a97bcfeaSJonathan Cameron 
cxl_device_register_init_t3(CXLType3Dev * ct3d)385ce3b4e5cSBen Widawsky void cxl_device_register_init_t3(CXLType3Dev *ct3d)
3866364adacSBen Widawsky {
3876364adacSBen Widawsky     CXLDeviceState *cxl_dstate = &ct3d->cxl_dstate;
388a97bcfeaSJonathan Cameron     uint64_t *cap_h = cxl_dstate->caps_reg_state64;
389a97bcfeaSJonathan Cameron     const int cap_count = 3;
390a97bcfeaSJonathan Cameron 
3916364adacSBen Widawsky     /* CXL Device Capabilities Array Register */
392d7b84ddcSIra Weiny     ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_ID, 0);
3936364adacSBen Widawsky     ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1);
394464e14acSBen Widawsky     ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count);
395d7b84ddcSIra Weiny 
396464e14acSBen Widawsky     cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1,
397464e14acSBen Widawsky                         CXL_DEVICE_STATUS_VERSION);
398d7b84ddcSIra Weiny     device_reg_init_common(cxl_dstate);
399ce3b4e5cSBen Widawsky 
400ce3b4e5cSBen Widawsky     cxl_device_cap_init(cxl_dstate, MAILBOX, 2, CXL_DEV_MAILBOX_VERSION);
401cac36a8fSJonathan Cameron     mailbox_reg_init_common(cxl_dstate);
402cac36a8fSJonathan Cameron 
4036364adacSBen Widawsky     cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000,
404547a652fSIra Weiny         CXL_MEM_DEV_STATUS_VERSION);
4054a583303SJonathan Cameron     memdev_reg_init_common(cxl_dstate);
4064a583303SJonathan Cameron 
4074a583303SJonathan Cameron     cxl_initialize_mailbox_t3(&ct3d->cci, DEVICE(ct3d),
4084a583303SJonathan Cameron                               CXL_MAILBOX_MAX_PAYLOAD_SIZE);
4094a583303SJonathan Cameron }
4104a583303SJonathan Cameron 
cxl_device_register_init_swcci(CSWMBCCIDev * sw)4114a583303SJonathan Cameron void cxl_device_register_init_swcci(CSWMBCCIDev *sw)
4124a583303SJonathan Cameron {
4134a583303SJonathan Cameron     CXLDeviceState *cxl_dstate = &sw->cxl_dstate;
4144a583303SJonathan Cameron     uint64_t *cap_h = cxl_dstate->caps_reg_state64;
4154a583303SJonathan Cameron     const int cap_count = 3;
4164a583303SJonathan Cameron 
4174a583303SJonathan Cameron     /* CXL Device Capabilities Array Register */
4184a583303SJonathan Cameron     ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_ID, 0);
4194a583303SJonathan Cameron     ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1);
4204a583303SJonathan Cameron     ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count);
4214a583303SJonathan Cameron 
4224a583303SJonathan Cameron     cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 2);
4234a583303SJonathan Cameron     device_reg_init_common(cxl_dstate);
4244a583303SJonathan Cameron 
4254a583303SJonathan Cameron     cxl_device_cap_init(cxl_dstate, MAILBOX, 2, 1);
426547a652fSIra Weiny     mailbox_reg_init_common(cxl_dstate);
427547a652fSIra Weiny 
428547a652fSIra Weiny     cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 1);
429547a652fSIra Weiny     memdev_reg_init_common(cxl_dstate);
430547a652fSIra Weiny }
431547a652fSIra Weiny 
cxl_device_get_timestamp(CXLDeviceState * cxl_dstate)432547a652fSIra Weiny uint64_t cxl_device_get_timestamp(CXLDeviceState *cxl_dstate)
433547a652fSIra Weiny {
434547a652fSIra Weiny     uint64_t time, delta;
435547a652fSIra Weiny     uint64_t final_time = 0;
436547a652fSIra Weiny 
437547a652fSIra Weiny     if (cxl_dstate->timestamp.set) {
438547a652fSIra Weiny         /* Find the delta from the last time the host set the time. */
439547a652fSIra Weiny         time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
440         delta = time - cxl_dstate->timestamp.last_set;
441         final_time = cxl_dstate->timestamp.host_set + delta;
442     }
443 
444     return final_time;
445 }
446