+ struct dsmas_entry *dent;
+
+ if (dsmas->hdr.length != sizeof(*dsmas)) {
+ pr_warn("Malformed DSMAS table length: (%lu:%u)\n",
+ (unsigned long)sizeof(*dsmas), dsmas->hdr.length);
+ return -EINVAL;
+ }
+
+ dent = kzalloc(sizeof(*dent), GFP_KERNEL);
+ if (!dent)
+ return -ENOMEM;
+
+ dent->handle = dsmas->dsmad_handle;
+ dent->dpa_range.start = le64_to_cpu(dsmas->dpa_base_address);
+ dent->dpa_range.end = le64_to_cpu(dsmas->dpa_base_address) +
+ le64_to_cpu(dsmas->dpa_length) - 1;
+ list_add_tail(&dent->list, dsmas_list);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dsmas_parse_entry, CXL);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index cc3309794b45..9d0e22fe72c0 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/list.h>
#include <linux/io.h>
/**
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 45e2f2bf5ef8..9a2468a93d83 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -104,6 +104,22 @@ struct cdat_subtable_entry {
enum cdat_type type;
};
+struct dsmas_entry {
+ struct list_head list;
+ struct range dpa_range;
+ u8 handle;
+};
+
+/* Sub-table 0: Device Scoped Memory Affinity Structure (DSMAS) */
+struct cdat_dsmas {
+ struct cdat_entry_header hdr;
+ u8 dsmad_handle;
+ u8 flags;
+ __u16 reserved;
+ __le64 dpa_base_address;
+ __le64 dpa_length;
+} __packed;
+
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
@@ -119,4 +135,6 @@ int cdat_table_parse_##x(struct cdat_header *table, \
cdat_table_parse(dsmas);
cdat_table_parse(dslbis);
cdat_table_parse(sslbis);
+
+int cxl_dsmas_parse_entry(struct cdat_entry_header *header, void *arg);
#endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 60a865680e22..c8136797d528 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -57,6 +57,16 @@ static int discover_region(struct device *dev, void *root)
return 0;
}
+static void dsmas_list_destroy(struct list_head *dsmas_list)
+{
+ struct dsmas_entry *dentry, *n;
+
+ list_for_each_entry_safe(dentry, n, dsmas_list, list) {
+ list_del(&dentry->list);
+ kfree(dentry);
+ }
+}
+
static int cxl_switch_port_probe(struct cxl_port *port)
{
struct cxl_hdm *cxlhdm;
@@ -131,9 +141,23 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
static int cxl_port_probe(struct device *dev)
{
struct cxl_port *port = to_cxl_port(dev);
+ int rc;
/* Cache the data early to ensure is_visible() works */
read_cdat_data(port);
+ if (port->cdat.table) {
+ if (is_cxl_endpoint(port)) {