aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mm/cache-b15-rac.c91
-rw-r--r--include/linux/cpuhotplug.h2
2 files changed, 93 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;
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 201ab7267986..3f7b30fcc96a 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -59,6 +59,7 @@ enum cpuhp_state {
59 CPUHP_PCI_XGENE_DEAD, 59 CPUHP_PCI_XGENE_DEAD,
60 CPUHP_IOMMU_INTEL_DEAD, 60 CPUHP_IOMMU_INTEL_DEAD,
61 CPUHP_LUSTRE_CFS_DEAD, 61 CPUHP_LUSTRE_CFS_DEAD,
62 CPUHP_AP_ARM_CACHE_B15_RAC_DEAD,
62 CPUHP_WORKQUEUE_PREP, 63 CPUHP_WORKQUEUE_PREP,
63 CPUHP_POWER_NUMA_PREPARE, 64 CPUHP_POWER_NUMA_PREPARE,
64 CPUHP_HRTIMERS_PREPARE, 65 CPUHP_HRTIMERS_PREPARE,
@@ -137,6 +138,7 @@ enum cpuhp_state {
137 CPUHP_AP_ARM64_ISNDEP_STARTING, 138 CPUHP_AP_ARM64_ISNDEP_STARTING,
138 CPUHP_AP_SMPCFD_DYING, 139 CPUHP_AP_SMPCFD_DYING,
139 CPUHP_AP_X86_TBOOT_DYING, 140 CPUHP_AP_X86_TBOOT_DYING,
141 CPUHP_AP_ARM_CACHE_B15_RAC_DYING,
140 CPUHP_AP_ONLINE, 142 CPUHP_AP_ONLINE,
141 CPUHP_TEARDOWN_CPU, 143 CPUHP_TEARDOWN_CPU,
142 CPUHP_AP_ONLINE_IDLE, 144 CPUHP_AP_ONLINE_IDLE,