From: chenzhen Date: Wed, 11 May 2016 10:18:04 +0000 (+0800) Subject: MALI: midgard: rockchip: add sysfs files to get GPU utilisation X-Git-Tag: firefly_0821_release~2033 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=9384c6c19e6629fa47549f22ad33a3ce444fb123;p=firefly-linux-kernel-4.4.55.git MALI: midgard: rockchip: add sysfs files to get GPU utilisation Change-Id: I758369bdd9ef945a89fd87fd7a69bd9f391f0880 Signed-off-by: chenzhen --- diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c index 62d477dd961e..f7c0a66e3879 100644 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c @@ -14,10 +14,12 @@ #include #include #include +#include #include #include #include +#include #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); +} diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_rk.h b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_rk.h index d6db811d1fce..e1623806abe8 100644 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_rk.h +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_rk.h @@ -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_ */