/** * menu_select - selects the next idle state to enter * @dev: the CPU */ static int menu_select(struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); int int_vote_req = pm_qos_request(PM_QOS_CPU_INT_LATENCY); unsigned int power_usage = -1; int i; int multiplier; struct timespec t; unsigned int timer_id = 0; unsigned int schedule_time = 0xffffffff; if (data->needs_update) { menu_update(dev); data->needs_update = 0; } data->last_state_idx = 0; data->exit_us = 0; if (unlikely(int_vote_req != PM_QOS_CPUIDLE_INT_DEFAULT_VALUE)) { PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,int_vote_req=0x%x\n",int_vote_req); return 0; } if(num_online_cpus() > 1) return 0; pwrctrl_sleep_mgr_get_next_schedule_time(0, &timer_id, &schedule_time); if(schedule_time > (0xFFFFFFFF / 1000)) { schedule_time = 0xFFFFFFFF; } else { schedule_time *= USEC_PER_MSEC; } /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) return 0; /* determine the expected residency time, round up */ t = ktime_to_timespec(tick_nohz_get_sleep_length()); data->expected_us = t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC; PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,data->expected_us=%d,schedule_time=%d\n",data->expected_us,schedule_time); if(schedule_time < data->expected_us) { /*PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,system time:%d private time:%d\n",data->expected_us, schedule_time);*/ data->expected_us = schedule_time; } data->bucket = which_bucket(data->expected_us); multiplier = performance_multiplier(); /* * if the correction factor is 0 (eg first time init or cpu hotplug * etc), we actually want to start out with a unity factor. */ if (data->correction_factor[data->bucket] == 0) data->correction_factor[data->bucket] = RESOLUTION * DECAY; /* Make sure to round up for half microseconds */ data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); detect_repeating_patterns(data); /* * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon. */ if (data->expected_us > 5) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; /* * Find the idle state with the lowest power while satisfying * our constraints. */ PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,multiplier=%d, latency_req=%d, predicted_us=%llu\n", multiplier,latency_req, data->predicted_us); for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; if (s->flags & CPUIDLE_FLAG_IGNORE) continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) continue; if (s->exit_latency * multiplier > data->predicted_us) continue; if (s->power_usage < power_usage) { power_usage = s->power_usage; data->last_state_idx = i; data->exit_us = s->exit_latency; } } return data->last_state_idx; }
/** * menu_select - selects the next idle state to enter * @dev: the CPU */ static int menu_select(struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); unsigned int power_usage = -1; int i; int multiplier; struct timespec t; if (data->needs_update) { menu_update(dev); data->needs_update = 0; } data->last_state_idx = 0; data->exit_us = 0; /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) return 0; /* determine the expected residency time, round up */ t = ktime_to_timespec(tick_nohz_get_sleep_length()); data->expected_us = t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC; data->bucket = which_bucket(data->expected_us); multiplier = performance_multiplier(); /* * if the correction factor is 0 (eg first time init or cpu hotplug * etc), we actually want to start out with a unity factor. */ if (data->correction_factor[data->bucket] == 0) data->correction_factor[data->bucket] = RESOLUTION * DECAY; /* Make sure to round up for half microseconds */ data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); detect_repeating_patterns(data); /* * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon. */ if (data->expected_us > 5) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; /* * Find the idle state with the lowest power while satisfying * our constraints. */ for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; if (s->flags & CPUIDLE_FLAG_IGNORE) continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) continue; if (s->exit_latency * multiplier > data->predicted_us) continue; if (s->power_usage < power_usage) { power_usage = s->power_usage; data->last_state_idx = i; data->exit_us = s->exit_latency; } } return data->last_state_idx; }