2005-07-27 11:44:57 -07:00
/*
* arch / s390 / lib / spinlock . c
* Out of line spinlock code .
*
2006-03-09 17:33:49 -08:00
* Copyright ( C ) IBM Corp . 2004 , 2006
2005-07-27 11:44:57 -07: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-09-30 23:27:45 -07:00
static inline void _raw_yield ( void )
2005-07-27 11:44:57 -07:00
{
if ( MACHINE_HAS_DIAG44 )
asm volatile ( " diag 0,0,0x44 " ) ;
}
2006-09-30 23:27:45 -07:00
static inline void _raw_yield_cpu ( int cpu )
{
if ( MACHINE_HAS_DIAG9C )
asm volatile ( " diag %0,0,0x9c "
2010-01-13 20:44:37 +01:00
: : " d " ( cpu_logical_map ( cpu ) ) ) ;
2006-09-30 23:27:45 -07:00
else
_raw_yield ( ) ;
}
2009-12-02 20:01:25 +01:00
void arch_spin_lock_wait ( arch_spinlock_t * lp )
2005-07-27 11:44:57 -07:00
{
int count = spin_retry ;
2006-09-30 23:27:45 -07:00
unsigned int cpu = ~ smp_processor_id ( ) ;
2005-07-27 11:44:57 -07:00
while ( 1 ) {
if ( count - - < = 0 ) {
2006-09-30 23:27:45 -07:00
unsigned int owner = lp - > owner_cpu ;
if ( owner ! = 0 )
_raw_yield_cpu ( ~ owner ) ;
2005-07-27 11:44:57 -07:00
count = spin_retry ;
}
2009-12-02 20:01:25 +01:00
if ( arch_spin_is_locked ( lp ) )
2006-03-09 17:33:49 -08:00
continue ;
2008-01-26 14:11:03 +01:00
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
2005-07-27 11:44:57 -07:00
return ;
}
}
2009-12-02 20:01:25 +01:00
EXPORT_SYMBOL ( arch_spin_lock_wait ) ;
2005-07-27 11:44:57 -07:00
2009-12-02 20:01:25 +01:00
void arch_spin_lock_wait_flags ( arch_spinlock_t * lp , unsigned long flags )
2008-01-26 14:11:28 +01:00
{
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 ;
}
2009-12-02 20:01:25 +01:00
if ( arch_spin_is_locked ( lp ) )
2008-01-26 14:11:28 +01:00
continue ;
local_irq_disable ( ) ;
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
return ;
local_irq_restore ( flags ) ;
}
}
2009-12-02 20:01:25 +01:00
EXPORT_SYMBOL ( arch_spin_lock_wait_flags ) ;
2008-01-26 14:11:28 +01:00
2009-12-02 20:01:25 +01:00
int arch_spin_trylock_retry ( arch_spinlock_t * lp )
2005-07-27 11:44:57 -07:00
{
2006-09-30 23:27:45 -07:00
unsigned int cpu = ~ smp_processor_id ( ) ;
int count ;
2005-07-27 11:44:57 -07:00
2006-09-30 23:27:45 -07:00
for ( count = spin_retry ; count > 0 ; count - - ) {
2009-12-02 20:01:25 +01:00
if ( arch_spin_is_locked ( lp ) )
2006-03-09 17:33:49 -08:00
continue ;
2008-01-26 14:11:03 +01:00
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
2005-07-27 11:44:57 -07:00
return 1 ;
}
return 0 ;
}
2009-12-02 20:01:25 +01:00
EXPORT_SYMBOL ( arch_spin_trylock_retry ) ;
2005-07-27 11:44:57 -07:00
2009-12-02 20:01:25 +01:00
void arch_spin_relax ( arch_spinlock_t * lock )
2006-09-30 23:27:45 -07:00
{
unsigned int cpu = lock - > owner_cpu ;
if ( cpu ! = 0 )
_raw_yield_cpu ( ~ cpu ) ;
}
2009-12-02 20:01:25 +01:00
EXPORT_SYMBOL ( arch_spin_relax ) ;
2006-09-30 23:27:45 -07:00
2009-12-03 20:01:19 +01:00
void _raw_read_lock_wait ( arch_rwlock_t * rw )
2005-07-27 11:44:57 -07:00
{
unsigned int old ;
int count = spin_retry ;
while ( 1 ) {
if ( count - - < = 0 ) {
2006-09-30 23:27:45 -07:00
_raw_yield ( ) ;
2005-07-27 11:44:57 -07:00
count = spin_retry ;
}
2009-12-03 20:08:46 +01:00
if ( ! arch_read_can_lock ( rw ) )
2006-03-09 17:33:49 -08:00
continue ;
2005-07-27 11:44:57 -07:00
old = rw - > lock & 0x7fffffffU ;
if ( _raw_compare_and_swap ( & rw - > lock , old , old + 1 ) = = old )
return ;
}
}
EXPORT_SYMBOL ( _raw_read_lock_wait ) ;
2009-12-03 20:01:19 +01:00
void _raw_read_lock_wait_flags ( arch_rwlock_t * rw , unsigned long flags )
2009-06-12 10:26:22 +02:00
{
unsigned int old ;
int count = spin_retry ;
local_irq_restore ( flags ) ;
while ( 1 ) {
if ( count - - < = 0 ) {
_raw_yield ( ) ;
count = spin_retry ;
}
2009-12-03 20:08:46 +01:00
if ( ! arch_read_can_lock ( rw ) )
2009-06-12 10:26:22 +02:00
continue ;
old = rw - > lock & 0x7fffffffU ;
local_irq_disable ( ) ;
if ( _raw_compare_and_swap ( & rw - > lock , old , old + 1 ) = = old )
return ;
}
}
EXPORT_SYMBOL ( _raw_read_lock_wait_flags ) ;
2009-12-03 20:01:19 +01:00
int _raw_read_trylock_retry ( arch_rwlock_t * rw )
2005-07-27 11:44:57 -07:00
{
unsigned int old ;
int count = spin_retry ;
while ( count - - > 0 ) {
2009-12-03 20:08:46 +01:00
if ( ! arch_read_can_lock ( rw ) )
2006-03-09 17:33:49 -08:00
continue ;
2005-07-27 11:44:57 -07: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 ) ;
2009-12-03 20:01:19 +01:00
void _raw_write_lock_wait ( arch_rwlock_t * rw )
2005-07-27 11:44:57 -07:00
{
int count = spin_retry ;
while ( 1 ) {
if ( count - - < = 0 ) {
2006-09-30 23:27:45 -07:00
_raw_yield ( ) ;
2005-07-27 11:44:57 -07:00
count = spin_retry ;
}
2009-12-03 20:08:46 +01:00
if ( ! arch_write_can_lock ( rw ) )
2006-03-09 17:33:49 -08:00
continue ;
2005-07-27 11:44:57 -07:00
if ( _raw_compare_and_swap ( & rw - > lock , 0 , 0x80000000 ) = = 0 )
return ;
}
}
EXPORT_SYMBOL ( _raw_write_lock_wait ) ;
2009-12-03 20:01:19 +01:00
void _raw_write_lock_wait_flags ( arch_rwlock_t * rw , unsigned long flags )
2009-06-12 10:26:22 +02:00
{
int count = spin_retry ;
local_irq_restore ( flags ) ;
while ( 1 ) {
if ( count - - < = 0 ) {
_raw_yield ( ) ;
count = spin_retry ;
}
2009-12-03 20:08:46 +01:00
if ( ! arch_write_can_lock ( rw ) )
2009-06-12 10:26:22 +02:00
continue ;
local_irq_disable ( ) ;
if ( _raw_compare_and_swap ( & rw - > lock , 0 , 0x80000000 ) = = 0 )
return ;
}
}
EXPORT_SYMBOL ( _raw_write_lock_wait_flags ) ;
2009-12-03 20:01:19 +01:00
int _raw_write_trylock_retry ( arch_rwlock_t * rw )
2005-07-27 11:44:57 -07:00
{
int count = spin_retry ;
while ( count - - > 0 ) {
2009-12-03 20:08:46 +01:00
if ( ! arch_write_can_lock ( rw ) )
2006-03-09 17:33:49 -08:00
continue ;
2005-07-27 11:44:57 -07:00
if ( _raw_compare_and_swap ( & rw - > lock , 0 , 0x80000000 ) = = 0 )
return 1 ;
}
return 0 ;
}
EXPORT_SYMBOL ( _raw_write_trylock_retry ) ;