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 LIST_HEAD(rng_list);
|
||||
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)
|
||||
{
|
||||
|
@ -67,19 +68,6 @@ static inline void hwrng_cleanup(struct hwrng *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)
|
||||
{
|
||||
/* enforce read-only access to this chrdev */
|
||||
|
@ -91,54 +79,87 @@ static int rng_dev_open(struct inode *inode, struct file *filp)
|
|||
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,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
u32 data;
|
||||
ssize_t ret = 0;
|
||||
int err = 0;
|
||||
int bytes_read;
|
||||
int bytes_read, len;
|
||||
|
||||
while (size) {
|
||||
err = -ERESTARTSYS;
|
||||
if (mutex_lock_interruptible(&rng_mutex))
|
||||
if (mutex_lock_interruptible(&rng_mutex)) {
|
||||
err = -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!current_rng) {
|
||||
mutex_unlock(&rng_mutex);
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (!data_avail) {
|
||||
bytes_read = rng_get_data(current_rng, rng_buffer,
|
||||
sizeof(rng_buffer),
|
||||
!(filp->f_flags & O_NONBLOCK));
|
||||
if (bytes_read < 0) {
|
||||
err = bytes_read;
|
||||
goto out_unlock;
|
||||
}
|
||||
data_avail = bytes_read;
|
||||
}
|
||||
|
||||
if (!data_avail) {
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
err = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
bytes_read = 0;
|
||||
if (hwrng_data_present(current_rng,
|
||||
!(filp->f_flags & O_NONBLOCK)))
|
||||
bytes_read = hwrng_data_read(current_rng, &data);
|
||||
mutex_unlock(&rng_mutex);
|
||||
|
||||
err = -EAGAIN;
|
||||
if (!bytes_read && (filp->f_flags & O_NONBLOCK))
|
||||
goto out;
|
||||
if (bytes_read < 0) {
|
||||
err = bytes_read;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = -EFAULT;
|
||||
while (bytes_read && size) {
|
||||
if (put_user((u8)data, buf++))
|
||||
goto out;
|
||||
size--;
|
||||
ret++;
|
||||
bytes_read--;
|
||||
data >>= 8;
|
||||
}
|
||||
|
||||
if (need_resched())
|
||||
schedule_timeout_interruptible(1);
|
||||
err = -ERESTARTSYS;
|
||||
if (signal_pending(current))
|
||||
|
||||
if (signal_pending(current)) {
|
||||
err = -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&rng_mutex);
|
||||
out:
|
||||
return ret ? : err;
|
||||
}
|
||||
|
@ -280,7 +301,7 @@ int hwrng_register(struct hwrng *rng)
|
|||
struct hwrng *old_rng, *tmp;
|
||||
|
||||
if (rng->name == NULL ||
|
||||
rng->data_read == NULL)
|
||||
(rng->data_read == NULL && rng->read == NULL))
|
||||
goto out;
|
||||
|
||||
mutex_lock(&rng_mutex);
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
* @cleanup: Cleanup callback (can be NULL).
|
||||
* @data_present: Callback to determine if data is available
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
struct hwrng {
|
||||
|
@ -34,6 +36,7 @@ struct hwrng {
|
|||
void (*cleanup)(struct hwrng *rng);
|
||||
int (*data_present)(struct hwrng *rng, int wait);
|
||||
int (*data_read)(struct hwrng *rng, u32 *data);
|
||||
int (*read)(struct hwrng *rng, void *data, size_t max, bool wait);
|
||||
unsigned long priv;
|
||||
|
||||
/* internal. */
|
||||
|
|
Loading…
Reference in a new issue