Loading drivers/devfreq/governor_msm_adreno_tz.c +234 −2 Original line number Diff line number Diff line Loading @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/errno.h> #include <linux/module.h> #include <linux/devfreq.h> Loading @@ -26,6 +31,7 @@ static DEFINE_SPINLOCK(tz_lock); static DEFINE_SPINLOCK(sample_lock); static DEFINE_SPINLOCK(sample_load_lock); static DEFINE_SPINLOCK(suspend_lock); /* * FLOOR is 5msec to capture up to 3 re-draws Loading Loading @@ -58,9 +64,26 @@ static DEFINE_SPINLOCK(suspend_lock); #define TAG "msm_adreno_tz: " static u64 suspend_time; static u64 suspend_start; #define USEC_PER_MINUTE (1*60*1000*1000) #define NMAX (15*60*60+1) struct gpu_load_data { unsigned long total_time; unsigned long busy_time; u64 update_time; }; struct gpu_load_queue { struct gpu_load_data *gpu_load; int head; int tail; }; static u64 suspend_time, suspend_time_idd; static u64 suspend_start, suspend_start_idd; static unsigned long acc_total, acc_relative_busy; static unsigned long gpu_load_total, gpu_load_rel_busy; static struct gpu_load_queue *gpu_load_infos; static struct msm_adreno_extended_profile *partner_gpu_profile; static void do_partner_start_event(struct work_struct *work); Loading Loading @@ -88,6 +111,21 @@ u64 suspend_time_ms(void) return time_diff; } u64 suspend_time_ms_idd(void) { u64 suspend_sampling_time; u64 time_diff = 0; if (suspend_start_idd == 0) return 0; suspend_sampling_time = (u64)ktime_to_ms(ktime_get()); time_diff = suspend_sampling_time - suspend_start_idd; /* Update the suspend_start sample again */ suspend_start_idd = suspend_sampling_time; return time_diff; } static ssize_t gpu_load_show(struct device *dev, struct device_attribute *attr, char *buf) Loading @@ -109,6 +147,135 @@ static ssize_t gpu_load_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%lu\n", sysfs_busy_perc); } int findItem(int head, int tail, u64 refTime) { int low = head, high = tail, middle; u64 update_time; while (low < high) { middle = (low + high) / 2; update_time = gpu_load_infos->gpu_load[middle % NMAX].update_time; if (update_time <= refTime) low = middle + 1; else if (update_time > refTime) high = middle - 1; } update_time = gpu_load_infos->gpu_load[low % NMAX].update_time; if (update_time > refTime) low = low - 1; if (low < tail) { u64 l = gpu_load_infos->gpu_load[low % NMAX].update_time; u64 r = gpu_load_infos->gpu_load[(low+1) % NMAX].update_time; if (r - refTime < refTime - l) low = low + 1; } return low % NMAX; } unsigned long cal_gpu_load(u64 current_time, u64 update_time, u64 begin_time, int minutes) { unsigned long sysfs_busy_perc; unsigned long tmp_act_relative_busy, tmp_act_total; int tail = gpu_load_infos->tail, head = gpu_load_infos->head; if (current_time - update_time > minutes * USEC_PER_MINUTE) { sysfs_busy_perc = 0; } else { int tmpIndex = head; if (current_time - begin_time <= minutes * USEC_PER_MINUTE) { tmpIndex = head; } else { u64 begin = current_time - minutes * USEC_PER_MINUTE; int tmpTail = (tail < head) ? tail + NMAX : tail; tmpIndex = findItem(head, tmpTail-1, begin); } tmp_act_relative_busy = gpu_load_infos->gpu_load[tail-1].busy_time - gpu_load_infos->gpu_load[tmpIndex].busy_time; tmp_act_total = current_time - gpu_load_infos->gpu_load[tmpIndex].update_time; sysfs_busy_perc = (tmp_act_relative_busy * 100 * 10) / tmp_act_total; } return sysfs_busy_perc; } void convert_int_to_string(unsigned long perc, char *str, unsigned int size) { char low[6] = "0"; char mid[] = "."; snprintf(str, sizeof(low), "%lu", (perc / 10)); snprintf(low, sizeof(low), "%lu", (perc % 10)); strlcat(str, mid, size); strlcat(str, low, size); } static ssize_t gpu_period_load_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long sysfs_busy_perc[3]; int tail, head; char load[3][6] = {"0", "0", "0"}; int i; unsigned int size; spin_lock(&sample_load_lock); tail = gpu_load_infos->tail; head = gpu_load_infos->head; if (tail == head) { sysfs_busy_perc[0] = 0; sysfs_busy_perc[1] = 0; sysfs_busy_perc[2] = 0; } else { u64 current_time = (u64)ktime_to_us(ktime_get()); u64 update_time = gpu_load_infos->gpu_load[tail-1].update_time; u64 begin_time = gpu_load_infos->gpu_load[head].update_time; sysfs_busy_perc[0] = cal_gpu_load(current_time, update_time, begin_time, 1); sysfs_busy_perc[1] = cal_gpu_load(current_time, update_time, begin_time, 5); sysfs_busy_perc[2] = cal_gpu_load(current_time, update_time, begin_time, 15); } for (i = 0; i < 3; i++) { size = sizeof(load[i]); convert_int_to_string(sysfs_busy_perc[i], load[i], size); } spin_unlock(&sample_load_lock); return snprintf(buf, PAGE_SIZE, "%s %s %s\n", load[0], load[1], load[2] ); } static ssize_t gpu_load_idd_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long busy, total; spin_lock(&sample_load_lock); busy = gpu_load_rel_busy; total = gpu_load_total; spin_unlock(&sample_load_lock); return snprintf(buf, PAGE_SIZE, "%lu %lu\n", busy, total); } /* * Returns the time in ms for which gpu was in suspend state * since last time the entry is read. Loading @@ -134,7 +301,30 @@ static ssize_t suspend_time_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%llu\n", time_diff); } static ssize_t suspend_time_idd_show(struct device *dev, struct device_attribute *attr, char *buf) { u64 time_diff = 0; spin_lock(&suspend_lock); time_diff = suspend_time_ms_idd(); /* * Adding the previous suspend time also as the gpu * can go and come out of suspend states in between * reads also and we should have the total suspend * since last read. */ suspend_time_idd += time_diff; spin_unlock(&suspend_lock); return snprintf(buf, PAGE_SIZE, "%llu\n", suspend_time_idd); } static DEVICE_ATTR(gpu_load, 0444, gpu_load_show, NULL); static DEVICE_ATTR(gpu_period_load, 0444, gpu_period_load_show, NULL); static DEVICE_ATTR(gpu_load_idd, 0444, gpu_load_idd_show, NULL); static DEVICE_ATTR(gpu_suspend_idd, 0444, suspend_time_idd_show, NULL); static DEVICE_ATTR(suspend_time, 0444, suspend_time_show, Loading @@ -142,10 +332,30 @@ static DEVICE_ATTR(suspend_time, 0444, static const struct device_attribute *adreno_tz_attr_list[] = { &dev_attr_gpu_load, &dev_attr_gpu_period_load, &dev_attr_gpu_load_idd, &dev_attr_gpu_suspend_idd, &dev_attr_suspend_time, NULL }; void store_work_load(unsigned long gpu_load_total, unsigned long gpu_load_busy) { /* Queue item to gpu_load_queue */ int index = gpu_load_infos->tail; int head = gpu_load_infos->head; gpu_load_infos->gpu_load[index].total_time = gpu_load_total; gpu_load_infos->gpu_load[index].busy_time = gpu_load_busy; gpu_load_infos->gpu_load[index].update_time = (u64)ktime_to_us(ktime_get()); if ((index + 1) % NMAX == head) gpu_load_infos->head = (head + 1) % NMAX; gpu_load_infos->tail = (index + 1) % NMAX; } void compute_work_load(struct devfreq_dev_status *stats, struct devfreq_msm_adreno_tz_data *priv, struct devfreq *devfreq) Loading @@ -164,6 +374,15 @@ void compute_work_load(struct devfreq_dev_status *stats, acc_relative_busy += busy; spin_unlock(&sample_lock); spin_lock(&sample_load_lock); gpu_load_total += stats->total_time; gpu_load_rel_busy += (stats->busy_time * stats->current_frequency) / devfreq->profile->freq_table[0]; store_work_load(gpu_load_total, gpu_load_rel_busy); spin_unlock(&sample_load_lock); } /* Trap into the TrustZone, and call funcs there. */ Loading Loading @@ -234,6 +453,14 @@ static int __secure_tz_update_entry3(unsigned int *scm_data, u32 size_scm_data, return ret; } static void tz_init_gpuloadinfos(void) { gpu_load_infos = kzalloc(sizeof(struct gpu_load_queue), GFP_KERNEL); gpu_load_infos->head = gpu_load_infos->tail = 0; gpu_load_infos->gpu_load = kcalloc(NMAX, sizeof(struct gpu_load_data), GFP_KERNEL); } static int tz_init_ca(struct devfreq_msm_adreno_tz_data *priv) { unsigned int tz_ca_data[2]; Loading Loading @@ -273,6 +500,8 @@ static int tz_init(struct devfreq_msm_adreno_tz_data *priv, unsigned int *version, u32 size_version) { int ret; tz_init_gpuloadinfos(); /* Make sure all CMD IDs are avaialble */ if (scm_is_call_available(SCM_SVC_DCVS, TZ_INIT_ID)) { ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels, Loading Loading @@ -560,6 +789,7 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) spin_lock(&suspend_lock); /* Collect the start sample for suspend time */ suspend_start = (u64)ktime_to_ms(ktime_get()); suspend_start_idd = suspend_start; spin_unlock(&suspend_lock); } break; Loading @@ -567,8 +797,10 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) case DEVFREQ_GOV_RESUME: spin_lock(&suspend_lock); suspend_time += suspend_time_ms(); suspend_time_idd += suspend_time_ms_idd(); /* Reset the suspend_start when gpu resumes */ suspend_start = 0; suspend_start_idd = 0; spin_unlock(&suspend_lock); case DEVFREQ_GOV_INTERVAL: Loading Loading
drivers/devfreq/governor_msm_adreno_tz.c +234 −2 Original line number Diff line number Diff line Loading @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/errno.h> #include <linux/module.h> #include <linux/devfreq.h> Loading @@ -26,6 +31,7 @@ static DEFINE_SPINLOCK(tz_lock); static DEFINE_SPINLOCK(sample_lock); static DEFINE_SPINLOCK(sample_load_lock); static DEFINE_SPINLOCK(suspend_lock); /* * FLOOR is 5msec to capture up to 3 re-draws Loading Loading @@ -58,9 +64,26 @@ static DEFINE_SPINLOCK(suspend_lock); #define TAG "msm_adreno_tz: " static u64 suspend_time; static u64 suspend_start; #define USEC_PER_MINUTE (1*60*1000*1000) #define NMAX (15*60*60+1) struct gpu_load_data { unsigned long total_time; unsigned long busy_time; u64 update_time; }; struct gpu_load_queue { struct gpu_load_data *gpu_load; int head; int tail; }; static u64 suspend_time, suspend_time_idd; static u64 suspend_start, suspend_start_idd; static unsigned long acc_total, acc_relative_busy; static unsigned long gpu_load_total, gpu_load_rel_busy; static struct gpu_load_queue *gpu_load_infos; static struct msm_adreno_extended_profile *partner_gpu_profile; static void do_partner_start_event(struct work_struct *work); Loading Loading @@ -88,6 +111,21 @@ u64 suspend_time_ms(void) return time_diff; } u64 suspend_time_ms_idd(void) { u64 suspend_sampling_time; u64 time_diff = 0; if (suspend_start_idd == 0) return 0; suspend_sampling_time = (u64)ktime_to_ms(ktime_get()); time_diff = suspend_sampling_time - suspend_start_idd; /* Update the suspend_start sample again */ suspend_start_idd = suspend_sampling_time; return time_diff; } static ssize_t gpu_load_show(struct device *dev, struct device_attribute *attr, char *buf) Loading @@ -109,6 +147,135 @@ static ssize_t gpu_load_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%lu\n", sysfs_busy_perc); } int findItem(int head, int tail, u64 refTime) { int low = head, high = tail, middle; u64 update_time; while (low < high) { middle = (low + high) / 2; update_time = gpu_load_infos->gpu_load[middle % NMAX].update_time; if (update_time <= refTime) low = middle + 1; else if (update_time > refTime) high = middle - 1; } update_time = gpu_load_infos->gpu_load[low % NMAX].update_time; if (update_time > refTime) low = low - 1; if (low < tail) { u64 l = gpu_load_infos->gpu_load[low % NMAX].update_time; u64 r = gpu_load_infos->gpu_load[(low+1) % NMAX].update_time; if (r - refTime < refTime - l) low = low + 1; } return low % NMAX; } unsigned long cal_gpu_load(u64 current_time, u64 update_time, u64 begin_time, int minutes) { unsigned long sysfs_busy_perc; unsigned long tmp_act_relative_busy, tmp_act_total; int tail = gpu_load_infos->tail, head = gpu_load_infos->head; if (current_time - update_time > minutes * USEC_PER_MINUTE) { sysfs_busy_perc = 0; } else { int tmpIndex = head; if (current_time - begin_time <= minutes * USEC_PER_MINUTE) { tmpIndex = head; } else { u64 begin = current_time - minutes * USEC_PER_MINUTE; int tmpTail = (tail < head) ? tail + NMAX : tail; tmpIndex = findItem(head, tmpTail-1, begin); } tmp_act_relative_busy = gpu_load_infos->gpu_load[tail-1].busy_time - gpu_load_infos->gpu_load[tmpIndex].busy_time; tmp_act_total = current_time - gpu_load_infos->gpu_load[tmpIndex].update_time; sysfs_busy_perc = (tmp_act_relative_busy * 100 * 10) / tmp_act_total; } return sysfs_busy_perc; } void convert_int_to_string(unsigned long perc, char *str, unsigned int size) { char low[6] = "0"; char mid[] = "."; snprintf(str, sizeof(low), "%lu", (perc / 10)); snprintf(low, sizeof(low), "%lu", (perc % 10)); strlcat(str, mid, size); strlcat(str, low, size); } static ssize_t gpu_period_load_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long sysfs_busy_perc[3]; int tail, head; char load[3][6] = {"0", "0", "0"}; int i; unsigned int size; spin_lock(&sample_load_lock); tail = gpu_load_infos->tail; head = gpu_load_infos->head; if (tail == head) { sysfs_busy_perc[0] = 0; sysfs_busy_perc[1] = 0; sysfs_busy_perc[2] = 0; } else { u64 current_time = (u64)ktime_to_us(ktime_get()); u64 update_time = gpu_load_infos->gpu_load[tail-1].update_time; u64 begin_time = gpu_load_infos->gpu_load[head].update_time; sysfs_busy_perc[0] = cal_gpu_load(current_time, update_time, begin_time, 1); sysfs_busy_perc[1] = cal_gpu_load(current_time, update_time, begin_time, 5); sysfs_busy_perc[2] = cal_gpu_load(current_time, update_time, begin_time, 15); } for (i = 0; i < 3; i++) { size = sizeof(load[i]); convert_int_to_string(sysfs_busy_perc[i], load[i], size); } spin_unlock(&sample_load_lock); return snprintf(buf, PAGE_SIZE, "%s %s %s\n", load[0], load[1], load[2] ); } static ssize_t gpu_load_idd_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long busy, total; spin_lock(&sample_load_lock); busy = gpu_load_rel_busy; total = gpu_load_total; spin_unlock(&sample_load_lock); return snprintf(buf, PAGE_SIZE, "%lu %lu\n", busy, total); } /* * Returns the time in ms for which gpu was in suspend state * since last time the entry is read. Loading @@ -134,7 +301,30 @@ static ssize_t suspend_time_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%llu\n", time_diff); } static ssize_t suspend_time_idd_show(struct device *dev, struct device_attribute *attr, char *buf) { u64 time_diff = 0; spin_lock(&suspend_lock); time_diff = suspend_time_ms_idd(); /* * Adding the previous suspend time also as the gpu * can go and come out of suspend states in between * reads also and we should have the total suspend * since last read. */ suspend_time_idd += time_diff; spin_unlock(&suspend_lock); return snprintf(buf, PAGE_SIZE, "%llu\n", suspend_time_idd); } static DEVICE_ATTR(gpu_load, 0444, gpu_load_show, NULL); static DEVICE_ATTR(gpu_period_load, 0444, gpu_period_load_show, NULL); static DEVICE_ATTR(gpu_load_idd, 0444, gpu_load_idd_show, NULL); static DEVICE_ATTR(gpu_suspend_idd, 0444, suspend_time_idd_show, NULL); static DEVICE_ATTR(suspend_time, 0444, suspend_time_show, Loading @@ -142,10 +332,30 @@ static DEVICE_ATTR(suspend_time, 0444, static const struct device_attribute *adreno_tz_attr_list[] = { &dev_attr_gpu_load, &dev_attr_gpu_period_load, &dev_attr_gpu_load_idd, &dev_attr_gpu_suspend_idd, &dev_attr_suspend_time, NULL }; void store_work_load(unsigned long gpu_load_total, unsigned long gpu_load_busy) { /* Queue item to gpu_load_queue */ int index = gpu_load_infos->tail; int head = gpu_load_infos->head; gpu_load_infos->gpu_load[index].total_time = gpu_load_total; gpu_load_infos->gpu_load[index].busy_time = gpu_load_busy; gpu_load_infos->gpu_load[index].update_time = (u64)ktime_to_us(ktime_get()); if ((index + 1) % NMAX == head) gpu_load_infos->head = (head + 1) % NMAX; gpu_load_infos->tail = (index + 1) % NMAX; } void compute_work_load(struct devfreq_dev_status *stats, struct devfreq_msm_adreno_tz_data *priv, struct devfreq *devfreq) Loading @@ -164,6 +374,15 @@ void compute_work_load(struct devfreq_dev_status *stats, acc_relative_busy += busy; spin_unlock(&sample_lock); spin_lock(&sample_load_lock); gpu_load_total += stats->total_time; gpu_load_rel_busy += (stats->busy_time * stats->current_frequency) / devfreq->profile->freq_table[0]; store_work_load(gpu_load_total, gpu_load_rel_busy); spin_unlock(&sample_load_lock); } /* Trap into the TrustZone, and call funcs there. */ Loading Loading @@ -234,6 +453,14 @@ static int __secure_tz_update_entry3(unsigned int *scm_data, u32 size_scm_data, return ret; } static void tz_init_gpuloadinfos(void) { gpu_load_infos = kzalloc(sizeof(struct gpu_load_queue), GFP_KERNEL); gpu_load_infos->head = gpu_load_infos->tail = 0; gpu_load_infos->gpu_load = kcalloc(NMAX, sizeof(struct gpu_load_data), GFP_KERNEL); } static int tz_init_ca(struct devfreq_msm_adreno_tz_data *priv) { unsigned int tz_ca_data[2]; Loading Loading @@ -273,6 +500,8 @@ static int tz_init(struct devfreq_msm_adreno_tz_data *priv, unsigned int *version, u32 size_version) { int ret; tz_init_gpuloadinfos(); /* Make sure all CMD IDs are avaialble */ if (scm_is_call_available(SCM_SVC_DCVS, TZ_INIT_ID)) { ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels, Loading Loading @@ -560,6 +789,7 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) spin_lock(&suspend_lock); /* Collect the start sample for suspend time */ suspend_start = (u64)ktime_to_ms(ktime_get()); suspend_start_idd = suspend_start; spin_unlock(&suspend_lock); } break; Loading @@ -567,8 +797,10 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) case DEVFREQ_GOV_RESUME: spin_lock(&suspend_lock); suspend_time += suspend_time_ms(); suspend_time_idd += suspend_time_ms_idd(); /* Reset the suspend_start when gpu resumes */ suspend_start = 0; suspend_start_idd = 0; spin_unlock(&suspend_lock); case DEVFREQ_GOV_INTERVAL: Loading