diff mbox series

[RFC,10/14] drm/qaic: Add sysfs

Message ID 1660588956-24027-11-git-send-email-quic_jhugo@quicinc.com
State New
Headers show
Series QAIC DRM accelerator driver | expand

Commit Message

Jeffrey Hugo Aug. 15, 2022, 6:42 p.m. UTC
The QAIC driver can advertise the state of individual dma_bridge channels
to userspace.  Userspace can use this information to manage userspace
state when a channel crashes.

Change-Id: Ifc7435c53cec6aa326bdcd9bfcb77ea7f2a63bab
Signed-off-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
---
 drivers/gpu/drm/qaic/qaic_sysfs.c | 113 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 drivers/gpu/drm/qaic/qaic_sysfs.c
diff mbox series

Patch

diff --git a/drivers/gpu/drm/qaic/qaic_sysfs.c b/drivers/gpu/drm/qaic/qaic_sysfs.c
new file mode 100644
index 0000000..5ee1696
--- /dev/null
+++ b/drivers/gpu/drm/qaic/qaic_sysfs.c
@@ -0,0 +1,113 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/sysfs.h>
+
+#include "qaic.h"
+
+#define NAME_LEN 14
+
+struct dbc_attribute {
+	struct device_attribute dev_attr;
+	u32 dbc_id;
+	char name[NAME_LEN];
+};
+
+static ssize_t dbc_state_show(struct device *dev,
+			      struct device_attribute *a, char *buf)
+{
+	struct dbc_attribute *attr = container_of(a, struct dbc_attribute, dev_attr);
+	struct qaic_device *qdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", qdev->dbc[attr->dbc_id].state);
+}
+
+void set_dbc_state(struct qaic_device *qdev, u32 dbc_id, unsigned int state)
+{
+	char id_str[12];
+	char state_str[16];
+	char *envp[] = { id_str, state_str, NULL };
+	struct qaic_drm_device *qddev;
+
+	if (state >= DBC_STATE_MAX) {
+		pci_dbg(qdev->pdev, "%s invalid state %d\n", __func__, state);
+		return;
+	}
+	if (dbc_id >= qdev->num_dbc) {
+		pci_dbg(qdev->pdev, "%s invalid dbc_id %d\n", __func__, dbc_id);
+		return;
+	}
+	if (state == qdev->dbc[dbc_id].state) {
+		pci_dbg(qdev->pdev, "%s already at state %d\n", __func__, state);
+		return;
+	}
+
+	snprintf(id_str, ARRAY_SIZE(id_str), "DBC_ID=%d", dbc_id);
+	snprintf(state_str, ARRAY_SIZE(state_str), "DBC_STATE=%d", state);
+
+	qdev->dbc[dbc_id].state = state;
+	mutex_lock(&qdev->qaic_drm_devices_mutex);
+	list_for_each_entry(qddev, &qdev->qaic_drm_devices, node)
+		kobject_uevent_env(&qddev->ddev->dev->kobj, KOBJ_CHANGE, envp);
+	mutex_unlock(&qdev->qaic_drm_devices_mutex);
+}
+
+int qaic_sysfs_init(struct qaic_drm_device *qddev)
+{
+	u32 num_dbc = qddev->qdev->num_dbc;
+	struct dbc_attribute *dbc_attrs;
+	int i, ret;
+
+	dbc_attrs = kcalloc(num_dbc, sizeof(*dbc_attrs), GFP_KERNEL);
+	if (!dbc_attrs)
+		return -ENOMEM;
+
+	qddev->sysfs_attrs = dbc_attrs;
+
+	for (i = 0; i < num_dbc; ++i) {
+		struct dbc_attribute *dbc = &dbc_attrs[i];
+
+		sysfs_attr_init(&dbc->dev_attr.attr);
+		dbc->dbc_id = i;
+		snprintf(dbc->name, NAME_LEN, "dbc%d_state", i);
+		dbc->dev_attr.attr.name = dbc->name;
+		dbc->dev_attr.attr.mode = 0444;
+		dbc->dev_attr.show = dbc_state_show;
+		ret = sysfs_create_file(&qddev->ddev->dev->kobj,
+					&dbc->dev_attr.attr);
+		if (ret) {
+			int j;
+
+			for (j = 0; j < i; ++j) {
+				dbc = &dbc_attrs[j];
+				sysfs_remove_file(&qddev->ddev->dev->kobj,
+						  &dbc->dev_attr.attr);
+			}
+			break;
+		}
+	}
+
+	if (ret)
+		kfree(dbc_attrs);
+
+	return ret;
+}
+
+void qaic_sysfs_remove(struct qaic_drm_device *qddev)
+{
+	struct dbc_attribute *dbc_attrs = qddev->sysfs_attrs;
+	u32 num_dbc = qddev->qdev->num_dbc;
+	int i;
+
+	for (i = 0; i < num_dbc; ++i)
+		sysfs_remove_file(&qddev->ddev->dev->kobj,
+				  &dbc_attrs[i].dev_attr.attr);
+
+	kfree(dbc_attrs);
+}