Blame SOURCES/0117-cxl-list-Extend-decoder-objects-with-target-informat.patch

2eb93d
From 1279d1989ef77085d214a193c1458b624039c612 Mon Sep 17 00:00:00 2001
2eb93d
From: Dan Williams <dan.j.williams@intel.com>
2eb93d
Date: Sun, 23 Jan 2022 16:54:34 -0800
2eb93d
Subject: [PATCH 117/217] cxl/list: Extend decoder objects with target
2eb93d
 information
2eb93d
2eb93d
A target combines information about a dport along with its position in the
2eb93d
intereleave order. With targets enumerated decoders can also be filtered be
2eb93d
memory devices by seeing which decoders have a dport in the memory-device's
2eb93d
ancestry.
2eb93d
2eb93d
$ cxl list -D -d 3.1 -T -u
2eb93d
{
2eb93d
  "decoder":"decoder3.1",
2eb93d
  "resource":"0x8030000000",
2eb93d
  "size":"512.00 MiB (536.87 MB)",
2eb93d
  "volatile_capable":true,
2eb93d
  "nr_targets":2,
2eb93d
  "targets":[
2eb93d
    {
2eb93d
      "target":"cxl_host_bridge.1",
2eb93d
      "position":1,
2eb93d
      "id":"0x1"
2eb93d
    },
2eb93d
    {
2eb93d
      "target":"cxl_host_bridge.0",
2eb93d
      "position":0,
2eb93d
      "id":"0"
2eb93d
    }
2eb93d
  ]
2eb93d
}
2eb93d
2eb93d
Link: https://lore.kernel.org/r/164298567435.3021641.3771899644901785666.stgit@dwillia2-desk3.amr.corp.intel.com
2eb93d
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2eb93d
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
2eb93d
---
2eb93d
 .clang-format                    |   1 +
2eb93d
 Documentation/cxl/cxl-list.txt   |   8 ++-
2eb93d
 Documentation/cxl/lib/libcxl.txt |  58 ++++++++++++++++
2eb93d
 cxl/filter.c                     |  25 +++++++
2eb93d
 cxl/filter.h                     |   1 +
2eb93d
 cxl/json.c                       |  46 +++++++++++++
2eb93d
 cxl/lib/libcxl.c                 | 115 +++++++++++++++++++++++++++++++
2eb93d
 cxl/lib/libcxl.sym               |  10 +++
2eb93d
 cxl/libcxl.h                     |  19 +++++
2eb93d
 cxl/list.c                       |   2 +
2eb93d
 10 files changed, 283 insertions(+), 2 deletions(-)
2eb93d
2eb93d
diff --git a/.clang-format b/.clang-format
2eb93d
index 16e28ac..47fb657 100644
2eb93d
--- a/.clang-format
2eb93d
+++ b/.clang-format
2eb93d
@@ -81,6 +81,7 @@ ForEachMacros:
2eb93d
   - 'cxl_bus_foreach'
2eb93d
   - 'cxl_port_foreach'
2eb93d
   - 'cxl_decoder_foreach'
2eb93d
+  - 'cxl_target_foreach'
2eb93d
   - 'cxl_endpoint_foreach'
2eb93d
   - 'daxctl_dev_foreach'
2eb93d
   - 'daxctl_mapping_foreach'
2eb93d
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
2eb93d
index 84872b9..20ff2cb 100644
2eb93d
--- a/Documentation/cxl/cxl-list.txt
2eb93d
+++ b/Documentation/cxl/cxl-list.txt
2eb93d
@@ -44,8 +44,8 @@ would only list objects that are beneath port10 AND map mem0, mem1, OR
2eb93d
 mem2.
2eb93d
 
2eb93d
 Given that many topology queries seek to answer questions relative to a
2eb93d
-given memdev, buses, ports, and endpoints can be filtered by one or more
2eb93d
-memdevs. For example:
2eb93d
+given memdev, buses, ports, endpoints, and decoders can be filtered by
2eb93d
+one or more memdevs. For example:
2eb93d
 ----
2eb93d
 # cxl list -P -p switch,endpoint -m mem0
2eb93d
 [
2eb93d
@@ -270,6 +270,10 @@ OPTIONS
2eb93d
 	"decoder<port_id>.<instance_id>". The possible decoder type names are
2eb93d
 	"root", "switch", or "endpoint", similar to the port filter syntax.
2eb93d
 
2eb93d
+-T::
2eb93d
+--targets::
2eb93d
+	Extend decoder listings with downstream port target information.
2eb93d
+
2eb93d
 --debug::
2eb93d
 	If the cxl tool was built with debug enabled, turn on debug
2eb93d
 	messages.
2eb93d
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
2eb93d
index 73af3d0..bd92fef 100644
2eb93d
--- a/Documentation/cxl/lib/libcxl.txt
2eb93d
+++ b/Documentation/cxl/lib/libcxl.txt
2eb93d
@@ -300,6 +300,7 @@ device-local-physical-address).
2eb93d
 struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);
2eb93d
 struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);
2eb93d
 struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder);
2eb93d
+struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target);
2eb93d
 
2eb93d
 #define cxl_decoder_foreach(port, decoder)                                  \
2eb93d
        for (decoder = cxl_decoder_get_first(port); decoder != NULL;         \
2eb93d
@@ -314,6 +315,7 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);
2eb93d
 unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);
2eb93d
 const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);
2eb93d
 int cxl_decoder_get_id(struct cxl_decoder *decoder);
2eb93d
+int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);
2eb93d
 
2eb93d
 enum cxl_decoder_target_type {
2eb93d
        CXL_DECODER_TTYPE_UNKNOWN,
2eb93d
@@ -352,6 +354,62 @@ Platform firmware may setup the CXL decode hierarchy before the OS
2eb93d
 boots, and may additionally require that the OS not change the decode
2eb93d
 settings. This property is indicated by the cxl_decoder_is_locked() API.
2eb93d
 
2eb93d
+==== TARGETS
2eb93d
+A root or switch level decoder takes an SPA (system-physical-address) as
2eb93d
+input and routes it to a downstream port. Which downstream port depends
2eb93d
+on the downstream port's position in the interleave. A 'struct
2eb93d
+cxl_target' object represents the properties of a given downstream port
2eb93d
+relative to its interleave configuration.
2eb93d
+
2eb93d
+===== TARGET: Enumeration
2eb93d
+----
2eb93d
+struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
2eb93d
+                                                   struct cxl_memdev *memdev);
2eb93d
+struct cxl_target *
2eb93d
+cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position);
2eb93d
+struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);
2eb93d
+struct cxl_target *cxl_target_get_next(struct cxl_target *target);
2eb93d
+
2eb93d
+#define cxl_target_foreach(decoder, target)                                   \
2eb93d
+       for (target = cxl_target_get_first(decoder); target != NULL;           \
2eb93d
+            target = cxl_target_get_next(target))
2eb93d
+----
2eb93d
+Target objects can only be enumerated if the decoder has been
2eb93d
+configured, for switch decoders. For root decoders they are always
2eb93d
+available since the root decoder target mapping is static. The
2eb93d
+cxl_decoder_get_target_by_memdev() helper walks the topology to validate
2eb93d
+if the given memory device is capable of receiving cycles from this
2eb93d
+upstream decoder. It does not validate if the memory device is currently
2eb93d
+configured to participate in that decode.
2eb93d
+
2eb93d
+===== TARGET: Attributes
2eb93d
+----
2eb93d
+int cxl_target_get_position(struct cxl_target *target);
2eb93d
+unsigned long cxl_target_get_id(struct cxl_target *target);
2eb93d
+const char *cxl_target_get_devname(struct cxl_target *target);
2eb93d
+bool cxl_target_maps_memdev(struct cxl_target *target,
2eb93d
+                           struct cxl_memdev *memdev);
2eb93d
+----
2eb93d
+The position of a decoder along with the interleave granularity dictate
2eb93d
+which address in the decoder's resource range map to which port.
2eb93d
+
2eb93d
+The target id is an identifier that the CXL port uses to reference this
2eb93d
+downstream port. For CXL / PCIe downstream switch ports the id is
2eb93d
+defined by the PCIe Link Capability Port Number field. For root decoders
2eb93d
+the id is specified by platform firmware specific mechanism. For
2eb93d
+ACPI.CXL defined root ports the id comes from the CEDT.CHBS / ACPI0016
2eb93d
+_UID.
2eb93d
+
2eb93d
+The device name of a target is the name of the host device for the
2eb93d
+downstream port. For CXL / PCIe downstream ports the devname is
2eb93d
+downstream switch port PCI device. For CXL root ports the devname is a
2eb93d
+platform firmware object for the host bridge like a ACPI0016 device
2eb93d
+instance.
2eb93d
+
2eb93d
+The cxl_target_maps_memdev() helper is the companion of
2eb93d
+cxl_decoder_get_target_by_memdev() to determine which downstream ports /
2eb93d
+targets are capable of mapping which memdevs.
2eb93d
+
2eb93d
 include::../../copyright.txt[]
2eb93d
 
2eb93d
 SEE ALSO
2eb93d
diff --git a/cxl/filter.c b/cxl/filter.c
2eb93d
index dc052f6..05ede91 100644
2eb93d
--- a/cxl/filter.c
2eb93d
+++ b/cxl/filter.c
2eb93d
@@ -421,6 +421,26 @@ static struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,
2eb93d
 	return NULL;
2eb93d
 }
2eb93d
 
2eb93d
+static struct cxl_decoder *
2eb93d
+util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,
2eb93d
+				  const char *ident, const char *serial)
2eb93d
+{
2eb93d
+	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
2eb93d
+	struct cxl_memdev *memdev;
2eb93d
+
2eb93d
+	if (!ident && !serial)
2eb93d
+		return decoder;
2eb93d
+
2eb93d
+	cxl_memdev_foreach(ctx, memdev) {
2eb93d
+		if (!util_cxl_memdev_filter(memdev, ident, serial))
2eb93d
+			continue;
2eb93d
+		if (cxl_decoder_get_target_by_memdev(decoder, memdev))
2eb93d
+			return decoder;
2eb93d
+	}
2eb93d
+
2eb93d
+	return NULL;
2eb93d
+}
2eb93d
+
2eb93d
 static unsigned long params_to_flags(struct cxl_filter_params *param)
2eb93d
 {
2eb93d
 	unsigned long flags = 0;
2eb93d
@@ -431,6 +451,8 @@ static unsigned long params_to_flags(struct cxl_filter_params *param)
2eb93d
 		flags |= UTIL_JSON_HUMAN;
2eb93d
 	if (param->health)
2eb93d
 		flags |= UTIL_JSON_HEALTH;
2eb93d
+	if (param->targets)
2eb93d
+		flags |= UTIL_JSON_TARGETS;
2eb93d
 	return flags;
2eb93d
 }
2eb93d
 
2eb93d
@@ -521,6 +543,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,
2eb93d
 		if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter,
2eb93d
 						     pf_mode(p)))
2eb93d
 			continue;
2eb93d
+		if (!util_cxl_decoder_filter_by_memdev(
2eb93d
+			    decoder, p->memdev_filter, p->serial_filter))
2eb93d
+			continue;
2eb93d
 		if (!p->idle && cxl_decoder_get_size(decoder) == 0)
2eb93d
 			continue;
2eb93d
 		jdecoder = util_cxl_decoder_to_json(decoder, flags);
2eb93d
diff --git a/cxl/filter.h b/cxl/filter.h
2eb93d
index 5d7bf45..6fd469f 100644
2eb93d
--- a/cxl/filter.h
2eb93d
+++ b/cxl/filter.h
2eb93d
@@ -16,6 +16,7 @@ struct cxl_filter_params {
2eb93d
 	bool single;
2eb93d
 	bool endpoints;
2eb93d
 	bool decoders;
2eb93d
+	bool targets;
2eb93d
 	bool memdevs;
2eb93d
 	bool ports;
2eb93d
 	bool buses;
2eb93d
diff --git a/cxl/json.c b/cxl/json.c
2eb93d
index 548bc52..3a37909 100644
2eb93d
--- a/cxl/json.c
2eb93d
+++ b/cxl/json.c
2eb93d
@@ -268,6 +268,8 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
2eb93d
 	const char *devname = cxl_decoder_get_devname(decoder);
2eb93d
 	struct cxl_port *port = cxl_decoder_get_port(decoder);
2eb93d
 	struct json_object *jdecoder, *jobj;
2eb93d
+	struct json_object *jtargets;
2eb93d
+	struct cxl_target *target;
2eb93d
 	u64 val;
2eb93d
 
2eb93d
 	jdecoder = json_object_new_object();
2eb93d
@@ -321,7 +323,51 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
2eb93d
 					       jobj);
2eb93d
 	}
2eb93d
 
2eb93d
+	/* Endpoints don't have targets, they *are* targets */
2eb93d
+	if (cxl_port_is_endpoint(port))
2eb93d
+		return jdecoder;
2eb93d
+
2eb93d
+	val = cxl_decoder_get_nr_targets(decoder);
2eb93d
+	jobj = json_object_new_int(val);
2eb93d
+	if (jobj)
2eb93d
+		json_object_object_add(jdecoder, "nr_targets", jobj);
2eb93d
+
2eb93d
+	if (!(flags & UTIL_JSON_TARGETS) ||
2eb93d
+	    !cxl_decoder_get_nr_targets(decoder))
2eb93d
+		return jdecoder;
2eb93d
+
2eb93d
+	jtargets = json_object_new_array();
2eb93d
+	if (!jtargets)
2eb93d
+		return jdecoder;
2eb93d
+
2eb93d
+	cxl_target_foreach(decoder, target) {
2eb93d
+		struct json_object *jtarget = json_object_new_object();
2eb93d
+
2eb93d
+		if (!jtarget)
2eb93d
+			continue;
2eb93d
+
2eb93d
+		devname = cxl_target_get_devname(target);
2eb93d
+		jobj = json_object_new_string(devname);
2eb93d
+		if (jobj)
2eb93d
+			json_object_object_add(jtarget, "target", jobj);
2eb93d
+
2eb93d
+		val = cxl_target_get_position(target);
2eb93d
+		jobj = json_object_new_int(val);
2eb93d
+		if (jobj)
2eb93d
+			json_object_object_add(jtarget, "position", jobj);
2eb93d
+
2eb93d
+		val = cxl_target_get_id(target);
2eb93d
+		jobj = util_json_object_hex(val, flags);
2eb93d
+		if (jobj)
2eb93d
+			json_object_object_add(jtarget, "id", jobj);
2eb93d
+
2eb93d
+		json_object_array_add(jtargets, jtarget);
2eb93d
+	}
2eb93d
+
2eb93d
+	json_object_object_add(jdecoder, "targets", jtargets);
2eb93d
+
2eb93d
 	return jdecoder;
2eb93d
+
2eb93d
 }
2eb93d
 
2eb93d
 static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,
2eb93d
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
2eb93d
index 5e30923..877f42c 100644
2eb93d
--- a/cxl/lib/libcxl.c
2eb93d
+++ b/cxl/lib/libcxl.c
2eb93d
@@ -67,10 +67,22 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
2eb93d
 	free(memdev);
2eb93d
 }
2eb93d
 
2eb93d
+static void free_target(struct cxl_target *target, struct list_head *head)
2eb93d
+{
2eb93d
+	if (head)
2eb93d
+		list_del_from(head, &target->list);
2eb93d
+	free(target->dev_path);
2eb93d
+	free(target);
2eb93d
+}
2eb93d
+
2eb93d
 static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)
2eb93d
 {
2eb93d
+	struct cxl_target *target, *_t;
2eb93d
+
2eb93d
 	if (head)
2eb93d
 		list_del_from(head, &decoder->list);
2eb93d
+	list_for_each_safe(&decoder->targets, target, _t, list)
2eb93d
+		free_target(target, &decoder->targets);
2eb93d
 	free(decoder->dev_buf);
2eb93d
 	free(decoder->dev_path);
2eb93d
 	free(decoder);
2eb93d
@@ -856,6 +868,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
2eb93d
 	struct cxl_port *port = parent;
2eb93d
 	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
2eb93d
 	char buf[SYSFS_ATTR_SIZE];
2eb93d
+	char *target_id, *save;
2eb93d
 	size_t i;
2eb93d
 
2eb93d
 	dbg(ctx, "%s: base: \'%s\'\n", devname, cxldecoder_base);
2eb93d
@@ -870,6 +883,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
2eb93d
 	decoder->id = id;
2eb93d
 	decoder->ctx = ctx;
2eb93d
 	decoder->port = port;
2eb93d
+	list_head_init(&decoder->targets);
2eb93d
 
2eb93d
 	decoder->dev_path = strdup(cxldecoder_base);
2eb93d
 	if (!decoder->dev_path)
2eb93d
@@ -935,6 +949,36 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
2eb93d
 	}
2eb93d
 	}
2eb93d
 
2eb93d
+	sprintf(path, "%s/target_list", cxldecoder_base);
2eb93d
+	if (sysfs_read_attr(ctx, path, buf) < 0)
2eb93d
+		buf[0] = '\0';
2eb93d
+
2eb93d
+	for (i = 0, target_id = strtok_r(buf, ",", &save); target_id;
2eb93d
+	     target_id = strtok_r(NULL, ",", &save), i++) {
2eb93d
+		int did = strtoul(target_id, NULL, 0);
2eb93d
+		struct cxl_target *target = calloc(1, sizeof(*target));
2eb93d
+
2eb93d
+		if (!target)
2eb93d
+			break;
2eb93d
+
2eb93d
+		target->id = did;
2eb93d
+		target->position = i;
2eb93d
+		target->decoder = decoder;
2eb93d
+		sprintf(port->dev_buf, "%s/dport%d", port->dev_path, did);
2eb93d
+		target->dev_path = realpath(port->dev_buf, NULL);
2eb93d
+		if (!target->dev_path) {
2eb93d
+			free(target);
2eb93d
+			break;
2eb93d
+		}
2eb93d
+		dbg(ctx, "%s: target%ld %s\n", devname, i, target->dev_path);
2eb93d
+		list_add(&decoder->targets, &target->list);
2eb93d
+	}
2eb93d
+
2eb93d
+	if (target_id)
2eb93d
+		err(ctx, "%s: failed to parse target%ld\n",
2eb93d
+		    devpath_to_devname(cxldecoder_base), i);
2eb93d
+	decoder->nr_targets = i;
2eb93d
+
2eb93d
 	cxl_decoder_foreach(port, decoder_dup)
2eb93d
 		if (decoder_dup->id == decoder->id) {
2eb93d
 			free_decoder(decoder, NULL);
2eb93d
@@ -1044,11 +1088,82 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder)
2eb93d
 	return decoder->locked;
2eb93d
 }
2eb93d
 
2eb93d
+CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder)
2eb93d
+{
2eb93d
+	return decoder->nr_targets;
2eb93d
+}
2eb93d
+
2eb93d
 CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder)
2eb93d
 {
2eb93d
 	return devpath_to_devname(decoder->dev_path);
2eb93d
 }
2eb93d
 
2eb93d
+CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder)
2eb93d
+{
2eb93d
+	return list_top(&decoder->targets, struct cxl_target, list);
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target)
2eb93d
+{
2eb93d
+	return target->decoder;
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT struct cxl_target *cxl_target_get_next(struct cxl_target *target)
2eb93d
+{
2eb93d
+	struct cxl_decoder *decoder = cxl_target_get_decoder(target);
2eb93d
+
2eb93d
+	return list_next(&decoder->targets, target, list);
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT const char *cxl_target_get_devname(struct cxl_target *target)
2eb93d
+{
2eb93d
+	return devpath_to_devname(target->dev_path);
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT unsigned long cxl_target_get_id(struct cxl_target *target)
2eb93d
+{
2eb93d
+	return target->id;
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT int cxl_target_get_position(struct cxl_target *target)
2eb93d
+{
2eb93d
+	return target->position;
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT bool cxl_target_maps_memdev(struct cxl_target *target,
2eb93d
+					struct cxl_memdev *memdev)
2eb93d
+{
2eb93d
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
2eb93d
+
2eb93d
+	dbg(ctx, "memdev: %s target: %s\n", memdev->host_path,
2eb93d
+	    target->dev_path);
2eb93d
+
2eb93d
+	return !!strstr(memdev->host_path, target->dev_path);
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT struct cxl_target *
2eb93d
+cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
2eb93d
+				 struct cxl_memdev *memdev)
2eb93d
+{
2eb93d
+	struct cxl_target *target;
2eb93d
+
2eb93d
+	cxl_target_foreach(decoder, target)
2eb93d
+		if (cxl_target_maps_memdev(target, memdev))
2eb93d
+			return target;
2eb93d
+	return NULL;
2eb93d
+}
2eb93d
+
2eb93d
+CXL_EXPORT struct cxl_target *
2eb93d
+cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position)
2eb93d
+{
2eb93d
+	struct cxl_target *target;
2eb93d
+
2eb93d
+	cxl_target_foreach(decoder, target)
2eb93d
+		if (target->position == position)
2eb93d
+			return target;
2eb93d
+	return NULL;
2eb93d
+}
2eb93d
+
2eb93d
 static void *add_cxl_port(void *parent, int id, const char *cxlport_base)
2eb93d
 {
2eb93d
 	const char *devname = devpath_to_devname(cxlport_base);
2eb93d
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
2eb93d
index 22babb7..cb33180 100644
2eb93d
--- a/cxl/lib/libcxl.sym
2eb93d
+++ b/cxl/lib/libcxl.sym
2eb93d
@@ -125,10 +125,20 @@ global:
2eb93d
 	cxl_decoder_get_resource;
2eb93d
 	cxl_decoder_get_size;
2eb93d
 	cxl_decoder_get_devname;
2eb93d
+	cxl_decoder_get_target_by_memdev;
2eb93d
+	cxl_decoder_get_target_by_position;
2eb93d
+	cxl_decoder_get_nr_targets;
2eb93d
 	cxl_decoder_get_target_type;
2eb93d
 	cxl_decoder_is_pmem_capable;
2eb93d
 	cxl_decoder_is_volatile_capable;
2eb93d
 	cxl_decoder_is_mem_capable;
2eb93d
 	cxl_decoder_is_accelmem_capable;
2eb93d
 	cxl_decoder_is_locked;
2eb93d
+	cxl_target_get_first;
2eb93d
+	cxl_target_get_next;
2eb93d
+	cxl_target_get_decoder;
2eb93d
+	cxl_target_get_position;
2eb93d
+	cxl_target_get_id;
2eb93d
+	cxl_target_get_devname;
2eb93d
+	cxl_target_maps_memdev;
2eb93d
 } LIBCXL_1;
2eb93d
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
2eb93d
index 439ed93..abda0e5 100644
2eb93d
--- a/cxl/libcxl.h
2eb93d
+++ b/cxl/libcxl.h
2eb93d
@@ -104,6 +104,11 @@ struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);
2eb93d
 unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);
2eb93d
 unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);
2eb93d
 const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);
2eb93d
+struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
2eb93d
+						    struct cxl_memdev *memdev);
2eb93d
+struct cxl_target *
2eb93d
+cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position);
2eb93d
+int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);
2eb93d
 struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder);
2eb93d
 int cxl_decoder_get_id(struct cxl_decoder *decoder);
2eb93d
 struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder);
2eb93d
@@ -126,6 +131,20 @@ bool cxl_decoder_is_locked(struct cxl_decoder *decoder);
2eb93d
 	for (decoder = cxl_decoder_get_first(port); decoder != NULL;           \
2eb93d
 	     decoder = cxl_decoder_get_next(decoder))
2eb93d
 
2eb93d
+struct cxl_target;
2eb93d
+struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);
2eb93d
+struct cxl_target *cxl_target_get_next(struct cxl_target *target);
2eb93d
+struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target);
2eb93d
+int cxl_target_get_position(struct cxl_target *target);
2eb93d
+unsigned long cxl_target_get_id(struct cxl_target *target);
2eb93d
+const char *cxl_target_get_devname(struct cxl_target *target);
2eb93d
+bool cxl_target_maps_memdev(struct cxl_target *target,
2eb93d
+			    struct cxl_memdev *memdev);
2eb93d
+
2eb93d
+#define cxl_target_foreach(decoder, target)                                    \
2eb93d
+	for (target = cxl_target_get_first(decoder); target != NULL;           \
2eb93d
+	     target = cxl_target_get_next(target))
2eb93d
+
2eb93d
 struct cxl_endpoint;
2eb93d
 struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);
2eb93d
 struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);
2eb93d
diff --git a/cxl/list.c b/cxl/list.c
2eb93d
index d70192a..27c963a 100644
2eb93d
--- a/cxl/list.c
2eb93d
+++ b/cxl/list.c
2eb93d
@@ -41,6 +41,8 @@ static const struct option options[] = {
2eb93d
 		   "filter by CXL decoder device name(s) / class"),
2eb93d
 	OPT_BOOLEAN('D', "decoders", &param.decoders,
2eb93d
 		    "include CXL decoder info"),
2eb93d
+	OPT_BOOLEAN('T', "targets", &param.targets,
2eb93d
+		    "include CXL target data with decoders"),
2eb93d
 	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
2eb93d
 	OPT_BOOLEAN('u', "human", &param.human,
2eb93d
 		    "use human friendly number formats "),
2eb93d
-- 
2eb93d
2.27.0
2eb93d