@@ -105,6 +105,12 @@ include::bus-option.txt[]
supplied, the first cross-host bridge (if available), decoder that
supports the largest interleave will be chosen.
+-Q::
+--enforce-qos::
+ Parameter to enforce qos_class mismatch failure. Region create operation
+ will fail of the qos_class of the root decoder and one of the memdev that
+ backs the region mismatches.
+
include::human-option.txt[]
include::debug-option.txt[]
@@ -1238,6 +1238,12 @@ struct json_object *util_cxl_region_to_json(struct cxl_region *region,
}
}
+ if (cxl_region_qos_class_mismatch(region)) {
+ jobj = json_object_new_boolean(true);
+ if (jobj)
+ json_object_object_add(jregion, "qos_class_mismatch", jobj);
+ }
+
json_object_set_userdata(jregion, region, NULL);
@@ -414,6 +414,35 @@ CXL_EXPORT int cxl_region_is_enabled(struct cxl_region *region)
return is_enabled(path);
}
+CXL_EXPORT bool cxl_region_qos_class_mismatch(struct cxl_region *region)
+{
+ struct cxl_decoder *root_decoder = cxl_region_get_decoder(region);
+ struct cxl_memdev_mapping *mapping;
+
+ cxl_mapping_foreach(region, mapping) {
+ struct cxl_decoder *decoder;
+ struct cxl_memdev *memdev;
+
+ decoder = cxl_mapping_get_decoder(mapping);
+ if (!decoder)
+ continue;
+
+ memdev = cxl_decoder_get_memdev(decoder);
+ if (!memdev)
+ continue;
+
+ if (region->mode == CXL_DECODER_MODE_RAM) {
+ if (root_decoder->qos_class != memdev->ram_qos_class)
+ return true;
+ } else if (region->mode == CXL_DECODER_MODE_PMEM) {
+ if (root_decoder->qos_class != memdev->pmem_qos_class)
+ return true;
+ }
+ }
+
+ return false;
+}
+
CXL_EXPORT int cxl_region_disable(struct cxl_region *region)
{
const char *devname = cxl_region_get_devname(region);
@@ -285,4 +285,5 @@ global:
cxl_root_decoder_get_qos_class;
cxl_memdev_get_pmem_qos_class;
cxl_memdev_get_ram_qos_class;
+ cxl_region_qos_class_mismatch;
} LIBCXL_7;
@@ -335,6 +335,7 @@ int cxl_region_clear_target(struct cxl_region *region, int position);
int cxl_region_clear_all_targets(struct cxl_region *region);
int cxl_region_decode_commit(struct cxl_region *region);
int cxl_region_decode_reset(struct cxl_region *region);
+bool cxl_region_qos_class_mismatch(struct cxl_region *region);
#define cxl_region_foreach(decoder, region) \
for (region = cxl_region_get_first(decoder); region != NULL; \
@@ -32,6 +32,7 @@ static struct region_params {
bool force;
bool human;
bool debug;
+ bool enforce_qos;
} param = {
.ways = INT_MAX,
.granularity = INT_MAX,
@@ -49,6 +50,7 @@ struct parsed_params {
const char **argv;
struct cxl_decoder *root_decoder;
enum cxl_decoder_mode mode;
+ bool enforce_qos;
};
enum region_actions {
@@ -81,7 +83,8 @@ OPT_STRING('U', "uuid", ¶m.uuid, \
"region uuid", "uuid for the new region (default: autogenerate)"), \
OPT_BOOLEAN('m', "memdevs", ¶m.memdevs, \
"non-option arguments are memdevs"), \
-OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats")
+OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats"), \
+OPT_BOOLEAN('Q', "enforce-qos", ¶m.enforce_qos, "enforce of qos_class matching")
static const struct option create_options[] = {
BASE_OPTIONS(),
@@ -360,6 +363,8 @@ static int parse_create_options(struct cxl_ctx *ctx, int count,
}
}
+ p->enforce_qos = param.enforce_qos;
+
return 0;
err:
@@ -423,10 +428,52 @@ static void collect_minsize(struct cxl_ctx *ctx, struct parsed_params *p)
}
}
+static int create_region_validate_qos_class(struct parsed_params *p)
+{
+ int root_qos_class;
+ int qos_class;
+ int i;
+
+ if (!p->enforce_qos)
+ return 0;
+
+ root_qos_class = cxl_root_decoder_get_qos_class(p->root_decoder);
+ if (root_qos_class == CXL_QOS_CLASS_NONE)
+ return 0;
+
+ for (i = 0; i < p->ways; i++) {
+ struct json_object *jobj =
+ json_object_array_get_idx(p->memdevs, i);
+ struct cxl_memdev *memdev = json_object_get_userdata(jobj);
+
+ if (p->mode == CXL_DECODER_MODE_RAM)
+ qos_class = cxl_memdev_get_ram_qos_class(memdev);
+ else
+ qos_class = cxl_memdev_get_pmem_qos_class(memdev);
+
+ /* No qos_class entries. Possibly no kernel support */
+ if (qos_class == CXL_QOS_CLASS_NONE)
+ break;
+
+ if (qos_class != root_qos_class) {
+ if (p->enforce_qos) {
+ log_err(&rl, "%s qos_class mismatch %s\n",
+ cxl_decoder_get_devname(p->root_decoder),
+ cxl_memdev_get_devname(memdev));
+
+ return -ENXIO;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int validate_decoder(struct cxl_decoder *decoder,
struct parsed_params *p)
{
const char *devname = cxl_decoder_get_devname(decoder);
+ int rc;
switch(p->mode) {
case CXL_DECODER_MODE_RAM:
@@ -446,6 +493,10 @@ static int validate_decoder(struct cxl_decoder *decoder,
return -EINVAL;
}
+ rc = create_region_validate_qos_class(p);
+ if (rc)
+ return rc;
+
/* TODO check if the interleave config is possible under this decoder */
return 0;