mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 19:56:18 +00:00
hwrng: core - Replace u32 in driver API with byte array
This patch implements a new method by which hw_random hardware drivers can pass data to the core more efficiently, using a shared buffer. The old methods have been retained as a compatability layer until all the drivers have been updated. Signed-off-by: Ian Molton <ian.molton@collabora.co.uk> Acked-by: Matt Mackall <mpm@selenic.com> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
2f32bfd834
commit
9996508b33
2 changed files with 71 additions and 47 deletions
|
@ -52,7 +52,8 @@
|
||||||
static struct hwrng *current_rng;
|
static struct hwrng *current_rng;
|
||||||
static LIST_HEAD(rng_list);
|
static LIST_HEAD(rng_list);
|
||||||
static DEFINE_MUTEX(rng_mutex);
|
static DEFINE_MUTEX(rng_mutex);
|
||||||
|
static int data_avail;
|
||||||
|
static u8 rng_buffer[SMP_CACHE_BYTES] __cacheline_aligned;
|
||||||
|
|
||||||
static inline int hwrng_init(struct hwrng *rng)
|
static inline int hwrng_init(struct hwrng *rng)
|
||||||
{
|
{
|
||||||
|
@ -67,19 +68,6 @@ static inline void hwrng_cleanup(struct hwrng *rng)
|
||||||
rng->cleanup(rng);
|
rng->cleanup(rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int hwrng_data_present(struct hwrng *rng, int wait)
|
|
||||||
{
|
|
||||||
if (!rng->data_present)
|
|
||||||
return 1;
|
|
||||||
return rng->data_present(rng, wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
|
|
||||||
{
|
|
||||||
return rng->data_read(rng, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int rng_dev_open(struct inode *inode, struct file *filp)
|
static int rng_dev_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
/* enforce read-only access to this chrdev */
|
/* enforce read-only access to this chrdev */
|
||||||
|
@ -91,54 +79,87 @@ static int rng_dev_open(struct inode *inode, struct file *filp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
|
||||||
|
int wait) {
|
||||||
|
int present;
|
||||||
|
|
||||||
|
if (rng->read)
|
||||||
|
return rng->read(rng, (void *)buffer, size, wait);
|
||||||
|
|
||||||
|
if (rng->data_present)
|
||||||
|
present = rng->data_present(rng, wait);
|
||||||
|
else
|
||||||
|
present = 1;
|
||||||
|
|
||||||
|
if (present)
|
||||||
|
return rng->data_read(rng, (u32 *)buffer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t rng_dev_read(struct file *filp, char __user *buf,
|
static ssize_t rng_dev_read(struct file *filp, char __user *buf,
|
||||||
size_t size, loff_t *offp)
|
size_t size, loff_t *offp)
|
||||||
{
|
{
|
||||||
u32 data;
|
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int bytes_read;
|
int bytes_read, len;
|
||||||
|
|
||||||
while (size) {
|
while (size) {
|
||||||
|
if (mutex_lock_interruptible(&rng_mutex)) {
|
||||||
err = -ERESTARTSYS;
|
err = -ERESTARTSYS;
|
||||||
if (mutex_lock_interruptible(&rng_mutex))
|
|
||||||
goto out;
|
|
||||||
if (!current_rng) {
|
|
||||||
mutex_unlock(&rng_mutex);
|
|
||||||
err = -ENODEV;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes_read = 0;
|
if (!current_rng) {
|
||||||
if (hwrng_data_present(current_rng,
|
err = -ENODEV;
|
||||||
!(filp->f_flags & O_NONBLOCK)))
|
goto out_unlock;
|
||||||
bytes_read = hwrng_data_read(current_rng, &data);
|
}
|
||||||
mutex_unlock(&rng_mutex);
|
|
||||||
|
|
||||||
err = -EAGAIN;
|
if (!data_avail) {
|
||||||
if (!bytes_read && (filp->f_flags & O_NONBLOCK))
|
bytes_read = rng_get_data(current_rng, rng_buffer,
|
||||||
goto out;
|
sizeof(rng_buffer),
|
||||||
|
!(filp->f_flags & O_NONBLOCK));
|
||||||
if (bytes_read < 0) {
|
if (bytes_read < 0) {
|
||||||
err = bytes_read;
|
err = bytes_read;
|
||||||
goto out;
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
data_avail = bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -EFAULT;
|
if (!data_avail) {
|
||||||
while (bytes_read && size) {
|
if (filp->f_flags & O_NONBLOCK) {
|
||||||
if (put_user((u8)data, buf++))
|
err = -EAGAIN;
|
||||||
goto out;
|
goto out_unlock;
|
||||||
size--;
|
|
||||||
ret++;
|
|
||||||
bytes_read--;
|
|
||||||
data >>= 8;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
len = data_avail;
|
||||||
|
if (len > size)
|
||||||
|
len = size;
|
||||||
|
|
||||||
|
data_avail -= len;
|
||||||
|
|
||||||
|
if (copy_to_user(buf + ret, rng_buffer + data_avail,
|
||||||
|
len)) {
|
||||||
|
err = -EFAULT;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= len;
|
||||||
|
ret += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&rng_mutex);
|
||||||
|
|
||||||
if (need_resched())
|
if (need_resched())
|
||||||
schedule_timeout_interruptible(1);
|
schedule_timeout_interruptible(1);
|
||||||
|
|
||||||
|
if (signal_pending(current)) {
|
||||||
err = -ERESTARTSYS;
|
err = -ERESTARTSYS;
|
||||||
if (signal_pending(current))
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&rng_mutex);
|
||||||
out:
|
out:
|
||||||
return ret ? : err;
|
return ret ? : err;
|
||||||
}
|
}
|
||||||
|
@ -280,7 +301,7 @@ int hwrng_register(struct hwrng *rng)
|
||||||
struct hwrng *old_rng, *tmp;
|
struct hwrng *old_rng, *tmp;
|
||||||
|
|
||||||
if (rng->name == NULL ||
|
if (rng->name == NULL ||
|
||||||
rng->data_read == NULL)
|
(rng->data_read == NULL && rng->read == NULL))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
mutex_lock(&rng_mutex);
|
mutex_lock(&rng_mutex);
|
||||||
|
|
|
@ -22,10 +22,12 @@
|
||||||
* @cleanup: Cleanup callback (can be NULL).
|
* @cleanup: Cleanup callback (can be NULL).
|
||||||
* @data_present: Callback to determine if data is available
|
* @data_present: Callback to determine if data is available
|
||||||
* on the RNG. If NULL, it is assumed that
|
* on the RNG. If NULL, it is assumed that
|
||||||
* there is always data available.
|
* there is always data available. *OBSOLETE*
|
||||||
* @data_read: Read data from the RNG device.
|
* @data_read: Read data from the RNG device.
|
||||||
* Returns the number of lower random bytes in "data".
|
* Returns the number of lower random bytes in "data".
|
||||||
* Must not be NULL.
|
* Must not be NULL. *OSOLETE*
|
||||||
|
* @read: New API. drivers can fill up to max bytes of data
|
||||||
|
* into the buffer. The buffer is aligned for any type.
|
||||||
* @priv: Private data, for use by the RNG driver.
|
* @priv: Private data, for use by the RNG driver.
|
||||||
*/
|
*/
|
||||||
struct hwrng {
|
struct hwrng {
|
||||||
|
@ -34,6 +36,7 @@ struct hwrng {
|
||||||
void (*cleanup)(struct hwrng *rng);
|
void (*cleanup)(struct hwrng *rng);
|
||||||
int (*data_present)(struct hwrng *rng, int wait);
|
int (*data_present)(struct hwrng *rng, int wait);
|
||||||
int (*data_read)(struct hwrng *rng, u32 *data);
|
int (*data_read)(struct hwrng *rng, u32 *data);
|
||||||
|
int (*read)(struct hwrng *rng, void *data, size_t max, bool wait);
|
||||||
unsigned long priv;
|
unsigned long priv;
|
||||||
|
|
||||||
/* internal. */
|
/* internal. */
|
||||||
|
|
Loading…
Reference in a new issue