]> err.no Git - linux-2.6/blobdiff - drivers/crypto/hifn_795x.c
pci: VT3336 can't do MSI either
[linux-2.6] / drivers / crypto / hifn_795x.c
index de594bc977428244d55310c2af8b175effd3126b..81f3f950cd7d4c5007a64cadd11c18b61c8c6db2 100644 (file)
@@ -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>
@@ -390,8 +392,8 @@ static atomic_t hifn_dev_number;
 
 struct hifn_desc
 {
-       volatile u32            l;
-       volatile u32            p;
+       volatile __le32         l;
+       volatile __le32         p;
 };
 
 struct hifn_dma {
@@ -458,6 +460,14 @@ struct hifn_device
 
        struct crypto_queue     queue;
        struct list_head        alg_list;
+
+       unsigned int            pk_clk_freq;
+
+#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG
+       unsigned int            rng_wait_time;
+       ktime_t                 rngtime;
+       struct hwrng            rng;
+#endif
 };
 
 #define        HIFN_D_LENGTH                   0x0000ffff
@@ -471,10 +481,10 @@ struct hifn_device
 
 struct hifn_base_command
 {
-       volatile u16            masks;
-       volatile u16            session_num;
-       volatile u16            total_source_count;
-       volatile u16            total_dest_count;
+       volatile __le16         masks;
+       volatile __le16         session_num;
+       volatile __le16         total_source_count;
+       volatile __le16         total_dest_count;
 };
 
 #define        HIFN_BASE_CMD_COMP              0x0100  /* enable compression engine */
@@ -494,10 +504,10 @@ struct hifn_base_command
  */
 struct hifn_crypt_command
 {
-       volatile u16            masks;
-       volatile u16            header_skip;
-       volatile u16            source_count;
-       volatile u16            reserved;
+       volatile __le16                 masks;
+       volatile __le16                 header_skip;
+       volatile __le16                 source_count;
+       volatile __le16                 reserved;
 };
 
 #define        HIFN_CRYPT_CMD_ALG_MASK         0x0003          /* algorithm: */
@@ -654,13 +664,13 @@ struct hifn_context
        atomic_t                sg_num;
 };
 
-#define crypto_alg_to_hifn(alg)        container_of(alg, struct hifn_crypto_alg, alg)
+#define crypto_alg_to_hifn(a)  container_of(a, struct hifn_crypto_alg, alg)
 
 static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg)
 {
        u32 ret;
 
-       ret = readl((char *)(dev->bar[0]) + reg);
+       ret = readl(dev->bar[0] + reg);
 
        return ret;
 }
@@ -669,19 +679,19 @@ static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg)
 {
        u32 ret;
 
-       ret = readl((char *)(dev->bar[1]) + reg);
+       ret = readl(dev->bar[1] + reg);
 
        return ret;
 }
 
 static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
 {
-       writel(val, (char *)(dev->bar[0]) + reg);
+       writel(val, dev->bar[0] + reg);
 }
 
 static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
 {
-       writel(val, (char *)(dev->bar[1]) + reg);
+       writel(val, dev->bar[1] + reg);
 }
 
 static void hifn_wait_puc(struct hifn_device *dev)
@@ -785,6 +795,56 @@ static struct pci2id {
        }
 };
 
+#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG
+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);
 
+#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG
+       /* 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);