From 85c4d41d99e58e421cd8f5eb97e63d2290e1377b Mon Sep 17 00:00:00 2001 From: Johnny Liu Date: Tue, 25 Apr 2023 08:23:31 +0000 Subject: [PATCH] devfreq: Get rid of unused CONFIGs Remove the config variables as there is no Kconfig to define these configs: CONFIG_DEVFREQ_GOV_WMARK_SIMPLE CONFIG_DEVFREQ_GOV_WMARK_ACTIVE Remove the handling of non-module build as devfreq is always build as module. Remove the wmark-related devfreq governors as we plan to keep them under drivers/gpu/drm/tegra. They are tightly bound with the actmon and drm drivers. Bug 4074863 Signed-off-by: Johnny Liu Change-Id: Iba8f5da770d86ddcfb6315f72fd74fc9a781ab39 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2893701 Reviewed-by: Laxman Dewangan GVS: Gerrit_Virtual_Submit --- drivers/devfreq/Makefile | 13 +- drivers/devfreq/governor_pod_scaling.c | 115 ++- drivers/devfreq/governor_pod_scaling_v2.c | 943 ------------------ drivers/devfreq/governor_wmark_active.c | 823 --------------- drivers/devfreq/governor_wmark_simple.c | 252 ----- .../drivers-private/devfreq/governor.h | 6 +- 6 files changed, 78 insertions(+), 2074 deletions(-) delete mode 100644 drivers/devfreq/governor_pod_scaling_v2.c delete mode 100644 drivers/devfreq/governor_wmark_active.c delete mode 100644 drivers/devfreq/governor_wmark_simple.c rename drivers/devfreq/governor_v2.h => include/drivers-private/devfreq/governor.h (91%) diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 45157b04..722171d6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -1,15 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. -ccflags-y += -I$(srctree)/drivers/devfreq - -obj-$(CONFIG_DEVFREQ_GOV_WMARK_SIMPLE) += governor_wmark_simple.o -obj-$(CONFIG_DEVFREQ_GOV_WMARK_ACTIVE) += governor_wmark_active.o - -ifeq ($(CONFIG_TEGRA_OOT_MODULE),m) - ccflags-y += -DGOVERNOR_POD_SCALING_V2_MODULE - obj-m += governor_pod_scaling_v2.o -else - obj-$(CONFIG_DEVFREQ_GOV_POD_SCALING) += governor_pod_scaling.o - obj-$(CONFIG_DEVFREQ_GOV_POD_SCALING_V2) += governor_pod_scaling_v2.o -endif +obj-m += governor_pod_scaling.o diff --git a/drivers/devfreq/governor_pod_scaling.c b/drivers/devfreq/governor_pod_scaling.c index bbbadbb4..14c02b72 100644 --- a/drivers/devfreq/governor_pod_scaling.c +++ b/drivers/devfreq/governor_pod_scaling.c @@ -13,22 +13,21 @@ * */ -#include -#include -#include #include -#include -#include #include +#include +#include +#include #include - +#include +#include +#include +#include +#include #define CREATE_TRACE_POINTS #include -#include "governor.h" - -#include -#include +#include #define GET_TARGET_FREQ_DONTSCALE 1 @@ -108,6 +107,45 @@ enum podgov_adjustment_type { ADJUSTMENT_DEVICE_REQ = 1 }; +#define HZ_PER_KHZ 1000 + +static void get_freq_range(struct devfreq *devfreq, + unsigned long *min_freq, + unsigned long *max_freq) +{ + unsigned long *freq_table = devfreq->profile->freq_table; + + lockdep_assert_held(&devfreq->lock); + + if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) { + *min_freq = freq_table[0]; + *max_freq = freq_table[devfreq->profile->max_state - 1]; + } else { + *min_freq = freq_table[devfreq->profile->max_state - 1]; + *max_freq = freq_table[0]; + } + + /* Apply constraints from OPP interface */ + *min_freq = max(*min_freq, devfreq->scaling_min_freq); + *max_freq = min(*max_freq, devfreq->scaling_max_freq); + + if (*min_freq > *max_freq) + *min_freq = *max_freq; +} + +static void get_min_freq_limit(struct devfreq *df, unsigned long *min_freq_hz) +{ + unsigned long max_freq_hz; + + get_freq_range(df, min_freq_hz, &max_freq_hz); +} + +static void get_max_freq_limit(struct devfreq *df, unsigned long *max_freq_hz) +{ + unsigned long min_freq_hz; + + get_freq_range(df, &min_freq_hz, max_freq_hz); +} /******************************************************************************* * scaling_limit(df, freq) @@ -117,10 +155,16 @@ enum podgov_adjustment_type { static void scaling_limit(struct devfreq *df, unsigned long *freq) { - if (*freq < df->min_freq) - *freq = df->min_freq; - else if (*freq > df->max_freq) - *freq = df->max_freq; + unsigned long min_freq_hz = 0; + unsigned long max_freq_hz = 0; + + get_min_freq_limit(df, &min_freq_hz); + get_max_freq_limit(df, &max_freq_hz); + + if (*freq < min_freq_hz) + *freq = min_freq_hz; + else if (*freq > max_freq_hz) + *freq = max_freq_hz; } /******************************************************************************* @@ -145,14 +189,6 @@ static void podgov_enable(struct devfreq *df, int enable) trace_podgov_enabled(df->dev.parent, enable); - /* bad configuration. quit. */ - if (df->min_freq == df->max_freq) { - mutex_unlock(&df->lock); - mutex_unlock(&podgov->lock); - pm_runtime_put(dev); - return; - } - /* store the enable information */ podgov->enable = enable; @@ -160,7 +196,7 @@ static void podgov_enable(struct devfreq *df, int enable) * suspended */ if (!enable && pm_runtime_active(dev)) { /* full speed */ - podgov->adjustment_frequency = df->max_freq; + get_max_freq_limit(df, &podgov->adjustment_frequency); podgov->adjustment_type = ADJUSTMENT_LOCAL; update_devfreq(df); } @@ -284,6 +320,7 @@ static unsigned long scaling_state_check(struct devfreq *df, ktime_t time) struct devfreq_dev_status *ds = &df->last_status; unsigned long dt, busyness, rt_load = pg->rt_load; long max_boost, damp, freq, boost, res; + unsigned long max_freq_hz = 0; dt = (unsigned long) ktime_us_delta(time, pg->last_scale); if (dt < pg->p_block_window || df->previous_freq == 0) @@ -291,7 +328,8 @@ static unsigned long scaling_state_check(struct devfreq *df, ktime_t time) /* convert to mhz to avoid overflow */ freq = df->previous_freq / 1000000; - max_boost = (df->max_freq/3) / 1000000; + get_max_freq_limit(df, &max_freq_hz); + max_boost = ((max_freq_hz / 3) / 1000000); /* calculate and trace load */ busyness = 1000ULL * pg->cycles_avg / ds->current_frequency; @@ -366,11 +404,12 @@ static int freqlist_up(struct podgov_info_rec *podgov, unsigned long target, static void nvhost_scale_emc_debug_init(struct devfreq *df) { struct podgov_info_rec *podgov = df->data; - struct dentry *f; char dirname[128]; + int err; - snprintf(dirname, sizeof(dirname), "%s_scaling", + err = snprintf(dirname, sizeof(dirname), "%s_scaling", to_platform_device(df->dev.parent)->name); + WARN_ON(err < 0); if (!podgov) return; @@ -383,12 +422,8 @@ static void nvhost_scale_emc_debug_init(struct devfreq *df) #define CREATE_PODGOV_FILE(fname) \ do {\ - f = debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, \ + debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, \ podgov->debugdir, &podgov->p_##fname); \ - if (NULL == f) { \ - pr_err("podgov: can\'t create file " #fname "\n"); \ - return; \ - } \ } while (0) CREATE_PODGOV_FILE(block_window); @@ -433,6 +468,7 @@ static ssize_t enable_3d_scaling_show(struct kobject *kobj, ssize_t res; res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->enable); + WARN_ON(res < 0); return res; } @@ -469,6 +505,7 @@ static ssize_t user_show(struct kobject *kobj, ssize_t res; res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->p_user); + WARN_ON(res < 0); return res; } @@ -498,6 +535,7 @@ static ssize_t freq_request_show(struct kobject *kobj, ssize_t res; res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->p_freq_request); + WARN_ON(res < 0); return res; } @@ -549,7 +587,7 @@ static int nvhost_pod_estimate_freq(struct devfreq *df, * min freq. */ if (pg->suspended) { - *freq = df->min_freq; + *freq = DEVFREQ_MIN_FREQ; pg->last_scale = ktime_get(); i = 0; for (; i < MAX_HISTORY_BUF_SIZE; i++) @@ -563,7 +601,7 @@ static int nvhost_pod_estimate_freq(struct devfreq *df, /* Ensure maximal clock when scaling is disabled */ if (!pg->enable) { - *freq = df->max_freq; + *freq = DEVFREQ_MAX_FREQ; if (*freq == df->previous_freq) return GET_TARGET_FREQ_DONTSCALE; else @@ -735,9 +773,7 @@ static int nvhost_pod_init(struct devfreq *df) goto err_get_freqs; /* store the limits */ - df->min_freq = podgov->freqlist[0]; - df->max_freq = podgov->freqlist[podgov->freq_count - 1]; - podgov->p_freq_request = df->max_freq; + podgov->p_freq_request = podgov->freqlist[podgov->freq_count - 1]; podgov->freq_avg = 0; @@ -803,10 +839,9 @@ static void nvhost_pod_suspend(struct devfreq *df) // Update frequency for the final time before going into suspension. mutex_lock(&df->lock); - df->suspended = false; update_devfreq(df); - df->suspended = true; mutex_unlock(&df->lock); + devfreq_monitor_suspend(df); } @@ -839,8 +874,8 @@ static int nvhost_pod_event_handler(struct devfreq *df, case DEVFREQ_GOV_STOP: nvhost_pod_exit(df); break; - case DEVFREQ_GOV_INTERVAL: - devfreq_interval_update(df, (unsigned int *)data); + case DEVFREQ_GOV_UPDATE_INTERVAL: + devfreq_update_interval(df, (unsigned int *)data); break; case DEVFREQ_GOV_SUSPEND: nvhost_pod_suspend(df); diff --git a/drivers/devfreq/governor_pod_scaling_v2.c b/drivers/devfreq/governor_pod_scaling_v2.c deleted file mode 100644 index 6f7552c6..00000000 --- a/drivers/devfreq/governor_pod_scaling_v2.c +++ /dev/null @@ -1,943 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2012-2023, NVIDIA CORPORATION. All rights reserved. - */ - -/* - * Power-on-demand clock scaling for nvhost devices - * - * devfreq calls nvhost_pod_estimate_freq() for estimating the new - * frequency for the device. The clocking is done using the load of the device - * is estimated using the busy times from the device profile. This information - * indicates if the device frequency should be altered. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define CREATE_TRACE_POINTS -#include - -#ifndef GOVERNOR_POD_SCALING_V2_MODULE -#include "governor.h" -#else -#include "governor_v2.h" -#endif // GOVERNOR_POD_SCALING_V2_MODULE - -#include -#include - -#define GET_TARGET_FREQ_DONTSCALE 1 - -#ifdef CONFIG_DEVFREQ_GOV_POD_SCALING_HISTORY_BUFFER_SIZE_MAX -#define MAX_HISTORY_BUF_SIZE \ - CONFIG_DEVFREQ_GOV_POD_SCALING_HISTORY_BUFFER_SIZE_MAX -#else -#define MAX_HISTORY_BUF_SIZE 0 -#endif - -static void podgov_enable(struct devfreq *df, int enable); -static void podgov_set_user_ctl(struct devfreq *df, int enable); - -static struct devfreq_governor nvhost_podgov; - -/******************************************************************************* - * podgov_info_rec - gr3d scaling governor specific parameters - ******************************************************************************/ - -struct podgov_info_rec { - int enable; - int suspended; - int init; - - ktime_t last_scale; - - unsigned int p_block_window; - unsigned int p_smooth; - int p_damp; - int p_load_max; - int p_load_target; - int p_bias; - unsigned int p_user; - unsigned int p_freq_request; - - unsigned long cycles_norm; - unsigned long cycles_avg; - - unsigned long *cycles_history_buf; - int p_history_buf_size; - int history_next; - int history_count; - unsigned long recent_high; - - unsigned long rt_load; - - int adjustment_type; - unsigned long adjustment_frequency; - - struct devfreq *power_manager; - struct dentry *debugdir; - - unsigned long *freqlist; - int freq_count; - - int freq_avg; - - struct kobj_attribute enable_3d_scaling_attr; - struct kobj_attribute user_attr; - struct kobj_attribute freq_request_attr; - - struct mutex lock; -}; - -/******************************************************************************* - * Adjustment type is used to tell the source that requested frequency re- - * estimation. Type ADJUSTMENT_LOCAL indicates that the re-estimation was - * initiated by the governor itself. This happens when one of the worker - * threads want to adjust the frequency. - * - * ADJUSTMENT_DEVICE_REQ (default value) indicates that the adjustment was - * initiated by a device event. - ******************************************************************************/ - -enum podgov_adjustment_type { - ADJUSTMENT_LOCAL = 0, - ADJUSTMENT_DEVICE_REQ = 1 -}; - -#define HZ_PER_KHZ 1000 - -#ifdef GOVERNOR_POD_SCALING_V2_MODULE -static void get_freq_range(struct devfreq *devfreq, - unsigned long *min_freq, - unsigned long *max_freq) -{ - unsigned long *freq_table = devfreq->profile->freq_table; - - lockdep_assert_held(&devfreq->lock); - - if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) { - *min_freq = freq_table[0]; - *max_freq = freq_table[devfreq->profile->max_state - 1]; - } else { - *min_freq = freq_table[devfreq->profile->max_state - 1]; - *max_freq = freq_table[0]; - } - - /* Apply constraints from OPP interface */ - *min_freq = max(*min_freq, devfreq->scaling_min_freq); - *max_freq = min(*max_freq, devfreq->scaling_max_freq); - - if (*min_freq > *max_freq) - *min_freq = *max_freq; -} - -static void get_min_freq_limit(struct devfreq *df, unsigned long *min_freq_hz) -{ - unsigned long max_freq_hz; - - get_freq_range(df, min_freq_hz, &max_freq_hz); -} - -static void get_max_freq_limit(struct devfreq *df, unsigned long *max_freq_hz) -{ - unsigned long min_freq_hz; - - get_freq_range(df, &min_freq_hz, max_freq_hz); -} -#else -static void get_min_freq_limit(struct devfreq *df, unsigned long *min_freq_hz) -{ - s32 qos_min_freq = 0; - - /* Apply constraints from PM QoS */ - qos_min_freq = dev_pm_qos_read_value(df->dev.parent, - DEV_PM_QOS_MIN_FREQUENCY); - - *min_freq_hz = (unsigned long)HZ_PER_KHZ * qos_min_freq; -} - -static void get_max_freq_limit(struct devfreq *df, unsigned long *max_freq_hz) -{ - s32 qos_max_freq = 0; - - /* Apply constraints from PM QoS */ - qos_max_freq = dev_pm_qos_read_value(df->dev.parent, - DEV_PM_QOS_MAX_FREQUENCY); - - *max_freq_hz = (unsigned long)HZ_PER_KHZ * qos_max_freq; -} -#endif // GOVERNOR_POD_SCALING_V2_MODULE - -/******************************************************************************* - * scaling_limit(df, freq) - * - * Limit the given frequency - ******************************************************************************/ - -static void scaling_limit(struct devfreq *df, unsigned long *freq) -{ - unsigned long min_freq_hz = 0; - unsigned long max_freq_hz = 0; - - get_min_freq_limit(df, &min_freq_hz); - get_max_freq_limit(df, &max_freq_hz); - - if (*freq < min_freq_hz) - *freq = min_freq_hz; - else if (*freq > max_freq_hz) - *freq = max_freq_hz; -} - -/******************************************************************************* - * podgov_enable(dev, enable) - * - * This function enables (enable=1) or disables (enable=0) the automatic scaling - * of the device. If the device is disabled, the device's clock is set to its - * maximum. - ******************************************************************************/ - -static void podgov_enable(struct devfreq *df, int enable) -{ - struct device *dev = df->dev.parent; - struct podgov_info_rec *podgov = df->data; - bool polling; - - /* make sure the device is alive before doing any scaling */ - pm_runtime_get_noresume(dev); - - mutex_lock(&podgov->lock); - mutex_lock(&df->lock); - - trace_podgov_enabled(df->dev.parent, enable); - - /* store the enable information */ - podgov->enable = enable; - - /* skip local adjustment if we are enabling or the device is - * suspended */ - if (!enable && pm_runtime_active(dev)) { - /* full speed */ - get_max_freq_limit(df, &podgov->adjustment_frequency); - podgov->adjustment_type = ADJUSTMENT_LOCAL; - update_devfreq(df); - } - - polling = podgov->enable && !podgov->p_user; - - /* Need to unlock to call devfreq_monitor_suspend/resume() - * still holding podgov->lock to guarantee atomicity - */ - mutex_unlock(&df->lock); - - if (polling) - devfreq_monitor_resume(df); - else - devfreq_monitor_suspend(df); - - mutex_unlock(&podgov->lock); - pm_runtime_put(dev); -} - -/***************************************************************************** - * podgov_set_user_ctl(dev, user) - * - * This function enables or disables user control of the gpu. If user control - * is enabled, setting the freq_request controls the gpu frequency, and other - * gpu scaling mechanisms are disabled. - ******************************************************************************/ - -static void podgov_set_user_ctl(struct devfreq *df, int user) -{ - struct device *dev = df->dev.parent; - struct podgov_info_rec *podgov = df->data; - int old_user; - bool polling; - - /* make sure the device is alive before doing any scaling */ - pm_runtime_get_noresume(dev); - - mutex_lock(&podgov->lock); - mutex_lock(&df->lock); - - trace_podgov_set_user_ctl(df->dev.parent, user); - - /* store the new user value */ - old_user = podgov->p_user; - podgov->p_user = user; - - /* skip scaling, if scaling (or the whole device) is turned off - * - or the scaling already was in user mode */ - if (pm_runtime_active(dev) && podgov->enable && user && !old_user) { - /* write request */ - podgov->adjustment_frequency = podgov->p_freq_request; - podgov->adjustment_type = ADJUSTMENT_LOCAL; - update_devfreq(df); - } - - polling = podgov->enable && !podgov->p_user; - - /* Need to unlock to call devfreq_monitor_suspend/resume() - * still holding podgov->lock to guarantee atomicity - */ - mutex_unlock(&df->lock); - - if (polling) - devfreq_monitor_resume(df); - else - devfreq_monitor_suspend(df); - - mutex_unlock(&podgov->lock); - pm_runtime_put(dev); -} - -/***************************************************************************** - * podgov_set_freq_request(dev, user) - * - * Set the current freq request. If scaling is enabled, and podgov user space - * control is enabled, this will set the gpu frequency. - ******************************************************************************/ - -static void podgov_set_freq_request(struct devfreq *df, int freq_request) -{ - struct device *dev = df->dev.parent; - struct podgov_info_rec *podgov; - - /* make sure the device is alive before doing any scaling */ - pm_runtime_get_noresume(dev); - - mutex_lock(&df->lock); - - podgov = df->data; - - trace_podgov_set_freq_request(df->dev.parent, freq_request); - - podgov->p_freq_request = freq_request; - - /* update the request only if podgov is enabled, device is turned on - * and the scaling is in user mode */ - if (podgov->enable && podgov->p_user && - pm_runtime_active(dev)) { - podgov->adjustment_frequency = freq_request; - podgov->adjustment_type = ADJUSTMENT_LOCAL; - update_devfreq(df); - } - - mutex_unlock(&df->lock); - pm_runtime_put(dev); -} - - -/******************************************************************************* - * freq = scaling_state_check(df, time) - * - * This handler is called to adjust the frequency of the device. The function - * returns the desired frequency for the clock. If there is no need to tune the - * clock immediately, 0 is returned. - ******************************************************************************/ - -static unsigned long scaling_state_check(struct devfreq *df, ktime_t time) -{ - struct podgov_info_rec *pg = df->data; - struct devfreq_dev_status *ds = &df->last_status; - unsigned long dt, busyness, rt_load = pg->rt_load; - long max_boost, damp, freq, boost, res; - unsigned long max_freq_hz = 0; - - dt = (unsigned long) ktime_us_delta(time, pg->last_scale); - if (dt < pg->p_block_window || df->previous_freq == 0) - return 0; - - /* convert to mhz to avoid overflow */ - freq = df->previous_freq / 1000000; - get_max_freq_limit(df, &max_freq_hz); - max_boost = ((max_freq_hz / 3) / 1000000); - - /* calculate and trace load */ - busyness = 1000ULL * pg->cycles_avg / ds->current_frequency; - - /* consider recent high load if required */ - if (pg->p_history_buf_size && pg->history_count) - busyness = 1000ULL * pg->recent_high / ds->current_frequency; - - trace_podgov_load(df->dev.parent, rt_load); - trace_podgov_busy(df->dev.parent, busyness); - - damp = pg->p_damp; - - if (rt_load > pg->p_load_max) { - /* if too busy, scale up max/3, do not damp */ - boost = max_boost; - damp = 10; - } else { - /* boost = bias * freq * (busyness - target)/target */ - boost = busyness - pg->p_load_target; - boost *= (pg->p_bias * freq); - boost /= (100 * pg->p_load_target); - - /* clamp to max boost */ - boost = (boost < max_boost) ? boost : max_boost; - } - - /* calculate new request */ - res = freq + boost; - - /* Maintain average request */ - pg->freq_avg = (pg->freq_avg * pg->p_smooth) + res; - pg->freq_avg /= (pg->p_smooth+1); - - /* Applying damping to frequencies */ - res = ((damp * res) + ((10 - damp)*pg->freq_avg)) / 10; - - /* Convert to hz, limit, and apply */ - res = res * 1000000; - scaling_limit(df, &res); - trace_podgov_scaling_state_check(df->dev.parent, - df->previous_freq, res); - return res; -} - -/******************************************************************************* - * freqlist_up(podgov, target, steps) - * - * This function determines the frequency that is "steps" frequency steps - * higher compared to the target frequency. - ******************************************************************************/ - -static int freqlist_up(struct podgov_info_rec *podgov, unsigned long target, - int steps) -{ - int i, pos; - - for (i = 0; i < podgov->freq_count; i++) - if (podgov->freqlist[i] >= target) - break; - - pos = min(podgov->freq_count - 1, i + steps); - return podgov->freqlist[pos]; -} - -/******************************************************************************* - * debugfs interface for controlling 3d clock scaling on the fly - ******************************************************************************/ - -#ifdef CONFIG_DEBUG_FS - -static void nvhost_scale_emc_debug_init(struct devfreq *df) -{ - struct podgov_info_rec *podgov = df->data; - char dirname[128]; - int err; - - err = snprintf(dirname, sizeof(dirname), "%s_scaling", - to_platform_device(df->dev.parent)->name); - WARN_ON(err < 0); - - if (!podgov) - return; - - podgov->debugdir = debugfs_create_dir(dirname, NULL); - if (!podgov->debugdir) { - pr_err("podgov: can\'t create debugfs directory\n"); - return; - } - -#define CREATE_PODGOV_FILE(fname) \ - do {\ - debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, \ - podgov->debugdir, &podgov->p_##fname); \ - } while (0) - - CREATE_PODGOV_FILE(block_window); - CREATE_PODGOV_FILE(load_max); - CREATE_PODGOV_FILE(load_target); - CREATE_PODGOV_FILE(bias); - CREATE_PODGOV_FILE(damp); - CREATE_PODGOV_FILE(smooth); -#undef CREATE_PODGOV_FILE -} - -static void nvhost_scale_emc_debug_deinit(struct devfreq *df) -{ - struct podgov_info_rec *podgov = df->data; - - debugfs_remove_recursive(podgov->debugdir); -} - -#else -static void nvhost_scale_emc_debug_init(struct devfreq *df) -{ - (void)df; -} - -static void nvhost_scale_emc_debug_deinit(struct devfreq *df) -{ - (void)df; -} -#endif - -/******************************************************************************* - * sysfs interface for enabling/disabling 3d scaling - ******************************************************************************/ - -static ssize_t enable_3d_scaling_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct podgov_info_rec *podgov = container_of(attr, - struct podgov_info_rec, - enable_3d_scaling_attr); - ssize_t res; - - res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->enable); - WARN_ON(res < 0); - - return res; -} - -static ssize_t enable_3d_scaling_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct podgov_info_rec *podgov = container_of(attr, - struct podgov_info_rec, - enable_3d_scaling_attr); - unsigned long val = 0; - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - podgov_enable(podgov->power_manager, val); - - return count; -} - -/******************************************************************************* - * sysfs interface for user space control - * user = [0,1] disables / enabled user space control - * freq_request is the sysfs node user space writes frequency requests to - ******************************************************************************/ - -static ssize_t user_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct podgov_info_rec *podgov = - container_of(attr, struct podgov_info_rec, user_attr); - ssize_t res; - - res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->p_user); - WARN_ON(res < 0); - - return res; -} - -static ssize_t user_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct podgov_info_rec *podgov = - container_of(attr, struct podgov_info_rec, user_attr); - unsigned long val = 0; - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - podgov_set_user_ctl(podgov->power_manager, val); - - return count; -} - -static ssize_t freq_request_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct podgov_info_rec *podgov = - container_of(attr, struct podgov_info_rec, freq_request_attr); - ssize_t res; - - res = snprintf(buf, PAGE_SIZE, "%d\n", podgov->p_freq_request); - WARN_ON(res < 0); - - return res; -} - -static ssize_t freq_request_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct podgov_info_rec *podgov = - container_of(attr, struct podgov_info_rec, freq_request_attr); - unsigned long val = 0; - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - podgov_set_freq_request(podgov->power_manager, val); - - return count; -} - -/******************************************************************************* - * nvhost_pod_estimate_freq(df, freq) - * - * This function is called for re-estimating the frequency. The function is - * called in three conditions: - * - * (1) Internal request to change the frequency. In this case a new clock - * target is immediately set for the device. - * (2) Call from the client (something has happened and re-estimation - * is required). - * (3) Some other reason (i.e. periodic call) - * - ******************************************************************************/ - -static int nvhost_pod_estimate_freq(struct devfreq *df, - unsigned long *freq) -{ - struct podgov_info_rec *pg = df->data; - struct devfreq_dev_status *ds; - int err, i; - int buf_size = pg->p_history_buf_size; - int buf_next = pg->history_next; - int buf_count = pg->history_count; - unsigned long *cycles_buffer = pg->cycles_history_buf; - ktime_t now; - unsigned long long norm_load; - - /* If the device is suspended, clear the history and set frequency to - * min freq. - */ - if (pg->suspended) { - *freq = DEVFREQ_MIN_FREQ; - pg->last_scale = ktime_get(); - i = 0; - for (; i < MAX_HISTORY_BUF_SIZE; i++) - pg->cycles_history_buf[i] = 0; - pg->history_count = 0; - pg->history_next = 0; - pg->recent_high = 0; - pg->freq_avg = 0; - return 0; - } - - /* Ensure maximal clock when scaling is disabled */ - if (!pg->enable) { - *freq = DEVFREQ_MAX_FREQ; - if (*freq == df->previous_freq) - return GET_TARGET_FREQ_DONTSCALE; - else - return 0; - } - - if (pg->p_user) { - *freq = pg->p_freq_request; - return 0; - } - - err = devfreq_update_stats(df); - if (err) - return err; - - ds = &df->last_status; - - if (ds->total_time == 0) { - *freq = ds->current_frequency; - return 0; - } - - now = ktime_get(); - - /* Local adjustments (i.e. requests from kernel threads) are - * handled here */ - - if (pg->adjustment_type == ADJUSTMENT_LOCAL) { - - pg->adjustment_type = ADJUSTMENT_DEVICE_REQ; - - /* Do not do unnecessary scaling */ - scaling_limit(df, &pg->adjustment_frequency); - - trace_podgov_estimate_freq(df->dev.parent, - df->previous_freq, - pg->adjustment_frequency); - - *freq = pg->adjustment_frequency; - return 0; - } - - /* Sustain local variables */ - norm_load = (u64)ds->current_frequency * ds->busy_time / ds->total_time; - pg->cycles_norm = norm_load; - pg->cycles_avg = ((u64)pg->cycles_avg * pg->p_smooth + norm_load) / - (pg->p_smooth + 1); - pg->rt_load = 1000ULL * ds->busy_time / ds->total_time; - - /* Update history of normalized cycle counts and recent highest count */ - if (buf_size) { - if (buf_count == buf_size) { - pg->recent_high = 0; - i = (buf_next + 1) % buf_size; - for (; i != buf_next; i = (i + 1) % buf_size) { - if (cycles_buffer[i] > pg->recent_high) - pg->recent_high = cycles_buffer[i]; - } - } - cycles_buffer[buf_next] = norm_load; - pg->history_next = (buf_next + 1) % buf_size; - if (buf_count < buf_size) - pg->history_count += 1; - if (norm_load > pg->recent_high) - pg->recent_high = norm_load; - } - - *freq = scaling_state_check(df, now); - - if (!(*freq)) { - *freq = ds->current_frequency; - return 0; - } - - if ((*freq = freqlist_up(pg, *freq, 0)) == ds->current_frequency) - return 0; - - pg->last_scale = now; - - trace_podgov_estimate_freq(df->dev.parent, df->previous_freq, *freq); - - - return 0; -} - -/******************************************************************************* - * nvhost_pod_init(struct devfreq *df) - * - * Governor initialisation. - ******************************************************************************/ - -static int nvhost_pod_init(struct devfreq *df) -{ - struct podgov_info_rec *podgov; - struct platform_device *d = to_platform_device(df->dev.parent); - ktime_t now = ktime_get(); - - struct kobj_attribute *attr = NULL; - - podgov = kzalloc(sizeof(struct podgov_info_rec), GFP_KERNEL); - if (!podgov) - goto err_alloc_podgov; - - podgov->cycles_history_buf = - kzalloc(sizeof(unsigned long) * MAX_HISTORY_BUF_SIZE, - GFP_KERNEL); - if (!podgov->cycles_history_buf) - goto err_alloc_history_buffer; - - podgov->p_history_buf_size = - MAX_HISTORY_BUF_SIZE < 100 ? MAX_HISTORY_BUF_SIZE : 100; - podgov->history_count = 0; - podgov->history_next = 0; - podgov->recent_high = 0; - - df->data = (void *)podgov; - - /* Set scaling parameter defaults */ - podgov->enable = 1; - podgov->suspended = 0; - - podgov->p_load_max = 900; - podgov->p_load_target = 700; - podgov->p_bias = 80; - podgov->p_smooth = 10; - podgov->p_damp = 7; - podgov->p_block_window = 50000; - - podgov->adjustment_type = ADJUSTMENT_DEVICE_REQ; - podgov->p_user = 0; - - /* Reset clock counters */ - podgov->last_scale = now; - - podgov->power_manager = df; - - mutex_init(&podgov->lock); - - attr = &podgov->enable_3d_scaling_attr; - attr->attr.name = "enable_3d_scaling"; - attr->attr.mode = S_IWUSR | S_IRUGO; - attr->show = enable_3d_scaling_show; - attr->store = enable_3d_scaling_store; - sysfs_attr_init(&attr->attr); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_enable_sysfs_entry; - - attr = &podgov->freq_request_attr; - attr->attr.name = "freq_request"; - attr->attr.mode = S_IWUSR | S_IRUGO; - attr->show = freq_request_show; - attr->store = freq_request_store; - sysfs_attr_init(&attr->attr); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_request_sysfs_entry; - - attr = &podgov->user_attr; - attr->attr.name = "user"; - attr->attr.mode = S_IWUSR | S_IRUGO; - attr->show = user_show; - attr->store = user_store; - sysfs_attr_init(&attr->attr); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_user_sysfs_entry; - - podgov->freq_count = df->profile->max_state; - podgov->freqlist = df->profile->freq_table; - if (!podgov->freq_count || !podgov->freqlist) - goto err_get_freqs; - - /* store the limits */ - podgov->p_freq_request = podgov->freqlist[podgov->freq_count - 1]; - - podgov->freq_avg = 0; - - nvhost_scale_emc_debug_init(df); - - devfreq_monitor_start(df); - - return 0; - -err_get_freqs: - sysfs_remove_file(&df->dev.parent->kobj, &podgov->user_attr.attr); -err_create_user_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &podgov->freq_request_attr.attr); -err_create_request_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &podgov->enable_3d_scaling_attr.attr); -err_create_enable_sysfs_entry: - dev_err(&d->dev, "failed to create sysfs attributes"); - kfree(podgov->cycles_history_buf); -err_alloc_history_buffer: - kfree(podgov); -err_alloc_podgov: - return -ENOMEM; -} - -/******************************************************************************* - * nvhost_pod_exit(struct devfreq *df) - * - * Clean up governor data structures - ******************************************************************************/ - -static void nvhost_pod_exit(struct devfreq *df) -{ - struct podgov_info_rec *podgov = df->data; - - devfreq_monitor_stop(df); - - sysfs_remove_file(&df->dev.parent->kobj, &podgov->user_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &podgov->freq_request_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &podgov->enable_3d_scaling_attr.attr); - - nvhost_scale_emc_debug_deinit(df); - kfree(podgov->cycles_history_buf); - kfree(podgov); -} - -/****************************************************************************** - * nvhost_pod_suspend(struct devfreq *df) - * - * Suspends the governor. - *****************************************************************************/ - -static void nvhost_pod_suspend(struct devfreq *df) -{ - // Record suspension in our own data structure because we'll have to - // erase and restore devfreq's for this to work. - struct podgov_info_rec *pg = df->data; - - pg->suspended = 1; - - // Update frequency for the final time before going into suspension. - mutex_lock(&df->lock); - update_devfreq(df); - mutex_unlock(&df->lock); - - devfreq_monitor_suspend(df); -} - -/****************************************************************************** - * nvhost_pod_resume(struct devfreq *df) - * - * Resumes the governor. - *****************************************************************************/ - -static void nvhost_pod_resume(struct devfreq *df) -{ - // Update our data structure's suspension field - struct podgov_info_rec *pg = df->data; - - pg->suspended = 0; - - // Resume - devfreq_monitor_resume(df); -} - -static int nvhost_pod_event_handler(struct devfreq *df, - unsigned int event, void *data) -{ - int ret = 0; - - switch (event) { - case DEVFREQ_GOV_START: - ret = nvhost_pod_init(df); - break; - case DEVFREQ_GOV_STOP: - nvhost_pod_exit(df); - break; - case DEVFREQ_GOV_UPDATE_INTERVAL: - devfreq_update_interval(df, (unsigned int *)data); - break; - case DEVFREQ_GOV_SUSPEND: - nvhost_pod_suspend(df); - break; - case DEVFREQ_GOV_RESUME: - nvhost_pod_resume(df); - break; - default: - break; - } - - return ret; -} - -static struct devfreq_governor nvhost_podgov = { - .name = "nvhost_podgov", - .get_target_freq = nvhost_pod_estimate_freq, - .event_handler = nvhost_pod_event_handler, -}; - - -static int __init podgov_init(void) -{ - return devfreq_add_governor(&nvhost_podgov); -} - -static void __exit podgov_exit(void) -{ - devfreq_remove_governor(&nvhost_podgov); - return; -} - -/* governor must be registered before initialising client devices */ -rootfs_initcall(podgov_init); -module_exit(podgov_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_wmark_active.c b/drivers/devfreq/governor_wmark_active.c deleted file mode 100644 index 9852c893..00000000 --- a/drivers/devfreq/governor_wmark_active.c +++ /dev/null @@ -1,823 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "governor.h" - -#define CREATE_TRACE_POINTS -#include - -struct wmark_gov_param { - unsigned int block_window; - unsigned int load_target; - unsigned int load_max; - unsigned int smooth; - unsigned int high_wmark_margin; - unsigned int low_wmark_margin; - bool freq_boost_en; -}; - -struct wmark_gov_info { - /* probed from the devfreq */ - unsigned long *freqlist; - int freq_count; - - /* algorithm parameters */ - struct wmark_gov_param param; - - struct kobj_attribute block_window_attr; - struct kobj_attribute load_target_attr; - struct kobj_attribute load_max_attr; - struct kobj_attribute smooth_attr; - struct kobj_attribute high_wmark_margin_attr; - struct kobj_attribute low_wmark_margin_attr; - struct kobj_attribute freq_boost_en_attr; - - spinlock_t param_lock; - - /* common data */ - struct devfreq *df; - struct platform_device *pdev; - struct dentry *debugdir; - - /* used for ensuring that we do not update frequency too often */ - ktime_t last_frequency_update; - - /* variable for keeping the average frequency request */ - unsigned long long average_target_freq; - - /* devfreq notifier_block */ - struct notifier_block nb; -}; - -static unsigned long freqlist_up(struct wmark_gov_info *wmarkinfo, - unsigned long curr_freq) -{ - unsigned long flags; - int i, pos; - int margin; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - if (wmarkinfo->param.high_wmark_margin > INT_MAX) - margin = wmarkinfo->freq_count - 1; - else - margin = wmarkinfo->param.high_wmark_margin; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - for (i = 0; i < wmarkinfo->freq_count; i++) - if (wmarkinfo->freqlist[i] > curr_freq) - break; - - pos = min(wmarkinfo->freq_count - 1, i + margin); - - return wmarkinfo->freqlist[pos]; -} - -static unsigned long freqlist_down(struct wmark_gov_info *wmarkinfo, - unsigned long curr_freq) -{ - unsigned long flags; - int i, pos; - int margin; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - if (wmarkinfo->param.low_wmark_margin > INT_MAX) - margin = wmarkinfo->freq_count - 1; - else - margin = wmarkinfo->param.low_wmark_margin; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - for (i = wmarkinfo->freq_count - 1; i >= 0; i--) - if (wmarkinfo->freqlist[i] < curr_freq) - break; - - pos = max(0, i - margin); - return wmarkinfo->freqlist[pos]; -} - -static unsigned long freqlist_round(struct wmark_gov_info *wmarkinfo, - unsigned long freq) -{ - int i, pos; - - for (i = 0; i < wmarkinfo->freq_count; i++) - if (wmarkinfo->freqlist[i] >= freq) - break; - - pos = min(wmarkinfo->freq_count - 1, i); - return wmarkinfo->freqlist[pos]; -} - - - /* - * update_watermarks - Re-estimate low and high watermarks - * @df: pointer to the devfreq structure - * @current_frequency: current frequency of the device - * @ideal_frequency: frequency that would change load to target load. - * - * This function updates the devfreq high and low watermarks. Target is - * to ensure that the interrupts are triggered whenever the load changes - * enough to make a change to the ideal frequency (given the DVFS table). - */ - -static void update_watermarks(struct devfreq *df, - unsigned long current_frequency, - unsigned long ideal_frequency) -{ - struct wmark_gov_info *wmarkinfo = df->data; - unsigned long long relation = 0, next_freq = 0; - unsigned long long current_frequency_khz = current_frequency / 1000; - unsigned long flags; - struct wmark_gov_param param; - - /* get governor parameters */ - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - - param = wmarkinfo->param; - - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - if (ideal_frequency == wmarkinfo->freqlist[0]) { - /* disable the low watermark if we are at lowest clock */ - df->profile->set_low_wmark(df->dev.parent, 0); - } else { - /* calculate the low threshold; what is the load value - * at which we would go into lower frequency given the - * that we are running at the new frequency? */ - next_freq = freqlist_down(wmarkinfo, ideal_frequency); - relation = ((next_freq / current_frequency_khz) * - param.load_target) / 1000; - df->profile->set_low_wmark(df->dev.parent, relation); - } - - if (ideal_frequency == - wmarkinfo->freqlist[wmarkinfo->freq_count - 1]) { - /* disable the high watermark if we are at highest clock */ - df->profile->set_high_wmark(df->dev.parent, 1000); - } else { - /* calculate the high threshold; what is the load value - * at which we would go into highest frequency given the - * that we are running at the new frequency? */ - next_freq = freqlist_up(wmarkinfo, ideal_frequency); - relation = ((next_freq / current_frequency_khz) * - param.load_target) / 1000; - relation = min_t(unsigned long long, param.load_max, - relation); - df->profile->set_high_wmark(df->dev.parent, relation); - } -} - -static int devfreq_watermark_target_freq(struct devfreq *df, - unsigned long *freq) -{ - struct wmark_gov_info *wmarkinfo = df->data; - struct platform_device *pdev = wmarkinfo->pdev; - struct devfreq_dev_status dev_stat; - unsigned long long load, relation, ideal_freq; - ktime_t current_time = ktime_get(); - s64 dt = ktime_us_delta(current_time, wmarkinfo->last_frequency_update); - int err; - unsigned long flags; - - struct wmark_gov_param param; - - err = df->profile->get_dev_status(df->dev.parent, &dev_stat); - if (err < 0) - return err; - - /* use current frequency by default */ - *freq = dev_stat.current_frequency; - - /* quit now if we are getting calls too often */ - if (!dev_stat.total_time) - return 0; - - /* get governor parameters */ - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - - param = wmarkinfo->param; - - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - /* calculate first load and relation load/load_target */ - load = (dev_stat.busy_time * 1000) / dev_stat.total_time; - - /* if we cross load max... */ - if (param.freq_boost_en && load >= param.load_max) { - /* we go directly to the highest frequency. depending - * on frequency table we might never go higher than - * the current frequency (i.e. load should be over 100% - * to make relation push to the next frequency). */ - ideal_freq = wmarkinfo->freqlist[wmarkinfo->freq_count - 1]; - } else { - /* otherwise, based on relation between current load and - * load target we calculate the "ideal" frequency - * where we would be just at the target */ - relation = (load * 1000) / param.load_target; - ideal_freq = relation * (dev_stat.current_frequency / 1000); - - /* round this frequency */ - ideal_freq = freqlist_round(wmarkinfo, ideal_freq); - } - - /* update average target frequency */ - wmarkinfo->average_target_freq = - (param.smooth * wmarkinfo->average_target_freq + - ideal_freq) / (param.smooth + 1); - - /* do not scale too often */ - if (dt < param.block_window) - return 0; - - /* update the frequency */ - *freq = freqlist_round(wmarkinfo, wmarkinfo->average_target_freq); - trace_devfreq_watermark_target_freq(pdev->name, load, *freq); - - /* check if frequency actually got updated */ - if (*freq == dev_stat.current_frequency) - return 0; - - /* enable hysteresis - frequency is updated */ - wmarkinfo->last_frequency_update = current_time; - - return 0; -} - -static ssize_t block_window_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - unsigned int val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - block_window_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.block_window; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%u\n", val); - - return res; -} - -static ssize_t block_window_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned long val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - block_window_attr); - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.block_window = val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count; -} - -static ssize_t load_target_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - unsigned int val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - load_target_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.load_target; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%u\n", val); - - return res; -} - -static ssize_t load_target_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned long val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - load_target_attr); - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.load_target = val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count; -} - -static ssize_t load_max_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - unsigned int val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - load_max_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.load_max; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%u\n", val); - - return res; -} - -static ssize_t load_max_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned long val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - load_max_attr); - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.load_max = val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count; -} - -static ssize_t smooth_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - unsigned int val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - smooth_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.smooth; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%u\n", val); - - return res; -} - -static ssize_t smooth_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned long val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - smooth_attr); - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.smooth = val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count; -} - -static ssize_t high_wmark_margin_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - unsigned int val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - high_wmark_margin_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.high_wmark_margin; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%u\n", val); - if (res >= PAGE_SIZE) - return -EINVAL; - - return res; -} - -static ssize_t high_wmark_margin_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned int val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - high_wmark_margin_attr); - - if (kstrtou32(buf, 0, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.high_wmark_margin = val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count <= INT_MAX ? count : -EINVAL; - -} - -static ssize_t low_wmark_margin_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - unsigned int val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - low_wmark_margin_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.low_wmark_margin; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%u\n", val); - if (res >= PAGE_SIZE) - return -EINVAL; - - return res; -} - -static ssize_t low_wmark_margin_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned int val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - low_wmark_margin_attr); - - if (kstrtou32(buf, 0, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.low_wmark_margin = val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count <= INT_MAX ? count : -EINVAL; -} - -static ssize_t freq_boost_en_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct wmark_gov_info *wmarkinfo = NULL; - ssize_t res; - bool val; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - freq_boost_en_attr); - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - val = wmarkinfo->param.freq_boost_en; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - res = snprintf(buf, PAGE_SIZE, "%d\n", val); - - return res; -} - -static ssize_t freq_boost_en_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - struct wmark_gov_info *wmarkinfo = NULL; - unsigned long val = 0; - unsigned long flags; - - wmarkinfo = container_of(attr, - struct wmark_gov_info, - freq_boost_en_attr); - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - spin_lock_irqsave(&wmarkinfo->param_lock, flags); - wmarkinfo->param.freq_boost_en = !!val; - spin_unlock_irqrestore(&wmarkinfo->param_lock, flags); - - return count; -} - -#define INIT_SYSFS_ATTR_RW(sysfs_name) \ - do { \ - attr->attr.name = #sysfs_name; \ - attr->attr.mode = 0644; \ - attr->show = sysfs_name##_show; \ - attr->store = sysfs_name##_store; \ - sysfs_attr_init(&attr->attr); \ - } while (0) - -static int devfreq_watermark_debug_start(struct devfreq *df) -{ - struct wmark_gov_info *wmarkinfo = df->data; - struct kobj_attribute *attr = NULL; - - if (!wmarkinfo) - return 0; - - spin_lock_init(&wmarkinfo->param_lock); - - attr = &wmarkinfo->block_window_attr; - INIT_SYSFS_ATTR_RW(block_window); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_block_window_sysfs_entry; - - attr = &wmarkinfo->load_target_attr; - INIT_SYSFS_ATTR_RW(load_target); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_load_target_sysfs_entry; - - attr = &wmarkinfo->load_max_attr; - INIT_SYSFS_ATTR_RW(load_max); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_load_max_sysfs_entry; - - attr = &wmarkinfo->smooth_attr; - INIT_SYSFS_ATTR_RW(smooth); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_smooth_sysfs_entry; - - attr = &wmarkinfo->high_wmark_margin_attr; - INIT_SYSFS_ATTR_RW(high_wmark_margin); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_high_wmark_margin_sysfs_entry; - - attr = &wmarkinfo->low_wmark_margin_attr; - INIT_SYSFS_ATTR_RW(low_wmark_margin); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_low_wmark_margin_sysfs_entry; - - attr = &wmarkinfo->freq_boost_en_attr; - INIT_SYSFS_ATTR_RW(freq_boost_en); - if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr)) - goto err_create_freq_boost_en_sysfs_entry; - - return 0; - -err_create_freq_boost_en_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->low_wmark_margin_attr.attr); -err_create_low_wmark_margin_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->high_wmark_margin_attr.attr); -err_create_high_wmark_margin_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->smooth_attr.attr); -err_create_smooth_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->load_max_attr.attr); -err_create_load_max_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->load_target_attr.attr); -err_create_load_target_sysfs_entry: - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->block_window_attr.attr); -err_create_block_window_sysfs_entry: - - return -ENOMEM; -} - -static void devfreq_watermark_debug_stop(struct devfreq *df) -{ - struct wmark_gov_info *wmarkinfo = df->data; - - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->freq_boost_en_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->high_wmark_margin_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->low_wmark_margin_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->smooth_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->load_max_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->load_target_attr.attr); - sysfs_remove_file(&df->dev.parent->kobj, - &wmarkinfo->block_window_attr.attr); -} - -static int devfreq_watermark_start(struct devfreq *df) -{ - struct wmark_gov_info *wmarkinfo; - struct platform_device *pdev = to_platform_device(df->dev.parent); - int ret; - - if (!df->profile->freq_table) { - dev_err(&pdev->dev, "Frequency table missing\n"); - return -EINVAL; - } - - wmarkinfo = kzalloc(sizeof(struct wmark_gov_info), GFP_KERNEL); - if (!wmarkinfo) - return -ENOMEM; - - df->data = (void *)wmarkinfo; - wmarkinfo->freqlist = df->profile->freq_table; - wmarkinfo->freq_count = df->profile->max_state; - wmarkinfo->param.load_target = 700; - wmarkinfo->param.load_max = 900; - wmarkinfo->param.smooth = 10; - wmarkinfo->param.block_window = 50000; - wmarkinfo->param.freq_boost_en = true; - wmarkinfo->df = df; - wmarkinfo->pdev = pdev; - - ret = devfreq_watermark_debug_start(df); - - return ret; -} - -static int devfreq_watermark_notifier_call(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct wmark_gov_info *data - = container_of(nb, struct wmark_gov_info, nb); - struct devfreq *df = (struct devfreq *)data->df; - unsigned long freq = 0; - - switch (event) { - case DEVFREQ_PRECHANGE: - break; - case DEVFREQ_POSTCHANGE: - /* get device freq. */ - df->profile->get_cur_freq(df->dev.parent, &freq); - - /* update watermarks by current device freq. */ - if (freq) - update_watermarks(df, freq, freq); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -static int devfreq_watermark_event_handler(struct devfreq *df, - unsigned int event, void *wmark_type) -{ - struct wmark_gov_info *wmarkinfo; - int ret = 0; - struct notifier_block *nb; - - switch (event) { - case DEVFREQ_GOV_START: - { - struct devfreq_dev_status dev_stat; - ret = df->profile->get_dev_status(df->dev.parent, &dev_stat); - if (ret < 0) - break; - - ret = devfreq_watermark_start(df); - if (ret < 0) - break; - - /* initialize average target freq */ - wmarkinfo = df->data; - wmarkinfo->average_target_freq = dev_stat.current_frequency; - - update_watermarks(df, dev_stat.current_frequency, - dev_stat.current_frequency); - - nb = &wmarkinfo->nb; - nb->notifier_call = devfreq_watermark_notifier_call; - ret = devm_devfreq_register_notifier(df->dev.parent, - df, nb, DEVFREQ_TRANSITION_NOTIFIER); - break; - } - case DEVFREQ_GOV_STOP: - devfreq_watermark_debug_stop(df); - - wmarkinfo = df->data; - nb = &wmarkinfo->nb; - devm_devfreq_unregister_notifier(df->dev.parent, - df, nb, DEVFREQ_TRANSITION_NOTIFIER); - - /* free wmark_gov_info struct */ - if (df->data != NULL) { - kfree(df->data); - df->data = NULL; - } - - break; - case DEVFREQ_GOV_SUSPEND: - devfreq_monitor_suspend(df); - break; - case DEVFREQ_GOV_RESUME: - { - struct devfreq_dev_status dev_stat; - ret = df->profile->get_dev_status(df->dev.parent, &dev_stat); - if (ret < 0) - break; - - /* reset average target freq to current freq */ - wmarkinfo = df->data; - wmarkinfo->average_target_freq = dev_stat.current_frequency; - - update_watermarks(df, dev_stat.current_frequency, - dev_stat.current_frequency); - devfreq_monitor_resume(df); - break; - } - case DEVFREQ_GOV_WMARK: - mutex_lock(&df->lock); - update_devfreq(df); - mutex_unlock(&df->lock); - break; - default: - break; - } - - return ret; -} - -static struct devfreq_governor devfreq_watermark_active = { - .name = "wmark_active", - .get_target_freq = devfreq_watermark_target_freq, - .event_handler = devfreq_watermark_event_handler, - .interrupt_driven = true, -}; - - -static int __init devfreq_watermark_init(void) -{ - return devfreq_add_governor(&devfreq_watermark_active); -} - -static void __exit devfreq_watermark_exit(void) -{ - devfreq_remove_governor(&devfreq_watermark_active); -} - -subsys_initcall(devfreq_watermark_init); -module_exit(devfreq_watermark_exit); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/devfreq/governor_wmark_simple.c b/drivers/devfreq/governor_wmark_simple.c deleted file mode 100644 index 631fd775..00000000 --- a/drivers/devfreq/governor_wmark_simple.c +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -enum watermark_type { - NO_WATERMARK_EVENT = 0, - HIGH_WATERMARK_EVENT = 1, - LOW_WATERMARK_EVENT = 2 -}; - -struct wmark_gov_info { - /* probed from the devfreq */ - unsigned long *freqlist; - int freq_count; - - /* algorithm parameters */ - unsigned int p_high_wmark; - unsigned int p_low_wmark; - - /* dynamically changing data */ - enum watermark_type event; - unsigned long last_request; - - /* common data */ - struct devfreq *df; - struct platform_device *pdev; - struct dentry *debugdir; -}; - -static unsigned long freqlist_up(struct wmark_gov_info *wmarkinfo, - unsigned long curr_freq) -{ - int i, pos; - - for (i = 0; i < wmarkinfo->freq_count; i++) - if (wmarkinfo->freqlist[i] > curr_freq) - break; - - pos = min(wmarkinfo->freq_count - 1, i); - - return wmarkinfo->freqlist[pos]; -} - -static unsigned long freqlist_down(struct wmark_gov_info *wmarkinfo, - unsigned long curr_freq) -{ - int i, pos; - - for (i = wmarkinfo->freq_count - 1; i >= 0; i--) - if (wmarkinfo->freqlist[i] < curr_freq) - break; - - pos = max(0, i); - return wmarkinfo->freqlist[pos]; -} - -static int devfreq_watermark_target_freq(struct devfreq *df, - unsigned long *freq) -{ - struct wmark_gov_info *wmarkinfo = df->data; - struct devfreq_dev_status dev_stat; - int err; - - err = df->profile->get_dev_status(df->dev.parent, &dev_stat); - if (err < 0) - return err; - - switch (wmarkinfo->event) { - case HIGH_WATERMARK_EVENT: - *freq = freqlist_up(wmarkinfo, dev_stat.current_frequency); - - /* always enable low watermark */ - df->profile->set_low_wmark(df->dev.parent, - wmarkinfo->p_low_wmark); - - /* disable high watermark if no change */ - if (*freq == wmarkinfo->last_request) - df->profile->set_high_wmark(df->dev.parent, 1000); - break; - case LOW_WATERMARK_EVENT: - *freq = freqlist_down(wmarkinfo, dev_stat.current_frequency); - - /* always enable high watermark */ - df->profile->set_high_wmark(df->dev.parent, - wmarkinfo->p_high_wmark); - - /* disable low watermark if no change */ - if (*freq == wmarkinfo->last_request) - df->profile->set_low_wmark(df->dev.parent, 0); - break; - default: - break; - } - - /* Mark that you handled event */ - wmarkinfo->event = NO_WATERMARK_EVENT; - wmarkinfo->last_request = *freq; - - return 0; -} - -static void devfreq_watermark_debug_start(struct devfreq *df) -{ - struct wmark_gov_info *wmarkinfo = df->data; - struct dentry *f; - char dirname[128]; - - snprintf(dirname, sizeof(dirname), "%s_scaling", - to_platform_device(df->dev.parent)->name); - - if (!wmarkinfo) - return; - - wmarkinfo->debugdir = debugfs_create_dir(dirname, NULL); - if (!wmarkinfo->debugdir) { - pr_warn("cannot create debugfs directory\n"); - return; - } - -#define CREATE_DBG_FILE(fname) \ - do {\ - f = debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, \ - wmarkinfo->debugdir, &wmarkinfo->p_##fname); \ - if (NULL == f) { \ - pr_warn("cannot create debug entry " #fname "\n"); \ - return; \ - } \ - } while (0) - - CREATE_DBG_FILE(low_wmark); - CREATE_DBG_FILE(high_wmark); -#undef CREATE_DBG_FILE - -} - -static void devfreq_watermark_debug_stop(struct devfreq *df) -{ - struct wmark_gov_info *wmarkinfo = df->data; - debugfs_remove_recursive(wmarkinfo->debugdir); -} - -static int devfreq_watermark_start(struct devfreq *df) -{ - struct wmark_gov_info *wmarkinfo; - struct platform_device *pdev = to_platform_device(df->dev.parent); - - if (!df->profile->freq_table) { - dev_err(&pdev->dev, "Frequency table missing\n"); - return -EINVAL; - } - - wmarkinfo = kzalloc(sizeof(struct wmark_gov_info), GFP_KERNEL); - if (!wmarkinfo) - return -ENOMEM; - - df->data = (void *)wmarkinfo; - wmarkinfo->freqlist = df->profile->freq_table; - wmarkinfo->freq_count = df->profile->max_state; - wmarkinfo->event = NO_WATERMARK_EVENT; - wmarkinfo->df = df; - wmarkinfo->pdev = pdev; - wmarkinfo->p_low_wmark = 100; - wmarkinfo->p_high_wmark = 600; - - devfreq_watermark_debug_start(df); - - return 0; -} - -static int devfreq_watermark_event_handler(struct devfreq *df, - unsigned int event, void *wmark_type) -{ - int ret = 0; - struct wmark_gov_info *wmarkinfo = df->data; - enum watermark_type *type = wmark_type; - - switch (event) { - case DEVFREQ_GOV_START: - devfreq_watermark_start(df); - wmarkinfo = df->data; - if (df->profile->set_low_wmark) - df->profile->set_low_wmark(df->dev.parent, - wmarkinfo->p_low_wmark); - if (df->profile->set_high_wmark) - df->profile->set_high_wmark(df->dev.parent, - wmarkinfo->p_high_wmark); - break; - case DEVFREQ_GOV_STOP: - devfreq_watermark_debug_stop(df); - break; - case DEVFREQ_GOV_SUSPEND: - devfreq_monitor_suspend(df); - break; - - case DEVFREQ_GOV_RESUME: - if (df->profile->set_low_wmark) - df->profile->set_low_wmark(df->dev.parent, - wmarkinfo->p_low_wmark); - if (df->profile->set_high_wmark) - df->profile->set_high_wmark(df->dev.parent, - wmarkinfo->p_high_wmark); - devfreq_monitor_resume(df); - break; - - case DEVFREQ_GOV_WMARK: - /* Set watermark interrupt type */ - wmarkinfo->event = *type; - - mutex_lock(&df->lock); - update_devfreq(df); - mutex_unlock(&df->lock); - - break; - - default: - break; - } - - return ret; -} - -static struct devfreq_governor devfreq_watermark = { - .name = "wmark_simple", - .get_target_freq = devfreq_watermark_target_freq, - .event_handler = devfreq_watermark_event_handler, -}; - - -static int __init devfreq_watermark_init(void) -{ - return devfreq_add_governor(&devfreq_watermark); -} - -static void __exit devfreq_watermark_exit(void) -{ - devfreq_remove_governor(&devfreq_watermark); -} - -rootfs_initcall(devfreq_watermark_init); -module_exit(devfreq_watermark_exit); diff --git a/drivers/devfreq/governor_v2.h b/include/drivers-private/devfreq/governor.h similarity index 91% rename from drivers/devfreq/governor_v2.h rename to include/drivers-private/devfreq/governor.h index 765896bb..f650e5f6 100644 --- a/drivers/devfreq/governor_v2.h +++ b/include/drivers-private/devfreq/governor.h @@ -7,9 +7,10 @@ * governor.h - internal header for devfreq governors. * This header is for devfreq governors in drivers/devfreq/ */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) + #ifndef _GOVERNOR_H #define _GOVERNOR_H + #include #define DEVFREQ_NAME_LEN 16 @@ -85,8 +86,6 @@ int devfreq_remove_governor(struct devfreq_governor *governor); int devfreq_update_status(struct devfreq *devfreq, unsigned long freq); int devfreq_update_target(struct devfreq *devfreq, unsigned long freq); -void devfreq_get_freq_range(struct devfreq *devfreq, unsigned long *min_freq, - unsigned long *max_freq); static inline int devfreq_update_stats(struct devfreq *df) { @@ -96,4 +95,3 @@ static inline int devfreq_update_stats(struct devfreq *df) return df->profile->get_dev_status(df->dev.parent, &df->last_status); } #endif /* _GOVERNOR_H */ -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) */