@@ -84,6 +84,7 @@ ForEachMacros:
- 'cxl_target_foreach'
- 'cxl_dport_foreach'
- 'cxl_endpoint_foreach'
+ - 'cxl_port_foreach_all'
- 'daxctl_dev_foreach'
- 'daxctl_mapping_foreach'
- 'daxctl_region_foreach'
@@ -61,6 +61,19 @@ one or more memdevs. For example:
}
]
----
+Additionally, when provisioning new interleave configurations it is
+useful to know which memdevs can be referenced by a given decoder like a
+root decoder:
+----
+# cxl list -Mu -d decoder0.0
+{
+ "memdev":"mem0",
+ "pmem_size":"256.00 MiB (268.44 MB)",
+ "ram_size":0,
+ "serial":"0",
+ "host":"0000:35:00.0"
+}
+----
The --human option in addition to reformatting some fields to more human
friendly strings also unwraps the array to reduce the number of lines of
@@ -219,10 +219,18 @@ struct cxl_port *cxl_port_get_parent(struct cxl_port *port);
struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);
const char *cxl_port_get_host(struct cxl_port *port);
struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder);
+struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,
+ const struct cxl_port *top);
#define cxl_port_foreach(parent, port) \
for (port = cxl_port_get_first(parent); port != NULL; \
port = cxl_port_get_next(port))
+
+#define cxl_port_foreach_all(top, port) \
+ for (port = cxl_port_get_first(top); port != NULL; \
+ port = cxl_port_get_next_all(port, top))
+
+
----
A bus object encapsulates a CXL port object. Use cxl_bus_get_port() to
use generic port APIs on root objects.
@@ -236,6 +244,9 @@ that hierarchy via cxl_port_get_bus().
The host of a port is the corresponding device name of the PCIe Root
Port, or Switch Upstream Port with CXL capabilities.
+The cxl_port_foreach_all() helper does a depth first iteration of all
+ports beneath the 'top' port argument.
+
=== PORT: Attributes
----
const char *cxl_port_get_devname(struct cxl_port *port);
@@ -441,6 +441,51 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,
return NULL;
}
+static bool __memdev_filter_by_decoder(struct cxl_memdev *memdev,
+ struct cxl_port *port, const char *ident)
+{
+ struct cxl_decoder *decoder;
+ struct cxl_endpoint *endpoint;
+
+ cxl_decoder_foreach(port, decoder) {
+ if (!util_cxl_decoder_filter(decoder, ident))
+ continue;
+ if (cxl_decoder_get_target_by_memdev(decoder, memdev))
+ return true;
+ }
+
+ cxl_endpoint_foreach(port, endpoint)
+ if (__memdev_filter_by_decoder(
+ memdev, cxl_endpoint_get_port(endpoint), ident))
+ return true;
+ return false;
+}
+
+static struct cxl_memdev *
+util_cxl_memdev_filter_by_decoder(struct cxl_memdev *memdev, const char *ident)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ struct cxl_bus *bus;
+
+ if (!ident)
+ return memdev;
+
+ cxl_bus_foreach(ctx, bus) {
+ struct cxl_port *port, *top;
+
+ port = cxl_bus_get_port(bus);
+ if (__memdev_filter_by_decoder(memdev, port, ident))
+ return memdev;
+
+ top = port;
+ cxl_port_foreach_all(top, port)
+ if (__memdev_filter_by_decoder(memdev, port, ident))
+ return memdev;
+ }
+
+ return NULL;
+}
+
static unsigned long params_to_flags(struct cxl_filter_params *param)
{
unsigned long flags = 0;
@@ -599,6 +644,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,
if (!util_cxl_memdev_filter(memdev, p->memdev_filter,
p->serial_filter))
continue;
+ if (!util_cxl_memdev_filter_by_decoder(
+ memdev, p->decoder_filter))
+ continue;
if (!p->idle && !cxl_memdev_is_enabled(memdev))
continue;
jobj = util_cxl_memdev_to_json(memdev, flags);
@@ -1257,6 +1257,19 @@ CXL_EXPORT struct cxl_port *cxl_port_get_next(struct cxl_port *port)
return list_next(&parent_port->child_ports, port, list);
}
+CXL_EXPORT struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,
+ const struct cxl_port *top)
+{
+ struct cxl_port *child, *iter = port;
+
+ child = cxl_port_get_first(iter);
+ if (child)
+ return child;
+ while (!cxl_port_get_next(iter) && iter->parent && iter->parent != top)
+ iter = iter->parent;
+ return cxl_port_get_next(iter);
+}
+
CXL_EXPORT const char *cxl_port_get_devname(struct cxl_port *port)
{
return devpath_to_devname(port->dev_path);
@@ -94,11 +94,17 @@ struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
const char *cxl_port_get_host(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);
+struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,
+ const struct cxl_port *top);
#define cxl_port_foreach(parent, port) \
for (port = cxl_port_get_first(parent); port != NULL; \
port = cxl_port_get_next(port))
+#define cxl_port_foreach_all(top, port) \
+ for (port = cxl_port_get_first(top); port != NULL; \
+ port = cxl_port_get_next_all(port, top))
+
struct cxl_dport;
struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);
struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);
In order to filter memdevs by decoders all the ports in the hierarchy need to be iterated, so introduce cxl_port_foreach_all() that starts at the bus and does a depth first iteration of all the descendant ports. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- .clang-format | 1 + Documentation/cxl/cxl-list.txt | 13 ++++++++++ Documentation/cxl/lib/libcxl.txt | 11 +++++++++ cxl/filter.c | 48 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.c | 13 ++++++++++ cxl/libcxl.h | 6 +++++ 6 files changed, 92 insertions(+)