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 struct kfd_process *process; 37 pid_t pid; 38 }; 39 40 #define MAX_DEBUGFS_FILENAME_LEN 32 41 42 static int kfd_debugfs_open(struct inode *inode, struct file *file) 43 { 44 int (*show)(struct seq_file *, void *) = inode->i_private; 45 46 return single_open(file, show, NULL); 47 } 48 static int kfd_debugfs_hang_hws_read(struct seq_file *m, void *data) 49 { 50 seq_puts(m, "echo gpu_id > hang_hws\n"); 51 return 0; 52 } 53 54 static ssize_t kfd_debugfs_hang_hws_write(struct file *file, 55 const char __user *user_buf, size_t size, loff_t *ppos) 56 { 57 struct kfd_node *dev; 58 char tmp[16]; 59 uint32_t gpu_id; 60 int ret = -EINVAL; 61 62 memset(tmp, 0, 16); 63 if (size >= 16) { 64 pr_err("Invalid input for gpu id.\n"); 65 goto out; 66 } 67 if (copy_from_user(tmp, user_buf, size)) { 68 ret = -EFAULT; 69 goto out; 70 } 71 if (kstrtoint(tmp, 10, &gpu_id)) { 72 pr_err("Invalid input for gpu id.\n"); 73 goto out; 74 } 75 dev = kfd_device_by_id(gpu_id); 76 if (dev) { 77 kfd_debugfs_hang_hws(dev); 78 ret = size; 79 } else 80 pr_err("Cannot find device %d.\n", gpu_id); 81 82 out: 83 return ret; 84 } 85 86 static const struct file_operations kfd_debugfs_fops = { 87 .owner = THIS_MODULE, 88 .open = kfd_debugfs_open, 89 .read = seq_read, 90 .llseek = seq_lseek, 91 .release = single_release, 92 }; 93 94 static const struct file_operations kfd_debugfs_hang_hws_fops = { 95 .owner = THIS_MODULE, 96 .open = kfd_debugfs_open, 97 .read = seq_read, 98 .write = kfd_debugfs_hang_hws_write, 99 .llseek = seq_lseek, 100 .release = single_release, 101 }; 102 103 void kfd_debugfs_init(void) 104 { 105 debugfs_root = debugfs_create_dir("kfd", NULL); 106 debugfs_proc = debugfs_create_dir("proc", debugfs_root); 107 INIT_LIST_HEAD(&procs); 108 109 debugfs_create_file("mqds", S_IFREG | 0444, debugfs_root, 110 kfd_debugfs_mqds_by_process, &kfd_debugfs_fops); 111 debugfs_create_file("hqds", S_IFREG | 0444, debugfs_root, 112 kfd_debugfs_hqds_by_device, &kfd_debugfs_fops); 113 debugfs_create_file("rls", S_IFREG | 0444, debugfs_root, 114 kfd_debugfs_rls_by_device, &kfd_debugfs_fops); 115 debugfs_create_file("hang_hws", S_IFREG | 0200, debugfs_root, 116 kfd_debugfs_hang_hws_read, &kfd_debugfs_hang_hws_fops); 117 debugfs_create_file("mem_limit", S_IFREG | 0200, debugfs_root, 118 kfd_debugfs_kfd_mem_limits, &kfd_debugfs_fops); 119 } 120 121 void kfd_debugfs_fini(void) 122 { 123 debugfs_remove_recursive(debugfs_proc); 124 debugfs_remove_recursive(debugfs_root); 125 } 126 127 static ssize_t kfd_debugfs_pasid_read(struct file *file, char __user *buf, 128 size_t count, loff_t *ppos) 129 { 130 struct kfd_process_device *pdd = file_inode(file)->i_private; 131 char tmp[32]; 132 int len; 133 134 len = snprintf(tmp, sizeof(tmp), "%u\n", pdd->pasid); 135 136 return simple_read_from_buffer(buf, count, ppos, tmp, len); 137 } 138 139 static const struct file_operations kfd_debugfs_pasid_fops = { 140 .owner = THIS_MODULE, 141 .read = kfd_debugfs_pasid_read, 142 }; 143 144 /* This helper locates the debugfs entry of a kfd process */ 145 static struct debugfs_proc_entry *kfd_debugfs_find_process_entry(struct kfd_process *p) 146 { 147 struct debugfs_proc_entry *entry; 148 149 list_for_each_entry(entry, &procs, list) { 150 if (entry->process == p) 151 return entry; 152 } 153 154 return NULL; 155 } 156 157 /* This helper creates pasid file of a kfd process under debugfs */ 158 static void kfd_debugfs_create_pasid_files(struct kfd_process *p, 159 struct dentry *dir) 160 { 161 char name[MAX_DEBUGFS_FILENAME_LEN]; 162 struct kfd_process_device *pdd; 163 int i; 164 165 /* create pasid file for each GPU */ 166 for (i = 0; i < p->n_pdds; i++) { 167 pdd = p->pdds[i]; 168 snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "pasid_%u", pdd->dev->id); 169 debugfs_create_file((const char *)name, S_IFREG | 0444, 170 dir, pdd, &kfd_debugfs_pasid_fops); 171 } 172 } 173 174 int kfd_debugfs_add_process(struct kfd_process *p) 175 { 176 struct debugfs_proc_entry *primary_entry; 177 char name[MAX_DEBUGFS_FILENAME_LEN]; 178 struct kfd_process *primary_process; 179 struct debugfs_proc_entry *entry; 180 int ret; 181 182 entry = kzalloc_obj(*entry); 183 if (!entry) 184 return -ENOMEM; 185 186 entry->process = p; 187 entry->pid = p->lead_thread->pid; 188 189 if (p->context_id == KFD_CONTEXT_ID_PRIMARY) { 190 snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "%d", 191 (int)entry->pid); 192 entry->proc_dentry = debugfs_create_dir(name, debugfs_proc); 193 } else { 194 primary_process = kfd_lookup_process_by_mm(p->lead_thread->mm); 195 if (!primary_process) { 196 ret = -ESRCH; 197 goto err_free_entry; 198 } 199 200 primary_entry = kfd_debugfs_find_process_entry(primary_process); 201 kfd_unref_process(primary_process); 202 if (!primary_entry) { 203 pr_warn("Failed to find the primary debugfs entry for pid %d\n", 204 entry->pid); 205 ret = -ENOENT; 206 goto err_free_entry; 207 } 208 209 snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "context_%u", 210 p->context_id); 211 entry->proc_dentry = debugfs_create_dir(name, 212 primary_entry->proc_dentry); 213 } 214 215 list_add(&entry->list, &procs); 216 kfd_debugfs_create_pasid_files(p, entry->proc_dentry); 217 218 return 0; 219 220 err_free_entry: 221 kfree(entry); 222 return ret; 223 } 224 225 /* This helper removes a debugfs entry and its sub-entries */ 226 static void kfd_debugfs_remove_entry(struct debugfs_proc_entry *entry) 227 { 228 debugfs_remove(entry->proc_dentry); 229 list_del(&entry->list); 230 kfree(entry); 231 } 232 233 void kfd_debugfs_remove_process(struct kfd_process *p) 234 { 235 struct debugfs_proc_entry *entry, *next; 236 237 mutex_lock(&kfd_processes_mutex); 238 if (p->context_id == KFD_CONTEXT_ID_PRIMARY) { 239 /* remove entries of secondary contexts */ 240 list_for_each_entry_safe(entry, next, &procs, list) { 241 if (entry->pid != p->lead_thread->pid || entry->process == p) 242 continue; 243 244 kfd_debugfs_remove_entry(entry); 245 } 246 } 247 248 list_for_each_entry_safe(entry, next, &procs, list) { 249 if (entry->process != p) 250 continue; 251 252 kfd_debugfs_remove_entry(entry); 253 } 254 255 mutex_unlock(&kfd_processes_mutex); 256 } 257