Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2019 HiSilicon Limited. */
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         /* copy remaining bytes */
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     /* Wait until the task is finished */
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");