Blame view
arch/s390/lib/delay.c
3 KB
1da177e4c
|
1 |
/* |
1da177e4c
|
2 3 |
* Precise Delay Loops for S390 * |
d3d238c77
|
4 5 6 |
* Copyright IBM Corp. 1999,2008 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, * Heiko Carstens <heiko.carstens@de.ibm.com>, |
1da177e4c
|
7 |
*/ |
1da177e4c
|
8 9 |
#include <linux/sched.h> #include <linux/delay.h> |
d54853ef8
|
10 |
#include <linux/timex.h> |
1485c5c88
|
11 |
#include <linux/module.h> |
d54853ef8
|
12 |
#include <linux/irqflags.h> |
bf6f6aa46
|
13 |
#include <linux/interrupt.h> |
b39663784
|
14 |
#include <asm/div64.h> |
1da177e4c
|
15 16 17 18 19 20 21 22 23 24 |
void __delay(unsigned long loops) { /* * To end the bloody studid and useless discussion about the * BogoMips number I took the liberty to define the __delay * function in a way that that resulting BogoMips number will * yield the megahertz number of the cpu. The important function * is udelay and that is done using the tod clock. -- martin. */ |
94c12cc7d
|
25 |
asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1)); |
1da177e4c
|
26 |
} |
0cd6a403e
|
27 |
static void __udelay_disabled(unsigned long long usecs) |
1da177e4c
|
28 |
{ |
d3d238c77
|
29 30 |
unsigned long mask, cr0, cr0_saved; u64 clock_saved; |
e8129c642
|
31 |
u64 end; |
d54853ef8
|
32 |
|
b50511e41
|
33 34 |
mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_MCHECK; |
e8129c642
|
35 |
end = get_clock() + (usecs << 12); |
d3d238c77
|
36 |
clock_saved = local_tick_disable(); |
d3d238c77
|
37 38 39 |
__ctl_store(cr0_saved, 0, 0); cr0 = (cr0_saved & 0xffff00e0) | 0x00000800; __ctl_load(cr0 , 0, 0); |
bb8c29caf
|
40 |
lockdep_off(); |
e8129c642
|
41 42 43 44 45 46 |
do { set_clock_comparator(end); trace_hardirqs_on(); __load_psw_mask(mask); local_irq_disable(); } while (get_clock() < end); |
bb8c29caf
|
47 |
lockdep_on(); |
d3d238c77
|
48 49 |
__ctl_load(cr0_saved, 0, 0); local_tick_enable(clock_saved); |
d3d238c77
|
50 |
} |
d54853ef8
|
51 |
|
0cd6a403e
|
52 |
static void __udelay_enabled(unsigned long long usecs) |
d3d238c77
|
53 54 |
{ unsigned long mask; |
78d81f2f8
|
55 56 |
u64 clock_saved; u64 end; |
d3d238c77
|
57 58 |
mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO; |
0cd6a403e
|
59 |
end = get_clock() + (usecs << 12); |
d54853ef8
|
60 |
do { |
78d81f2f8
|
61 62 63 64 65 |
clock_saved = 0; if (end < S390_lowcore.clock_comparator) { clock_saved = local_tick_disable(); set_clock_comparator(end); } |
d54853ef8
|
66 67 68 |
trace_hardirqs_on(); __load_psw_mask(mask); local_irq_disable(); |
78d81f2f8
|
69 70 |
if (clock_saved) local_tick_enable(clock_saved); |
d54853ef8
|
71 |
} while (get_clock() < end); |
d3d238c77
|
72 |
} |
1da177e4c
|
73 |
|
d3d238c77
|
74 75 76 |
/* * Waits for 'usecs' microseconds using the TOD clock comparator. */ |
0cd6a403e
|
77 |
void __udelay(unsigned long long usecs) |
d3d238c77
|
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
{ unsigned long flags; preempt_disable(); local_irq_save(flags); if (in_irq()) { __udelay_disabled(usecs); goto out; } if (in_softirq()) { if (raw_irqs_disabled_flags(flags)) __udelay_disabled(usecs); else __udelay_enabled(usecs); goto out; |
d54853ef8
|
93 |
} |
d3d238c77
|
94 95 96 |
if (raw_irqs_disabled_flags(flags)) { local_bh_disable(); __udelay_disabled(usecs); |
bf6f6aa46
|
97 |
_local_bh_enable(); |
d3d238c77
|
98 99 100 101 |
goto out; } __udelay_enabled(usecs); out: |
d54853ef8
|
102 |
local_irq_restore(flags); |
d3d238c77
|
103 |
preempt_enable(); |
1da177e4c
|
104 |
} |
1485c5c88
|
105 |
EXPORT_SYMBOL(__udelay); |
5a0d0e653
|
106 107 108 109 110 |
/* * Simple udelay variant. To be used on startup and reboot * when the interrupt handler isn't working. */ |
0cd6a403e
|
111 |
void udelay_simple(unsigned long long usecs) |
5a0d0e653
|
112 113 |
{ u64 end; |
0cd6a403e
|
114 |
end = get_clock() + (usecs << 12); |
5a0d0e653
|
115 116 117 |
while (get_clock() < end) cpu_relax(); } |
b39663784
|
118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
void __ndelay(unsigned long long nsecs) { u64 end; nsecs <<= 9; do_div(nsecs, 125); end = get_clock() + nsecs; if (nsecs & ~0xfffUL) __udelay(nsecs >> 12); while (get_clock() < end) barrier(); } EXPORT_SYMBOL(__ndelay); |