diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2017-11-30 19:10:11 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-12-17 17:15:37 -0500 |
commit | 55de88778f4bfe6333db4e475afb15ef413b4874 (patch) | |
tree | 0356ce4d899ff7e982754e551e24177e92b1694d /arch/arm/mm/cache-b15-rac.c | |
parent | 1238c4fd4812e225c93bc4c152769afa8493f903 (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.c | 91 |
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 | ||
43 | static void __iomem *b15_rac_base; | 45 | static void __iomem *b15_rac_base; |
44 | static DEFINE_SPINLOCK(rac_lock); | 46 | static DEFINE_SPINLOCK(rac_lock); |
47 | static 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 */ | ||
181 | static 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 */ | ||
197 | static 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 | |||
140 | static int __init b15_rac_init(void) | 211 | static 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 | |||
260 | out_cpu_dead: | ||
261 | cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CACHE_B15_RAC_DYING); | ||
262 | out_unmap: | ||
263 | iounmap(b15_rac_base); | ||
173 | out: | 264 | out: |
174 | of_node_put(dn); | 265 | of_node_put(dn); |
175 | return ret; | 266 | return ret; |