Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0382d978 authored by Dinesh K Garg's avatar Dinesh K Garg
Browse files

msm_rng: Resolve race condition issues



Resolve race condition between initializing the mutex vs hwrng
register.
Remove the HWRNG FIFO, not required in Software.

Change-Id: I9fa3e5c7e2e9e14feb88a4656dcfab7dec3cbd67
Signed-off-by: default avatarDinesh K Garg <dineshg@codeaurora.org>
parent bb004d0f
Loading
Loading
Loading
Loading
+39 −24
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/qrng.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/delay.h>

#include <linux/platform_data/qcom_crypto_device.h>

@@ -115,10 +116,13 @@ int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, void *data)
	unsigned long val;
	unsigned long *retdata = data;
	int ret;
	int failed = 0;

	pdev = msm_rng_dev->pdev;
	base = msm_rng_dev->base;

	mutex_lock(&msm_rng_dev->rng_lock);

	if (msm_rng_dev->qrng_perf_client) {
		ret = msm_bus_scale_client_update_request(
				msm_rng_dev->qrng_perf_client, 1);
@@ -129,13 +133,21 @@ int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, void *data)
	ret = clk_prepare_enable(msm_rng_dev->prng_clk);
	if (ret) {
		dev_err(&pdev->dev, "failed to enable clock in callback\n");
		return 0;
		goto err;
	}
	/* read random data from h/w */
	do {
		/* check status bit if data is available */
		if (!(readl_relaxed(base + PRNG_STATUS_OFFSET) & 0x00000001))
			break;	/* no data to read so just bail */
		while (!(readl_relaxed(base + PRNG_STATUS_OFFSET)
					& 0x00000001)) {
			if (failed == 10) {
				pr_err("Data not available after retry\n");
				break;
			}
			pr_err("msm_rng:Data not available!\n");
			msleep_interruptible(10);
			failed++;
		}

		/* read FIFO */
		val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
@@ -150,17 +162,17 @@ int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, void *data)

	/* vote to turn off clock */
	clk_disable_unprepare(msm_rng_dev->prng_clk);

err:
	if (msm_rng_dev->qrng_perf_client) {
		ret = msm_bus_scale_client_update_request(
				msm_rng_dev->qrng_perf_client, 0);
		if (ret)
			pr_err("bus_scale_client_update_req failed!\n");
	}
	mutex_unlock(&msm_rng_dev->rng_lock);

	val = 0L;
	return currsize;

}

static int msm_rng_drbg_read(struct hwrng *rng,
@@ -169,29 +181,25 @@ static int msm_rng_drbg_read(struct hwrng *rng,
	struct msm_rng_device *msm_rng_dev;
	struct platform_device *pdev;
	void __iomem *base;
	size_t maxsize;
	size_t currsize = 0;
	unsigned long val;
	unsigned long *retdata = data;
	int ret, ret1;
	int failed = 0;

	msm_rng_dev = (struct msm_rng_device *)rng->priv;
	pdev = msm_rng_dev->pdev;
	base = msm_rng_dev->base;


	down(&msm_rng_dev->drbg_sem);

	/* calculate max size bytes to transfer back to caller */
	maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max);

	/* no room for word data */
	if (maxsize < 4)
	if (max < 4)
		return 0;

	mutex_lock(&msm_rng_dev->rng_lock);

	/* read random data from CTR-AES based DRBG */
	if (FIPS140_DRBG_ENABLED == msm_rng_dev->fips140_drbg_enabled) {
		ret1 = fips_drbg_gen(msm_rng_dev->drbg_ctx, data, maxsize);
		ret1 = fips_drbg_gen(msm_rng_dev->drbg_ctx, data, max);
		if (FIPS140_PRNG_ERR == ret1)
			panic("random number generator generator error.\n");
	} else
@@ -209,14 +217,21 @@ static int msm_rng_drbg_read(struct hwrng *rng,
	ret = clk_prepare_enable(msm_rng_dev->prng_clk);
	if (ret) {
		dev_err(&pdev->dev, "failed to enable clock in callback\n");
		up(&msm_rng_dev->drbg_sem);
		return 0;
		goto err;
	}
	/* read random data from h/w */
	do {
		/* check status bit if data is available */
		if (!(readl_relaxed(base + PRNG_STATUS_OFFSET) & 0x00000001))
			break;	/* no data to read so just bail */
		while (!(readl_relaxed(base + PRNG_STATUS_OFFSET)
				& 0x00000001)) {
			if (failed == 10) {
				pr_err("Data not available after retry\n");
				break;
			}
			pr_err("msm_rng:Data not available!\n");
			msleep_interruptible(10);
			failed++;
		}

		/* read FIFO */
		val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
@@ -229,12 +244,12 @@ static int msm_rng_drbg_read(struct hwrng *rng,
		currsize += 4;

		/* make sure we stay on 32bit boundary */
		if ((maxsize - currsize) < 4)
		if ((max - currsize) < 4)
			break;
	} while (currsize < maxsize);
	} while (currsize < max);
	/* vote to turn off clock */
	clk_disable_unprepare(msm_rng_dev->prng_clk);

err:
	if (msm_rng_dev->qrng_perf_client) {
		ret = msm_bus_scale_client_update_request(
				msm_rng_dev->qrng_perf_client, 0);
@@ -242,7 +257,7 @@ static int msm_rng_drbg_read(struct hwrng *rng,
			pr_err("bus_scale_client_update_req failed!\n");
	}

	up(&msm_rng_dev->drbg_sem);
	mutex_unlock(&msm_rng_dev->rng_lock);

	return currsize;
}
@@ -502,6 +517,8 @@ static int msm_rng_probe(struct platform_device *pdev)
	if (error)
		goto rollback_clk;

	mutex_init(&msm_rng_dev->rng_lock);

	/* register with hwrng framework */
	msm_rng.priv = (unsigned long) msm_rng_dev;
	error = hwrng_register(&msm_rng);
@@ -527,8 +544,6 @@ static int msm_rng_probe(struct platform_device *pdev)
	}
	cdev_init(&msm_rng_cdev, &msm_rng_fops);

	sema_init(&msm_rng_dev->drbg_sem, 1);

	_first_msm_drbg_init(msm_rng_dev);

	return error;
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ struct msm_rng_device {
	void __iomem *base;
	struct clk *prng_clk;
	uint32_t qrng_perf_client;
	struct  semaphore drbg_sem;
	struct mutex rng_lock;
	struct fips_drbg_ctx_s *drbg_ctx;
	int    fips140_drbg_enabled;
};