---
cxl/json.c | 8 ++++++++
cxl/lib/libcxl.c | 38 ++++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 1 +
cxl/lib/private.h | 2 ++
cxl/libcxl.h | 1 +
5 files changed, 50 insertions(+)
diff --git a/cxl/json.c b/cxl/json.c
index 5cff532acb13..2f3639ede2f8 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -783,6 +783,14 @@ static struct json_object *__util_cxl_port_to_json(struct
cxl_port *port,
if (jobj)
json_object_object_add(jport, "host", jobj);
+ if (cxl_port_get_parent_dport(port)) {
+ struct cxl_dport *dport = cxl_port_get_parent_dport(port);
+
+ jobj = json_object_new_string(cxl_dport_get_devname(dport));
+ if (jobj)
+ json_object_object_add(jport, "parent_dport", jobj);
+ }
+
jobj = json_object_new_int(cxl_port_get_depth(port));
if (jobj)
json_object_object_add(jport, "depth", jobj);
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index a69e31bc8a6e..9475d0e51f8c 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -162,6 +162,7 @@ static void __free_port(struct cxl_port *port, struct
list_head *head)
free(port->dev_buf);
free(port->dev_path);
free(port->uport);
+ free(port->parent_dport_path);
}
static void free_port(struct cxl_port *port, struct list_head *head)
@@ -1488,6 +1489,20 @@ static int cxl_port_init(struct cxl_port *port, struct
cxl_port *parent_port,
if (!port->uport)
goto err;
+ /*
+ * CXL root devices have no parents and level 1 ports are both
+ * CXL root targets and hosts of the next level, so:
+ * parent_dport == uport
+ * ...at depth == 1
+ */
+ if (port->depth > 1) {
+ rc = snprintf(port->dev_buf, port->buf_len, "%s/parent_dport",
+ cxlport_base);
+ if (rc >= port->buf_len)
+ goto err;
+ port->parent_dport_path = realpath(port->dev_buf, NULL);
+ }
+
sprintf(path, "%s/modalias", cxlport_base);
if (sysfs_read_attr(ctx, path, buf) == 0)
port->module = util_modalias_to_module(ctx, buf);
@@ -2465,6 +2480,29 @@ CXL_EXPORT const char *cxl_port_get_host(struct cxl_port
*port)
return devpath_to_devname(port->uport);
}
+CXL_EXPORT struct cxl_dport *cxl_port_get_parent_dport(struct cxl_port *port)
+{
+ struct cxl_port *parent;
+ struct cxl_dport *dport;
+ const char *name;
+
+ if (port->parent_dport)
+ return port->parent_dport;
+
+ if (!port->parent_dport_path)
+ return NULL;
+
+ parent = cxl_port_get_parent(port);
+ name = devpath_to_devname(port->parent_dport_path);
+ cxl_dport_foreach(parent, dport)
+ if (strcmp(cxl_dport_get_devname(dport), name) == 0) {
+ port->parent_dport = dport;
+ return dport;
+ }
+
+ return NULL;
+}
+
CXL_EXPORT bool cxl_port_hosts_memdev(struct cxl_port *port,
struct cxl_memdev *memdev)
{
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 490ed1fda5d3..cc5c1d543484 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -222,4 +222,5 @@ LIBCXL_4 {
global:
cxl_target_get_firmware_node;
cxl_dport_get_firmware_node;
+ cxl_port_get_parent_dport;
} LIBCXL_3;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index e378339ec353..da2fce33cb07 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -62,6 +62,8 @@ struct cxl_port {
size_t buf_len;
char *dev_path;
char *uport;
+ char *parent_dport_path;
+ struct cxl_dport *parent_dport;
int ports_init;
int endpoints_init;
int decoders_init;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 1e0076908901..8d75330886f8 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -96,6 +96,7 @@ bool cxl_port_is_endpoint(struct cxl_port *port);
struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port);
struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
const char *cxl_port_get_host(struct cxl_port *port);
+struct cxl_dport *cxl_port_get_parent_dport(struct cxl_port *port);
bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);
int cxl_port_get_nr_dports(struct cxl_port *port);
int cxl_port_disable_invalidate(struct cxl_port *port);