[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260120143212.3006273-2-pawel.mielimonka@fujitsu.com>
Date: Tue, 20 Jan 2026 23:32:12 +0900
From: Pawel Mielimonka <pawel.mielimonka@...itsu.com>
To: dan.j.williams@...el.com,
alison.schofield@...el.com
Cc: Smita.KoralahalliChannabasappa@....com,
linux-cxl@...r.kernel.org,
linux-kernel@...r.kernel.org,
dave@...olabs.net,
jonathan.cameron@...wei.com,
dave.jiang@...el.com,
vishal.l.verma@...el.com,
ira.weiny@...el.com,
Pawel Mielimonka <pawel.mielimonka@...itsu.com>
Subject: [PATCH v2 1/1] cxl/cli: enforce HPA-descening teardown order for destroy-region
Note: This revision collapses the previous 2patch series into a single
patch.
Signed-off-by: Pawel Mielimonka <pawel.mielimonka@...itsu.com>
---
cxl/region.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 108 insertions(+), 2 deletions(-)
diff --git a/cxl/region.c b/cxl/region.c
index 207cf2d0..2e0f215d 100644
--- a/cxl/region.c
+++ b/cxl/region.c
@@ -831,6 +831,59 @@ out:
return cxl_region_disable(region);
}
+static int cmp_region_hpa(const void *l, const void *r)
+{
+ const struct cxl_region *const *left = l;
+ const struct cxl_region *const *right = r;
+ u64 hpa1 = cxl_region_get_resource((struct cxl_region *) *left);
+ u64 hpa2 = cxl_region_get_resource((struct cxl_region *) *right);
+
+ return (hpa1 > hpa2) - (hpa1 < hpa2);
+}
+
+static int collect_regions_sorted(struct cxl_decoder *root,
+ struct cxl_region ***out,
+ int *out_nr)
+{
+ struct cxl_region *region;
+ struct cxl_region **list = NULL;
+ int nr = 0, alloc = 0;
+
+ struct cxl_port *root_port = cxl_decoder_get_port(root)
+
+ cxl_decoder_foreach(root_port, decoder) {
+ if (!cxl_port_is_root(port))
+ continue;
+ cxl_region_foreach(decoder, region) {
+ if (nr == alloc) {
+ int new_alloc = alloc ? alloc * 2 : 8;
+ size_t new_size = (size_t)new_alloc * sizeof(*list);
+ struct cxl_region **tmp;
+
+ tmp = realloc(list, new_size);
+ if (!tmp) {
+ free(list);
+ return -ENOMEM;
+ }
+ list = tmp;
+ alloc = new_alloc;
+ }
+ list[nr++] = region;
+ }
+
+ if (!nr) {
+ free(list);
+ *out = NULL;
+ *out_nr = 0;
+ return 0;
+ }
+ }
+ qsort(list, nr, sizeof(*list), cmp_region_hpa);
+ *out = list;
+ *out_nr = nr;
+ return 0;
+}
+
static int destroy_region(struct cxl_region *region)
{
const char *devname = cxl_region_get_devname(region);
@@ -895,6 +948,58 @@ static int destroy_region(struct cxl_region *region)
return cxl_region_delete(region);
}
+static int destroy_multiple_regions(struct cxl_ctx *ctx,
+ struct parsed_params *p,
+ int *count)
+{
+ struct cxl_region **list;
+ int nr, rc, i;
+ bool skipped = false;
+
+ rc = collect_regions_sorted(ctx, NULL, &list, &nr);
+ if (rc) {
+ log_err(&rl, "failed to allocate region list: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ for (i = nr - 1; i >= 0; --i) {
+ struct cxl_region *region = NULL;
+
+ for (int j = 0; j < p->argc; j++) {
+ region = util_cxl_region_filter(list[i], p->argv[j]);
+ if (region)
+ break;
+ }
+
+ if (!region) {
+ skipped = true;
+ continue;
+ }
+
+ /*
+ * If current region matches filter, but previous didn't, destroying would
+ * result in breaking HPA continuity
+ */
+ if (skipped) {
+ log_err(&rl, "failed to destroy %s: out of order %s reset\n",
+ cxl_region_get_devname(region),
+ cxl_decoder_get_devname(decoder));
+ rc = -EINVAL;
+ break;
+ }
+
+ rc = destroy_region(region);
+ if (rc) {
+ log_err(&rl, "%s: failed: %s\n",
+ cxl_region_get_devname(region), strerror(-rc));
+ break;
+ }
+ ++(*count);
+ }
+ free(list);
+ return rc;
+}
+
static int do_region_xable(struct cxl_region *region, enum region_actions action)
{
switch (action) {
@@ -902,8 +1007,6 @@ static int do_region_xable(struct cxl_region *region, enum region_actions action
return cxl_region_enable(region);
case ACTION_DISABLE:
return disable_region(region);
- case ACTION_DESTROY:
- return destroy_region(region);
default:
return -EINVAL;
}
@@ -956,6 +1059,9 @@ static int region_action(int argc, const char **argv, struct cxl_ctx *ctx,
if (action == ACTION_CREATE)
return create_region(ctx, count, p);
+ if (action == ACTION_DESTROY)
+ return destroy_multiple_regions(ctx, p, count);
+
cxl_bus_foreach(ctx, bus) {
struct cxl_decoder *decoder;
struct cxl_port *port;
--
2.45.1.windows.1
Powered by blists - more mailing lists