diff options
author | Patrick McHardy <kaber@trash.net> | 2007-11-20 23:51:52 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-10 16:16:17 -0500 |
commit | fcd06755936d2209b69650d2a7cc99cbcd3ccc67 (patch) | |
tree | 3c4fff3df68f822c636e0b218d3bcb32a23d6dd6 | |
parent | 37a8023ce59bfc1fa24067fd94aee7b286f4c01b (diff) |
[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>
-rw-r--r-- | drivers/crypto/hifn_795x.c | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index de594bc97742..1a197003f1a2 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/highmem.h> | 31 | #include <linux/highmem.h> |
32 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
33 | #include <linux/crypto.h> | 33 | #include <linux/crypto.h> |
34 | #include <linux/hw_random.h> | ||
35 | #include <linux/ktime.h> | ||
34 | 36 | ||
35 | #include <crypto/algapi.h> | 37 | #include <crypto/algapi.h> |
36 | #include <crypto/des.h> | 38 | #include <crypto/des.h> |
@@ -458,6 +460,14 @@ struct hifn_device | |||
458 | 460 | ||
459 | struct crypto_queue queue; | 461 | struct crypto_queue queue; |
460 | struct list_head alg_list; | 462 | struct list_head alg_list; |
463 | |||
464 | unsigned int pk_clk_freq; | ||
465 | |||
466 | #if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) | ||
467 | unsigned int rng_wait_time; | ||
468 | ktime_t rngtime; | ||
469 | struct hwrng rng; | ||
470 | #endif | ||
461 | }; | 471 | }; |
462 | 472 | ||
463 | #define HIFN_D_LENGTH 0x0000ffff | 473 | #define HIFN_D_LENGTH 0x0000ffff |
@@ -785,6 +795,56 @@ static struct pci2id { | |||
785 | } | 795 | } |
786 | }; | 796 | }; |
787 | 797 | ||
798 | #if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) | ||
799 | static int hifn_rng_data_present(struct hwrng *rng, int wait) | ||
800 | { | ||
801 | struct hifn_device *dev = (struct hifn_device *)rng->priv; | ||
802 | s64 nsec; | ||
803 | |||
804 | nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime)); | ||
805 | nsec -= dev->rng_wait_time; | ||
806 | if (nsec <= 0) | ||
807 | return 1; | ||
808 | if (!wait) | ||
809 | return 0; | ||
810 | ndelay(nsec); | ||
811 | return 1; | ||
812 | } | ||
813 | |||
814 | static int hifn_rng_data_read(struct hwrng *rng, u32 *data) | ||
815 | { | ||
816 | struct hifn_device *dev = (struct hifn_device *)rng->priv; | ||
817 | |||
818 | *data = hifn_read_1(dev, HIFN_1_RNG_DATA); | ||
819 | dev->rngtime = ktime_get(); | ||
820 | return 4; | ||
821 | } | ||
822 | |||
823 | static int hifn_register_rng(struct hifn_device *dev) | ||
824 | { | ||
825 | /* | ||
826 | * We must wait at least 256 Pk_clk cycles between two reads of the rng. | ||
827 | */ | ||
828 | dev->rng_wait_time = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) * | ||
829 | 256; | ||
830 | |||
831 | dev->rng.name = dev->name; | ||
832 | dev->rng.data_present = hifn_rng_data_present, | ||
833 | dev->rng.data_read = hifn_rng_data_read, | ||
834 | dev->rng.priv = (unsigned long)dev; | ||
835 | |||
836 | return hwrng_register(&dev->rng); | ||
837 | } | ||
838 | |||
839 | static void hifn_unregister_rng(struct hifn_device *dev) | ||
840 | { | ||
841 | hwrng_unregister(&dev->rng); | ||
842 | } | ||
843 | #else | ||
844 | #define hifn_register_rng(dev) 0 | ||
845 | #define hifn_unregister_rng(dev) | ||
846 | #endif | ||
847 | |||
788 | static int hifn_init_pubrng(struct hifn_device *dev) | 848 | static int hifn_init_pubrng(struct hifn_device *dev) |
789 | { | 849 | { |
790 | int i; | 850 | int i; |
@@ -820,6 +880,11 @@ static int hifn_init_pubrng(struct hifn_device *dev) | |||
820 | dprintk("Chip %s: RNG engine has been successfully initialised.\n", | 880 | dprintk("Chip %s: RNG engine has been successfully initialised.\n", |
821 | dev->name); | 881 | dev->name); |
822 | 882 | ||
883 | #if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) | ||
884 | /* First value must be discarded */ | ||
885 | hifn_read_1(dev, HIFN_1_RNG_DATA); | ||
886 | dev->rngtime = ktime_get(); | ||
887 | #endif | ||
823 | return 0; | 888 | return 0; |
824 | } | 889 | } |
825 | 890 | ||
@@ -952,6 +1017,14 @@ static void hifn_init_pll(struct hifn_device *dev) | |||
952 | /* Switch the engines to the PLL */ | 1017 | /* Switch the engines to the PLL */ |
953 | hifn_write_1(dev, HIFN_1_PLL, pllcfg | | 1018 | hifn_write_1(dev, HIFN_1_PLL, pllcfg | |
954 | HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL); | 1019 | HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL); |
1020 | |||
1021 | /* | ||
1022 | * The Fpk_clk runs at half the total speed. Its frequency is needed to | ||
1023 | * calculate the minimum time between two reads of the rng. Since 33MHz | ||
1024 | * is actually 33.333... we overestimate the frequency here, resulting | ||
1025 | * in slightly larger intervals. | ||
1026 | */ | ||
1027 | dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2; | ||
955 | } | 1028 | } |
956 | 1029 | ||
957 | static void hifn_init_registers(struct hifn_device *dev) | 1030 | 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) | |||
2609 | if (err) | 2682 | if (err) |
2610 | goto err_out_stop_device; | 2683 | goto err_out_stop_device; |
2611 | 2684 | ||
2612 | err = hifn_register_alg(dev); | 2685 | err = hifn_register_rng(dev); |
2613 | if (err) | 2686 | if (err) |
2614 | goto err_out_stop_device; | 2687 | goto err_out_stop_device; |
2615 | 2688 | ||
2689 | err = hifn_register_alg(dev); | ||
2690 | if (err) | ||
2691 | goto err_out_unregister_rng; | ||
2692 | |||
2616 | INIT_DELAYED_WORK(&dev->work, hifn_work); | 2693 | INIT_DELAYED_WORK(&dev->work, hifn_work); |
2617 | schedule_delayed_work(&dev->work, HZ); | 2694 | schedule_delayed_work(&dev->work, HZ); |
2618 | 2695 | ||
@@ -2622,6 +2699,8 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2622 | 2699 | ||
2623 | return 0; | 2700 | return 0; |
2624 | 2701 | ||
2702 | err_out_unregister_rng: | ||
2703 | hifn_unregister_rng(dev); | ||
2625 | err_out_stop_device: | 2704 | err_out_stop_device: |
2626 | hifn_reset_dma(dev, 1); | 2705 | hifn_reset_dma(dev, 1); |
2627 | hifn_stop_device(dev); | 2706 | hifn_stop_device(dev); |
@@ -2662,6 +2741,7 @@ static void hifn_remove(struct pci_dev *pdev) | |||
2662 | cancel_delayed_work(&dev->work); | 2741 | cancel_delayed_work(&dev->work); |
2663 | flush_scheduled_work(); | 2742 | flush_scheduled_work(); |
2664 | 2743 | ||
2744 | hifn_unregister_rng(dev); | ||
2665 | hifn_unregister_alg(dev); | 2745 | hifn_unregister_alg(dev); |
2666 | hifn_reset_dma(dev, 1); | 2746 | hifn_reset_dma(dev, 1); |
2667 | hifn_stop_device(dev); | 2747 | hifn_stop_device(dev); |