diff options
Diffstat (limited to 'arch/s390/lib/delay.c')
| -rw-r--r-- | arch/s390/lib/delay.c | 63 | 
1 files changed, 38 insertions, 25 deletions
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 752b362bf65..a9f3d0042d5 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -1,7 +1,7 @@  /*   *    Precise Delay Loops for S390   * - *    Copyright IBM Corp. 1999,2008 + *    Copyright IBM Corp. 1999, 2008   *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,   *		 Heiko Carstens <heiko.carstens@de.ibm.com>,   */ @@ -12,6 +12,8 @@  #include <linux/module.h>  #include <linux/irqflags.h>  #include <linux/interrupt.h> +#include <asm/vtimer.h> +#include <asm/div64.h>  void __delay(unsigned long loops)  { @@ -27,46 +29,43 @@ void __delay(unsigned long loops)  static void __udelay_disabled(unsigned long long usecs)  { -	unsigned long mask, cr0, cr0_saved; -	u64 clock_saved; +	unsigned long cr0, cr6, new; +	u64 clock_saved, end; +	end = get_tod_clock() + (usecs << 12);  	clock_saved = local_tick_disable(); -	set_clock_comparator(get_clock() + (usecs << 12)); -	__ctl_store(cr0_saved, 0, 0); -	cr0 = (cr0_saved & 0xffff00e0) | 0x00000800; -	__ctl_load(cr0 , 0, 0); -	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; +	__ctl_store(cr0, 0, 0); +	__ctl_store(cr6, 6, 6); +	new = (cr0 &  0xffff00e0) | 0x00000800; +	__ctl_load(new , 0, 0); +	new = 0; +	__ctl_load(new, 6, 6);  	lockdep_off(); -	trace_hardirqs_on(); -	__load_psw_mask(mask); -	local_irq_disable(); +	do { +		set_clock_comparator(end); +		vtime_stop_cpu(); +	} while (get_tod_clock_fast() < end);  	lockdep_on(); -	__ctl_load(cr0_saved, 0, 0); +	__ctl_load(cr0, 0, 0); +	__ctl_load(cr6, 6, 6);  	local_tick_enable(clock_saved); -	set_clock_comparator(S390_lowcore.clock_comparator);  }  static void __udelay_enabled(unsigned long long usecs)  { -	unsigned long mask; -	u64 clock_saved; -	u64 end; +	u64 clock_saved, end; -	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO; -	end = get_clock() + (usecs << 12); +	end = get_tod_clock_fast() + (usecs << 12);  	do {  		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(); +		vtime_stop_cpu();  		if (clock_saved)  			local_tick_enable(clock_saved); -	} while (get_clock() < end); -	set_clock_comparator(S390_lowcore.clock_comparator); +	} while (get_tod_clock_fast() < end);  }  /* @@ -110,7 +109,21 @@ void udelay_simple(unsigned long long usecs)  {  	u64 end; -	end = get_clock() + (usecs << 12); -	while (get_clock() < end) +	end = get_tod_clock_fast() + (usecs << 12); +	while (get_tod_clock_fast() < end)  		cpu_relax();  } + +void __ndelay(unsigned long long nsecs) +{ +	u64 end; + +	nsecs <<= 9; +	do_div(nsecs, 125); +	end = get_tod_clock_fast() + nsecs; +	if (nsecs & ~0xfffUL) +		__udelay(nsecs >> 12); +	while (get_tod_clock_fast() < end) +		barrier(); +} +EXPORT_SYMBOL(__ndelay);  | 
