1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2026, Advanced Micro Devices, Inc. 4 */ 5 6 #include "amdxdna_cbuf.h" 7 #include "amdxdna_debugfs.h" 8 9 #include <drm/drm_file.h> 10 #include <linux/debugfs.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/seq_file.h> 13 #include <linux/string.h> 14 #include <linux/uaccess.h> 15 16 #define _DBGFS_FOPS(_open, _release, _write) \ 17 { \ 18 .owner = THIS_MODULE, \ 19 .open = _open, \ 20 .read = seq_read, \ 21 .llseek = seq_lseek, \ 22 .release = _release, \ 23 .write = _write, \ 24 } 25 26 #define AMDXDNA_DBGFS_FOPS(_name, _show, _write) \ 27 static int amdxdna_dbgfs_##_name##_open(struct inode *inode, struct file *file) \ 28 { \ 29 return single_open(file, _show, inode->i_private); \ 30 } \ 31 static int amdxdna_dbgfs_##_name##_release(struct inode *inode, struct file *file) \ 32 { \ 33 return single_release(inode, file); \ 34 } \ 35 static const struct file_operations amdxdna_fops_##_name = \ 36 _DBGFS_FOPS(amdxdna_dbgfs_##_name##_open, amdxdna_dbgfs_##_name##_release, _write) 37 38 #define AMDXDNA_DBGFS_FILE(_name, _mode) { #_name, &amdxdna_fops_##_name, _mode } 39 40 #define file_to_xdna(file) (((struct seq_file *)(file)->private_data)->private) 41 42 static ssize_t amdxdna_carveout_write(struct file *file, const char __user *buf, 43 size_t count, loff_t *ppos) 44 { 45 struct amdxdna_dev *xdna = file_to_xdna(file); 46 char kbuf[128]; 47 u64 size, addr; 48 char *sep; 49 int ret; 50 51 if (count == 0 || count >= sizeof(kbuf)) 52 return -EINVAL; 53 54 if (copy_from_user(kbuf, buf, count)) 55 return -EFAULT; 56 kbuf[count] = '\0'; 57 strim(kbuf); 58 XDNA_DBG(xdna, "Trying to set carveout to %s", kbuf); 59 60 sep = strchr(kbuf, '@'); 61 if (!sep) 62 return -EINVAL; 63 *sep = '\0'; 64 sep++; 65 66 ret = kstrtou64(kbuf, 0, &size); 67 if (ret) 68 return ret; 69 70 ret = kstrtou64(sep, 0, &addr); 71 if (ret) 72 return ret; 73 74 /* Sanity check the addr and size. */ 75 if (!size) 76 return -EINVAL; 77 if (!IS_ALIGNED(addr, PAGE_SIZE) || !IS_ALIGNED(size, PAGE_SIZE)) 78 return -EINVAL; 79 80 guard(mutex)(&xdna->dev_lock); 81 82 ret = amdxdna_carveout_init(xdna, addr, size); 83 if (ret) 84 return ret; 85 86 return count; 87 } 88 89 static int amdxdna_carveout_show(struct seq_file *m, void *unused) 90 { 91 struct amdxdna_dev *xdna = m->private; 92 u64 addr, size; 93 94 guard(mutex)(&xdna->dev_lock); 95 amdxdna_get_carveout_conf(xdna, &addr, &size); 96 seq_printf(m, "0x%llx@0x%llx\n", size, addr); 97 return 0; 98 } 99 100 /* 101 * Input/output format: <carveout_size>@<carveout_address> 102 */ 103 AMDXDNA_DBGFS_FOPS(carveout, amdxdna_carveout_show, amdxdna_carveout_write); 104 105 static const struct { 106 const char *name; 107 const struct file_operations *fops; 108 umode_t mode; 109 } amdxdna_dbgfs_files[] = { 110 AMDXDNA_DBGFS_FILE(carveout, 0600), 111 }; 112 113 void amdxdna_debugfs_init(struct amdxdna_dev *xdna) 114 { 115 struct drm_minor *minor = xdna->ddev.accel; 116 int i; 117 118 /* 119 * It should be okay that debugfs fails to init. 120 * We rely on DRM framework to finish debugfs. 121 */ 122 for (i = 0; i < ARRAY_SIZE(amdxdna_dbgfs_files); i++) { 123 debugfs_create_file(amdxdna_dbgfs_files[i].name, 124 amdxdna_dbgfs_files[i].mode, 125 minor->debugfs_root, 126 xdna, 127 amdxdna_dbgfs_files[i].fops); 128 } 129 } 130