root/drivers/accel/amdxdna/amdxdna_debugfs.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2026, Advanced Micro Devices, Inc.
 */

#include "amdxdna_cbuf.h"
#include "amdxdna_debugfs.h"

#include <drm/drm_file.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/uaccess.h>

#define _DBGFS_FOPS(_open, _release, _write) \
{ \
        .owner = THIS_MODULE, \
        .open = _open, \
        .read = seq_read, \
        .llseek = seq_lseek, \
        .release = _release, \
        .write = _write, \
}

#define AMDXDNA_DBGFS_FOPS(_name, _show, _write) \
        static int amdxdna_dbgfs_##_name##_open(struct inode *inode, struct file *file) \
        { \
                return single_open(file, _show, inode->i_private); \
        } \
        static int amdxdna_dbgfs_##_name##_release(struct inode *inode, struct file *file) \
        { \
                return single_release(inode, file); \
        } \
        static const struct file_operations amdxdna_fops_##_name = \
                _DBGFS_FOPS(amdxdna_dbgfs_##_name##_open, amdxdna_dbgfs_##_name##_release, _write)

#define AMDXDNA_DBGFS_FILE(_name, _mode) { #_name, &amdxdna_fops_##_name, _mode }

#define file_to_xdna(file) (((struct seq_file *)(file)->private_data)->private)

static ssize_t amdxdna_carveout_write(struct file *file, const char __user *buf,
                                      size_t count, loff_t *ppos)
{
        struct amdxdna_dev *xdna = file_to_xdna(file);
        char kbuf[128];
        u64 size, addr;
        char *sep;
        int ret;

        if (count == 0 || count >= sizeof(kbuf))
                return -EINVAL;

        if (copy_from_user(kbuf, buf, count))
                return -EFAULT;
        kbuf[count] = '\0';
        strim(kbuf);
        XDNA_DBG(xdna, "Trying to set carveout to %s", kbuf);

        sep = strchr(kbuf, '@');
        if (!sep)
                return -EINVAL;
        *sep = '\0';
        sep++;

        ret = kstrtou64(kbuf, 0, &size);
        if (ret)
                return ret;

        ret = kstrtou64(sep, 0, &addr);
        if (ret)
                return ret;

        /* Sanity check the addr and size. */
        if (!size)
                return -EINVAL;
        if (!IS_ALIGNED(addr, PAGE_SIZE) || !IS_ALIGNED(size, PAGE_SIZE))
                return -EINVAL;

        guard(mutex)(&xdna->dev_lock);

        ret = amdxdna_carveout_init(xdna, addr, size);
        if (ret)
                return ret;

        return count;
}

static int amdxdna_carveout_show(struct seq_file *m, void *unused)
{
        struct amdxdna_dev *xdna = m->private;
        u64 addr, size;

        guard(mutex)(&xdna->dev_lock);
        amdxdna_get_carveout_conf(xdna, &addr, &size);
        seq_printf(m, "0x%llx@0x%llx\n", size, addr);
        return 0;
}

/*
 * Input/output format: <carveout_size>@<carveout_address>
 */
AMDXDNA_DBGFS_FOPS(carveout, amdxdna_carveout_show, amdxdna_carveout_write);

static const struct {
        const char *name;
        const struct file_operations *fops;
        umode_t mode;
} amdxdna_dbgfs_files[] = {
        AMDXDNA_DBGFS_FILE(carveout, 0600),
};

void amdxdna_debugfs_init(struct amdxdna_dev *xdna)
{
        struct drm_minor *minor = xdna->ddev.accel;
        int i;

        /*
         * It should be okay that debugfs fails to init.
         * We rely on DRM framework to finish debugfs.
         */
        for (i = 0; i < ARRAY_SIZE(amdxdna_dbgfs_files); i++) {
                debugfs_create_file(amdxdna_dbgfs_files[i].name,
                                    amdxdna_dbgfs_files[i].mode,
                                    minor->debugfs_root,
                                    xdna,
                                    amdxdna_dbgfs_files[i].fops);
        }
}