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