aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2013-12-18 17:08:52 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-01-28 09:06:25 -0500
commitc5ca95b507c8a2a69e49eeda539b41bd76922d7f (patch)
tree2ebbc82dcd1834300ec341a351a7f48ee5e5df0e
parent668bc38669f9a6d5e91846e9435b22b196cee9d1 (diff)
ARM: 7930/1: Introduce atomic MMIO modify
Some SoC have MMIO regions that are shared across orthogonal subsystems. This commit implements a possible solution for the thread-safe access of such regions through a spinlock-protected API. Concurrent access is protected with a single spinlock for the entire MMIO address space. While this protects shared-registers, it also serializes access to unrelated/unshared registers. We add relaxed and non-relaxed variants, by using writel_relaxed and writel, respectively. The rationale for this is that some users may not require register write completion but only thread-safe access to a register. Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Acked-by: Jason Cooper <jason@lakedaemon.net> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/include/asm/io.h6
-rw-r--r--arch/arm/kernel/io.c35
2 files changed, 41 insertions, 0 deletions
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index fbeb39c869e9..8aa4cca74501 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -38,6 +38,12 @@
38#define isa_bus_to_virt phys_to_virt 38#define isa_bus_to_virt phys_to_virt
39 39
40/* 40/*
41 * Atomic MMIO-wide IO modify
42 */
43extern void atomic_io_modify(void __iomem *reg, u32 mask, u32 set);
44extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set);
45
46/*
41 * Generic IO read/write. These perform native-endian accesses. Note 47 * Generic IO read/write. These perform native-endian accesses. Note
42 * that some architectures will want to re-define __raw_{read,write}w. 48 * that some architectures will want to re-define __raw_{read,write}w.
43 */ 49 */
diff --git a/arch/arm/kernel/io.c b/arch/arm/kernel/io.c
index dcd5b4d86143..9203cf883330 100644
--- a/arch/arm/kernel/io.c
+++ b/arch/arm/kernel/io.c
@@ -1,6 +1,41 @@
1#include <linux/export.h> 1#include <linux/export.h>
2#include <linux/types.h> 2#include <linux/types.h>
3#include <linux/io.h> 3#include <linux/io.h>
4#include <linux/spinlock.h>
5
6static DEFINE_RAW_SPINLOCK(__io_lock);
7
8/*
9 * Generic atomic MMIO modify.
10 *
11 * Allows thread-safe access to registers shared by unrelated subsystems.
12 * The access is protected by a single MMIO-wide lock.
13 */
14void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
15{
16 unsigned long flags;
17 u32 value;
18
19 raw_spin_lock_irqsave(&__io_lock, flags);
20 value = readl_relaxed(reg) & ~mask;
21 value |= (set & mask);
22 writel_relaxed(value, reg);
23 raw_spin_unlock_irqrestore(&__io_lock, flags);
24}
25EXPORT_SYMBOL(atomic_io_modify_relaxed);
26
27void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
28{
29 unsigned long flags;
30 u32 value;
31
32 raw_spin_lock_irqsave(&__io_lock, flags);
33 value = readl_relaxed(reg) & ~mask;
34 value |= (set & mask);
35 writel(value, reg);
36 raw_spin_unlock_irqrestore(&__io_lock, flags);
37}
38EXPORT_SYMBOL(atomic_io_modify);
4 39
5/* 40/*
6 * Copy data from IO memory space to "real" memory space. 41 * Copy data from IO memory space to "real" memory space.