drm/amdkfd: Add procfs-style information for KFD processes [Linux 5.3]

This Linux kernel change "drm/amdkfd: Add procfs-style information for KFD processes" is included in the Linux 5.3 release. This change is authored by Kent Russell <kent.russell [at] amd.com> on Thu Jun 13 09:55:40 2019 -0400. The commit for this change in Linux stable tree is de9f26b (patch).

drm/amdkfd: Add procfs-style information for KFD processes

Add a folder structure to /sys/class/kfd/kfd/ called proc which contains
subfolders, each representing an active KFD process' PID, containing 1
file: pasid.

Signed-off-by: Kent Russell <kent.russell@amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>
Acked-by: Christian K├Ânig <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

There are 115 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/gpu/drm/amd/amdkfd/kfd_module.c  |   6 ++
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h    |   9 +++
 drivers/gpu/drm/amd/amdkfd/kfd_process.c | 100 ++++++++++++++++++++++++++++++-
 3 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
index 932007e..986ff52 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
@@ -56,6 +56,11 @@ static int kfd_init(void)
    if (err < 0)
        goto err_create_wq;

+   /* Ignore the return value, so that we can continue
+    * to init the KFD, even if procfs isn't craated
+    */
+   kfd_procfs_init();
+
    kfd_debugfs_init();

    return 0;
@@ -72,6 +77,7 @@ static void kfd_exit(void)
 {
    kfd_debugfs_fini();
    kfd_process_destroy_wq();
+   kfd_procfs_shutdown();
    kfd_topology_shutdown();
    kfd_chardev_exit();
 }
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index da589ee1..bd01396 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -35,6 +35,7 @@
 #include <linux/kfifo.h>
 #include <linux/seq_file.h>
 #include <linux/kref.h>
+#include <linux/sysfs.h>
 #include <kgd_kfd_interface.h>

 #include "amd_shared.h"
@@ -718,6 +719,10 @@ struct kfd_process {
     * restored after an eviction
     */
    unsigned long last_restore_timestamp;
+
+   /* Kobj for our procfs */
+   struct kobject *kobj;
+   struct attribute attr_pasid;
 };

 #define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */
@@ -820,6 +825,10 @@ int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,

 extern struct device *kfd_device;

+/* KFD's procfs */
+void kfd_procfs_init(void);
+void kfd_procfs_shutdown(void);
+
 /* Topology */
 int kfd_topology_init(void);
 void kfd_topology_shutdown(void);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 4bdae78..ed2d83f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -68,6 +68,68 @@ static struct kfd_process *create_process(const struct task_struct *thread,
 static void evict_process_worker(struct work_struct *work);
 static void restore_process_worker(struct work_struct *work);

+struct kfd_procfs_tree {
+   struct kobject *kobj;
+};
+
+static struct kfd_procfs_tree procfs;
+
+static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr,
+                  char *buffer)
+{
+   int val = 0;
+
+   if (strcmp(attr->name, "pasid") == 0) {
+       struct kfd_process *p = container_of(attr, struct kfd_process,
+                            attr_pasid);
+       val = p->pasid;
+   } else {
+       pr_err("Invalid attribute");
+       return -EINVAL;
+   }
+
+   return snprintf(buffer, PAGE_SIZE, "%d\n", val);
+}
+
+static void kfd_procfs_kobj_release(struct kobject *kobj)
+{
+   kfree(kobj);
+}
+
+static const struct sysfs_ops kfd_procfs_ops = {
+   .show = kfd_procfs_show,
+};
+
+static struct kobj_type procfs_type = {
+   .release = kfd_procfs_kobj_release,
+   .sysfs_ops = &kfd_procfs_ops,
+};
+
+void kfd_procfs_init(void)
+{
+   int ret = 0;
+
+   procfs.kobj = kfd_alloc_struct(procfs.kobj);
+   if (!procfs.kobj)
+       return;
+
+   ret = kobject_init_and_add(procfs.kobj, &procfs_type,
+                  &kfd_device->kobj, "proc");
+   if (ret) {
+       pr_warn("Could not create procfs proc folder");
+       /* If we fail to create the procfs, clean up */
+       kfd_procfs_shutdown();
+   }
+}
+
+void kfd_procfs_shutdown(void)
+{
+   if (procfs.kobj) {
+       kobject_del(procfs.kobj);
+       kobject_put(procfs.kobj);
+       procfs.kobj = NULL;
+   }
+}

 int kfd_process_create_wq(void)
 {
@@ -206,6 +268,7 @@ struct kfd_process *kfd_create_process(struct file *filep)
 {
    struct kfd_process *process;
    struct task_struct *thread = current;
+   int ret;

    if (!thread->mm)
        return ERR_PTR(-EINVAL);
@@ -223,11 +286,36 @@ struct kfd_process *kfd_create_process(struct file *filep)

    /* A prior open of /dev/kfd could have already created the process. */
    process = find_process(thread);
-   if (process)
+   if (process) {
        pr_debug("Process already found\n");
-   else
+   } else {
        process = create_process(thread, filep);

+       if (!procfs.kobj)
+           goto out;
+
+       process->kobj = kfd_alloc_struct(process->kobj);
+       if (!process->kobj) {
+           pr_warn("Creating procfs kobject failed");
+           goto out;
+       }
+       ret = kobject_init_and_add(process->kobj, &procfs_type,
+                      procfs.kobj, "%d",
+                      (int)process->lead_thread->pid);
+       if (ret) {
+           pr_warn("Creating procfs pid directory failed");
+           goto out;
+       }
+
+       process->attr_pasid.name = "pasid";
+       process->attr_pasid.mode = KFD_SYSFS_FILE_MODE;
+       sysfs_attr_init(&process->attr_pasid);
+       ret = sysfs_create_file(process->kobj, &process->attr_pasid);
+       if (ret)
+           pr_warn("Creating pasid for pid %d failed",
+                   (int)process->lead_thread->pid);
+   }
+out:
    mutex_unlock(&kfd_processes_mutex);

    return process;
@@ -355,6 +443,14 @@ static void kfd_process_wq_release(struct work_struct *work)
    struct kfd_process *p = container_of(work, struct kfd_process,
                         release_work);

+   /* Remove the procfs files */
+   if (p->kobj) {
+       sysfs_remove_file(p->kobj, &p->attr_pasid);
+       kobject_del(p->kobj);
+       kobject_put(p->kobj);
+       p->kobj = NULL;
+   }
+
    kfd_iommu_unbind_process(p);

    kfd_process_free_outstanding_kfd_bos(p);

Leave a Reply

Your email address will not be published. Required fields are marked *