@@ -132,6 +132,8 @@ 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);
+int cxl_memdev_inject_poison(struct cxl_memdev *memdev, const char *address);
+int cxl_memdev_clear_poison(struct cxl_memdev *memdev, const char *address);
struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev);
struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,
unsigned long long volatile_size);
@@ -172,6 +174,9 @@ cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple
label access commands over an arbitrary extent of the device's label
area.
+cxl_memdev_{inject,clear}_poison() support injecting/clearing poison
+into/from a physical address on a specified CXL memory device.
+
cxl_cmd_partition_set_mode() supports selecting NEXTBOOT or IMMEDIATE
mode. When CXL_SETPART_IMMEDIATE mode is set, it is the caller’s
responsibility to avoid immediate changes to partitioning when the
@@ -1458,6 +1458,59 @@ CXL_EXPORT int cxl_memdev_enable(struct cxl_memdev *memdev)
return 0;
}
+#define PATH_DEBUG_FS "/sys/kernel/debug/cxl"
+CXL_EXPORT int cxl_memdev_inject_poison(struct cxl_memdev *memdev,
+ const char *address)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ char *path = memdev->dev_buf;
+ int len = memdev->buf_len, rc;
+
+ if (snprintf(path, len, "%s/%s/inject_poison", PATH_DEBUG_FS,
+ cxl_memdev_get_devname(memdev)) >= len) {
+ err(ctx, "%s: buffer too small\n",
+ cxl_memdev_get_devname(memdev));
+ return -ENXIO;
+ }
+ rc = sysfs_write_attr(ctx, path, address);
+ if (rc < 0) {
+ err(ctx, "%s: failed to inject poison\n",
+ cxl_memdev_get_devname(memdev));
+ return rc;
+ }
+
+ dbg(ctx, "%s: poison injected at %s\n", cxl_memdev_get_devname(memdev),
+ address);
+
+ return 0;
+}
+
+CXL_EXPORT int cxl_memdev_clear_poison(struct cxl_memdev *memdev,
+ const char *address)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ char *path = memdev->dev_buf;
+ int len = memdev->buf_len, rc;
+
+ if (snprintf(path, len, "%s/%s/clear_poison", PATH_DEBUG_FS,
+ cxl_memdev_get_devname(memdev)) >= len) {
+ err(ctx, "%s: buffer too small\n",
+ cxl_memdev_get_devname(memdev));
+ return -ENXIO;
+ }
+ rc = sysfs_write_attr(ctx, path, address);
+ if (rc < 0) {
+ err(ctx, "%s: failed to clear poison\n",
+ cxl_memdev_get_devname(memdev));
+ return rc;
+ }
+
+ dbg(ctx, "%s: poison cleared at %s\n", cxl_memdev_get_devname(memdev),
+ address);
+
+ return 0;
+}
+
static struct cxl_endpoint *
cxl_port_recurse_endpoint(struct cxl_port *parent_port,
struct cxl_memdev *memdev)
@@ -250,3 +250,9 @@ global:
cxl_region_get_daxctl_region;
cxl_port_get_parent_dport;
} LIBCXL_4;
+
+LIBCXL_6 {
+global:
+ cxl_memdev_inject_poison;
+ cxl_memdev_clear_poison;
+} LIBCXL_5;
@@ -68,6 +68,8 @@ 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);
+int cxl_memdev_inject_poison(struct cxl_memdev *memdev, const char *address);
+int cxl_memdev_clear_poison(struct cxl_memdev *memdev, const char *address);
#define cxl_memdev_foreach(ctx, memdev) \
for (memdev = cxl_memdev_get_first(ctx); \
Add abilities to inject and clear poison to memdev based on the debugfs (/sys/kernel/debug/cxl/memX/{inject_/clear_}poison) interfaces that target kernel v6.4[1]. These interfaces trigger inject/clear poison function by writing DPA to the memory device debugfs attributes. In order to write the DPA in the debugfs attribute, 'sysfs_write_attr' macro is used which already defined. Signed-off-by: Junhyeok Im <junhyeok.im@samsung.com> [1] https://lore.kernel.org/linux-cxl/cover.1681874357.git.alison.schofield@intel.com/ --- Documentation/cxl/lib/libcxl.txt | 5 +++ cxl/lib/libcxl.c | 53 ++++++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 6 ++++ cxl/libcxl.h | 2 ++ 4 files changed, 66 insertions(+)