mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-07 04:09:21 +00:00
[HIFN]: Add support for using the random number generator
Signed-off-by: Patrick McHardy <kaber@trash.net> Acked-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
37a8023ce5
commit
fcd0675593
1 changed files with 81 additions and 1 deletions
|
@ -31,6 +31,8 @@
|
|||
#include <linux/highmem.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/des.h>
|
||||
|
@ -458,6 +460,14 @@ struct hifn_device
|
|||
|
||||
struct crypto_queue queue;
|
||||
struct list_head alg_list;
|
||||
|
||||
unsigned int pk_clk_freq;
|
||||
|
||||
#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE)
|
||||
unsigned int rng_wait_time;
|
||||
ktime_t rngtime;
|
||||
struct hwrng rng;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define HIFN_D_LENGTH 0x0000ffff
|
||||
|
@ -785,6 +795,56 @@ static struct pci2id {
|
|||
}
|
||||
};
|
||||
|
||||
#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE)
|
||||
static int hifn_rng_data_present(struct hwrng *rng, int wait)
|
||||
{
|
||||
struct hifn_device *dev = (struct hifn_device *)rng->priv;
|
||||
s64 nsec;
|
||||
|
||||
nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime));
|
||||
nsec -= dev->rng_wait_time;
|
||||
if (nsec <= 0)
|
||||
return 1;
|
||||
if (!wait)
|
||||
return 0;
|
||||
ndelay(nsec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hifn_rng_data_read(struct hwrng *rng, u32 *data)
|
||||
{
|
||||
struct hifn_device *dev = (struct hifn_device *)rng->priv;
|
||||
|
||||
*data = hifn_read_1(dev, HIFN_1_RNG_DATA);
|
||||
dev->rngtime = ktime_get();
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int hifn_register_rng(struct hifn_device *dev)
|
||||
{
|
||||
/*
|
||||
* We must wait at least 256 Pk_clk cycles between two reads of the rng.
|
||||
*/
|
||||
dev->rng_wait_time = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) *
|
||||
256;
|
||||
|
||||
dev->rng.name = dev->name;
|
||||
dev->rng.data_present = hifn_rng_data_present,
|
||||
dev->rng.data_read = hifn_rng_data_read,
|
||||
dev->rng.priv = (unsigned long)dev;
|
||||
|
||||
return hwrng_register(&dev->rng);
|
||||
}
|
||||
|
||||
static void hifn_unregister_rng(struct hifn_device *dev)
|
||||
{
|
||||
hwrng_unregister(&dev->rng);
|
||||
}
|
||||
#else
|
||||
#define hifn_register_rng(dev) 0
|
||||
#define hifn_unregister_rng(dev)
|
||||
#endif
|
||||
|
||||
static int hifn_init_pubrng(struct hifn_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
@ -820,6 +880,11 @@ static int hifn_init_pubrng(struct hifn_device *dev)
|
|||
dprintk("Chip %s: RNG engine has been successfully initialised.\n",
|
||||
dev->name);
|
||||
|
||||
#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE)
|
||||
/* First value must be discarded */
|
||||
hifn_read_1(dev, HIFN_1_RNG_DATA);
|
||||
dev->rngtime = ktime_get();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -952,6 +1017,14 @@ static void hifn_init_pll(struct hifn_device *dev)
|
|||
/* Switch the engines to the PLL */
|
||||
hifn_write_1(dev, HIFN_1_PLL, pllcfg |
|
||||
HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL);
|
||||
|
||||
/*
|
||||
* The Fpk_clk runs at half the total speed. Its frequency is needed to
|
||||
* calculate the minimum time between two reads of the rng. Since 33MHz
|
||||
* is actually 33.333... we overestimate the frequency here, resulting
|
||||
* in slightly larger intervals.
|
||||
*/
|
||||
dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2;
|
||||
}
|
||||
|
||||
static void hifn_init_registers(struct hifn_device *dev)
|
||||
|
@ -2609,10 +2682,14 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (err)
|
||||
goto err_out_stop_device;
|
||||
|
||||
err = hifn_register_alg(dev);
|
||||
err = hifn_register_rng(dev);
|
||||
if (err)
|
||||
goto err_out_stop_device;
|
||||
|
||||
err = hifn_register_alg(dev);
|
||||
if (err)
|
||||
goto err_out_unregister_rng;
|
||||
|
||||
INIT_DELAYED_WORK(&dev->work, hifn_work);
|
||||
schedule_delayed_work(&dev->work, HZ);
|
||||
|
||||
|
@ -2622,6 +2699,8 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
return 0;
|
||||
|
||||
err_out_unregister_rng:
|
||||
hifn_unregister_rng(dev);
|
||||
err_out_stop_device:
|
||||
hifn_reset_dma(dev, 1);
|
||||
hifn_stop_device(dev);
|
||||
|
@ -2662,6 +2741,7 @@ static void hifn_remove(struct pci_dev *pdev)
|
|||
cancel_delayed_work(&dev->work);
|
||||
flush_scheduled_work();
|
||||
|
||||
hifn_unregister_rng(dev);
|
||||
hifn_unregister_alg(dev);
|
||||
hifn_reset_dma(dev, 1);
|
||||
hifn_stop_device(dev);
|
||||
|
|
Loading…
Reference in a new issue