/
githubmirror
/
ndctl
Обзор
Документация
Войти
/
githubmirror
/
ndctl
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
cxl/filter.c
1 297 строк
31 KB
Alison Schofield
cxl/list: apply bus and port filters to anonymous memdevs
21 апр 2026, 02:36
21 апр 2026, 02:36
56e02a9
Код
Авторство
О чём код?
// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2015-2022 Intel Corporation. All rights reserved. #include <errno.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <util/log.h> #include <util/json.h> #include <cxl/libcxl.h> #include <json-c/json.h> #include "filter.h" #include "json.h" static const char *which_sep(const char *filter) { if (strchr(filter, ' ')) return " "; if (strchr(filter, ',')) return ","; return " "; } bool cxl_filter_has(const char *__filter, const char *needle) { char *filter, *save; const char *arg; if (!needle) return true; if (!__filter) return false; filter = strdup(__filter); if (!filter) return false; for (arg = strtok_r(filter, which_sep(__filter), &save); arg; arg = strtok_r(NULL, which_sep(__filter), &save)) if (strstr(arg, needle)) break; free(filter); if (arg) return true; return false; } struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident) { char *ident, *save; const char *arg; int endpoint_id; if (!__ident) return endpoint; ident = strdup(__ident); if (!ident) return NULL; for (arg = strtok_r(ident, which_sep(__ident), &save); arg; arg = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(arg, "all") == 0) break; if ((sscanf(arg, "%d", &endpoint_id) == 1 || sscanf(arg, "endpoint%d", &endpoint_id) == 1) && cxl_endpoint_get_id(endpoint) == endpoint_id) break; if (strcmp(arg, cxl_endpoint_get_devname(endpoint)) == 0) break; if (strcmp(arg, cxl_endpoint_get_host(endpoint)) == 0) break; } free(ident); if (arg) return endpoint; return NULL; } static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port, const char *__ident) { char *ident, *save; const char *arg; int port_id; if (!__ident) return port; ident = strdup(__ident); if (!ident) return NULL; for (arg = strtok_r(ident, which_sep(__ident), &save); arg; arg = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(arg, "all") == 0) break; if (strcmp(arg, "root") == 0 && cxl_port_is_root(port)) break; if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port)) break; if (strcmp(arg, "endpoint") == 0 && cxl_port_is_endpoint(port)) break; if ((sscanf(arg, "%d", &port_id) == 1 || sscanf(arg, "port%d", &port_id) == 1) && cxl_port_get_id(port) == port_id) break; if (strcmp(arg, cxl_port_get_devname(port)) == 0) break; if (strcmp(arg, cxl_port_get_host(port)) == 0) break; } free(ident); if (arg) return port; return NULL; } static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p) { if (p->single) return CXL_PF_SINGLE; return CXL_PF_ANCESTRY; } struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident, enum cxl_port_filter_mode mode) { struct cxl_port *iter = port; while (iter) { if (__util_cxl_port_filter(iter, ident)) return port; if (mode == CXL_PF_SINGLE) return NULL; iter = cxl_port_get_parent(iter); } return NULL; } static struct cxl_endpoint * util_cxl_endpoint_filter_by_port(struct cxl_endpoint *endpoint, const char *ident, enum cxl_port_filter_mode mode) { struct cxl_port *iter = cxl_endpoint_get_port(endpoint); if (util_cxl_port_filter(iter, ident, CXL_PF_SINGLE)) return endpoint; iter = cxl_port_get_parent(iter); if (!iter) return NULL; if (util_cxl_port_filter(iter, ident, mode)) return endpoint; return NULL; } struct cxl_dport *util_cxl_dport_filter(struct cxl_dport *dport, const char *__ident) { char *ident, *save; const char *arg; if (!__ident) return dport; ident = strdup(__ident); if (!ident) return NULL; for (arg = strtok_r(ident, which_sep(__ident), &save); arg; arg = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(arg, cxl_dport_get_devname(dport)) == 0) break; } free(ident); if (arg) return dport; return NULL; } static struct cxl_decoder * util_cxl_decoder_filter_by_port(struct cxl_decoder *decoder, const char *ident, enum cxl_port_filter_mode mode) { struct cxl_port *port = cxl_decoder_get_port(decoder); if (util_cxl_port_filter(port, ident, mode)) return decoder; return NULL; } struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident) { char *ident, *save; const char *arg; int bus_id; if (!__ident) return bus; ident = strdup(__ident); if (!ident) return NULL; for (arg = strtok_r(ident, which_sep(__ident), &save); arg; arg = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(arg, "all") == 0) break; if ((sscanf(arg, "%d", &bus_id) == 1 || sscanf(arg, "root%d", &bus_id) == 1) && cxl_bus_get_id(bus) == bus_id) break; if (strcmp(arg, cxl_bus_get_devname(bus)) == 0) break; if (strcmp(arg, cxl_bus_get_provider(bus)) == 0) break; } free(ident); if (arg) return bus; return NULL; } static struct cxl_port *util_cxl_port_filter_by_bus(struct cxl_port *port, const char *__ident) { struct cxl_ctx *ctx = cxl_port_get_ctx(port); struct cxl_bus *bus; if (!__ident) return port; if (cxl_port_is_root(port)) { bus = cxl_port_to_bus(port); bus = util_cxl_bus_filter(bus, __ident); return bus ? port : NULL; } cxl_bus_foreach(ctx, bus) { if (!util_cxl_bus_filter(bus, __ident)) continue; if (bus == cxl_port_get_bus(port)) return port; } return NULL; } struct cxl_memdev *util_cxl_memdev_filter_by_bus(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) { if (!util_cxl_bus_filter(bus, __ident)) continue; if (bus == cxl_memdev_get_bus(memdev)) return memdev; } return NULL; } static struct cxl_decoder * util_cxl_decoder_filter_by_bus(struct cxl_decoder *decoder, const char *__ident) { struct cxl_port *port = cxl_decoder_get_port(decoder); if (!util_cxl_port_filter_by_bus(port, __ident)) return NULL; return decoder; } static struct cxl_memdev * util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials) { unsigned long long serial = 0; char *serials, *save, *end; const char *arg; if (!__serials) return memdev; serials = strdup(__serials); if (!serials) return NULL; for (arg = strtok_r(serials, which_sep(__serials), &save); arg; arg = strtok_r(NULL, which_sep(__serials), &save)) { serial = strtoull(arg, &end, 0); if (!arg[0] || end[0] != 0) continue; if (cxl_memdev_get_serial(memdev) == serial) break; } free(serials); if (arg) return memdev; return NULL; } struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, const char *__ident, const char *serials) { char *ident, *save; const char *name; int memdev_id; if (!__ident) return util_cxl_memdev_serial_filter(memdev, serials); ident = strdup(__ident); if (!ident) return NULL; for (name = strtok_r(ident, which_sep(__ident), &save); name; name = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(name, "all") == 0) break; if ((sscanf(name, "%d", &memdev_id) == 1 || sscanf(name, "mem%d", &memdev_id) == 1) && cxl_memdev_get_id(memdev) == memdev_id) break; if (strcmp(name, cxl_memdev_get_devname(memdev)) == 0) break; if (strcmp(name, cxl_memdev_get_host(memdev)) == 0) break; } free(ident); if (name) return util_cxl_memdev_serial_filter(memdev, serials); return NULL; } static struct cxl_bus *util_cxl_bus_filter_by_memdev(struct cxl_bus *bus, const char *ident, const char *serial) { struct cxl_ctx *ctx = cxl_bus_get_ctx(bus); struct cxl_memdev *memdev; if (!ident && !serial) return bus; cxl_memdev_foreach(ctx, memdev) { if (!util_cxl_memdev_filter(memdev, ident, serial)) continue; if (cxl_memdev_get_bus(memdev) == bus) return bus; } return NULL; } static struct cxl_endpoint * util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint, const char *ident, const char *serial) { struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint); struct cxl_memdev *memdev; if (!ident && !serial) return endpoint; cxl_memdev_foreach(ctx, memdev) { if (!util_cxl_memdev_filter(memdev, ident, serial)) continue; if (cxl_memdev_get_endpoint(memdev) == endpoint) return endpoint; } return NULL; } struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, const char *ident, const char *serial) { struct cxl_ctx *ctx = cxl_port_get_ctx(port); struct cxl_memdev *memdev; if (!ident && !serial) return port; cxl_memdev_foreach(ctx, memdev) { if (!util_cxl_memdev_filter(memdev, ident, serial)) continue; if (cxl_port_hosts_memdev(port, memdev)) return port; } return NULL; } struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder, const char *__ident) { struct cxl_port *port = cxl_decoder_get_port(decoder); int pid, did; char *ident, *save; const char *name; if (!__ident) return decoder; ident = strdup(__ident); if (!ident) return NULL; for (name = strtok_r(ident, which_sep(__ident), &save); name; name = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(name, "all") == 0) break; if (strcmp(name, "root") == 0 && cxl_port_is_root(port)) break; if (strcmp(name, "switch") == 0 && cxl_port_is_switch(port)) break; if (strcmp(name, "endpoint") == 0 && cxl_port_is_endpoint(port)) break; if ((sscanf(name, "%d.%d", &pid, &did) == 2 || sscanf(name, "decoder%d.%d", &pid, &did) == 2) && cxl_port_get_id(port) == pid && cxl_decoder_get_id(decoder) == did) break; if (strcmp(name, cxl_decoder_get_devname(decoder)) == 0) break; } free(ident); if (name) return 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_endpoint *endpoint; struct cxl_memdev *memdev; struct cxl_port *port; 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; port = cxl_decoder_get_port(decoder); if (!port || !cxl_port_is_endpoint(port)) continue; endpoint = cxl_port_to_endpoint(port); if (cxl_endpoint_get_memdev(endpoint) == memdev) return decoder; } return NULL; } struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target, const char *ident, const char *serial) { struct cxl_decoder *decoder = cxl_target_get_decoder(target); struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); struct cxl_memdev *memdev; if (!ident && !serial) return target; cxl_memdev_foreach(ctx, memdev) { if (!util_cxl_memdev_filter(memdev, ident, serial)) continue; if (cxl_target_maps_memdev(target, memdev)) return target; } return NULL; } struct cxl_dport *util_cxl_dport_filter_by_memdev(struct cxl_dport *dport, const char *ident, const char *serial) { struct cxl_port *port = cxl_dport_get_port(dport); struct cxl_ctx *ctx = cxl_port_get_ctx(port); struct cxl_memdev *memdev; if (!ident && !serial) return dport; cxl_memdev_foreach (ctx, memdev) { if (!util_cxl_memdev_filter(memdev, ident, serial)) continue; if (cxl_dport_maps_memdev(dport, memdev)) return dport; } 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 bool __memdev_filter_by_port(struct cxl_memdev *memdev, struct cxl_port *port, const char *port_ident) { struct cxl_endpoint *endpoint; if (util_cxl_port_filter(port, port_ident, CXL_PF_SINGLE) && cxl_memdev_is_port_ancestor(memdev, port)) return true; cxl_endpoint_foreach(port, endpoint) if (__memdev_filter_by_port(memdev, cxl_endpoint_get_port(endpoint), port_ident)) return true; return false; } static struct cxl_memdev * util_cxl_memdev_filter_by_port(struct cxl_memdev *memdev, const char *bus_ident, const char *port_ident) { struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); struct cxl_bus *bus; if (!bus_ident && !port_ident) return memdev; cxl_bus_foreach(ctx, bus) { struct cxl_port *port, *top; port = cxl_bus_get_port(bus); if (!util_cxl_bus_filter(bus, bus_ident)) continue; if (__memdev_filter_by_port(memdev, port, port_ident)) return memdev; top = port; cxl_port_foreach_all(top, port) if (__memdev_filter_by_port(memdev, port, port_ident)) return memdev; } return NULL; } static struct cxl_region * util_cxl_region_filter_by_bus(struct cxl_region *region, const char *__ident) { struct cxl_decoder *decoder = cxl_region_get_decoder(region); if (!util_cxl_decoder_filter_by_bus(decoder, __ident)) return NULL; return region; } static struct cxl_region * util_cxl_region_filter_by_port(struct cxl_region *region, const char *__ident) { struct cxl_decoder *decoder = cxl_region_get_decoder(region); struct cxl_port *port = cxl_decoder_get_port(decoder); if (!util_cxl_port_filter(port, __ident ,CXL_PF_ANCESTRY)) return NULL; return region; } static struct cxl_region * util_cxl_region_filter_by_decoder(struct cxl_region *region, const char *__ident) { struct cxl_decoder *decoder = cxl_region_get_decoder(region); if (!util_cxl_decoder_filter(decoder, __ident)) return NULL; return region; } struct cxl_region *util_cxl_region_filter(struct cxl_region *region, const char *__ident) { char *ident, *save; const char *name; int id; if (!__ident) return region; ident = strdup(__ident); if (!ident) return NULL; for (name = strtok_r(ident, which_sep(__ident), &save); name; name = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(name, "all") == 0) break; if ((sscanf(name, "%d", &id) == 1 || sscanf(name, "region%d", &id) == 1) && cxl_region_get_id(region) == id) break; if (strcmp(name, cxl_region_get_devname(region)) == 0) break; } free(ident); if (name) return region; return NULL; } static struct cxl_decoder * util_cxl_decoder_filter_by_region(struct cxl_decoder *decoder, const char *__ident) { struct cxl_region *region; if (!__ident) return decoder; /* root decoders filter by children */ cxl_region_foreach(decoder, region) if (util_cxl_region_filter(region, __ident)) return decoder; /* switch and endpoint decoders have a 1:1 association with a region */ region = cxl_decoder_get_region(decoder); if (!region) return NULL; region = util_cxl_region_filter(region, __ident); if (!region) return NULL; return decoder; } static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs, struct json_object *platform, const char *container_name, bool do_container) { size_t count; if (!json_object_array_length(jobjs)) { json_object_put(jobjs); return; } if (do_container) { struct json_object *container = json_object_new_object(); if (!container) { err(p, "failed to list: %s\n", container_name); return; } json_object_object_add(container, container_name, jobjs); json_object_array_add(platform, container); return; } for (count = json_object_array_length(jobjs); count; count--) { struct json_object *jobj = json_object_array_get_idx(jobjs, 0); json_object_get(jobj); json_object_array_del_idx(jobjs, 0, 1); json_object_array_add(platform, jobj); } json_object_put(jobjs); } static bool cond_add_put_array(struct json_object *jobj, const char *key, struct json_object *array) { if (jobj && array && json_object_array_length(array) > 0) { json_object_object_add(jobj, key, array); return true; } else { json_object_put(array); return false; } } static bool cond_add_put_array_suffix(struct json_object *jobj, const char *key, const char *suffix, struct json_object *array) { char *name; bool rc; if (asprintf(&name, "%s:%s", key, suffix) < 0) return false; rc = cond_add_put_array(jobj, name, array); free(name); return rc; } static struct json_object *pick_array(struct json_object *child, struct json_object *container) { if (child) return child; if (container) return container; return NULL; } static void walk_regions(struct cxl_decoder *decoder, struct json_object *jregions, struct cxl_filter_params *p, unsigned long flags) { struct json_object *jregion; struct cxl_region *region; cxl_region_foreach(decoder, region) { if (!util_cxl_region_filter(region, p->region_filter)) continue; if (!util_cxl_region_filter_by_bus(region, p->bus_filter)) continue; if (!util_cxl_region_filter_by_port(region, p->port_filter)) continue; if (!util_cxl_region_filter_by_decoder(region, p->decoder_filter)) continue; if (!p->idle && !cxl_region_is_enabled(region)) continue; jregion = util_cxl_region_to_json(region, flags); if (!jregion) continue; json_object_array_add(jregions, jregion); } return; } static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p, struct json_object *jdecoders, struct json_object *jregions, unsigned long flags) { struct cxl_decoder *decoder; cxl_decoder_foreach(port, decoder) { const char *devname = cxl_decoder_get_devname(decoder); struct json_object *jchildregions = NULL; struct json_object *jdecoder = NULL; if (!p->decoders) goto walk_children; if (!util_cxl_decoder_filter(decoder, p->decoder_filter)) goto walk_children; if (!util_cxl_decoder_filter_by_bus(decoder, p->bus_filter)) goto walk_children; if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter, pf_mode(p))) goto walk_children; if (!util_cxl_decoder_filter_by_memdev( decoder, p->memdev_filter, p->serial_filter)) goto walk_children; if (!util_cxl_decoder_filter_by_region(decoder, p->region_filter)) goto walk_children; if (!p->idle && cxl_decoder_get_size(decoder) == 0) continue; jdecoder = util_cxl_decoder_to_json(decoder, flags); if (!decoder) { dbg(p, "decoder object allocation failure\n"); continue; } util_cxl_targets_append_json(jdecoder, decoder, p->memdev_filter, p->serial_filter, flags); if (p->regions) { jchildregions = json_object_new_array(); if (!jchildregions) { err(p, "failed to allocate region object\n"); return; } } json_object_array_add(jdecoders, jdecoder); walk_children: if (!p->regions) continue; if (!cxl_port_is_root(port)) continue; walk_regions(decoder, pick_array(jchildregions, jregions), p, flags); cond_add_put_array_suffix(jdecoder, "regions", devname, jchildregions); } } static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, struct json_object *jeps, struct json_object *jdevs, struct json_object *jdecoders, unsigned long flags) { struct cxl_endpoint *endpoint; cxl_endpoint_foreach(port, endpoint) { struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint); const char *devname = cxl_endpoint_get_devname(endpoint); struct json_object *jchilddecoders = NULL; struct json_object *jendpoint = NULL; struct cxl_memdev *memdev; if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter)) continue; if (!util_cxl_port_filter_by_bus(ep_port, p->bus_filter)) continue; if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter, pf_mode(p))) continue; if (!util_cxl_endpoint_filter_by_memdev( endpoint, p->memdev_filter, p->serial_filter)) continue; if (!p->idle && !cxl_endpoint_is_enabled(endpoint)) continue; if (p->endpoints) { jendpoint = util_cxl_endpoint_to_json(endpoint, flags); if (!jendpoint) { err(p, "%s: failed to list\n", devname); continue; } json_object_array_add(jeps, jendpoint); } if (p->memdevs) { struct json_object *jobj; memdev = cxl_endpoint_get_memdev(endpoint); if (!memdev) continue; 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 (!util_cxl_memdev_filter_by_port( memdev, p->bus_filter, p->port_filter)) continue; if (!p->idle && !cxl_memdev_is_enabled(memdev)) continue; jobj = util_cxl_memdev_to_json(memdev, flags); if (!jobj) { err(p, "failed to json serialize %s\n", cxl_memdev_get_devname(memdev)); continue; } if (p->endpoints) json_object_object_add(jendpoint, "memdev", jobj); else json_object_array_add(jdevs, jobj); } if (p->decoders && p->endpoints) { jchilddecoders = json_object_new_array(); if (!jchilddecoders) { err(p, "%s: failed to enumerate child decoders\n", devname); continue; } } if (!p->decoders) continue; walk_decoders(cxl_endpoint_get_port(endpoint), p, pick_array(jchilddecoders, jdecoders), NULL, flags); cond_add_put_array_suffix(jendpoint, "decoders", devname, jchilddecoders); } } static void walk_child_ports(struct cxl_port *parent_port, struct cxl_filter_params *p, struct json_object *jports, struct json_object *jportdecoders, struct json_object *jeps, struct json_object *jepdecoders, struct json_object *jdevs, unsigned long flags) { struct cxl_port *port; cxl_port_foreach(parent_port, port) { const char *devname = cxl_port_get_devname(port); struct json_object *jport = NULL; struct json_object *jchilddevs = NULL; struct json_object *jchildports = NULL; struct json_object *jchildeps = NULL; struct json_object *jchilddecoders = NULL; if (!util_cxl_port_filter_by_memdev(port, p->memdev_filter, p->serial_filter)) continue; if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) goto walk_children; if (!util_cxl_port_filter_by_bus(port, p->bus_filter)) goto walk_children; if (!p->idle && !cxl_port_is_enabled(port)) continue; if (p->ports) { jport = util_cxl_port_to_json(port, flags); if (!jport) { err(p, "%s: failed to list\n", devname); continue; } util_cxl_dports_append_json(jport, port, p->memdev_filter, p->serial_filter, flags); json_object_array_add(jports, jport); jchildports = json_object_new_array(); if (!jchildports) { err(p, "%s: failed to enumerate child ports\n", devname); continue; } if (p->memdevs) { jchilddevs = json_object_new_array(); if (!jchilddevs) { err(p, "%s: failed to enumerate child memdevs\n", devname); continue; } } if (p->endpoints) { jchildeps = json_object_new_array(); if (!jchildeps) { err(p, "%s: failed to enumerate child endpoints\n", devname); continue; } } if (p->decoders) { jchilddecoders = json_object_new_array(); if (!jchilddecoders) { err(p, "%s: failed to enumerate child decoders\n", devname); continue; } } } walk_children: if (p->endpoints || p->memdevs || p->decoders) walk_endpoints(port, p, pick_array(jchildeps, jeps), pick_array(jchilddevs, jdevs), pick_array(jchilddecoders, jepdecoders), flags); walk_decoders(port, p, pick_array(jchilddecoders, jportdecoders), NULL, flags); walk_child_ports(port, p, pick_array(jchildports, jports), pick_array(jchilddecoders, jportdecoders), pick_array(jchildeps, jeps), pick_array(jchilddecoders, jepdecoders), pick_array(jchilddevs, jdevs), flags); cond_add_put_array_suffix(jport, "ports", devname, jchildports); cond_add_put_array_suffix(jport, "endpoints", devname, jchildeps); cond_add_put_array_suffix(jport, "decoders", devname, jchilddecoders); cond_add_put_array_suffix(jport, "memdevs", devname, jchilddevs); } } struct json_object *cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) { struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL; struct json_object *jplatform = json_object_new_array(); unsigned long flags = cxl_filter_to_flags(p); struct json_object *jportdecoders = NULL; struct json_object *jbusdecoders = NULL; struct json_object *jepdecoders = NULL; struct json_object *janondevs = NULL; struct json_object *jregions = NULL; struct json_object *jeps = NULL; struct cxl_memdev *memdev; int top_level_objs = 0; struct cxl_bus *bus; if (!jplatform) { dbg(p, "platform object allocation failure\n"); return NULL; } janondevs = json_object_new_array(); if (!janondevs) goto err; jbuses = json_object_new_array(); if (!jbuses) goto err; jports = json_object_new_array(); if (!jports) goto err; jeps = json_object_new_array(); if (!jeps) goto err; jdevs = json_object_new_array(); if (!jdevs) goto err; jbusdecoders = json_object_new_array(); if (!jbusdecoders) goto err; jportdecoders = json_object_new_array(); if (!jportdecoders) goto err; jepdecoders = json_object_new_array(); if (!jepdecoders) goto err; jregions = json_object_new_array(); if (!jregions) goto err; dbg(p, "walk memdevs\n"); cxl_memdev_foreach(ctx, memdev) { struct json_object *janondev; 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 (!util_cxl_memdev_filter_by_port(memdev, p->bus_filter, p->port_filter)) continue; if (cxl_memdev_is_enabled(memdev)) continue; if (!p->idle) continue; if (p->memdevs) { janondev = util_cxl_memdev_to_json(memdev, flags); if (!janondev) { dbg(p, "memdev object allocation failure\n"); continue; } json_object_array_add(janondevs, janondev); } } dbg(p, "walk buses\n"); cxl_bus_foreach(ctx, bus) { struct json_object *jbus = NULL; struct json_object *jchilddecoders = NULL; struct json_object *jchildports = NULL; struct json_object *jchilddevs = NULL; struct json_object *jchildeps = NULL; struct json_object *jchildregions = NULL; struct cxl_port *port = cxl_bus_get_port(bus); const char *devname = cxl_bus_get_devname(bus); if (!util_cxl_bus_filter_by_memdev(bus, p->memdev_filter, p->serial_filter)) continue; if (!util_cxl_bus_filter(bus, p->bus_filter)) goto walk_children; if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) goto walk_children; if (p->buses) { jbus = util_cxl_bus_to_json(bus, flags); if (!jbus) { dbg(p, "bus object allocation failure\n"); continue; } util_cxl_dports_append_json(jbus, port, p->memdev_filter, p->serial_filter, flags); json_object_array_add(jbuses, jbus); if (p->ports) { jchildports = json_object_new_array(); if (!jchildports) { err(p, "%s: failed to enumerate child ports\n", devname); continue; } } if (p->endpoints) { jchildeps = json_object_new_array(); if (!jchildeps) { err(p, "%s: failed to enumerate child endpoints\n", devname); continue; } } if (p->memdevs) { jchilddevs = json_object_new_array(); if (!jchilddevs) { err(p, "%s: failed to enumerate child memdevs\n", devname); continue; } } if (p->decoders) { jchilddecoders = json_object_new_array(); if (!jchilddecoders) { err(p, "%s: failed to enumerate child decoders\n", devname); continue; } } if (p->regions) { jchildregions = json_object_new_array(); if (!jchildregions) { err(p, "%s: failed to enumerate child regions\n", devname); continue; } } } walk_children: dbg(p, "walk decoders\n"); walk_decoders(port, p, pick_array(jchilddecoders, jbusdecoders), pick_array(jchildregions, jregions), flags); dbg(p, "walk rch endpoints\n"); if (p->endpoints || p->memdevs || p->decoders) walk_endpoints(port, p, pick_array(jchildeps, jeps), pick_array(jchilddevs, jdevs), pick_array(jchilddecoders, jepdecoders), flags); dbg(p, "walk ports\n"); walk_child_ports(port, p, pick_array(jchildports, jports), pick_array(jchilddecoders, jportdecoders), pick_array(jchildeps, jeps), pick_array(jchilddecoders, jepdecoders), pick_array(jchilddevs, jdevs), flags); cond_add_put_array_suffix(jbus, "ports", devname, jchildports); cond_add_put_array_suffix(jbus, "endpoints", devname, jchildeps); cond_add_put_array_suffix(jbus, "decoders", devname, jchilddecoders); cond_add_put_array_suffix(jbus, "regions", devname, jchildregions); cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs); } if (json_object_array_length(janondevs)) top_level_objs++; if (json_object_array_length(jbuses)) top_level_objs++; if (json_object_array_length(jports)) top_level_objs++; if (json_object_array_length(jeps)) top_level_objs++; if (json_object_array_length(jdevs)) top_level_objs++; if (json_object_array_length(jbusdecoders)) top_level_objs++; if (json_object_array_length(jportdecoders)) top_level_objs++; if (json_object_array_length(jepdecoders)) top_level_objs++; if (json_object_array_length(jregions)) top_level_objs++; splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1); splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); splice_array(p, jports, jplatform, "ports", top_level_objs > 1); splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1); splice_array(p, jdevs, jplatform, "memdevs", top_level_objs > 1); splice_array(p, jbusdecoders, jplatform, "root decoders", top_level_objs > 1); splice_array(p, jportdecoders, jplatform, "port decoders", top_level_objs > 1); splice_array(p, jepdecoders, jplatform, "endpoint decoders", top_level_objs > 1); splice_array(p, jregions, jplatform, "regions", top_level_objs > 1); return jplatform; err: json_object_put(janondevs); json_object_put(jbuses); json_object_put(jports); json_object_put(jeps); json_object_put(jdevs); json_object_put(jbusdecoders); json_object_put(jportdecoders); json_object_put(jepdecoders); json_object_put(jregions); json_object_put(jplatform); return NULL; }