|
|
e0018b |
From cafe4b2d4970b0d7f2193abb9cb32f58c03cbe3b Mon Sep 17 00:00:00 2001
|
|
|
e0018b |
From: Vishal Verma <vishal.l.verma@intel.com>
|
|
|
e0018b |
Date: Mon, 15 Aug 2022 13:22:09 -0600
|
|
|
e0018b |
Subject: [PATCH 194/217] libcxl: add low level APIs for region creation
|
|
|
e0018b |
|
|
|
e0018b |
Add libcxl APIs to create a region under a given root decoder, and to
|
|
|
e0018b |
set different attributes for the new region. These allow setting the
|
|
|
e0018b |
size, interleave_ways, interleave_granularity, uuid, and the target
|
|
|
e0018b |
devices for the newly minted cxl_region object.
|
|
|
e0018b |
|
|
|
e0018b |
Link: https://lore.kernel.org/r/20220815192214.545800-7-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 |
Documentation/cxl/lib/libcxl.txt | 69 ++++++
|
|
|
e0018b |
cxl/lib/libcxl.c | 381 ++++++++++++++++++++++++++++++-
|
|
|
e0018b |
cxl/lib/libcxl.sym | 16 ++
|
|
|
e0018b |
cxl/lib/private.h | 2 +
|
|
|
e0018b |
cxl/libcxl.h | 23 +-
|
|
|
e0018b |
5 files changed, 488 insertions(+), 3 deletions(-)
|
|
|
e0018b |
|
|
|
e0018b |
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
|
|
|
e0018b |
index 7a38ce4..50b0c9c 100644
|
|
|
e0018b |
--- a/Documentation/cxl/lib/libcxl.txt
|
|
|
e0018b |
+++ b/Documentation/cxl/lib/libcxl.txt
|
|
|
e0018b |
@@ -508,6 +508,75 @@ device to represent the root of a PCI device hierarchy. The
|
|
|
e0018b |
cxl_target_get_physical_node() helper returns the device name of that
|
|
|
e0018b |
companion object in the PCI hierarchy.
|
|
|
e0018b |
|
|
|
e0018b |
+==== REGIONS
|
|
|
e0018b |
+A CXL region is composed of one or more slices of CXL memdevs, with configurable
|
|
|
e0018b |
+interleave settings - both the number of interleave ways, and the interleave
|
|
|
e0018b |
+granularity. In terms of hierarchy, it is the child of a CXL root decoder. A root
|
|
|
e0018b |
+decoder (recall that this corresponds to an ACPI CEDT.CFMWS 'window'), may have
|
|
|
e0018b |
+multiple child regions, but a region is strictly tied to one root decoder.
|
|
|
e0018b |
+
|
|
|
e0018b |
+The slices that compose a region are called mappings. A mapping is a
|
|
|
e0018b |
+tuple of 'memdev', 'endpoint decoder', and the 'position'.
|
|
|
e0018b |
+
|
|
|
e0018b |
+===== REGION: Enumeration
|
|
|
e0018b |
+----
|
|
|
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 |
+
|
|
|
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 |
+
|
|
|
e0018b |
+===== REGION: Attributes
|
|
|
e0018b |
+----
|
|
|
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 |
+struct cxl_decoder *cxl_region_get_target_decoder(struct cxl_region *region,
|
|
|
e0018b |
+ int position);
|
|
|
e0018b |
+int cxl_region_set_size(struct cxl_region *region, unsigned long long size);
|
|
|
e0018b |
+int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu);
|
|
|
e0018b |
+int cxl_region_set_interleave_ways(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned int ways);
|
|
|
e0018b |
+int cxl_region_set_interleave_granularity(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned int granularity);
|
|
|
e0018b |
+int cxl_region_set_target(struct cxl_region *region, int position,
|
|
|
e0018b |
+ struct cxl_decoder *decoder);
|
|
|
e0018b |
+int cxl_region_clear_target(struct cxl_region *region, int position);
|
|
|
e0018b |
+int cxl_region_clear_all_targets(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_decode_commit(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_decode_reset(struct cxl_region *region);
|
|
|
e0018b |
+----
|
|
|
e0018b |
+
|
|
|
e0018b |
+A region's resource attribute is the Host Physical Address at which the region's
|
|
|
e0018b |
+address space starts. The region's address space is a subset of the parent root
|
|
|
e0018b |
+decoder's address space.
|
|
|
e0018b |
+
|
|
|
e0018b |
+The interleave ways is the number of component memdevs participating in the
|
|
|
e0018b |
+region.
|
|
|
e0018b |
+
|
|
|
e0018b |
+The interleave granularity depends on the root decoder's granularity, and must
|
|
|
e0018b |
+follow the interleave math rules defined in the CXL spec.
|
|
|
e0018b |
+
|
|
|
e0018b |
+Regions have a list of targets 0..N, which are programmed with the name of an
|
|
|
e0018b |
+endpoint decoder under each participating memdev.
|
|
|
e0018b |
+
|
|
|
e0018b |
+The 'decode_commit' and 'decode_reset' attributes reserve and free DPA space
|
|
|
e0018b |
+on a given memdev by allocating an endpoint decoder, and programming it based
|
|
|
e0018b |
+on the region's interleave geometry.
|
|
|
e0018b |
+
|
|
|
e0018b |
include::../../copyright.txt[]
|
|
|
e0018b |
|
|
|
e0018b |
SEE ALSO
|
|
|
e0018b |
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
|
|
|
e0018b |
index ad98188..fd2ea4f 100644
|
|
|
e0018b |
--- a/cxl/lib/libcxl.c
|
|
|
e0018b |
+++ b/cxl/lib/libcxl.c
|
|
|
e0018b |
@@ -17,6 +17,7 @@
|
|
|
e0018b |
#include <ccan/minmax/minmax.h>
|
|
|
e0018b |
#include <ccan/array_size/array_size.h>
|
|
|
e0018b |
#include <ccan/short_types/short_types.h>
|
|
|
e0018b |
+#include <ccan/container_of/container_of.h>
|
|
|
e0018b |
|
|
|
e0018b |
#include <util/log.h>
|
|
|
e0018b |
#include <util/list.h>
|
|
|
e0018b |
@@ -420,6 +421,40 @@ CXL_EXPORT int cxl_region_enable(struct cxl_region *region)
|
|
|
e0018b |
return 0;
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
+static int cxl_region_delete_name(struct cxl_decoder *decoder,
|
|
|
e0018b |
+ const char *devname)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
|
|
|
e0018b |
+ char *path = decoder->dev_buf;
|
|
|
e0018b |
+ int rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/delete_region", decoder->dev_path);
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, devname);
|
|
|
e0018b |
+ if (rc != 0) {
|
|
|
e0018b |
+ err(ctx, "error deleting region: %s\n", strerror(-rc));
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_delete(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_decoder *decoder = cxl_region_get_decoder(region);
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ int rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (cxl_region_is_enabled(region))
|
|
|
e0018b |
+ return -EBUSY;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ rc = cxl_region_delete_name(decoder, devname);
|
|
|
e0018b |
+ if (rc != 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ decoder->regions_init = 0;
|
|
|
e0018b |
+ free_region(region, &decoder->regions);
|
|
|
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 |
@@ -599,6 +634,258 @@ cxl_region_get_interleave_granularity(struct cxl_region *region)
|
|
|
e0018b |
return region->interleave_granularity;
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
+CXL_EXPORT struct cxl_decoder *
|
|
|
e0018b |
+cxl_region_get_target_decoder(struct cxl_region *region, int position)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ struct cxl_decoder *decoder;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/target%d", region->dev_path, position) >=
|
|
|
e0018b |
+ len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ rc = sysfs_read_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0) {
|
|
|
e0018b |
+ err(ctx, "%s: error reading target%d: %s\n", devname,
|
|
|
e0018b |
+ position, strerror(-rc));
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ decoder = cxl_decoder_get_by_name(ctx, buf);
|
|
|
e0018b |
+ if (!decoder) {
|
|
|
e0018b |
+ err(ctx, "%s: error locating decoder for target%d\n", devname,
|
|
|
e0018b |
+ position);
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+ return decoder;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_set_size(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned long long size)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (size == 0) {
|
|
|
e0018b |
+ dbg(ctx, "%s: cannot use %s to delete a region\n", __func__,
|
|
|
e0018b |
+ devname);
|
|
|
e0018b |
+ return -EINVAL;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/size", region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(buf, "%#llx\n", size);
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->size = size;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ char uuid[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/uuid", region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ uuid_unparse(uu, uuid);
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, uuid);
|
|
|
e0018b |
+ if (rc != 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+ memcpy(region->uuid, uu, sizeof(uuid_t));
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_set_interleave_ways(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned int ways)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/interleave_ways",
|
|
|
e0018b |
+ region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(buf, "%u\n", ways);
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->interleave_ways = ways;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_set_interleave_granularity(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned int granularity)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/interleave_granularity",
|
|
|
e0018b |
+ region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(buf, "%u\n", granularity);
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->interleave_granularity = granularity;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static int region_write_target(struct cxl_region *region, int position,
|
|
|
e0018b |
+ struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ const char *dec_name = "";
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (decoder)
|
|
|
e0018b |
+ dec_name = cxl_decoder_get_devname(decoder);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/target%d", region->dev_path, position) >=
|
|
|
e0018b |
+ len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, dec_name);
|
|
|
e0018b |
+ if (rc < 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_set_target(struct cxl_region *region, int position,
|
|
|
e0018b |
+ struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ if (!decoder)
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return region_write_target(region, position, decoder);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_clear_target(struct cxl_region *region, int position)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (cxl_region_is_enabled(region)) {
|
|
|
e0018b |
+ err(ctx, "%s: can't clear targets on an active region\n",
|
|
|
e0018b |
+ devname);
|
|
|
e0018b |
+ return -EBUSY;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ rc = region_write_target(region, position, NULL);
|
|
|
e0018b |
+ if (rc) {
|
|
|
e0018b |
+ err(ctx, "%s: error clearing target%d: %s\n",
|
|
|
e0018b |
+ devname, position, strerror(-rc));
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_clear_all_targets(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 |
+ unsigned int ways, i;
|
|
|
e0018b |
+ int rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (cxl_region_is_enabled(region)) {
|
|
|
e0018b |
+ err(ctx, "%s: can't clear targets on an active region\n",
|
|
|
e0018b |
+ devname);
|
|
|
e0018b |
+ return -EBUSY;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ ways = cxl_region_get_interleave_ways(region);
|
|
|
e0018b |
+ if (ways == 0 || ways == UINT_MAX)
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ for (i = 0; i < ways; i++) {
|
|
|
e0018b |
+ rc = region_write_target(region, i, NULL);
|
|
|
e0018b |
+ if (rc) {
|
|
|
e0018b |
+ err(ctx, "%s: error clearing target%d: %s\n",
|
|
|
e0018b |
+ devname, i, strerror(-rc));
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+static int set_region_decode(struct cxl_region *region,
|
|
|
e0018b |
+ enum cxl_decode_state decode_state)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_region_get_ctx(region);
|
|
|
e0018b |
+ int len = region->buf_len, rc;
|
|
|
e0018b |
+ char *path = region->dev_buf;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (snprintf(path, len, "%s/commit", region->dev_path) >= len) {
|
|
|
e0018b |
+ err(ctx, "%s: buffer too small!\n", devname);
|
|
|
e0018b |
+ return -ENXIO;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(buf, "%d\n", decode_state);
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0)
|
|
|
e0018b |
+ return rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ region->decode_state = decode_state;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return 0;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_decode_commit(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return set_region_decode(region, CXL_DECODE_COMMIT);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT int cxl_region_decode_reset(struct cxl_region *region)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return set_region_decode(region, CXL_DECODE_RESET);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
static struct cxl_decoder *__cxl_port_match_decoder(struct cxl_port *port,
|
|
|
e0018b |
const char *ident)
|
|
|
e0018b |
{
|
|
|
e0018b |
@@ -633,8 +920,8 @@ static struct cxl_decoder *cxl_port_find_decoder(struct cxl_port *port,
|
|
|
e0018b |
return NULL;
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
-static struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,
|
|
|
e0018b |
- const char *ident)
|
|
|
e0018b |
+CXL_EXPORT struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,
|
|
|
e0018b |
+ const char *ident)
|
|
|
e0018b |
{
|
|
|
e0018b |
struct cxl_bus *bus;
|
|
|
e0018b |
|
|
|
e0018b |
@@ -1399,6 +1686,18 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
|
|
|
e0018b |
} else
|
|
|
e0018b |
decoder->mode = CXL_DECODER_MODE_NONE;
|
|
|
e0018b |
|
|
|
e0018b |
+ sprintf(path, "%s/interleave_granularity", cxldecoder_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ decoder->interleave_granularity = UINT_MAX;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ decoder->interleave_granularity = strtoul(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/interleave_ways", cxldecoder_base);
|
|
|
e0018b |
+ if (sysfs_read_attr(ctx, path, buf) < 0)
|
|
|
e0018b |
+ decoder->interleave_ways = UINT_MAX;
|
|
|
e0018b |
+ else
|
|
|
e0018b |
+ decoder->interleave_ways = strtoul(buf, NULL, 0);
|
|
|
e0018b |
+
|
|
|
e0018b |
switch (port->type) {
|
|
|
e0018b |
case CXL_PORT_ENDPOINT:
|
|
|
e0018b |
sprintf(path, "%s/dpa_resource", cxldecoder_base);
|
|
|
e0018b |
@@ -1731,6 +2030,66 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder)
|
|
|
e0018b |
return decoder->locked;
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
+CXL_EXPORT unsigned int
|
|
|
e0018b |
+cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return decoder->interleave_granularity;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT unsigned int
|
|
|
e0018b |
+cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ return decoder->interleave_ways;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
+CXL_EXPORT struct cxl_region *
|
|
|
e0018b |
+cxl_decoder_create_pmem_region(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
|
|
|
e0018b |
+ char *path = decoder->dev_buf;
|
|
|
e0018b |
+ char buf[SYSFS_ATTR_SIZE];
|
|
|
e0018b |
+ struct cxl_region *region;
|
|
|
e0018b |
+ int rc;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ sprintf(path, "%s/create_pmem_region", decoder->dev_path);
|
|
|
e0018b |
+ rc = sysfs_read_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0) {
|
|
|
e0018b |
+ err(ctx, "failed to read new region name: %s\n",
|
|
|
e0018b |
+ strerror(-rc));
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ rc = sysfs_write_attr(ctx, path, buf);
|
|
|
e0018b |
+ if (rc < 0) {
|
|
|
e0018b |
+ err(ctx, "failed to write new region name: %s\n",
|
|
|
e0018b |
+ strerror(-rc));
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /* Force a re-init of regions so that the new one can be discovered */
|
|
|
e0018b |
+ decoder->regions_init = 0;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /* create_region was successful, walk to the new region */
|
|
|
e0018b |
+ cxl_region_foreach(decoder, region) {
|
|
|
e0018b |
+ const char *devname = cxl_region_get_devname(region);
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (strcmp(devname, buf) == 0)
|
|
|
e0018b |
+ goto found;
|
|
|
e0018b |
+ }
|
|
|
e0018b |
+
|
|
|
e0018b |
+ /*
|
|
|
e0018b |
+ * If walking to the region we just created failed, something has gone
|
|
|
e0018b |
+ * very wrong. Attempt to delete it to avoid leaving a dangling region
|
|
|
e0018b |
+ * id behind.
|
|
|
e0018b |
+ */
|
|
|
e0018b |
+ err(ctx, "failed to add new region to libcxl\n");
|
|
|
e0018b |
+ cxl_region_delete_name(decoder, buf);
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ found:
|
|
|
e0018b |
+ return region;
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder)
|
|
|
e0018b |
{
|
|
|
e0018b |
return decoder->nr_targets;
|
|
|
e0018b |
@@ -1741,6 +2100,24 @@ CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder)
|
|
|
e0018b |
return devpath_to_devname(decoder->dev_path);
|
|
|
e0018b |
}
|
|
|
e0018b |
|
|
|
e0018b |
+CXL_EXPORT struct cxl_memdev *
|
|
|
e0018b |
+cxl_decoder_get_memdev(struct cxl_decoder *decoder)
|
|
|
e0018b |
+{
|
|
|
e0018b |
+ struct cxl_port *port = cxl_decoder_get_port(decoder);
|
|
|
e0018b |
+ struct cxl_endpoint *ep;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ if (!port)
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+ if (!cxl_port_is_endpoint(port))
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ ep = container_of(port, struct cxl_endpoint, port);
|
|
|
e0018b |
+ if (!ep)
|
|
|
e0018b |
+ return NULL;
|
|
|
e0018b |
+
|
|
|
e0018b |
+ return cxl_endpoint_get_memdev(ep);
|
|
|
e0018b |
+}
|
|
|
e0018b |
+
|
|
|
e0018b |
CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder)
|
|
|
e0018b |
{
|
|
|
e0018b |
return list_top(&decoder->targets, struct cxl_target, list);
|
|
|
e0018b |
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
|
|
|
e0018b |
index e410298..cb23a0b 100644
|
|
|
e0018b |
--- a/cxl/lib/libcxl.sym
|
|
|
e0018b |
+++ b/cxl/lib/libcxl.sym
|
|
|
e0018b |
@@ -140,6 +140,7 @@ global:
|
|
|
e0018b |
cxl_decoder_is_mem_capable;
|
|
|
e0018b |
cxl_decoder_is_accelmem_capable;
|
|
|
e0018b |
cxl_decoder_is_locked;
|
|
|
e0018b |
+ cxl_decoder_create_pmem_region;
|
|
|
e0018b |
cxl_target_get_first;
|
|
|
e0018b |
cxl_target_get_next;
|
|
|
e0018b |
cxl_target_get_decoder;
|
|
|
e0018b |
@@ -183,6 +184,7 @@ global:
|
|
|
e0018b |
cxl_region_is_enabled;
|
|
|
e0018b |
cxl_region_disable;
|
|
|
e0018b |
cxl_region_enable;
|
|
|
e0018b |
+ cxl_region_delete;
|
|
|
e0018b |
cxl_region_get_ctx;
|
|
|
e0018b |
cxl_region_get_decoder;
|
|
|
e0018b |
cxl_region_get_id;
|
|
|
e0018b |
@@ -192,9 +194,23 @@ global:
|
|
|
e0018b |
cxl_region_get_resource;
|
|
|
e0018b |
cxl_region_get_interleave_ways;
|
|
|
e0018b |
cxl_region_get_interleave_granularity;
|
|
|
e0018b |
+ cxl_region_get_target_decoder;
|
|
|
e0018b |
+ cxl_region_set_size;
|
|
|
e0018b |
+ cxl_region_set_uuid;
|
|
|
e0018b |
+ cxl_region_set_interleave_ways;
|
|
|
e0018b |
+ cxl_region_set_interleave_granularity;
|
|
|
e0018b |
+ cxl_region_set_target;
|
|
|
e0018b |
+ cxl_region_clear_target;
|
|
|
e0018b |
+ cxl_region_clear_all_targets;
|
|
|
e0018b |
+ cxl_region_decode_commit;
|
|
|
e0018b |
+ cxl_region_decode_reset;
|
|
|
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 |
+ cxl_decoder_get_by_name;
|
|
|
e0018b |
+ cxl_decoder_get_memdev;
|
|
|
e0018b |
+ cxl_decoder_get_interleave_granularity;
|
|
|
e0018b |
+ cxl_decoder_get_interleave_ways;
|
|
|
e0018b |
} LIBCXL_2;
|
|
|
e0018b |
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
|
|
|
e0018b |
index 5e2fdd5..8bc9620 100644
|
|
|
e0018b |
--- a/cxl/lib/private.h
|
|
|
e0018b |
+++ b/cxl/lib/private.h
|
|
|
e0018b |
@@ -110,6 +110,8 @@ struct cxl_decoder {
|
|
|
e0018b |
int nr_targets;
|
|
|
e0018b |
int id;
|
|
|
e0018b |
enum cxl_decoder_mode mode;
|
|
|
e0018b |
+ unsigned int interleave_ways;
|
|
|
e0018b |
+ unsigned int interleave_granularity;
|
|
|
e0018b |
bool pmem_capable;
|
|
|
e0018b |
bool volatile_capable;
|
|
|
e0018b |
bool mem_capable;
|
|
|
e0018b |
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
|
|
|
e0018b |
index 19d94e4..69d9c09 100644
|
|
|
e0018b |
--- a/cxl/libcxl.h
|
|
|
e0018b |
+++ b/cxl/libcxl.h
|
|
|
e0018b |
@@ -195,7 +195,13 @@ bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder);
|
|
|
e0018b |
bool cxl_decoder_is_mem_capable(struct cxl_decoder *decoder);
|
|
|
e0018b |
bool cxl_decoder_is_accelmem_capable(struct cxl_decoder *decoder);
|
|
|
e0018b |
bool cxl_decoder_is_locked(struct cxl_decoder *decoder);
|
|
|
e0018b |
-
|
|
|
e0018b |
+unsigned int
|
|
|
e0018b |
+cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder);
|
|
|
e0018b |
+unsigned int cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder);
|
|
|
e0018b |
+struct cxl_region *cxl_decoder_create_pmem_region(struct cxl_decoder *decoder);
|
|
|
e0018b |
+struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,
|
|
|
e0018b |
+ const char *ident);
|
|
|
e0018b |
+struct cxl_memdev *cxl_decoder_get_memdev(struct cxl_decoder *decoder);
|
|
|
e0018b |
#define cxl_decoder_foreach(port, decoder) \
|
|
|
e0018b |
for (decoder = cxl_decoder_get_first(port); decoder != NULL; \
|
|
|
e0018b |
decoder = cxl_decoder_get_next(decoder))
|
|
|
e0018b |
@@ -244,6 +250,7 @@ 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 |
+int cxl_region_delete(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 |
@@ -253,6 +260,20 @@ 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 |
+struct cxl_decoder *cxl_region_get_target_decoder(struct cxl_region *region,
|
|
|
e0018b |
+ int position);
|
|
|
e0018b |
+int cxl_region_set_size(struct cxl_region *region, unsigned long long size);
|
|
|
e0018b |
+int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu);
|
|
|
e0018b |
+int cxl_region_set_interleave_ways(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned int ways);
|
|
|
e0018b |
+int cxl_region_set_interleave_granularity(struct cxl_region *region,
|
|
|
e0018b |
+ unsigned int granularity);
|
|
|
e0018b |
+int cxl_region_set_target(struct cxl_region *region, int position,
|
|
|
e0018b |
+ struct cxl_decoder *decoder);
|
|
|
e0018b |
+int cxl_region_clear_target(struct cxl_region *region, int position);
|
|
|
e0018b |
+int cxl_region_clear_all_targets(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_decode_commit(struct cxl_region *region);
|
|
|
e0018b |
+int cxl_region_decode_reset(struct cxl_region *region);
|
|
|
e0018b |
|
|
|
e0018b |
#define cxl_region_foreach(decoder, region) \
|
|
|
e0018b |
for (region = cxl_region_get_first(decoder); region != NULL; \
|
|
|
e0018b |
--
|
|
|
e0018b |
2.27.0
|
|
|
e0018b |
|