cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

imx-rngc.c (8495B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * RNG driver for Freescale RNGC
      4 *
      5 * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
      6 * Copyright (C) 2017 Martin Kaiser <martin@kaiser.cx>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/mod_devicetable.h>
     11#include <linux/init.h>
     12#include <linux/kernel.h>
     13#include <linux/clk.h>
     14#include <linux/err.h>
     15#include <linux/platform_device.h>
     16#include <linux/interrupt.h>
     17#include <linux/hw_random.h>
     18#include <linux/completion.h>
     19#include <linux/io.h>
     20
     21#define RNGC_VER_ID			0x0000
     22#define RNGC_COMMAND			0x0004
     23#define RNGC_CONTROL			0x0008
     24#define RNGC_STATUS			0x000C
     25#define RNGC_ERROR			0x0010
     26#define RNGC_FIFO			0x0014
     27
     28/* the fields in the ver id register */
     29#define RNGC_TYPE_SHIFT		28
     30#define RNGC_VER_MAJ_SHIFT		8
     31
     32/* the rng_type field */
     33#define RNGC_TYPE_RNGB			0x1
     34#define RNGC_TYPE_RNGC			0x2
     35
     36
     37#define RNGC_CMD_CLR_ERR		0x00000020
     38#define RNGC_CMD_CLR_INT		0x00000010
     39#define RNGC_CMD_SEED			0x00000002
     40#define RNGC_CMD_SELF_TEST		0x00000001
     41
     42#define RNGC_CTRL_MASK_ERROR		0x00000040
     43#define RNGC_CTRL_MASK_DONE		0x00000020
     44#define RNGC_CTRL_AUTO_SEED		0x00000010
     45
     46#define RNGC_STATUS_ERROR		0x00010000
     47#define RNGC_STATUS_FIFO_LEVEL_MASK	0x00000f00
     48#define RNGC_STATUS_FIFO_LEVEL_SHIFT	8
     49#define RNGC_STATUS_SEED_DONE		0x00000020
     50#define RNGC_STATUS_ST_DONE		0x00000010
     51
     52#define RNGC_ERROR_STATUS_STAT_ERR	0x00000008
     53
     54#define RNGC_TIMEOUT  3000 /* 3 sec */
     55
     56
     57static bool self_test = true;
     58module_param(self_test, bool, 0);
     59
     60struct imx_rngc {
     61	struct device		*dev;
     62	struct clk		*clk;
     63	void __iomem		*base;
     64	struct hwrng		rng;
     65	struct completion	rng_op_done;
     66	/*
     67	 * err_reg is written only by the irq handler and read only
     68	 * when interrupts are masked, we need no spinlock
     69	 */
     70	u32			err_reg;
     71};
     72
     73
     74static inline void imx_rngc_irq_mask_clear(struct imx_rngc *rngc)
     75{
     76	u32 ctrl, cmd;
     77
     78	/* mask interrupts */
     79	ctrl = readl(rngc->base + RNGC_CONTROL);
     80	ctrl |= RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR;
     81	writel(ctrl, rngc->base + RNGC_CONTROL);
     82
     83	/*
     84	 * CLR_INT clears the interrupt only if there's no error
     85	 * CLR_ERR clear the interrupt and the error register if there
     86	 * is an error
     87	 */
     88	cmd = readl(rngc->base + RNGC_COMMAND);
     89	cmd |= RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR;
     90	writel(cmd, rngc->base + RNGC_COMMAND);
     91}
     92
     93static inline void imx_rngc_irq_unmask(struct imx_rngc *rngc)
     94{
     95	u32 ctrl;
     96
     97	ctrl = readl(rngc->base + RNGC_CONTROL);
     98	ctrl &= ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR);
     99	writel(ctrl, rngc->base + RNGC_CONTROL);
    100}
    101
    102static int imx_rngc_self_test(struct imx_rngc *rngc)
    103{
    104	u32 cmd;
    105	int ret;
    106
    107	imx_rngc_irq_unmask(rngc);
    108
    109	/* run self test */
    110	cmd = readl(rngc->base + RNGC_COMMAND);
    111	writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND);
    112
    113	ret = wait_for_completion_timeout(&rngc->rng_op_done, RNGC_TIMEOUT);
    114	imx_rngc_irq_mask_clear(rngc);
    115	if (!ret)
    116		return -ETIMEDOUT;
    117
    118	return rngc->err_reg ? -EIO : 0;
    119}
    120
    121static int imx_rngc_read(struct hwrng *rng, void *data, size_t max, bool wait)
    122{
    123	struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
    124	unsigned int status;
    125	unsigned int level;
    126	int retval = 0;
    127
    128	while (max >= sizeof(u32)) {
    129		status = readl(rngc->base + RNGC_STATUS);
    130
    131		/* is there some error while reading this random number? */
    132		if (status & RNGC_STATUS_ERROR)
    133			break;
    134
    135		/* how many random numbers are in FIFO? [0-16] */
    136		level = (status & RNGC_STATUS_FIFO_LEVEL_MASK) >>
    137			RNGC_STATUS_FIFO_LEVEL_SHIFT;
    138
    139		if (level) {
    140			/* retrieve a random number from FIFO */
    141			*(u32 *)data = readl(rngc->base + RNGC_FIFO);
    142
    143			retval += sizeof(u32);
    144			data += sizeof(u32);
    145			max -= sizeof(u32);
    146		}
    147	}
    148
    149	return retval ? retval : -EIO;
    150}
    151
    152static irqreturn_t imx_rngc_irq(int irq, void *priv)
    153{
    154	struct imx_rngc *rngc = (struct imx_rngc *)priv;
    155	u32 status;
    156
    157	/*
    158	 * clearing the interrupt will also clear the error register
    159	 * read error and status before clearing
    160	 */
    161	status = readl(rngc->base + RNGC_STATUS);
    162	rngc->err_reg = readl(rngc->base + RNGC_ERROR);
    163
    164	imx_rngc_irq_mask_clear(rngc);
    165
    166	if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE))
    167		complete(&rngc->rng_op_done);
    168
    169	return IRQ_HANDLED;
    170}
    171
    172static int imx_rngc_init(struct hwrng *rng)
    173{
    174	struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
    175	u32 cmd, ctrl;
    176	int ret;
    177
    178	/* clear error */
    179	cmd = readl(rngc->base + RNGC_COMMAND);
    180	writel(cmd | RNGC_CMD_CLR_ERR, rngc->base + RNGC_COMMAND);
    181
    182	imx_rngc_irq_unmask(rngc);
    183
    184	/* create seed, repeat while there is some statistical error */
    185	do {
    186		/* seed creation */
    187		cmd = readl(rngc->base + RNGC_COMMAND);
    188		writel(cmd | RNGC_CMD_SEED, rngc->base + RNGC_COMMAND);
    189
    190		ret = wait_for_completion_timeout(&rngc->rng_op_done,
    191				RNGC_TIMEOUT);
    192
    193		if (!ret) {
    194			ret = -ETIMEDOUT;
    195			goto err;
    196		}
    197
    198	} while (rngc->err_reg == RNGC_ERROR_STATUS_STAT_ERR);
    199
    200	if (rngc->err_reg) {
    201		ret = -EIO;
    202		goto err;
    203	}
    204
    205	/*
    206	 * enable automatic seeding, the rngc creates a new seed automatically
    207	 * after serving 2^20 random 160-bit words
    208	 */
    209	ctrl = readl(rngc->base + RNGC_CONTROL);
    210	ctrl |= RNGC_CTRL_AUTO_SEED;
    211	writel(ctrl, rngc->base + RNGC_CONTROL);
    212
    213	/*
    214	 * if initialisation was successful, we keep the interrupt
    215	 * unmasked until imx_rngc_cleanup is called
    216	 * we mask the interrupt ourselves if we return an error
    217	 */
    218	return 0;
    219
    220err:
    221	imx_rngc_irq_mask_clear(rngc);
    222	return ret;
    223}
    224
    225static void imx_rngc_cleanup(struct hwrng *rng)
    226{
    227	struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
    228
    229	imx_rngc_irq_mask_clear(rngc);
    230}
    231
    232static int imx_rngc_probe(struct platform_device *pdev)
    233{
    234	struct imx_rngc *rngc;
    235	int ret;
    236	int irq;
    237	u32 ver_id;
    238	u8  rng_type;
    239
    240	rngc = devm_kzalloc(&pdev->dev, sizeof(*rngc), GFP_KERNEL);
    241	if (!rngc)
    242		return -ENOMEM;
    243
    244	rngc->base = devm_platform_ioremap_resource(pdev, 0);
    245	if (IS_ERR(rngc->base))
    246		return PTR_ERR(rngc->base);
    247
    248	rngc->clk = devm_clk_get(&pdev->dev, NULL);
    249	if (IS_ERR(rngc->clk)) {
    250		dev_err(&pdev->dev, "Can not get rng_clk\n");
    251		return PTR_ERR(rngc->clk);
    252	}
    253
    254	irq = platform_get_irq(pdev, 0);
    255	if (irq < 0)
    256		return irq;
    257
    258	ret = clk_prepare_enable(rngc->clk);
    259	if (ret)
    260		return ret;
    261
    262	ver_id = readl(rngc->base + RNGC_VER_ID);
    263	rng_type = ver_id >> RNGC_TYPE_SHIFT;
    264	/*
    265	 * This driver supports only RNGC and RNGB. (There's a different
    266	 * driver for RNGA.)
    267	 */
    268	if (rng_type != RNGC_TYPE_RNGC && rng_type != RNGC_TYPE_RNGB) {
    269		ret = -ENODEV;
    270		goto err;
    271	}
    272
    273	ret = devm_request_irq(&pdev->dev,
    274			irq, imx_rngc_irq, 0, pdev->name, (void *)rngc);
    275	if (ret) {
    276		dev_err(rngc->dev, "Can't get interrupt working.\n");
    277		goto err;
    278	}
    279
    280	init_completion(&rngc->rng_op_done);
    281
    282	rngc->rng.name = pdev->name;
    283	rngc->rng.init = imx_rngc_init;
    284	rngc->rng.read = imx_rngc_read;
    285	rngc->rng.cleanup = imx_rngc_cleanup;
    286	rngc->rng.quality = 19;
    287
    288	rngc->dev = &pdev->dev;
    289	platform_set_drvdata(pdev, rngc);
    290
    291	imx_rngc_irq_mask_clear(rngc);
    292
    293	if (self_test) {
    294		ret = imx_rngc_self_test(rngc);
    295		if (ret) {
    296			dev_err(rngc->dev, "self test failed\n");
    297			goto err;
    298		}
    299	}
    300
    301	ret = hwrng_register(&rngc->rng);
    302	if (ret) {
    303		dev_err(&pdev->dev, "hwrng registration failed\n");
    304		goto err;
    305	}
    306
    307	dev_info(&pdev->dev,
    308		"Freescale RNG%c registered (HW revision %d.%02d)\n",
    309		rng_type == RNGC_TYPE_RNGB ? 'B' : 'C',
    310		(ver_id >> RNGC_VER_MAJ_SHIFT) & 0xff, ver_id & 0xff);
    311	return 0;
    312
    313err:
    314	clk_disable_unprepare(rngc->clk);
    315
    316	return ret;
    317}
    318
    319static int __exit imx_rngc_remove(struct platform_device *pdev)
    320{
    321	struct imx_rngc *rngc = platform_get_drvdata(pdev);
    322
    323	hwrng_unregister(&rngc->rng);
    324
    325	clk_disable_unprepare(rngc->clk);
    326
    327	return 0;
    328}
    329
    330static int __maybe_unused imx_rngc_suspend(struct device *dev)
    331{
    332	struct imx_rngc *rngc = dev_get_drvdata(dev);
    333
    334	clk_disable_unprepare(rngc->clk);
    335
    336	return 0;
    337}
    338
    339static int __maybe_unused imx_rngc_resume(struct device *dev)
    340{
    341	struct imx_rngc *rngc = dev_get_drvdata(dev);
    342
    343	clk_prepare_enable(rngc->clk);
    344
    345	return 0;
    346}
    347
    348static SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume);
    349
    350static const struct of_device_id imx_rngc_dt_ids[] = {
    351	{ .compatible = "fsl,imx25-rngb", .data = NULL, },
    352	{ /* sentinel */ }
    353};
    354MODULE_DEVICE_TABLE(of, imx_rngc_dt_ids);
    355
    356static struct platform_driver imx_rngc_driver = {
    357	.driver = {
    358		.name = "imx_rngc",
    359		.pm = &imx_rngc_pm_ops,
    360		.of_match_table = imx_rngc_dt_ids,
    361	},
    362	.remove = __exit_p(imx_rngc_remove),
    363};
    364
    365module_platform_driver_probe(imx_rngc_driver, imx_rngc_probe);
    366
    367MODULE_AUTHOR("Freescale Semiconductor, Inc.");
    368MODULE_DESCRIPTION("H/W RNGC driver for i.MX");
    369MODULE_LICENSE("GPL");