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

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