Loading drivers/gpu/msm/kgsl_pwrctrl.c +42 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,42 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device, static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); /** * _record_pwrevent() - Record the history of the new event * @device: Pointer to the kgsl_device struct * @t: Timestamp * @event: Event type * * Finish recording the duration of the previous event. Then update the * index, record the start of the new event, and the relevant data. */ static void _record_pwrevent(struct kgsl_device *device, ktime_t t, int event) { struct kgsl_pwrscale *psc = &device->pwrscale; struct kgsl_pwr_history *history = &psc->history[event]; int i = history->index; if (history->events == NULL) return; history->events[i].duration = ktime_us_delta(t, history->events[i].start); i = (i + 1) % history->size; history->index = i; history->events[i].start = t; switch (event) { case KGSL_PWREVENT_STATE: history->events[i].data = device->state; break; case KGSL_PWREVENT_GPU_FREQ: history->events[i].data = device->pwrctrl.active_pwrlevel; break; case KGSL_PWREVENT_BUS_FREQ: history->events[i].data = last_vote_buslevel; break; default: break; } } /** * kgsl_get_bw() - Return latest msm bus IB vote */ Loading Loading @@ -2046,6 +2082,12 @@ int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state) status = -EINVAL; break; } /* Record the state timing info */ if (!status) { ktime_t t = ktime_get(); _record_pwrevent(device, t, KGSL_PWREVENT_STATE); } return status; } EXPORT_SYMBOL(kgsl_pwrctrl_change_state); Loading drivers/gpu/msm/kgsl_pwrscale.c +12 −1 Original line number Diff line number Diff line /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -610,6 +610,14 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) pwrscale->next_governor_call = ktime_add_us(ktime_get(), KGSL_GOVERNOR_CALL_INTERVAL); /* history tracking */ for (i = 0; i < KGSL_PWREVENT_MAX; i++) { pwrscale->history[i].events = kzalloc( pwrscale->history[i].size * sizeof(struct kgsl_pwr_event), GFP_KERNEL); pwrscale->history[i].type = i; } return 0; } EXPORT_SYMBOL(kgsl_pwrscale_init); Loading @@ -622,6 +630,7 @@ EXPORT_SYMBOL(kgsl_pwrscale_init); */ void kgsl_pwrscale_close(struct kgsl_device *device) { int i; struct kgsl_pwrscale *pwrscale; BUG_ON(!mutex_is_locked(&device->mutex)); Loading @@ -634,6 +643,8 @@ void kgsl_pwrscale_close(struct kgsl_device *device) devfreq_remove_device(device->pwrscale.devfreqptr); device->pwrscale.devfreqptr = NULL; srcu_cleanup_notifier_head(&device->pwrscale.nh); for (i = 0; i < KGSL_PWREVENT_MAX; i++) kfree(pwrscale->history[i].events); } EXPORT_SYMBOL(kgsl_pwrscale_close); Loading drivers/gpu/msm/kgsl_pwrscale.h +28 −2 Original line number Diff line number Diff line /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -20,12 +20,32 @@ /* devfreq governor call window in usec */ #define KGSL_GOVERNOR_CALL_INTERVAL 10000 /* Power events to be tracked with history */ #define KGSL_PWREVENT_STATE 0 #define KGSL_PWREVENT_GPU_FREQ 1 #define KGSL_PWREVENT_BUS_FREQ 2 #define KGSL_PWREVENT_POPP 3 #define KGSL_PWREVENT_MAX 4 struct kgsl_power_stats { u64 busy_time; u64 ram_time; u64 ram_wait; }; struct kgsl_pwr_event { unsigned int data; ktime_t start; s64 duration; }; struct kgsl_pwr_history { struct kgsl_pwr_event *events; unsigned int type; unsigned int index; unsigned int size; }; struct kgsl_pwrscale { struct devfreq *devfreqptr; struct msm_adreno_extended_profile gpu_profile; Loading @@ -42,6 +62,7 @@ struct kgsl_pwrscale { struct work_struct devfreq_resume_ws; struct work_struct devfreq_notify_ws; ktime_t next_governor_call; struct kgsl_pwr_history history[KGSL_PWREVENT_MAX]; }; int kgsl_pwrscale_init(struct device *dev, const char *governor); Loading Loading @@ -80,5 +101,10 @@ int kgsl_busmon_get_cur_freq(struct device *dev, unsigned long *freq); .target = kgsl_busmon_target, \ .get_dev_status = kgsl_busmon_get_dev_status, \ .get_cur_freq = kgsl_busmon_get_cur_freq, \ } } } } }, \ .history[KGSL_PWREVENT_STATE].size = 10, \ .history[KGSL_PWREVENT_GPU_FREQ].size = 3, \ .history[KGSL_PWREVENT_BUS_FREQ].size = 5, \ .history[KGSL_PWREVENT_POPP].size = 5, \ } #endif Loading
drivers/gpu/msm/kgsl_pwrctrl.c +42 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,42 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device, static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); /** * _record_pwrevent() - Record the history of the new event * @device: Pointer to the kgsl_device struct * @t: Timestamp * @event: Event type * * Finish recording the duration of the previous event. Then update the * index, record the start of the new event, and the relevant data. */ static void _record_pwrevent(struct kgsl_device *device, ktime_t t, int event) { struct kgsl_pwrscale *psc = &device->pwrscale; struct kgsl_pwr_history *history = &psc->history[event]; int i = history->index; if (history->events == NULL) return; history->events[i].duration = ktime_us_delta(t, history->events[i].start); i = (i + 1) % history->size; history->index = i; history->events[i].start = t; switch (event) { case KGSL_PWREVENT_STATE: history->events[i].data = device->state; break; case KGSL_PWREVENT_GPU_FREQ: history->events[i].data = device->pwrctrl.active_pwrlevel; break; case KGSL_PWREVENT_BUS_FREQ: history->events[i].data = last_vote_buslevel; break; default: break; } } /** * kgsl_get_bw() - Return latest msm bus IB vote */ Loading Loading @@ -2046,6 +2082,12 @@ int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state) status = -EINVAL; break; } /* Record the state timing info */ if (!status) { ktime_t t = ktime_get(); _record_pwrevent(device, t, KGSL_PWREVENT_STATE); } return status; } EXPORT_SYMBOL(kgsl_pwrctrl_change_state); Loading
drivers/gpu/msm/kgsl_pwrscale.c +12 −1 Original line number Diff line number Diff line /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -610,6 +610,14 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) pwrscale->next_governor_call = ktime_add_us(ktime_get(), KGSL_GOVERNOR_CALL_INTERVAL); /* history tracking */ for (i = 0; i < KGSL_PWREVENT_MAX; i++) { pwrscale->history[i].events = kzalloc( pwrscale->history[i].size * sizeof(struct kgsl_pwr_event), GFP_KERNEL); pwrscale->history[i].type = i; } return 0; } EXPORT_SYMBOL(kgsl_pwrscale_init); Loading @@ -622,6 +630,7 @@ EXPORT_SYMBOL(kgsl_pwrscale_init); */ void kgsl_pwrscale_close(struct kgsl_device *device) { int i; struct kgsl_pwrscale *pwrscale; BUG_ON(!mutex_is_locked(&device->mutex)); Loading @@ -634,6 +643,8 @@ void kgsl_pwrscale_close(struct kgsl_device *device) devfreq_remove_device(device->pwrscale.devfreqptr); device->pwrscale.devfreqptr = NULL; srcu_cleanup_notifier_head(&device->pwrscale.nh); for (i = 0; i < KGSL_PWREVENT_MAX; i++) kfree(pwrscale->history[i].events); } EXPORT_SYMBOL(kgsl_pwrscale_close); Loading
drivers/gpu/msm/kgsl_pwrscale.h +28 −2 Original line number Diff line number Diff line /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -20,12 +20,32 @@ /* devfreq governor call window in usec */ #define KGSL_GOVERNOR_CALL_INTERVAL 10000 /* Power events to be tracked with history */ #define KGSL_PWREVENT_STATE 0 #define KGSL_PWREVENT_GPU_FREQ 1 #define KGSL_PWREVENT_BUS_FREQ 2 #define KGSL_PWREVENT_POPP 3 #define KGSL_PWREVENT_MAX 4 struct kgsl_power_stats { u64 busy_time; u64 ram_time; u64 ram_wait; }; struct kgsl_pwr_event { unsigned int data; ktime_t start; s64 duration; }; struct kgsl_pwr_history { struct kgsl_pwr_event *events; unsigned int type; unsigned int index; unsigned int size; }; struct kgsl_pwrscale { struct devfreq *devfreqptr; struct msm_adreno_extended_profile gpu_profile; Loading @@ -42,6 +62,7 @@ struct kgsl_pwrscale { struct work_struct devfreq_resume_ws; struct work_struct devfreq_notify_ws; ktime_t next_governor_call; struct kgsl_pwr_history history[KGSL_PWREVENT_MAX]; }; int kgsl_pwrscale_init(struct device *dev, const char *governor); Loading Loading @@ -80,5 +101,10 @@ int kgsl_busmon_get_cur_freq(struct device *dev, unsigned long *freq); .target = kgsl_busmon_target, \ .get_dev_status = kgsl_busmon_get_dev_status, \ .get_cur_freq = kgsl_busmon_get_cur_freq, \ } } } } }, \ .history[KGSL_PWREVENT_STATE].size = 10, \ .history[KGSL_PWREVENT_GPU_FREQ].size = 3, \ .history[KGSL_PWREVENT_BUS_FREQ].size = 5, \ .history[KGSL_PWREVENT_POPP].size = 5, \ } #endif