Exemplo n.º 1
0
/**
 * 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;
}
Exemplo n.º 2
0
int enter_lowpm(struct cpuidle_device *dev,
			struct cpuidle_state *state)
{
	int icanidle = 0;
	int idle_time;
	int cpu_id = 0;
	int cpu_idle_flag = IDLE_DISABLE;
	struct cpuidle_state *new_state = state;
	struct timeval before, after;
    int enter_state;
    struct timespec t;
	unsigned int timer_id = 0;
	unsigned int schedule_time = 0xffffffff;
    unsigned int expected_us;

    local_irq_disable();
    cpu_id = get_cpu();
    put_cpu();
    if(get_enter_state(state, &enter_state) != 0)
    {
        local_irq_enable();
        return 0;
    }

    /* Used to keep track of the total time in idle */
	getnstimeofday(&before);

    #if 1
    /*启动过程中不允许ACPU下电*/
    /*if((CPU_IDLE_C1 <= enter_state)&&(CPU_IDLE_C3 >= enter_state)&&(before.tv_sec < IDLE_ACTIVE_DELAY_S))*/
    if((CPU_IDLE_C1 <= enter_state)&&(CPU_IDLE_C3 >= enter_state)&&(0 == g_pwc_init_flag))
    {
        PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"before.tv_sec:0x%x\n",before.tv_sec);

        local_irq_enable();
        return 0;
    }
    #endif

    if((RET_OK == pwrctrl_is_func_on(PWC_SWITCH_CPUIDLE))&&((CPU_IDLE_C0 < enter_state)&&(CPU_IDLE_C4 > enter_state))&&(0 == cpu_id))
    {
        cpu_idle_flag = IDLE_ENABLE;
    }
    else
    {
        cpu_idle_flag = IDLE_DISABLE;
    }


    /*C3起定时器来唤醒 后续可优化*/
    if((enter_state >= CPU_IDLE_C3)&&(IDLE_ENABLE == cpu_idle_flag))
    {
        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;
        }
        /*C3停止所有TCXO定时器,待优化*/

    	/* determine the expected residency time, round up */
    	t = ktime_to_timespec(tick_nohz_get_sleep_length());
    	expected_us = t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;

        if(schedule_time < expected_us)
        {
            PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"enter_lowpm,system time:%d private time:%d\n",expected_us, schedule_time);
            expected_us = schedule_time;
        }

        expected_us -= state->exit_latency;
        DRV_TIMER_STOP(CPU_IDLE_TIMER);
        DRV_TIMER_START((unsigned int)CPU_IDLE_TIMER, cpu_idle_timer_isr, (int)0, (expected_us / MSEC_PER_SEC), TIMER_ONCE_COUNT, TIMER_UNIT_MS);
    }


    if(IDLE_ENABLE == cpu_idle_flag)
    {
        *gp_cpuidle_state = (enter_state << CPUIDLE_STATE_START_BIT) | (CPU_IDLE_STAT_VALID << CPUIDLE_STATE_MAGIC_START_BIT);
        /*pwrctrl_wdt_disable();*/
    }

    if(0 == cpu_id)
    {
        PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"system will enter cpuidle state(%d)\n",enter_state);
    }

    if(CPU_IDLE_C0 == enter_state)
    {
        cpu_do_idle();
    }
    else if(IDLE_ENABLE == cpu_idle_flag)
    {
        pwrctrl_deep_sleep();
    }

    if(enter_state >= SPECIAL_HANDLE_STATE)
    {
        /*清除timer中断*/
        /*C3恢复之前停止所有TCXO定时器,待优化*/
    }

    if(IDLE_ENABLE == cpu_idle_flag)
    {
        *gp_cpuidle_state = (CPU_IDLE_C4 << CPUIDLE_STATE_START_BIT) | (CPU_IDLE_STAT_VALID << CPUIDLE_STATE_MAGIC_START_BIT);
        /*pwrctrl_wdt_enable();*/
    }

    getnstimeofday(&after);

    idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
		    (after.tv_usec - before.tv_usec);
    local_irq_enable();

	return idle_time;
}