2005-07-27 22:44:57 +04:00
/*
* arch / s390 / lib / spinlock . c
* Out of line spinlock code .
*
2006-03-10 04:33:49 +03:00
* Copyright ( C ) IBM Corp . 2004 , 2006
2005-07-27 22:44:57 +04:00
* Author ( s ) : Martin Schwidefsky ( schwidefsky @ de . ibm . com )
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/init.h>
# include <asm/io.h>
int spin_retry = 1000 ;
/**
* spin_retry = parameter
*/
static int __init spin_retry_setup ( char * str )
{
spin_retry = simple_strtoul ( str , & str , 0 ) ;
return 1 ;
}
__setup ( " spin_retry= " , spin_retry_setup ) ;
2006-10-01 10:27:45 +04:00
static inline void _raw_yield ( void )
2005-07-27 22:44:57 +04:00
{
if ( MACHINE_HAS_DIAG44 )
asm volatile ( " diag 0,0,0x44 " ) ;
}
2006-10-01 10:27:45 +04:00
static inline void _raw_yield_cpu ( int cpu )
{
if ( MACHINE_HAS_DIAG9C )
asm volatile ( " diag %0,0,0x9c "
: : " d " ( __cpu_logical_map [ cpu ] ) ) ;
else
_raw_yield ( ) ;
}
2008-01-26 16:11:03 +03:00
void _raw_spin_lock_wait ( raw_spinlock_t * lp )
2005-07-27 22:44:57 +04:00
{
int count = spin_retry ;
2006-10-01 10:27:45 +04:00
unsigned int cpu = ~ smp_processor_id ( ) ;
2005-07-27 22:44:57 +04:00
while ( 1 ) {
if ( count - - < = 0 ) {
2006-10-01 10:27:45 +04:00
unsigned int owner = lp - > owner_cpu ;
if ( owner ! = 0 )
_raw_yield_cpu ( ~ owner ) ;
2005-07-27 22:44:57 +04:00
count = spin_retry ;
}
2006-03-10 04:33:49 +03:00
if ( __raw_spin_is_locked ( lp ) )
continue ;
2008-01-26 16:11:03 +03:00
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
2005-07-27 22:44:57 +04:00
return ;
}
}
EXPORT_SYMBOL ( _raw_spin_lock_wait ) ;
2008-01-26 16:11:28 +03:00
void _raw_spin_lock_wait_flags ( raw_spinlock_t * lp , unsigned long flags )
{
int count = spin_retry ;
unsigned int cpu = ~ smp_processor_id ( ) ;
local_irq_restore ( flags ) ;
while ( 1 ) {
if ( count - - < = 0 ) {
unsigned int owner = lp - > owner_cpu ;
if ( owner ! = 0 )
_raw_yield_cpu ( ~ owner ) ;
count = spin_retry ;
}
if ( __raw_spin_is_locked ( lp ) )
continue ;
local_irq_disable ( ) ;
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
return ;
local_irq_restore ( flags ) ;
}
}
EXPORT_SYMBOL ( _raw_spin_lock_wait_flags ) ;
2008-01-26 16:11:03 +03:00
int _raw_spin_trylock_retry ( raw_spinlock_t * lp )
2005-07-27 22:44:57 +04:00
{
2006-10-01 10:27:45 +04:00
unsigned int cpu = ~ smp_processor_id ( ) ;
int count ;
2005-07-27 22:44:57 +04:00
2006-10-01 10:27:45 +04:00
for ( count = spin_retry ; count > 0 ; count - - ) {
2006-03-10 04:33:49 +03:00
if ( __raw_spin_is_locked ( lp ) )
continue ;
2008-01-26 16:11:03 +03:00
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
2005-07-27 22:44:57 +04:00
return 1 ;
}
return 0 ;
}
EXPORT_SYMBOL ( _raw_spin_trylock_retry ) ;
2006-10-01 10:27:45 +04:00
void _raw_spin_relax ( raw_spinlock_t * lock )
{
unsigned int cpu = lock - > owner_cpu ;
if ( cpu ! = 0 )
_raw_yield_cpu ( ~ cpu ) ;
}
EXPORT_SYMBOL ( _raw_spin_relax ) ;
void _raw_read_lock_wait ( raw_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
unsigned int old ;
int count = spin_retry ;
while ( 1 ) {
if ( count - - < = 0 ) {
2006-10-01 10:27:45 +04:00
_raw_yield ( ) ;
2005-07-27 22:44:57 +04:00
count = spin_retry ;
}
2006-03-10 04:33:49 +03:00
if ( ! __raw_read_can_lock ( rw ) )
continue ;
2005-07-27 22:44:57 +04:00
old = rw - > lock & 0x7fffffffU ;
if ( _raw_compare_and_swap ( & rw - > lock , old , old + 1 ) = = old )
return ;
}
}
EXPORT_SYMBOL ( _raw_read_lock_wait ) ;
2006-10-01 10:27:45 +04:00
int _raw_read_trylock_retry ( raw_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
unsigned int old ;
int count = spin_retry ;
while ( count - - > 0 ) {
2006-03-10 04:33:49 +03:00
if ( ! __raw_read_can_lock ( rw ) )
continue ;
2005-07-27 22:44:57 +04:00
old = rw - > lock & 0x7fffffffU ;
if ( _raw_compare_and_swap ( & rw - > lock , old , old + 1 ) = = old )
return 1 ;
}
return 0 ;
}
EXPORT_SYMBOL ( _raw_read_trylock_retry ) ;
2006-10-01 10:27:45 +04:00
void _raw_write_lock_wait ( raw_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
int count = spin_retry ;
while ( 1 ) {
if ( count - - < = 0 ) {
2006-10-01 10:27:45 +04:00
_raw_yield ( ) ;
2005-07-27 22:44:57 +04:00
count = spin_retry ;
}
2006-03-10 04:33:49 +03:00
if ( ! __raw_write_can_lock ( rw ) )
continue ;
2005-07-27 22:44:57 +04:00
if ( _raw_compare_and_swap ( & rw - > lock , 0 , 0x80000000 ) = = 0 )
return ;
}
}
EXPORT_SYMBOL ( _raw_write_lock_wait ) ;
2006-10-01 10:27:45 +04:00
int _raw_write_trylock_retry ( raw_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
int count = spin_retry ;
while ( count - - > 0 ) {
2006-03-10 04:33:49 +03:00
if ( ! __raw_write_can_lock ( rw ) )
continue ;
2005-07-27 22:44:57 +04:00
if ( _raw_compare_and_swap ( & rw - > lock , 0 , 0x80000000 ) = = 0 )
return 1 ;
}
return 0 ;
}
EXPORT_SYMBOL ( _raw_write_trylock_retry ) ;