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