aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-10-20 00:37:05 -0400
committerPaul Mackerras <paulus@samba.org>2006-10-24 21:54:18 -0400
commit859deea949c382d9ccb6397fe33df3703ecef45d (patch)
treeb0fe2d7a814143f3ff61a73a0727522a1a3dd6e4 /include
parent21c4ff80cba5e24932f3ef79c8482c0491630b2b (diff)
[POWERPC] Cell timebase bug workaround
The Cell CPU timebase has an erratum. When reading the entire 64 bits of the timebase with one mftb instruction, there is a handful of cycles window during which one might read a value with the low order 32 bits already reset to 0x00000000 but the high order bits not yet incremeted by one. This fixes it by reading the timebase again until the low order 32 bits is no longer 0. That might introduce occasional latencies if hitting mftb just at the wrong time, but no more than 70ns on a cell blade, and that was considered acceptable. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Olof Johansson <olof@lixom.net> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include')
-rw-r--r--include/asm-powerpc/cputable.h3
-rw-r--r--include/asm-powerpc/ppc_asm.h18
-rw-r--r--include/asm-powerpc/reg.h25
-rw-r--r--include/asm-powerpc/time.h27
-rw-r--r--include/asm-powerpc/timex.h12
5 files changed, 62 insertions, 23 deletions
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index 02e52d68cbbe..a9a40149a7c0 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -147,6 +147,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
147#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000) 147#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
148#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000) 148#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
149#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000) 149#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
150#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
150 151
151#ifndef __ASSEMBLY__ 152#ifndef __ASSEMBLY__
152 153
@@ -335,7 +336,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
335#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ 336#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
336 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ 337 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
337 CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ 338 CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
338 CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE) 339 CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
339#define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ 340#define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
340 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ 341 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
341 CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \ 342 CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h
index a940cfe040da..fa083d8e4663 100644
--- a/include/asm-powerpc/ppc_asm.h
+++ b/include/asm-powerpc/ppc_asm.h
@@ -30,9 +30,9 @@ BEGIN_FTR_SECTION; \
30 mfspr ra,SPRN_PURR; /* get processor util. reg */ \ 30 mfspr ra,SPRN_PURR; /* get processor util. reg */ \
31END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 31END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
32BEGIN_FTR_SECTION; \ 32BEGIN_FTR_SECTION; \
33 mftb ra; /* or get TB if no PURR */ \ 33 MFTB(ra); /* or get TB if no PURR */ \
34END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \ 34END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
35 ld rb,PACA_STARTPURR(r13); \ 35 ld rb,PACA_STARTPURR(r13); \
36 std ra,PACA_STARTPURR(r13); \ 36 std ra,PACA_STARTPURR(r13); \
37 subf rb,rb,ra; /* subtract start value */ \ 37 subf rb,rb,ra; /* subtract start value */ \
38 ld ra,PACA_USER_TIME(r13); \ 38 ld ra,PACA_USER_TIME(r13); \
@@ -45,9 +45,9 @@ BEGIN_FTR_SECTION; \
45 mfspr ra,SPRN_PURR; /* get processor util. reg */ \ 45 mfspr ra,SPRN_PURR; /* get processor util. reg */ \
46END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ 46END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
47BEGIN_FTR_SECTION; \ 47BEGIN_FTR_SECTION; \
48 mftb ra; /* or get TB if no PURR */ \ 48 MFTB(ra); /* or get TB if no PURR */ \
49END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \ 49END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
50 ld rb,PACA_STARTPURR(r13); \ 50 ld rb,PACA_STARTPURR(r13); \
51 std ra,PACA_STARTPURR(r13); \ 51 std ra,PACA_STARTPURR(r13); \
52 subf rb,rb,ra; /* subtract start value */ \ 52 subf rb,rb,ra; /* subtract start value */ \
53 ld ra,PACA_SYSTEM_TIME(r13); \ 53 ld ra,PACA_SYSTEM_TIME(r13); \
@@ -274,6 +274,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
274#define ISYNC_601 274#define ISYNC_601
275#endif 275#endif
276 276
277#ifdef CONFIG_PPC_CELL
278#define MFTB(dest) \
27990: mftb dest; \
280BEGIN_FTR_SECTION_NESTED(96); \
281 cmpwi dest,0; \
282 beq- 90b; \
283END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
284#else
285#define MFTB(dest) mftb dest
286#endif
277 287
278#ifndef CONFIG_SMP 288#ifndef CONFIG_SMP
279#define TLBSYNC 289#define TLBSYNC
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index fde5c804eccb..6faae7b14d55 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -619,10 +619,35 @@
619 : "=r" (rval)); rval;}) 619 : "=r" (rval)); rval;})
620#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)) 620#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
621 621
622#ifdef __powerpc64__
623#ifdef CONFIG_PPC_CELL
624#define mftb() ({unsigned long rval; \
625 asm volatile( \
626 "90: mftb %0;\n" \
627 "97: cmpwi %0,0;\n" \
628 " beq- 90b;\n" \
629 "99:\n" \
630 ".section __ftr_fixup,\"a\"\n" \
631 ".align 3\n" \
632 "98:\n" \
633 " .llong %1\n" \
634 " .llong %1\n" \
635 " .llong 97b-98b\n" \
636 " .llong 99b-98b\n" \
637 ".previous" \
638 : "=r" (rval) : "i" (CPU_FTR_CELL_TB_BUG)); rval;})
639#else
622#define mftb() ({unsigned long rval; \ 640#define mftb() ({unsigned long rval; \
623 asm volatile("mftb %0" : "=r" (rval)); rval;}) 641 asm volatile("mftb %0" : "=r" (rval)); rval;})
642#endif /* !CONFIG_PPC_CELL */
643
644#else /* __powerpc64__ */
645
624#define mftbl() ({unsigned long rval; \ 646#define mftbl() ({unsigned long rval; \
625 asm volatile("mftbl %0" : "=r" (rval)); rval;}) 647 asm volatile("mftbl %0" : "=r" (rval)); rval;})
648#define mftbu() ({unsigned long rval; \
649 asm volatile("mftbu %0" : "=r" (rval)); rval;})
650#endif /* !__powerpc64__ */
626 651
627#define mttbl(v) asm volatile("mttbl %0":: "r"(v)) 652#define mttbl(v) asm volatile("mttbl %0":: "r"(v))
628#define mttbu(v) asm volatile("mttbu %0":: "r"(v)) 653#define mttbu(v) asm volatile("mttbu %0":: "r"(v))
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index b051d4c88c3b..a78285010d62 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -82,30 +82,35 @@ struct div_result {
82#define __USE_RTC() 0 82#define __USE_RTC() 0
83#endif 83#endif
84 84
85/* On ppc64 this gets us the whole timebase; on ppc32 just the lower half */ 85#ifdef CONFIG_PPC64
86
87/* For compatibility, get_tbl() is defined as get_tb() on ppc64 */
88#define get_tbl get_tb
89
90#else
91
86static inline unsigned long get_tbl(void) 92static inline unsigned long get_tbl(void)
87{ 93{
88 unsigned long tbl;
89
90#if defined(CONFIG_403GCX) 94#if defined(CONFIG_403GCX)
95 unsigned long tbl;
91 asm volatile("mfspr %0, 0x3dd" : "=r" (tbl)); 96 asm volatile("mfspr %0, 0x3dd" : "=r" (tbl));
97 return tbl;
92#else 98#else
93 asm volatile("mftb %0" : "=r" (tbl)); 99 return mftbl();
94#endif 100#endif
95 return tbl;
96} 101}
97 102
98static inline unsigned int get_tbu(void) 103static inline unsigned int get_tbu(void)
99{ 104{
105#ifdef CONFIG_403GCX
100 unsigned int tbu; 106 unsigned int tbu;
101
102#if defined(CONFIG_403GCX)
103 asm volatile("mfspr %0, 0x3dc" : "=r" (tbu)); 107 asm volatile("mfspr %0, 0x3dc" : "=r" (tbu));
108 return tbu;
104#else 109#else
105 asm volatile("mftbu %0" : "=r" (tbu)); 110 return mftbu();
106#endif 111#endif
107 return tbu;
108} 112}
113#endif /* !CONFIG_PPC64 */
109 114
110static inline unsigned int get_rtcl(void) 115static inline unsigned int get_rtcl(void)
111{ 116{
@@ -131,7 +136,7 @@ static inline u64 get_tb(void)
131{ 136{
132 return mftb(); 137 return mftb();
133} 138}
134#else 139#else /* CONFIG_PPC64 */
135static inline u64 get_tb(void) 140static inline u64 get_tb(void)
136{ 141{
137 unsigned int tbhi, tblo, tbhi2; 142 unsigned int tbhi, tblo, tbhi2;
@@ -144,7 +149,7 @@ static inline u64 get_tb(void)
144 149
145 return ((u64)tbhi << 32) | tblo; 150 return ((u64)tbhi << 32) | tblo;
146} 151}
147#endif 152#endif /* !CONFIG_PPC64 */
148 153
149static inline void set_tb(unsigned int upper, unsigned int lower) 154static inline void set_tb(unsigned int upper, unsigned int lower)
150{ 155{
diff --git a/include/asm-powerpc/timex.h b/include/asm-powerpc/timex.h
index e3f08cf91486..92dedde761d1 100644
--- a/include/asm-powerpc/timex.h
+++ b/include/asm-powerpc/timex.h
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include <asm/cputable.h> 10#include <asm/cputable.h>
11#include <asm/reg.h>
11 12
12#define CLOCK_TICK_RATE 1024000 /* Underlying HZ */ 13#define CLOCK_TICK_RATE 1024000 /* Underlying HZ */
13 14
@@ -15,13 +16,11 @@ typedef unsigned long cycles_t;
15 16
16static inline cycles_t get_cycles(void) 17static inline cycles_t get_cycles(void)
17{ 18{
18 cycles_t ret;
19
20#ifdef __powerpc64__ 19#ifdef __powerpc64__
21 20 return mftb();
22 __asm__ __volatile__("mftb %0" : "=r" (ret) : );
23
24#else 21#else
22 cycles_t ret;
23
25 /* 24 /*
26 * For the "cycle" counter we use the timebase lower half. 25 * For the "cycle" counter we use the timebase lower half.
27 * Currently only used on SMP. 26 * Currently only used on SMP.
@@ -41,9 +40,8 @@ static inline cycles_t get_cycles(void)
41 " .long 99b-98b\n" 40 " .long 99b-98b\n"
42 ".previous" 41 ".previous"
43 : "=r" (ret) : "i" (CPU_FTR_601)); 42 : "=r" (ret) : "i" (CPU_FTR_601));
44#endif
45
46 return ret; 43 return ret;
44#endif
47} 45}
48 46
49#endif /* __KERNEL__ */ 47#endif /* __KERNEL__ */