0001
0002
0003
0004 #include <linux/acpi.h>
0005 #include <linux/crypto.h>
0006 #include <linux/err.h>
0007 #include <linux/hw_random.h>
0008 #include <linux/io.h>
0009 #include <linux/iopoll.h>
0010 #include <linux/kernel.h>
0011 #include <linux/list.h>
0012 #include <linux/module.h>
0013 #include <linux/mutex.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/random.h>
0016 #include <crypto/internal/rng.h>
0017
0018 #define HISI_TRNG_REG 0x00F0
0019 #define HISI_TRNG_BYTES 4
0020 #define HISI_TRNG_QUALITY 512
0021 #define HISI_TRNG_VERSION 0x01B8
0022 #define HISI_TRNG_VER_V1 GENMASK(31, 0)
0023 #define SLEEP_US 10
0024 #define TIMEOUT_US 10000
0025 #define SW_DRBG_NUM_SHIFT 2
0026 #define SW_DRBG_KEY_BASE 0x082C
0027 #define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
0028 #define SW_DRBG_SEED_REGS_NUM 12
0029 #define SW_DRBG_SEED_SIZE 48
0030 #define SW_DRBG_BLOCKS 0x0830
0031 #define SW_DRBG_INIT 0x0834
0032 #define SW_DRBG_GEN 0x083c
0033 #define SW_DRBG_STATUS 0x0840
0034 #define SW_DRBG_BLOCKS_NUM 4095
0035 #define SW_DRBG_DATA_BASE 0x0850
0036 #define SW_DRBG_DATA_NUM 4
0037 #define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
0038 #define SW_DRBG_BYTES 16
0039 #define SW_DRBG_ENABLE_SHIFT 12
0040 #define SEED_SHIFT_24 24
0041 #define SEED_SHIFT_16 16
0042 #define SEED_SHIFT_8 8
0043
0044 struct hisi_trng_list {
0045 struct mutex lock;
0046 struct list_head list;
0047 bool is_init;
0048 };
0049
0050 struct hisi_trng {
0051 void __iomem *base;
0052 struct hisi_trng_list *trng_list;
0053 struct list_head list;
0054 struct hwrng rng;
0055 u32 ver;
0056 bool is_used;
0057 struct mutex mutex;
0058 };
0059
0060 struct hisi_trng_ctx {
0061 struct hisi_trng *trng;
0062 };
0063
0064 static atomic_t trng_active_devs;
0065 static struct hisi_trng_list trng_devices;
0066
0067 static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
0068 {
0069 u32 val, seed_reg, i;
0070
0071 for (i = 0; i < SW_DRBG_SEED_SIZE;
0072 i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
0073 val = seed[i] << SEED_SHIFT_24;
0074 val |= seed[i + 1UL] << SEED_SHIFT_16;
0075 val |= seed[i + 2UL] << SEED_SHIFT_8;
0076 val |= seed[i + 3UL];
0077
0078 seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
0079 writel(val, trng->base + SW_DRBG_SEED(seed_reg));
0080 }
0081 }
0082
0083 static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
0084 unsigned int slen)
0085 {
0086 struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
0087 struct hisi_trng *trng = ctx->trng;
0088 u32 val = 0;
0089 int ret = 0;
0090
0091 if (slen < SW_DRBG_SEED_SIZE) {
0092 pr_err("slen(%u) is not matched with trng(%d)\n", slen,
0093 SW_DRBG_SEED_SIZE);
0094 return -EINVAL;
0095 }
0096
0097 writel(0x0, trng->base + SW_DRBG_BLOCKS);
0098 hisi_trng_set_seed(trng, seed);
0099
0100 writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
0101 trng->base + SW_DRBG_BLOCKS);
0102 writel(0x1, trng->base + SW_DRBG_INIT);
0103
0104 ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
0105 val, val & BIT(0), SLEEP_US, TIMEOUT_US);
0106 if (ret)
0107 pr_err("fail to init trng(%d)\n", ret);
0108
0109 return ret;
0110 }
0111
0112 static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
0113 unsigned int slen, u8 *dstn, unsigned int dlen)
0114 {
0115 struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
0116 struct hisi_trng *trng = ctx->trng;
0117 u32 data[SW_DRBG_DATA_NUM];
0118 u32 currsize = 0;
0119 u32 val = 0;
0120 int ret;
0121 u32 i;
0122
0123 if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) {
0124 pr_err("dlen(%d) exceeds limit(%d)!\n", dlen,
0125 SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES);
0126 return -EINVAL;
0127 }
0128
0129 do {
0130 ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
0131 val, val & BIT(1), SLEEP_US, TIMEOUT_US);
0132 if (ret) {
0133 pr_err("fail to generate random number(%d)!\n", ret);
0134 break;
0135 }
0136
0137 for (i = 0; i < SW_DRBG_DATA_NUM; i++)
0138 data[i] = readl(trng->base + SW_DRBG_DATA(i));
0139
0140 if (dlen - currsize >= SW_DRBG_BYTES) {
0141 memcpy(dstn + currsize, data, SW_DRBG_BYTES);
0142 currsize += SW_DRBG_BYTES;
0143 } else {
0144 memcpy(dstn + currsize, data, dlen - currsize);
0145 currsize = dlen;
0146 }
0147
0148 writel(0x1, trng->base + SW_DRBG_GEN);
0149 } while (currsize < dlen);
0150
0151 return ret;
0152 }
0153
0154 static int hisi_trng_init(struct crypto_tfm *tfm)
0155 {
0156 struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
0157 struct hisi_trng *trng;
0158 int ret = -EBUSY;
0159
0160 mutex_lock(&trng_devices.lock);
0161 list_for_each_entry(trng, &trng_devices.list, list) {
0162 if (!trng->is_used) {
0163 trng->is_used = true;
0164 ctx->trng = trng;
0165 ret = 0;
0166 break;
0167 }
0168 }
0169 mutex_unlock(&trng_devices.lock);
0170
0171 return ret;
0172 }
0173
0174 static void hisi_trng_exit(struct crypto_tfm *tfm)
0175 {
0176 struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
0177
0178 mutex_lock(&trng_devices.lock);
0179 ctx->trng->is_used = false;
0180 mutex_unlock(&trng_devices.lock);
0181 }
0182
0183 static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
0184 {
0185 struct hisi_trng *trng;
0186 int currsize = 0;
0187 u32 val = 0;
0188 int ret;
0189
0190 trng = container_of(rng, struct hisi_trng, rng);
0191
0192 do {
0193 ret = readl_poll_timeout(trng->base + HISI_TRNG_REG, val,
0194 val, SLEEP_US, TIMEOUT_US);
0195 if (ret)
0196 return currsize;
0197
0198 if (max - currsize >= HISI_TRNG_BYTES) {
0199 memcpy(buf + currsize, &val, HISI_TRNG_BYTES);
0200 currsize += HISI_TRNG_BYTES;
0201 if (currsize == max)
0202 return currsize;
0203 continue;
0204 }
0205
0206
0207 memcpy(buf + currsize, &val, max - currsize);
0208 currsize = max;
0209 } while (currsize < max);
0210
0211 return currsize;
0212 }
0213
0214 static struct rng_alg hisi_trng_alg = {
0215 .generate = hisi_trng_generate,
0216 .seed = hisi_trng_seed,
0217 .seedsize = SW_DRBG_SEED_SIZE,
0218 .base = {
0219 .cra_name = "stdrng",
0220 .cra_driver_name = "hisi_stdrng",
0221 .cra_priority = 300,
0222 .cra_ctxsize = sizeof(struct hisi_trng_ctx),
0223 .cra_module = THIS_MODULE,
0224 .cra_init = hisi_trng_init,
0225 .cra_exit = hisi_trng_exit,
0226 },
0227 };
0228
0229 static void hisi_trng_add_to_list(struct hisi_trng *trng)
0230 {
0231 mutex_lock(&trng_devices.lock);
0232 list_add_tail(&trng->list, &trng_devices.list);
0233 mutex_unlock(&trng_devices.lock);
0234 }
0235
0236 static int hisi_trng_del_from_list(struct hisi_trng *trng)
0237 {
0238 int ret = -EBUSY;
0239
0240 mutex_lock(&trng_devices.lock);
0241 if (!trng->is_used) {
0242 list_del(&trng->list);
0243 ret = 0;
0244 }
0245 mutex_unlock(&trng_devices.lock);
0246
0247 return ret;
0248 }
0249
0250 static int hisi_trng_probe(struct platform_device *pdev)
0251 {
0252 struct hisi_trng *trng;
0253 int ret;
0254
0255 trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
0256 if (!trng)
0257 return -ENOMEM;
0258
0259 platform_set_drvdata(pdev, trng);
0260
0261 trng->base = devm_platform_ioremap_resource(pdev, 0);
0262 if (IS_ERR(trng->base))
0263 return PTR_ERR(trng->base);
0264
0265 trng->is_used = false;
0266 trng->ver = readl(trng->base + HISI_TRNG_VERSION);
0267 if (!trng_devices.is_init) {
0268 INIT_LIST_HEAD(&trng_devices.list);
0269 mutex_init(&trng_devices.lock);
0270 trng_devices.is_init = true;
0271 }
0272
0273 hisi_trng_add_to_list(trng);
0274 if (trng->ver != HISI_TRNG_VER_V1 &&
0275 atomic_inc_return(&trng_active_devs) == 1) {
0276 ret = crypto_register_rng(&hisi_trng_alg);
0277 if (ret) {
0278 dev_err(&pdev->dev,
0279 "failed to register crypto(%d)\n", ret);
0280 atomic_dec_return(&trng_active_devs);
0281 goto err_remove_from_list;
0282 }
0283 }
0284
0285 trng->rng.name = pdev->name;
0286 trng->rng.read = hisi_trng_read;
0287 trng->rng.quality = HISI_TRNG_QUALITY;
0288 ret = devm_hwrng_register(&pdev->dev, &trng->rng);
0289 if (ret) {
0290 dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
0291 goto err_crypto_unregister;
0292 }
0293
0294 return ret;
0295
0296 err_crypto_unregister:
0297 if (trng->ver != HISI_TRNG_VER_V1 &&
0298 atomic_dec_return(&trng_active_devs) == 0)
0299 crypto_unregister_rng(&hisi_trng_alg);
0300
0301 err_remove_from_list:
0302 hisi_trng_del_from_list(trng);
0303 return ret;
0304 }
0305
0306 static int hisi_trng_remove(struct platform_device *pdev)
0307 {
0308 struct hisi_trng *trng = platform_get_drvdata(pdev);
0309
0310
0311 while (hisi_trng_del_from_list(trng))
0312 ;
0313
0314 if (trng->ver != HISI_TRNG_VER_V1 &&
0315 atomic_dec_return(&trng_active_devs) == 0)
0316 crypto_unregister_rng(&hisi_trng_alg);
0317
0318 return 0;
0319 }
0320
0321 static const struct acpi_device_id hisi_trng_acpi_match[] = {
0322 { "HISI02B3", 0 },
0323 { }
0324 };
0325 MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
0326
0327 static struct platform_driver hisi_trng_driver = {
0328 .probe = hisi_trng_probe,
0329 .remove = hisi_trng_remove,
0330 .driver = {
0331 .name = "hisi-trng-v2",
0332 .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
0333 },
0334 };
0335
0336 module_platform_driver(hisi_trng_driver);
0337
0338 MODULE_LICENSE("GPL v2");
0339 MODULE_AUTHOR("Weili Qian <qianweili@huawei.com>");
0340 MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
0341 MODULE_DESCRIPTION("HiSilicon true random number generator V2 driver");