Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto: hisilicon/trng - support tfms sharing the device

Since the number of devices is limited, and the number
of tfms may exceed the number of devices, to ensure that
tfms can be successfully allocated, support tfms
sharing the same device.

Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG")
Signed-off-by: Weili Qian <qianweili@huawei.com>
Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Weili Qian and committed by
Herbert Xu
3d313505 ea377793

+87 -36
+87 -36
drivers/crypto/hisilicon/trng/trng.c
··· 40 40 #define SEED_SHIFT_24 24 41 41 #define SEED_SHIFT_16 16 42 42 #define SEED_SHIFT_8 8 43 + #define SW_MAX_RANDOM_BYTES 65520 43 44 44 45 struct hisi_trng_list { 45 46 struct mutex lock; ··· 54 53 struct list_head list; 55 54 struct hwrng rng; 56 55 u32 ver; 57 - bool is_used; 58 - struct mutex mutex; 56 + u32 ctx_num; 57 + /* The bytes of the random number generated since the last seeding. */ 58 + u32 random_bytes; 59 + struct mutex lock; 59 60 }; 60 61 61 62 struct hisi_trng_ctx { ··· 66 63 67 64 static atomic_t trng_active_devs; 68 65 static struct hisi_trng_list trng_devices; 66 + static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); 69 67 70 - static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) 68 + static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) 71 69 { 72 70 u32 val, seed_reg, i; 71 + int ret; 72 + 73 + writel(0x0, trng->base + SW_DRBG_BLOCKS); 73 74 74 75 for (i = 0; i < SW_DRBG_SEED_SIZE; 75 76 i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { ··· 85 78 seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; 86 79 writel(val, trng->base + SW_DRBG_SEED(seed_reg)); 87 80 } 81 + 82 + writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), 83 + trng->base + SW_DRBG_BLOCKS); 84 + writel(0x1, trng->base + SW_DRBG_INIT); 85 + ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, 86 + val, val & BIT(0), SLEEP_US, TIMEOUT_US); 87 + if (ret) { 88 + pr_err("failed to init trng(%d)\n", ret); 89 + return -EIO; 90 + } 91 + 92 + trng->random_bytes = 0; 93 + 94 + return 0; 88 95 } 89 96 90 97 static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, ··· 106 85 { 107 86 struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); 108 87 struct hisi_trng *trng = ctx->trng; 109 - u32 val = 0; 110 - int ret = 0; 88 + int ret; 111 89 112 90 if (slen < SW_DRBG_SEED_SIZE) { 113 91 pr_err("slen(%u) is not matched with trng(%d)\n", slen, ··· 114 94 return -EINVAL; 115 95 } 116 96 117 - writel(0x0, trng->base + SW_DRBG_BLOCKS); 118 - hisi_trng_set_seed(trng, seed); 119 - 120 - writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), 121 - trng->base + SW_DRBG_BLOCKS); 122 - writel(0x1, trng->base + SW_DRBG_INIT); 123 - 124 - ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, 125 - val, val & BIT(0), SLEEP_US, TIMEOUT_US); 126 - if (ret) 127 - pr_err("fail to init trng(%d)\n", ret); 97 + mutex_lock(&trng->lock); 98 + ret = hisi_trng_set_seed(trng, seed); 99 + mutex_unlock(&trng->lock); 128 100 129 101 return ret; 130 102 } 131 103 132 - static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, 133 - unsigned int slen, u8 *dstn, unsigned int dlen) 104 + static int hisi_trng_reseed(struct hisi_trng *trng) 134 105 { 135 - struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); 136 - struct hisi_trng *trng = ctx->trng; 106 + u8 seed[SW_DRBG_SEED_SIZE]; 107 + int size; 108 + 109 + if (!trng->random_bytes) 110 + return 0; 111 + 112 + size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); 113 + if (size != SW_DRBG_SEED_SIZE) 114 + return -EIO; 115 + 116 + return hisi_trng_set_seed(trng, seed); 117 + } 118 + 119 + static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) 120 + { 137 121 u32 data[SW_DRBG_DATA_NUM]; 138 122 u32 currsize = 0; 139 123 u32 val = 0; 140 124 int ret; 141 125 u32 i; 142 126 143 - if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) { 144 - pr_err("dlen(%u) exceeds limit(%d)!\n", dlen, 145 - SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES); 146 - return -EINVAL; 147 - } 127 + ret = hisi_trng_reseed(trng); 128 + if (ret) 129 + return ret; 148 130 149 131 do { 150 132 ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, 151 - val, val & BIT(1), SLEEP_US, TIMEOUT_US); 133 + val, val & BIT(1), SLEEP_US, TIMEOUT_US); 152 134 if (ret) { 153 - pr_err("fail to generate random number(%d)!\n", ret); 135 + pr_err("failed to generate random number(%d)!\n", ret); 154 136 break; 155 137 } 156 138 ··· 167 145 currsize = dlen; 168 146 } 169 147 148 + trng->random_bytes += SW_DRBG_BYTES; 170 149 writel(0x1, trng->base + SW_DRBG_GEN); 171 150 } while (currsize < dlen); 172 151 173 152 return ret; 174 153 } 175 154 155 + static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, 156 + unsigned int slen, u8 *dstn, unsigned int dlen) 157 + { 158 + struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); 159 + struct hisi_trng *trng = ctx->trng; 160 + unsigned int currsize = 0; 161 + unsigned int block_size; 162 + int ret; 163 + 164 + if (!dstn || !dlen) { 165 + pr_err("output is error, dlen %u!\n", dlen); 166 + return -EINVAL; 167 + } 168 + 169 + do { 170 + block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); 171 + mutex_lock(&trng->lock); 172 + ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); 173 + mutex_unlock(&trng->lock); 174 + if (ret) 175 + return ret; 176 + currsize += block_size; 177 + } while (currsize < dlen); 178 + 179 + return 0; 180 + } 181 + 176 182 static int hisi_trng_init(struct crypto_tfm *tfm) 177 183 { 178 184 struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); 179 185 struct hisi_trng *trng; 180 - int ret = -EBUSY; 186 + u32 ctx_num = ~0; 181 187 182 188 mutex_lock(&trng_devices.lock); 183 189 list_for_each_entry(trng, &trng_devices.list, list) { 184 - if (!trng->is_used) { 185 - trng->is_used = true; 190 + if (trng->ctx_num < ctx_num) { 191 + ctx_num = trng->ctx_num; 186 192 ctx->trng = trng; 187 - ret = 0; 188 - break; 189 193 } 190 194 } 195 + ctx->trng->ctx_num++; 191 196 mutex_unlock(&trng_devices.lock); 192 197 193 - return ret; 198 + return 0; 194 199 } 195 200 196 201 static void hisi_trng_exit(struct crypto_tfm *tfm) ··· 225 176 struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); 226 177 227 178 mutex_lock(&trng_devices.lock); 228 - ctx->trng->is_used = false; 179 + ctx->trng->ctx_num--; 229 180 mutex_unlock(&trng_devices.lock); 230 181 } 231 182 ··· 287 238 int ret = -EBUSY; 288 239 289 240 mutex_lock(&trng_devices.lock); 290 - if (!trng->is_used) { 241 + if (!trng->ctx_num) { 291 242 list_del(&trng->list); 292 243 ret = 0; 293 244 } ··· 311 262 if (IS_ERR(trng->base)) 312 263 return PTR_ERR(trng->base); 313 264 314 - trng->is_used = false; 265 + trng->ctx_num = 0; 266 + trng->random_bytes = SW_MAX_RANDOM_BYTES; 267 + mutex_init(&trng->lock); 315 268 trng->ver = readl(trng->base + HISI_TRNG_VERSION); 316 269 if (!trng_devices.is_init) { 317 270 INIT_LIST_HEAD(&trng_devices.list);