@@ -105,6 +105,15 @@ include::bus-option.txt[]
supplied, the first cross-host bridge (if available), decoder that
supports the largest interleave will be chosen.
+-e::
+--strict::
+ Enforce strict execution where any potential error will force failure.
+ For example, if QTG ID mismatches will cause failure.
+
+-q::
+--no-enforce-qtg::
+ Parameter to bypass QTG ID mismatch failure. Will only emit warning.
+
include::human-option.txt[]
include::debug-option.txt[]
@@ -31,6 +31,8 @@ static struct region_params {
bool force;
bool human;
bool debug;
+ bool strict;
+ bool no_qtg;
} param = {
.ways = INT_MAX,
.granularity = INT_MAX,
@@ -48,6 +50,8 @@ struct parsed_params {
const char **argv;
struct cxl_decoder *root_decoder;
enum cxl_decoder_mode mode;
+ bool strict;
+ bool no_qtg;
};
enum region_actions {
@@ -80,7 +84,9 @@ 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('e', "strict", ¶m.strict, "strict execution enforcement"), \
+OPT_BOOLEAN('q', "no-enforce-qtg", ¶m.no_qtg, "no enforce of QTG ID")
static const struct option create_options[] = {
BASE_OPTIONS(),
@@ -357,6 +363,9 @@ static int parse_create_options(struct cxl_ctx *ctx, int count,
}
}
+ p->strict = param.strict;
+ p->no_qtg = param.no_qtg;
+
return 0;
}
@@ -460,6 +469,50 @@ static void set_type_from_decoder(struct cxl_ctx *ctx, struct parsed_params *p)
p->mode = CXL_DECODER_MODE_PMEM;
}
+static int create_region_validate_qtg_id(struct cxl_ctx *ctx,
+ struct parsed_params *p)
+{
+ int root_qtg_id, dev_qtg_id, i;
+
+ root_qtg_id = cxl_decoder_get_qtg_id(p->root_decoder);
+ if (root_qtg_id == -1)
+ 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)
+ dev_qtg_id = cxl_memdev_get_ram_qtg_id(memdev);
+ else
+ dev_qtg_id = cxl_memdev_get_pmem_qtg_id(memdev);
+
+ if (dev_qtg_id == -1)
+ return 0;
+
+ if (root_qtg_id != dev_qtg_id) {
+ if (p->strict && !p->no_qtg) {
+ log_err(&rl, "%s QTG ID %d mismatch %s QTG ID %d\n",
+ cxl_decoder_get_devname(p->root_decoder),
+ root_qtg_id,
+ cxl_memdev_get_devname(memdev),
+ dev_qtg_id);
+
+ return -ENXIO;
+ } else {
+ log_notice(&rl, "%s QTG ID %d mismatch %s QTG ID %d\n",
+ cxl_decoder_get_devname(p->root_decoder),
+ root_qtg_id,
+ cxl_memdev_get_devname(memdev),
+ dev_qtg_id);
+ }
+ }
+ }
+
+ return 0;
+}
+
static int create_region_validate_config(struct cxl_ctx *ctx,
struct parsed_params *p)
{
@@ -500,6 +553,8 @@ found:
return rc;
collect_minsize(ctx, p);
+ create_region_validate_qtg_id(ctx, p);
+
return 0;
}
The CFMWS provides a QTG ID. The kernel driver creates a root decoder that represents the CFMWS. A qtg_id attribute is exported via sysfs for the root decoder. A QTG id is retrieved via QTG ID _DSM from the ACPI0017 device for a CXL memory device. The input for the _DSM is the read and write latency and bandwidth for the path between the device and the CPU. The numbers are constructed by the kernel driver for the _DSM input. When a device is probed, the QTG ID is retrieved. This is useful for a hot-plugged CXL memory device that does not have regions created. Add a check for config check during region creation. Emit a warning if the QTG ID from the root decoder is different than the mem device QTG ID. User parameter options are provided to fail instead of just warning. Signed-off-by: Dave Jiang <dave.jiang@intel.com> --- Documentation/cxl/cxl-create-region.txt | 9 +++++ cxl/region.c | 57 ++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-)