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>
2012-03-11 19:59:26 +04:00
# include <linux/smp.h>
2005-07-27 22:44:57 +04:00
# 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 ) ;
2009-12-02 22:01:25 +03:00
void arch_spin_lock_wait ( arch_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 ( ) ;
2010-02-27 00:37:40 +03:00
unsigned int owner ;
2005-07-27 22:44:57 +04:00
while ( 1 ) {
2010-02-27 00:37:40 +03:00
owner = lp - > owner_cpu ;
if ( ! owner | | smp_vcpu_scheduled ( ~ owner ) ) {
for ( count = spin_retry ; count > 0 ; count - - ) {
if ( arch_spin_is_locked ( lp ) )
continue ;
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 ,
cpu ) = = 0 )
return ;
}
if ( MACHINE_IS_LPAR )
continue ;
2005-07-27 22:44:57 +04:00
}
2010-02-27 00:37:40 +03:00
owner = lp - > owner_cpu ;
if ( owner )
2012-03-11 19:59:26 +04:00
smp_yield_cpu ( ~ owner ) ;
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 ;
}
}
2009-12-02 22:01:25 +03:00
EXPORT_SYMBOL ( arch_spin_lock_wait ) ;
2005-07-27 22:44:57 +04:00
2009-12-02 22:01:25 +03:00
void arch_spin_lock_wait_flags ( arch_spinlock_t * lp , unsigned long flags )
2008-01-26 16:11:28 +03:00
{
int count = spin_retry ;
unsigned int cpu = ~ smp_processor_id ( ) ;
2010-02-27 00:37:40 +03:00
unsigned int owner ;
2008-01-26 16:11:28 +03:00
local_irq_restore ( flags ) ;
while ( 1 ) {
2010-02-27 00:37:40 +03:00
owner = lp - > owner_cpu ;
if ( ! owner | | smp_vcpu_scheduled ( ~ owner ) ) {
for ( count = spin_retry ; count > 0 ; count - - ) {
if ( arch_spin_is_locked ( lp ) )
continue ;
local_irq_disable ( ) ;
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 ,
cpu ) = = 0 )
return ;
local_irq_restore ( flags ) ;
}
if ( MACHINE_IS_LPAR )
continue ;
2008-01-26 16:11:28 +03:00
}
2010-02-27 00:37:40 +03:00
owner = lp - > owner_cpu ;
if ( owner )
2012-03-11 19:59:26 +04:00
smp_yield_cpu ( ~ owner ) ;
2008-01-26 16:11:28 +03:00
local_irq_disable ( ) ;
if ( _raw_compare_and_swap ( & lp - > owner_cpu , 0 , cpu ) = = 0 )
return ;
local_irq_restore ( flags ) ;
}
}
2009-12-02 22:01:25 +03:00
EXPORT_SYMBOL ( arch_spin_lock_wait_flags ) ;
2008-01-26 16:11:28 +03:00
2009-12-02 22:01:25 +03:00
int arch_spin_trylock_retry ( arch_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 - - ) {
2009-12-02 22:01:25 +03:00
if ( arch_spin_is_locked ( lp ) )
2006-03-10 04:33:49 +03:00
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 ;
}
2009-12-02 22:01:25 +03:00
EXPORT_SYMBOL ( arch_spin_trylock_retry ) ;
2005-07-27 22:44:57 +04:00
2009-12-02 22:01:25 +03:00
void arch_spin_relax ( arch_spinlock_t * lock )
2006-10-01 10:27:45 +04:00
{
unsigned int cpu = lock - > owner_cpu ;
2010-02-27 00:37:40 +03:00
if ( cpu ! = 0 ) {
if ( MACHINE_IS_VM | | MACHINE_IS_KVM | |
! smp_vcpu_scheduled ( ~ cpu ) )
2012-03-11 19:59:26 +04:00
smp_yield_cpu ( ~ cpu ) ;
2010-02-27 00:37:40 +03:00
}
2006-10-01 10:27:45 +04:00
}
2009-12-02 22:01:25 +03:00
EXPORT_SYMBOL ( arch_spin_relax ) ;
2006-10-01 10:27:45 +04:00
2009-12-03 22:01:19 +03:00
void _raw_read_lock_wait ( arch_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
unsigned int old ;
int count = spin_retry ;
while ( 1 ) {
if ( count - - < = 0 ) {
2012-03-11 19:59:26 +04:00
smp_yield ( ) ;
2005-07-27 22:44:57 +04:00
count = spin_retry ;
}
2009-12-03 22:08:46 +03:00
if ( ! arch_read_can_lock ( rw ) )
2006-03-10 04:33:49 +03:00
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 ) ;
2009-12-03 22:01:19 +03:00
void _raw_read_lock_wait_flags ( arch_rwlock_t * rw , unsigned long flags )
2009-06-12 12:26:22 +04:00
{
unsigned int old ;
int count = spin_retry ;
local_irq_restore ( flags ) ;
while ( 1 ) {
if ( count - - < = 0 ) {
2012-03-11 19:59:26 +04:00
smp_yield ( ) ;
2009-06-12 12:26:22 +04:00
count = spin_retry ;
}
2009-12-03 22:08:46 +03:00
if ( ! arch_read_can_lock ( rw ) )
2009-06-12 12:26:22 +04: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 22:01:19 +03:00
int _raw_read_trylock_retry ( arch_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
unsigned int old ;
int count = spin_retry ;
while ( count - - > 0 ) {
2009-12-03 22:08:46 +03:00
if ( ! arch_read_can_lock ( rw ) )
2006-03-10 04:33:49 +03:00
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 ) ;
2009-12-03 22:01:19 +03:00
void _raw_write_lock_wait ( arch_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
int count = spin_retry ;
while ( 1 ) {
if ( count - - < = 0 ) {
2012-03-11 19:59:26 +04:00
smp_yield ( ) ;
2005-07-27 22:44:57 +04:00
count = spin_retry ;
}
2009-12-03 22:08:46 +03:00
if ( ! arch_write_can_lock ( rw ) )
2006-03-10 04:33:49 +03:00
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 ) ;
2009-12-03 22:01:19 +03:00
void _raw_write_lock_wait_flags ( arch_rwlock_t * rw , unsigned long flags )
2009-06-12 12:26:22 +04:00
{
int count = spin_retry ;
local_irq_restore ( flags ) ;
while ( 1 ) {
if ( count - - < = 0 ) {
2012-03-11 19:59:26 +04:00
smp_yield ( ) ;
2009-06-12 12:26:22 +04:00
count = spin_retry ;
}
2009-12-03 22:08:46 +03:00
if ( ! arch_write_can_lock ( rw ) )
2009-06-12 12:26:22 +04: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 22:01:19 +03:00
int _raw_write_trylock_retry ( arch_rwlock_t * rw )
2005-07-27 22:44:57 +04:00
{
int count = spin_retry ;
while ( count - - > 0 ) {
2009-12-03 22:08:46 +03:00
if ( ! arch_write_can_lock ( rw ) )
2006-03-10 04:33:49 +03:00
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 ) ;