aboutsummaryrefslogtreecommitdiff
path: root/hw/cxl/cxl-device-utils.c
diff options
context:
space:
mode:
authorBen Widawsky <ben.widawsky@intel.com>2022-04-29 15:40:31 +0100
committerMichael S. Tsirkin <mst@redhat.com>2022-05-13 06:13:36 -0400
commit464e14ac438e21c532889d78caf54a1dc837012a (patch)
tree50bf6a90ef8f69d988dd4092602e3ed6460fc32f /hw/cxl/cxl-device-utils.c
parent6364adacdfa6a24e3f5b08f6b5ffa789a5d828a7 (diff)
hw/cxl/device: Implement basic mailbox (8.2.8.4)
This is the beginning of implementing mailbox support for CXL 2.0 devices. The implementation recognizes when the doorbell is rung, handles the command/payload, clears the doorbell while returning error codes and data. Generally the mailbox mechanism is designed to permit communication between the host OS and the firmware running on the device. For our purposes, we emulate both the firmware, implemented primarily in cxl-mailbox-utils.c, and the hardware. No commands are implemented yet. Signed-off-by: Ben Widawsky <ben.widawsky@intel.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20220429144110.25167-7-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/cxl/cxl-device-utils.c')
-rw-r--r--hw/cxl/cxl-device-utils.c122
1 files changed, 121 insertions, 1 deletions
diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c
index 241f9f82e3..f6c3e0f095 100644
--- a/hw/cxl/cxl-device-utils.c
+++ b/hw/cxl/cxl-device-utils.c
@@ -44,6 +44,108 @@ static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size)
return 0;
}
+static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size)
+{
+ CXLDeviceState *cxl_dstate = opaque;
+
+ switch (size) {
+ case 1:
+ return cxl_dstate->mbox_reg_state[offset];
+ case 2:
+ return cxl_dstate->mbox_reg_state16[offset / size];
+ case 4:
+ return cxl_dstate->mbox_reg_state32[offset / size];
+ case 8:
+ return cxl_dstate->mbox_reg_state64[offset / size];
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset,
+ uint64_t value)
+{
+ switch (offset) {
+ case A_CXL_DEV_MAILBOX_CTRL:
+ /* fallthrough */
+ case A_CXL_DEV_MAILBOX_CAP:
+ /* RO register */
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n",
+ __func__, offset);
+ return;
+ }
+
+ reg_state[offset / sizeof(*reg_state)] = value;
+}
+
+static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset,
+ uint64_t value)
+{
+ switch (offset) {
+ case A_CXL_DEV_MAILBOX_CMD:
+ break;
+ case A_CXL_DEV_BG_CMD_STS:
+ /* BG not supported */
+ /* fallthrough */
+ case A_CXL_DEV_MAILBOX_STS:
+ /* Read only register, will get updated by the state machine */
+ return;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n",
+ __func__, offset);
+ return;
+ }
+
+
+ reg_state[offset / sizeof(*reg_state)] = value;
+}
+
+static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ CXLDeviceState *cxl_dstate = opaque;
+
+ if (offset >= A_CXL_DEV_CMD_PAYLOAD) {
+ memcpy(cxl_dstate->mbox_reg_state + offset, &value, size);
+ return;
+ }
+
+ switch (size) {
+ case 4:
+ mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value);
+ break;
+ case 8:
+ mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL,
+ DOORBELL)) {
+ cxl_process_mailbox(cxl_dstate);
+ }
+}
+
+static const MemoryRegionOps mailbox_ops = {
+ .read = mailbox_reg_read,
+ .write = mailbox_reg_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ .unaligned = false,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
static const MemoryRegionOps dev_ops = {
.read = dev_reg_read,
.write = NULL, /* status register is read only */
@@ -84,20 +186,33 @@ void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate)
"cap-array", CXL_CAPS_SIZE);
memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate,
"device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH);
+ memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cxl_dstate,
+ "mailbox", CXL_MAILBOX_REGISTERS_LENGTH);
memory_region_add_subregion(&cxl_dstate->device_registers, 0,
&cxl_dstate->caps);
memory_region_add_subregion(&cxl_dstate->device_registers,
CXL_DEVICE_STATUS_REGISTERS_OFFSET,
&cxl_dstate->device);
+ memory_region_add_subregion(&cxl_dstate->device_registers,
+ CXL_MAILBOX_REGISTERS_OFFSET,
+ &cxl_dstate->mailbox);
}
static void device_reg_init_common(CXLDeviceState *cxl_dstate) { }
+static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate)
+{
+ /* 2048 payload size, with no interrupt or background support */
+ ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
+ PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT);
+ cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE;
+}
+
void cxl_device_register_init_common(CXLDeviceState *cxl_dstate)
{
uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64;
- const int cap_count = 1;
+ const int cap_count = 2;
/* CXL Device Capabilities Array Register */
ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0);
@@ -106,4 +221,9 @@ void cxl_device_register_init_common(CXLDeviceState *cxl_dstate)
cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1);
device_reg_init_common(cxl_dstate);
+
+ cxl_device_cap_init(cxl_dstate, MAILBOX, 2);
+ mailbox_reg_init_common(cxl_dstate);
+
+ assert(cxl_initialize_mailbox(cxl_dstate) == 0);
}