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

Commit 9996508b authored by Ian Molton's avatar Ian Molton Committed by Herbert Xu
Browse files

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: default avatarIan Molton <ian.molton@collabora.co.uk>
Acked-by: default avatarMatt Mackall <mpm@selenic.com>
Acked-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 2f32bfd8
Loading
Loading
Loading
Loading
+64 −43
Original line number Diff line number Diff line
@@ -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) {
		if (mutex_lock_interruptible(&rng_mutex)) {
			err = -ERESTARTSYS;
		if (mutex_lock_interruptible(&rng_mutex))
			goto out;
		}

		if (!current_rng) {
			mutex_unlock(&rng_mutex);
			err = -ENODEV;
			goto out;
			goto out_unlock;
		}

		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 (!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;
				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;
		while (bytes_read && size) {
			if (put_user((u8)data, buf++))
				goto out;
			size--;
			ret++;
			bytes_read--;
			data >>= 8;
				goto out_unlock;
			}

			size -= len;
			ret += len;
		}

		mutex_unlock(&rng_mutex);

		if (need_resched())
			schedule_timeout_interruptible(1);

		if (signal_pending(current)) {
			err = -ERESTARTSYS;
		if (signal_pending(current))
			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);
+5 −2
Original line number Diff line number Diff line
@@ -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. */