2015-05-21 12:13:06 +05:30
/*
* POWER Data Stream Control Register ( DSCR ) default test
*
* This test modifies the system wide default DSCR through
* it ' s sysfs interface and then verifies that all threads
* see the correct changed DSCR value immediately .
*
* Copyright 2012 , Anton Blanchard , IBM Corporation .
* Copyright 2015 , Anshuman Khandual , IBM Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation .
*/
# include "dscr.h"
static unsigned long dscr ; /* System DSCR default */
static unsigned long sequence ;
static unsigned long result [ THREADS ] ;
static void * do_test ( void * in )
{
unsigned long thread = ( unsigned long ) in ;
unsigned long i ;
for ( i = 0 ; i < COUNT ; i + + ) {
unsigned long d , cur_dscr , cur_dscr_usr ;
unsigned long s1 , s2 ;
locking/atomics, selftests/powerpc: Convert ACCESS_ONCE() to READ_ONCE()/WRITE_ONCE()
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't currently harmful.
However, for some features it is necessary to instrument reads and
writes separately, which is not possible with ACCESS_ONCE(). This
distinction is critical to correct operation.
The bulk of the kernel code can be transformed via Coccinelle to use
{READ,WRITE}_ONCE(), though this only modifies users of ACCESS_ONCE(),
and not the implementation itself. As such, it has the potential to
break homebrew ACCESS_ONCE() macros seen in some user code in the kernel
tree (e.g. the virtio code, as fixed in commit ea9156fb3b71d9f7).
To avoid fragility if/when that transformation occurs, and to align with
the preferred usage of {READ,WRITE}_ONCE(), this patch updates the DSCR
selftest code to use READ_ONCE() rather than ACCESS_ONCE(). There should
be no functional change as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: Michael Ellerman <mpe@ellerman.id.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-11-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-23 14:07:21 -07:00
s1 = READ_ONCE ( sequence ) ;
2015-05-21 12:13:06 +05:30
if ( s1 & 1 )
continue ;
rmb ( ) ;
d = dscr ;
cur_dscr = get_dscr ( ) ;
cur_dscr_usr = get_dscr_usr ( ) ;
rmb ( ) ;
s2 = sequence ;
if ( s1 ! = s2 )
continue ;
if ( cur_dscr ! = d ) {
fprintf ( stderr , " thread %ld kernel DSCR should be %ld "
" but is %ld \n " , thread , d , cur_dscr ) ;
result [ thread ] = 1 ;
pthread_exit ( & result [ thread ] ) ;
}
if ( cur_dscr_usr ! = d ) {
fprintf ( stderr , " thread %ld user DSCR should be %ld "
" but is %ld \n " , thread , d , cur_dscr_usr ) ;
result [ thread ] = 1 ;
pthread_exit ( & result [ thread ] ) ;
}
}
result [ thread ] = 0 ;
pthread_exit ( & result [ thread ] ) ;
}
int dscr_default ( void )
{
pthread_t threads [ THREADS ] ;
unsigned long i , * status [ THREADS ] ;
unsigned long orig_dscr_default ;
orig_dscr_default = get_default_dscr ( ) ;
/* Initial DSCR default */
dscr = 1 ;
set_default_dscr ( dscr ) ;
/* Spawn all testing threads */
for ( i = 0 ; i < THREADS ; i + + ) {
if ( pthread_create ( & threads [ i ] , NULL , do_test , ( void * ) i ) ) {
perror ( " pthread_create() failed " ) ;
goto fail ;
}
}
srand ( getpid ( ) ) ;
/* Keep changing the DSCR default */
for ( i = 0 ; i < COUNT ; i + + ) {
double ret = uniform_deviate ( rand ( ) ) ;
if ( ret < 0.0001 ) {
sequence + + ;
wmb ( ) ;
dscr + + ;
if ( dscr > DSCR_MAX )
dscr = 0 ;
set_default_dscr ( dscr ) ;
wmb ( ) ;
sequence + + ;
}
}
/* Individual testing thread exit status */
for ( i = 0 ; i < THREADS ; i + + ) {
if ( pthread_join ( threads [ i ] , ( void * * ) & ( status [ i ] ) ) ) {
perror ( " pthread_join() failed " ) ;
goto fail ;
}
if ( * status [ i ] ) {
printf ( " %ldth thread failed to join with %ld status \n " ,
i , * status [ i ] ) ;
goto fail ;
}
}
set_default_dscr ( orig_dscr_default ) ;
return 0 ;
fail :
set_default_dscr ( orig_dscr_default ) ;
return 1 ;
}
int main ( int argc , char * argv [ ] )
{
return test_harness ( dscr_default , " dscr_default_test " ) ;
}