mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-11 15:38:07 +09:00
MALI: midgard: rockchip: add sysfs files to get GPU utilisation
Change-Id: I758369bdd9ef945a89fd87fd7a69bd9f391f0880 Signed-off-by: chenzhen <chenzhen@rock-chips.com>
This commit is contained in:
committed by
Gerrit Code Review
parent
8b6de6fa83
commit
9384c6c19e
@@ -14,10 +14,12 @@
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_defs.h>
|
||||
#include <mali_kbase_config.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "mali_kbase_rk.h"
|
||||
|
||||
@@ -48,6 +50,10 @@ static int rk_pm_enable_clk(struct kbase_device *kbdev);
|
||||
|
||||
static void rk_pm_disable_clk(struct kbase_device *kbdev);
|
||||
|
||||
static int kbase_platform_rk_create_sysfs_files(struct device *dev);
|
||||
|
||||
static void kbase_platform_rk_remove_sysfs_files(struct device *dev);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static void rk_pm_power_off_delay_work(struct work_struct *work)
|
||||
@@ -74,6 +80,7 @@ static void rk_pm_power_off_delay_work(struct work_struct *work)
|
||||
|
||||
static int kbase_platform_rk_init(struct kbase_device *kbdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct rk_context *platform;
|
||||
|
||||
platform = kzalloc(sizeof(*platform), GFP_KERNEL);
|
||||
@@ -96,11 +103,19 @@ static int kbase_platform_rk_init(struct kbase_device *kbdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_DEFERRABLE_WORK(&platform->work, rk_pm_power_off_delay_work);
|
||||
platform->utilisation_period = DEFAULT_UTILISATION_PERIOD_IN_MS;
|
||||
|
||||
ret = kbase_platform_rk_create_sysfs_files(kbdev->dev);
|
||||
if (ret) {
|
||||
E("fail to create sysfs_files. ret = %d.", ret);
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
kbdev->platform_context = (void *)platform;
|
||||
pm_runtime_enable(kbdev->dev);
|
||||
|
||||
return 0;
|
||||
EXIT:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kbase_platform_rk_term(struct kbase_device *kbdev)
|
||||
@@ -117,6 +132,7 @@ static void kbase_platform_rk_term(struct kbase_device *kbdev)
|
||||
platform->kbdev = NULL;
|
||||
kfree(platform);
|
||||
}
|
||||
kbase_platform_rk_remove_sysfs_files(kbdev->dev);
|
||||
}
|
||||
|
||||
struct kbase_platform_funcs_conf platform_funcs = {
|
||||
@@ -139,8 +155,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev)
|
||||
{
|
||||
int ret = 1; /* Assume GPU has been powered off */
|
||||
int err = 0;
|
||||
struct rk_context *platform =
|
||||
(struct rk_context *)kbdev->platform_context;
|
||||
struct rk_context *platform = get_rk_context(kbdev);
|
||||
|
||||
cancel_delayed_work_sync(&platform->work);
|
||||
|
||||
@@ -186,8 +201,7 @@ static int rk_pm_callback_power_on(struct kbase_device *kbdev)
|
||||
|
||||
static void rk_pm_callback_power_off(struct kbase_device *kbdev)
|
||||
{
|
||||
struct rk_context *platform =
|
||||
(struct rk_context *)kbdev->platform_context;
|
||||
struct rk_context *platform = get_rk_context(kbdev);
|
||||
|
||||
rk_pm_disable_clk(kbdev);
|
||||
queue_delayed_work(platform->power_off_wq, &platform->work,
|
||||
@@ -292,3 +306,97 @@ static void rk_pm_disable_clk(struct kbase_device *kbdev)
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static ssize_t utilisation_period_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
struct rk_context *platform = get_rk_context(kbdev);
|
||||
ssize_t ret = 0;
|
||||
|
||||
ret += snprintf(buf, PAGE_SIZE, "%u\n", platform->utilisation_period);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t utilisation_period_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
struct rk_context *platform = get_rk_context(kbdev);
|
||||
int ret = 0;
|
||||
|
||||
ret = kstrtouint(buf, 0, &platform->utilisation_period);
|
||||
if (ret) {
|
||||
E("invalid input period : %s.", buf);
|
||||
return ret;
|
||||
}
|
||||
D("set utilisation_period to '%d'.", platform->utilisation_period);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t utilisation_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
struct rk_context *platform = get_rk_context(kbdev);
|
||||
ssize_t ret = 0;
|
||||
unsigned long period_in_us = platform->utilisation_period * 1000;
|
||||
unsigned long total_time;
|
||||
unsigned long busy_time;
|
||||
unsigned long utilisation;
|
||||
|
||||
kbase_pm_reset_dvfs_utilisation(kbdev);
|
||||
usleep_range(period_in_us, period_in_us + 100);
|
||||
kbase_pm_get_dvfs_utilisation(kbdev, &total_time, &busy_time);
|
||||
/* 'devfreq_dev_profile' instance registered to devfreq
|
||||
* also uses kbase_pm_reset_dvfs_utilisation
|
||||
* and kbase_pm_get_dvfs_utilisation.
|
||||
* it's better to cat this file when DVFS is disabled.
|
||||
*/
|
||||
D("total_time : %lu, busy_time : %lu.", total_time, busy_time);
|
||||
|
||||
utilisation = busy_time * 100 / total_time;
|
||||
ret += snprintf(buf, PAGE_SIZE, "%ld\n", utilisation);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(utilisation_period);
|
||||
static DEVICE_ATTR_RO(utilisation);
|
||||
|
||||
static int kbase_platform_rk_create_sysfs_files(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_utilisation_period);
|
||||
if (ret) {
|
||||
E("fail to create sysfs file 'utilisation_period'.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_utilisation);
|
||||
if (ret) {
|
||||
E("fail to create sysfs file 'utilisation'.");
|
||||
goto remove_utilisation_period;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_utilisation_period:
|
||||
device_remove_file(dev, &dev_attr_utilisation_period);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kbase_platform_rk_remove_sysfs_files(struct device *dev)
|
||||
{
|
||||
device_remove_file(dev, &dev_attr_utilisation_period);
|
||||
device_remove_file(dev, &dev_attr_utilisation);
|
||||
}
|
||||
|
||||
@@ -17,18 +17,34 @@
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
#define DEFAULT_UTILISATION_PERIOD_IN_MS (100)
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* struct rk_context - work_context of platform_dependent_part_of_rk.
|
||||
* @is_powered: record the status
|
||||
* of common_parts calling 'power_on_callback' and 'power_off_callback'.
|
||||
*/
|
||||
struct rk_context {
|
||||
/*
|
||||
* record the status of common_parts calling 'power_on_callback'
|
||||
* and 'power_off_callback'.
|
||||
*/
|
||||
bool is_powered;
|
||||
struct kbase_device *kbdev;
|
||||
struct workqueue_struct *power_off_wq;
|
||||
struct delayed_work work;
|
||||
unsigned int delay_ms;
|
||||
/* debug only, the period in ms to count gpu_utilisation. */
|
||||
unsigned int utilisation_period;
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static inline struct rk_context *get_rk_context(
|
||||
const struct kbase_device *kbdev)
|
||||
{
|
||||
return (struct rk_context *)(kbdev->platform_context);
|
||||
}
|
||||
|
||||
#endif /* _MALI_KBASE_RK_H_ */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user