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: Dinesh K Garg <dineshg@codeaurora.org>
This commit is contained in:
Dinesh K Garg 2014-07-29 11:07:02 -07:00 committed by followmsi
parent 8df7aab686
commit 15acebb33e
2 changed files with 40 additions and 25 deletions

View File

@ -28,6 +28,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>
@ -116,10 +117,13 @@ int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, void *data)
u32 val;
u32 *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);
@ -130,13 +134,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);
@ -151,17 +163,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,
@ -170,29 +182,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;
u32 val;
u32 *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
@ -210,14 +218,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);
@ -230,12 +245,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);
@ -243,7 +258,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;
}
@ -503,6 +518,8 @@ static int __devinit 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);
@ -528,8 +545,6 @@ static int __devinit 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;

View File

@ -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;
};