示例#1
0
static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
					   struct cpuidle_driver *drv,
					   int index)
{
	/* All CPUs entering LP2 is not working.
	 * Don't let CPU0 enter LP2 when any secondary CPU is online.
	 */
	if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) {
		cpu_do_idle();
		return false;
	}

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);

	tegra_idle_lp2_last();

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);

	return true;
}
示例#2
0
static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
					   struct cpuidle_driver *drv,
					   int index)
{
	/* All CPUs entering LP2 is not working.
	 * Don't let CPU0 enter LP2 when any secondary CPU is online.
	 */
	if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) {
		cpu_do_idle();
		return false;
	}

	tick_broadcast_enter();

	tegra_idle_lp2_last();

	tick_broadcast_exit();

	return true;
}
示例#3
0
static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
					   struct cpuidle_driver *drv,
					   int index)
{
	while (tegra20_cpu_is_resettable_soon())
		cpu_relax();

	if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready())
		return false;

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);

	tegra_idle_lp2_last();

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);

	if (cpu_online(1))
		tegra20_wake_cpu1_from_reset();

	return true;
}
示例#4
0
static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
					   struct cpuidle_driver *drv,
					   int index)
{
	struct cpuidle_state *state = &drv->states[index];
	u32 cpu_on_time = state->exit_latency;
	u32 cpu_off_time = state->target_residency - state->exit_latency;

	/* All CPUs entering LP2 is not working.
	 * Don't let CPU0 enter LP2 when any secondary CPU is online.
	 */
	if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) {
		cpu_do_idle();
		return false;
	}

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);

	tegra_idle_lp2_last(cpu_on_time, cpu_off_time);

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);

	return true;
}
示例#5
0
static int tegra2_idle_lp2_cpu_0(struct cpuidle_device *dev,
			   struct cpuidle_state *state, s64 request)
{
	ktime_t entry_time;
	ktime_t exit_time;
	s64 wake_time;
	bool sleep_completed = false;
	int bin;
	int i;

	while (tegra2_cpu_is_resettable_soon())
		cpu_relax();

	if (tegra2_reset_other_cpus(dev->cpu))
		return 0;

	idle_stats.both_idle_count++;

	if (request < state->target_residency) {
		tegra2_lp3_fall_back(dev);
		return -EBUSY;
	}

	/* LP2 entry time */
	entry_time = ktime_get();

	/* LP2 initial targeted wake time */
	wake_time = ktime_to_us(entry_time) + request;

	/* CPU0 must wake up before CPU1. */
	smp_rmb();
	wake_time = min_t(s64, wake_time, tegra_cpu1_wake_by_time);

	/* LP2 actual targeted wake time */
	request = wake_time - ktime_to_us(entry_time);
	BUG_ON(wake_time < 0LL);

	idle_stats.tear_down_count++;
	entry_time = ktime_get();

	if (request > state->target_residency) {
		s64 sleep_time = request - tegra_lp2_exit_latency;

		bin = time_to_bin((u32)request / 1000);
		idle_stats.lp2_count++;
		idle_stats.lp2_count_bin[bin]++;

		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);

		if (tegra_idle_lp2_last(sleep_time, 0) == 0)
			sleep_completed = true;
		else {
			int irq = tegra_gic_pending_interrupt();
			idle_stats.lp2_int_count[irq]++;
		}

		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
	}

	for_each_online_cpu(i) {
		if (i != dev->cpu)
			tegra2_wake_reset_cpu(i);
	}

	exit_time = ktime_get();
	if (sleep_completed) {
		/*
		 * Stayed in LP2 for the full time until the next tick,
		 * adjust the exit latency based on measurement
		 */
		s64 actual_time = ktime_to_us(ktime_sub(exit_time, entry_time));
		long offset = (long)(actual_time - request);
		int latency = tegra_lp2_exit_latency + offset / 16;
		latency = clamp(latency, 0, 10000);
		tegra_lp2_exit_latency = latency;
		smp_wmb();

		idle_stats.lp2_completed_count++;
		idle_stats.lp2_completed_count_bin[bin]++;
		idle_stats.in_lp2_time += actual_time;

		pr_debug("%lld %lld %ld %d\n", request, actual_time,
			offset, bin);
	}

	return 0;
}