204 lines
5.0 KiB
C
204 lines
5.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2020 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/of.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/device.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/kobject.h>
|
|
|
|
#include "mnoc_qos.h"
|
|
#include "mnoc_api.h"
|
|
#include "mnoc_drv.h"
|
|
|
|
static ssize_t mnoc_apu_qos_boost_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
#if MNOC_QOS_BOOST_ENABLE
|
|
ret = sprintf(buf, "apu_qos_boost_flag = %d\n", apu_qos_boost_flag);
|
|
#endif
|
|
if (ret < 0)
|
|
LOG_ERR("%s failed, ret %d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mnoc_apu_qos_boost_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned int val;
|
|
|
|
if (kstrtoint(buf, 10, &val) == 0) {
|
|
#if MNOC_QOS_BOOST_ENABLE
|
|
if (val == 0) {
|
|
mutex_lock(&apu_qos_boost_mtx);
|
|
apu_qos_boost_flag = false;
|
|
apu_qos_boost_end();
|
|
mutex_unlock(&apu_qos_boost_mtx);
|
|
} else if (val == 1) {
|
|
mutex_lock(&apu_qos_boost_mtx);
|
|
apu_qos_boost_flag = true;
|
|
apu_qos_boost_start();
|
|
mutex_unlock(&apu_qos_boost_mtx);
|
|
}
|
|
#endif
|
|
LOG_DEBUG("set boost %d\n", val);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct kobj_attribute apu_qos_boost_attr =
|
|
__ATTR(mnoc_apu_qos_boost, 0660, mnoc_apu_qos_boost_show,
|
|
mnoc_apu_qos_boost_store);
|
|
|
|
static ssize_t mnoc_cmd_qos_start_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
#if MNOC_TIME_PROFILE
|
|
ret = sprintf(buf, "sum_start = %lu, cnt_start = %d, avg = %lu\n",
|
|
sum_start, cnt_start, sum_start / cnt_start);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mnoc_cmd_qos_start_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t count)
|
|
{
|
|
unsigned int cmd_id, sub_cmd_id;
|
|
unsigned int dev_type, devcore, boost;
|
|
|
|
if (sscanf(buf, "%d %d %d %d %d", &cmd_id, &sub_cmd_id,
|
|
&dev_type, &devcore, &boost) == 4) {
|
|
apu_cmd_qos_start((uint64_t)cmd_id, (uint64_t)sub_cmd_id,
|
|
dev_type, devcore, boost);
|
|
} else {
|
|
LOG_ERR("%s input order is wrong\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_RW(mnoc_cmd_qos_start);
|
|
|
|
static ssize_t mnoc_cmd_qos_suspend_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
|
|
#if MNOC_TIME_PROFILE
|
|
ret = sprintf(buf, "sum_suspend = %lu, cnt_suspend = %d, avg = %lu\n",
|
|
sum_suspend, cnt_suspend, sum_suspend / cnt_suspend);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mnoc_cmd_qos_suspend_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t count)
|
|
{
|
|
unsigned int cmd_id, sub_cmd_id;
|
|
unsigned int dev_type, devcore;
|
|
|
|
if (sscanf(buf, "%d %d %d %d", &cmd_id, &sub_cmd_id,
|
|
&dev_type, &devcore) == 4) {
|
|
apu_cmd_qos_suspend((uint64_t)cmd_id, (uint64_t)sub_cmd_id,
|
|
dev_type, devcore);
|
|
} else {
|
|
LOG_ERR("%s input order is wrong\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_RW(mnoc_cmd_qos_suspend);
|
|
|
|
static ssize_t mnoc_cmd_qos_end_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
#if MNOC_TIME_PROFILE
|
|
ret = sprintf(buf, "sum_end = %lu, cnt_end = %d, avg = %lu\n",
|
|
sum_end, cnt_end, sum_end / cnt_end);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t mnoc_cmd_qos_end_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t count)
|
|
{
|
|
unsigned int cmd_id, sub_cmd_id;
|
|
unsigned int dev_type, devcore;
|
|
|
|
if (sscanf(buf, "%d %d %d %d", &cmd_id, &sub_cmd_id,
|
|
&dev_type, &devcore) == 4) {
|
|
apu_cmd_qos_end((uint64_t)cmd_id, (uint64_t)sub_cmd_id,
|
|
dev_type, devcore);
|
|
} else {
|
|
LOG_ERR("%s input order is wrong\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR_RW(mnoc_cmd_qos_end);
|
|
|
|
static struct attribute *qos_attrs[] = {
|
|
&dev_attr_mnoc_cmd_qos_start.attr,
|
|
&dev_attr_mnoc_cmd_qos_suspend.attr,
|
|
&dev_attr_mnoc_cmd_qos_end.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group mnoc_qos_attr_group = {
|
|
.name = "qos", /* create separate directory to put qos attributes */
|
|
.attrs = qos_attrs,
|
|
};
|
|
|
|
int mnoc_qos_create_sys(struct device *dev)
|
|
{
|
|
int ret = 0;
|
|
struct apu_mnoc *p_mnoc = dev_get_drvdata(dev);
|
|
|
|
/* create /sys/kernel/apusys */
|
|
p_mnoc->root_dir = kobject_create_and_add("apusys", kernel_kobj);
|
|
if (!p_mnoc->root_dir)
|
|
return -EINVAL;
|
|
|
|
/* create /sys/kernel/apusys/mnoc_apu_qos_boost */
|
|
ret = sysfs_create_file(p_mnoc->root_dir, &apu_qos_boost_attr.attr);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = kobject_uevent(p_mnoc->root_dir, KOBJ_ADD);
|
|
if (ret)
|
|
goto out;
|
|
|
|
/* create /sys/devices/platform/xxxx/qos */
|
|
ret = sysfs_create_group(&dev->kobj, &mnoc_qos_attr_group);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
void mnoc_qos_remove_sys(struct device *dev)
|
|
{
|
|
struct apu_mnoc *p_mnoc = dev_get_drvdata(dev);
|
|
|
|
sysfs_remove_file(p_mnoc->root_dir, &apu_qos_boost_attr.attr);
|
|
sysfs_remove_group(&dev->kobj, &mnoc_qos_attr_group);
|
|
}
|