2005-04-16 15:20:36 -07:00
/*
2007-02-05 21:18:19 +01:00
* arch / s390 / lib / delay . c
2005-04-16 15:20:36 -07:00
* Precise Delay Loops for S390
*
* S390 version
* Copyright ( C ) 1999 IBM Deutschland Entwicklung GmbH , IBM Corporation
* Author ( s ) : Martin Schwidefsky ( schwidefsky @ de . ibm . com ) ,
*
* Derived from " arch/i386/lib/delay.c "
* Copyright ( C ) 1993 Linus Torvalds
* Copyright ( C ) 1997 Martin Mares < mj @ atrey . karlin . mff . cuni . cz >
*/
# include <linux/sched.h>
# include <linux/delay.h>
2007-02-05 21:18:19 +01:00
# include <linux/timex.h>
# include <linux/irqflags.h>
2007-02-21 10:55:00 +01:00
# include <linux/interrupt.h>
2005-04-16 15:20:36 -07:00
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 .
*/
2006-09-28 16:56:43 +02:00
asm volatile ( " 0: brct %0,0b " : : " d " ( ( loops / 2 ) + 1 ) ) ;
2005-04-16 15:20:36 -07:00
}
/*
2007-02-05 21:18:19 +01:00
* Waits for ' usecs ' microseconds using the TOD clock comparator .
2005-04-16 15:20:36 -07:00
*/
void __udelay ( unsigned long usecs )
{
2007-02-05 21:18:19 +01:00
u64 end , time , jiffy_timer = 0 ;
unsigned long flags , cr0 , mask , dummy ;
2007-02-21 10:55:00 +01:00
int irq_context ;
2007-02-05 21:18:19 +01:00
2007-02-21 10:55:00 +01:00
irq_context = in_interrupt ( ) ;
if ( ! irq_context )
local_bh_disable ( ) ;
2007-02-05 21:18:19 +01:00
local_irq_save ( flags ) ;
if ( raw_irqs_disabled_flags ( flags ) ) {
jiffy_timer = S390_lowcore . jiffy_timer ;
S390_lowcore . jiffy_timer = - 1ULL - ( 4096 < < 12 ) ;
__ctl_store ( cr0 , 0 , 0 ) ;
dummy = ( cr0 & 0xffff00e0 ) | 0x00000800 ;
__ctl_load ( dummy , 0 , 0 ) ;
mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT ;
} else
mask = psw_kernel_bits | PSW_MASK_WAIT |
PSW_MASK_EXT | PSW_MASK_IO ;
end = get_clock ( ) + ( ( u64 ) usecs < < 12 ) ;
do {
time = end < S390_lowcore . jiffy_timer ?
end : S390_lowcore . jiffy_timer ;
set_clock_comparator ( time ) ;
trace_hardirqs_on ( ) ;
__load_psw_mask ( mask ) ;
local_irq_disable ( ) ;
} while ( get_clock ( ) < end ) ;
2005-04-16 15:20:36 -07:00
2007-02-05 21:18:19 +01:00
if ( raw_irqs_disabled_flags ( flags ) ) {
__ctl_load ( cr0 , 0 , 0 ) ;
S390_lowcore . jiffy_timer = jiffy_timer ;
}
2007-02-21 10:55:00 +01:00
if ( ! irq_context )
_local_bh_enable ( ) ;
2007-02-05 21:18:19 +01:00
set_clock_comparator ( S390_lowcore . jiffy_timer ) ;
local_irq_restore ( flags ) ;
2005-04-16 15:20:36 -07:00
}