aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm/cache-b15-rac.c
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2017-11-30 19:10:11 -0500
committerRussell King <rmk+kernel@armlinux.org.uk>2017-12-17 17:15:37 -0500
commit55de88778f4bfe6333db4e475afb15ef413b4874 (patch)
tree0356ce4d899ff7e982754e551e24177e92b1694d /arch/arm/mm/cache-b15-rac.c
parent1238c4fd4812e225c93bc4c152769afa8493f903 (diff)
ARM: 8726/1: B15: Add CPU hotplug awareness
The Broadcom Brahma-B15 readahead cache needs to be disabled, respectively re-enable during a CPU hotplug. In case we were not to do, CPU hotplug would occasionally fail with random crashes when a given CPU exits the coherency domain while the RAC is still enabled, as it would get stale data from the RAC. In order to avoid adding any specific B15 readahead-cache awareness to arch/arm/mach-bcm/hotplug-brcmstb.c we use a CPU hotplug state machine which allows us to catch CPU hotplug events and disable/flush enable the RAC accordingly. Signed-off-by: Alamy Liu <alamyliu@broadcom.com> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'arch/arm/mm/cache-b15-rac.c')
-rw-r--r--arch/arm/mm/cache-b15-rac.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/arch/arm/mm/cache-b15-rac.c b/arch/arm/mm/cache-b15-rac.c
index 679d44f003fd..d85b63211759 100644
--- a/arch/arm/mm/cache-b15-rac.c
+++ b/arch/arm/mm/cache-b15-rac.c
@@ -13,6 +13,8 @@
13#include <linux/io.h> 13#include <linux/io.h>
14#include <linux/bitops.h> 14#include <linux/bitops.h>
15#include <linux/of_address.h> 15#include <linux/of_address.h>
16#include <linux/notifier.h>
17#include <linux/cpu.h>
16 18
17#include <asm/cacheflush.h> 19#include <asm/cacheflush.h>
18#include <asm/hardware/cache-b15-rac.h> 20#include <asm/hardware/cache-b15-rac.h>
@@ -42,6 +44,7 @@ extern void v7_flush_kern_cache_all(void);
42 44
43static void __iomem *b15_rac_base; 45static void __iomem *b15_rac_base;
44static DEFINE_SPINLOCK(rac_lock); 46static DEFINE_SPINLOCK(rac_lock);
47static u32 rac_config0_reg;
45 48
46/* Initialization flag to avoid checking for b15_rac_base, and to prevent 49/* Initialization flag to avoid checking for b15_rac_base, and to prevent
47 * multi-platform kernels from crashing here as well. 50 * multi-platform kernels from crashing here as well.
@@ -137,6 +140,74 @@ static void b15_rac_enable(void)
137 __b15_rac_enable(enable); 140 __b15_rac_enable(enable);
138} 141}
139 142
143#ifdef CONFIG_HOTPLUG_CPU
144/* The CPU hotplug case is the most interesting one, we basically need to make
145 * sure that the RAC is disabled for the entire system prior to having a CPU
146 * die, in particular prior to this dying CPU having exited the coherency
147 * domain.
148 *
149 * Once this CPU is marked dead, we can safely re-enable the RAC for the
150 * remaining CPUs in the system which are still online.
151 *
152 * Offlining a CPU is the problematic case, onlining a CPU is not much of an
153 * issue since the CPU and its cache-level hierarchy will start filling with
154 * the RAC disabled, so L1 and L2 only.
155 *
156 * In this function, we should NOT have to verify any unsafe setting/condition
157 * b15_rac_base:
158 *
159 * It is protected by the RAC_ENABLED flag which is cleared by default, and
160 * being cleared when initial procedure is done. b15_rac_base had been set at
161 * that time.
162 *
163 * RAC_ENABLED:
164 * There is a small timing windows, in b15_rac_init(), between
165 * cpuhp_setup_state_*()
166 * ...
167 * set RAC_ENABLED
168 * However, there is no hotplug activity based on the Linux booting procedure.
169 *
170 * Since we have to disable RAC for all cores, we keep RAC on as long as as
171 * possible (disable it as late as possible) to gain the cache benefit.
172 *
173 * Thus, dying/dead states are chosen here
174 *
175 * We are choosing not do disable the RAC on a per-CPU basis, here, if we did
176 * we would want to consider disabling it as early as possible to benefit the
177 * other active CPUs.
178 */
179
180/* Running on the dying CPU */
181static int b15_rac_dying_cpu(unsigned int cpu)
182{
183 spin_lock(&rac_lock);
184
185 /* Indicate that we are starting a hotplug procedure */
186 __clear_bit(RAC_ENABLED, &b15_rac_flags);
187
188 /* Disable the readahead cache and save its value to a global */
189 rac_config0_reg = b15_rac_disable_and_flush();
190
191 spin_unlock(&rac_lock);
192
193 return 0;
194}
195
196/* Running on a non-dying CPU */
197static int b15_rac_dead_cpu(unsigned int cpu)
198{
199 spin_lock(&rac_lock);
200
201 /* And enable it */
202 __b15_rac_enable(rac_config0_reg);
203 __set_bit(RAC_ENABLED, &b15_rac_flags);
204
205 spin_unlock(&rac_lock);
206
207 return 0;
208}
209#endif /* CONFIG_HOTPLUG_CPU */
210
140static int __init b15_rac_init(void) 211static int __init b15_rac_init(void)
141{ 212{
142 struct device_node *dn; 213 struct device_node *dn;
@@ -157,6 +228,20 @@ static int __init b15_rac_init(void)
157 goto out; 228 goto out;
158 } 229 }
159 230
231#ifdef CONFIG_HOTPLUG_CPU
232 ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CACHE_B15_RAC_DEAD,
233 "arm/cache-b15-rac:dead",
234 NULL, b15_rac_dead_cpu);
235 if (ret)
236 goto out_unmap;
237
238 ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CACHE_B15_RAC_DYING,
239 "arm/cache-b15-rac:dying",
240 NULL, b15_rac_dying_cpu);
241 if (ret)
242 goto out_cpu_dead;
243#endif
244
160 spin_lock(&rac_lock); 245 spin_lock(&rac_lock);
161 reg = __raw_readl(b15_rac_base + RAC_CONFIG0_REG); 246 reg = __raw_readl(b15_rac_base + RAC_CONFIG0_REG);
162 for_each_possible_cpu(cpu) 247 for_each_possible_cpu(cpu)
@@ -170,6 +255,12 @@ static int __init b15_rac_init(void)
170 pr_info("Broadcom Brahma-B15 readahead cache at: 0x%p\n", 255 pr_info("Broadcom Brahma-B15 readahead cache at: 0x%p\n",
171 b15_rac_base + RAC_CONFIG0_REG); 256 b15_rac_base + RAC_CONFIG0_REG);
172 257
258 goto out;
259
260out_cpu_dead:
261 cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CACHE_B15_RAC_DYING);
262out_unmap:
263 iounmap(b15_rac_base);
173out: 264out:
174 of_node_put(dn); 265 of_node_put(dn);
175 return ret; 266 return ret;