aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-10-28 02:00:41 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-28 02:00:41 -0400
commite9b9eb59ffcdee09ec96b040f85c919618f4043e (patch)
tree30f93cc20aa577ec5b12f609641fdf84d0bd5124
parent270c10e00a1e557e068803a22e0556281ceb1830 (diff)
sparc64: Use pause instruction when available.
In atomic backoff and cpu_relax(), use the pause instruction found on SPARC-T4 and later. It makes the cpu strand unselectable for the given number of cycles, unless an intervening disrupting trap occurs. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/include/asm/backoff.h32
-rw-r--r--arch/sparc/include/asm/processor_64.h13
-rw-r--r--arch/sparc/kernel/entry.h7
-rw-r--r--arch/sparc/kernel/setup_64.c21
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S5
5 files changed, 62 insertions, 16 deletions
diff --git a/arch/sparc/include/asm/backoff.h b/arch/sparc/include/asm/backoff.h
index 64b077b3b13..20f01df0871 100644
--- a/arch/sparc/include/asm/backoff.h
+++ b/arch/sparc/include/asm/backoff.h
@@ -11,19 +11,25 @@
11#define BACKOFF_LABEL(spin_label, continue_label) \ 11#define BACKOFF_LABEL(spin_label, continue_label) \
12 spin_label 12 spin_label
13 13
14#define BACKOFF_SPIN(reg, tmp, label) \ 14#define BACKOFF_SPIN(reg, tmp, label) \
15 mov reg, tmp; \ 15 mov reg, tmp; \
1688: rd %ccr, %g0; \ 1688: rd %ccr, %g0; \
17 rd %ccr, %g0; \ 17 rd %ccr, %g0; \
18 rd %ccr, %g0; \ 18 rd %ccr, %g0; \
19 brnz,pt tmp, 88b; \ 19 .section .pause_patch,"ax"; \
20 sub tmp, 1, tmp; \ 20 .word 88b; \
21 set BACKOFF_LIMIT, tmp; \ 21 sllx tmp, 7, tmp; \
22 cmp reg, tmp; \ 22 wr tmp, 0, %asr27; \
23 bg,pn %xcc, label; \ 23 clr tmp; \
24 nop; \ 24 .previous; \
25 ba,pt %xcc, label; \ 25 brnz,pt tmp, 88b; \
26 sllx reg, 1, reg; 26 sub tmp, 1, tmp; \
27 set BACKOFF_LIMIT, tmp; \
28 cmp reg, tmp; \
29 bg,pn %xcc, label; \
30 nop; \
31 ba,pt %xcc, label; \
32 sllx reg, 1, reg;
27 33
28#else 34#else
29 35
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h
index 98656340946..9cdf52eec48 100644
--- a/arch/sparc/include/asm/processor_64.h
+++ b/arch/sparc/include/asm/processor_64.h
@@ -196,9 +196,16 @@ extern unsigned long get_wchan(struct task_struct *task);
196#define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc) 196#define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc)
197#define KSTK_ESP(tsk) (task_pt_regs(tsk)->u_regs[UREG_FP]) 197#define KSTK_ESP(tsk) (task_pt_regs(tsk)->u_regs[UREG_FP])
198 198
199#define cpu_relax() asm volatile("rd %%ccr, %%g0\n\t" \ 199#define cpu_relax() asm volatile("\n99:\n\t" \
200 "rd %%ccr, %%g0\n\t" \ 200 "rd %%ccr, %%g0\n\t" \
201 "rd %%ccr, %%g0" \ 201 "rd %%ccr, %%g0\n\t" \
202 "rd %%ccr, %%g0\n\t" \
203 ".section .pause_patch,\"ax\"\n\t"\
204 ".word 99b\n\t" \
205 "wr %%g0, 128, %%asr27\n\t" \
206 "nop\n\t" \
207 "nop\n\t" \
208 ".previous" \
202 ::: "memory") 209 ::: "memory")
203 210
204/* Prefetch support. This is tuned for UltraSPARC-III and later. 211/* Prefetch support. This is tuned for UltraSPARC-III and later.
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index 0c218e4c088..51742df63c7 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -59,6 +59,13 @@ struct popc_6insn_patch_entry {
59extern struct popc_6insn_patch_entry __popc_6insn_patch, 59extern struct popc_6insn_patch_entry __popc_6insn_patch,
60 __popc_6insn_patch_end; 60 __popc_6insn_patch_end;
61 61
62struct pause_patch_entry {
63 unsigned int addr;
64 unsigned int insns[3];
65};
66extern struct pause_patch_entry __pause_patch,
67 __pause_patch_end;
68
62extern void __init per_cpu_patch(void); 69extern void __init per_cpu_patch(void);
63extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, 70extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
64 struct sun4v_1insn_patch_entry *); 71 struct sun4v_1insn_patch_entry *);
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 0800e71d8a8..b45cff408de 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -316,6 +316,25 @@ static void __init popc_patch(void)
316 } 316 }
317} 317}
318 318
319static void __init pause_patch(void)
320{
321 struct pause_patch_entry *p;
322
323 p = &__pause_patch;
324 while (p < &__pause_patch_end) {
325 unsigned long i, addr = p->addr;
326
327 for (i = 0; i < 3; i++) {
328 *(unsigned int *) (addr + (i * 4)) = p->insns[i];
329 wmb();
330 __asm__ __volatile__("flush %0"
331 : : "r" (addr + (i * 4)));
332 }
333
334 p++;
335 }
336}
337
319#ifdef CONFIG_SMP 338#ifdef CONFIG_SMP
320void __init boot_cpu_id_too_large(int cpu) 339void __init boot_cpu_id_too_large(int cpu)
321{ 340{
@@ -528,6 +547,8 @@ static void __init init_sparc64_elf_hwcap(void)
528 547
529 if (sparc64_elf_hwcap & AV_SPARC_POPC) 548 if (sparc64_elf_hwcap & AV_SPARC_POPC)
530 popc_patch(); 549 popc_patch();
550 if (sparc64_elf_hwcap & AV_SPARC_PAUSE)
551 pause_patch();
531} 552}
532 553
533void __init setup_arch(char **cmdline_p) 554void __init setup_arch(char **cmdline_p)
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 89c2c29f154..847f9f79361 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -132,6 +132,11 @@ SECTIONS
132 *(.popc_6insn_patch) 132 *(.popc_6insn_patch)
133 __popc_6insn_patch_end = .; 133 __popc_6insn_patch_end = .;
134 } 134 }
135 .pause_patch : {
136 __pause_patch = .;
137 *(.pause_patch)
138 __pause_patch_end = .;
139 }
135 PERCPU_SECTION(SMP_CACHE_BYTES) 140 PERCPU_SECTION(SMP_CACHE_BYTES)
136 141
137 . = ALIGN(PAGE_SIZE); 142 . = ALIGN(PAGE_SIZE);