diff options
author | Mustafa Yigit Bilgen <mbilgen@nvidia.com> | 2016-09-02 19:30:22 -0700 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2017-04-05 14:09:51 -0700 |
commit | 322b00fcfb6e8b1b5aa533c9503955c0bfdf826b (patch) | |
tree | 03985137ba469cdc82215b015757195f0588c105 | |
parent | ac26b96b40c4cda751f1923b4906d7027e529327 (diff) |
Tegra186: clean CPU wake times from L2 cache
When entering C7, ATF disables caches and flushes the L1 cache. However,
wake_time[cpu] can still remain in the L2 cache, causing later reads to it
to fetch from DRAM. This will read stale values.
Fix this by aligning wake_time[cpu] to cache lines, and explicitly cleaning it
before disabling caches.
Change-Id: Id73d095b479677595a6b3dd0abb240a1fef5f311
Signed-off-by: Mustafa Yigit Bilgen <mbilgen@nvidia.com>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_psci_handlers.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c index 35828787..8485e044 100644 --- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c @@ -63,7 +63,9 @@ extern uint32_t __tegra186_cpu_reset_handler_data, #define TEGRA186_SE_CONTEXT_SIZE 3 static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE]; -static unsigned int wake_time[PLATFORM_CORE_COUNT]; +static struct t18x_psci_percpu_data { + unsigned int wake_time; +} __aligned(CACHE_WRITEBACK_GRANULE) percpu_data[PLATFORM_CORE_COUNT]; /* System power down state */ uint32_t tegra186_system_powerdn_state = TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF; @@ -75,9 +77,19 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state, int cpu = plat_my_core_pos(); /* save the core wake time (us) */ - wake_time[cpu] = (power_state >> TEGRA186_WAKE_TIME_SHIFT) & + percpu_data[cpu].wake_time = (power_state >> TEGRA186_WAKE_TIME_SHIFT) & TEGRA186_WAKE_TIME_MASK; + /* + * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that + * the correct value is read in tegra_soc_pwr_domain_suspend(), which + * is called with caches disabled. It is possible to read a stale value + * from DRAM in that function, because the L2 cache is not flushed + * unless the cluster is entering CC6/CC7. + */ + clean_dcache_range((uint64_t)&percpu_data[cpu], + sizeof(percpu_data[cpu])); + /* Sanity check the requested state id */ switch (state_id) { case PSTATE_ID_CORE_IDLE: @@ -121,7 +133,7 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ? TEGRA_ARI_CORE_C6 : TEGRA_ARI_CORE_C7; (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, val, - wake_time[cpu], 0); + percpu_data[cpu].wake_time, 0); } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { @@ -193,7 +205,8 @@ plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl, /* Check if CCx state is allowed. */ ret = mce_command_handler(MCE_CMD_IS_CCX_ALLOWED, - TEGRA_ARI_CORE_C7, wake_time[cpu], 0); + TEGRA_ARI_CORE_C7, percpu_data[cpu].wake_time, + 0); if (ret) return PSTATE_ID_CORE_POWERDN; } |