1 // SPDX-License-Identifier: GPL-2.0-only 2 3 /* Copyright (c) 2020-2025, The Linux Foundation. All rights reserved. */ 4 5 #include <drm/drm_file.h> 6 #include <drm/drm_managed.h> 7 #include <linux/device.h> 8 #include <linux/kernel.h> 9 #include <linux/kobject.h> 10 #include <linux/mutex.h> 11 #include <linux/sysfs.h> 12 13 #include "qaic.h" 14 15 #define NAME_LEN 14 16 17 struct dbc_attribute { 18 struct device_attribute dev_attr; 19 u32 dbc_id; 20 char name[NAME_LEN]; 21 }; 22 23 static ssize_t dbc_state_show(struct device *dev, struct device_attribute *a, char *buf) 24 { 25 struct dbc_attribute *dbc_attr = container_of(a, struct dbc_attribute, dev_attr); 26 struct drm_minor *minor = dev_get_drvdata(dev); 27 struct qaic_device *qdev; 28 29 qdev = to_qaic_device(minor->dev); 30 return sysfs_emit(buf, "%d\n", qdev->dbc[dbc_attr->dbc_id].state); 31 } 32 33 void set_dbc_state(struct qaic_device *qdev, u32 dbc_id, unsigned int state) 34 { 35 struct device *kdev = to_accel_kdev(qdev->qddev); 36 char *envp[3] = {}; 37 char state_str[16]; 38 char id_str[12]; 39 40 envp[0] = id_str; 41 envp[1] = state_str; 42 43 if (state >= DBC_STATE_MAX) 44 return; 45 if (dbc_id >= qdev->num_dbc) 46 return; 47 if (state == qdev->dbc[dbc_id].state) 48 return; 49 50 scnprintf(id_str, ARRAY_SIZE(id_str), "DBC_ID=%d", dbc_id); 51 scnprintf(state_str, ARRAY_SIZE(state_str), "DBC_STATE=%d", state); 52 53 qdev->dbc[dbc_id].state = state; 54 kobject_uevent_env(&kdev->kobj, KOBJ_CHANGE, envp); 55 } 56 57 int qaic_sysfs_init(struct qaic_drm_device *qddev) 58 { 59 struct device *kdev = to_accel_kdev(qddev); 60 struct drm_device *drm = to_drm(qddev); 61 u32 num_dbc = qddev->qdev->num_dbc; 62 struct dbc_attribute *dbc_attrs; 63 int i, ret; 64 65 dbc_attrs = drmm_kcalloc(drm, num_dbc, sizeof(*dbc_attrs), GFP_KERNEL); 66 if (!dbc_attrs) 67 return -ENOMEM; 68 69 for (i = 0; i < num_dbc; ++i) { 70 struct dbc_attribute *dbc_attr = &dbc_attrs[i]; 71 72 sysfs_attr_init(&dbc_attr->dev_attr.attr); 73 dbc_attr->dbc_id = i; 74 scnprintf(dbc_attr->name, NAME_LEN, "dbc%d_state", i); 75 dbc_attr->dev_attr.attr.name = dbc_attr->name; 76 dbc_attr->dev_attr.attr.mode = 0444; 77 dbc_attr->dev_attr.show = dbc_state_show; 78 ret = sysfs_create_file(&kdev->kobj, &dbc_attr->dev_attr.attr); 79 if (ret) { 80 int j; 81 82 for (j = 0; j < i; ++j) { 83 dbc_attr = &dbc_attrs[j]; 84 sysfs_remove_file(&kdev->kobj, &dbc_attr->dev_attr.attr); 85 } 86 drmm_kfree(drm, dbc_attrs); 87 return ret; 88 } 89 } 90 91 qddev->sysfs_attrs = dbc_attrs; 92 return 0; 93 } 94 95 void qaic_sysfs_remove(struct qaic_drm_device *qddev) 96 { 97 struct dbc_attribute *dbc_attrs = qddev->sysfs_attrs; 98 struct device *kdev = to_accel_kdev(qddev); 99 u32 num_dbc = qddev->qdev->num_dbc; 100 int i; 101 102 if (!dbc_attrs) 103 return; 104 105 qddev->sysfs_attrs = NULL; 106 for (i = 0; i < num_dbc; ++i) 107 sysfs_remove_file(&kdev->kobj, &dbc_attrs[i].dev_attr.attr); 108 drmm_kfree(to_drm(qddev), dbc_attrs); 109 } 110