2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-06-04 02:56:11 +04:00
/* n2-drv.c: Niagara-2 RNG driver.
*
2011-07-28 10:33:03 +04:00
* Copyright ( C ) 2008 , 2011 David S . Miller < davem @ davemloft . net >
2008-06-04 02:56:11 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/workqueue.h>
# include <linux/preempt.h>
# include <linux/hw_random.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <asm/hypervisor.h>
# include "n2rng.h"
# define DRV_MODULE_NAME "n2rng"
# define PFX DRV_MODULE_NAME ": "
2017-01-12 21:52:49 +03:00
# define DRV_MODULE_VERSION "0.3"
# define DRV_MODULE_RELDATE "Jan 7, 2017"
2008-06-04 02:56:11 +04:00
2012-11-19 22:24:36 +04:00
static char version [ ] =
2017-01-12 21:52:49 +03:00
DRV_MODULE_NAME " v " DRV_MODULE_VERSION " ( " DRV_MODULE_RELDATE " ) \n " ;
2008-06-04 02:56:11 +04:00
MODULE_AUTHOR ( " David S. Miller (davem@davemloft.net) " ) ;
MODULE_DESCRIPTION ( " Niagara2 RNG driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRV_MODULE_VERSION ) ;
/* The Niagara2 RNG provides a 64-bit read-only random number
* register , plus a control register . Access to the RNG is
* virtualized through the hypervisor so that both guests and control
* nodes can access the device .
*
* The entropy source consists of raw entropy sources , each
* constructed from a voltage controlled oscillator whose phase is
* jittered by thermal noise sources .
*
* The oscillator in each of the three raw entropy sources run at
* different frequencies . Normally , all three generator outputs are
* gathered , xored together , and fed into a CRC circuit , the output of
* which is the 64 - bit read - only register .
*
* Some time is necessary for all the necessary entropy to build up
* such that a full 64 - bits of entropy are available in the register .
* In normal operating mode ( RNG_CTL_LFSR is set ) , the chip implements
* an interlock which blocks register reads until sufficient entropy
* is available .
*
* A control register is provided for adjusting various aspects of RNG
* operation , and to enable diagnostic modes . Each of the three raw
* entropy sources has an enable bit ( RNG_CTL_ES { 1 , 2 , 3 } ) . Also
* provided are fields for controlling the minimum time in cycles
* between read accesses to the register ( RNG_CTL_WAIT , this controls
* the interlock described in the previous paragraph ) .
*
* The standard setting is to have the mode bit ( RNG_CTL_LFSR ) set ,
* all three entropy sources enabled , and the interlock time set
* appropriately .
*
* The CRC polynomial used by the chip is :
*
* P ( X ) = x64 + x61 + x57 + x56 + x52 + x51 + x50 + x48 + x47 + x46 +
* x43 + x42 + x41 + x39 + x38 + x37 + x35 + x32 + x28 + x25 +
* x22 + x21 + x17 + x15 + x13 + x12 + x11 + x7 + x5 + x + 1
*
* The RNG_CTL_VCO value of each noise cell must be programmed
tree-wide: Assorted spelling fixes
In particular, several occurances of funny versions of 'success',
'unknown', 'therefore', 'acknowledge', 'argument', 'achieve', 'address',
'beginning', 'desirable', 'separate' and 'necessary' are fixed.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Joe Perches <joe@perches.com>
Cc: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2010-02-03 03:01:28 +03:00
* separately . This is why 4 control register values must be provided
2008-06-04 02:56:11 +04:00
* to the hypervisor . During a write , the hypervisor writes them all ,
* one at a time , to the actual RNG_CTL register . The first three
* values are used to setup the desired RNG_CTL_VCO for each entropy
* source , for example :
*
* control 0 : ( 1 < < RNG_CTL_VCO_SHIFT ) | RNG_CTL_ES1
* control 1 : ( 2 < < RNG_CTL_VCO_SHIFT ) | RNG_CTL_ES2
* control 2 : ( 3 < < RNG_CTL_VCO_SHIFT ) | RNG_CTL_ES3
*
* And then the fourth value sets the final chip state and enables
* desired .
*/
static int n2rng_hv_err_trans ( unsigned long hv_err )
{
switch ( hv_err ) {
case HV_EOK :
return 0 ;
case HV_EWOULDBLOCK :
return - EAGAIN ;
case HV_ENOACCESS :
return - EPERM ;
case HV_EIO :
return - EIO ;
case HV_EBUSY :
return - EBUSY ;
case HV_EBADALIGN :
case HV_ENORADDR :
return - EFAULT ;
default :
return - EINVAL ;
}
}
static unsigned long n2rng_generic_read_control_v2 ( unsigned long ra ,
unsigned long unit )
{
unsigned long hv_err , state , ticks , watchdog_delta , watchdog_status ;
int block = 0 , busy = 0 ;
while ( 1 ) {
hv_err = sun4v_rng_ctl_read_v2 ( ra , unit , & state ,
& ticks ,
& watchdog_delta ,
& watchdog_status ) ;
if ( hv_err = = HV_EOK )
break ;
if ( hv_err = = HV_EBUSY ) {
if ( + + busy > = N2RNG_BUSY_LIMIT )
break ;
udelay ( 1 ) ;
} else if ( hv_err = = HV_EWOULDBLOCK ) {
if ( + + block > = N2RNG_BLOCK_LIMIT )
break ;
__delay ( ticks ) ;
} else
break ;
}
return hv_err ;
}
/* In multi-socket situations, the hypervisor might need to
* queue up the RNG control register write if it ' s for a unit
* that is on a cpu socket other than the one we are executing on .
*
* We poll here waiting for a successful read of that control
* register to make sure the write has been actually performed .
*/
static unsigned long n2rng_control_settle_v2 ( struct n2rng * np , int unit )
{
unsigned long ra = __pa ( & np - > scratch_control [ 0 ] ) ;
return n2rng_generic_read_control_v2 ( ra , unit ) ;
}
static unsigned long n2rng_write_ctl_one ( struct n2rng * np , int unit ,
unsigned long state ,
unsigned long control_ra ,
unsigned long watchdog_timeout ,
unsigned long * ticks )
{
unsigned long hv_err ;
if ( np - > hvapi_major = = 1 ) {
hv_err = sun4v_rng_ctl_write_v1 ( control_ra , state ,
watchdog_timeout , ticks ) ;
} else {
hv_err = sun4v_rng_ctl_write_v2 ( control_ra , state ,
watchdog_timeout , unit ) ;
if ( hv_err = = HV_EOK )
hv_err = n2rng_control_settle_v2 ( np , unit ) ;
* ticks = N2RNG_ACCUM_CYCLES_DEFAULT ;
}
return hv_err ;
}
static int n2rng_generic_read_data ( unsigned long data_ra )
{
unsigned long ticks , hv_err ;
int block = 0 , hcheck = 0 ;
while ( 1 ) {
hv_err = sun4v_rng_data_read ( data_ra , & ticks ) ;
if ( hv_err = = HV_EOK )
return 0 ;
if ( hv_err = = HV_EWOULDBLOCK ) {
if ( + + block > = N2RNG_BLOCK_LIMIT )
return - EWOULDBLOCK ;
__delay ( ticks ) ;
} else if ( hv_err = = HV_ENOACCESS ) {
return - EPERM ;
} else if ( hv_err = = HV_EIO ) {
if ( + + hcheck > = N2RNG_HCHECK_LIMIT )
return - EIO ;
udelay ( 10000 ) ;
} else
return - ENODEV ;
}
}
static unsigned long n2rng_read_diag_data_one ( struct n2rng * np ,
unsigned long unit ,
unsigned long data_ra ,
unsigned long data_len ,
unsigned long * ticks )
{
unsigned long hv_err ;
if ( np - > hvapi_major = = 1 ) {
hv_err = sun4v_rng_data_read_diag_v1 ( data_ra , data_len , ticks ) ;
} else {
hv_err = sun4v_rng_data_read_diag_v2 ( data_ra , data_len ,
unit , ticks ) ;
if ( ! * ticks )
* ticks = N2RNG_ACCUM_CYCLES_DEFAULT ;
}
return hv_err ;
}
static int n2rng_generic_read_diag_data ( struct n2rng * np ,
unsigned long unit ,
unsigned long data_ra ,
unsigned long data_len )
{
unsigned long ticks , hv_err ;
int block = 0 ;
while ( 1 ) {
hv_err = n2rng_read_diag_data_one ( np , unit ,
data_ra , data_len ,
& ticks ) ;
if ( hv_err = = HV_EOK )
return 0 ;
if ( hv_err = = HV_EWOULDBLOCK ) {
if ( + + block > = N2RNG_BLOCK_LIMIT )
return - EWOULDBLOCK ;
__delay ( ticks ) ;
} else if ( hv_err = = HV_ENOACCESS ) {
return - EPERM ;
} else if ( hv_err = = HV_EIO ) {
return - EIO ;
} else
return - ENODEV ;
}
}
static int n2rng_generic_write_control ( struct n2rng * np ,
unsigned long control_ra ,
unsigned long unit ,
unsigned long state )
{
unsigned long hv_err , ticks ;
int block = 0 , busy = 0 ;
while ( 1 ) {
hv_err = n2rng_write_ctl_one ( np , unit , state , control_ra ,
np - > wd_timeo , & ticks ) ;
if ( hv_err = = HV_EOK )
return 0 ;
if ( hv_err = = HV_EWOULDBLOCK ) {
if ( + + block > = N2RNG_BLOCK_LIMIT )
return - EWOULDBLOCK ;
__delay ( ticks ) ;
} else if ( hv_err = = HV_EBUSY ) {
if ( + + busy > = N2RNG_BUSY_LIMIT )
return - EBUSY ;
udelay ( 1 ) ;
} else
return - ENODEV ;
}
}
/* Just try to see if we can successfully access the control register
* of the RNG on the domain on which we are currently executing .
*/
static int n2rng_try_read_ctl ( struct n2rng * np )
{
unsigned long hv_err ;
unsigned long x ;
if ( np - > hvapi_major = = 1 ) {
hv_err = sun4v_rng_get_diag_ctl ( ) ;
} else {
/* We purposefully give invalid arguments, HV_NOACCESS
* is higher priority than the errors we ' d get from
* these other cases , and that ' s the error we are
* truly interested in .
*/
hv_err = sun4v_rng_ctl_read_v2 ( 0UL , ~ 0UL , & x , & x , & x , & x ) ;
switch ( hv_err ) {
case HV_EWOULDBLOCK :
case HV_ENOACCESS :
break ;
default :
hv_err = HV_EOK ;
break ;
}
}
return n2rng_hv_err_trans ( hv_err ) ;
}
2017-01-12 21:52:48 +03:00
static u64 n2rng_control_default ( struct n2rng * np , int ctl )
{
u64 val = 0 ;
if ( np - > data - > chip_version = = 1 ) {
val = ( ( 2 < < RNG_v1_CTL_ASEL_SHIFT ) |
( N2RNG_ACCUM_CYCLES_DEFAULT < < RNG_v1_CTL_WAIT_SHIFT ) |
RNG_CTL_LFSR ) ;
switch ( ctl ) {
case 0 :
val | = ( 1 < < RNG_v1_CTL_VCO_SHIFT ) | RNG_CTL_ES1 ;
break ;
case 1 :
val | = ( 2 < < RNG_v1_CTL_VCO_SHIFT ) | RNG_CTL_ES2 ;
break ;
case 2 :
val | = ( 3 < < RNG_v1_CTL_VCO_SHIFT ) | RNG_CTL_ES3 ;
break ;
case 3 :
val | = RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3 ;
break ;
default :
break ;
}
} else {
val = ( ( 2 < < RNG_v2_CTL_ASEL_SHIFT ) |
( N2RNG_ACCUM_CYCLES_DEFAULT < < RNG_v2_CTL_WAIT_SHIFT ) |
RNG_CTL_LFSR ) ;
switch ( ctl ) {
case 0 :
val | = ( 1 < < RNG_v2_CTL_VCO_SHIFT ) | RNG_CTL_ES1 ;
break ;
case 1 :
val | = ( 2 < < RNG_v2_CTL_VCO_SHIFT ) | RNG_CTL_ES2 ;
break ;
case 2 :
val | = ( 3 < < RNG_v2_CTL_VCO_SHIFT ) | RNG_CTL_ES3 ;
break ;
case 3 :
val | = RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3 ;
break ;
default :
break ;
}
}
return val ;
}
2008-06-04 02:56:11 +04:00
static void n2rng_control_swstate_init ( struct n2rng * np )
{
int i ;
np - > flags | = N2RNG_FLAG_CONTROL ;
np - > health_check_sec = N2RNG_HEALTH_CHECK_SEC_DEFAULT ;
np - > accum_cycles = N2RNG_ACCUM_CYCLES_DEFAULT ;
np - > wd_timeo = N2RNG_WD_TIMEO_DEFAULT ;
for ( i = 0 ; i < np - > num_units ; i + + ) {
struct n2rng_unit * up = & np - > units [ i ] ;
2017-01-12 21:52:48 +03:00
up - > control [ 0 ] = n2rng_control_default ( np , 0 ) ;
up - > control [ 1 ] = n2rng_control_default ( np , 1 ) ;
up - > control [ 2 ] = n2rng_control_default ( np , 2 ) ;
up - > control [ 3 ] = n2rng_control_default ( np , 3 ) ;
2008-06-04 02:56:11 +04:00
}
np - > hv_state = HV_RNG_STATE_UNCONFIGURED ;
}
static int n2rng_grab_diag_control ( struct n2rng * np )
{
int i , busy_count , err = - ENODEV ;
busy_count = 0 ;
for ( i = 0 ; i < 100 ; i + + ) {
err = n2rng_try_read_ctl ( np ) ;
if ( err ! = - EAGAIN )
break ;
if ( + + busy_count > 100 ) {
dev_err ( & np - > op - > dev ,
" Grab diag control timeout. \n " ) ;
return - ENODEV ;
}
udelay ( 1 ) ;
}
return err ;
}
static int n2rng_init_control ( struct n2rng * np )
{
int err = n2rng_grab_diag_control ( np ) ;
/* Not in the control domain, that's OK we are only a consumer
* of the RNG data , we don ' t setup and program it .
*/
if ( err = = - EPERM )
return 0 ;
if ( err )
return err ;
n2rng_control_swstate_init ( np ) ;
return 0 ;
}
static int n2rng_data_read ( struct hwrng * rng , u32 * data )
{
2010-08-09 18:29:28 +04:00
struct n2rng * np = ( struct n2rng * ) rng - > priv ;
2008-06-04 02:56:11 +04:00
unsigned long ra = __pa ( & np - > test_data ) ;
int len ;
if ( ! ( np - > flags & N2RNG_FLAG_READY ) ) {
len = 0 ;
} else if ( np - > flags & N2RNG_FLAG_BUFFER_VALID ) {
np - > flags & = ~ N2RNG_FLAG_BUFFER_VALID ;
* data = np - > buffer ;
len = 4 ;
} else {
int err = n2rng_generic_read_data ( ra ) ;
if ( ! err ) {
2017-01-12 21:52:48 +03:00
np - > flags | = N2RNG_FLAG_BUFFER_VALID ;
2008-06-04 02:56:11 +04:00
np - > buffer = np - > test_data > > 32 ;
* data = np - > test_data & 0xffffffff ;
len = 4 ;
} else {
2018-05-09 01:18:42 +03:00
dev_err ( & np - > op - > dev , " RNG error, retesting \n " ) ;
2008-06-04 02:56:11 +04:00
np - > flags & = ~ N2RNG_FLAG_READY ;
if ( ! ( np - > flags & N2RNG_FLAG_SHUTDOWN ) )
schedule_delayed_work ( & np - > work , 0 ) ;
len = 0 ;
}
}
return len ;
}
/* On a guest node, just make sure we can read random data properly.
* If a control node reboots or reloads it ' s n2rng driver , this won ' t
* work during that time . So we have to keep probing until the device
* becomes usable .
*/
static int n2rng_guest_check ( struct n2rng * np )
{
unsigned long ra = __pa ( & np - > test_data ) ;
return n2rng_generic_read_data ( ra ) ;
}
static int n2rng_entropy_diag_read ( struct n2rng * np , unsigned long unit ,
u64 * pre_control , u64 pre_state ,
u64 * buffer , unsigned long buf_len ,
u64 * post_control , u64 post_state )
{
unsigned long post_ctl_ra = __pa ( post_control ) ;
unsigned long pre_ctl_ra = __pa ( pre_control ) ;
unsigned long buffer_ra = __pa ( buffer ) ;
int err ;
err = n2rng_generic_write_control ( np , pre_ctl_ra , unit , pre_state ) ;
if ( err )
return err ;
err = n2rng_generic_read_diag_data ( np , unit ,
buffer_ra , buf_len ) ;
( void ) n2rng_generic_write_control ( np , post_ctl_ra , unit ,
post_state ) ;
return err ;
}
static u64 advance_polynomial ( u64 poly , u64 val , int count )
{
int i ;
for ( i = 0 ; i < count ; i + + ) {
int highbit_set = ( ( s64 ) val < 0 ) ;
val < < = 1 ;
if ( highbit_set )
val ^ = poly ;
}
return val ;
}
static int n2rng_test_buffer_find ( struct n2rng * np , u64 val )
{
int i , count = 0 ;
/* Purposefully skip over the first word. */
for ( i = 1 ; i < SELFTEST_BUFFER_WORDS ; i + + ) {
if ( np - > test_buffer [ i ] = = val )
count + + ;
}
return count ;
}
static void n2rng_dump_test_buffer ( struct n2rng * np )
{
int i ;
for ( i = 0 ; i < SELFTEST_BUFFER_WORDS ; i + + )
2009-01-07 00:20:38 +03:00
dev_err ( & np - > op - > dev , " Test buffer slot %d [0x%016llx] \n " ,
2008-06-04 02:56:11 +04:00
i , np - > test_buffer [ i ] ) ;
}
static int n2rng_check_selftest_buffer ( struct n2rng * np , unsigned long unit )
{
2017-01-12 21:52:48 +03:00
u64 val ;
2008-06-04 02:56:11 +04:00
int err , matches , limit ;
2017-01-12 21:52:48 +03:00
switch ( np - > data - > id ) {
case N2_n2_rng :
case N2_vf_rng :
case N2_kt_rng :
case N2_m4_rng : /* yes, m4 uses the old value */
val = RNG_v1_SELFTEST_VAL ;
break ;
default :
val = RNG_v2_SELFTEST_VAL ;
break ;
}
2008-06-04 02:56:11 +04:00
matches = 0 ;
for ( limit = 0 ; limit < SELFTEST_LOOPS_MAX ; limit + + ) {
matches + = n2rng_test_buffer_find ( np , val ) ;
if ( matches > = SELFTEST_MATCH_GOAL )
break ;
val = advance_polynomial ( SELFTEST_POLY , val , 1 ) ;
}
err = 0 ;
if ( limit > = SELFTEST_LOOPS_MAX ) {
err = - ENODEV ;
dev_err ( & np - > op - > dev , " Selftest failed on unit %lu \n " , unit ) ;
n2rng_dump_test_buffer ( np ) ;
} else
dev_info ( & np - > op - > dev , " Selftest passed on unit %lu \n " , unit ) ;
return err ;
}
static int n2rng_control_selftest ( struct n2rng * np , unsigned long unit )
{
int err ;
2017-01-12 21:52:48 +03:00
u64 base , base3 ;
switch ( np - > data - > id ) {
case N2_n2_rng :
case N2_vf_rng :
case N2_kt_rng :
base = RNG_v1_CTL_ASEL_NOOUT < < RNG_v1_CTL_ASEL_SHIFT ;
base3 = base | RNG_CTL_LFSR |
( ( RNG_v1_SELFTEST_TICKS - 2 ) < < RNG_v1_CTL_WAIT_SHIFT ) ;
break ;
case N2_m4_rng :
base = RNG_v2_CTL_ASEL_NOOUT < < RNG_v2_CTL_ASEL_SHIFT ;
base3 = base | RNG_CTL_LFSR |
( ( RNG_v1_SELFTEST_TICKS - 2 ) < < RNG_v2_CTL_WAIT_SHIFT ) ;
break ;
default :
base = RNG_v2_CTL_ASEL_NOOUT < < RNG_v2_CTL_ASEL_SHIFT ;
base3 = base | RNG_CTL_LFSR |
( RNG_v2_SELFTEST_TICKS < < RNG_v2_CTL_WAIT_SHIFT ) ;
break ;
}
2008-06-04 02:56:11 +04:00
2017-01-12 21:52:48 +03:00
np - > test_control [ 0 ] = base ;
np - > test_control [ 1 ] = base ;
np - > test_control [ 2 ] = base ;
np - > test_control [ 3 ] = base3 ;
2008-06-04 02:56:11 +04:00
err = n2rng_entropy_diag_read ( np , unit , np - > test_control ,
HV_RNG_STATE_HEALTHCHECK ,
np - > test_buffer ,
sizeof ( np - > test_buffer ) ,
& np - > units [ unit ] . control [ 0 ] ,
np - > hv_state ) ;
if ( err )
return err ;
return n2rng_check_selftest_buffer ( np , unit ) ;
}
static int n2rng_control_check ( struct n2rng * np )
{
int i ;
for ( i = 0 ; i < np - > num_units ; i + + ) {
int err = n2rng_control_selftest ( np , i ) ;
if ( err )
return err ;
}
return 0 ;
}
/* The sanity checks passed, install the final configuration into the
* chip , it ' s ready to use .
*/
static int n2rng_control_configure_units ( struct n2rng * np )
{
int unit , err ;
err = 0 ;
for ( unit = 0 ; unit < np - > num_units ; unit + + ) {
struct n2rng_unit * up = & np - > units [ unit ] ;
unsigned long ctl_ra = __pa ( & up - > control [ 0 ] ) ;
int esrc ;
2017-01-12 21:52:48 +03:00
u64 base , shift ;
2008-06-04 02:56:11 +04:00
2017-01-12 21:52:48 +03:00
if ( np - > data - > chip_version = = 1 ) {
base = ( ( np - > accum_cycles < < RNG_v1_CTL_WAIT_SHIFT ) |
( RNG_v1_CTL_ASEL_NOOUT < < RNG_v1_CTL_ASEL_SHIFT ) |
RNG_CTL_LFSR ) ;
shift = RNG_v1_CTL_VCO_SHIFT ;
} else {
base = ( ( np - > accum_cycles < < RNG_v2_CTL_WAIT_SHIFT ) |
( RNG_v2_CTL_ASEL_NOOUT < < RNG_v2_CTL_ASEL_SHIFT ) |
RNG_CTL_LFSR ) ;
shift = RNG_v2_CTL_VCO_SHIFT ;
}
2008-06-04 02:56:11 +04:00
/* XXX This isn't the best. We should fetch a bunch
* XXX of words using each entropy source combined XXX
* with each VCO setting , and see which combinations
* XXX give the best random data .
*/
for ( esrc = 0 ; esrc < 3 ; esrc + + )
up - > control [ esrc ] = base |
2017-01-12 21:52:48 +03:00
( esrc < < shift ) |
2008-06-04 02:56:11 +04:00
( RNG_CTL_ES1 < < esrc ) ;
up - > control [ 3 ] = base |
( RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3 ) ;
err = n2rng_generic_write_control ( np , ctl_ra , unit ,
HV_RNG_STATE_CONFIGURED ) ;
if ( err )
break ;
}
return err ;
}
static void n2rng_work ( struct work_struct * work )
{
struct n2rng * np = container_of ( work , struct n2rng , work . work ) ;
int err = 0 ;
2017-01-12 21:52:46 +03:00
static int retries = 4 ;
2008-06-04 02:56:11 +04:00
if ( ! ( np - > flags & N2RNG_FLAG_CONTROL ) ) {
err = n2rng_guest_check ( np ) ;
} else {
preempt_disable ( ) ;
err = n2rng_control_check ( np ) ;
preempt_enable ( ) ;
if ( ! err )
err = n2rng_control_configure_units ( np ) ;
}
if ( ! err ) {
np - > flags | = N2RNG_FLAG_READY ;
dev_info ( & np - > op - > dev , " RNG ready \n " ) ;
}
2017-01-12 21:52:46 +03:00
if ( - - retries = = 0 )
dev_err ( & np - > op - > dev , " Self-test retries failed, RNG not ready \n " ) ;
else if ( err & & ! ( np - > flags & N2RNG_FLAG_SHUTDOWN ) )
2008-06-04 02:56:11 +04:00
schedule_delayed_work ( & np - > work , HZ * 2 ) ;
}
2012-12-22 03:12:08 +04:00
static void n2rng_driver_version ( void )
2008-06-04 02:56:11 +04:00
{
static int n2rng_version_printed ;
if ( n2rng_version_printed + + = = 0 )
pr_info ( " %s " , version ) ;
}
2011-05-18 21:19:24 +04:00
static const struct of_device_id n2rng_match [ ] ;
2012-12-22 03:12:08 +04:00
static int n2rng_probe ( struct platform_device * op )
2008-06-04 02:56:11 +04:00
{
2011-05-18 21:19:24 +04:00
const struct of_device_id * match ;
2008-06-04 02:56:11 +04:00
int err = - ENOMEM ;
struct n2rng * np ;
2011-05-18 21:19:24 +04:00
match = of_match_device ( n2rng_match , & op - > dev ) ;
if ( ! match )
2011-02-23 06:01:33 +03:00
return - EINVAL ;
2008-06-04 02:56:11 +04:00
2011-02-23 06:01:33 +03:00
n2rng_driver_version ( ) ;
hwrng: n2-drv - Introduce the use of the managed version of kzalloc
This patch moves data allocated using kzalloc to managed data allocated
using devm_kzalloc and cleans now unnecessary kfrees in probe and remove
functions. The NULL assignment to np->units is removed as there is no
interaction between this field and sun4v_hvapi_unregister. Also, the
labels out_free_units and out_free are removed as they are no longer
required.
The following Coccinelle semantic patch was used for making the change:
@platform@
identifier p, probefn, removefn;
@@
struct platform_driver p = {
.probe = probefn,
.remove = removefn,
};
@prb@
identifier platform.probefn, pdev;
expression e, e1, e2;
@@
probefn(struct platform_device *pdev, ...) {
<+...
- e = kzalloc(e1, e2)
+ e = devm_kzalloc(&pdev->dev, e1, e2)
...
?-kfree(e);
...+>
}
@rem depends on prb@
identifier platform.removefn;
expression e;
@@
removefn(...) {
<...
- kfree(e);
...>
}
Signed-off-by: Himangi Saraogi <himangi774@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2014-05-10 22:49:00 +04:00
np = devm_kzalloc ( & op - > dev , sizeof ( * np ) , GFP_KERNEL ) ;
2008-06-04 02:56:11 +04:00
if ( ! np )
goto out ;
np - > op = op ;
2017-01-12 21:52:47 +03:00
np - > data = ( struct n2rng_template * ) match - > data ;
2008-06-04 02:56:11 +04:00
INIT_DELAYED_WORK ( & np - > work , n2rng_work ) ;
2017-01-12 21:52:47 +03:00
if ( np - > data - > multi_capable )
2011-07-28 10:33:03 +04:00
np - > flags | = N2RNG_FLAG_MULTI ;
2008-06-04 02:56:11 +04:00
err = - ENODEV ;
np - > hvapi_major = 2 ;
if ( sun4v_hvapi_register ( HV_GRP_RNG ,
np - > hvapi_major ,
& np - > hvapi_minor ) ) {
np - > hvapi_major = 1 ;
if ( sun4v_hvapi_register ( HV_GRP_RNG ,
np - > hvapi_major ,
& np - > hvapi_minor ) ) {
dev_err ( & op - > dev , " Cannot register suitable "
" HVAPI version. \n " ) ;
hwrng: n2-drv - Introduce the use of the managed version of kzalloc
This patch moves data allocated using kzalloc to managed data allocated
using devm_kzalloc and cleans now unnecessary kfrees in probe and remove
functions. The NULL assignment to np->units is removed as there is no
interaction between this field and sun4v_hvapi_unregister. Also, the
labels out_free_units and out_free are removed as they are no longer
required.
The following Coccinelle semantic patch was used for making the change:
@platform@
identifier p, probefn, removefn;
@@
struct platform_driver p = {
.probe = probefn,
.remove = removefn,
};
@prb@
identifier platform.probefn, pdev;
expression e, e1, e2;
@@
probefn(struct platform_device *pdev, ...) {
<+...
- e = kzalloc(e1, e2)
+ e = devm_kzalloc(&pdev->dev, e1, e2)
...
?-kfree(e);
...+>
}
@rem depends on prb@
identifier platform.removefn;
expression e;
@@
removefn(...) {
<...
- kfree(e);
...>
}
Signed-off-by: Himangi Saraogi <himangi774@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2014-05-10 22:49:00 +04:00
goto out ;
2008-06-04 02:56:11 +04:00
}
}
2011-07-28 10:33:03 +04:00
if ( np - > flags & N2RNG_FLAG_MULTI ) {
2008-06-04 02:56:11 +04:00
if ( np - > hvapi_major < 2 ) {
2011-07-28 10:33:03 +04:00
dev_err ( & op - > dev , " multi-unit-capable RNG requires "
" HVAPI major version 2 or later, got %lu \n " ,
2008-06-04 02:56:11 +04:00
np - > hvapi_major ) ;
goto out_hvapi_unregister ;
}
2010-04-14 03:12:29 +04:00
np - > num_units = of_getintprop_default ( op - > dev . of_node ,
2008-06-04 02:56:11 +04:00
" rng-#units " , 0 ) ;
if ( ! np - > num_units ) {
dev_err ( & op - > dev , " VF RNG lacks rng-#units property \n " ) ;
goto out_hvapi_unregister ;
}
2017-01-12 21:52:47 +03:00
} else {
2008-06-04 02:56:11 +04:00
np - > num_units = 1 ;
2017-01-12 21:52:47 +03:00
}
2008-06-04 02:56:11 +04:00
dev_info ( & op - > dev , " Registered RNG HVAPI major %lu minor %lu \n " ,
np - > hvapi_major , np - > hvapi_minor ) ;
2017-04-19 11:30:47 +03:00
np - > units = devm_kcalloc ( & op - > dev , np - > num_units , sizeof ( * np - > units ) ,
hwrng: n2-drv - Introduce the use of the managed version of kzalloc
This patch moves data allocated using kzalloc to managed data allocated
using devm_kzalloc and cleans now unnecessary kfrees in probe and remove
functions. The NULL assignment to np->units is removed as there is no
interaction between this field and sun4v_hvapi_unregister. Also, the
labels out_free_units and out_free are removed as they are no longer
required.
The following Coccinelle semantic patch was used for making the change:
@platform@
identifier p, probefn, removefn;
@@
struct platform_driver p = {
.probe = probefn,
.remove = removefn,
};
@prb@
identifier platform.probefn, pdev;
expression e, e1, e2;
@@
probefn(struct platform_device *pdev, ...) {
<+...
- e = kzalloc(e1, e2)
+ e = devm_kzalloc(&pdev->dev, e1, e2)
...
?-kfree(e);
...+>
}
@rem depends on prb@
identifier platform.removefn;
expression e;
@@
removefn(...) {
<...
- kfree(e);
...>
}
Signed-off-by: Himangi Saraogi <himangi774@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2014-05-10 22:49:00 +04:00
GFP_KERNEL ) ;
2008-06-04 02:56:11 +04:00
err = - ENOMEM ;
if ( ! np - > units )
goto out_hvapi_unregister ;
err = n2rng_init_control ( np ) ;
if ( err )
hwrng: n2-drv - Introduce the use of the managed version of kzalloc
This patch moves data allocated using kzalloc to managed data allocated
using devm_kzalloc and cleans now unnecessary kfrees in probe and remove
functions. The NULL assignment to np->units is removed as there is no
interaction between this field and sun4v_hvapi_unregister. Also, the
labels out_free_units and out_free are removed as they are no longer
required.
The following Coccinelle semantic patch was used for making the change:
@platform@
identifier p, probefn, removefn;
@@
struct platform_driver p = {
.probe = probefn,
.remove = removefn,
};
@prb@
identifier platform.probefn, pdev;
expression e, e1, e2;
@@
probefn(struct platform_device *pdev, ...) {
<+...
- e = kzalloc(e1, e2)
+ e = devm_kzalloc(&pdev->dev, e1, e2)
...
?-kfree(e);
...+>
}
@rem depends on prb@
identifier platform.removefn;
expression e;
@@
removefn(...) {
<...
- kfree(e);
...>
}
Signed-off-by: Himangi Saraogi <himangi774@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2014-05-10 22:49:00 +04:00
goto out_hvapi_unregister ;
2008-06-04 02:56:11 +04:00
dev_info ( & op - > dev , " Found %s RNG, units: %d \n " ,
2011-07-28 10:33:03 +04:00
( ( np - > flags & N2RNG_FLAG_MULTI ) ?
" multi-unit-capable " : " single-unit " ) ,
2008-06-04 02:56:11 +04:00
np - > num_units ) ;
2017-01-12 21:52:49 +03:00
np - > hwrng . name = DRV_MODULE_NAME ;
2008-06-04 02:56:11 +04:00
np - > hwrng . data_read = n2rng_data_read ;
np - > hwrng . priv = ( unsigned long ) np ;
err = hwrng_register ( & np - > hwrng ) ;
if ( err )
hwrng: n2-drv - Introduce the use of the managed version of kzalloc
This patch moves data allocated using kzalloc to managed data allocated
using devm_kzalloc and cleans now unnecessary kfrees in probe and remove
functions. The NULL assignment to np->units is removed as there is no
interaction between this field and sun4v_hvapi_unregister. Also, the
labels out_free_units and out_free are removed as they are no longer
required.
The following Coccinelle semantic patch was used for making the change:
@platform@
identifier p, probefn, removefn;
@@
struct platform_driver p = {
.probe = probefn,
.remove = removefn,
};
@prb@
identifier platform.probefn, pdev;
expression e, e1, e2;
@@
probefn(struct platform_device *pdev, ...) {
<+...
- e = kzalloc(e1, e2)
+ e = devm_kzalloc(&pdev->dev, e1, e2)
...
?-kfree(e);
...+>
}
@rem depends on prb@
identifier platform.removefn;
expression e;
@@
removefn(...) {
<...
- kfree(e);
...>
}
Signed-off-by: Himangi Saraogi <himangi774@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2014-05-10 22:49:00 +04:00
goto out_hvapi_unregister ;
2008-06-04 02:56:11 +04:00
2013-05-29 04:47:29 +04:00
platform_set_drvdata ( op , np ) ;
2008-06-04 02:56:11 +04:00
schedule_delayed_work ( & np - > work , 0 ) ;
return 0 ;
out_hvapi_unregister :
sun4v_hvapi_unregister ( HV_GRP_RNG ) ;
out :
return err ;
}
2012-11-19 22:26:26 +04:00
static int n2rng_remove ( struct platform_device * op )
2008-06-04 02:56:11 +04:00
{
2013-05-29 04:47:29 +04:00
struct n2rng * np = platform_get_drvdata ( op ) ;
2008-06-04 02:56:11 +04:00
np - > flags | = N2RNG_FLAG_SHUTDOWN ;
cancel_delayed_work_sync ( & np - > work ) ;
hwrng_unregister ( & np - > hwrng ) ;
sun4v_hvapi_unregister ( HV_GRP_RNG ) ;
return 0 ;
}
2017-01-12 21:52:47 +03:00
static struct n2rng_template n2_template = {
. id = N2_n2_rng ,
. multi_capable = 0 ,
. chip_version = 1 ,
} ;
static struct n2rng_template vf_template = {
. id = N2_vf_rng ,
. multi_capable = 1 ,
. chip_version = 1 ,
} ;
static struct n2rng_template kt_template = {
. id = N2_kt_rng ,
. multi_capable = 1 ,
. chip_version = 1 ,
} ;
static struct n2rng_template m4_template = {
. id = N2_m4_rng ,
. multi_capable = 1 ,
. chip_version = 2 ,
} ;
static struct n2rng_template m7_template = {
. id = N2_m7_rng ,
. multi_capable = 1 ,
. chip_version = 2 ,
} ;
2008-08-31 12:23:17 +04:00
static const struct of_device_id n2rng_match [ ] = {
2008-06-04 02:56:11 +04:00
{
. name = " random-number-generator " ,
. compatible = " SUNW,n2-rng " ,
2017-01-12 21:52:47 +03:00
. data = & n2_template ,
2008-06-04 02:56:11 +04:00
} ,
{
. name = " random-number-generator " ,
. compatible = " SUNW,vf-rng " ,
2017-01-12 21:52:47 +03:00
. data = & vf_template ,
2008-06-04 02:56:11 +04:00
} ,
2011-07-28 10:33:03 +04:00
{
. name = " random-number-generator " ,
. compatible = " SUNW,kt-rng " ,
2017-01-12 21:52:47 +03:00
. data = & kt_template ,
2011-07-28 10:33:03 +04:00
} ,
2016-01-26 00:19:02 +03:00
{
. name = " random-number-generator " ,
. compatible = " ORCL,m4-rng " ,
2017-01-12 21:52:47 +03:00
. data = & m4_template ,
2016-01-26 00:19:02 +03:00
} ,
{
. name = " random-number-generator " ,
. compatible = " ORCL,m7-rng " ,
2017-01-12 21:52:47 +03:00
. data = & m7_template ,
2016-01-26 00:19:02 +03:00
} ,
2008-06-04 02:56:11 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , n2rng_match ) ;
2011-02-23 06:01:33 +03:00
static struct platform_driver n2rng_driver = {
2010-04-14 03:13:02 +04:00
. driver = {
. name = " n2rng " ,
. of_match_table = n2rng_match ,
} ,
2008-06-04 02:56:11 +04:00
. probe = n2rng_probe ,
2012-12-22 03:12:08 +04:00
. remove = n2rng_remove ,
2008-06-04 02:56:11 +04:00
} ;
2011-11-26 17:11:06 +04:00
module_platform_driver ( n2rng_driver ) ;