1 /* 2 * CXL Utility library for devices 3 * 4 * Copyright(C) 2020 Intel Corporation. 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 #include "qemu/osdep.h" 11 #include "qemu/log.h" 12 #include "hw/cxl/cxl.h" 13 14 /* 15 * Device registers have no restrictions per the spec, and so fall back to the 16 * default memory mapped register rules in 8.2: 17 * Software shall use CXL.io Memory Read and Write to access memory mapped 18 * register defined in this section. Unless otherwise specified, software 19 * shall restrict the accesses width based on the following: 20 * • A 32 bit register shall be accessed as a 1 Byte, 2 Bytes or 4 Bytes 21 * quantity. 22 * • A 64 bit register shall be accessed as a 1 Byte, 2 Bytes, 4 Bytes or 8 23 * Bytes 24 * • The address shall be a multiple of the access width, e.g. when 25 * accessing a register as a 4 Byte quantity, the address shall be 26 * multiple of 4. 27 * • The accesses shall map to contiguous bytes.If these rules are not 28 * followed, the behavior is undefined 29 */ 30 31 static uint64_t caps_reg_read(void *opaque, hwaddr offset, unsigned size) 32 { 33 CXLDeviceState *cxl_dstate = opaque; 34 35 if (size == 4) { 36 return cxl_dstate->caps_reg_state32[offset / sizeof(*cxl_dstate->caps_reg_state32)]; 37 } else { 38 return cxl_dstate->caps_reg_state64[offset / sizeof(*cxl_dstate->caps_reg_state64)]; 39 } 40 } 41 42 static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size) 43 { 44 CXLDeviceState *cxl_dstate = opaque; 45 46 switch (size) { 47 case 1: 48 return cxl_dstate->dev_reg_state[offset]; 49 case 2: 50 return cxl_dstate->dev_reg_state16[offset / size]; 51 case 4: 52 return cxl_dstate->dev_reg_state32[offset / size]; 53 case 8: 54 return cxl_dstate->dev_reg_state64[offset / size]; 55 default: 56 g_assert_not_reached(); 57 } 58 } 59 60 static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size) 61 { 62 CXLDeviceState *cxl_dstate = opaque; 63 64 switch (size) { 65 case 1: 66 return cxl_dstate->mbox_reg_state[offset]; 67 case 2: 68 return cxl_dstate->mbox_reg_state16[offset / size]; 69 case 4: 70 return cxl_dstate->mbox_reg_state32[offset / size]; 71 case 8: 72 return cxl_dstate->mbox_reg_state64[offset / size]; 73 default: 74 g_assert_not_reached(); 75 } 76 } 77 78 static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset, 79 uint64_t value) 80 { 81 switch (offset) { 82 case A_CXL_DEV_MAILBOX_CTRL: 83 /* fallthrough */ 84 case A_CXL_DEV_MAILBOX_CAP: 85 /* RO register */ 86 break; 87 default: 88 qemu_log_mask(LOG_UNIMP, 89 "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n", 90 __func__, offset); 91 return; 92 } 93 94 reg_state[offset / sizeof(*reg_state)] = value; 95 } 96 97 static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset, 98 uint64_t value) 99 { 100 switch (offset) { 101 case A_CXL_DEV_MAILBOX_CMD: 102 break; 103 case A_CXL_DEV_BG_CMD_STS: 104 /* BG not supported */ 105 /* fallthrough */ 106 case A_CXL_DEV_MAILBOX_STS: 107 /* Read only register, will get updated by the state machine */ 108 return; 109 default: 110 qemu_log_mask(LOG_UNIMP, 111 "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n", 112 __func__, offset); 113 return; 114 } 115 116 117 reg_state[offset / sizeof(*reg_state)] = value; 118 } 119 120 static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value, 121 unsigned size) 122 { 123 CXLDeviceState *cxl_dstate = opaque; 124 125 if (offset >= A_CXL_DEV_CMD_PAYLOAD) { 126 memcpy(cxl_dstate->mbox_reg_state + offset, &value, size); 127 return; 128 } 129 130 switch (size) { 131 case 4: 132 mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value); 133 break; 134 case 8: 135 mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value); 136 break; 137 default: 138 g_assert_not_reached(); 139 } 140 141 if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, 142 DOORBELL)) { 143 cxl_process_mailbox(cxl_dstate); 144 } 145 } 146 147 static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size) 148 { 149 uint64_t retval = 0; 150 151 retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MEDIA_STATUS, 1); 152 retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MBOX_READY, 1); 153 154 return retval; 155 } 156 157 static void ro_reg_write(void *opaque, hwaddr offset, uint64_t value, 158 unsigned size) 159 { 160 /* Many register sets are read only */ 161 } 162 163 static const MemoryRegionOps mdev_ops = { 164 .read = mdev_reg_read, 165 .write = ro_reg_write, 166 .endianness = DEVICE_LITTLE_ENDIAN, 167 .valid = { 168 .min_access_size = 1, 169 .max_access_size = 8, 170 .unaligned = false, 171 }, 172 .impl = { 173 .min_access_size = 8, 174 .max_access_size = 8, 175 }, 176 }; 177 178 static const MemoryRegionOps mailbox_ops = { 179 .read = mailbox_reg_read, 180 .write = mailbox_reg_write, 181 .endianness = DEVICE_LITTLE_ENDIAN, 182 .valid = { 183 .min_access_size = 1, 184 .max_access_size = 8, 185 .unaligned = false, 186 }, 187 .impl = { 188 .min_access_size = 1, 189 .max_access_size = 8, 190 }, 191 }; 192 193 static const MemoryRegionOps dev_ops = { 194 .read = dev_reg_read, 195 .write = ro_reg_write, 196 .endianness = DEVICE_LITTLE_ENDIAN, 197 .valid = { 198 .min_access_size = 1, 199 .max_access_size = 8, 200 .unaligned = false, 201 }, 202 .impl = { 203 .min_access_size = 1, 204 .max_access_size = 8, 205 }, 206 }; 207 208 static const MemoryRegionOps caps_ops = { 209 .read = caps_reg_read, 210 .write = ro_reg_write, 211 .endianness = DEVICE_LITTLE_ENDIAN, 212 .valid = { 213 .min_access_size = 1, 214 .max_access_size = 8, 215 .unaligned = false, 216 }, 217 .impl = { 218 .min_access_size = 4, 219 .max_access_size = 8, 220 }, 221 }; 222 223 void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) 224 { 225 /* This will be a BAR, so needs to be rounded up to pow2 for PCI spec */ 226 memory_region_init(&cxl_dstate->device_registers, obj, "device-registers", 227 pow2ceil(CXL_MMIO_SIZE)); 228 229 memory_region_init_io(&cxl_dstate->caps, obj, &caps_ops, cxl_dstate, 230 "cap-array", CXL_CAPS_SIZE); 231 memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate, 232 "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH); 233 memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cxl_dstate, 234 "mailbox", CXL_MAILBOX_REGISTERS_LENGTH); 235 memory_region_init_io(&cxl_dstate->memory_device, obj, &mdev_ops, 236 cxl_dstate, "memory device caps", 237 CXL_MEMORY_DEVICE_REGISTERS_LENGTH); 238 239 memory_region_add_subregion(&cxl_dstate->device_registers, 0, 240 &cxl_dstate->caps); 241 memory_region_add_subregion(&cxl_dstate->device_registers, 242 CXL_DEVICE_STATUS_REGISTERS_OFFSET, 243 &cxl_dstate->device); 244 memory_region_add_subregion(&cxl_dstate->device_registers, 245 CXL_MAILBOX_REGISTERS_OFFSET, 246 &cxl_dstate->mailbox); 247 memory_region_add_subregion(&cxl_dstate->device_registers, 248 CXL_MEMORY_DEVICE_REGISTERS_OFFSET, 249 &cxl_dstate->memory_device); 250 } 251 252 void cxl_event_set_status(CXLDeviceState *cxl_dstate, CXLEventLogType log_type, 253 bool available) 254 { 255 if (available) { 256 cxl_dstate->event_status |= (1 << log_type); 257 } else { 258 cxl_dstate->event_status &= ~(1 << log_type); 259 } 260 261 ARRAY_FIELD_DP64(cxl_dstate->dev_reg_state64, CXL_DEV_EVENT_STATUS, 262 EVENT_STATUS, cxl_dstate->event_status); 263 } 264 265 static void device_reg_init_common(CXLDeviceState *cxl_dstate) 266 { 267 CXLEventLogType log; 268 269 for (log = 0; log < CXL_EVENT_TYPE_MAX; log++) { 270 cxl_event_set_status(cxl_dstate, log, false); 271 } 272 } 273 274 static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate) 275 { 276 /* 2048 payload size, with no interrupt or background support */ 277 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, 278 PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT); 279 cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE; 280 } 281 282 static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) { } 283 284 void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) 285 { 286 uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64; 287 const int cap_count = 3; 288 289 /* CXL Device Capabilities Array Register */ 290 ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0); 291 ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); 292 ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); 293 294 cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 2); 295 device_reg_init_common(cxl_dstate); 296 297 cxl_device_cap_init(cxl_dstate, MAILBOX, 2, 1); 298 mailbox_reg_init_common(cxl_dstate); 299 300 cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 1); 301 memdev_reg_init_common(cxl_dstate); 302 303 cxl_initialize_mailbox(cxl_dstate); 304 } 305 306 uint64_t cxl_device_get_timestamp(CXLDeviceState *cxl_dstate) 307 { 308 uint64_t time, delta; 309 uint64_t final_time = 0; 310 311 if (cxl_dstate->timestamp.set) { 312 /* Find the delta from the last time the host set the time. */ 313 time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 314 delta = time - cxl_dstate->timestamp.last_set; 315 final_time = cxl_dstate->timestamp.host_set + delta; 316 } 317 318 return final_time; 319 } 320