[IA64] disable preemption in udelay()
authorJohn Hawkes <hawkes@sgi.com>
Fri, 16 Dec 2005 18:00:24 +0000 (10:00 -0800)
committerTony Luck <tony.luck@intel.com>
Fri, 16 Dec 2005 18:00:24 +0000 (10:00 -0800)
The udelay() inline for ia64 uses the ITC.  If CONFIG_PREEMPT is enabled
and the platform has unsynchronized ITCs and the calling task migrates
to another CPU while doing the udelay loop, then the effective delay may
be too short or very, very long.

This patch disables preemption around 100 usec chunks of the overall
desired udelay time.  This minimizes preemption-holdoffs.

udelay() is now too big to be inline, move it out of line and export it.

Signed-off-by: John Hawkes <hawkes@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
arch/ia64/kernel/time.c
include/asm-ia64/delay.h

index 5b7e736f3b4924beb5e779a92b3c93a7f2a606f2..028a2b95936c1fa48ca316921c65b1023b9e1585 100644 (file)
@@ -249,3 +249,32 @@ time_init (void)
         */
        set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
 }
+
+#define SMALLUSECS 100
+
+void
+udelay (unsigned long usecs)
+{
+       unsigned long start;
+       unsigned long cycles;
+       unsigned long smallusecs;
+
+       /*
+        * Execute the non-preemptible delay loop (because the ITC might
+        * not be synchronized between CPUS) in relatively short time
+        * chunks, allowing preemption between the chunks.
+        */
+       while (usecs > 0) {
+               smallusecs = (usecs > SMALLUSECS) ? SMALLUSECS : usecs;
+               preempt_disable();
+               cycles = smallusecs*local_cpu_data->cyc_per_usec;
+               start = ia64_get_itc();
+
+               while (ia64_get_itc() - start < cycles)
+                       cpu_relax();
+
+               preempt_enable();
+               usecs -= smallusecs;
+       }
+}
+EXPORT_SYMBOL(udelay);
index 57182d6f2b9a10c3f3f9f288d1e6f4613a9121bd..bba70207639103caaa05d0a0815b90d6eb4d3fa2 100644 (file)
@@ -84,14 +84,6 @@ __delay (unsigned long loops)
        ia64_delay_loop (loops - 1);
 }
 
-static __inline__ void
-udelay (unsigned long usecs)
-{
-       unsigned long start = ia64_get_itc();
-       unsigned long cycles = usecs*local_cpu_data->cyc_per_usec;
-
-       while (ia64_get_itc() - start < cycles)
-               cpu_relax();
-}
+extern void udelay (unsigned long usecs);
 
 #endif /* _ASM_IA64_DELAY_H */