diff mbox series

[RFC,3/3] cxl/memdev: Add background command sysfs file

Message ID 20230922130607.3476828-1-jtp.park@samsung.com
State New, archived
Headers show
Series cxl: Fix background operation handling | expand

Commit Message

Jeongtae Park Sept. 22, 2023, 1:06 p.m. UTC
Add a read-only sysfs file to notify the background
command state of a device:

    /sys/bus/cxl/devices/memX/bgcmd/complete

Signed-off-by: Jeongtae Park <jtp.park@samsung.com>
Signed-off-by: Hojin Nam <hj96.nam@samsung.com>
---
 Documentation/ABI/testing/sysfs-bus-cxl | 10 ++++
 drivers/cxl/core/memdev.c               | 63 +++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 6350dd82b9a9..e9773f20deac 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -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.
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 8d1692231767..ba23ef6b6278 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -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);