summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/platsmp.c
diff options
context:
space:
mode:
authorBo Yan <byan@nvidia.com>2012-11-15 14:07:17 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:42:25 -0700
commita57dc41e436d3de5ffccbcb305e90057e230d31a (patch)
tree1bfdf58f7ed6862c26f396c31f6151d9fe1d1ed9 /arch/arm/mach-tegra/platsmp.c
parenta560952285fec0ffa88bb9dc4a877f8f0e893393 (diff)
ARM: tegra11x: Fix race condition in cpu hot plug
The secondary CPU power up can happen so fast that it enters power gating even before the CPU that's trying to bring it up gets a chance to check status in PMC register. This can happen because interrupt and preemption are not disabled, so the primary CPU can switch to do something else, when it comes back to check PMC status, it's already too late. When this happens, it will simply declare a timeout failure, though the secondary power up is actually successful. The fix is to check online status as well, because the CPU that's coming up will set online flag before entering idle loop. Another enhancement is to skip the status check altogether if this is not the first boot up after cold boot or warm boot. The synchronisation done in __cpu_up is more adequate. For the first boot after cold boot or warm boot, set the timeout back to 100ms. Bug 1169512 Change-Id: Ie4b873d853c40207c7b1bc1acf0982a7bf0ecd9f Signed-off-by: Bo Yan <byan@nvidia.com> Reviewed-on: http://git-master/r/164065 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Peter Boonstoppel <pboonstoppel@nvidia.com> Tested-by: Peter Boonstoppel <pboonstoppel@nvidia.com> Tested-by: Sang-Hun Lee <sanlee@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/platsmp.c')
-rw-r--r--arch/arm/mach-tegra/platsmp.c14
1 files changed, 6 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 7ac69866c4c8..46c6bd5d1d94 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -237,7 +237,6 @@ fail:
static int tegra11x_power_up_cpu(unsigned int cpu)
{
- int ret;
unsigned long timeout;
BUG_ON(cpu == smp_processor_id());
@@ -250,6 +249,7 @@ static int tegra11x_power_up_cpu(unsigned int cpu)
/* set SCLK as event trigger for flow conroller */
flowctrl_write_cpu_csr(cpu, 0x1);
flowctrl_write_cpu_halt(cpu, 0x48000000);
+ return 0;
} else {
u32 reg;
@@ -258,16 +258,14 @@ static int tegra11x_power_up_cpu(unsigned int cpu)
pmc_writel(reg, PWRGATE_TOGGLE);
}
- ret = -ETIMEDOUT;
-
/* Wait for the power to come up. */
- timeout = jiffies + msecs_to_jiffies(2000);
+ timeout = jiffies + msecs_to_jiffies(100);
do {
- if (is_cpu_powered(cpu) && is_clamp_removed(cpu)) {
+ if ((is_cpu_powered(cpu) && is_clamp_removed(cpu)) ||
+ cpu_online(cpu)) {
cpumask_set_cpu(cpu, tegra_cpu_power_mask);
wmb();
- ret = 0;
- break;
+ return 0;
}
udelay(10);
} while (time_before(jiffies, timeout));
@@ -275,7 +273,7 @@ static int tegra11x_power_up_cpu(unsigned int cpu)
/* Clear flow controller CSR. */
flowctrl_write_cpu_csr(cpu, 0);
- return ret;
+ return -ETIMEDOUT;
}
static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle)