ARM: Broadcom Brahma-B15 readahead cache support
Subsystems (2)
cover ARM: Broadcom Brahma-B15 readahead cache support
Hi all,
This patch series adds support for the Broadcom Brahma-B15 CPU read-ahead cache which is to be found in several Broadcom SoCs, and mainline brcmstb.
Let me know your thoughts on this, we have tried to minimize both the compile-time and runtime impact for non-Broadcom CPU parts.
Florian Fainelli (5):
ARM: v7: allow setting different cache functions
ARM: Add Broadcom Brahma-B15 readahead cache support
ARM: Hook B15 readahead cache functions based on processor
ARM: B15: Add CPU hotplug awareness
ARM: B15: Add suspend/resume hooks
arch/arm/include/asm/cacheflush.h | 2 +- arch/arm/include/asm/glue-cache.h | 4 + arch/arm/include/asm/hardware/cache-b15-rac.h | 12 + arch/arm/mm/Kconfig | 8 + arch/arm/mm/Makefile | 1 + arch/arm/mm/cache-b15-rac.c | 329 ++++++++++++++++++++++++++ arch/arm/mm/cache-v7.S | 21 ++ arch/arm/mm/proc-v7.S | 6 +- 8 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 arch/arm/include/asm/hardware/cache-b15-rac.h create mode 100644 arch/arm/mm/cache-b15-rac.c
Signature · 1 line
2.1.0
PATCH 1/5 ARM: v7: allow setting different cache functions
In preparation for adding support for the Broadcom Brahma-B15 read-ahead cache which requires a different set of cache functions, allow the __v7_proc macro to override the cache_fns settings, and default to v7_cache_fns unless specified otherwise.
--- arch/arm/mm/proc-v7.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm/mm/proc-v7.S +2 -2
@@ -467,7 +467,7 @@ __v7_setup_stack: /* * Standard v7 proc info content */ -.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions +.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions, cache_fns = v7_cache_fns ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \ PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags) ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
@@ -483,7 +483,7 @@ __v7_setup_stack: .long \proc_fns .long v7wbi_tlb_fns .long v6_user_fns - .long v7_cache_fns + .long \cache_fns .endm #ifndef CONFIG_ARM_LPAE
Signature · 1 line
2.1.0
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
In reply to Florian FainelliThis patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
The readahead cache is mostly transparent, except for flush_kern_cache_all, flush_kern_cache_louis and flush_icache_all, which is precisely what we are overriding here.
The readahead cache only intercepts reads, not writes, as such, some data can remain stale in any of its buffers, such that we need to flush it, which is an operation that needs to happen in a particular order:
- disable the readahead cache
- flush it
- call the appropriate cache-v7.S function
- re-enable
This patch tries to minimize the impact to the cache-v7.S file by only providing a stub in case CONFIG_CACHE_B15_RAC is enabled (default for ARCH_BRCMSTB since it is the current user).
--- arch/arm/include/asm/cacheflush.h | 2 +- arch/arm/include/asm/glue-cache.h | 4 + arch/arm/include/asm/hardware/cache-b15-rac.h | 12 ++ arch/arm/mm/Kconfig | 8 ++ arch/arm/mm/Makefile | 1 + arch/arm/mm/cache-b15-rac.c | 181 ++++++++++++++++++++++++++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/hardware/cache-b15-rac.h create mode 100644 arch/arm/mm/cache-b15-rac.c
arch/arm/include/asm/cacheflush.h +1 -1
@@ -199,7 +199,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,*/ #if (defined(CONFIG_CPU_V7 ) && \ (defined(CONFIG_CPU_V6 ) || defined(CONFIG_CPU_V6K ))) || \ - defined(CONFIG_SMP_ON_UP ) + defined(CONFIG_SMP_ON_UP ) || defined(CONFIG_CACHE_B15_RAC )#define __flush_icache_preferred __cpuc_flush_icache_all#elif __LINUX_ARM_ARCH__ >=7 && defined(CONFIG_SMP )#define __flush_icache_preferred __flush_icache_all_v7_smp
arch/arm/include/asm/glue-cache.h +4 -0
@@ -117,6 +117,10 @@# endif #endif +#if defined(CONFIG_CACHE_B15_RAC ) +# define MULTI_CACHE 1 +#endif +#if defined(CONFIG_CPU_V7M )# ifdef _CACHE# define MULTI_CACHE 1
arch/arm/include/asm/hardware/cache-b15-rac.h new file +12 -0
@@ -0,0 +1,12 @@ +#ifndef __ASM_ARM_HARDWARE_CACHE_B15_RAC_H +#define __ASM_ARM_HARDWARE_CACHE_B15_RAC_H + +#ifndef __ASSEMBLY__ + +void b15_flush_kern_cache_all (void ); +void b15_flush_kern_cache_louis (void ); +void b15_flush_icache_all (void ); + +#endif + +#endif
arch/arm/mm/Kconfig +8 -0
@@ -853,6 +853,14 @@ config OUTER_CACHE_SYNC The outer cache has a outer_cache_fns.sync function pointer that can be used to drain the write buffer of the outer cache. +config CACHE_B15_RAC + bool "Enable the Broadcom Brahma-B15 read-ahead cache controller" + depends on ARCH_BRCMSTB + default y + help + This option enables the Broadcom Brahma-B15 read-ahead cache + controller. If disabled, the read-ahead cache remains off. + config CACHE_FEROCEON_L2 bool "Enable the Feroceon L2 cache controller" depends on ARCH_MV78XX0 || ARCH_MVEBU
arch/arm/mm/Makefile +1 -0
@@ -96,6 +96,7 @@ 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_B15_RAC) += cache-b15-rac.o obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o
arch/arm/mm/cache-b15-rac.c new file +181 -0
181 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 143 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.The readahead cache only intercepts reads, not writes, as such, some data can remain stale in any of its buffers, such that we need to flush it, which is an operation that needs to happen in a particular order:
- disable the readahead cache
- flush it
- call the appropriatecache-v7.Sfunction
- re-enableThis patch tries to minimize the impact to the
cache-v7.Sfile by only providing a stub in caseCONFIG_CACHE_B15_RACis enabled (default forARCH_BRCMSTBsince it is the current user).Signed-off-by Alamy Liu <[email protected]>Signed-off-by Florian Fainelli <[email protected]>--- arch/arm/include/asm/cacheflush.h | 2 +- arch/arm/include/asm/glue-cache.h | 4 + arch/arm/include/asm/hardware/cache-b15-rac.h | 12 ++ arch/arm/mm/Kconfig | 8 ++ arch/arm/mm/Makefile | 1 + arch/arm/mm/cache-b15-rac.c | 181 ++++++++++++++++++++++++++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/hardware/cache-b15-rac.h create mode 100644 arch/arm/mm/cache-b15-rac.carch/arm/include/asm/cacheflush.h +1
-1@@ -199,7 +199,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,*/ #if (defined(CONFIG_CPU_V7 ) && \ (defined(CONFIG_CPU_V6 ) || defined(CONFIG_CPU_V6K ))) || \ - defined(CONFIG_SMP_ON_UP ) + defined(CONFIG_SMP_ON_UP ) || defined(CONFIG_CACHE_B15_RAC )#define __flush_icache_preferred __cpuc_flush_icache_all#elif __LINUX_ARM_ARCH__ >=7 && defined(CONFIG_SMP )#define __flush_icache_preferred __flush_icache_all_v7_smparch/arm/include/asm/glue-cache.h +4
-0@@ -117,6 +117,10 @@# endif #endif +#if defined(CONFIG_CACHE_B15_RAC ) +# define MULTI_CACHE 1 +#endif +#if defined(CONFIG_CPU_V7M )# ifdef _CACHE# define MULTI_CACHE 1arch/arm/include/asm/hardware/cache-b15-rac.h new file +12
-0@@ -0,0 +1,12 @@ +#ifndef __ASM_ARM_HARDWARE_CACHE_B15_RAC_H +#define __ASM_ARM_HARDWARE_CACHE_B15_RAC_H + +#ifndef __ASSEMBLY__ + +void b15_flush_kern_cache_all (void ); +void b15_flush_kern_cache_louis (void ); +void b15_flush_icache_all (void ); + +#endif + +#endif arch/arm/mm/Kconfig +8
-0@@ -853,6 +853,14 @@ config OUTER_CACHE_SYNC The outer cache has a outer_cache_fns.sync function pointer that can be used to drain the write buffer of the outer cache. +config CACHE_B15_RAC + bool "Enable the Broadcom Brahma-B15 read-ahead cache controller" + depends on ARCH_BRCMSTB + default y + help + This option enables the Broadcom Brahma-B15 read-ahead cache + controller. If disabled, the read-ahead cache remains off. + config CACHE_FEROCEON_L2 bool "Enable the Feroceon L2 cache controller" depends on ARCH_MV78XX0 || ARCH_MVEBUarch/arm/mm/Makefile +1
-0@@ -96,6 +96,7 @@ 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_B15_RAC) += cache-b15-rac.o obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.oarch/arm/mm/cache-b15-rac.c new file +25
-0@@ -0,0 +1,181 @@ +/* +* Broadcom Brahma-B15 CPU read-ahead cache management functions +* +* Copyright (C) 2015, Broadcom Corporation +* +* 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 <linux/err.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/of_address.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/cache-b15-rac.h> + +extern void v7_flush_kern_cache_all (void ); +extern void v7_flush_kern_cache_louis (void ); +extern void v7_flush_icache_all (void ); + +/* RAC register offsets, relative to the HIF_CPU_BIUCTRL register base */ +#define RAC_CONFIG0_REG (0x78)
arch/arm/mm/cache-b15-rac.c line 35
Quoted 10 lines
arch/arm/mm/cache-b15-rac.c new file +10
-0+#define RACENPREF_MASK (0x3) +#define RACPREFINST_SHIFT (0) +#define RACENINST_SHIFT (2) +#define RACPREFDATA_SHIFT (4) +#define RACENDATA_SHIFT (6) +#define RAC_CPU_SHIFT (8) +#define RACCFG_MASK (0xff) +#define RAC_CONFIG1_REG (0x7c) +#define RAC_FLUSH_REG (0x80) +#define FLUSH_RAC (1 << 0)
BIT(0) ?
arch/arm/mm/cache-b15-rac.c line 43
Quoted 8 lines
arch/arm/mm/cache-b15-rac.c new file +8
-0+ +/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */ +#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \ + RACENPREF_MASK << RACENINST_SHIFT | \ + 1 << RACPREFDATA_SHIFT | \ + RACENPREF_MASK << RACENDATA_SHIFT) + +#define RAC_ENABLED (1 << 0)
BIT(0) ?
However, you don't use RAC_ENABLED as a bitmask, but a bit index, so shouldn't this be zero?
Quoted 46 lines
arch/arm/mm/cache-b15-rac.c new file +46
-0+ +static void __iomem *b15_rac_base; +static DEFINE_SPINLOCK (rac_lock); + +/* Initialization flag to avoid checking for b15_rac_base, and to prevent +* multi-platform kernels from crashing here as well. +*/ +static unsigned long b15_rac_flags; + +static inline u32 __b15_rac_disable (void ) +{ +u32 val =__raw_readl (b15_rac_base +RAC_CONFIG0_REG ); +__raw_writel (0 , b15_rac_base +RAC_CONFIG0_REG ); +dmb (); +return val; +} + +static inline void __b15_rac_flush (void ) +{ +u32 reg; + +__raw_writel (FLUSH_RAC , b15_rac_base +RAC_FLUSH_REG ); +do { +/* This dmb() is required to force the Bus Interface Unit +* to clean oustanding writes, and forces an idle cycle +* to be inserted. +*/ +dmb (); + reg =__raw_readl (b15_rac_base +RAC_FLUSH_REG ); + }while (reg &RAC_FLUSH_REG ); +} + +static inline u32 b15_rac_disable_and_flush (void ) +{ +u32 reg; + + reg =__b15_rac_disable (); +__b15_rac_flush (); +return reg; +} + +static inline void __b15_rac_enable (u32 val) +{ +__raw_writel (val, b15_rac_base +RAC_CONFIG0_REG ); +/* dsb() is required here to be consistent with __flush_icache_all() */ +dsb ();
arch/arm/mm/cache-b15-rac.c line 99
Quoted 10 lines
arch/arm/mm/cache-b15-rac.c new file +10
-0+} + +#define BUILD_RAC_CACHE_OP (name, bar) \ +void b15_flush_##name(void) \ +{ \ + unsigned int do_flush; \ + u32 val = 0; \ + \ + spin_lock(&rac_lock); \ + do_flush = test_bit(RAC_ENABLED, &b15_rac_flags); \
Do you need to use test_bit() here? You set and test this location under a spinlock, so it's safe to use non-atomic ops here.
arch/arm/mm/cache-b15-rac.c line 139
Quoted 7 lines
arch/arm/mm/cache-b15-rac.c new file +7
-0+static void b15_rac_enable (void ) +{ +unsigned int cpu; +u32 enable =0 ; + +for_each_possible_cpu (cpu) + enable |= (RAC_DATA_INST_EN_MASK << (cpu *RAC_CPU_SHIFT ));
enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT);
You don't need the additional parens - the right hand side of |= is already expected to be an expression by the compiler.
arch/arm/mm/cache-b15-rac.c line 167
Quoted 4 lines
arch/arm/mm/cache-b15-rac.c new file +4
-0+spin_lock (&rac_lock); + reg =__raw_readl (b15_rac_base +RAC_CONFIG0_REG ); +for_each_possible_cpu (cpu) + en_mask |= ((1 <<RACPREFDATA_SHIFT ) << (cpu *RAC_CPU_SHIFT ));
en_mask |= 1 << (RACPREFDATA_SHIFT + cpu * RAC_CPU_SHIFT);
looks nicer, rather than having two shifts.
What happens when the system goes down (eg, for kexec?) Does the RAC need to be disabled for that?
Signature · 2 lines
FTTC broadband for 0.8mile line: [email protected] down 400kbps up according to speedtest.net.
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 26 lines · Russell King - ARM Linux
Quoted 25 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.The readahead cache only intercepts reads, not writes, as such, some data can remain stale in any of its buffers, such that we need to flush it, which is an operation that needs to happen in a particular order:
- disable the readahead cache
- flush it
- call the appropriatecache-v7.Sfunction
- re-enableThis patch tries to minimize the impact to the
cache-v7.Sfile by only providing a stub in caseCONFIG_CACHE_B15_RACis enabled (default forARCH_BRCMSTBsince it is the current user).Signed-off-by Alamy Liu <[email protected]>Signed-off-by Florian Fainelli <[email protected]>---
[snip]
Quoted 10 lines
arch/arm/mm/cache-b15-rac.c line 43
Quoted 7 lines
arch/arm/mm/cache-b15-rac.c new file +7
-0+/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */ +#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \ + RACENPREF_MASK << RACENINST_SHIFT | \ + 1 << RACPREFDATA_SHIFT | \ + RACENPREF_MASK << RACENDATA_SHIFT) + +#define RAC_ENABLED (1 << 0)BIT(0) ?
Quoted 2 lines
However, you don't use
RAC_ENABLEDas a bitmask, but a bit index, so shouldn't this be zero?
In subsequent patches we have a need for distinguishing RAC_ENABLED from RAC_SUSPENDED, so that's the primary reason for using it as a bitmask (could make that clear somewhere).
[snip]
Quoted 11 lines
arch/arm/mm/cache-b15-rac.c line 99
Quoted 8 lines
arch/arm/mm/cache-b15-rac.c new file +8
-0+#define BUILD_RAC_CACHE_OP (name, bar) \ +void b15_flush_##name(void) \ +{ \ + unsigned int do_flush; \ + u32 val = 0; \ + \ + spin_lock(&rac_lock); \ + do_flush = test_bit(RAC_ENABLED, &b15_rac_flags); \Do you need to use
test_bit()here? You set and test this location under a spinlock, so it's safe to use non-atomic ops here.
Right, we don't need the test_bit, it just felt a little nicer.
Quoted 14 lines
arch/arm/mm/cache-b15-rac.c line 139
Quoted 8 lines
arch/arm/mm/cache-b15-rac.c new file +7
-0+static void b15_rac_enable (void ) +{ +unsigned int cpu; +u32 enable =0 ; + +for_each_possible_cpu (cpu) + enable |= (RAC_DATA_INST_EN_MASK << (cpu *RAC_CPU_SHIFT ));enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT);You don't need the additional parens - the right hand side of |= is already expected to be an expression by the compiler.
Quoted 8 lines
arch/arm/mm/cache-b15-rac.c line 167
Quoted 4 lines
arch/arm/mm/cache-b15-rac.c new file +4
-0+spin_lock (&rac_lock); + reg =__raw_readl (b15_rac_base +RAC_CONFIG0_REG ); +for_each_possible_cpu (cpu) + en_mask |= ((1 <<RACPREFDATA_SHIFT ) << (cpu *RAC_CPU_SHIFT ));en_mask |= 1 << (RACPREFDATA_SHIFT + cpu * RAC_CPU_SHIFT);looks nicer, rather than having two shifts.
Indeed, thanks.
Quoted 3 lines
What happens when the system goes down (eg, for kexec?) Does the RAC need to be disabled for that?
Per boot convention, I would say so, yes, since this is another level of instruction and data cache, we should turn it off. Can we register some sort of notifier specifically for kexec?
Thanks!
Signature · 1 line
Florian
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 40 lines · Florian Fainelli
Quoted 26 lines · Russell King - ARM Linux
Quoted 25 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.The readahead cache only intercepts reads, not writes, as such, some data can remain stale in any of its buffers, such that we need to flush it, which is an operation that needs to happen in a particular order:
- disable the readahead cache
- flush it
- call the appropriatecache-v7.Sfunction
- re-enableThis patch tries to minimize the impact to the
cache-v7.Sfile by only providing a stub in caseCONFIG_CACHE_B15_RACis enabled (default forARCH_BRCMSTBsince it is the current user).Signed-off-by Alamy Liu <[email protected]>Signed-off-by Florian Fainelli <[email protected]>---
[snip]
Quoted 10 lines
arch/arm/mm/cache-b15-rac.c line 43
Quoted 7 lines
arch/arm/mm/cache-b15-rac.c new file +7
-0+/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */ +#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \ + RACENPREF_MASK << RACENINST_SHIFT | \ + 1 << RACPREFDATA_SHIFT | \ + RACENPREF_MASK << RACENDATA_SHIFT) + +#define RAC_ENABLED (1 << 0)BIT(0) ?
Quoted 6 lines
Quoted 2 lines
However, you don't use
RAC_ENABLEDas a bitmask, but a bit index, so shouldn't this be zero?In subsequent patches we have a need for distinguishing
RAC_ENABLEDfromRAC_SUSPENDED, so that's the primary reason for using it as a bitmask (could make that clear somewhere).
However, test_bit() etc take a bit _number_ not a bit _mask_. So:
Passing in 1 << 0 will test bit 1 rather than bit 0. Passing in 1 << 1 will test bit 2 rather than bit 1. Passing in 1 << 2 will test bit 4 rather than bit 2. Passing in 1 << 3 will test bit 8 rather than bit 3. etc.
This is not what you wanted. Either use a mask directly, or use test_bit() with a bit number etc. Don't try and do both together. :)
Quoted 6 lines
Quoted 2 lines
What happens when the system goes down (eg, for kexec?) Does the RAC need to be disabled for that?
Per boot convention, I would say so, yes, since this is another level of instruction and data cache, we should turn it off. Can we register some sort of notifier specifically for kexec?
The code at present doesn't expect there to be platform specific caches, so that probably isn't catered for yet. I mentioned the point to raise the issue that there's an oversight here.
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up according to speedtest.net.
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 50 lines · Russell King - ARM Linux
Quoted 40 lines · Florian Fainelli
Quoted 26 lines · Russell King - ARM Linux
Quoted 25 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.The readahead cache only intercepts reads, not writes, as such, some data can remain stale in any of its buffers, such that we need to flush it, which is an operation that needs to happen in a particular order:
- disable the readahead cache
- flush it
- call the appropriatecache-v7.Sfunction
- re-enableThis patch tries to minimize the impact to the
cache-v7.Sfile by only providing a stub in caseCONFIG_CACHE_B15_RACis enabled (default forARCH_BRCMSTBsince it is the current user).Signed-off-by Alamy Liu <[email protected]>Signed-off-by Florian Fainelli <[email protected]>---
[snip]
Quoted 10 lines
arch/arm/mm/cache-b15-rac.c line 43
Quoted 7 lines
arch/arm/mm/cache-b15-rac.c new file +7
-0+/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */ +#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \ + RACENPREF_MASK << RACENINST_SHIFT | \ + 1 << RACPREFDATA_SHIFT | \ + RACENPREF_MASK << RACENDATA_SHIFT) + +#define RAC_ENABLED (1 << 0)BIT(0) ?Quoted 6 lines
Quoted 2 lines
However, you don't use
RAC_ENABLEDas a bitmask, but a bit index, so shouldn't this be zero?In subsequent patches we have a need for distinguishing
RAC_ENABLEDfromRAC_SUSPENDED, so that's the primary reason for using it as a bitmask (could make that clear somewhere).However,
test_bit()etc take a bit _number_ not a bit _mask_. So:
Quoted 8 lines
Passing in 1 << 0 will test bit 1 rather than bit 0. Passing in 1 << 1 will test bit 2 rather than bit 1. Passing in 1 << 2 will test bit 4 rather than bit 2. Passing in 1 << 3 will test bit 8 rather than bit 3. etc.
This is not what you wanted. Either use a mask directly, or use
test_bit()with a bit number etc. Don't try and do both together. :)
Fixed, thanks.
Quoted 11 lines
Quoted 7 lines
Quoted 3 lines
What happens when the system goes down (eg, for kexec?) Does the RAC need to be disabled for that?
Per boot convention, I would say so, yes, since this is another level of instruction and data cache, we should turn it off. Can we register some sort of notifier specifically for kexec?
The code at present doesn't expect there to be platform specific caches, so that probably isn't catered for yet. I mentioned the point to raise the issue that there's an oversight here.
Since kexec goes through the usual suspend/resume path, it will suspend the RAC by calling into syscore_suspend (patch 5), that's when CONFIG_KERNEL_KEXEC_JUMP is set, which is not guaranteed.
kernel_restart_prepare() calls a reboot notifier with SYS_RESTART, so if we disable the RAC at this point, we should be good, I will add that.
Signature · 1 line
Florian
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
In reply to Florian FainelliQuoted 8 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.
I'm struggling to understand why you care about flush_kern_cache_louis and flush_icache_all for a cache that sits the other side of the L2.
Can you explain why we need to do anything in these cases, please?
Will
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 6 lines · Will Deacon
Quoted 5 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
Quoted 8 lines
Quoted 3 lines
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.I'm struggling to understand why you care about
flush_kern_cache_louisandflush_icache_allfor a cache that sits the other side of the L2.Can you explain why we need to do anything in these cases, please?
Let's try, as you may have read in the comment, all MVA-based cache maintenance operations are snooped by the RAC, so they are effectively "transparent" to software, all others are not.
flush_kern_cache_louis() and flush_icache_all() both use ICALLIUS in the SMP case and ICIALLU in the UP case which were flagged as not being transparently handled.
The concern is that, if you perform a L1 cache (data or instruction) flush (essentially an invalidate), this will also flush (invalidate) corresponding L2 cache lines, but the RAC has no way to be signaled that is should also invalidate its own RAC cache lines pertaining to that data, and RAC holds per-CPU "super" cache lines.
In arch/arm/kernel/smp.c, all uses of flush_cache_louis() are for writing-back data, so the RAC is not an issue. In arch/arm/kernel/suspend.c, flush_cache_louis() is known not to guarantee a "clean" all the way to main memory, so __cpu_flush_dcache_area is used in conjunction. In arch/arm/mm/idmap.c and mmu.c, the use of flush_cache_louis() seems to be meant to see fresh data, not write-back, so not transparent to the RAC, is that right?
It may very well be that we are super cautious here and that the only case to take care of is essentially flush_cache_all(), and nothing more.
Would you suggestions on how to instrument/exercise whether we really need to deal with flush_cache_louis() and flush_icache_all()?
Thanks!
Signature · 1 line
Florian
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 38 lines · Florian Fainelli
Quoted 6 lines · Will Deacon
Quoted 5 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
Quoted 8 lines
Quoted 3 lines
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.I'm struggling to understand why you care about
flush_kern_cache_louisandflush_icache_allfor a cache that sits the other side of the L2.Can you explain why we need to do anything in these cases, please?
Let's try, as you may have read in the comment, all MVA-based cache maintenance operations are snooped by the RAC, so they are effectively "transparent" to software, all others are not.
flush_kern_cache_louis()andflush_icache_all()both use ICALLIUS in the SMP case and ICIALLU in the UP case which were flagged as not being transparently handled.The concern is that, if you perform a L1 cache (data or instruction) flush (essentially an invalidate), this will also flush (invalidate) corresponding L2 cache lines, but the RAC has no way to be signaled that is should also invalidate its own RAC cache lines pertaining to that data, and RAC holds per-CPU "super" cache lines.
In
arch/arm/kernel/smp.c, all uses offlush_cache_louis()are for writing-back data, so the RAC is not an issue. Inarch/arm/kernel/suspend.c,flush_cache_louis()is known not to guarantee a "clean" all the way to main memory, so__cpu_flush_dcache_areais used in conjunction. Inarch/arm/mm/idmap.candmmu.c, the use offlush_cache_louis()seems to be meant to see fresh data, not write-back, so not transparent to the RAC, is that right?
Quoted 5 lines
It may very well be that we are super cautious here and that the only case to take care of is essentially
flush_cache_all(), and nothing more.Would you suggestions on how to instrument/exercise whether we really need to deal with
flush_cache_louis()andflush_icache_all()?
I think that both flush_cache_louis and flush_icache_all only care about the inner-shareable domain, so you don't need to do anything with the RAC. It's a bit like the PL310 outer-cache, which is also not affected by these operations.
I don't think there's a good way to determine statically if we have missing cacheflush calls. Maybe a better bet would be to implement a RAC driver using the outer_cache framework and only implement the flush_all callback.
Will
PATCH 2/5 ARM: Add Broadcom Brahma-B15 readahead cache support
Quoted 42 lines · Will Deacon
Quoted 41 lines · Florian Fainelli
Quoted 6 lines · Will Deacon
Quoted 5 lines · Florian Fainelli
This patch adds support for the Broadcom Brahma-B15 CPU readahead cache controller. This cache controller sits between the L2 and the memory bus and its purpose is to provide a friendler burst size towards the DDR interface than the native cache line size.
Quoted 8 lines
Quoted 3 lines
The readahead cache is mostly transparent, except for
flush_kern_cache_all,flush_kern_cache_louisandflush_icache_all, which is precisely what we are overriding here.I'm struggling to understand why you care about
flush_kern_cache_louisandflush_icache_allfor a cache that sits the other side of the L2.Can you explain why we need to do anything in these cases, please?
Let's try, as you may have read in the comment, all MVA-based cache maintenance operations are snooped by the RAC, so they are effectively "transparent" to software, all others are not.
flush_kern_cache_louis()andflush_icache_all()both use ICALLIUS in the SMP case and ICIALLU in the UP case which were flagged as not being transparently handled.The concern is that, if you perform a L1 cache (data or instruction) flush (essentially an invalidate), this will also flush (invalidate) corresponding L2 cache lines, but the RAC has no way to be signaled that is should also invalidate its own RAC cache lines pertaining to that data, and RAC holds per-CPU "super" cache lines.
In
arch/arm/kernel/smp.c, all uses offlush_cache_louis()are for writing-back data, so the RAC is not an issue. Inarch/arm/kernel/suspend.c,flush_cache_louis()is known not to guarantee a "clean" all the way to main memory, so__cpu_flush_dcache_areais used in conjunction. Inarch/arm/mm/idmap.candmmu.c, the use offlush_cache_louis()seems to be meant to see fresh data, not write-back, so not transparent to the RAC, is that right?It may very well be that we are super cautious here and that the only case to take care of is essentially
flush_cache_all(), and nothing more.
Quoted 7 lines
Quoted 2 lines
Would you suggestions on how to instrument/exercise whether we really need to deal with
flush_cache_louis()andflush_icache_all()?I think that both
flush_cache_louisandflush_icache_allonly care about the inner-shareable domain, so you don't need to do anything with the RAC. It's a bit like the PL310 outer-cache, which is also not affected by these operations.
I see, will keep experimenting with removing these two and see if anything breaks.
Quoted 5 lines
I don't think there's a good way to determine statically if we have missing cacheflush calls. Maybe a better bet would be to implement a RAC driver using the
outer_cacheframework and only implement theflush_allcallback.
Last I tried this, the performance became absolutely terrible for e.g:
networking which involves doing frequent invalidation + write-back due to DMA operations. Also, it did not seem to me like it was possible to get an information about the DMA transfer direction (at least not at this level) which could help speed the write-back case since there nothing to do in that case (unlike in the PL310 case).
Signature · 1 line
Florian
PATCH 3/5 ARM: Hook B15 readahead cache functions based on processor
In reply to Florian FainelliIf we detect that we are running on a Broadcom Brahma-B15 CPU, and CONFIG_CACHE_B15_RAC is enabled, make sure that we pick-up the b15_cache_fns function operations.
If CONFIG_CACHE_B15_RAC is enabled, but we are not running on a Broadcom Brahma-B15 CPU, we will fallback to calling into the regular v7_cache_fns with no cost. If CONFIG_CACHE_B15_RAC is disabled, there is no cost and we just use the regular v7_cache_fns.
--- arch/arm/mm/cache-v7.S | 21 +++++++++++++++++++++ arch/arm/mm/proc-v7.S | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-)
arch/arm/mm/cache-v7.S +21 -0
@@ -15,6 +15,7 @@ #include <asm/assembler.h> #include <asm/errno.h> #include <asm/unwind.h> +#include <asm/hardware/cache-b15-rac.h> #include "proc-macros.S"
@@ -446,3 +447,23 @@ ENDPROC(v7_dma_unmap_area) @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions v7 + + /* The Broadcom Brahma-B15 read-ahead cache requires some modifications + * to the v7_cache_fns, we only override the ones we need + */ +#ifndef CONFIG_CACHE_B15_RAC + globl_equ b15_flush_icache_all, v7_flush_icache_all + globl_equ b15_flush_kern_cache_all, v7_flush_kern_cache_all + globl_equ b15_flush_kern_cache_louis, v7_flush_kern_cache_louis +#endif + globl_equ b15_flush_user_cache_all, v7_flush_user_cache_all + globl_equ b15_flush_user_cache_range, v7_flush_user_cache_range + globl_equ b15_coherent_kern_range, v7_coherent_kern_range + globl_equ b15_coherent_user_range, v7_coherent_user_range + globl_equ b15_flush_kern_dcache_area, v7_flush_kern_dcache_area + + globl_equ b15_dma_map_area, v7_dma_map_area + globl_equ b15_dma_unmap_area, v7_dma_unmap_area + globl_equ b15_dma_flush_range, v7_dma_flush_range + + define_cache_functions b15
arch/arm/mm/proc-v7.S +1 -1
@@ -568,7 +568,7 @@ __v7_ca15mp_proc_info: __v7_b15mp_proc_info: .long 0x420f00f0 .long 0xff0ffff0 - __v7_proc __v7_b15mp_setup + __v7_proc __v7_b15mp_setup, cache_fns = b15_cache_fns .size __v7_b15mp_proc_info, . - __v7_b15mp_proc_info /*
Signature · 1 line
2.1.0
PATCH 4/5 ARM: B15: Add CPU hotplug awareness
In reply to Florian FainelliThe 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 notifier which allows us to catch CPU hotplug events and disable/flush enable the RAC accordingly.
--- arch/arm/mm/cache-b15-rac.c | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
arch/arm/mm/cache-b15-rac.c +100 -0
@@ -13,6 +13,8 @@#include <linux/io.h> #include <linux/bitops.h> #include <linux/of_address.h> +#include <linux/notifier.h> +#include <linux/cpu.h> #include <asm/cacheflush.h> #include <asm/hardware/cache-b15-rac.h>
@@ -44,6 +46,7 @@ extern void v7_flush_icache_all(void);static void __iomem *b15_rac_base;static DEFINE_SPINLOCK (rac_lock); +static u32 rac_config0_reg;/* Initialization flag to avoid checking for b15_rac_base, and to prevent * multi-platform kernels from crashing here as well.
@@ -142,6 +145,94 @@ static void b15_rac_enable(void)__b15_rac_enable (enable); } +#ifdef CONFIG_HOTPLUG_CPU +static void b15_rac_hotplug_start (void ) +{ +/* Indicate that we are starting a hotplug procedure */ +clear_bit (RAC_ENABLED , &b15_rac_flags); + +/* Disable the readahead cache and save its value to a global */ + rac_config0_reg =b15_rac_disable_and_flush (); +} + +static void b15_rac_hotplug_end (void ) +{ +/* And enable it */ +__b15_rac_enable (rac_config0_reg); +set_bit (RAC_ENABLED , &b15_rac_flags); +} + +/* The CPU hotplug case is the most interesting one, we basically need to make +* sure that the RAC is disabled for the entire system prior to having a CPU +* die, in particular prior to this dying CPU having exited the coherency +* domain. +* +* Once this CPU is marked dead, we can safely re-enable the RAC for the +* remaining CPUs in the system which are still online. +* +* Offlining a CPU is the problematic case, onlining a CPU is not much of an +* issue since the CPU and its cache-level hierarchy will start filling with +* the RAC disabled, so L1 and L2 only. +* +* In this function, we should NOT have to verify any unsafe setting/condition +* b15_rac_base: +* +* It is protected by the RAC_ENABLED flag which is cleared by default, and +* being cleared when initial procedure is done. b15_rac_base had been set at +* that time. +* +* RAC_ENABLED: +* There is a small timing windows, in b15_rac_init(), between +* register_cpu_notifier(&b15_rac_cpu_nb); +* ... +* set RAC_ENABLED +* However, there is no hotplug activity based on the Linux booting procedure. +* +* Regarding the notification actions, we will receive CPU_DOWN_PREPARE, +* CPU_DOWN_FAILED, CPU_DYING, CPU_DEAD, and CPU_POST_DEAD notification (see +* _cpu_down() for detail). +* +* Since we have to disable RAC for all cores, we keep RAC on as long as as +* possible (disable it as late as possible) to gain the cache benefit. +* +* Thus, CPU_DYING/CPU_DEAD pair are chosen. +* +* We are choosing not do disable the RAC on a per-CPU basis, here, if we did +* we would want to consider disabling it as early as possible to benefit the +* other active CPUs. +*/ +static int b15_rac_cpu_notify (struct notifier_block *self, +unsigned long action,void *hcpu) +{ + action &= ~CPU_TASKS_FROZEN ; + +if (action !=CPU_DYING && action !=CPU_DOWN_FAILED && + action !=CPU_DEAD ) +return NOTIFY_OK ; + +spin_lock (&rac_lock); +switch (action) { +/* called on the dying CPU, exactly what we want */ +case CPU_DYING : +b15_rac_hotplug_start (); +break ; + +/* called on a non-dying CPU, what we want too */ +case CPU_DOWN_FAILED : +case CPU_DEAD : +b15_rac_hotplug_end (); +break ; + } +spin_unlock (&rac_lock); + +return NOTIFY_OK ; +} + +static struct notifier_block b15_rac_cpu_nb = { + .notifier_call = b15_rac_cpu_notify, +}; +#endif /* CONFIG_HOTPLUG_CPU */ +static int __init b15_rac_init (void ) {struct device_node *dn;
@@ -161,6 +252,15 @@ static int __init b15_rac_init(void) goto out; } +#ifdef CONFIG_HOTPLUG_CPU + ret =register_cpu_notifier (&b15_rac_cpu_nb); +if (ret) { +pr_err ("failed to register notifier block\n" ); +iounmap (b15_rac_base); + goto out; + } +#endif +spin_lock (&rac_lock); reg =__raw_readl (b15_rac_base +RAC_CONFIG0_REG );for_each_possible_cpu (cpu)
Signature · 1 line
2.1.0
PATCH 5/5 ARM: B15: Add suspend/resume hooks
In reply to Florian FainelliThe Broadcom Brahma-B15 CPU readahead cache registers will be restored to their Power-on-Reset values after a S3 suspend/resume cycles, so we want to restore what we had enabled before.
Another thing we want to take care of is disabling the read-ahead cache prior to suspending to avoid any sort of side effect with the spinlock we need to grab to serialize register accesses.
--- arch/arm/mm/cache-b15-rac.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
arch/arm/mm/cache-b15-rac.c +48 -0
@@ -15,6 +15,7 @@#include <linux/of_address.h> #include <linux/notifier.h> #include <linux/cpu.h> +#include <linux/syscore_ops.h> #include <asm/cacheflush.h> #include <asm/hardware/cache-b15-rac.h>
@@ -43,6 +44,10 @@ extern void v7_flush_icache_all(void); RACENPREF_MASK << RACENDATA_SHIFT)#define RAC_ENABLED (1 << 0) +/* Special state where we want to bypass the spinlock and call directly +* into the v7 cache maintenance operations during suspend/resume +*/ +#define RAC_SUSPENDED (1 << 1)static void __iomem *b15_rac_base;static DEFINE_SPINLOCK (rac_lock);
@@ -98,6 +103,12 @@ void b15_flush_##name(void) \unsigned int do_flush; \u32 val =0 ; \ \ +if (test_bit (RAC_SUSPENDED , &b15_rac_flags)) { \ + v7_flush_##name(); \ + bar; \ +return ; \ + } \ + \spin_lock (&rac_lock); \ do_flush =test_bit (RAC_ENABLED , &b15_rac_flags); \if (do_flush) \
@@ -233,6 +244,39 @@ static struct notifier_block b15_rac_cpu_nb = { };#endif /* CONFIG_HOTPLUG_CPU */ +#ifdef CONFIG_PM_SLEEP +static int b15_rac_suspend (void ) +{ +/* Suspend the read-ahead cache oeprations, forcing our cache +* implementation to fallback to the regular ARMv7 calls. +* +* We are guaranteed to be running on the boot CPU@this point and +* with every other CPU quiesced, so setting RAC_SUSPENDED is not racy +* here. +*/ + rac_config0_reg =b15_rac_disable_and_flush (); +set_bit (RAC_SUSPENDED , &b15_rac_flags); + +return 0 ; +} + +static void b15_rac_resume (void ) +{ +/* Coming out of a S3 suspend/resume cycle, the read-ahead cache +* register RAC_CONFIG0_REG will be restored to its default value, make +* sure we re-enable it and set the enable flag, we are also guaranteed +* to run on the boot CPU, so not racy again. +*/ +__b15_rac_enable (rac_config0_reg); +clear_bit (RAC_SUSPENDED , &b15_rac_flags); +} + +static struct syscore_ops b15_rac_syscore_ops = { + .suspend = b15_rac_suspend, + .resume = b15_rac_resume, +}; +#endif +static int __init b15_rac_init (void ) {struct device_node *dn;
@@ -261,6 +305,10 @@ static int __init b15_rac_init(void) }#endif +#ifdef CONFIG_PM_SLEEP +register_syscore_ops (&b15_rac_syscore_ops); +#endif +spin_lock (&rac_lock); reg =__raw_readl (b15_rac_base +RAC_CONFIG0_REG );for_each_possible_cpu (cpu)
Signature · 1 line
2.1.0
cover ARM: Broadcom Brahma-B15 readahead cache support
In reply to Florian FainelliQuoted 7 lines · Florian Fainelli
Hi all,
This patch series adds support for the Broadcom Brahma-B15 CPU read-ahead cache which is to be found in several Broadcom SoCs, and mainline brcmstb.
Let me know your thoughts on this, we have tried to minimize both the compile-time and runtime impact for non-Broadcom CPU parts.
Any feedback on this implementation? Thanks!
Quoted 20 lines
Florian Fainelli (5):
ARM: v7: allow setting different cache functions
ARM: Add Broadcom Brahma-B15 readahead cache support
ARM: Hook B15 readahead cache functions based on processor
ARM: B15: Add CPU hotplug awareness
ARM: B15: Add suspend/resume hooksarch/arm/include/asm/cacheflush.h | 2 +- arch/arm/include/asm/glue-cache.h | 4 + arch/arm/include/asm/hardware/cache-b15-rac.h | 12 + arch/arm/mm/Kconfig | 8 + arch/arm/mm/Makefile | 1 + arch/arm/mm/cache-b15-rac.c | 329 ++++++++++++++++++++++++++ arch/arm/mm/cache-v7.S | 21 ++ arch/arm/mm/proc-v7.S | 6 +- 8 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 arch/arm/include/asm/hardware/cache-b15-rac.h create mode 100644 arch/arm/mm/cache-b15-rac.c
Signature · 1 line
Florian