Add a library API for clearing and injecting poison into a CXL memory device through the CXL debugfs.
This API will be used by the 'cxl-inject-error' and 'cxl-clear-error' commands in later commits. Reviewed-by: Dave Jiang <[email protected]> Signed-off-by: Ben Cheatham <[email protected]> --- cxl/lib/libcxl.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 3 ++ cxl/libcxl.h | 3 ++ 3 files changed, 89 insertions(+) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index af34db0..655eef0 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -5024,3 +5024,86 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_set_alert_config(struct cxl_memdev *memde { return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_SET_ALERT_CONFIG); } + +CXL_EXPORT bool cxl_memdev_has_poison_injection(struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = memdev->ctx; + size_t path_len, len; + bool exists = true; + char *path; + int rc; + + if (!ctx->debugfs) + return false; + + path_len = strlen(ctx->debugfs) + 100; + path = calloc(path_len, sizeof(char)); + if (!path) + return false; + + len = snprintf(path, path_len, "%s/cxl/%s/inject_poison", ctx->debugfs, + cxl_memdev_get_devname(memdev)); + if (len >= path_len) { + err(ctx, "%s: buffer too small\n", + cxl_memdev_get_devname(memdev)); + free(path); + return false; + } + + rc = access(path, F_OK); + if (rc) + exists = false; + + free(path); + return exists; +} + +static int cxl_memdev_poison_action(struct cxl_memdev *memdev, size_t dpa, + bool clear) +{ + struct cxl_ctx *ctx = memdev->ctx; + size_t path_len, len; + char addr[32]; + char *path; + int rc; + + if (!ctx->debugfs) + return -ENOENT; + + path_len = strlen(ctx->debugfs) + 100; + path = calloc(path_len, sizeof(char)); + if (!path) + return -ENOMEM; + + len = snprintf(path, path_len, "%s/cxl/%s/%s", ctx->debugfs, + cxl_memdev_get_devname(memdev), + clear ? "clear_poison" : "inject_poison"); + if (len >= path_len) { + err(ctx, "%s: buffer too small\n", + cxl_memdev_get_devname(memdev)); + free(path); + return -ENOMEM; + } + + len = snprintf(addr, sizeof(addr), "0x%lx\n", dpa); + if (len >= sizeof(addr)) { + err(ctx, "%s: buffer too small\n", + cxl_memdev_get_devname(memdev)); + free(path); + return -ENOMEM; + } + + rc = sysfs_write_attr(ctx, path, addr); + free(path); + return rc; +} + +CXL_EXPORT int cxl_memdev_inject_poison(struct cxl_memdev *memdev, size_t addr) +{ + return cxl_memdev_poison_action(memdev, addr, false); +} + +CXL_EXPORT int cxl_memdev_clear_poison(struct cxl_memdev *memdev, size_t addr) +{ + return cxl_memdev_poison_action(memdev, addr, true); +} diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 02d5119..3bce60d 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -304,4 +304,7 @@ global: cxl_protocol_error_get_num; cxl_protocol_error_get_str; cxl_dport_protocol_error_inject; + cxl_memdev_has_poison_injection; + cxl_memdev_inject_poison; + cxl_memdev_clear_poison; } LIBCXL_9; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index adb5716..56cba8f 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -105,6 +105,9 @@ int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length, size_t offset); int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length, size_t offset); +bool cxl_memdev_has_poison_injection(struct cxl_memdev *memdev); +int cxl_memdev_inject_poison(struct cxl_memdev *memdev, size_t dpa); +int cxl_memdev_clear_poison(struct cxl_memdev *memdev, size_t dpa); struct cxl_cmd *cxl_cmd_new_get_fw_info(struct cxl_memdev *memdev); unsigned int cxl_cmd_fw_info_get_num_slots(struct cxl_cmd *cmd); unsigned int cxl_cmd_fw_info_get_active_slot(struct cxl_cmd *cmd); -- 2.52.0
