@@ -5,6 +5,7 @@ menuconfig CXL_BUS
select FW_LOADER
select FW_UPLOAD
select PCI_DOE
+ select FIRMWARE_TABLE
help
CXL is a bus that is electrically compatible with PCI Express, but
layers three protocols on that signalling (CXL.io, CXL.cache, and
@@ -13,5 +13,6 @@ cxl_core-y += mbox.o
cxl_core-y += pci.o
cxl_core-y += hdm.o
cxl_core-y += pmu.o
+cxl_core-y += cdat.o
cxl_core-$(CONFIG_TRACING) += trace.o
cxl_core-$(CONFIG_CXL_REGION) += region.o
new file mode 100644
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
+#include <linux/acpi.h>
+#include <linux/fw_table.h>
+#include "cxlpci.h"
+#include "cxl.h"
+
+static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
+ const unsigned long end)
+{
+ struct acpi_cdat_header *hdr = &header->cdat;
+ struct acpi_cdat_dsmas *dsmas;
+ int size = sizeof(*hdr) + sizeof(*dsmas);
+ struct xarray *dsmas_xa = arg;
+ struct dsmas_entry *dent;
+ u16 len;
+ int rc;
+
+ len = le16_to_cpu((__force __le16)hdr->length);
+ if (len != size || (unsigned long)hdr + len > end) {
+ pr_warn("Malformed DSMAS table length: (%u:%u)\n", size, len);
+ return -EINVAL;
+ }
+
+ /* Skip common header */
+ dsmas = (struct acpi_cdat_dsmas *)(hdr + 1);
+
+ dent = kzalloc(sizeof(*dent), GFP_KERNEL);
+ if (!dent)
+ return -ENOMEM;
+
+ dent->handle = dsmas->dsmad_handle;
+ dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
+ dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
+ le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
+
+ rc = xa_insert(dsmas_xa, dent->handle, dent, GFP_KERNEL);
+ if (rc) {
+ kfree(dent);
+ return rc;
+ }
+
+ return 0;
+}
+
+int cxl_cdat_endpoint_process(struct cxl_port *port, struct xarray *dsmas_xa)
+{
+ return cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
+ dsmas_xa, port->cdat.table);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
+
+void cxl_cdat_dsmas_xa_destroy(struct xarray *dsmas_xa)
+{
+ struct dsmas_entry *dentry;
+ unsigned long index;
+
+ xa_for_each(dsmas_xa, index, dentry) {
+ xa_erase(dsmas_xa, index);
+ kfree(dentry);
+ }
+ xa_destroy(dsmas_xa);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cdat_dsmas_xa_destroy, CXL);
+
+MODULE_IMPORT_NS(CXL);
@@ -839,6 +839,15 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
}
#endif
+/* CDAT related bits */
+struct dsmas_entry {
+ struct range dpa_range;
+ u8 handle;
+};
+
+int cxl_cdat_endpoint_process(struct cxl_port *port, struct xarray *dsmas_xa);
+void cxl_cdat_dsmas_xa_destroy(struct xarray *dsmas_xa);
+
/*
* Unit test builds overrides this to __weak, find the 'strong' version
* of these symbols in tools/testing/cxl/.
@@ -136,6 +136,18 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
device_for_each_child(&port->dev, root, discover_region);
put_device(&root->dev);
+ if (port->cdat.table) {
+ DEFINE_XARRAY(dsmas_xa);
+
+ rc = cxl_cdat_endpoint_process(port, &dsmas_xa);
+ if (rc < 0)
+ dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc);
+
+ /* Performance data processing */
+
+ cxl_cdat_dsmas_xa_destroy(&dsmas_xa);
+ }
+
return 0;
}
@@ -58,6 +58,7 @@ cxl_core-y += $(CXL_CORE_SRC)/mbox.o
cxl_core-y += $(CXL_CORE_SRC)/pci.o
cxl_core-y += $(CXL_CORE_SRC)/hdm.o
cxl_core-y += $(CXL_CORE_SRC)/pmu.o
+cxl_core-y += $(CXL_CORE_SRC)/cdat.o
cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
cxl_core-y += config_check.o