Loading drivers/gpu/msm/kgsl_pwrctrl.c +23 −119 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ #define KGSL_PWRFLAGS_IRQ_ON 3 #define UPDATE_BUSY_VAL 1000000 #define UPDATE_BUSY 50 /* * Expected delay for post-interrupt processing on A3xx. Loading Loading @@ -78,30 +77,6 @@ static struct clk_pair clks[KGSL_MAX_CLKS] = { static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state); static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state); /* Update the elapsed time at a particular clock level * if the device is active(on_time = true).Otherwise * store it as sleep time. */ static void update_clk_statistics(struct kgsl_device *device, bool on_time) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_clk_stats *clkstats = &pwr->clk_stats; ktime_t elapsed; int elapsed_us; if (clkstats->start.tv64 == 0) clkstats->start = ktime_get(); clkstats->stop = ktime_get(); elapsed = ktime_sub(clkstats->stop, clkstats->start); elapsed_us = ktime_to_us(elapsed); clkstats->elapsed += elapsed_us; if (on_time) clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us; else clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us; clkstats->start = ktime_get(); } /* * Given a requested power level do bounds checking on the constraints and * return the nearest possible level Loading Loading @@ -159,8 +134,6 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, if (new_level == pwr->active_pwrlevel) return; update_clk_statistics(device, true); /* * Set the active powerlevel first in case the clocks are off - if we * don't do this then the pwrlevel change won't take effect when the Loading Loading @@ -542,49 +515,20 @@ static ssize_t kgsl_pwrctrl_gpubusy_show(struct device *dev, { int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_clk_stats *clkstats; struct kgsl_clk_stats *stats; if (device == NULL) return 0; clkstats = &device->pwrctrl.clk_stats; stats = &device->pwrctrl.clk_stats; ret = snprintf(buf, PAGE_SIZE, "%7d %7d\n", clkstats->on_time_old, clkstats->elapsed_old); stats->busy_old, stats->total_old); if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { clkstats->on_time_old = 0; clkstats->elapsed_old = 0; stats->busy_old = 0; stats->total_old = 0; } return ret; } static ssize_t kgsl_pwrctrl_gputop_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_clk_stats *clkstats; int i = 0; char *ptr = buf; if (device == NULL) return 0; clkstats = &device->pwrctrl.clk_stats; ret = snprintf(buf, PAGE_SIZE, "%7d %7d ", clkstats->on_time_old, clkstats->elapsed_old); for (i = 0, ptr += ret; i < device->pwrctrl.num_pwrlevels; i++, ptr += ret) ret = snprintf(ptr, PAGE_SIZE, "%7d ", clkstats->old_clock_time[i]); if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { clkstats->on_time_old = 0; clkstats->elapsed_old = 0; for (i = 0; i < KGSL_MAX_PWRLEVELS ; i++) clkstats->old_clock_time[i] = 0; } return (unsigned int) (ptr - buf); } static ssize_t kgsl_pwrctrl_gpu_available_frequencies_show( struct device *dev, struct device_attribute *attr, Loading Loading @@ -752,8 +696,6 @@ static DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show, kgsl_pwrctrl_idle_timer_store); static DEVICE_ATTR(gpubusy, 0444, kgsl_pwrctrl_gpubusy_show, NULL); static DEVICE_ATTR(gputop, 0444, kgsl_pwrctrl_gputop_show, NULL); static DEVICE_ATTR(gpu_available_frequencies, 0444, kgsl_pwrctrl_gpu_available_frequencies_show, NULL); Loading Loading @@ -793,7 +735,6 @@ static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_max_gpuclk, &dev_attr_idle_timer, &dev_attr_gpubusy, &dev_attr_gputop, &dev_attr_gpu_available_frequencies, &dev_attr_max_pwrlevel, &dev_attr_min_pwrlevel, Loading @@ -818,41 +759,26 @@ void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device) kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list); } static void update_statistics(struct kgsl_device *device) { struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats; unsigned int on_time = 0; int i; int num_pwrlevels = device->pwrctrl.num_pwrlevels - 1; /*PER CLK TIME*/ for (i = 0; i < num_pwrlevels; i++) { clkstats->old_clock_time[i] = clkstats->clock_time[i]; on_time += clkstats->clock_time[i]; clkstats->clock_time[i] = 0; } clkstats->old_clock_time[num_pwrlevels] = clkstats->clock_time[num_pwrlevels]; clkstats->clock_time[num_pwrlevels] = 0; clkstats->on_time_old = on_time; clkstats->elapsed_old = clkstats->elapsed; clkstats->elapsed = 0; trace_kgsl_gpubusy(device, clkstats->on_time_old, clkstats->elapsed_old); } /* Track the amount of time the gpu is on vs the total system time. * * Regularly update the percentage of busy time displayed by sysfs. */ static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time) void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy) { struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats; update_clk_statistics(device, on_time); struct kgsl_clk_stats *stats = &device->pwrctrl.clk_stats; stats->total += time; stats->busy += busy; if (stats->total < UPDATE_BUSY_VAL) return; /* Update the output regularly and reset the counters. */ if ((clkstats->elapsed > UPDATE_BUSY_VAL) || !test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { update_statistics(device); } stats->total_old = stats->total; stats->busy_old = stats->busy; stats->total = 0; stats->busy = 0; trace_kgsl_gpubusy(device, stats->busy_old, stats->total_old); } EXPORT_SYMBOL(kgsl_pwrctrl_busy_time); void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state) Loading Loading @@ -880,7 +806,6 @@ void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); } kgsl_pwrctrl_busy_time(device, true); } else if (requested_state == KGSL_STATE_SLEEP) { /* High latency clock maintenance. */ for (i = KGSL_MAX_CLKS - 1; i > 0; i--) Loading Loading @@ -911,7 +836,6 @@ void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, for (i = KGSL_MAX_CLKS - 1; i > 0; i--) if (pwr->grp_clks[i]) clk_enable(pwr->grp_clks[i]); kgsl_pwrctrl_busy_time(device, false); } } } Loading Loading @@ -1217,21 +1141,10 @@ void kgsl_idle_check(struct work_struct *work) kgsl_pwrctrl_sleep(device); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); if (device->state == KGSL_STATE_ACTIVE) { if (device->state == KGSL_STATE_ACTIVE) mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); /* * If the GPU has been too busy to sleep, make sure * that is acurately reflected in the % busy numbers. */ device->pwrctrl.clk_stats.no_nap_cnt++; if (device->pwrctrl.clk_stats.no_nap_cnt > UPDATE_BUSY) { kgsl_pwrctrl_busy_time(device, true); device->pwrctrl.clk_stats.no_nap_cnt = 0; } } } mutex_unlock(&device->mutex); Loading Loading @@ -1312,15 +1225,6 @@ _nap(struct kgsl_device *device) return 0; } static void _sleep_accounting(struct kgsl_device *device) { kgsl_pwrctrl_busy_time(device, false); device->pwrctrl.clk_stats.start = ktime_set(0, 0); kgsl_pwrscale_sleep(device); } static int _sleep(struct kgsl_device *device) { Loading @@ -1334,7 +1238,7 @@ _sleep(struct kgsl_device *device) case KGSL_STATE_NAP: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF); _sleep_accounting(device); kgsl_pwrscale_sleep(device); kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, Loading Loading @@ -1369,7 +1273,7 @@ _slumber(struct kgsl_device *device) kgsl_pwrctrl_enable(device); device->ftbl->suspend_context(device); device->ftbl->stop(device); _sleep_accounting(device); kgsl_pwrscale_sleep(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, PM_QOS_DEFAULT_VALUE); Loading drivers/gpu/msm/kgsl_pwrctrl.h +5 −8 Original line number Diff line number Diff line Loading @@ -33,14 +33,10 @@ struct platform_device; struct kgsl_clk_stats { unsigned int old_clock_time[KGSL_MAX_PWRLEVELS]; unsigned int clock_time[KGSL_MAX_PWRLEVELS]; unsigned int on_time_old; ktime_t start; ktime_t stop; unsigned int no_nap_cnt; unsigned int elapsed; unsigned int elapsed_old; unsigned int busy; unsigned int total; unsigned int busy_old; unsigned int total_old; }; struct kgsl_pwr_constraint { Loading Loading @@ -158,5 +154,6 @@ int kgsl_active_count_wait(struct kgsl_device *device, int count); void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state); int kgsl_pwrctrl_slumber(struct kgsl_device *device); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); #endif /* __KGSL_PWRCTRL_H */ drivers/gpu/msm/kgsl_pwrscale.c +1 −0 Original line number Diff line number Diff line Loading @@ -317,6 +317,7 @@ int kgsl_devfreq_get_dev_status(struct device *dev, b->mod = device->pwrctrl.bus_mod; } kgsl_pwrctrl_busy_time(device, stat->total_time, stat->busy_time); trace_kgsl_pwrstats(device, stat->total_time, &pwrscale->accum_stats); memset(&pwrscale->accum_stats, 0, sizeof(pwrscale->accum_stats)); Loading Loading
drivers/gpu/msm/kgsl_pwrctrl.c +23 −119 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ #define KGSL_PWRFLAGS_IRQ_ON 3 #define UPDATE_BUSY_VAL 1000000 #define UPDATE_BUSY 50 /* * Expected delay for post-interrupt processing on A3xx. Loading Loading @@ -78,30 +77,6 @@ static struct clk_pair clks[KGSL_MAX_CLKS] = { static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state); static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state); /* Update the elapsed time at a particular clock level * if the device is active(on_time = true).Otherwise * store it as sleep time. */ static void update_clk_statistics(struct kgsl_device *device, bool on_time) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_clk_stats *clkstats = &pwr->clk_stats; ktime_t elapsed; int elapsed_us; if (clkstats->start.tv64 == 0) clkstats->start = ktime_get(); clkstats->stop = ktime_get(); elapsed = ktime_sub(clkstats->stop, clkstats->start); elapsed_us = ktime_to_us(elapsed); clkstats->elapsed += elapsed_us; if (on_time) clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us; else clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us; clkstats->start = ktime_get(); } /* * Given a requested power level do bounds checking on the constraints and * return the nearest possible level Loading Loading @@ -159,8 +134,6 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, if (new_level == pwr->active_pwrlevel) return; update_clk_statistics(device, true); /* * Set the active powerlevel first in case the clocks are off - if we * don't do this then the pwrlevel change won't take effect when the Loading Loading @@ -542,49 +515,20 @@ static ssize_t kgsl_pwrctrl_gpubusy_show(struct device *dev, { int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_clk_stats *clkstats; struct kgsl_clk_stats *stats; if (device == NULL) return 0; clkstats = &device->pwrctrl.clk_stats; stats = &device->pwrctrl.clk_stats; ret = snprintf(buf, PAGE_SIZE, "%7d %7d\n", clkstats->on_time_old, clkstats->elapsed_old); stats->busy_old, stats->total_old); if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { clkstats->on_time_old = 0; clkstats->elapsed_old = 0; stats->busy_old = 0; stats->total_old = 0; } return ret; } static ssize_t kgsl_pwrctrl_gputop_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_clk_stats *clkstats; int i = 0; char *ptr = buf; if (device == NULL) return 0; clkstats = &device->pwrctrl.clk_stats; ret = snprintf(buf, PAGE_SIZE, "%7d %7d ", clkstats->on_time_old, clkstats->elapsed_old); for (i = 0, ptr += ret; i < device->pwrctrl.num_pwrlevels; i++, ptr += ret) ret = snprintf(ptr, PAGE_SIZE, "%7d ", clkstats->old_clock_time[i]); if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { clkstats->on_time_old = 0; clkstats->elapsed_old = 0; for (i = 0; i < KGSL_MAX_PWRLEVELS ; i++) clkstats->old_clock_time[i] = 0; } return (unsigned int) (ptr - buf); } static ssize_t kgsl_pwrctrl_gpu_available_frequencies_show( struct device *dev, struct device_attribute *attr, Loading Loading @@ -752,8 +696,6 @@ static DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show, kgsl_pwrctrl_idle_timer_store); static DEVICE_ATTR(gpubusy, 0444, kgsl_pwrctrl_gpubusy_show, NULL); static DEVICE_ATTR(gputop, 0444, kgsl_pwrctrl_gputop_show, NULL); static DEVICE_ATTR(gpu_available_frequencies, 0444, kgsl_pwrctrl_gpu_available_frequencies_show, NULL); Loading Loading @@ -793,7 +735,6 @@ static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_max_gpuclk, &dev_attr_idle_timer, &dev_attr_gpubusy, &dev_attr_gputop, &dev_attr_gpu_available_frequencies, &dev_attr_max_pwrlevel, &dev_attr_min_pwrlevel, Loading @@ -818,41 +759,26 @@ void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device) kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list); } static void update_statistics(struct kgsl_device *device) { struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats; unsigned int on_time = 0; int i; int num_pwrlevels = device->pwrctrl.num_pwrlevels - 1; /*PER CLK TIME*/ for (i = 0; i < num_pwrlevels; i++) { clkstats->old_clock_time[i] = clkstats->clock_time[i]; on_time += clkstats->clock_time[i]; clkstats->clock_time[i] = 0; } clkstats->old_clock_time[num_pwrlevels] = clkstats->clock_time[num_pwrlevels]; clkstats->clock_time[num_pwrlevels] = 0; clkstats->on_time_old = on_time; clkstats->elapsed_old = clkstats->elapsed; clkstats->elapsed = 0; trace_kgsl_gpubusy(device, clkstats->on_time_old, clkstats->elapsed_old); } /* Track the amount of time the gpu is on vs the total system time. * * Regularly update the percentage of busy time displayed by sysfs. */ static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time) void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy) { struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats; update_clk_statistics(device, on_time); struct kgsl_clk_stats *stats = &device->pwrctrl.clk_stats; stats->total += time; stats->busy += busy; if (stats->total < UPDATE_BUSY_VAL) return; /* Update the output regularly and reset the counters. */ if ((clkstats->elapsed > UPDATE_BUSY_VAL) || !test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { update_statistics(device); } stats->total_old = stats->total; stats->busy_old = stats->busy; stats->total = 0; stats->busy = 0; trace_kgsl_gpubusy(device, stats->busy_old, stats->total_old); } EXPORT_SYMBOL(kgsl_pwrctrl_busy_time); void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state) Loading Loading @@ -880,7 +806,6 @@ void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); } kgsl_pwrctrl_busy_time(device, true); } else if (requested_state == KGSL_STATE_SLEEP) { /* High latency clock maintenance. */ for (i = KGSL_MAX_CLKS - 1; i > 0; i--) Loading Loading @@ -911,7 +836,6 @@ void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, for (i = KGSL_MAX_CLKS - 1; i > 0; i--) if (pwr->grp_clks[i]) clk_enable(pwr->grp_clks[i]); kgsl_pwrctrl_busy_time(device, false); } } } Loading Loading @@ -1217,21 +1141,10 @@ void kgsl_idle_check(struct work_struct *work) kgsl_pwrctrl_sleep(device); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); if (device->state == KGSL_STATE_ACTIVE) { if (device->state == KGSL_STATE_ACTIVE) mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); /* * If the GPU has been too busy to sleep, make sure * that is acurately reflected in the % busy numbers. */ device->pwrctrl.clk_stats.no_nap_cnt++; if (device->pwrctrl.clk_stats.no_nap_cnt > UPDATE_BUSY) { kgsl_pwrctrl_busy_time(device, true); device->pwrctrl.clk_stats.no_nap_cnt = 0; } } } mutex_unlock(&device->mutex); Loading Loading @@ -1312,15 +1225,6 @@ _nap(struct kgsl_device *device) return 0; } static void _sleep_accounting(struct kgsl_device *device) { kgsl_pwrctrl_busy_time(device, false); device->pwrctrl.clk_stats.start = ktime_set(0, 0); kgsl_pwrscale_sleep(device); } static int _sleep(struct kgsl_device *device) { Loading @@ -1334,7 +1238,7 @@ _sleep(struct kgsl_device *device) case KGSL_STATE_NAP: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF); _sleep_accounting(device); kgsl_pwrscale_sleep(device); kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, Loading Loading @@ -1369,7 +1273,7 @@ _slumber(struct kgsl_device *device) kgsl_pwrctrl_enable(device); device->ftbl->suspend_context(device); device->ftbl->stop(device); _sleep_accounting(device); kgsl_pwrscale_sleep(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, PM_QOS_DEFAULT_VALUE); Loading
drivers/gpu/msm/kgsl_pwrctrl.h +5 −8 Original line number Diff line number Diff line Loading @@ -33,14 +33,10 @@ struct platform_device; struct kgsl_clk_stats { unsigned int old_clock_time[KGSL_MAX_PWRLEVELS]; unsigned int clock_time[KGSL_MAX_PWRLEVELS]; unsigned int on_time_old; ktime_t start; ktime_t stop; unsigned int no_nap_cnt; unsigned int elapsed; unsigned int elapsed_old; unsigned int busy; unsigned int total; unsigned int busy_old; unsigned int total_old; }; struct kgsl_pwr_constraint { Loading Loading @@ -158,5 +154,6 @@ int kgsl_active_count_wait(struct kgsl_device *device, int count); void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state); int kgsl_pwrctrl_slumber(struct kgsl_device *device); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); #endif /* __KGSL_PWRCTRL_H */
drivers/gpu/msm/kgsl_pwrscale.c +1 −0 Original line number Diff line number Diff line Loading @@ -317,6 +317,7 @@ int kgsl_devfreq_get_dev_status(struct device *dev, b->mod = device->pwrctrl.bus_mod; } kgsl_pwrctrl_busy_time(device, stat->total_time, stat->busy_time); trace_kgsl_pwrstats(device, stat->total_time, &pwrscale->accum_stats); memset(&pwrscale->accum_stats, 0, sizeof(pwrscale->accum_stats)); Loading