--- 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);