KVM: PPC: Book3S HV: Add fast real-mode H_RANDOM implementation.
[cascardo/linux.git] / arch / powerpc / platforms / powernv / rng.c
index 80db439..6eb808f 100644 (file)
 
 struct powernv_rng {
        void __iomem *regs;
+       void __iomem *regs_real;
        unsigned long mask;
 };
 
 static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
 
 
+int powernv_hwrng_present(void)
+{
+       struct powernv_rng *rng;
+
+       rng = get_cpu_var(powernv_rng);
+       put_cpu_var(rng);
+       return rng != NULL;
+}
+
 static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val)
 {
        unsigned long parity;
@@ -46,6 +56,17 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val)
        return val;
 }
 
+int powernv_get_random_real_mode(unsigned long *v)
+{
+       struct powernv_rng *rng;
+
+       rng = raw_cpu_read(powernv_rng);
+
+       *v = rng_whiten(rng, in_rm64(rng->regs_real));
+
+       return 1;
+}
+
 int powernv_get_random_long(unsigned long *v)
 {
        struct powernv_rng *rng;
@@ -80,12 +101,20 @@ static __init void rng_init_per_cpu(struct powernv_rng *rng,
 static __init int rng_create(struct device_node *dn)
 {
        struct powernv_rng *rng;
+       struct resource res;
        unsigned long val;
 
        rng = kzalloc(sizeof(*rng), GFP_KERNEL);
        if (!rng)
                return -ENOMEM;
 
+       if (of_address_to_resource(dn, 0, &res)) {
+               kfree(rng);
+               return -ENXIO;
+       }
+
+       rng->regs_real = (void __iomem *)res.start;
+
        rng->regs = of_iomap(dn, 0);
        if (!rng->regs) {
                kfree(rng);