Tegra: smmu: add smmu_verify function

The SMMU configuration can get corrupted or updated by
external clients during boot without our knowledge.

This patch introduces a "verify" function for the SMMU
driver, to check that the boot configuration settings are
intact.  Usually, this function should be called at the
end of the boot cycle.

This function only calls panic() on silicon platforms.

Change-Id: I2ab45a7f228781e71c73ba1f4ffc49353effe146
Signed-off-by: George Bauernschmidt <georgeb@nvidia.com>
This commit is contained in:
Varun Wadekar 2019-09-26 08:26:41 -07:00 committed by Manish Pandey
parent 13fed5a7b4
commit 21ec61a904
4 changed files with 70 additions and 3 deletions

View File

@ -28,6 +28,7 @@
#include <memctrl.h>
#include <profiler.h>
#include <smmu.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
@ -272,6 +273,13 @@ void bl31_plat_runtime_setup(void)
*/
tegra_memctrl_disable_ahb_redirection();
#if defined(TEGRA_SMMU0_BASE)
/*
* Verify the integrity of the previously configured SMMU(s) settings
*/
tegra_smmu_verify();
#endif
/*
* Add final timestamp before exiting BL31.
*/

View File

@ -14,6 +14,7 @@
#include <common/debug.h>
#include <smmu.h>
#include <tegra_platform.h>
#include <tegra_private.h>
extern void memcpy16(void *dest, const void *src, unsigned int length);
@ -21,15 +22,17 @@ extern void memcpy16(void *dest, const void *src, unsigned int length);
#define SMMU_NUM_CONTEXTS 64U
#define SMMU_CONTEXT_BANK_MAX_IDX 64U
#define MISMATCH_DETECTED 0x55AA55AAU
/*
* Init SMMU during boot or "System Suspend" exit
*/
void tegra_smmu_init(void)
{
uint32_t val, cb_idx, smmu_id, ctx_base;
uint32_t smmu_counter = plat_get_num_smmu_devices();
uint32_t num_smmu_devices = plat_get_num_smmu_devices();
for (smmu_id = 0U; smmu_id < smmu_counter; smmu_id++) {
for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
/* Program the SMMU pagesize and reset CACHE_LOCK bit */
val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
val |= SMMU_GSR0_PGSIZE_64K;
@ -44,7 +47,7 @@ void tegra_smmu_init(void)
/* disable TCU prefetch for all contexts */
ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS)
+ SMMU_CBn_ACTLR;
for (cb_idx = 0; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
val = tegra_smmu_read_32(smmu_id,
ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
val &= (uint32_t)~SMMU_CBn_ACTLR_CPRE_BIT;
@ -63,3 +66,56 @@ void tegra_smmu_init(void)
tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val);
}
}
/*
* Verify SMMU settings have not been altered during boot
*/
void tegra_smmu_verify(void)
{
uint32_t cb_idx, ctx_base, smmu_id, val;
uint32_t num_smmu_devices = plat_get_num_smmu_devices();
uint32_t mismatch = 0U;
for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
/* check PGSIZE_64K bit inr S Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
if (0U == (val & SMMU_GSR0_PGSIZE_64K)) {
ERROR("%s: PGSIZE_64K Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
__func__, smmu_id, val);
mismatch = MISMATCH_DETECTED;
}
/* check CACHE LOCK bit in S Aux. Config. Register */
if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
ERROR("%s: CACHE_LOCK Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
__func__, smmu_id, val);
mismatch = MISMATCH_DETECTED;
}
/* check CACHE LOCK bit in NS Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
ERROR("%s: Mismatch - smmu_id=%d, GNSR_ACR=%x\n",
__func__, smmu_id, val);
mismatch = MISMATCH_DETECTED;
}
/* verify TCU prefetch for all contexts is disabled */
ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) +
SMMU_CBn_ACTLR;
for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
val = tegra_smmu_read_32(smmu_id,
ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
if (0U != (val & SMMU_CBn_ACTLR_CPRE_BIT)) {
ERROR("%s: Mismatch - smmu_id=%d, cb_idx=%d, GSR0_PGSIZE_64K=%x\n",
__func__, smmu_id, cb_idx, val);
mismatch = MISMATCH_DETECTED;
}
}
}
/* Treat configuration mismatch as fatal */
if ((mismatch == MISMATCH_DETECTED) && tegra_platform_is_silicon()) {
panic();
}
}

View File

@ -144,6 +144,7 @@ static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
mmio_write_32(TEGRA_MC_BASE + off, val);
}
#if defined(TEGRA_MC_STREAMID_BASE)
static inline uint32_t tegra_mc_streamid_read_32(uint32_t off)
{
return mmio_read_32(TEGRA_MC_STREAMID_BASE + off);
@ -153,6 +154,7 @@ static inline void tegra_mc_streamid_write_32(uint32_t off, uint32_t val)
{
mmio_write_32(TEGRA_MC_STREAMID_BASE + off, val);
}
#endif
#define mc_set_pcfifo_unordered_boot_so_mss(id, client) \
((uint32_t)~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \

View File

@ -86,6 +86,7 @@ static inline void tegra_smmu_write_32(uint32_t smmu_id,
}
void tegra_smmu_init(void);
void tegra_smmu_verify(void);
uint32_t plat_get_num_smmu_devices(void);
#endif /* SMMU_H */