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 | |
| 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')
| -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; |
