@@ -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);
@@ -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)
{
@@ -222,4 +222,5 @@ LIBCXL_4 {
global:
cxl_target_get_firmware_node;
cxl_dport_get_firmware_node;
+ cxl_port_get_parent_dport;
} LIBCXL_3;
@@ -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;
@@ -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);