// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright (c) 2023 Imagination Technologies Ltd. */
#include "pvr_params.h"
#include <linux/cache.h>
#include <linux/moduleparam.h>
static struct pvr_device_params pvr_device_param_defaults __read_mostly = {
#define X(type_, name_, value_, desc_, ...) .name_ = (value_),
PVR_DEVICE_PARAMS
#undef X
};
#define PVR_DEVICE_PARAM_NAMED(name_, type_, desc_) \
module_param_named(name_, pvr_device_param_defaults.name_, type_, \
0400); \
MODULE_PARM_DESC(name_, desc_);
/*
* This list of defines must contain every type specified in "pvr_params.h" as
* ``PVR_PARAM_TYPE_*_C``.
*/
#define PVR_PARAM_TYPE_X32_MODPARAM uint
#define X(type_, name_, value_, desc_, ...) \
PVR_DEVICE_PARAM_NAMED(name_, PVR_PARAM_TYPE_##type_##_MODPARAM, desc_);
PVR_DEVICE_PARAMS
#undef X
int
pvr_device_params_init(struct pvr_device_params *params)
{
/*
* If heap-allocated parameters are added in the future (e.g.
* modparam's charp type), they must be handled specially here (via
* kstrdup() in the case of charp). Since that's not necessary yet,
* a straight copy will do for now. This change will also require a
* pvr_device_params_fini() function to free any heap-allocated copies.
*/
*params = pvr_device_param_defaults;
return 0;
}
#if defined(CONFIG_DEBUG_FS)
#include "pvr_device.h"
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/stddef.h>
/*
* This list of defines must contain every type specified in "pvr_params.h" as
* ``PVR_PARAM_TYPE_*_C``.
*/
#define PVR_PARAM_TYPE_X32_FMT "0x%08llx"
#define X_SET(name_, mode_) X_SET_##mode_(name_)
#define X_SET_DEF(name_, update_, mode_) X_SET_DEF_##mode_(name_, update_)
#define X_SET_RO(name_) NULL
#define X_SET_RW(name_) __pvr_device_param_##name_##set
#define X_SET_DEF_RO(name_, update_)
#define X_SET_DEF_RW(name_, update_) \
static int \
X_SET_RW(name_)(void *data, u64 val) \
{ \
struct pvr_device *pvr_dev = data; \
/* This is not just (update_) to suppress -Waddress. */ \
if ((void *)(update_) != NULL) \
(update_)(pvr_dev, pvr_dev->params.name_, val); \
pvr_dev->params.name_ = val; \
return 0; \
}
#define X(type_, name_, value_, desc_, mode_, update_) \
static int \
__pvr_device_param_##name_##_get(void *data, u64 *val) \
{ \
struct pvr_device *pvr_dev = data; \
*val = pvr_dev->params.name_; \
return 0; \
} \
X_SET_DEF(name_, update_, mode_) \
static int \
__pvr_device_param_##name_##_open(struct inode *inode, \
struct file *file) \
{ \
__simple_attr_check_format(PVR_PARAM_TYPE_##type_##_FMT, \
0ull); \
return simple_attr_open(inode, file, \
__pvr_device_param_##name_##_get, \
X_SET(name_, mode_), \
PVR_PARAM_TYPE_##type_##_FMT); \
}
PVR_DEVICE_PARAMS
#undef X
#undef X_SET
#undef X_SET_RO
#undef X_SET_RW
#undef X_SET_DEF
#undef X_SET_DEF_RO
#undef X_SET_DEF_RW
static struct {
#define X(type_, name_, value_, desc_, mode_, update_) \
const struct file_operations name_;
PVR_DEVICE_PARAMS
#undef X
} pvr_device_param_debugfs_fops = {
#define X(type_, name_, value_, desc_, mode_, update_) \
.name_ = { \
.owner = THIS_MODULE, \
.open = __pvr_device_param_##name_##_open, \
.release = simple_attr_release, \
.read = simple_attr_read, \
.write = simple_attr_write, \
.llseek = generic_file_llseek, \
},
PVR_DEVICE_PARAMS
#undef X
};
void
pvr_params_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir)
{
#define X_MODE(mode_) X_MODE_##mode_
#define X_MODE_RO 0400
#define X_MODE_RW 0600
#define X(type_, name_, value_, desc_, mode_, update_) \
debugfs_create_file(#name_, X_MODE(mode_), dir, pvr_dev, \
&pvr_device_param_debugfs_fops.name_);
PVR_DEVICE_PARAMS
#undef X
#undef X_MODE
#undef X_MODE_RO
#undef X_MODE_RW
}
#endif