diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2015-03-20 05:39:41 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2015-04-21 09:21:29 -0400 |
commit | e928e9cb3601ce240189bfea05b67ebd391c85ae (patch) | |
tree | d76d6501bea8ffe04a448e5a5660d8926f22b3b4 /arch/powerpc/platforms | |
parent | 99342cf8044420eebdf9297ca03a14cb6a7085a1 (diff) |
KVM: PPC: Book3S HV: Add fast real-mode H_RANDOM implementation.
Some PowerNV systems include a hardware random-number generator.
This HWRNG is present on POWER7+ and POWER8 chips and is capable of
generating one 64-bit random number every microsecond. The random
numbers are produced by sampling a set of 64 unstable high-frequency
oscillators and are almost completely entropic.
PAPR defines an H_RANDOM hypercall which guests can use to obtain one
64-bit random sample from the HWRNG. This adds a real-mode
implementation of the H_RANDOM hypercall. This hypercall was
implemented in real mode because the latency of reading the HWRNG is
generally small compared to the latency of a guest exit and entry for
all the threads in the same virtual core.
Userspace can detect the presence of the HWRNG and the H_RANDOM
implementation by querying the KVM_CAP_PPC_HWRNG capability. The
H_RANDOM hypercall implementation will only be invoked when the guest
does an H_RANDOM hypercall if userspace first enables the in-kernel
H_RANDOM implementation using the KVM_CAP_PPC_ENABLE_HCALL capability.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/powernv/rng.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c index 80db43944afe..6eb808ff637e 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c | |||
@@ -24,12 +24,22 @@ | |||
24 | 24 | ||
25 | struct powernv_rng { | 25 | struct powernv_rng { |
26 | void __iomem *regs; | 26 | void __iomem *regs; |
27 | void __iomem *regs_real; | ||
27 | unsigned long mask; | 28 | unsigned long mask; |
28 | }; | 29 | }; |
29 | 30 | ||
30 | static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng); | 31 | static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng); |
31 | 32 | ||
32 | 33 | ||
34 | int powernv_hwrng_present(void) | ||
35 | { | ||
36 | struct powernv_rng *rng; | ||
37 | |||
38 | rng = get_cpu_var(powernv_rng); | ||
39 | put_cpu_var(rng); | ||
40 | return rng != NULL; | ||
41 | } | ||
42 | |||
33 | static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) | 43 | static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) |
34 | { | 44 | { |
35 | unsigned long parity; | 45 | unsigned long parity; |
@@ -46,6 +56,17 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) | |||
46 | return val; | 56 | return val; |
47 | } | 57 | } |
48 | 58 | ||
59 | int powernv_get_random_real_mode(unsigned long *v) | ||
60 | { | ||
61 | struct powernv_rng *rng; | ||
62 | |||
63 | rng = raw_cpu_read(powernv_rng); | ||
64 | |||
65 | *v = rng_whiten(rng, in_rm64(rng->regs_real)); | ||
66 | |||
67 | return 1; | ||
68 | } | ||
69 | |||
49 | int powernv_get_random_long(unsigned long *v) | 70 | int powernv_get_random_long(unsigned long *v) |
50 | { | 71 | { |
51 | struct powernv_rng *rng; | 72 | struct powernv_rng *rng; |
@@ -80,12 +101,20 @@ static __init void rng_init_per_cpu(struct powernv_rng *rng, | |||
80 | static __init int rng_create(struct device_node *dn) | 101 | static __init int rng_create(struct device_node *dn) |
81 | { | 102 | { |
82 | struct powernv_rng *rng; | 103 | struct powernv_rng *rng; |
104 | struct resource res; | ||
83 | unsigned long val; | 105 | unsigned long val; |
84 | 106 | ||
85 | rng = kzalloc(sizeof(*rng), GFP_KERNEL); | 107 | rng = kzalloc(sizeof(*rng), GFP_KERNEL); |
86 | if (!rng) | 108 | if (!rng) |
87 | return -ENOMEM; | 109 | return -ENOMEM; |
88 | 110 | ||
111 | if (of_address_to_resource(dn, 0, &res)) { | ||
112 | kfree(rng); | ||
113 | return -ENXIO; | ||
114 | } | ||
115 | |||
116 | rng->regs_real = (void __iomem *)res.start; | ||
117 | |||
89 | rng->regs = of_iomap(dn, 0); | 118 | rng->regs = of_iomap(dn, 0); |
90 | if (!rng->regs) { | 119 | if (!rng->regs) { |
91 | kfree(rng); | 120 | kfree(rng); |