mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
f81309067f
The existing memory barrier macro causes a significant amount of code to be inserted inline at every call site. For example, in gpio_set_irq_type(), we have this for mb(): c0344c08: f57ff04e dsb st c0344c0c: e59f8190 ldr r8, [pc, #400] ; c0344da4 <gpio_set_irq_type+0x230> c0344c10: e3590004 cmp r9, #4 c0344c14: e5983014 ldr r3, [r8, #20] c0344c18: 0a000054 beq c0344d70 <gpio_set_irq_type+0x1fc> c0344c1c: e3530000 cmp r3, #0 c0344c20: 0a000004 beq c0344c38 <gpio_set_irq_type+0xc4> c0344c24: e50b2030 str r2, [fp, #-48] ; 0xffffffd0 c0344c28: e50bc034 str ip, [fp, #-52] ; 0xffffffcc c0344c2c: e12fff33 blx r3 c0344c30: e51bc034 ldr ip, [fp, #-52] ; 0xffffffcc c0344c34: e51b2030 ldr r2, [fp, #-48] ; 0xffffffd0 c0344c38: e5963004 ldr r3, [r6, #4] Moving the outer_cache_sync() call out of line reduces the impact of the barrier: c0344968: f57ff04e dsb st c034496c: e35a0004 cmp sl, #4 c0344970: e50b2030 str r2, [fp, #-48] ; 0xffffffd0 c0344974: 0a000044 beq c0344a8c <gpio_set_irq_type+0x1b8> c0344978: ebf363dd bl c001d8f4 <arm_heavy_mb> c034497c: e5953004 ldr r3, [r5, #4] This should reduce the cache footprint of this code. Overall, this results in a reduction of around 20K in the kernel size: text data bss dec hex filename 10773970 667392 10369656 21811018 14ccf4a ../build/imx6/vmlinux-old 10754219 667392 10369656 21791267 14c8223 ../build/imx6/vmlinux-new Another advantage to this approach is that we can finally resolve the issue of SoCs which have their own memory barrier requirements within multiplatform kernels (such as OMAP.) Here, the bus interconnects need additional handling to ensure that writes become visible in the correct order (eg, between dma_map() operations, writes to DMA coherent memory, and MMIO accesses.) Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Richard Woodruff <r-woodruff2@ti.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
133 lines
3.8 KiB
C
133 lines
3.8 KiB
C
/*
|
|
* arch/arm/include/asm/outercache.h
|
|
*
|
|
* Copyright (C) 2010 ARM Ltd.
|
|
* Written by Catalin Marinas <catalin.marinas@arm.com>
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifndef __ASM_OUTERCACHE_H
|
|
#define __ASM_OUTERCACHE_H
|
|
|
|
#include <linux/types.h>
|
|
|
|
struct l2x0_regs;
|
|
|
|
struct outer_cache_fns {
|
|
void (*inv_range)(unsigned long, unsigned long);
|
|
void (*clean_range)(unsigned long, unsigned long);
|
|
void (*flush_range)(unsigned long, unsigned long);
|
|
void (*flush_all)(void);
|
|
void (*disable)(void);
|
|
#ifdef CONFIG_OUTER_CACHE_SYNC
|
|
void (*sync)(void);
|
|
#endif
|
|
void (*resume)(void);
|
|
|
|
/* This is an ARM L2C thing */
|
|
void (*write_sec)(unsigned long, unsigned);
|
|
void (*configure)(const struct l2x0_regs *);
|
|
};
|
|
|
|
extern struct outer_cache_fns outer_cache;
|
|
|
|
#ifdef CONFIG_OUTER_CACHE
|
|
/**
|
|
* outer_inv_range - invalidate range of outer cache lines
|
|
* @start: starting physical address, inclusive
|
|
* @end: end physical address, exclusive
|
|
*/
|
|
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
|
|
{
|
|
if (outer_cache.inv_range)
|
|
outer_cache.inv_range(start, end);
|
|
}
|
|
|
|
/**
|
|
* outer_clean_range - clean dirty outer cache lines
|
|
* @start: starting physical address, inclusive
|
|
* @end: end physical address, exclusive
|
|
*/
|
|
static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
|
|
{
|
|
if (outer_cache.clean_range)
|
|
outer_cache.clean_range(start, end);
|
|
}
|
|
|
|
/**
|
|
* outer_flush_range - clean and invalidate outer cache lines
|
|
* @start: starting physical address, inclusive
|
|
* @end: end physical address, exclusive
|
|
*/
|
|
static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
|
|
{
|
|
if (outer_cache.flush_range)
|
|
outer_cache.flush_range(start, end);
|
|
}
|
|
|
|
/**
|
|
* outer_flush_all - clean and invalidate all cache lines in the outer cache
|
|
*
|
|
* Note: depending on implementation, this may not be atomic - it must
|
|
* only be called with interrupts disabled and no other active outer
|
|
* cache masters.
|
|
*
|
|
* It is intended that this function is only used by implementations
|
|
* needing to override the outer_cache.disable() method due to security.
|
|
* (Some implementations perform this as a clean followed by an invalidate.)
|
|
*/
|
|
static inline void outer_flush_all(void)
|
|
{
|
|
if (outer_cache.flush_all)
|
|
outer_cache.flush_all();
|
|
}
|
|
|
|
/**
|
|
* outer_disable - clean, invalidate and disable the outer cache
|
|
*
|
|
* Disable the outer cache, ensuring that any data contained in the outer
|
|
* cache is pushed out to lower levels of system memory. The note and
|
|
* conditions above concerning outer_flush_all() applies here.
|
|
*/
|
|
extern void outer_disable(void);
|
|
|
|
/**
|
|
* outer_resume - restore the cache configuration and re-enable outer cache
|
|
*
|
|
* Restore any configuration that the cache had when previously enabled,
|
|
* and re-enable the outer cache.
|
|
*/
|
|
static inline void outer_resume(void)
|
|
{
|
|
if (outer_cache.resume)
|
|
outer_cache.resume();
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
|
|
{ }
|
|
static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
|
|
{ }
|
|
static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
|
|
{ }
|
|
static inline void outer_flush_all(void) { }
|
|
static inline void outer_disable(void) { }
|
|
static inline void outer_resume(void) { }
|
|
|
|
#endif
|
|
|
|
#endif /* __ASM_OUTERCACHE_H */
|