* [PATCH v3 1/4] ARM: Change the mandatory barriers implementation
2010-03-03 12:16 [PATCH v3 0/4] ARM mandatory barriers Catalin Marinas
@ 2010-03-03 12:16 ` Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 2/4] ARM: Move the outer_cache definitions into a separate file Catalin Marinas
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Catalin Marinas @ 2010-03-03 12:16 UTC (permalink / raw)
To: linux-arm-kernel
The mandatory barriers (mb, rmb, wmb) are used even on uniprocessor
systems for things like ordering Normal Non-cacheable memory accesses
with DMA transfer (via Device memory writes). The current implementation
uses dmb() for mb() and friends but this is not sufficient. The DMB only
ensures the relative ordering of the observability of accesses by other
processors or devices acting as masters. In case of DMA transfers
started by writes to device memory, the relative ordering is not ensured
because accesses to slave ports of a device are not considered
observable by the DMB definition.
A DSB is required for the data to reach the main memory (even if mapped
as Normal Non-cacheable) before the device receives the notification to
begin the transfer.
The patch also adds support for platform-defined barriers that can be
defined in mach/barriers.h. This is required by at least two platforms -
MSM and RealView (possible OMAP as well). On RealView with an outer
cache (PL310 for example) stores to Normal Non-cacheable memory are
buffered by the outer cache but the DSB doesn't go as far as this. A
separate L2x0 sync command is required (a store to Strongly Ordered
memory would do as well, similar to the MSM requirements and maybe
faster).
Note that the SMP barriers are implemented as DMB since they are only
guaranteed to work with Normal cacheable memory.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Daniel Walker <dwalker@codeaurora.org>
Cc: Larry Bassel <lbassel@quicinc.com>
Cc: Tony Lindgren <tony@atomide.com>
---
arch/arm/include/asm/system.h | 14 ++++++++------
arch/arm/mm/Kconfig | 6 ++++++
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 058e7e9..146305a 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -138,10 +138,12 @@ extern unsigned int user_debug;
#define dmb() __asm__ __volatile__ ("" : : : "memory")
#endif
-#if __LINUX_ARM_ARCH__ >= 7 || defined(CONFIG_SMP)
-#define mb() dmb()
+#ifdef CONFIG_ARCH_HAS_BARRIERS
+#include <mach/barriers.h>
+#elif __LINUX_ARM_ARCH__ >= 7 || defined(CONFIG_SMP)
+#define mb() dsb()
#define rmb() dmb()
-#define wmb() dmb()
+#define wmb() dsb()
#else
#define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
@@ -153,9 +155,9 @@ extern unsigned int user_debug;
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#else
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
+#define smp_mb() dmb()
+#define smp_rmb() dmb()
+#define smp_wmb() dmb()
#endif
#define read_barrier_depends() do { } while(0)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index f62beb7..f67f2c4 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -802,3 +802,9 @@ config ARM_L1_CACHE_SHIFT
int
default 6 if ARCH_OMAP3 || ARCH_S5PC1XX
default 5
+
+config ARCH_HAS_BARRIERS
+ bool
+ help
+ This option allows the use of custom mandatory barriers
+ included via the mach/barriers.h file.
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v3 2/4] ARM: Move the outer_cache definitions into a separate file
2010-03-03 12:16 [PATCH v3 0/4] ARM mandatory barriers Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 1/4] ARM: Change the mandatory barriers implementation Catalin Marinas
@ 2010-03-03 12:16 ` Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 3/4] ARM: Add outer_cache_fns sync function and support for L2x0 Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 4/4] ARM: Add RealView-specific barrier implementation Catalin Marinas
3 siblings, 0 replies; 5+ messages in thread
From: Catalin Marinas @ 2010-03-03 12:16 UTC (permalink / raw)
To: linux-arm-kernel
To avoid #include collisions with subsequent patches in the series, this
patch moves the outer_cache definitions to a separate asm/outercache.h
file.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/include/asm/cacheflush.h | 38 +----------------------
arch/arm/include/asm/outercache.h | 61 +++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 37 deletions(-)
create mode 100644 arch/arm/include/asm/outercache.h
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 8113bb5..ed7d289 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -15,6 +15,7 @@
#include <asm/glue.h>
#include <asm/shmparam.h>
#include <asm/cachetype.h>
+#include <asm/outercache.h>
#define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
@@ -233,12 +234,6 @@ struct cpu_cache_fns {
void (*dma_flush_range)(const void *, const void *);
};
-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);
-};
-
/*
* Select the calling method
*/
@@ -295,37 +290,6 @@ extern void dmac_flush_range(const void *, const void *);
#endif
-#ifdef CONFIG_OUTER_CACHE
-
-extern struct outer_cache_fns outer_cache;
-
-static inline void outer_inv_range(unsigned long start, unsigned long end)
-{
- if (outer_cache.inv_range)
- outer_cache.inv_range(start, end);
-}
-static inline void outer_clean_range(unsigned long start, unsigned long end)
-{
- if (outer_cache.clean_range)
- outer_cache.clean_range(start, end);
-}
-static inline void outer_flush_range(unsigned long start, unsigned long end)
-{
- if (outer_cache.flush_range)
- outer_cache.flush_range(start, end);
-}
-
-#else
-
-static inline void outer_inv_range(unsigned long start, unsigned long end)
-{ }
-static inline void outer_clean_range(unsigned long start, unsigned long end)
-{ }
-static inline void outer_flush_range(unsigned long start, unsigned long end)
-{ }
-
-#endif
-
/*
* Copy user data from/to a page which is mapped into a different
* processes address space. Really, we want to allow our "user
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
new file mode 100644
index 0000000..c8571cb
--- /dev/null
+++ b/arch/arm/include/asm/outercache.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+
+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);
+};
+
+#ifdef CONFIG_OUTER_CACHE
+
+extern struct outer_cache_fns outer_cache;
+
+static inline void outer_inv_range(unsigned long start, unsigned long end)
+{
+ if (outer_cache.inv_range)
+ outer_cache.inv_range(start, end);
+}
+static inline void outer_clean_range(unsigned long start, unsigned long end)
+{
+ if (outer_cache.clean_range)
+ outer_cache.clean_range(start, end);
+}
+static inline void outer_flush_range(unsigned long start, unsigned long end)
+{
+ if (outer_cache.flush_range)
+ outer_cache.flush_range(start, end);
+}
+
+#else
+
+static inline void outer_inv_range(unsigned long start, unsigned long end)
+{ }
+static inline void outer_clean_range(unsigned long start, unsigned long end)
+{ }
+static inline void outer_flush_range(unsigned long start, unsigned long end)
+{ }
+
+#endif
+
+#endif /* __ASM_OUTERCACHE_H */
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v3 3/4] ARM: Add outer_cache_fns sync function and support for L2x0
2010-03-03 12:16 [PATCH v3 0/4] ARM mandatory barriers Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 1/4] ARM: Change the mandatory barriers implementation Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 2/4] ARM: Move the outer_cache definitions into a separate file Catalin Marinas
@ 2010-03-03 12:16 ` Catalin Marinas
2010-03-03 12:16 ` [PATCH v3 4/4] ARM: Add RealView-specific barrier implementation Catalin Marinas
3 siblings, 0 replies; 5+ messages in thread
From: Catalin Marinas @ 2010-03-03 12:16 UTC (permalink / raw)
To: linux-arm-kernel
This patch introduces the outer_cache_fns.sync function that can be used
to drain the write buffers of the outer cache. It also initialises this
function for cache-l2x0.c.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/include/asm/outercache.h | 8 ++++++++
arch/arm/mm/cache-l2x0.c | 10 ++++++++++
2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index c8571cb..c94bfe1 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -25,6 +25,7 @@ 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 (*sync)(void);
};
#ifdef CONFIG_OUTER_CACHE
@@ -46,6 +47,11 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
if (outer_cache.flush_range)
outer_cache.flush_range(start, end);
}
+static inline void outer_sync(void)
+{
+ if (outer_cache.sync)
+ outer_cache.sync();
+}
#else
@@ -55,6 +61,8 @@ static inline void outer_clean_range(unsigned long start, unsigned long end)
{ }
static inline void outer_flush_range(unsigned long start, unsigned long end)
{ }
+static inline void outer_sync(void)
+{ }
#endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 5951ded..47149d2 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -43,6 +43,15 @@ static inline void cache_sync(void)
cache_wait(base + L2X0_CACHE_SYNC, 1);
}
+static void l2x0_cache_sync(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&l2x0_lock, flags);
+ cache_sync();
+ spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
static inline void l2x0_inv_all(void)
{
unsigned long flags;
@@ -179,6 +188,7 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
outer_cache.inv_range = l2x0_inv_range;
outer_cache.clean_range = l2x0_clean_range;
outer_cache.flush_range = l2x0_flush_range;
+ outer_cache.sync = l2x0_cache_sync;
printk(KERN_INFO "L2X0 cache controller enabled\n");
}
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v3 4/4] ARM: Add RealView-specific barrier implementation
2010-03-03 12:16 [PATCH v3 0/4] ARM mandatory barriers Catalin Marinas
` (2 preceding siblings ...)
2010-03-03 12:16 ` [PATCH v3 3/4] ARM: Add outer_cache_fns sync function and support for L2x0 Catalin Marinas
@ 2010-03-03 12:16 ` Catalin Marinas
3 siblings, 0 replies; 5+ messages in thread
From: Catalin Marinas @ 2010-03-03 12:16 UTC (permalink / raw)
To: linux-arm-kernel
This patch defines ARCH_HAS_BARRIERS for the RealView boards if
CACHE_L2X0 is enabled and adds the mach/barriers.h file. The mb() and
wmb() barriers perform an L2 cache sync in addition to the DSB.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/Kconfig | 1 +
arch/arm/mach-realview/include/mach/barriers.h | 30 ++++++++++++++++++++++++
2 files changed, 31 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-realview/include/mach/barriers.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 184a6bd..d2b1f3f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -235,6 +235,7 @@ config ARCH_REALVIEW
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select ARCH_HAS_BARRIERS if CACHE_L2X0
help
This enables support for ARM Ltd RealView boards.
diff --git a/arch/arm/mach-realview/include/mach/barriers.h b/arch/arm/mach-realview/include/mach/barriers.h
new file mode 100644
index 0000000..cc11517
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/barriers.h
@@ -0,0 +1,30 @@
+/*
+ * arch/arm/mach-realview/include/mach/barriers.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 __MACH_BARRIERS_H
+#define __MACH_BARRIERS_H
+
+#include <asm/outercache.h>
+
+#define rmb() dmb()
+#define wmb() do { dsb(); outer_sync(); } while (0)
+#define mb() wmb()
+
+#endif /* __MACH_BARRIERS_H */
^ permalink raw reply related [flat|nested] 5+ messages in thread