2016-08-24 02:27:15 +03:00
/*
* Hardware Random Number Generator support for Cavium , Inc .
* Thunder processor family .
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2016 Cavium , Inc .
*/
# include <linux/hw_random.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/pci_ids.h>
struct cavium_rng {
struct hwrng ops ;
void __iomem * result ;
} ;
/* Read data from the RNG unit */
static int cavium_rng_read ( struct hwrng * rng , void * dat , size_t max , bool wait )
{
struct cavium_rng * p = container_of ( rng , struct cavium_rng , ops ) ;
unsigned int size = max ;
while ( size > = 8 ) {
* ( ( u64 * ) dat ) = readq ( p - > result ) ;
size - = 8 ;
dat + = 8 ;
}
while ( size > 0 ) {
* ( ( u8 * ) dat ) = readb ( p - > result ) ;
size - - ;
dat + + ;
}
return max ;
}
/* Map Cavium RNG to an HWRNG object */
static int cavium_rng_probe_vf ( struct pci_dev * pdev ,
const struct pci_device_id * id )
{
struct cavium_rng * rng ;
int ret ;
rng = devm_kzalloc ( & pdev - > dev , sizeof ( * rng ) , GFP_KERNEL ) ;
if ( ! rng )
return - ENOMEM ;
/* Map the RNG result */
rng - > result = pcim_iomap ( pdev , 0 , 0 ) ;
if ( ! rng - > result ) {
dev_err ( & pdev - > dev , " Error iomap failed retrieving result. \n " ) ;
return - ENOMEM ;
}
2017-02-07 01:28:46 +03:00
rng - > ops . name = devm_kasprintf ( & pdev - > dev , GFP_KERNEL ,
" cavium-rng-%s " , dev_name ( & pdev - > dev ) ) ;
if ( ! rng - > ops . name )
return - ENOMEM ;
2016-08-24 02:27:15 +03:00
rng - > ops . read = cavium_rng_read ;
rng - > ops . quality = 1000 ;
pci_set_drvdata ( pdev , rng ) ;
ret = hwrng_register ( & rng - > ops ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Error registering device as HWRNG. \n " ) ;
return ret ;
}
return 0 ;
}
/* Remove the VF */
2018-02-26 17:51:19 +03:00
static void cavium_rng_remove_vf ( struct pci_dev * pdev )
2016-08-24 02:27:15 +03:00
{
struct cavium_rng * rng ;
rng = pci_get_drvdata ( pdev ) ;
hwrng_unregister ( & rng - > ops ) ;
}
static const struct pci_device_id cavium_rng_vf_id_table [ ] = {
{ PCI_DEVICE ( PCI_VENDOR_ID_CAVIUM , 0xa033 ) , 0 , 0 , 0 } ,
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , cavium_rng_vf_id_table ) ;
static struct pci_driver cavium_rng_vf_driver = {
. name = " cavium_rng_vf " ,
. id_table = cavium_rng_vf_id_table ,
. probe = cavium_rng_probe_vf ,
. remove = cavium_rng_remove_vf ,
} ;
module_pci_driver ( cavium_rng_vf_driver ) ;
MODULE_AUTHOR ( " Omer Khaliq <okhaliq@caviumnetworks.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;