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