Loading drivers/gpu/msm/kgsl_pwrscale.c +66 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,17 @@ #define FAST_BUS 1 #define SLOW_BUS -1 /* * "SLEEP" is generic counting both NAP & SLUMBER * PERIODS generally won't exceed 9 for the relavent 150msec * window, but can be significantly smaller and still POPP * pushable in cases where SLUMBER is involved. Hence the * additional reliance on PERCENT to make sure a reasonable * amount of down-time actually exists. */ #define MIN_SLEEP_PERIODS 3 #define MIN_SLEEP_PERCENT 5 static struct kgsl_popp popp_param[POPP_MAX] = { {0, 0}, {-5, 20}, Loading @@ -48,11 +59,15 @@ static struct devfreq_dev_status last_status = { .private_data = &last_xstats }; */ void kgsl_pwrscale_sleep(struct kgsl_device *device) { struct kgsl_pwrscale *psc = &device->pwrscale; BUG_ON(!mutex_is_locked(&device->mutex)); if (!device->pwrscale.enabled) return; device->pwrscale.on_time = 0; psc->popp_level = 0; clear_bit(POPP_PUSH, &device->pwrscale.popp_state); /* to call devfreq_suspend_device() from a kernel thread */ queue_work(device->pwrscale.devfreq_wq, &device->pwrscale.devfreq_suspend_ws); Loading Loading @@ -240,20 +255,62 @@ static int _thermal_adjust(struct kgsl_pwrctrl *pwr, int level) static bool popp_stable(struct kgsl_device *device) { s64 t; s64 nap_time = 0; s64 go_time = 0; int i, index; int nap = 0; s64 percent_nap = 0; struct kgsl_pwr_event *e; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrscale *psc = &device->pwrscale; if (!test_bit(POPP_ON, &psc->popp_state)) return false; /* If running at turbo, min, or already pushed don't change levels */ if (test_bit(POPP_PUSH, &psc->popp_state) || pwr->active_pwrlevel == 0 || (!psc->popp_level && pwr->active_pwrlevel == pwr->min_pwrlevel)) /* If already pushed or running naturally at min don't push further */ if (test_bit(POPP_PUSH, &psc->popp_state)) return false; if (!psc->popp_level && pwr->active_pwrlevel != 0) return false; if (psc->history[KGSL_PWREVENT_STATE].events == NULL) return false; t = ktime_to_ms(ktime_get()); /* Check for recent NAP statistics: NAPping regularly and well? */ if (pwr->active_pwrlevel == 0) { index = psc->history[KGSL_PWREVENT_STATE].index; i = index > 0 ? (index - 1) : (psc->history[KGSL_PWREVENT_STATE].size - 1); while (i != index) { e = &psc->history[KGSL_PWREVENT_STATE].events[i]; if (e->data == KGSL_STATE_NAP || e->data == KGSL_STATE_SLUMBER) { if (ktime_to_ms(e->start) + STABLE_TIME > t) { nap++; nap_time += e->duration; } } else if (e->data == KGSL_STATE_ACTIVE) { if (ktime_to_ms(e->start) + STABLE_TIME > t) go_time += e->duration; } if (i == 0) i = psc->history[KGSL_PWREVENT_STATE].size - 1; else i--; } if (nap_time && go_time) { percent_nap = 100 * nap_time; do_div(percent_nap, nap_time + go_time); } trace_kgsl_popp_nap(device, (int)nap_time / 1000, nap, percent_nap); /* If running high at turbo, don't push */ if (nap < MIN_SLEEP_PERIODS || percent_nap < MIN_SLEEP_PERCENT) return false; } /* Finally check that there hasn't been a recent change */ if ((device->pwrscale.freq_change_time + STABLE_TIME) < t) { device->pwrscale.freq_change_time = t; return true; Loading Loading @@ -300,12 +357,16 @@ bool kgsl_popp_check(struct kgsl_device *device) static void popp_trans1(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwr->active_pwrlevel]; struct kgsl_pwrscale *psc = &device->pwrscale; int old_level = psc->popp_level; switch (old_level) { case 0: psc->popp_level = 2; /* If the current level has a high default bus don't push it */ if (pl->bus_freq == pl->bus_max) pwr->bus_mod = 1; kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel + 1); break; case 1: Loading drivers/gpu/msm/kgsl_pwrscale.h +1 −1 Original line number Diff line number Diff line Loading @@ -151,7 +151,7 @@ bool kgsl_popp_check(struct kgsl_device *device); .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_STATE].size = 20, \ .history[KGSL_PWREVENT_GPU_FREQ].size = 3, \ .history[KGSL_PWREVENT_BUS_FREQ].size = 5, \ .history[KGSL_PWREVENT_POPP].size = 5, \ Loading drivers/gpu/msm/kgsl_trace.h +26 −0 Original line number Diff line number Diff line Loading @@ -900,6 +900,32 @@ TRACE_EVENT(kgsl_popp_mod, __get_str(device_name), __entry->x, __entry->y) ); TRACE_EVENT(kgsl_popp_nap, TP_PROTO(struct kgsl_device *device, int t, int nap, int percent), TP_ARGS(device, t, nap, percent), TP_STRUCT__entry( __string(device_name, device->name) __field(int, t) __field(int, nap) __field(int, percent) ), TP_fast_assign( __assign_str(device_name, device->name); __entry->t = t; __entry->nap = nap; __entry->percent = percent; ), TP_printk( "d_name=%s nap time=%d number of naps=%d percentage=%d", __get_str(device_name), __entry->t, __entry->nap, __entry->percent) ); TRACE_EVENT(kgsl_register_event, TP_PROTO(unsigned int id, unsigned int timestamp, void *func), TP_ARGS(id, timestamp, func), Loading Loading
drivers/gpu/msm/kgsl_pwrscale.c +66 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,17 @@ #define FAST_BUS 1 #define SLOW_BUS -1 /* * "SLEEP" is generic counting both NAP & SLUMBER * PERIODS generally won't exceed 9 for the relavent 150msec * window, but can be significantly smaller and still POPP * pushable in cases where SLUMBER is involved. Hence the * additional reliance on PERCENT to make sure a reasonable * amount of down-time actually exists. */ #define MIN_SLEEP_PERIODS 3 #define MIN_SLEEP_PERCENT 5 static struct kgsl_popp popp_param[POPP_MAX] = { {0, 0}, {-5, 20}, Loading @@ -48,11 +59,15 @@ static struct devfreq_dev_status last_status = { .private_data = &last_xstats }; */ void kgsl_pwrscale_sleep(struct kgsl_device *device) { struct kgsl_pwrscale *psc = &device->pwrscale; BUG_ON(!mutex_is_locked(&device->mutex)); if (!device->pwrscale.enabled) return; device->pwrscale.on_time = 0; psc->popp_level = 0; clear_bit(POPP_PUSH, &device->pwrscale.popp_state); /* to call devfreq_suspend_device() from a kernel thread */ queue_work(device->pwrscale.devfreq_wq, &device->pwrscale.devfreq_suspend_ws); Loading Loading @@ -240,20 +255,62 @@ static int _thermal_adjust(struct kgsl_pwrctrl *pwr, int level) static bool popp_stable(struct kgsl_device *device) { s64 t; s64 nap_time = 0; s64 go_time = 0; int i, index; int nap = 0; s64 percent_nap = 0; struct kgsl_pwr_event *e; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrscale *psc = &device->pwrscale; if (!test_bit(POPP_ON, &psc->popp_state)) return false; /* If running at turbo, min, or already pushed don't change levels */ if (test_bit(POPP_PUSH, &psc->popp_state) || pwr->active_pwrlevel == 0 || (!psc->popp_level && pwr->active_pwrlevel == pwr->min_pwrlevel)) /* If already pushed or running naturally at min don't push further */ if (test_bit(POPP_PUSH, &psc->popp_state)) return false; if (!psc->popp_level && pwr->active_pwrlevel != 0) return false; if (psc->history[KGSL_PWREVENT_STATE].events == NULL) return false; t = ktime_to_ms(ktime_get()); /* Check for recent NAP statistics: NAPping regularly and well? */ if (pwr->active_pwrlevel == 0) { index = psc->history[KGSL_PWREVENT_STATE].index; i = index > 0 ? (index - 1) : (psc->history[KGSL_PWREVENT_STATE].size - 1); while (i != index) { e = &psc->history[KGSL_PWREVENT_STATE].events[i]; if (e->data == KGSL_STATE_NAP || e->data == KGSL_STATE_SLUMBER) { if (ktime_to_ms(e->start) + STABLE_TIME > t) { nap++; nap_time += e->duration; } } else if (e->data == KGSL_STATE_ACTIVE) { if (ktime_to_ms(e->start) + STABLE_TIME > t) go_time += e->duration; } if (i == 0) i = psc->history[KGSL_PWREVENT_STATE].size - 1; else i--; } if (nap_time && go_time) { percent_nap = 100 * nap_time; do_div(percent_nap, nap_time + go_time); } trace_kgsl_popp_nap(device, (int)nap_time / 1000, nap, percent_nap); /* If running high at turbo, don't push */ if (nap < MIN_SLEEP_PERIODS || percent_nap < MIN_SLEEP_PERCENT) return false; } /* Finally check that there hasn't been a recent change */ if ((device->pwrscale.freq_change_time + STABLE_TIME) < t) { device->pwrscale.freq_change_time = t; return true; Loading Loading @@ -300,12 +357,16 @@ bool kgsl_popp_check(struct kgsl_device *device) static void popp_trans1(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwr->active_pwrlevel]; struct kgsl_pwrscale *psc = &device->pwrscale; int old_level = psc->popp_level; switch (old_level) { case 0: psc->popp_level = 2; /* If the current level has a high default bus don't push it */ if (pl->bus_freq == pl->bus_max) pwr->bus_mod = 1; kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel + 1); break; case 1: Loading
drivers/gpu/msm/kgsl_pwrscale.h +1 −1 Original line number Diff line number Diff line Loading @@ -151,7 +151,7 @@ bool kgsl_popp_check(struct kgsl_device *device); .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_STATE].size = 20, \ .history[KGSL_PWREVENT_GPU_FREQ].size = 3, \ .history[KGSL_PWREVENT_BUS_FREQ].size = 5, \ .history[KGSL_PWREVENT_POPP].size = 5, \ Loading
drivers/gpu/msm/kgsl_trace.h +26 −0 Original line number Diff line number Diff line Loading @@ -900,6 +900,32 @@ TRACE_EVENT(kgsl_popp_mod, __get_str(device_name), __entry->x, __entry->y) ); TRACE_EVENT(kgsl_popp_nap, TP_PROTO(struct kgsl_device *device, int t, int nap, int percent), TP_ARGS(device, t, nap, percent), TP_STRUCT__entry( __string(device_name, device->name) __field(int, t) __field(int, nap) __field(int, percent) ), TP_fast_assign( __assign_str(device_name, device->name); __entry->t = t; __entry->nap = nap; __entry->percent = percent; ), TP_printk( "d_name=%s nap time=%d number of naps=%d percentage=%d", __get_str(device_name), __entry->t, __entry->nap, __entry->percent) ); TRACE_EVENT(kgsl_register_event, TP_PROTO(unsigned int id, unsigned int timestamp, void *func), TP_ARGS(id, timestamp, func), Loading