aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-02-14 04:28:06 -0500
committerPaul Burton <paul.burton@imgtec.com>2014-05-02 11:39:14 -0400
commit76ae658465c2319a63f3814b1e1e6e0664a1f542 (patch)
tree4af72b0569cbd60201131e23a9a5da161a638276
parent2ba60250b01bfbab6b2293f8c1492312eb6a4131 (diff)
MIPS: CPC: provide locking functions
This patch provides functions to lock & unlock access to the "core-other" register region of the CPC. Without performing appropriate locking it is possible for code using this region to be preempted or to race with code on another VPE within the same core, with one changing the core which the "core-other" region is acting upon at an inopportune time for the other. Signed-off-by: Paul Burton <paul.burton@imgtec.com>
-rw-r--r--arch/mips/include/asm/mips-cpc.h27
-rw-r--r--arch/mips/kernel/mips-cpc.c26
2 files changed, 53 insertions, 0 deletions
diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h
index c5bb609c4b97..e139a534e0fd 100644
--- a/arch/mips/include/asm/mips-cpc.h
+++ b/arch/mips/include/asm/mips-cpc.h
@@ -152,4 +152,31 @@ BUILD_CPC_Cx_RW(other, 0x10)
152#define CPC_Cx_OTHER_CORENUM_SHF 16 152#define CPC_Cx_OTHER_CORENUM_SHF 16
153#define CPC_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xff) << 16) 153#define CPC_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xff) << 16)
154 154
155#ifdef CONFIG_MIPS_CPC
156
157/**
158 * mips_cpc_lock_other - lock access to another core
159 * core: the other core to be accessed
160 *
161 * Call before operating upon a core via the 'other' register region in
162 * order to prevent the region being moved during access. Must be followed
163 * by a call to mips_cpc_unlock_other.
164 */
165extern void mips_cpc_lock_other(unsigned int core);
166
167/**
168 * mips_cpc_unlock_other - unlock access to another core
169 *
170 * Call after operating upon another core via the 'other' register region.
171 * Must be called after mips_cpc_lock_other.
172 */
173extern void mips_cpc_unlock_other(void);
174
175#else /* !CONFIG_MIPS_CPC */
176
177static inline void mips_cpc_lock_other(unsigned int core) { }
178static inline void mips_cpc_unlock_other(void) { }
179
180#endif /* !CONFIG_MIPS_CPC */
181
155#endif /* __MIPS_ASM_MIPS_CPC_H__ */ 182#endif /* __MIPS_ASM_MIPS_CPC_H__ */
diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c
index c9dc67402969..2368fc5ccf1e 100644
--- a/arch/mips/kernel/mips-cpc.c
+++ b/arch/mips/kernel/mips-cpc.c
@@ -15,6 +15,10 @@
15 15
16void __iomem *mips_cpc_base; 16void __iomem *mips_cpc_base;
17 17
18static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock);
19
20static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags);
21
18phys_t __weak mips_cpc_phys_base(void) 22phys_t __weak mips_cpc_phys_base(void)
19{ 23{
20 u32 cpc_base; 24 u32 cpc_base;
@@ -39,6 +43,10 @@ phys_t __weak mips_cpc_phys_base(void)
39int mips_cpc_probe(void) 43int mips_cpc_probe(void)
40{ 44{
41 phys_t addr; 45 phys_t addr;
46 unsigned cpu;
47
48 for_each_possible_cpu(cpu)
49 spin_lock_init(&per_cpu(cpc_core_lock, cpu));
42 50
43 addr = mips_cpc_phys_base(); 51 addr = mips_cpc_phys_base();
44 if (!addr) 52 if (!addr)
@@ -50,3 +58,21 @@ int mips_cpc_probe(void)
50 58
51 return 0; 59 return 0;
52} 60}
61
62void mips_cpc_lock_other(unsigned int core)
63{
64 unsigned curr_core;
65 preempt_disable();
66 curr_core = current_cpu_data.core;
67 spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core),
68 per_cpu(cpc_core_lock_flags, curr_core));
69 write_cpc_cl_other(core << CPC_Cx_OTHER_CORENUM_SHF);
70}
71
72void mips_cpc_unlock_other(void)
73{
74 unsigned curr_core = current_cpu_data.core;
75 spin_unlock_irqrestore(&per_cpu(cpc_core_lock, curr_core),
76 per_cpu(cpc_core_lock_flags, curr_core));
77 preempt_enable();
78}