--- /dev/null
+From stable-bounces@linux.kernel.org Tue Jan 17 15:27:59 2006
+Date: Tue, 17 Jan 2006 15:23:00 -0800 (PST)
+Message-Id: <20060117.152300.10006770.davem@davemloft.net>
+To: stable@kernel.org
+From: "David S. Miller" <davem@davemloft.net>
+Subject: [PATCH] Fix timekeeping on sparc64 ultra-IIe machines
+
+From: Richard Mortimer <richm@oldelvet.org.uk>
+
+[SPARC64]: Eliminate race condition reading Hummingbird STICK register
+
+Ensure a consistent value is read from the STICK register by ensuring
+that both high and low are read without high changing due to a roll
+over of the low register.
+
+Various Debian/SPARC users (myself include) have noticed problems with
+Hummingbird based systems. The symptoms are that the system time is
+seen to jump forward 3 days, 6 hours, 11 minutes give or take a few
+seconds. In many cases the system then hangs some time afterwards.
+
+I've spotted a race condition in the code to read the STICK register.
+I could not work out why 3d, 6h, 11m is important but guess that it is
+due to the 2^32 jump of STICK (forwards on one read and then the next
+read will seem to be backwards) during a timer interrupt. I'm guessing
+that a change of -2^32 will get converted to a large unsigned
+increment after the arithmetic manipulation between STICK,
+nanoseconds, jiffies etc.
+
+I did a test where I modified __hbird_read_stick to artificially
+inject rollover faults forcefully every few seconds. With this I saw
+the clock jump over 6 times in 12 hours compared to once every month
+or so.
+
+Signed-off-by: Richard Mortimer <richm@oldelvet.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+ arch/sparc64/kernel/time.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- linux-2.6.15.1.orig/arch/sparc64/kernel/time.c
++++ linux-2.6.15.1/arch/sparc64/kernel/time.c
+@@ -280,9 +280,9 @@ static struct sparc64_tick_ops stick_ope
+ * Since STICK is constantly updating, we have to access it carefully.
+ *
+ * The sequence we use to read is:
+- * 1) read low
+- * 2) read high
+- * 3) read low again, if it rolled over increment high by 1
++ * 1) read high
++ * 2) read low
++ * 3) read high again, if it rolled re-read both low and high again.
+ *
+ * Writing STICK safely is also tricky:
+ * 1) write low to zero
+@@ -295,18 +295,18 @@ static struct sparc64_tick_ops stick_ope
+ static unsigned long __hbird_read_stick(void)
+ {
+ unsigned long ret, tmp1, tmp2, tmp3;
+- unsigned long addr = HBIRD_STICK_ADDR;
++ unsigned long addr = HBIRD_STICK_ADDR+8;
+
+- __asm__ __volatile__("ldxa [%1] %5, %2\n\t"
+- "add %1, 0x8, %1\n\t"
+- "ldxa [%1] %5, %3\n\t"
++ __asm__ __volatile__("ldxa [%1] %5, %2\n"
++ "1:\n\t"
+ "sub %1, 0x8, %1\n\t"
++ "ldxa [%1] %5, %3\n\t"
++ "add %1, 0x8, %1\n\t"
+ "ldxa [%1] %5, %4\n\t"
+ "cmp %4, %2\n\t"
+- "blu,a,pn %%xcc, 1f\n\t"
+- " add %3, 1, %3\n"
+- "1:\n\t"
+- "sllx %3, 32, %3\n\t"
++ "bne,a,pn %%xcc, 1b\n\t"
++ " mov %4, %2\n\t"
++ "sllx %4, 32, %4\n\t"
+ "or %3, %4, %0\n\t"
+ : "=&r" (ret), "=&r" (addr),
+ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)