kernel: move console loglevel to generic
[oweals/openwrt.git] / target / linux / sunxi / patches-4.9 / 0054-crypto-sun4i-ss_support_the_Security_System_PRNG.patch
1 From b8ae5c7387ad075ee61e8c8774ce2bca46bc9236 Mon Sep 17 00:00:00 2001
2 From: Corentin LABBE <clabbe.montjoie@gmail.com>
3 Date: Mon, 3 Jul 2017 20:48:48 +0200
4 Subject: crypto: sun4i-ss - support the Security System PRNG
5
6 The Security System has a PRNG, this patch adds support for it via
7 crypto_rng.
8
9 Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
10 Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
11 ---
12  drivers/crypto/Kconfig                  |  8 +++++
13  drivers/crypto/sunxi-ss/Makefile        |  1 +
14  drivers/crypto/sunxi-ss/sun4i-ss-core.c | 30 ++++++++++++++++++
15  drivers/crypto/sunxi-ss/sun4i-ss-prng.c | 56 +++++++++++++++++++++++++++++++++
16  drivers/crypto/sunxi-ss/sun4i-ss.h      | 11 +++++++
17  5 files changed, 106 insertions(+)
18  create mode 100644 drivers/crypto/sunxi-ss/sun4i-ss-prng.c
19
20 --- a/drivers/crypto/Kconfig
21 +++ b/drivers/crypto/Kconfig
22 @@ -538,6 +538,14 @@ config CRYPTO_DEV_SUN4I_SS
23           To compile this driver as a module, choose M here: the module
24           will be called sun4i-ss.
25  
26 +config CRYPTO_DEV_SUN4I_SS_PRNG
27 +       bool "Support for Allwinner Security System PRNG"
28 +       depends on CRYPTO_DEV_SUN4I_SS
29 +       select CRYPTO_RNG
30 +       help
31 +         Select this option if you want to provide kernel-side support for
32 +         the Pseudo-Random Number Generator found in the Security System.
33 +
34  config CRYPTO_DEV_ROCKCHIP
35         tristate "Rockchip's Cryptographic Engine driver"
36         depends on OF && ARCH_ROCKCHIP
37 --- a/drivers/crypto/sunxi-ss/Makefile
38 +++ b/drivers/crypto/sunxi-ss/Makefile
39 @@ -1,2 +1,3 @@
40  obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
41  sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
42 +sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
43 --- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c
44 +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
45 @@ -214,6 +214,23 @@ static struct sun4i_ss_alg_template ss_a
46                 }
47         }
48  },
49 +#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
50 +{
51 +       .type = CRYPTO_ALG_TYPE_RNG,
52 +       .alg.rng = {
53 +               .base = {
54 +                       .cra_name               = "stdrng",
55 +                       .cra_driver_name        = "sun4i_ss_rng",
56 +                       .cra_priority           = 300,
57 +                       .cra_ctxsize            = 0,
58 +                       .cra_module             = THIS_MODULE,
59 +               },
60 +               .generate               = sun4i_ss_prng_generate,
61 +               .seed                   = sun4i_ss_prng_seed,
62 +               .seedsize               = SS_SEED_LEN / BITS_PER_BYTE,
63 +       }
64 +},
65 +#endif
66  };
67  
68  static int sun4i_ss_probe(struct platform_device *pdev)
69 @@ -356,6 +373,13 @@ static int sun4i_ss_probe(struct platfor
70                                 goto error_alg;
71                         }
72                         break;
73 +               case CRYPTO_ALG_TYPE_RNG:
74 +                       err = crypto_register_rng(&ss_algs[i].alg.rng);
75 +                       if (err) {
76 +                               dev_err(ss->dev, "Fail to register %s\n",
77 +                                       ss_algs[i].alg.rng.base.cra_name);
78 +                       }
79 +                       break;
80                 }
81         }
82         platform_set_drvdata(pdev, ss);
83 @@ -370,6 +394,9 @@ error_alg:
84                 case CRYPTO_ALG_TYPE_AHASH:
85                         crypto_unregister_ahash(&ss_algs[i].alg.hash);
86                         break;
87 +               case CRYPTO_ALG_TYPE_RNG:
88 +                       crypto_unregister_rng(&ss_algs[i].alg.rng);
89 +                       break;
90                 }
91         }
92         if (ss->reset)
93 @@ -394,6 +421,9 @@ static int sun4i_ss_remove(struct platfo
94                 case CRYPTO_ALG_TYPE_AHASH:
95                         crypto_unregister_ahash(&ss_algs[i].alg.hash);
96                         break;
97 +               case CRYPTO_ALG_TYPE_RNG:
98 +                       crypto_unregister_rng(&ss_algs[i].alg.rng);
99 +                       break;
100                 }
101         }
102  
103 --- /dev/null
104 +++ b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c
105 @@ -0,0 +1,56 @@
106 +#include "sun4i-ss.h"
107 +
108 +int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
109 +                      unsigned int slen)
110 +{
111 +       struct sun4i_ss_alg_template *algt;
112 +       struct rng_alg *alg = crypto_rng_alg(tfm);
113 +
114 +       algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
115 +       memcpy(algt->ss->seed, seed, slen);
116 +
117 +       return 0;
118 +}
119 +
120 +int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
121 +                          unsigned int slen, u8 *dst, unsigned int dlen)
122 +{
123 +       struct sun4i_ss_alg_template *algt;
124 +       struct rng_alg *alg = crypto_rng_alg(tfm);
125 +       int i;
126 +       u32 v;
127 +       u32 *data = (u32 *)dst;
128 +       const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
129 +       size_t len;
130 +       struct sun4i_ss_ctx *ss;
131 +       unsigned int todo = (dlen / 4) * 4;
132 +
133 +       algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
134 +       ss = algt->ss;
135 +
136 +       spin_lock(&ss->slock);
137 +
138 +       writel(mode, ss->base + SS_CTL);
139 +
140 +       while (todo > 0) {
141 +               /* write the seed */
142 +               for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
143 +                       writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
144 +
145 +               /* Read the random data */
146 +               len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
147 +               readsl(ss->base + SS_TXFIFO, data, len / 4);
148 +               data += len / 4;
149 +               todo -= len;
150 +
151 +               /* Update the seed */
152 +               for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
153 +                       v = readl(ss->base + SS_KEY0 + i * 4);
154 +                       ss->seed[i] = v;
155 +               }
156 +       }
157 +
158 +       writel(0, ss->base + SS_CTL);
159 +       spin_unlock(&ss->slock);
160 +       return dlen;
161 +}
162 --- a/drivers/crypto/sunxi-ss/sun4i-ss.h
163 +++ b/drivers/crypto/sunxi-ss/sun4i-ss.h
164 @@ -30,6 +30,7 @@
165  #include <crypto/aes.h>
166  #include <crypto/des.h>
167  #include <crypto/internal/rng.h>
168 +#include <crypto/rng.h>
169  
170  #define SS_CTL            0x00
171  #define SS_KEY0           0x04
172 @@ -125,6 +126,9 @@
173  #define SS_RXFIFO_EMP_INT_ENABLE       (1 << 2)
174  #define SS_TXFIFO_AVA_INT_ENABLE       (1 << 0)
175  
176 +#define SS_SEED_LEN 192
177 +#define SS_DATA_LEN 160
178 +
179  struct sun4i_ss_ctx {
180         void __iomem *base;
181         int irq;
182 @@ -134,6 +138,9 @@ struct sun4i_ss_ctx {
183         struct device *dev;
184         struct resource *res;
185         spinlock_t slock; /* control the use of the device */
186 +#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
187 +       u32 seed[SS_SEED_LEN / BITS_PER_LONG];
188 +#endif
189  };
190  
191  struct sun4i_ss_alg_template {
192 @@ -142,6 +149,7 @@ struct sun4i_ss_alg_template {
193         union {
194                 struct crypto_alg crypto;
195                 struct ahash_alg hash;
196 +               struct rng_alg rng;
197         } alg;
198         struct sun4i_ss_ctx *ss;
199  };
200 @@ -199,3 +207,6 @@ int sun4i_ss_des_setkey(struct crypto_ab
201                         unsigned int keylen);
202  int sun4i_ss_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
203                          unsigned int keylen);
204 +int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
205 +                          unsigned int slen, u8 *dst, unsigned int dlen);
206 +int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);