Blame SOURCES/0199-cxl-decoder-add-a-max_available_extent-attribute.patch

26ccd9
From bf0c44e79c0db04b0c1eea884022dfbdc011b979 Mon Sep 17 00:00:00 2001
26ccd9
From: Vishal Verma <vishal.l.verma@intel.com>
26ccd9
Date: Mon, 15 Aug 2022 13:22:14 -0600
26ccd9
Subject: [PATCH 199/217] cxl/decoder: add a max_available_extent attribute
26ccd9
26ccd9
Add a max_available_extent attribute to cxl_decoder. In order to aid in
26ccd9
its calculation, change the order of regions in the root decoder's list
26ccd9
to be sorted by start HPA of the region.
26ccd9
26ccd9
Additionally, emit this attribute in decoder listings, and consult it
26ccd9
for available space before creating a new region.
26ccd9
26ccd9
Link: https://lore.kernel.org/r/20220815192214.545800-12-vishal.l.verma@intel.com
26ccd9
Cc: Dan Williams <dan.j.williams@intel.com>
26ccd9
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
26ccd9
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
26ccd9
---
26ccd9
 cxl/json.c         |  8 +++++
26ccd9
 cxl/lib/libcxl.c   | 84 +++++++++++++++++++++++++++++++++++++++++++++-
26ccd9
 cxl/lib/libcxl.sym |  1 +
26ccd9
 cxl/lib/private.h  |  1 +
26ccd9
 cxl/libcxl.h       |  3 ++
26ccd9
 cxl/region.c       | 14 +++++++-
26ccd9
 6 files changed, 109 insertions(+), 2 deletions(-)
26ccd9
26ccd9
diff --git a/cxl/json.c b/cxl/json.c
26ccd9
index 9dc99df..9cec58b 100644
26ccd9
--- a/cxl/json.c
26ccd9
+++ b/cxl/json.c
26ccd9
@@ -499,6 +499,14 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
26ccd9
 	}
26ccd9
 
26ccd9
 	if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) {
26ccd9
+		size = cxl_decoder_get_max_available_extent(decoder);
26ccd9
+		if (size < ULLONG_MAX) {
26ccd9
+			jobj = util_json_object_size(size, flags);
26ccd9
+			if (jobj)
26ccd9
+				json_object_object_add(jdecoder,
26ccd9
+						       "max_available_extent",
26ccd9
+						       jobj);
26ccd9
+		}
26ccd9
 		if (cxl_decoder_is_pmem_capable(decoder)) {
26ccd9
 			jobj = json_object_new_boolean(true);
26ccd9
 			if (jobj)
26ccd9
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
26ccd9
index fd2ea4f..c7dc2b0 100644
26ccd9
--- a/cxl/lib/libcxl.c
26ccd9
+++ b/cxl/lib/libcxl.c
26ccd9
@@ -455,6 +455,16 @@ CXL_EXPORT int cxl_region_delete(struct cxl_region *region)
26ccd9
 	return 0;
26ccd9
 }
26ccd9
 
26ccd9
+static int region_start_cmp(struct cxl_region *r1, struct cxl_region *r2)
26ccd9
+{
26ccd9
+	if (r1->start == r2->start)
26ccd9
+		return 0;
26ccd9
+	else if (r1->start < r2->start)
26ccd9
+		return -1;
26ccd9
+	else
26ccd9
+		return 1;
26ccd9
+}
26ccd9
+
26ccd9
 static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)
26ccd9
 {
26ccd9
 	const char *devname = devpath_to_devname(cxlregion_base);
26ccd9
@@ -539,7 +549,7 @@ static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)
26ccd9
 			break;
26ccd9
 		}
26ccd9
 
26ccd9
-	list_add(&decoder->regions, &region->list);
26ccd9
+	list_add_sorted(&decoder->regions, region, list, region_start_cmp);
26ccd9
 
26ccd9
 	return region;
26ccd9
 err:
26ccd9
@@ -1618,6 +1628,70 @@ cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint)
26ccd9
 	return NULL;
26ccd9
 }
26ccd9
 
26ccd9
+static bool cxl_region_is_configured(struct cxl_region *region)
26ccd9
+{
26ccd9
+	return region->size && (region->decode_state != CXL_DECODE_RESET);
26ccd9
+}
26ccd9
+
26ccd9
+/**
26ccd9
+ * cxl_decoder_calc_max_available_extent() - calculate max available free space
26ccd9
+ * @decoder - the root decoder to calculate the free extents for
26ccd9
+ *
26ccd9
+ * The add_cxl_region() function  adds regions to the parent decoder's list
26ccd9
+ * sorted by the region's start HPAs. It can also be assumed that regions have
26ccd9
+ * no overlapped / aliased HPA space. Therefore, calculating each extent is as
26ccd9
+ * simple as walking the region list in order, and subtracting the previous
26ccd9
+ * region's end HPA from the next region's start HPA (and taking into account
26ccd9
+ * the decoder's start and end HPAs as well).
26ccd9
+ */
26ccd9
+static unsigned long long
26ccd9
+cxl_decoder_calc_max_available_extent(struct cxl_decoder *decoder)
26ccd9
+{
26ccd9
+	u64 prev_end, decoder_end, cur_extent, max_extent = 0;
26ccd9
+	struct cxl_port *port = cxl_decoder_get_port(decoder);
26ccd9
+	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
26ccd9
+	struct cxl_region *region;
26ccd9
+
26ccd9
+	if (!cxl_port_is_root(port)) {
26ccd9
+		err(ctx, "%s: not a root decoder\n",
26ccd9
+		    cxl_decoder_get_devname(decoder));
26ccd9
+		return ULLONG_MAX;
26ccd9
+	}
26ccd9
+
26ccd9
+	/*
26ccd9
+	 * Preload prev_end with an imaginary region that ends just before
26ccd9
+	 * the decoder's start, so that the extent calculation for the
26ccd9
+	 * first region Just Works
26ccd9
+	 */
26ccd9
+	prev_end = decoder->start - 1;
26ccd9
+
26ccd9
+	cxl_region_foreach(decoder, region) {
26ccd9
+		if (!cxl_region_is_configured(region))
26ccd9
+			continue;
26ccd9
+
26ccd9
+		/*
26ccd9
+		 * region->start - prev_end would get the difference in
26ccd9
+		 * addresses, but a difference of 1 in addresses implies
26ccd9
+		 * an extent of 0. Hence the '-1'.
26ccd9
+		 */
26ccd9
+		cur_extent = region->start - prev_end - 1;
26ccd9
+		max_extent = max(max_extent, cur_extent);
26ccd9
+		prev_end = region->start + region->size - 1;
26ccd9
+	}
26ccd9
+
26ccd9
+	/*
26ccd9
+	 * Finally, consider the extent after the last region, up to the end
26ccd9
+	 * of the decoder's address space, if any. If there were no regions,
26ccd9
+	 * this simply reduces to decoder->size.
26ccd9
+	 * Subtracting two addrs gets us a 'size' directly, no need for +/- 1.
26ccd9
+	 */
26ccd9
+	decoder_end = decoder->start + decoder->size - 1;
26ccd9
+	cur_extent = decoder_end - prev_end;
26ccd9
+	max_extent = max(max_extent, cur_extent);
26ccd9
+
26ccd9
+	return max_extent;
26ccd9
+}
26ccd9
+
26ccd9
 static int decoder_id_cmp(struct cxl_decoder *d1, struct cxl_decoder *d2)
26ccd9
 {
26ccd9
 	return d1->id - d2->id;
26ccd9
@@ -1748,6 +1822,8 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
26ccd9
 			if (sysfs_read_attr(ctx, path, buf) == 0)
26ccd9
 				*(flag->flag) = !!strtoul(buf, NULL, 0);
26ccd9
 		}
26ccd9
+		decoder->max_available_extent =
26ccd9
+			cxl_decoder_calc_max_available_extent(decoder);
26ccd9
 		break;
26ccd9
 	}
26ccd9
 	}
26ccd9
@@ -1912,6 +1988,12 @@ cxl_decoder_get_dpa_size(struct cxl_decoder *decoder)
26ccd9
 	return decoder->dpa_size;
26ccd9
 }
26ccd9
 
26ccd9
+CXL_EXPORT unsigned long long
26ccd9
+cxl_decoder_get_max_available_extent(struct cxl_decoder *decoder)
26ccd9
+{
26ccd9
+	return decoder->max_available_extent;
26ccd9
+}
26ccd9
+
26ccd9
 CXL_EXPORT int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder,
26ccd9
 					unsigned long long size)
26ccd9
 {
26ccd9
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
26ccd9
index cb23a0b..549f88d 100644
26ccd9
--- a/cxl/lib/libcxl.sym
26ccd9
+++ b/cxl/lib/libcxl.sym
26ccd9
@@ -213,4 +213,5 @@ global:
26ccd9
 	cxl_decoder_get_memdev;
26ccd9
 	cxl_decoder_get_interleave_granularity;
26ccd9
 	cxl_decoder_get_interleave_ways;
26ccd9
+	cxl_decoder_get_max_available_extent;
26ccd9
 } LIBCXL_2;
26ccd9
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
26ccd9
index 8bc9620..437eade 100644
26ccd9
--- a/cxl/lib/private.h
26ccd9
+++ b/cxl/lib/private.h
26ccd9
@@ -104,6 +104,7 @@ struct cxl_decoder {
26ccd9
 	u64 size;
26ccd9
 	u64 dpa_resource;
26ccd9
 	u64 dpa_size;
26ccd9
+	u64 max_available_extent;
26ccd9
 	void *dev_buf;
26ccd9
 	size_t buf_len;
26ccd9
 	char *dev_path;
26ccd9
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
26ccd9
index 69d9c09..61c7fc4 100644
26ccd9
--- a/cxl/libcxl.h
26ccd9
+++ b/cxl/libcxl.h
26ccd9
@@ -134,6 +134,9 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);
26ccd9
 unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);
26ccd9
 unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);
26ccd9
 unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);
26ccd9
+unsigned long long
26ccd9
+cxl_decoder_get_max_available_extent(struct cxl_decoder *decoder);
26ccd9
+
26ccd9
 enum cxl_decoder_mode {
26ccd9
 	CXL_DECODER_MODE_NONE,
26ccd9
 	CXL_DECODER_MODE_MIXED,
26ccd9
diff --git a/cxl/region.c b/cxl/region.c
26ccd9
index b22d3c8..a30313c 100644
26ccd9
--- a/cxl/region.c
26ccd9
+++ b/cxl/region.c
26ccd9
@@ -438,9 +438,9 @@ static int create_region(struct cxl_ctx *ctx, int *count,
26ccd9
 	struct json_object *jregion;
26ccd9
 	unsigned int i, granularity;
26ccd9
 	struct cxl_region *region;
26ccd9
+	u64 size, max_extent;
26ccd9
 	const char *devname;
26ccd9
 	uuid_t uuid;
26ccd9
-	u64 size;
26ccd9
 	int rc;
26ccd9
 
26ccd9
 	rc = create_region_validate_config(ctx, p);
26ccd9
@@ -455,6 +455,18 @@ static int create_region(struct cxl_ctx *ctx, int *count,
26ccd9
 		log_err(&rl, "%s: unable to determine region size\n", __func__);
26ccd9
 		return -ENXIO;
26ccd9
 	}
26ccd9
+	max_extent = cxl_decoder_get_max_available_extent(p->root_decoder);
26ccd9
+	if (max_extent == ULLONG_MAX) {
26ccd9
+		log_err(&rl, "%s: unable to determine max extent\n",
26ccd9
+			cxl_decoder_get_devname(p->root_decoder));
26ccd9
+		return -EINVAL;
26ccd9
+	}
26ccd9
+	if (size > max_extent) {
26ccd9
+		log_err(&rl,
26ccd9
+			"%s: region size %#lx exceeds max available space\n",
26ccd9
+			cxl_decoder_get_devname(p->root_decoder), size);
26ccd9
+		return -ENOSPC;
26ccd9
+	}
26ccd9
 
26ccd9
 	if (p->mode == CXL_DECODER_MODE_PMEM) {
26ccd9
 		region = cxl_decoder_create_pmem_region(p->root_decoder);
26ccd9
-- 
26ccd9
2.27.0
26ccd9