Skip to content

Commit

Permalink
[IA64] disable preemption in udelay()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
John Hawkes authored and aegl committed Dec 16, 2005
1 parent 7b66665 commit f5899b5
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
29 changes: 29 additions & 0 deletions arch/ia64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
10 changes: 1 addition & 9 deletions include/asm-ia64/delay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit f5899b5

Please sign in to comment.