X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fcrypto%2Fhifn_795x.c;h=81f3f950cd7d4c5007a64cadd11c18b61c8c6db2;hb=66d715c95a39e84cd25204a665915621457d9691;hp=de594bc977428244d55310c2af8b175effd3126b;hpb=37a8023ce59bfc1fa24067fd94aee7b286f4c01b;p=linux-2.6 diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index de594bc977..81f3f950cd 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -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);