@@ -451,3 +451,21 @@ Description:
inject_poison attribute is only visible for devices supporting
the capability. Kconfig option CXL_POISON_INJECT must be on
to enable this option. The default is off.
+
+
+What: /sys/bus/cxl/devices/memX/clear_poison
+Date: March, 2023
+KernelVersion: v6.4
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (WO) When a Device Physical Address (DPA) is written to this
+ attribute, the memdev driver sends a clear poison command to
+ the device for the specified address. Clearing poison removes
+ the address from the device's Poison List and writes 0 (zero)
+ for 64 bytes starting at address. It is not an error to clear
+ poison from an address that does not have poison set, and if
+ poison was not set, the address is not overwritten. If the
+ device cannot clear poison from the address, -ENXIO is returned.
+ The clear_poison attribute is only visible for devices
+ supporting the capability. Kconfig option CXL_POISON_INJECT
+ must be on to enable this option. The default is off.
@@ -254,6 +254,53 @@ static ssize_t inject_poison_store(struct device *dev,
}
static DEVICE_ATTR_WO(inject_poison);
+static ssize_t clear_poison_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_mbox_clear_poison clear;
+ struct cxl_mbox_cmd mbox_cmd;
+ u64 dpa;
+ int rc;
+
+ rc = kstrtou64(buf, 0, &dpa);
+ if (rc)
+ return rc;
+
+ down_read(&cxl_dpa_rwsem);
+ rc = cxl_validate_poison_dpa(cxlmd, dpa);
+ if (rc) {
+ up_read(&cxl_dpa_rwsem);
+ return rc;
+ }
+
+ /*
+ * In CXL 3.0 Spec 8.2.9.8.4.3, the Clear Poison mailbox command
+ * is defined to accept 64 bytes of 'write-data', along with the
+ * address to clear. The device writes the data into the address
+ * atomically, while clearing poison if the location is marked as
+ * being poisoned.
+ *
+ * Always use '0' for the write-data.
+ */
+ clear = (struct cxl_mbox_clear_poison) {
+ .address = cpu_to_le64(dpa)
+ };
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_CLEAR_POISON,
+ .size_in = sizeof(clear),
+ .payload_in = &clear,
+ };
+
+ rc = cxl_internal_send_cmd(cxlmd->cxlds, &mbox_cmd);
+
+ up_read(&cxl_dpa_rwsem);
+ return rc ? rc : len;
+}
+static DEVICE_ATTR_WO(clear_poison);
+
static struct attribute *cxl_memdev_attributes[] = {
&dev_attr_serial.attr,
&dev_attr_firmware_version.attr,
@@ -262,6 +309,7 @@ static struct attribute *cxl_memdev_attributes[] = {
&dev_attr_numa_node.attr,
&dev_attr_trigger_poison_list.attr,
&dev_attr_inject_poison.attr,
+ &dev_attr_clear_poison.attr,
NULL,
};
@@ -298,6 +346,17 @@ static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
to_cxl_memdev(dev)->cxlds->enabled_cmds))
return 0;
}
+ if (a == &dev_attr_clear_poison.attr) {
+ struct device *dev = kobj_to_dev(kobj);
+
+ if (!IS_ENABLED(CONFIG_CXL_POISON_INJECT))
+ return 0;
+
+ if (!test_bit(CXL_MEM_COMMAND_ID_CLEAR_POISON,
+ to_cxl_memdev(dev)->cxlds->enabled_cmds)) {
+ return 0;
+ }
+ }
return a->mode;
}
@@ -607,6 +607,12 @@ struct cxl_mbox_inject_poison {
__le64 address;
};
+/* Clear Poison CXL 3.0 Spec 8.2.9.8.4.3 */
+struct cxl_mbox_clear_poison {
+ __le64 address;
+ u8 write_data[CXL_POISON_LEN_MULT];
+} __packed;
+
/**
* struct cxl_mem_command - Driver representation of a memory device command
* @info: Command information as it exists for the UAPI