From 265c271c822bd57677e3b286389487fd45e6960d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:44 +0000 Subject: ARM: l2c: remove outer_inv_all() method No one ever calls this function anywhere in the kernel, so let's completely remove it from the outer cache API and turn it into an internal-only thing. Signed-off-by: Russell King --- arch/arm/include/asm/outercache.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch/arm/include/asm/outercache.h') diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index f94784f0e3a6..0e4420858990 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -28,7 +28,6 @@ struct outer_cache_fns { void (*clean_range)(unsigned long, unsigned long); void (*flush_range)(unsigned long, unsigned long); void (*flush_all)(void); - void (*inv_all)(void); void (*disable)(void); #ifdef CONFIG_OUTER_CACHE_SYNC void (*sync)(void); @@ -63,12 +62,6 @@ static inline void outer_flush_all(void) outer_cache.flush_all(); } -static inline void outer_inv_all(void) -{ - if (outer_cache.inv_all) - outer_cache.inv_all(); -} - static inline void outer_disable(void) { if (outer_cache.disable) @@ -90,7 +83,6 @@ static inline void outer_clean_range(phys_addr_t start, phys_addr_t end) 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 void outer_resume(void) { } -- cgit v1.2.3 From bc4f94d85cad6035d02d2bed1b27f9bea7e7b6e6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Mar 2014 10:52:55 +0000 Subject: ARM: outer cache: add documentation of outer cache functions Add some documentation to cover the outer cache functions so that their requirements can be better understood. Of particular note are the flush_all() and disable() methods which must not be called except in very specific circumstances. Signed-off-by: Russell King --- arch/arm/include/asm/outercache.h | 48 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'arch/arm/include/asm/outercache.h') diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 0e4420858990..2615b3d9e807 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -39,35 +39,75 @@ struct outer_cache_fns { extern struct outer_cache_fns outer_cache; #ifdef CONFIG_OUTER_CACHE - +/** + * outer_inv_range - invalidate range of outer cache lines + * @start: starting physical address, inclusive + * @end: end physical address, exclusive + */ static inline void outer_inv_range(phys_addr_t start, phys_addr_t end) { if (outer_cache.inv_range) outer_cache.inv_range(start, end); } + +/** + * outer_clean_range - clean dirty outer cache lines + * @start: starting physical address, inclusive + * @end: end physical address, exclusive + */ static inline void outer_clean_range(phys_addr_t start, phys_addr_t end) { if (outer_cache.clean_range) outer_cache.clean_range(start, end); } + +/** + * outer_flush_range - clean and invalidate outer cache lines + * @start: starting physical address, inclusive + * @end: end physical address, exclusive + */ static inline void outer_flush_range(phys_addr_t start, phys_addr_t end) { if (outer_cache.flush_range) outer_cache.flush_range(start, end); } +/** + * outer_flush_all - clean and invalidate all cache lines in the outer cache + * + * Note: depending on implementation, this may not be atomic - it must + * only be called with interrupts disabled and no other active outer + * cache masters. + * + * It is intended that this function is only used by implementations + * needing to override the outer_cache.disable() method due to security. + * (Some implementations perform this as a clean followed by an invalidate.) + */ static inline void outer_flush_all(void) { if (outer_cache.flush_all) outer_cache.flush_all(); } +/** + * outer_disable - clean, invalidate and disable the outer cache + * + * Disable the outer cache, ensuring that any data contained in the outer + * cache is pushed out to lower levels of system memory. The note and + * conditions above concerning outer_flush_all() applies here. + */ static inline void outer_disable(void) { if (outer_cache.disable) outer_cache.disable(); } +/** + * outer_resume - restore the cache configuration and re-enable outer cache + * + * Restore any configuration that the cache had when previously enabled, + * and re-enable the outer cache. + */ static inline void outer_resume(void) { if (outer_cache.resume) @@ -89,6 +129,12 @@ static inline void outer_resume(void) { } #endif #ifdef CONFIG_OUTER_CACHE_SYNC +/** + * outer_sync - perform a sync point for outer cache + * + * Ensure that all outer cache operations are complete and any store + * buffers are drained. + */ static inline void outer_sync(void) { if (outer_cache.sync) -- cgit v1.2.3 From 1f1d5b745a4617a2cb2ffd8f4a9bc3be664cfc98 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Mar 2014 13:14:38 +0000 Subject: ARM: outer cache: add WARN_ON() to outer_disable() Add WARN_ON() conditions to outer_disable() to ensure that its requirements aren't violated. Signed-off-by: Russell King --- arch/arm/include/asm/outercache.h | 6 +----- arch/arm/mm/Makefile | 1 + arch/arm/mm/l2c-common.c | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mm/l2c-common.c (limited to 'arch/arm/include/asm/outercache.h') diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 2615b3d9e807..e96f194bf3d4 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -96,11 +96,7 @@ static inline void outer_flush_all(void) * cache is pushed out to lower levels of system memory. The note and * conditions above concerning outer_flush_all() applies here. */ -static inline void outer_disable(void) -{ - if (outer_cache.disable) - outer_cache.disable(); -} +extern void outer_disable(void); /** * outer_resume - restore the cache configuration and re-enable outer cache diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 7f39ce2f841f..de5a6a27081b 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_CPU_V7M) += proc-v7m.o AFLAGS_proc-v6.o :=-Wa,-march=armv6 AFLAGS_proc-v7.o :=-Wa,-march=armv7-a +obj-$(CONFIG_OUTER_CACHE) += l2c-common.o obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o diff --git a/arch/arm/mm/l2c-common.c b/arch/arm/mm/l2c-common.c new file mode 100644 index 000000000000..10a3cf28c362 --- /dev/null +++ b/arch/arm/mm/l2c-common.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2010 ARM Ltd. + * Written by Catalin Marinas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +void outer_disable(void) +{ + WARN_ON(!irqs_disabled()); + WARN_ON(num_online_cpus() > 1); + + if (outer_cache.disable) + outer_cache.disable(); +} -- cgit v1.2.3 From 8abd259f657d5742f96ffd46ed65feb11c44b1fb Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Mar 2014 17:38:08 +0000 Subject: ARM: l2c: provide generic hook to intercept writes to secure registers When Linux is running in the non-secure world, any write to a secure L2C register will generate an abort. Platforms normally have to call firmware to work around this. Provide a hook for them to intercept any L2C secure register write. l2c_write_sec() avoids writes to secure registers which are already set to the appropriate value, thus avoiding the overhead of needlessly calling into the secure monitor. Signed-off-by: Russell King --- arch/arm/include/asm/outercache.h | 5 ++++- arch/arm/mm/cache-l2x0.c | 42 ++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 13 deletions(-) (limited to 'arch/arm/include/asm/outercache.h') diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index e96f194bf3d4..864afe2114d3 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -32,8 +32,11 @@ struct outer_cache_fns { #ifdef CONFIG_OUTER_CACHE_SYNC void (*sync)(void); #endif - void (*set_debug)(unsigned long); void (*resume)(void); + + /* This is an ARM L2C thing */ + void (*set_debug)(unsigned long); + void (*write_sec)(unsigned long, unsigned); }; extern struct outer_cache_fns outer_cache; diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index b4d373ab1a5c..369a9d01d94f 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -59,6 +59,20 @@ static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask) cpu_relax(); } +/* + * By default, we write directly to secure registers. Platforms must + * override this if they are running non-secure. + */ +static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg) +{ + if (val == readl_relaxed(base + reg)) + return; + if (outer_cache.write_sec) + outer_cache.write_sec(val, reg); + else + writel_relaxed(val, base + reg); +} + /* * This should only be called when we have a requirement that the * register be written due to a work-around, as platforms running @@ -66,7 +80,10 @@ static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask) */ static inline void l2c_set_debug(void __iomem *base, unsigned long val) { - outer_cache.set_debug(val); + if (outer_cache.set_debug) + outer_cache.set_debug(val); + else + l2c_write_sec(val, base, L2X0_DEBUG_CTRL); } static void __l2c_op_way(void __iomem *reg) @@ -95,9 +112,7 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) { unsigned long flags; - /* Only write the aux register if it needs changing */ - if (readl_relaxed(base + L2X0_AUX_CTRL) != aux) - writel_relaxed(aux, base + L2X0_AUX_CTRL); + l2c_write_sec(aux, base, L2X0_AUX_CTRL); l2c_unlock(base, num_lock); @@ -107,7 +122,7 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) l2c_wait_mask(base + sync_reg_offset, 1); local_irq_restore(flags); - writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL); + l2c_write_sec(L2X0_CTRL_EN, base, L2X0_CTRL); } static void l2c_disable(void) @@ -115,7 +130,7 @@ static void l2c_disable(void) void __iomem *base = l2x0_base; outer_cache.flush_all(); - writel_relaxed(0, base + L2X0_CTRL); + l2c_write_sec(0, base, L2X0_CTRL); dsb(st); } @@ -139,7 +154,7 @@ static inline void cache_sync(void) #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) static inline void debug_writel(unsigned long val) { - if (outer_cache.set_debug) + if (outer_cache.set_debug || outer_cache.write_sec) l2c_set_debug(l2x0_base, val); } #else @@ -182,7 +197,7 @@ static void l2x0_disable(void) raw_spin_lock_irqsave(&l2x0_lock, flags); __l2x0_flush_all(); - writel_relaxed(0, l2x0_base + L2X0_CTRL); + l2c_write_sec(0, l2x0_base, L2X0_CTRL); dsb(st); raw_spin_unlock_irqrestore(&l2x0_lock, flags); } @@ -599,11 +614,11 @@ static void l2c310_resume(void) L2X0_CACHE_ID_RTL_MASK; if (revision >= L310_CACHE_ID_RTL_R2P0) - writel_relaxed(l2x0_saved_regs.prefetch_ctrl, - base + L2X0_PREFETCH_CTRL); + l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, + L2X0_PREFETCH_CTRL); if (revision >= L310_CACHE_ID_RTL_R3P0) - writel_relaxed(l2x0_saved_regs.pwr_ctrl, - base + L2X0_POWER_CTRL); + l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, + L2X0_POWER_CTRL); l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); } @@ -732,8 +747,11 @@ static void __init __l2c_init(const struct l2c_init_data *data, l2x0_size = ways * (data->way_size_0 << way_size_bits); fns = data->outer_cache; + fns.write_sec = outer_cache.write_sec; if (data->fixup) data->fixup(l2x0_base, cache_id, &fns); + if (fns.write_sec) + fns.set_debug = NULL; /* * Check if l2x0 controller is already enabled. If we are booting -- cgit v1.2.3 From 678ea28b7c3cc9a7196192dc77dfc13513db3d5f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Mar 2014 19:38:25 +0000 Subject: ARM: l2c: remove old .set_debug method We no longer need or require the .set_debug method; we handle everything it used to do via the .write_sec method instead. Signed-off-by: Russell King --- arch/arm/include/asm/outercache.h | 1 - arch/arm/mm/cache-l2x0.c | 21 ++------------------- 2 files changed, 2 insertions(+), 20 deletions(-) (limited to 'arch/arm/include/asm/outercache.h') diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 864afe2114d3..891a56b35bcf 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -35,7 +35,6 @@ struct outer_cache_fns { void (*resume)(void); /* This is an ARM L2C thing */ - void (*set_debug)(unsigned long); void (*write_sec)(unsigned long, unsigned); }; diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index c4f3e8dc64ff..ae6e71b3295c 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -81,10 +81,7 @@ static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg) */ static inline void l2c_set_debug(void __iomem *base, unsigned long val) { - if (outer_cache.set_debug) - outer_cache.set_debug(val); - else - l2c_write_sec(val, base, L2X0_DEBUG_CTRL); + l2c_write_sec(val, base, L2X0_DEBUG_CTRL); } static void __l2c_op_way(void __iomem *reg) @@ -155,8 +152,7 @@ static inline void cache_sync(void) #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) static inline void debug_writel(unsigned long val) { - if (outer_cache.set_debug || outer_cache.write_sec) - l2c_set_debug(l2x0_base, val); + l2c_set_debug(l2x0_base, val); } #else /* Optimised out for non-errata case */ @@ -514,11 +510,6 @@ static const struct l2c_init_data l2c220_data = { * Affects: store buffer * store buffer is not automatically drained. */ -static void l2c310_set_debug(unsigned long val) -{ - writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL); -} - static void l2c310_inv_range_erratum(unsigned long start, unsigned long end) { void __iomem *base = l2x0_base; @@ -695,10 +686,6 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id, const char *errata[8]; unsigned n = 0; - /* For compatibility */ - if (revision <= L310_CACHE_ID_RTL_R3P0) - fns->set_debug = l2c310_set_debug; - if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) && revision < L310_CACHE_ID_RTL_R2P0 && /* For bcm compatibility */ @@ -759,7 +746,6 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { .flush_all = l2c210_flush_all, .disable = l2c_disable, .sync = l2c210_sync, - .set_debug = l2c310_set_debug, .resume = l2c310_resume, }, }; @@ -819,8 +805,6 @@ static void __init __l2c_init(const struct l2c_init_data *data, fns.write_sec = outer_cache.write_sec; if (data->fixup) data->fixup(l2x0_base, cache_id, &fns); - if (fns.write_sec) - fns.set_debug = NULL; /* * Check if l2x0 controller is already enabled. If we are booting @@ -1000,7 +984,6 @@ static const struct l2c_init_data of_l2c310_data __initconst = { .flush_all = l2c210_flush_all, .disable = l2c_disable, .sync = l2c210_sync, - .set_debug = l2c310_set_debug, .resume = l2c310_resume, }, }; -- cgit v1.2.3