mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 05:17:10 +09:00
ARM: tegra: cpuidle: Fix compile issues with CONFIG_SMP=n
Change-Id: Id02744bcdfc079a6091be2e8a736bcd3a6cc0ba6 Signed-off-by: Colin Cross <ccross@android.com>
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
#include <asm/localtimer.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
@@ -63,7 +64,7 @@ static bool lp2_in_idle __read_mostly = true;
|
||||
static bool lp2_disabled_by_suspend;
|
||||
module_param(lp2_in_idle, bool, 0644);
|
||||
|
||||
static s64 tegra_cpu1_idle_time;
|
||||
static s64 tegra_cpu1_idle_time = LLONG_MAX;;
|
||||
static int tegra_lp2_exit_latency;
|
||||
static int tegra_lp2_power_off_time;
|
||||
|
||||
@@ -146,6 +147,7 @@ static inline void tegra_flow_wfi(struct cpuidle_device *dev)
|
||||
reg = __raw_readl(flow_ctrl);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline bool tegra_wait_for_both_idle(struct cpuidle_device *dev)
|
||||
{
|
||||
int wake_int;
|
||||
@@ -183,36 +185,9 @@ static inline bool tegra_cpu_in_reset(int cpu)
|
||||
return !!(readl(CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET) & (1 << cpu));
|
||||
}
|
||||
|
||||
static void tegra_idle_enter_lp2_cpu0(struct cpuidle_device *dev,
|
||||
struct cpuidle_state *state)
|
||||
static int tegra_tear_down_cpu1(void)
|
||||
{
|
||||
s64 request;
|
||||
u32 reg;
|
||||
ktime_t enter;
|
||||
ktime_t exit;
|
||||
bool sleep_completed = false;
|
||||
int bin;
|
||||
unsigned long boot_vector;
|
||||
unsigned long old_boot_vector;
|
||||
unsigned long timeout;
|
||||
|
||||
restart:
|
||||
if (!tegra_wait_for_both_idle(dev))
|
||||
return;
|
||||
|
||||
idle_stats.both_idle_count++;
|
||||
|
||||
if (need_resched())
|
||||
return;
|
||||
|
||||
/* CPU1 woke CPU0 because both are idle */
|
||||
|
||||
request = ktime_to_us(tick_nohz_get_sleep_length());
|
||||
if (request < tegra_lp2_exit_latency) {
|
||||
/* Not enough time left to enter LP2 */
|
||||
tegra_flow_wfi(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Signal to CPU1 to tear down */
|
||||
tegra_legacy_force_irq_set(TEGRA_CPUIDLE_TEAR_DOWN);
|
||||
@@ -226,39 +201,24 @@ restart:
|
||||
|
||||
tegra_legacy_force_irq_clr(TEGRA_CPUIDLE_TEAR_DOWN);
|
||||
|
||||
idle_stats.tear_down_count++;
|
||||
|
||||
/* If CPU1 aborted LP2, restart the process */
|
||||
if (!tegra_legacy_force_irq_status(TEGRA_CPUIDLE_BOTH_IDLE))
|
||||
goto restart;
|
||||
return -EAGAIN;
|
||||
|
||||
/* CPU1 is ready for LP2, clock gate it */
|
||||
reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
|
||||
writel(reg | (1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
|
||||
|
||||
/* Enter LP2 */
|
||||
request = ktime_to_us(tick_nohz_get_sleep_length());
|
||||
smp_rmb();
|
||||
request = min_t(s64, request, tegra_cpu1_idle_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
enter = ktime_get();
|
||||
if (request > tegra_lp2_exit_latency + state->target_residency) {
|
||||
s64 sleep_time = request - tegra_lp2_exit_latency;
|
||||
static void tegra_wake_cpu1(void)
|
||||
{
|
||||
unsigned long boot_vector;
|
||||
unsigned long old_boot_vector;
|
||||
unsigned long timeout;
|
||||
u32 reg;
|
||||
|
||||
bin = time_to_bin((u32)request / 1000);
|
||||
idle_stats.lp2_count++;
|
||||
idle_stats.lp2_count_bin[bin]++;
|
||||
|
||||
if (tegra_suspend_lp2(sleep_time) == 0)
|
||||
sleep_completed = true;
|
||||
}
|
||||
|
||||
/* Bring CPU1 out of LP2 */
|
||||
/* TODO: polls for CPU1 to boot, wfi would be better */
|
||||
/* takes ~80 us */
|
||||
|
||||
/* set the reset vector to point to the secondary_startup routine */
|
||||
smp_wmb();
|
||||
boot_vector = virt_to_phys(tegra_hotplug_startup);
|
||||
old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
|
||||
writel(boot_vector, EVP_CPU_RESET_VECTOR);
|
||||
@@ -284,6 +244,80 @@ restart:
|
||||
writel(old_boot_vector, EVP_CPU_RESET_VECTOR);
|
||||
|
||||
/* CPU1 is now started */
|
||||
}
|
||||
#else
|
||||
static inline bool tegra_wait_for_both_idle(struct cpuidle_device *dev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int tegra_tear_down_cpu1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void tegra_wake_cpu1(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tegra_idle_enter_lp2_cpu0(struct cpuidle_device *dev,
|
||||
struct cpuidle_state *state)
|
||||
{
|
||||
s64 request;
|
||||
ktime_t enter;
|
||||
ktime_t exit;
|
||||
bool sleep_completed = false;
|
||||
int bin;
|
||||
|
||||
restart:
|
||||
if (!tegra_wait_for_both_idle(dev))
|
||||
return;
|
||||
|
||||
idle_stats.both_idle_count++;
|
||||
|
||||
if (need_resched())
|
||||
return;
|
||||
|
||||
/* CPU1 woke CPU0 because both are idle */
|
||||
|
||||
request = ktime_to_us(tick_nohz_get_sleep_length());
|
||||
if (request < state->target_residency) {
|
||||
/* Not enough time left to enter LP2 */
|
||||
tegra_flow_wfi(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
idle_stats.tear_down_count++;
|
||||
|
||||
if (tegra_tear_down_cpu1())
|
||||
goto restart;
|
||||
|
||||
/* Enter LP2 */
|
||||
request = ktime_to_us(tick_nohz_get_sleep_length());
|
||||
smp_rmb();
|
||||
request = min_t(s64, request, tegra_cpu1_idle_time);
|
||||
|
||||
enter = 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]++;
|
||||
|
||||
if (tegra_suspend_lp2(sleep_time) == 0)
|
||||
sleep_completed = true;
|
||||
}
|
||||
|
||||
/* Bring CPU1 out of LP2 */
|
||||
/* TODO: polls for CPU1 to boot, wfi would be better */
|
||||
/* takes ~80 us */
|
||||
|
||||
/* set the reset vector to point to the secondary_startup routine */
|
||||
smp_wmb();
|
||||
|
||||
tegra_wake_cpu1();
|
||||
|
||||
/*
|
||||
* TODO: is it worth going back to wfi if no interrupt is pending
|
||||
@@ -312,6 +346,7 @@ restart:
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void tegra_idle_enter_lp2_cpu1(struct cpuidle_device *dev,
|
||||
struct cpuidle_state *state)
|
||||
{
|
||||
@@ -380,6 +415,7 @@ static void tegra_idle_enter_lp2_cpu1(struct cpuidle_device *dev,
|
||||
out:
|
||||
tegra_legacy_force_irq_clr(TEGRA_CPUIDLE_BOTH_IDLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
|
||||
struct cpuidle_state *state)
|
||||
@@ -416,10 +452,14 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev,
|
||||
|
||||
idle_stats.cpu_ready_count[dev->cpu]++;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (dev->cpu == 0)
|
||||
tegra_idle_enter_lp2_cpu0(dev, state);
|
||||
else
|
||||
tegra_idle_enter_lp2_cpu1(dev, state);
|
||||
#else
|
||||
tegra_idle_enter_lp2_cpu0(dev, state);
|
||||
#endif
|
||||
|
||||
exit = ktime_sub(ktime_get(), enter);
|
||||
us = ktime_to_us(exit);
|
||||
|
||||
Reference in New Issue
Block a user