summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2009-10-06 10:34:04 +0200
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-10-06 10:35:08 +0200
commit78d81f2f844b739b377817cfd279fb6067e191a7 (patch)
treef252e003e3ead8079a35167eea19f54bc4047964
parent102e835d5152e4299c1d150d6481b9bd47095998 (diff)
downloadop-kernel-dev-78d81f2f844b739b377817cfd279fb6067e191a7.zip
op-kernel-dev-78d81f2f844b739b377817cfd279fb6067e191a7.tar.gz
[S390] Fix enabled udelay for short delays.
When udelay() gets called with a delay that would expire before the next clock event it reprograms the clock comparator. When the interrupt happens the clock comparator won't be resetted therefore the interrupt condition doesn't get cleared. The result is an endless timer interrupt loop until the next clock event would expire (stored in lowcore). So udelay() usually would wait much longer for small delays than it should. Fix this by disabling the local tick which makes sure that the clock comparator will be resetted when a timer interrupt happens. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/lib/delay.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 97c1eca8..2c30943 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -49,17 +49,22 @@ static void __udelay_disabled(unsigned long usecs)
static void __udelay_enabled(unsigned long usecs)
{
unsigned long mask;
- u64 end, time;
+ u64 clock_saved;
+ u64 end;
mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO;
end = get_clock() + ((u64) usecs << 12);
do {
- time = end < S390_lowcore.clock_comparator ?
- end : S390_lowcore.clock_comparator;
- set_clock_comparator(time);
+ clock_saved = 0;
+ if (end < S390_lowcore.clock_comparator) {
+ clock_saved = local_tick_disable();
+ set_clock_comparator(end);
+ }
trace_hardirqs_on();
__load_psw_mask(mask);
local_irq_disable();
+ if (clock_saved)
+ local_tick_enable(clock_saved);
} while (get_clock() < end);
set_clock_comparator(S390_lowcore.clock_comparator);
}
OpenPOWER on IntegriCloud