mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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:
parent
bb004d0fe3
commit
0382d97866
2 changed files with 40 additions and 25 deletions
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/qrng.h>
|
#include <linux/qrng.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include <linux/platform_data/qcom_crypto_device.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 val;
|
||||||
unsigned long *retdata = data;
|
unsigned long *retdata = data;
|
||||||
int ret;
|
int ret;
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
pdev = msm_rng_dev->pdev;
|
pdev = msm_rng_dev->pdev;
|
||||||
base = msm_rng_dev->base;
|
base = msm_rng_dev->base;
|
||||||
|
|
||||||
|
mutex_lock(&msm_rng_dev->rng_lock);
|
||||||
|
|
||||||
if (msm_rng_dev->qrng_perf_client) {
|
if (msm_rng_dev->qrng_perf_client) {
|
||||||
ret = msm_bus_scale_client_update_request(
|
ret = msm_bus_scale_client_update_request(
|
||||||
msm_rng_dev->qrng_perf_client, 1);
|
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);
|
ret = clk_prepare_enable(msm_rng_dev->prng_clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "failed to enable clock in callback\n");
|
dev_err(&pdev->dev, "failed to enable clock in callback\n");
|
||||||
return 0;
|
goto err;
|
||||||
}
|
}
|
||||||
/* read random data from h/w */
|
/* read random data from h/w */
|
||||||
do {
|
do {
|
||||||
/* check status bit if data is available */
|
/* check status bit if data is available */
|
||||||
if (!(readl_relaxed(base + PRNG_STATUS_OFFSET) & 0x00000001))
|
while (!(readl_relaxed(base + PRNG_STATUS_OFFSET)
|
||||||
break; /* no data to read so just bail */
|
& 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 */
|
/* read FIFO */
|
||||||
val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
|
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 */
|
/* vote to turn off clock */
|
||||||
clk_disable_unprepare(msm_rng_dev->prng_clk);
|
clk_disable_unprepare(msm_rng_dev->prng_clk);
|
||||||
|
err:
|
||||||
if (msm_rng_dev->qrng_perf_client) {
|
if (msm_rng_dev->qrng_perf_client) {
|
||||||
ret = msm_bus_scale_client_update_request(
|
ret = msm_bus_scale_client_update_request(
|
||||||
msm_rng_dev->qrng_perf_client, 0);
|
msm_rng_dev->qrng_perf_client, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
pr_err("bus_scale_client_update_req failed!\n");
|
pr_err("bus_scale_client_update_req failed!\n");
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&msm_rng_dev->rng_lock);
|
||||||
|
|
||||||
val = 0L;
|
val = 0L;
|
||||||
return currsize;
|
return currsize;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msm_rng_drbg_read(struct hwrng *rng,
|
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 msm_rng_device *msm_rng_dev;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
size_t maxsize;
|
|
||||||
size_t currsize = 0;
|
size_t currsize = 0;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
unsigned long *retdata = data;
|
unsigned long *retdata = data;
|
||||||
int ret, ret1;
|
int ret, ret1;
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
msm_rng_dev = (struct msm_rng_device *)rng->priv;
|
msm_rng_dev = (struct msm_rng_device *)rng->priv;
|
||||||
pdev = msm_rng_dev->pdev;
|
pdev = msm_rng_dev->pdev;
|
||||||
base = msm_rng_dev->base;
|
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 */
|
/* no room for word data */
|
||||||
if (maxsize < 4)
|
if (max < 4)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
mutex_lock(&msm_rng_dev->rng_lock);
|
||||||
|
|
||||||
/* read random data from CTR-AES based DRBG */
|
/* read random data from CTR-AES based DRBG */
|
||||||
if (FIPS140_DRBG_ENABLED == msm_rng_dev->fips140_drbg_enabled) {
|
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)
|
if (FIPS140_PRNG_ERR == ret1)
|
||||||
panic("random number generator generator error.\n");
|
panic("random number generator generator error.\n");
|
||||||
} else
|
} else
|
||||||
|
@ -209,14 +217,21 @@ static int msm_rng_drbg_read(struct hwrng *rng,
|
||||||
ret = clk_prepare_enable(msm_rng_dev->prng_clk);
|
ret = clk_prepare_enable(msm_rng_dev->prng_clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "failed to enable clock in callback\n");
|
dev_err(&pdev->dev, "failed to enable clock in callback\n");
|
||||||
up(&msm_rng_dev->drbg_sem);
|
goto err;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
/* read random data from h/w */
|
/* read random data from h/w */
|
||||||
do {
|
do {
|
||||||
/* check status bit if data is available */
|
/* check status bit if data is available */
|
||||||
if (!(readl_relaxed(base + PRNG_STATUS_OFFSET) & 0x00000001))
|
while (!(readl_relaxed(base + PRNG_STATUS_OFFSET)
|
||||||
break; /* no data to read so just bail */
|
& 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 */
|
/* read FIFO */
|
||||||
val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
|
val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
|
||||||
|
@ -229,12 +244,12 @@ static int msm_rng_drbg_read(struct hwrng *rng,
|
||||||
currsize += 4;
|
currsize += 4;
|
||||||
|
|
||||||
/* make sure we stay on 32bit boundary */
|
/* make sure we stay on 32bit boundary */
|
||||||
if ((maxsize - currsize) < 4)
|
if ((max - currsize) < 4)
|
||||||
break;
|
break;
|
||||||
} while (currsize < maxsize);
|
} while (currsize < max);
|
||||||
/* vote to turn off clock */
|
/* vote to turn off clock */
|
||||||
clk_disable_unprepare(msm_rng_dev->prng_clk);
|
clk_disable_unprepare(msm_rng_dev->prng_clk);
|
||||||
|
err:
|
||||||
if (msm_rng_dev->qrng_perf_client) {
|
if (msm_rng_dev->qrng_perf_client) {
|
||||||
ret = msm_bus_scale_client_update_request(
|
ret = msm_bus_scale_client_update_request(
|
||||||
msm_rng_dev->qrng_perf_client, 0);
|
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");
|
pr_err("bus_scale_client_update_req failed!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
up(&msm_rng_dev->drbg_sem);
|
mutex_unlock(&msm_rng_dev->rng_lock);
|
||||||
|
|
||||||
return currsize;
|
return currsize;
|
||||||
}
|
}
|
||||||
|
@ -502,6 +517,8 @@ static int msm_rng_probe(struct platform_device *pdev)
|
||||||
if (error)
|
if (error)
|
||||||
goto rollback_clk;
|
goto rollback_clk;
|
||||||
|
|
||||||
|
mutex_init(&msm_rng_dev->rng_lock);
|
||||||
|
|
||||||
/* register with hwrng framework */
|
/* register with hwrng framework */
|
||||||
msm_rng.priv = (unsigned long) msm_rng_dev;
|
msm_rng.priv = (unsigned long) msm_rng_dev;
|
||||||
error = hwrng_register(&msm_rng);
|
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);
|
cdev_init(&msm_rng_cdev, &msm_rng_fops);
|
||||||
|
|
||||||
sema_init(&msm_rng_dev->drbg_sem, 1);
|
|
||||||
|
|
||||||
_first_msm_drbg_init(msm_rng_dev);
|
_first_msm_drbg_init(msm_rng_dev);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct msm_rng_device {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *prng_clk;
|
struct clk *prng_clk;
|
||||||
uint32_t qrng_perf_client;
|
uint32_t qrng_perf_client;
|
||||||
struct semaphore drbg_sem;
|
struct mutex rng_lock;
|
||||||
struct fips_drbg_ctx_s *drbg_ctx;
|
struct fips_drbg_ctx_s *drbg_ctx;
|
||||||
int fips140_drbg_enabled;
|
int fips140_drbg_enabled;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue