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

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