aboutsummaryrefslogtreecommitdiff
path: root/hw/cxl
diff options
context:
space:
mode:
authorHuai-Cheng Kuo <hchkuo@avery-design.com.tw>2022-10-14 16:10:43 +0100
committerMichael S. Tsirkin <mst@redhat.com>2022-11-07 13:12:19 -0500
commitaba578bdace5303a441f8a37aad781b5cb06f38c (patch)
tree4998602462926d0b2ea290210ea97a72376a7cb2 /hw/cxl
parent23325c8df4318e5f4388dc2e53e6b7c8c3996880 (diff)
downloadqemu-aba578bdace5303a441f8a37aad781b5cb06f38c.zip
qemu-aba578bdace5303a441f8a37aad781b5cb06f38c.tar.gz
qemu-aba578bdace5303a441f8a37aad781b5cb06f38c.tar.bz2
hw/cxl/cdat: CXL CDAT Data Object Exchange implementation
The Data Object Exchange implementation of CXL Coherent Device Attribute Table (CDAT). This implementation is referring to "Coherent Device Attribute Table Specification, Rev. 1.03, July. 2022" and "Compute Express Link Specification, Rev. 3.0, July. 2022" This patch adds core support that will be shared by both end-points and switch port emulation. Signed-off-by: Huai-Cheng Kuo <hchkuo@avery-design.com.tw> Signed-off-by: Chris Browy <cbrowy@avery-design.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Message-Id: <20221014151045.24781-4-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')
-rw-r--r--hw/cxl/cxl-cdat.c224
-rw-r--r--hw/cxl/meson.build1
2 files changed, 225 insertions, 0 deletions
diff --git a/hw/cxl/cxl-cdat.c b/hw/cxl/cxl-cdat.c
new file mode 100644
index 0000000..3653aa5
--- /dev/null
+++ b/hw/cxl/cxl-cdat.c
@@ -0,0 +1,224 @@
+/*
+ * CXL CDAT Structure
+ *
+ * Copyright (C) 2021 Avery Design Systems, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "hw/cxl/cxl.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+
+static void cdat_len_check(CDATSubHeader *hdr, Error **errp)
+{
+ assert(hdr->length);
+ assert(hdr->reserved == 0);
+
+ switch (hdr->type) {
+ case CDAT_TYPE_DSMAS:
+ assert(hdr->length == sizeof(CDATDsmas));
+ break;
+ case CDAT_TYPE_DSLBIS:
+ assert(hdr->length == sizeof(CDATDslbis));
+ break;
+ case CDAT_TYPE_DSMSCIS:
+ assert(hdr->length == sizeof(CDATDsmscis));
+ break;
+ case CDAT_TYPE_DSIS:
+ assert(hdr->length == sizeof(CDATDsis));
+ break;
+ case CDAT_TYPE_DSEMTS:
+ assert(hdr->length == sizeof(CDATDsemts));
+ break;
+ case CDAT_TYPE_SSLBIS:
+ assert(hdr->length >= sizeof(CDATSslbisHeader));
+ assert((hdr->length - sizeof(CDATSslbisHeader)) %
+ sizeof(CDATSslbe) == 0);
+ break;
+ default:
+ error_setg(errp, "Type %d is reserved", hdr->type);
+ }
+}
+
+static void ct3_build_cdat(CDATObject *cdat, Error **errp)
+{
+ g_autofree CDATTableHeader *cdat_header = NULL;
+ g_autofree CDATEntry *cdat_st = NULL;
+ uint8_t sum = 0;
+ int ent, i;
+
+ /* Use default table if fopen == NULL */
+ assert(cdat->build_cdat_table);
+
+ cdat_header = g_malloc0(sizeof(*cdat_header));
+ if (!cdat_header) {
+ error_setg(errp, "Failed to allocate CDAT header");
+ return;
+ }
+
+ cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf, cdat->private);
+
+ if (!cdat->built_buf_len) {
+ /* Build later as not all data available yet */
+ cdat->to_update = true;
+ return;
+ }
+ cdat->to_update = false;
+
+ cdat_st = g_malloc0(sizeof(*cdat_st) * (cdat->built_buf_len + 1));
+ if (!cdat_st) {
+ error_setg(errp, "Failed to allocate CDAT entry array");
+ return;
+ }
+
+ /* Entry 0 for CDAT header, starts with Entry 1 */
+ for (ent = 1; ent < cdat->built_buf_len + 1; ent++) {
+ CDATSubHeader *hdr = cdat->built_buf[ent - 1];
+ uint8_t *buf = (uint8_t *)cdat->built_buf[ent - 1];
+
+ cdat_st[ent].base = hdr;
+ cdat_st[ent].length = hdr->length;
+
+ cdat_header->length += hdr->length;
+ for (i = 0; i < hdr->length; i++) {
+ sum += buf[i];
+ }
+ }
+
+ /* CDAT header */
+ cdat_header->revision = CXL_CDAT_REV;
+ /* For now, no runtime updates */
+ cdat_header->sequence = 0;
+ cdat_header->length += sizeof(CDATTableHeader);
+ sum += cdat_header->revision + cdat_header->sequence +
+ cdat_header->length;
+ /* Sum of all bytes including checksum must be 0 */
+ cdat_header->checksum = ~sum + 1;
+
+ cdat_st[0].base = g_steal_pointer(&cdat_header);
+ cdat_st[0].length = sizeof(*cdat_header);
+ cdat->entry_len = 1 + cdat->built_buf_len;
+ cdat->entry = g_steal_pointer(&cdat_st);
+}
+
+static void ct3_load_cdat(CDATObject *cdat, Error **errp)
+{
+ g_autofree CDATEntry *cdat_st = NULL;
+ uint8_t sum = 0;
+ int num_ent;
+ int i = 0, ent = 1, file_size = 0;
+ CDATSubHeader *hdr;
+ FILE *fp = NULL;
+
+ /* Read CDAT file and create its cache */
+ fp = fopen(cdat->filename, "r");
+ if (!fp) {
+ error_setg(errp, "CDAT: Unable to open file");
+ return;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ file_size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ cdat->buf = g_malloc0(file_size);
+
+ if (fread(cdat->buf, file_size, 1, fp) == 0) {
+ error_setg(errp, "CDAT: File read failed");
+ return;
+ }
+
+ fclose(fp);
+
+ if (file_size < sizeof(CDATTableHeader)) {
+ error_setg(errp, "CDAT: File too short");
+ return;
+ }
+ i = sizeof(CDATTableHeader);
+ num_ent = 1;
+ while (i < file_size) {
+ hdr = (CDATSubHeader *)(cdat->buf + i);
+ cdat_len_check(hdr, errp);
+ i += hdr->length;
+ num_ent++;
+ }
+ if (i != file_size) {
+ error_setg(errp, "CDAT: File length missmatch");
+ return;
+ }
+
+ cdat_st = g_malloc0(sizeof(*cdat_st) * num_ent);
+ if (!cdat_st) {
+ error_setg(errp, "CDAT: Failed to allocate entry array");
+ return;
+ }
+
+ /* Set CDAT header, Entry = 0 */
+ cdat_st[0].base = cdat->buf;
+ cdat_st[0].length = sizeof(CDATTableHeader);
+ i = 0;
+
+ while (i < cdat_st[0].length) {
+ sum += cdat->buf[i++];
+ }
+
+ /* Read CDAT structures */
+ while (i < file_size) {
+ hdr = (CDATSubHeader *)(cdat->buf + i);
+ cdat_len_check(hdr, errp);
+
+ cdat_st[ent].base = hdr;
+ cdat_st[ent].length = hdr->length;
+
+ while (cdat->buf + i <
+ (uint8_t *)cdat_st[ent].base + cdat_st[ent].length) {
+ assert(i < file_size);
+ sum += cdat->buf[i++];
+ }
+
+ ent++;
+ }
+
+ if (sum != 0) {
+ warn_report("CDAT: Found checksum mismatch in %s", cdat->filename);
+ }
+ cdat->entry_len = num_ent;
+ cdat->entry = g_steal_pointer(&cdat_st);
+}
+
+void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp)
+{
+ CDATObject *cdat = &cxl_cstate->cdat;
+
+ if (cdat->filename) {
+ ct3_load_cdat(cdat, errp);
+ } else {
+ ct3_build_cdat(cdat, errp);
+ }
+}
+
+void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp)
+{
+ CDATObject *cdat = &cxl_cstate->cdat;
+
+ if (cdat->to_update) {
+ ct3_build_cdat(cdat, errp);
+ }
+}
+
+void cxl_doe_cdat_release(CXLComponentState *cxl_cstate)
+{
+ CDATObject *cdat = &cxl_cstate->cdat;
+
+ free(cdat->entry);
+ if (cdat->built_buf) {
+ cdat->free_cdat_table(cdat->built_buf, cdat->built_buf_len,
+ cdat->private);
+ }
+ if (cdat->buf) {
+ free(cdat->buf);
+ }
+}
diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build
index f117b99..cfa95ff 100644
--- a/hw/cxl/meson.build
+++ b/hw/cxl/meson.build
@@ -4,6 +4,7 @@ softmmu_ss.add(when: 'CONFIG_CXL',
'cxl-device-utils.c',
'cxl-mailbox-utils.c',
'cxl-host.c',
+ 'cxl-cdat.c',
),
if_false: files(
'cxl-host-stubs.c',