Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Linux: Kernel

[PATCH 1/2] hw_random: core updates to allow more efficient drivers

 

 

Linux kernel RSS feed   Index | Next | Previous | View Threaded


ian.molton at collabora

Nov 25, 2009, 4:25 PM

Post #1 of 12 (267 views)
Permalink
[PATCH 1/2] hw_random: core updates to allow more efficient drivers

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 [at] collabora>
---
drivers/char/hw_random/core.c | 120 ++++++++++++++++++++++++++---------------
include/linux/hw_random.h | 9 ++-
2 files changed, 82 insertions(+), 47 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1573aeb..e179afd 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -47,12 +47,14 @@
#define RNG_MODULE_NAME "hw_random"
#define PFX RNG_MODULE_NAME ": "
#define RNG_MISCDEV_MINOR 183 /* official */
+#define RNG_BUFFSIZE 64


static struct hwrng *current_rng;
static LIST_HEAD(rng_list);
static DEFINE_MUTEX(rng_mutex);
-
+static u8 *rng_buffer;
+static int data_avail;

static inline int hwrng_init(struct hwrng *rng)
{
@@ -67,19 +69,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 +80,86 @@ static int rng_dev_open(struct inode *inode, struct file *filp)
return 0;
}

+static inline int rng_get_data(struct hwrng *rng, u8 *rng_buffer, size_t size,
+ int wait) {
+ int present;
+
+ if (rng->read)
+ return rng->read(rng, (void *)rng_buffer, size, wait);
+
+ if (rng->data_present)
+ present = rng->data_present(rng, wait);
+ else
+ present = 1;
+
+ if (present)
+ return rng->data_read(rng, (u32 *)rng_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;
}

- 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;
+ if (!data_avail) {
+ bytes_read = rng_get_data(current_rng, rng_buffer,
+ RNG_BUFFSIZE, !(filp->f_flags & O_NONBLOCK));
+ if (bytes_read < 0) {
+ err = bytes_read;
+ goto out_unlock;
+ }
+ data_avail = bytes_read;
}

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

+ mutex_unlock(&rng_mutex);
+
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,11 +301,19 @@ 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);

+ if (!rng_buffer) {
+ rng_buffer = kmalloc(RNG_BUFFSIZE, GFP_KERNEL);
+ if (!rng_buffer) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ }
+
/* Must not register two RNGs with the same name. */
err = -EEXIST;
list_for_each_entry(tmp, &rng_list, list) {
@@ -338,8 +367,11 @@ void hwrng_unregister(struct hwrng *rng)
current_rng = NULL;
}
}
- if (list_empty(&rng_list))
+ if (list_empty(&rng_list)) {
unregister_miscdev();
+ kfree(rng_buffer);
+ rng_buffer = NULL;
+ }

mutex_unlock(&rng_mutex);
}
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 7244456..8447989 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -22,18 +22,21 @@
* @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 {
const char *name;
- int (*init)(struct hwrng *rng);
+ int (*init)(struct hwrng *rng, void *data, size_t size);
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. */
--
1.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


ian.molton at collabora

Nov 25, 2009, 4:44 PM

Post #2 of 12 (257 views)
Permalink
[PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

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 [at] collabora>
---
drivers/char/hw_random/core.c | 120 ++++++++++++++++++++++++++---------------
include/linux/hw_random.h | 7 ++-
2 files changed, 81 insertions(+), 46 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1573aeb..e179afd 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -47,12 +47,14 @@
#define RNG_MODULE_NAME "hw_random"
#define PFX RNG_MODULE_NAME ": "
#define RNG_MISCDEV_MINOR 183 /* official */
+#define RNG_BUFFSIZE 64


static struct hwrng *current_rng;
static LIST_HEAD(rng_list);
static DEFINE_MUTEX(rng_mutex);
-
+static u8 *rng_buffer;
+static int data_avail;

static inline int hwrng_init(struct hwrng *rng)
{
@@ -67,19 +69,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 +80,86 @@ static int rng_dev_open(struct inode *inode, struct file *filp)
return 0;
}

+static inline int rng_get_data(struct hwrng *rng, u8 *rng_buffer, size_t size,
+ int wait) {
+ int present;
+
+ if (rng->read)
+ return rng->read(rng, (void *)rng_buffer, size, wait);
+
+ if (rng->data_present)
+ present = rng->data_present(rng, wait);
+ else
+ present = 1;
+
+ if (present)
+ return rng->data_read(rng, (u32 *)rng_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;
}

- 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;
+ if (!data_avail) {
+ bytes_read = rng_get_data(current_rng, rng_buffer,
+ RNG_BUFFSIZE, !(filp->f_flags & O_NONBLOCK));
+ if (bytes_read < 0) {
+ err = bytes_read;
+ goto out_unlock;
+ }
+ data_avail = bytes_read;
}

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

+ mutex_unlock(&rng_mutex);
+
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,11 +301,19 @@ 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);

+ if (!rng_buffer) {
+ rng_buffer = kmalloc(RNG_BUFFSIZE, GFP_KERNEL);
+ if (!rng_buffer) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ }
+
/* Must not register two RNGs with the same name. */
err = -EEXIST;
list_for_each_entry(tmp, &rng_list, list) {
@@ -338,8 +367,11 @@ void hwrng_unregister(struct hwrng *rng)
current_rng = NULL;
}
}
- if (list_empty(&rng_list))
+ if (list_empty(&rng_list)) {
unregister_miscdev();
+ kfree(rng_buffer);
+ rng_buffer = NULL;
+ }

mutex_unlock(&rng_mutex);
}
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 7244456..9bede76 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -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. */
--
1.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


mpm at selenic

Nov 25, 2009, 5:03 PM

Post #3 of 12 (255 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

On Thu, 2009-11-26 at 00:25 +0000, Ian Molton wrote:
> 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 [at] collabora>
> ---
> drivers/char/hw_random/core.c | 120 ++++++++++++++++++++++++++---------------
> include/linux/hw_random.h | 9 ++-
> 2 files changed, 82 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
> index 1573aeb..e179afd 100644
> --- a/drivers/char/hw_random/core.c
> +++ b/drivers/char/hw_random/core.c
> @@ -47,12 +47,14 @@
> #define RNG_MODULE_NAME "hw_random"
> #define PFX RNG_MODULE_NAME ": "
> #define RNG_MISCDEV_MINOR 183 /* official */
> +#define RNG_BUFFSIZE 64
>
>
> static struct hwrng *current_rng;
> static LIST_HEAD(rng_list);
> static DEFINE_MUTEX(rng_mutex);
> -
> +static u8 *rng_buffer;

How about just:

static u8 rng_buffer[RNG_BUFFSIZE] __cacheline_aligned;

And lose all the kmalloc and kfree code? The memory use will be smaller,
even when the buffer isn't needed.

> + if (!data_avail) {
> + bytes_read = rng_get_data(current_rng, rng_buffer,
> + RNG_BUFFSIZE, !(filp->f_flags & O_NONBLOCK));

No need to pass rng_buffer to the helper as there's only one with global
scope.

--
http://selenic.com : development and support for Mercurial and Linux


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


jeff at garzik

Nov 25, 2009, 7:12 PM

Post #4 of 12 (249 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

On 11/25/2009 07:25 PM, Ian Molton wrote:
> 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 [at] collabora>
> ---
> drivers/char/hw_random/core.c | 120 ++++++++++++++++++++++++++---------------
> include/linux/hw_random.h | 9 ++-
> 2 files changed, 82 insertions(+), 47 deletions(-)

Speaking as the original hw_random author... very nice! We have needed
a more efficient API for years.

Jeff


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


ian.molton at collabora

Nov 26, 2009, 2:49 AM

Post #5 of 12 (243 views)
Permalink
[PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

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 [at] collabora>
---
drivers/char/hw_random/core.c | 107 ++++++++++++++++++++++++----------------
include/linux/hw_random.h | 7 ++-
2 files changed, 69 insertions(+), 45 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1573aeb..da31573 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -47,12 +47,14 @@
#define RNG_MODULE_NAME "hw_random"
#define PFX RNG_MODULE_NAME ": "
#define RNG_MISCDEV_MINOR 183 /* official */
+#define RNG_BUFFSIZE 64


static struct hwrng *current_rng;
static LIST_HEAD(rng_list);
static DEFINE_MUTEX(rng_mutex);
-
+static int data_avail;
+static u8 rng_buffer[RNG_BUFFSIZE] __cacheline_aligned;

static inline int hwrng_init(struct hwrng *rng)
{
@@ -67,19 +69,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 +80,86 @@ 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;
}

- 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;
+ if (!data_avail) {
+ bytes_read = rng_get_data(current_rng, rng_buffer,
+ RNG_BUFFSIZE, !(filp->f_flags & O_NONBLOCK));
+ if (bytes_read < 0) {
+ err = bytes_read;
+ goto out_unlock;
+ }
+ data_avail = bytes_read;
}

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

+ mutex_unlock(&rng_mutex);
+
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);
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 7244456..9bede76 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -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. */
--
1.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


rusty at rustcorp

Nov 28, 2009, 2:05 AM

Post #6 of 12 (242 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

On Thu, 26 Nov 2009 11:33:23 am Matt Mackall wrote:
> On Thu, 2009-11-26 at 00:25 +0000, Ian Molton wrote:
> > #define PFX RNG_MODULE_NAME ": "
> > #define RNG_MISCDEV_MINOR 183 /* official */
> > +#define RNG_BUFFSIZE 64
>
> How about just:
>
> static u8 rng_buffer[RNG_BUFFSIZE] __cacheline_aligned;
>
> And lose all the kmalloc and kfree code? The memory use will be smaller,
> even when the buffer isn't needed.

And might as well just #defube RNG_BUFFSIZE SMP_CACHE_BYTES (or use
SMP_CACHE_BYTES here and sizeof() elsewhere).

> > + if (!data_avail) {
> > + bytes_read = rng_get_data(current_rng, rng_buffer,
> > + RNG_BUFFSIZE, !(filp->f_flags & O_NONBLOCK));
>
> No need to pass rng_buffer to the helper as there's only one with global
> scope.

Naah, I like the separation; it matches the rest of the kernel and means we
can get funky with buffer management in 10 years time when we rewrite this
again.

Thanks,
Rusty.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


ian.molton at collabora

Nov 30, 2009, 2:28 AM

Post #7 of 12 (219 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

Rusty Russell wrote:

> And might as well just #defube RNG_BUFFSIZE SMP_CACHE_BYTES (or use
> SMP_CACHE_BYTES here and sizeof() elsewhere).

This can lead to a rather small (4 byte) buffer on some systems, however
I don't know if in practice a tiny buffer or a big one would be better
for performance on those machines. I guess if its a problem someone can
patch the code to allocate a minimum of (say) 16 bytes in future...

so changed :)

>>> + if (!data_avail) {
>>> + bytes_read = rng_get_data(current_rng, rng_buffer,
>>> + RNG_BUFFSIZE, !(filp->f_flags & O_NONBLOCK));
>> No need to pass rng_buffer to the helper as there's only one with global
>> scope.
>
> Naah, I like the separation; it matches the rest of the kernel and means we
> can get funky with buffer management in 10 years time when we rewrite this
> again.

Tweaked to use sizeof().
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


ian.molton at collabora

Nov 30, 2009, 2:38 AM

Post #8 of 12 (218 views)
Permalink
[PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

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 [at] collabora>
---
drivers/char/hw_random/core.c | 107 ++++++++++++++++++++++++----------------
include/linux/hw_random.h | 7 ++-
2 files changed, 69 insertions(+), 45 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1573aeb..5c2d13c 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -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;
}

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

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

+ mutex_unlock(&rng_mutex);
+
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);
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 7244456..9bede76 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -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. */
--
1.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


mpm at selenic

Nov 30, 2009, 10:44 AM

Post #9 of 12 (217 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

On Mon, 2009-11-30 at 10:28 +0000, Ian Molton wrote:
> Rusty Russell wrote:
>
> > And might as well just #defube RNG_BUFFSIZE SMP_CACHE_BYTES (or use
> > SMP_CACHE_BYTES here and sizeof() elsewhere).
>
> This can lead to a rather small (4 byte) buffer on some systems, however
> I don't know if in practice a tiny buffer or a big one would be better
> for performance on those machines. I guess if its a problem someone can
> patch the code to allocate a minimum of (say) 16 bytes in future...

Hmmm, I think this was bad advice from Rusty.

The goal is to size and align the buffer so that we know it will always
work. Thus 64 bytes (always big enough but not so big that anyone will
complain) and cache aligned (makes stupid things like Via Padlock happy
-on Vias-).

Rusty's suggestion could easily have us in trouble if some driver wants
to hand us a mere 64 bits on an architecture with 4-byte cache alignment
but is otherwise perfectly happy with 64-bit stores.

--
http://selenic.com : development and support for Mercurial and Linux


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


rusty at rustcorp

Nov 30, 2009, 7:08 PM

Post #10 of 12 (215 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

On Tue, 1 Dec 2009 05:14:16 am Matt Mackall wrote:
> On Mon, 2009-11-30 at 10:28 +0000, Ian Molton wrote:
> > Rusty Russell wrote:
> >
> > > And might as well just #defube RNG_BUFFSIZE SMP_CACHE_BYTES (or use
> > > SMP_CACHE_BYTES here and sizeof() elsewhere).
> >
> > This can lead to a rather small (4 byte) buffer on some systems, however
> > I don't know if in practice a tiny buffer or a big one would be better
> > for performance on those machines. I guess if its a problem someone can
> > patch the code to allocate a minimum of (say) 16 bytes in future...
>
> Hmmm, I think this was bad advice from Rusty.

Me too. But really, it's because we're using cacheline alignment
as a proxy for something else, and it's not a good fit.

But we're bikeshedding, so apply or revert.

/* A buffer which can hold any fundamental type: drivers are fussy. */
static u8 rng_buffer[SMP_CACHE_BYTES < 8 ? 8 : SMP_CACHE_BYTES]
__cacheline_aligned;

Either way, both patches: Acked-by: Rusty Russell <rusty [at] rustcorp>

Thanks,
Rusty.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


ian.molton at collabora

Dec 1, 2009, 1:18 AM

Post #11 of 12 (215 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

Matt Mackall wrote:
> On Mon, 2009-11-30 at 10:28 +0000, Ian Molton wrote:
>> Rusty Russell wrote:
>>
>>> And might as well just #defube RNG_BUFFSIZE SMP_CACHE_BYTES (or use
>>> SMP_CACHE_BYTES here and sizeof() elsewhere).
>> This can lead to a rather small (4 byte) buffer on some systems, however
>> I don't know if in practice a tiny buffer or a big one would be better
>> for performance on those machines. I guess if its a problem someone can
>> patch the code to allocate a minimum of (say) 16 bytes in future...
>
> Hmmm, I think this was bad advice from Rusty.

Not entirely...

> The goal is to size and align the buffer so that we know it will always
> work. Thus 64 bytes (always big enough but not so big that anyone will
> complain) and cache aligned (makes stupid things like Via Padlock happy
> -on Vias-).

yep. Although making it the size of a cacheline makes sense on /most/
modern architectures - 32 bytes is a very common size - I think the
(current) worst case is one of the drivers wants to dump 3 u64s in one
go. virtio-rng will take what it can...

> Rusty's suggestion could easily have us in trouble if some driver wants
> to hand us a mere 64 bits on an architecture with 4-byte cache alignment
> but is otherwise perfectly happy with 64-bit stores.

How about SNP_CACHE_BYTES or if less, then 32 bytes minimum? Or just
stick with 64 bytes. Either way works for me.

-Ian
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


ian.molton at collabora

Dec 1, 2009, 1:23 AM

Post #12 of 12 (215 views)
Permalink
Re: [PATCH 1/2] hw_random: core updates to allow more efficient drivers [In reply to]

Rusty Russell wrote:

> But we're bikeshedding, so apply or revert.
>
> /* A buffer which can hold any fundamental type: drivers are fussy. */
> static u8 rng_buffer[SMP_CACHE_BYTES < 8 ? 8 : SMP_CACHE_BYTES]
> __cacheline_aligned;

One nit - theres one driver where <24 bytes will be quite suboptimal.
I'd say pick 32 bytes, which is a common cachline size, too.

> Either way, both patches: Acked-by: Rusty Russell <rusty [at] rustcorp>

Thanks!

-Ian
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Linux kernel RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.