1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /* 3 * Copyright 2016-2022 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include <linux/debugfs.h> 25 #include <linux/uaccess.h> 26 27 #include "kfd_priv.h" 28 29 static struct dentry *debugfs_root; 30 static struct dentry *debugfs_proc; 31 static struct list_head procs; 32 33 struct debugfs_proc_entry { 34 struct list_head list; 35 struct dentry *proc_dentry; 36 pid_t pid; 37 }; 38 39 #define MAX_DEBUGFS_FILENAME_LEN 32 40 41 static int kfd_debugfs_open(struct inode *inode, struct file *file) 42 { 43 int (*show)(struct seq_file *, void *) = inode->i_private; 44 45 return single_open(file, show, NULL); 46 } 47 static int kfd_debugfs_hang_hws_read(struct seq_file *m, void *data) 48 { 49 seq_puts(m, "echo gpu_id > hang_hws\n"); 50 return 0; 51 } 52 53 static ssize_t kfd_debugfs_hang_hws_write(struct file *file, 54 const char __user *user_buf, size_t size, loff_t *ppos) 55 { 56 struct kfd_node *dev; 57 char tmp[16]; 58 uint32_t gpu_id; 59 int ret = -EINVAL; 60 61 memset(tmp, 0, 16); 62 if (size >= 16) { 63 pr_err("Invalid input for gpu id.\n"); 64 goto out; 65 } 66 if (copy_from_user(tmp, user_buf, size)) { 67 ret = -EFAULT; 68 goto out; 69 } 70 if (kstrtoint(tmp, 10, &gpu_id)) { 71 pr_err("Invalid input for gpu id.\n"); 72 goto out; 73 } 74 dev = kfd_device_by_id(gpu_id); 75 if (dev) { 76 kfd_debugfs_hang_hws(dev); 77 ret = size; 78 } else 79 pr_err("Cannot find device %d.\n", gpu_id); 80 81 out: 82 return ret; 83 } 84 85 static const struct file_operations kfd_debugfs_fops = { 86 .owner = THIS_MODULE, 87 .open = kfd_debugfs_open, 88 .read = seq_read, 89 .llseek = seq_lseek, 90 .release = single_release, 91 }; 92 93 static const struct file_operations kfd_debugfs_hang_hws_fops = { 94 .owner = THIS_MODULE, 95 .open = kfd_debugfs_open, 96 .read = seq_read, 97 .write = kfd_debugfs_hang_hws_write, 98 .llseek = seq_lseek, 99 .release = single_release, 100 }; 101 102 void kfd_debugfs_init(void) 103 { 104 debugfs_root = debugfs_create_dir("kfd", NULL); 105 debugfs_proc = debugfs_create_dir("proc", debugfs_root); 106 INIT_LIST_HEAD(&procs); 107 108 debugfs_create_file("mqds", S_IFREG | 0444, debugfs_root, 109 kfd_debugfs_mqds_by_process, &kfd_debugfs_fops); 110 debugfs_create_file("hqds", S_IFREG | 0444, debugfs_root, 111 kfd_debugfs_hqds_by_device, &kfd_debugfs_fops); 112 debugfs_create_file("rls", S_IFREG | 0444, debugfs_root, 113 kfd_debugfs_rls_by_device, &kfd_debugfs_fops); 114 debugfs_create_file("hang_hws", S_IFREG | 0200, debugfs_root, 115 kfd_debugfs_hang_hws_read, &kfd_debugfs_hang_hws_fops); 116 debugfs_create_file("mem_limit", S_IFREG | 0200, debugfs_root, 117 kfd_debugfs_kfd_mem_limits, &kfd_debugfs_fops); 118 } 119 120 void kfd_debugfs_fini(void) 121 { 122 debugfs_remove_recursive(debugfs_proc); 123 debugfs_remove_recursive(debugfs_root); 124 } 125 126 static ssize_t kfd_debugfs_pasid_read(struct file *file, char __user *buf, 127 size_t count, loff_t *ppos) 128 { 129 struct kfd_process_device *pdd = file_inode(file)->i_private; 130 char tmp[32]; 131 int len; 132 133 len = snprintf(tmp, sizeof(tmp), "%u\n", pdd->pasid); 134 135 return simple_read_from_buffer(buf, count, ppos, tmp, len); 136 } 137 138 static const struct file_operations kfd_debugfs_pasid_fops = { 139 .owner = THIS_MODULE, 140 .read = kfd_debugfs_pasid_read, 141 }; 142 143 void kfd_debugfs_add_process(struct kfd_process *p) 144 { 145 int i; 146 char name[MAX_DEBUGFS_FILENAME_LEN]; 147 struct debugfs_proc_entry *entry; 148 149 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 150 if (!entry) 151 return; 152 153 list_add(&entry->list, &procs); 154 entry->pid = p->lead_thread->pid; 155 snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "%d", 156 (int)entry->pid); 157 entry->proc_dentry = debugfs_create_dir(name, debugfs_proc); 158 159 /* Create debugfs files for each GPU: 160 * - proc/<pid>/pasid_<gpuid> 161 */ 162 for (i = 0; i < p->n_pdds; i++) { 163 struct kfd_process_device *pdd = p->pdds[i]; 164 165 snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "pasid_%u", 166 pdd->dev->id); 167 debugfs_create_file((const char *)name, S_IFREG | 0444, 168 entry->proc_dentry, pdd, 169 &kfd_debugfs_pasid_fops); 170 } 171 } 172 173 void kfd_debugfs_remove_process(struct kfd_process *p) 174 { 175 struct debugfs_proc_entry *entry, *next; 176 177 mutex_lock(&kfd_processes_mutex); 178 list_for_each_entry_safe(entry, next, &procs, list) { 179 if (entry->pid != p->lead_thread->pid) 180 continue; 181 182 debugfs_remove_recursive(entry->proc_dentry); 183 list_del(&entry->list); 184 kfree(entry); 185 } 186 mutex_unlock(&kfd_processes_mutex); 187 } 188