@@ -477,3 +477,13 @@ Description:
attribute is only visible for devices supporting the
capability. The retrieved errors are logged as kernel
events when cxl_poison event tracing is enabled.
+
+What: /sys/bus/cxl/devices/memX/bgcmd/complete
+Date: September, 2023
+KernelVersion: v6.6
+Contact: linux-cxl@vger.kernel.org
+Description:
+ (RO) This file can be used to read the processing status of
+ background commands. When a background command starts successfully,
+ it represents the progress as a percentage, and when it finishes,
+ userspace can read the opcode of a completed background operations.
@@ -201,6 +201,24 @@ static ssize_t security_erase_store(struct device *dev,
static struct device_attribute dev_attr_security_erase =
__ATTR(erase, 0200, NULL, security_erase_store);
+static ssize_t bgcmd_complete_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ u64 reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
+ u32 pct = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK, reg);
+ u16 cmd = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
+
+ if (pct == 100)
+ return sysfs_emit(buf, "0x%04x\n", cmd);
+ else
+ return sysfs_emit(buf, "%3u\n", pct);
+}
+static struct device_attribute dev_attr_bgcmd_complete =
+ __ATTR(complete, 0444, bgcmd_complete_show, NULL);
+
static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
{
struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -454,6 +472,11 @@ static struct attribute *cxl_memdev_security_attributes[] = {
NULL,
};
+static struct attribute *cxl_memdev_bgcmd_attributes[] = {
+ &dev_attr_bgcmd_complete.attr,
+ NULL,
+};
+
static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
int n)
{
@@ -482,11 +505,17 @@ static struct attribute_group cxl_memdev_security_attribute_group = {
.attrs = cxl_memdev_security_attributes,
};
+static struct attribute_group cxl_memdev_bgcmd_attribute_group = {
+ .name = "bgcmd",
+ .attrs = cxl_memdev_bgcmd_attributes,
+};
+
static const struct attribute_group *cxl_memdev_attribute_groups[] = {
&cxl_memdev_attribute_group,
&cxl_memdev_ram_attribute_group,
&cxl_memdev_pmem_attribute_group,
&cxl_memdev_security_attribute_group,
+ &cxl_memdev_bgcmd_attribute_group,
NULL,
};
@@ -1012,6 +1041,36 @@ static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
}
+static void put_bgcmd(void *data)
+{
+ struct cxl_memdev_state *mds = data;
+
+ sysfs_put(mds->bgcmd.complete_node);
+}
+
+static int cxl_memdev_bgcmd_init(struct cxl_memdev *cxlmd)
+{
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+ struct device *dev = &cxlmd->dev;
+ struct kernfs_node *bg;
+
+ bg = sysfs_get_dirent(dev->kobj.sd, "bgcmd");
+ if (!bg) {
+ dev_err(dev, "sysfs_get_dirent 'bgcmd' failed\n");
+ return -ENODEV;
+ }
+
+ mds->bgcmd.complete_node = sysfs_get_dirent(bg, "complete");
+ sysfs_put(bg);
+ if (!mds->bgcmd.complete_node) {
+ dev_err(dev, "sysfs_get_dirent 'complete' failed\n");
+ return -ENODEV;
+ }
+
+ return devm_add_action_or_reset(cxlds->dev, put_bgcmd, mds);
+}
+
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
{
struct cxl_memdev *cxlmd;
@@ -1044,6 +1103,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
if (rc)
goto err;
+ rc = cxl_memdev_bgcmd_init(cxlmd);
+ if (rc)
+ goto err;
+
rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
if (rc)
return ERR_PTR(rc);