@@ -23,4 +23,5 @@ int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_monitor(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_inject_poison(int argc, const char **argv, struct cxl_ctx *ctx);
#endif /* _CXL_BUILTIN_H_ */
@@ -77,6 +77,7 @@ static struct cmd_struct commands[] = {
{ "disable-region", .c_fn = cmd_disable_region },
{ "destroy-region", .c_fn = cmd_destroy_region },
{ "monitor", .c_fn = cmd_monitor },
+ { "inject-poison", .c_fn = cmd_inject_poison },
};
int main(int argc, const char **argv)
@@ -34,6 +34,7 @@ static struct parameters {
const char *type;
const char *size;
const char *decoder_filter;
+ const char *poison_address;
} param;
static struct log_ctx ml;
@@ -85,6 +86,10 @@ OPT_STRING('t', "type", ¶m.type, "type", \
OPT_BOOLEAN('f', "force", ¶m.force, \
"Attempt 'expected to fail' operations")
+#define INJECT_POISON_OPTIONS() \
+OPT_STRING('a', "address", ¶m.poison_address, "dpa", \
+ "DPA to inject poison")
+
static const struct option read_options[] = {
BASE_OPTIONS(),
LABEL_OPTIONS(),
@@ -135,6 +140,12 @@ static const struct option free_dpa_options[] = {
OPT_END(),
};
+static const struct option inject_poison_options[] = {
+ BASE_OPTIONS(),
+ INJECT_POISON_OPTIONS(),
+ OPT_END(),
+};
+
enum reserve_dpa_mode {
DPA_ALLOC,
DPA_FREE,
@@ -351,6 +362,24 @@ static int action_free_dpa(struct cxl_memdev *memdev,
return __reserve_dpa(memdev, DPA_FREE, actx);
}
+static int action_inject_poison(struct cxl_memdev *memdev,
+ struct action_context *actx)
+{
+ int rc;
+
+ if (!param.poison_address) {
+ log_err(&ml, "%s: set dpa to inject poison.\n",
+ cxl_memdev_get_devname(memdev));
+ return -EINVAL;
+ }
+ rc = cxl_memdev_inject_poison(memdev, param.poison_address);
+ if (rc < 0) {
+ log_err(&ml, "%s: inject poison failed: %s\n",
+ cxl_memdev_get_devname(memdev), strerror(-rc));
+ }
+ return rc;
+}
+
static int action_disable(struct cxl_memdev *memdev, struct action_context *actx)
{
if (!cxl_memdev_is_enabled(memdev))
@@ -755,7 +784,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
continue;
found = true;
- if (action == action_write) {
+ if ((action == action_write) ||
+ (action == action_inject_poison)) {
single = memdev;
rc = 0;
} else
@@ -771,9 +801,15 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
}
rc = err;
- if (action == action_write) {
+ if ((action == action_write) || (action == action_inject_poison)) {
if (count > 1) {
- error("write-labels only supports writing a single memdev\n");
+ if (action == action_write) {
+ error("write-labels only supports writing "
+ "a single memdev\n");
+ } else {
+ error("inject-poison only supports injection "
+ "of poison into a single memdev\n");
+ }
usage_with_options(u, options);
return -EINVAL;
} else if (single) {
@@ -893,3 +929,14 @@ int cmd_free_dpa(int argc, const char **argv, struct cxl_ctx *ctx)
return count >= 0 ? 0 : EXIT_FAILURE;
}
+
+int cmd_inject_poison(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(
+ argc, argv, ctx, action_inject_poison, inject_poison_options,
+ "cxl inject-poison <memdev> -a <dpa> [<options>]");
+ log_info(&ml, "inject-poison %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
+
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}