|
|
e0018b |
From d25dc6d7956bc022d7e4c4453416c52368df291d Mon Sep 17 00:00:00 2001
|
|
|
e0018b |
From: Vishal Verma <vishal.l.verma@intel.com>
|
|
|
e0018b |
Date: Mon, 15 Aug 2022 13:22:07 -0600
|
|
|
e0018b |
Subject: [PATCH 192/217] libcxl: Introduce libcxl region and mapping objects
|
|
|
e0018b |
|
|
|
e0018b |
Add a cxl_region object to libcxl that represents a CXL region. CXL
|
|
|
e0018b |
regions are made up of one or more cxl_memdev 'targets'. The
|
|
|
e0018b |
relationship between a target and a region is conveyed with a
|
|
|
e0018b |
cxl_memdev_mapping object.
|
|
|
e0018b |
|
|
|
e0018b |
CXL regions are childeren of root decoders, and are organized as such.
|
|
|
e0018b |
Mapping objects are childeren of a CXL region. Introduce the two
|
|
|
e0018b |
classes of objects themselves, and common accessors related to them.
|
|
|
e0018b |
|
|
|
e0018b |
Link: https://lore.kernel.org/r/20220815192214.545800-5-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 |
.clang-format | 2 +
|
|
|
e0018b |
cxl/lib/libcxl.c | 442 ++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
e0018b |
cxl/lib/libcxl.sym | 20 ++
|
|
|
e0018b |
cxl/lib/private.h | 35 ++++
|
|
|
e0018b |
cxl/libcxl.h | 41 +++++
|
|
|
e0018b |
5 files changed, 530 insertions(+), 10 deletions(-)
|
|
|
e0018b |
|
|
|
e0018b |
diff --git a/.clang-format b/.clang-format
|
|
|
e0018b |
index 7254a1b..b6169e1 100644
|
|
|
e0018b |
--- a/.clang-format
|
|
|
e0018b |
+++ b/.clang-format
|
|
|
e0018b |
@@ -86,6 +86,8 @@ ForEachMacros:
|
|
|
e0018b |
- 'cxl_dport_foreach'
|
|
|
e0018b |
- 'cxl_endpoint_foreach'
|
|
|
e0018b |
- 'cxl_port_foreach_all'
|
|
|
e0018b |
+ - 'cxl_region_foreach'
|
|
|
e0018b |
+ - 'cxl_region_foreach_safe'
|
|
|
e0018b |
- 'daxctl_dev_foreach'
|
|
|
e0018b |
- 'daxctl_mapping_foreach'
|
|
|
e0018b |
- 'daxctl_region_foreach'
|
|
|
e0018b |
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
|
|
|
e0018b |
index 145c6ba..ad98188 100644
|
|
|
e0018b |
--- a/cxl/lib/libcxl.c
|
|
|
e0018b |
+++ b/cxl/lib/libcxl.c
|
|
|
e0018b |
@@ -79,6 +79,38 @@ static void free_target(struct cxl_target *target, struct list_head *head)
|
|
|
e0018b |
free(target);
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
+static void free_region(struct cxl_region *region, struct list_head *head)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_memdev_mapping *mapping, *_m;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ list_for_each_safe(®ion->mappings, mapping, _m, list) {
|
|
|
e0018b |
+ list_del_from(®ion->mappings, &mapping->list);
|
|
|
e0018b |
+ free(mapping);
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+ if (head)
|
|
|
e0018b |
+ list_del_from(head, ®ion->list);
|
|
|
e0018b |
+ kmod_module_unref(region->module);
|
|
|
e0018b |
+ free(region->dev_buf);
|
|
|
e0018b |
+ free(region->dev_path);
|
|
|
e0018b |
+ free(region);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static void free_stale_regions(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_region *region, *_r;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ list_for_each_safe(&decoder->stale_regions, region, _r, list)
|
|
|
e0018b |
+ free_region(region, &decoder->stale_regions);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static void free_regions(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_region *region, *_r;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ list_for_each_safe(&decoder->regions, region, _r, list)
|
|
|
e0018b |
+ free_region(region, &decoder->regions);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)
|
|
|
e0018b |
{
|
|
|
e0018b |
struct cxl_target *target, *_t;
|
|
|
e0018b |
@@ -87,6 +119,8 @@ static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)
|
|
|
e0018b |
list_del_from(head, &decoder->list);
|
|
|
e0018b |
list_for_each_safe(&decoder->targets, target, _t, list)
|
|
|
e0018b |
free_target(target, &decoder->targets);
|
|
|
e0018b |
+ free_regions(decoder);
|
|
|
e0018b |
+ free_stale_regions(decoder);
|
|
|
e0018b |
free(decoder->dev_buf);
|
|
|
e0018b |
free(decoder->dev_path);
|
|
|
e0018b |
free(decoder);
|
|
|
e0018b |
@@ -304,6 +338,402 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)
|
|
|
e0018b |
ctx->ctx.log_priority = priority;
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
+static int is_enabled(const char *drvpath)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct stat st;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode))
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ return 1;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_is_enabled(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ int len = region->buf_len;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/driver", region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", cxl_region_get_devname(region));
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return is_enabled(path);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_disable(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ util_unbind(region->dev_path, ctx);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (cxl_region_is_enabled(region)) {
|
|
|
e0018b |
+ err(ctx, "%s: failed to disable\n", devname);
|
|
|
e0018b |
+ return -EBUSY;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ dbg(ctx, "%s: disabled\n", devname);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_enable(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ int len = region->buf_len;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+ u64 resource = ULLONG_MAX;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (cxl_region_is_enabled(region))
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ util_bind(devname, region->module, "cxl", ctx);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (!cxl_region_is_enabled(region)) {
|
|
|
e0018b |
+ err(ctx, "%s: failed to enable\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /*
|
|
|
e0018b |
+ * Currently 'resource' is the only attr that may change after enabling.
|
|
|
e0018b |
+ * Just refresh it here. If there are additional resources that need
|
|
|
e0018b |
+ * to be refreshed here later, split these out into a common helper
|
|
|
e0018b |
+ * for this and add_cxl_region()
|
|
|
e0018b |
+ */
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/resource", region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) == 0)
|
|
|
e0018b |
+ resource = strtoull(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (resource < ULLONG_MAX)
|
|
|
e0018b |
+ region->start = resource;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ dbg(ctx, "%s: enabled\n", devname);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
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 |
+ char *path = calloc(1, strlen(cxlregion_base) + 100);
|
|
|
e0018b |
+ struct cxl_region *region, *region_dup, *_r;
|
|
|
e0018b |
+ struct cxl_decoder *decoder = parent;
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+ u64 resource = ULLONG_MAX;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ dbg(ctx, "%s: base: \'%s\'\n", devname, cxlregion_base);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (!path)
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region = calloc(1, sizeof(*region));
|
|
|
e0018b |
+ if (!region)
|
|
|
e0018b |
+ goto err;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->id = id;
|
|
|
e0018b |
+ region->ctx = ctx;
|
|
|
e0018b |
+ region->decoder = decoder;
|
|
|
e0018b |
+ list_head_init(®ion->mappings);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->dev_path = strdup(cxlregion_base);
|
|
|
e0018b |
+ if (!region->dev_path)
|
|
|
e0018b |
+ goto err;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->dev_buf = calloc(1, strlen(cxlregion_base) + 50);
|
|
|
e0018b |
+ if (!region->dev_buf)
|
|
|
e0018b |
+ goto err;
|
|
|
e0018b |
+ region->buf_len = strlen(cxlregion_base) + 50;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/size", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ region->size = ULLONG_MAX;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ region->size = strtoull(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/resource", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) == 0)
|
|
|
e0018b |
+ resource = strtoull(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (resource < ULLONG_MAX)
|
|
|
e0018b |
+ region->start = resource;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/uuid", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ goto err;
|
|
|
e0018b |
+ if (strlen(buf) && uuid_parse(buf, region->uuid) < 0) {
|
|
|
e0018b |
+ dbg(ctx, "%s:%s\n", path, buf);
|
|
|
e0018b |
+ goto err;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/interleave_granularity", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ region->interleave_granularity = UINT_MAX;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ region->interleave_granularity = strtoul(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/interleave_ways", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ region->interleave_ways = UINT_MAX;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ region->interleave_ways = strtoul(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/commit", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ region->decode_state = CXL_DECODE_UNKNOWN;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ region->decode_state = strtoul(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/modalias", cxlregion_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) == 0)
|
|
|
e0018b |
+ region->module = util_modalias_to_module(ctx, buf);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ cxl_region_foreach_safe(decoder, region_dup, _r)
|
|
|
e0018b |
+ if (region_dup->id == region->id) {
|
|
|
e0018b |
+ list_del_from(&decoder->regions, ®ion_dup->list);
|
|
|
e0018b |
+ list_add_tail(&decoder->stale_regions,
|
|
|
e0018b |
+ ®ion_dup->list);
|
|
|
e0018b |
+ break;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ list_add(&decoder->regions, ®ion->list);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return region;
|
|
|
e0018b |
+err:
|
|
|
e0018b |
+ free(region->dev_path);
|
|
|
e0018b |
+ free(region->dev_buf);
|
|
|
e0018b |
+ free(region);
|
|
|
e0018b |
+ free(path);
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static void cxl_regions_init(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_port *port = cxl_decoder_get_port(decoder);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (decoder->regions_init)
|
|
|
e0018b |
+ return;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /* Only root port decoders may have child regions */
|
|
|
e0018b |
+ if (!cxl_port_is_root(port))
|
|
|
e0018b |
+ return;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ decoder->regions_init = 1;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sysfs_device_parse(ctx, decoder->dev_path, "region", decoder,
|
|
|
e0018b |
+ add_cxl_region);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ cxl_regions_init(decoder);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return list_top(&decoder->regions, struct cxl_region, list);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_region *cxl_region_get_next(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_decoder *decoder = region->decoder;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return list_next(&decoder->regions, region, list);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->ctx;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->decoder;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_get_id(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->id;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT const char *cxl_region_get_devname(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return devpath_to_devname(region->dev_path);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ memcpy(uu, region->uuid, sizeof(uuid_t));
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT unsigned long long cxl_region_get_size(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->size;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT unsigned long long cxl_region_get_resource(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->start;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT unsigned int
|
|
|
e0018b |
+cxl_region_get_interleave_ways(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->interleave_ways;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_decode_is_committed(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return (region->decode_state == CXL_DECODE_COMMIT) ? 1 : 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT unsigned int
|
|
|
e0018b |
+cxl_region_get_interleave_granularity(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return region->interleave_granularity;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static struct cxl_decoder *__cxl_port_match_decoder(struct cxl_port *port,
|
|
|
e0018b |
+ const char *ident)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ cxl_decoder_foreach(port, decoder)
|
|
|
e0018b |
+ if (strcmp(cxl_decoder_get_devname(decoder), ident) == 0)
|
|
|
e0018b |
+ return decoder;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static struct cxl_decoder *cxl_port_find_decoder(struct cxl_port *port,
|
|
|
e0018b |
+ const char *ident)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+ struct cxl_endpoint *ep;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /* First, check decoders directly under @port */
|
|
|
e0018b |
+ decoder = __cxl_port_match_decoder(port, ident);
|
|
|
e0018b |
+ if (decoder)
|
|
|
e0018b |
+ return decoder;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /* Next, iterate over the endpoints under @port */
|
|
|
e0018b |
+ cxl_endpoint_foreach(port, ep) {
|
|
|
e0018b |
+ decoder = __cxl_port_match_decoder(cxl_endpoint_get_port(ep),
|
|
|
e0018b |
+ ident);
|
|
|
e0018b |
+ if (decoder)
|
|
|
e0018b |
+ return decoder;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,
|
|
|
e0018b |
+ const char *ident)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_bus *bus;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ cxl_bus_foreach(ctx, bus) {
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+ struct cxl_port *port, *top;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ port = cxl_bus_get_port(bus);
|
|
|
e0018b |
+ decoder = cxl_port_find_decoder(port, ident);
|
|
|
e0018b |
+ if (decoder)
|
|
|
e0018b |
+ return decoder;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ top = port;
|
|
|
e0018b |
+ cxl_port_foreach_all (top, port) {
|
|
|
e0018b |
+ decoder = cxl_port_find_decoder(port, ident);
|
|
|
e0018b |
+ if (decoder)
|
|
|
e0018b |
+ return decoder;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static void cxl_mappings_init(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ char *mapping_path, buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+ unsigned int i;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (region->mappings_init)
|
|
|
e0018b |
+ return;
|
|
|
e0018b |
+ region->mappings_init = 1;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ mapping_path = calloc(1, strlen(region->dev_path) + 100);
|
|
|
e0018b |
+ if (!mapping_path) {
|
|
|
e0018b |
+ err(ctx, "%s: allocation failure\n", devname);
|
|
|
e0018b |
+ return;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ for (i = 0; i < region->interleave_ways; i++) {
|
|
|
e0018b |
+ struct cxl_memdev_mapping *mapping;
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(mapping_path, "%s/target%d", region->dev_path, i);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, mapping_path, buf) < 0) {
|
|
|
e0018b |
+ err(ctx, "%s: failed to read target%d\n", devname, i);
|
|
|
e0018b |
+ continue;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ decoder = cxl_decoder_get_by_name(ctx, buf);
|
|
|
e0018b |
+ if (!decoder) {
|
|
|
e0018b |
+ err(ctx, "%s target%d: %s lookup failure\n",
|
|
|
e0018b |
+ devname, i, buf);
|
|
|
e0018b |
+ continue;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ mapping = calloc(1, sizeof(*mapping));
|
|
|
e0018b |
+ if (!mapping) {
|
|
|
e0018b |
+ err(ctx, "%s target%d: allocation failure\n", devname, i);
|
|
|
e0018b |
+ continue;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ mapping->region = region;
|
|
|
e0018b |
+ mapping->decoder = decoder;
|
|
|
e0018b |
+ mapping->position = i;
|
|
|
e0018b |
+ list_add(®ion->mappings, &mapping->list);
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+ free(mapping_path);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_memdev_mapping *
|
|
|
e0018b |
+cxl_mapping_get_first(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ cxl_mappings_init(region);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return list_top(®ion->mappings, struct cxl_memdev_mapping, list);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_memdev_mapping *
|
|
|
e0018b |
+cxl_mapping_get_next(struct cxl_memdev_mapping *mapping)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_region *region = mapping->region;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return list_next(®ion->mappings, mapping, list);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_decoder *
|
|
|
e0018b |
+cxl_mapping_get_decoder(struct cxl_memdev_mapping *mapping)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return mapping->decoder;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT unsigned int
|
|
|
e0018b |
+cxl_mapping_get_position(struct cxl_memdev_mapping *mapping)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return mapping->position;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
static void *add_cxl_pmem(void *parent, int id, const char *br_base)
|
|
|
e0018b |
{
|
|
|
e0018b |
const char *devname = devpath_to_devname(br_base);
|
|
|
e0018b |
@@ -681,16 +1111,6 @@ CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)
|
|
|
e0018b |
return memdev->lsa_size;
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
-static int is_enabled(const char *drvpath)
|
|
|
e0018b |
-{
|
|
|
e0018b |
- struct stat st;
|
|
|
e0018b |
-
|
|
|
e0018b |
- if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode))
|
|
|
e0018b |
- return 0;
|
|
|
e0018b |
- else
|
|
|
e0018b |
- return 1;
|
|
|
e0018b |
-}
|
|
|
e0018b |
-
|
|
|
e0018b |
CXL_EXPORT int cxl_memdev_is_enabled(struct cxl_memdev *memdev)
|
|
|
e0018b |
{
|
|
|
e0018b |
struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
|
|
|
e0018b |
@@ -940,6 +1360,8 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
|
|
|
e0018b |
decoder->ctx = ctx;
|
|
|
e0018b |
decoder->port = port;
|
|
|
e0018b |
list_head_init(&decoder->targets);
|
|
|
e0018b |
+ list_head_init(&decoder->regions);
|
|
|
e0018b |
+ list_head_init(&decoder->stale_regions);
|
|
|
e0018b |
|
|
|
e0018b |
decoder->dev_path = strdup(cxldecoder_base);
|
|
|
e0018b |
if (!decoder->dev_path)
|
|
|
e0018b |
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
|
|
|
e0018b |
index 7712de0..e410298 100644
|
|
|
e0018b |
--- a/cxl/lib/libcxl.sym
|
|
|
e0018b |
+++ b/cxl/lib/libcxl.sym
|
|
|
e0018b |
@@ -177,4 +177,24 @@ global:
|
|
|
e0018b |
cxl_decoder_get_prev;
|
|
|
e0018b |
cxl_decoder_set_dpa_size;
|
|
|
e0018b |
cxl_decoder_set_mode;
|
|
|
e0018b |
+ cxl_region_get_first;
|
|
|
e0018b |
+ cxl_region_get_next;
|
|
|
e0018b |
+ cxl_region_decode_is_committed;
|
|
|
e0018b |
+ cxl_region_is_enabled;
|
|
|
e0018b |
+ cxl_region_disable;
|
|
|
e0018b |
+ cxl_region_enable;
|
|
|
e0018b |
+ cxl_region_get_ctx;
|
|
|
e0018b |
+ cxl_region_get_decoder;
|
|
|
e0018b |
+ cxl_region_get_id;
|
|
|
e0018b |
+ cxl_region_get_devname;
|
|
|
e0018b |
+ cxl_region_get_uuid;
|
|
|
e0018b |
+ cxl_region_get_size;
|
|
|
e0018b |
+ cxl_region_get_resource;
|
|
|
e0018b |
+ cxl_region_get_interleave_ways;
|
|
|
e0018b |
+ cxl_region_get_interleave_granularity;
|
|
|
e0018b |
+ cxl_mapping_get_first;
|
|
|
e0018b |
+ cxl_mapping_get_next;
|
|
|
e0018b |
+ cxl_mapping_get_decoder;
|
|
|
e0018b |
+ cxl_mapping_get_region;
|
|
|
e0018b |
+ cxl_mapping_get_position;
|
|
|
e0018b |
} LIBCXL_2;
|
|
|
e0018b |
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
|
|
|
e0018b |
index 832a815..5e2fdd5 100644
|
|
|
e0018b |
--- a/cxl/lib/private.h
|
|
|
e0018b |
+++ b/cxl/lib/private.h
|
|
|
e0018b |
@@ -116,7 +116,42 @@ struct cxl_decoder {
|
|
|
e0018b |
bool accelmem_capable;
|
|
|
e0018b |
bool locked;
|
|
|
e0018b |
enum cxl_decoder_target_type target_type;
|
|
|
e0018b |
+ int regions_init;
|
|
|
e0018b |
struct list_head targets;
|
|
|
e0018b |
+ struct list_head regions;
|
|
|
e0018b |
+ struct list_head stale_regions;
|
|
|
e0018b |
+};
|
|
|
e0018b |
+
|
|
|
e0018b |
+enum cxl_decode_state {
|
|
|
e0018b |
+ CXL_DECODE_UNKNOWN = -1,
|
|
|
e0018b |
+ CXL_DECODE_RESET = 0,
|
|
|
e0018b |
+ CXL_DECODE_COMMIT,
|
|
|
e0018b |
+};
|
|
|
e0018b |
+
|
|
|
e0018b |
+struct cxl_region {
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+ struct list_node list;
|
|
|
e0018b |
+ int mappings_init;
|
|
|
e0018b |
+ struct cxl_ctx *ctx;
|
|
|
e0018b |
+ void *dev_buf;
|
|
|
e0018b |
+ size_t buf_len;
|
|
|
e0018b |
+ char *dev_path;
|
|
|
e0018b |
+ int id;
|
|
|
e0018b |
+ uuid_t uuid;
|
|
|
e0018b |
+ u64 start;
|
|
|
e0018b |
+ u64 size;
|
|
|
e0018b |
+ unsigned int interleave_ways;
|
|
|
e0018b |
+ unsigned int interleave_granularity;
|
|
|
e0018b |
+ enum cxl_decode_state decode_state;
|
|
|
e0018b |
+ struct kmod_module *module;
|
|
|
e0018b |
+ struct list_head mappings;
|
|
|
e0018b |
+};
|
|
|
e0018b |
+
|
|
|
e0018b |
+struct cxl_memdev_mapping {
|
|
|
e0018b |
+ struct cxl_region *region;
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+ unsigned int position;
|
|
|
e0018b |
+ struct list_node list;
|
|
|
e0018b |
};
|
|
|
e0018b |
|
|
|
e0018b |
enum cxl_cmd_query_status {
|
|
|
e0018b |
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
|
|
|
e0018b |
index c1f8d14..19d94e4 100644
|
|
|
e0018b |
--- a/cxl/libcxl.h
|
|
|
e0018b |
+++ b/cxl/libcxl.h
|
|
|
e0018b |
@@ -237,6 +237,47 @@ int cxl_memdev_is_enabled(struct cxl_memdev *memdev);
|
|
|
e0018b |
for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
|
|
|
e0018b |
endpoint = cxl_endpoint_get_next(endpoint))
|
|
|
e0018b |
|
|
|
e0018b |
+struct cxl_region;
|
|
|
e0018b |
+struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder);
|
|
|
e0018b |
+struct cxl_region *cxl_region_get_next(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_decode_is_committed(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_is_enabled(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_disable(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_enable(struct cxl_region *region);
|
|
|
e0018b |
+struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region);
|
|
|
e0018b |
+struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_get_id(struct cxl_region *region);
|
|
|
e0018b |
+const char *cxl_region_get_devname(struct cxl_region *region);
|
|
|
e0018b |
+void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu);
|
|
|
e0018b |
+unsigned long long cxl_region_get_size(struct cxl_region *region);
|
|
|
e0018b |
+unsigned long long cxl_region_get_resource(struct cxl_region *region);
|
|
|
e0018b |
+unsigned int cxl_region_get_interleave_ways(struct cxl_region *region);
|
|
|
e0018b |
+unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region);
|
|
|
e0018b |
+
|
|
|
e0018b |
+#define cxl_region_foreach(decoder, region) \
|
|
|
e0018b |
+ for (region = cxl_region_get_first(decoder); region != NULL; \
|
|
|
e0018b |
+ region = cxl_region_get_next(region))
|
|
|
e0018b |
+
|
|
|
e0018b |
+#define cxl_region_foreach_safe(decoder, region, _region) \
|
|
|
e0018b |
+ for (region = cxl_region_get_first(decoder), \
|
|
|
e0018b |
+ _region = region ? cxl_region_get_next(region) : NULL; \
|
|
|
e0018b |
+ region != NULL; \
|
|
|
e0018b |
+ region = _region, \
|
|
|
e0018b |
+ _region = _region ? cxl_region_get_next(_region) : NULL)
|
|
|
e0018b |
+
|
|
|
e0018b |
+struct cxl_memdev_mapping;
|
|
|
e0018b |
+struct cxl_memdev_mapping *cxl_mapping_get_first(struct cxl_region *region);
|
|
|
e0018b |
+struct cxl_memdev_mapping *
|
|
|
e0018b |
+cxl_mapping_get_next(struct cxl_memdev_mapping *mapping);
|
|
|
e0018b |
+struct cxl_decoder *cxl_mapping_get_decoder(struct cxl_memdev_mapping *mapping);
|
|
|
e0018b |
+struct cxl_region *cxl_mapping_get_region(struct cxl_memdev_mapping *mapping);
|
|
|
e0018b |
+unsigned int cxl_mapping_get_position(struct cxl_memdev_mapping *mapping);
|
|
|
e0018b |
+
|
|
|
e0018b |
+#define cxl_mapping_foreach(region, mapping) \
|
|
|
e0018b |
+ for (mapping = cxl_mapping_get_first(region); \
|
|
|
e0018b |
+ mapping != NULL; \
|
|
|
e0018b |
+ mapping = cxl_mapping_get_next(mapping))
|
|
|
e0018b |
+
|
|
|
e0018b |
struct cxl_cmd;
|
|
|
e0018b |
const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);
|
|
|
e0018b |
struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
|
|
|
e0018b |
--
|
|
|
e0018b |
2.27.0
|
|
|
e0018b |
|