[PATCH 1/2] arm/mm: L2CC shared mutex with ARM TZ
Etienne CARRIERE
etienne.carriere at st.com
Tue Nov 13 11:08:14 EST 2012
From: Etienne Carriere <etienne.carriere at stericsson.com>
Secure code in TrustZone space may need to perform L2 cache
maintenance operations. A shared mutex is required to synchronize
linux l2cc maintenance and TZ l2cc maintenance.
The TZ mutex is an "arch_spinlock": a 32bit DDR cell (ARMv7-A mutex).
Linux L2 cache driver must lock TZ mutex if enabled.
Signed-off-by: Etienne Carriere <etienne.carriere at stericsson.com>
---
arch/arm/include/asm/outercache.h | 9 ++++
arch/arm/mm/cache-l2x0.c | 87 +++++++++++++++++++++++++++++----------
2 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 53426c6..7aa5eac 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -35,6 +35,7 @@ struct outer_cache_fns {
#endif
void (*set_debug)(unsigned long);
void (*resume)(void);
+ bool (*tz_mutex)(unsigned long);
};
#ifdef CONFIG_OUTER_CACHE
@@ -81,6 +82,13 @@ static inline void outer_resume(void)
outer_cache.resume();
}
+static inline bool outer_tz_mutex(unsigned long addr)
+{
+ if (outer_cache.tz_mutex)
+ return outer_cache.tz_mutex(addr);
+ return false;
+}
+
#else
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
@@ -92,6 +100,7 @@ static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
static inline void outer_flush_all(void) { }
static inline void outer_inv_all(void) { }
static inline void outer_disable(void) { }
+static inline bool outer_tz_mutex(unsigned long addr) { return false; }
#endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index a53fd2a..eacdc74 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -41,6 +41,26 @@ struct l2x0_of_data {
void (*resume)(void);
};
+/*
+ * arch_spinlock (single 32bit DDR mutex cell) pointer to synchronise
+ * L2CC maintenance between linux world and secure world (ARM TZ).
+ */
+arch_spinlock_t *l2x0_tz_mutex;
+
+#define l2x0_spin_lock_irqsave(flags) \
+ do { \
+ raw_spin_lock_irqsave(&l2x0_lock, flags); \
+ if (l2x0_tz_mutex) \
+ arch_spin_lock(l2x0_tz_mutex); \
+ } while (0)
+
+#define l2x0_spin_unlock_irqrestore(flags) \
+ do { \
+ if (l2x0_tz_mutex) \
+ arch_spin_unlock(l2x0_tz_mutex); \
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); \
+ } while (0)
+
static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
{
/* wait for cache operation by line or way to complete */
@@ -126,9 +146,9 @@ static void l2x0_cache_sync(void)
{
unsigned long flags;
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
cache_sync();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void __l2x0_flush_all(void)
@@ -145,9 +165,9 @@ static void l2x0_flush_all(void)
unsigned long flags;
/* clean all ways */
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
__l2x0_flush_all();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_clean_all(void)
@@ -155,11 +175,11 @@ static void l2x0_clean_all(void)
unsigned long flags;
/* clean all ways */
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY);
cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask);
cache_sync();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_inv_all(void)
@@ -167,13 +187,13 @@ static void l2x0_inv_all(void)
unsigned long flags;
/* invalidate all ways */
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
/* Invalidating when L2 is enabled is a nono */
BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
cache_sync();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_inv_range(unsigned long start, unsigned long end)
@@ -181,7 +201,7 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
void __iomem *base = l2x0_base;
unsigned long flags;
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
if (start & (CACHE_LINE_SIZE - 1)) {
start &= ~(CACHE_LINE_SIZE - 1);
debug_writel(0x03);
@@ -206,13 +226,13 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
}
if (blk_end < end) {
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
+ l2x0_spin_lock_irqsave(flags);
}
}
cache_wait(base + L2X0_INV_LINE_PA, 1);
cache_sync();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_clean_range(unsigned long start, unsigned long end)
@@ -225,7 +245,7 @@ static void l2x0_clean_range(unsigned long start, unsigned long end)
return;
}
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
unsigned long blk_end = start + min(end - start, 4096UL);
@@ -236,13 +256,13 @@ static void l2x0_clean_range(unsigned long start, unsigned long end)
}
if (blk_end < end) {
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
+ l2x0_spin_lock_irqsave(flags);
}
}
cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
cache_sync();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_flush_range(unsigned long start, unsigned long end)
@@ -255,7 +275,7 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
return;
}
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
unsigned long blk_end = start + min(end - start, 4096UL);
@@ -268,24 +288,24 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
debug_writel(0x00);
if (blk_end < end) {
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
+ l2x0_spin_lock_irqsave(flags);
}
}
cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
cache_sync();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_disable(void)
{
unsigned long flags;
- raw_spin_lock_irqsave(&l2x0_lock, flags);
+ l2x0_spin_lock_irqsave(flags);
__l2x0_flush_all();
writel_relaxed(0, l2x0_base + L2X0_CTRL);
dsb();
- raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ l2x0_spin_unlock_irqrestore(flags);
}
static void l2x0_unlock(u32 cache_id)
@@ -307,6 +327,28 @@ static void l2x0_unlock(u32 cache_id)
}
}
+/* Enable/disable external mutex shared with TZ code */
+static bool l2x0_tz_mutex_cfg(unsigned long addr)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2x0_lock, flags);
+
+ if (addr && l2x0_tz_mutex && (addr != (uint)l2x0_tz_mutex)) {
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ pr_err("%s: a TZ mutex is already enabled\n", __func__);
+ return false;
+ }
+
+ l2x0_tz_mutex = (arch_spinlock_t *)addr;
+ /* insure mutex ptr is updated before lock is released */
+ smp_wmb();
+
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ pr_debug("\n%s: %sable TZ mutex\n\n", __func__, (addr) ? "en" : "dis");
+ return true;
+}
+
void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
{
u32 aux;
@@ -380,6 +422,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
outer_cache.inv_all = l2x0_inv_all;
outer_cache.disable = l2x0_disable;
outer_cache.set_debug = l2x0_set_debug;
+ outer_cache.tz_mutex = l2x0_tz_mutex_cfg;
printk(KERN_INFO "%s cache controller enabled\n", type);
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
--
1.7.11.3
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121113/b0f6414c/attachment-0001.html>
More information about the linux-arm-kernel
mailing list