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 CXL r3.1 Section 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 switch (size) { 36 case 4: 37 return cxl_dstate->caps_reg_state32[offset / size]; 38 case 8: 39 return cxl_dstate->caps_reg_state64[offset / size]; 40 default: 41 g_assert_not_reached(); 42 } 43 } 44 45 static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size) 46 { 47 CXLDeviceState *cxl_dstate = opaque; 48 49 switch (size) { 50 case 1: 51 return cxl_dstate->dev_reg_state[offset]; 52 case 2: 53 return cxl_dstate->dev_reg_state16[offset / size]; 54 case 4: 55 return cxl_dstate->dev_reg_state32[offset / size]; 56 case 8: 57 return cxl_dstate->dev_reg_state64[offset / size]; 58 default: 59 g_assert_not_reached(); 60 } 61 } 62 63 static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size) 64 { 65 CXLDeviceState *cxl_dstate; 66 CXLCCI *cci = opaque; 67 68 if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) { 69 cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate; 70 } else if (object_dynamic_cast(OBJECT(cci->intf), 71 TYPE_CXL_SWITCH_MAILBOX_CCI)) { 72 cxl_dstate = &CXL_SWITCH_MAILBOX_CCI(cci->intf)->cxl_dstate; 73 } else { 74 return 0; 75 } 76 77 switch (size) { 78 case 1: 79 return cxl_dstate->mbox_reg_state[offset]; 80 case 2: 81 return cxl_dstate->mbox_reg_state16[offset / size]; 82 case 4: 83 return cxl_dstate->mbox_reg_state32[offset / size]; 84 case 8: 85 if (offset == A_CXL_DEV_BG_CMD_STS) { 86 uint64_t bg_status_reg; 87 bg_status_reg = FIELD_DP64(0, CXL_DEV_BG_CMD_STS, OP, 88 cci->bg.opcode); 89 bg_status_reg = FIELD_DP64(bg_status_reg, CXL_DEV_BG_CMD_STS, 90 PERCENTAGE_COMP, cci->bg.complete_pct); 91 bg_status_reg = FIELD_DP64(bg_status_reg, CXL_DEV_BG_CMD_STS, 92 RET_CODE, cci->bg.ret_code); 93 /* endian? */ 94 cxl_dstate->mbox_reg_state64[offset / size] = bg_status_reg; 95 } 96 if (offset == A_CXL_DEV_MAILBOX_STS) { 97 uint64_t status_reg = cxl_dstate->mbox_reg_state64[offset / size]; 98 int bgop; 99 100 qemu_mutex_lock(&cci->bg.lock); 101 bgop = !(cci->bg.complete_pct == 100 || cci->bg.aborted); 102 103 status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, BG_OP, 104 bgop); 105 cxl_dstate->mbox_reg_state64[offset / size] = status_reg; 106 qemu_mutex_unlock(&cci->bg.lock); 107 } 108 return cxl_dstate->mbox_reg_state64[offset / size]; 109 default: 110 g_assert_not_reached(); 111 } 112 } 113 114 static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset, 115 uint64_t value) 116 { 117 switch (offset) { 118 case A_CXL_DEV_MAILBOX_CTRL: 119 /* fallthrough */ 120 case A_CXL_DEV_MAILBOX_CAP: 121 /* RO register */ 122 break; 123 default: 124 qemu_log_mask(LOG_UNIMP, 125 "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n", 126 __func__, offset); 127 return; 128 } 129 130 reg_state[offset / sizeof(*reg_state)] = value; 131 } 132 133 static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset, 134 uint64_t value) 135 { 136 switch (offset) { 137 case A_CXL_DEV_MAILBOX_CMD: 138 break; 139 case A_CXL_DEV_BG_CMD_STS: 140 break; 141 case A_CXL_DEV_MAILBOX_STS: 142 /* Read only register, will get updated by the state machine */ 143 return; 144 default: 145 qemu_log_mask(LOG_UNIMP, 146 "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n", 147 __func__, offset); 148 return; 149 } 150 151 152 reg_state[offset / sizeof(*reg_state)] = value; 153 } 154 155 static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value, 156 unsigned size) 157 { 158 CXLDeviceState *cxl_dstate; 159 CXLCCI *cci = opaque; 160 161 if (object_dynamic_cast(OBJECT(cci->intf), TYPE_CXL_TYPE3)) { 162 cxl_dstate = &CXL_TYPE3(cci->intf)->cxl_dstate; 163 } else if (object_dynamic_cast(OBJECT(cci->intf), 164 TYPE_CXL_SWITCH_MAILBOX_CCI)) { 165 cxl_dstate = &CXL_SWITCH_MAILBOX_CCI(cci->intf)->cxl_dstate; 166 } else { 167 return; 168 } 169 170 if (offset >= A_CXL_DEV_CMD_PAYLOAD) { 171 memcpy(cxl_dstate->mbox_reg_state + offset, &value, size); 172 return; 173 } 174 175 switch (size) { 176 case 4: 177 mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value); 178 break; 179 case 8: 180 mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value); 181 break; 182 default: 183 g_assert_not_reached(); 184 } 185 186 if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, 187 DOORBELL)) { 188 uint64_t command_reg = 189 cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD]; 190 uint8_t cmd_set = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, 191 COMMAND_SET); 192 uint8_t cmd = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND); 193 size_t len_in = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH); 194 uint8_t *pl = cxl_dstate->mbox_reg_state + A_CXL_DEV_CMD_PAYLOAD; 195 /* 196 * Copy taken to avoid need for individual command handlers to care 197 * about aliasing. 198 */ 199 g_autofree uint8_t *pl_in_copy = NULL; 200 size_t len_out = 0; 201 uint64_t status_reg; 202 bool bg_started = false; 203 int rc; 204 205 pl_in_copy = g_memdup2(pl, len_in); 206 if (len_in == 0 || pl_in_copy) { 207 /* Avoid stale data - including from earlier cmds */ 208 memset(pl, 0, CXL_MAILBOX_MAX_PAYLOAD_SIZE); 209 rc = cxl_process_cci_message(cci, cmd_set, cmd, len_in, pl_in_copy, 210 &len_out, pl, &bg_started); 211 } else { 212 rc = CXL_MBOX_INTERNAL_ERROR; 213 } 214 215 /* Set bg and the return code */ 216 status_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_STS, BG_OP, 217 bg_started ? 1 : 0); 218 status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, ERRNO, rc); 219 /* Set the return length */ 220 command_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_CMD, COMMAND_SET, cmd_set); 221 command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, 222 COMMAND, cmd); 223 command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, 224 LENGTH, len_out); 225 226 cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD] = command_reg; 227 cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_STS] = status_reg; 228 /* Tell the host we're done */ 229 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL, 230 DOORBELL, 0); 231 } 232 } 233 234 static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size) 235 { 236 CXLDeviceState *cxl_dstate = opaque; 237 238 return cxl_dstate->memdev_status; 239 } 240 241 static void ro_reg_write(void *opaque, hwaddr offset, uint64_t value, 242 unsigned size) 243 { 244 /* Many register sets are read only */ 245 } 246 247 static const MemoryRegionOps mdev_ops = { 248 .read = mdev_reg_read, 249 .write = ro_reg_write, 250 .endianness = DEVICE_LITTLE_ENDIAN, 251 .valid = { 252 .min_access_size = 1, 253 .max_access_size = 8, 254 .unaligned = false, 255 }, 256 .impl = { 257 .min_access_size = 8, 258 .max_access_size = 8, 259 }, 260 }; 261 262 static const MemoryRegionOps mailbox_ops = { 263 .read = mailbox_reg_read, 264 .write = mailbox_reg_write, 265 .endianness = DEVICE_LITTLE_ENDIAN, 266 .valid = { 267 .min_access_size = 1, 268 .max_access_size = 8, 269 .unaligned = false, 270 }, 271 .impl = { 272 .min_access_size = 1, 273 .max_access_size = 8, 274 }, 275 }; 276 277 static const MemoryRegionOps dev_ops = { 278 .read = dev_reg_read, 279 .write = ro_reg_write, 280 .endianness = DEVICE_LITTLE_ENDIAN, 281 .valid = { 282 .min_access_size = 1, 283 .max_access_size = 8, 284 .unaligned = false, 285 }, 286 .impl = { 287 .min_access_size = 1, 288 .max_access_size = 8, 289 }, 290 }; 291 292 static const MemoryRegionOps caps_ops = { 293 .read = caps_reg_read, 294 .write = ro_reg_write, 295 .endianness = DEVICE_LITTLE_ENDIAN, 296 .valid = { 297 .min_access_size = 1, 298 .max_access_size = 8, 299 .unaligned = false, 300 }, 301 .impl = { 302 .min_access_size = 4, 303 .max_access_size = 8, 304 }, 305 }; 306 307 void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate, 308 CXLCCI *cci) 309 { 310 /* This will be a BAR, so needs to be rounded up to pow2 for PCI spec */ 311 memory_region_init(&cxl_dstate->device_registers, obj, "device-registers", 312 pow2ceil(CXL_MMIO_SIZE)); 313 314 memory_region_init_io(&cxl_dstate->caps, obj, &caps_ops, cxl_dstate, 315 "cap-array", CXL_CAPS_SIZE); 316 memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate, 317 "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH); 318 memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cci, 319 "mailbox", CXL_MAILBOX_REGISTERS_LENGTH); 320 memory_region_init_io(&cxl_dstate->memory_device, obj, &mdev_ops, 321 cxl_dstate, "memory device caps", 322 CXL_MEMORY_DEVICE_REGISTERS_LENGTH); 323 324 memory_region_add_subregion(&cxl_dstate->device_registers, 0, 325 &cxl_dstate->caps); 326 memory_region_add_subregion(&cxl_dstate->device_registers, 327 CXL_DEVICE_STATUS_REGISTERS_OFFSET, 328 &cxl_dstate->device); 329 memory_region_add_subregion(&cxl_dstate->device_registers, 330 CXL_MAILBOX_REGISTERS_OFFSET, 331 &cxl_dstate->mailbox); 332 memory_region_add_subregion(&cxl_dstate->device_registers, 333 CXL_MEMORY_DEVICE_REGISTERS_OFFSET, 334 &cxl_dstate->memory_device); 335 } 336 337 void cxl_event_set_status(CXLDeviceState *cxl_dstate, CXLEventLogType log_type, 338 bool available) 339 { 340 if (available) { 341 cxl_dstate->event_status |= (1 << log_type); 342 } else { 343 cxl_dstate->event_status &= ~(1 << log_type); 344 } 345 346 ARRAY_FIELD_DP64(cxl_dstate->dev_reg_state64, CXL_DEV_EVENT_STATUS, 347 EVENT_STATUS, cxl_dstate->event_status); 348 } 349 350 static void device_reg_init_common(CXLDeviceState *cxl_dstate) 351 { 352 CXLEventLogType log; 353 354 for (log = 0; log < CXL_EVENT_TYPE_MAX; log++) { 355 cxl_event_set_status(cxl_dstate, log, false); 356 } 357 } 358 359 static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate, int msi_n) 360 { 361 /* 2048 payload size */ 362 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, 363 PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT); 364 cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE; 365 /* irq support */ 366 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, 367 BG_INT_CAP, 1); 368 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, 369 MSI_N, msi_n); 370 cxl_dstate->mbox_msi_n = msi_n; 371 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, 372 MBOX_READY_TIME, 0); /* Not reported */ 373 ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP, 374 TYPE, 0); /* Inferred from class code */ 375 } 376 377 static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) 378 { 379 uint64_t memdev_status_reg; 380 381 memdev_status_reg = FIELD_DP64(0, CXL_MEM_DEV_STS, MEDIA_STATUS, 1); 382 memdev_status_reg = FIELD_DP64(memdev_status_reg, CXL_MEM_DEV_STS, 383 MBOX_READY, 1); 384 cxl_dstate->memdev_status = memdev_status_reg; 385 } 386 387 void cxl_device_register_init_t3(CXLType3Dev *ct3d, int msi_n) 388 { 389 CXLDeviceState *cxl_dstate = &ct3d->cxl_dstate; 390 uint64_t *cap_h = cxl_dstate->caps_reg_state64; 391 const int cap_count = 3; 392 393 /* CXL Device Capabilities Array Register */ 394 ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_ID, 0); 395 ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); 396 ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); 397 398 cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 399 CXL_DEVICE_STATUS_VERSION); 400 device_reg_init_common(cxl_dstate); 401 402 cxl_device_cap_init(cxl_dstate, MAILBOX, 2, CXL_DEV_MAILBOX_VERSION); 403 mailbox_reg_init_common(cxl_dstate, msi_n); 404 405 cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 406 CXL_MEM_DEV_STATUS_VERSION); 407 memdev_reg_init_common(cxl_dstate); 408 409 cxl_initialize_mailbox_t3(&ct3d->cci, DEVICE(ct3d), 410 CXL_MAILBOX_MAX_PAYLOAD_SIZE); 411 } 412 413 void cxl_device_register_init_swcci(CSWMBCCIDev *sw, int msi_n) 414 { 415 CXLDeviceState *cxl_dstate = &sw->cxl_dstate; 416 uint64_t *cap_h = cxl_dstate->caps_reg_state64; 417 const int cap_count = 3; 418 419 /* CXL Device Capabilities Array Register */ 420 ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_ID, 0); 421 ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); 422 ARRAY_FIELD_DP64(cap_h, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); 423 424 cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 2); 425 device_reg_init_common(cxl_dstate); 426 427 cxl_device_cap_init(cxl_dstate, MAILBOX, 2, 1); 428 mailbox_reg_init_common(cxl_dstate, msi_n); 429 430 cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 1); 431 memdev_reg_init_common(cxl_dstate); 432 } 433 434 uint64_t cxl_device_get_timestamp(CXLDeviceState *cxl_dstate) 435 { 436 uint64_t time, delta; 437 uint64_t final_time = 0; 438 439 if (cxl_dstate->timestamp.set) { 440 /* Find the delta from the last time the host set the time. */ 441 time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 442 delta = time - cxl_dstate->timestamp.last_set; 443 final_time = cxl_dstate->timestamp.host_set + delta; 444 } 445 446 return final_time; 447 } 448