From: Jonathan Cameron <jic23@kernel.org>
To: Octavian Purdila <octavian.purdila@intel.com>, linux-iio@vger.kernel.org
Cc: srinivas.pandruvada@linux.intel.com,
Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
Subject: Re: [PATCH v3 2/9] iio: add watermark logic to iio read and poll
Date: Wed, 04 Feb 2015 18:49:27 +0000 [thread overview]
Message-ID: <54D269B7.3070202@kernel.org> (raw)
In-Reply-To: <1422662408-8149-3-git-send-email-octavian.purdila@intel.com>
On 31/01/15 00:00, Octavian Purdila wrote:
> From: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
>
> Currently the IIO buffer blocking read only wait until at least one
> data element is available.
> This patch makes the reader sleep until enough data is collected before
> returning to userspace. This should limit the read() calls count when
> trying to get data in batches.
>
> Co-author: Yannick Bedhomme <yannick.bedhomme@mobile-devices.fr>
> Signed-off-by: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
> [rebased and remove buffer timeout]
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
One question on the ABI below... Otherwise looks good to me.
> ---
> Documentation/ABI/testing/sysfs-bus-iio | 10 +++
> drivers/iio/industrialio-buffer.c | 124 ++++++++++++++++++++++++++-----
> drivers/iio/kfifo_buf.c | 11 +--
> drivers/staging/iio/accel/sca3000_ring.c | 4 +-
> include/linux/iio/buffer.h | 8 +-
> 5 files changed, 127 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index c03a140..2a3dc12 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1193,3 +1193,13 @@ Description:
> This attribute is used to read the current speed value of the
> user (which is the norm or magnitude of the velocity vector).
> Units after application of scale are m/s.
> +
> +What: /sys/bus/iio/devices/iio:deviceX/buffer/low_watermark
Just thinking about this again. Why low?
> +KernelVersion: 3.20
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + A single positive integer specifying the maximum number of scan
> + elements to wait for.
> + Poll will block until the watermark is reached.
> + Blocking read will wait until the minimum between the requested
> + read amount or the low water mark is available.
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index c2d5440..e008ce03 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -37,7 +37,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
> return !list_empty(&buf->buffer_list);
> }
>
> -static bool iio_buffer_data_available(struct iio_buffer *buf)
> +static size_t iio_buffer_data_available(struct iio_buffer *buf)
> {
> return buf->access->data_available(buf);
> }
> @@ -53,6 +53,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
> {
> struct iio_dev *indio_dev = filp->private_data;
> struct iio_buffer *rb = indio_dev->buffer;
> + size_t datum_size = rb->bytes_per_datum;
> + size_t to_read;
> + size_t count = 0;
> int ret;
>
> if (!indio_dev->info)
> @@ -61,26 +64,48 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
> if (!rb || !rb->access->read_first_n)
> return -EINVAL;
>
> - do {
> - if (!iio_buffer_data_available(rb)) {
> - if (filp->f_flags & O_NONBLOCK)
> - return -EAGAIN;
> + /*
> + * If datum_size is 0 there will never be anything to read from the
> + * buffer, so signal end of file now.
> + */
> + if (!datum_size)
> + return 0;
>
> + to_read = min_t(size_t, n / datum_size, rb->low_watermark);
> +
> + do {
> + if (filp->f_flags & O_NONBLOCK) {
> + if (!iio_buffer_data_available(rb)) {
> + ret = -EAGAIN;
> + break;
> + }
> + } else {
> ret = wait_event_interruptible(rb->pollq,
> - iio_buffer_data_available(rb) ||
> - indio_dev->info == NULL);
> + iio_buffer_data_available(rb) >= to_read ||
> + indio_dev->info == NULL);
> if (ret)
> return ret;
> - if (indio_dev->info == NULL)
> - return -ENODEV;
> + if (indio_dev->info == NULL) {
> + ret = -ENODEV;
> + break;
> + }
> }
>
> - ret = rb->access->read_first_n(rb, n, buf);
> - if (ret == 0 && (filp->f_flags & O_NONBLOCK))
> - ret = -EAGAIN;
> - } while (ret == 0);
> + ret = rb->access->read_first_n(rb, n, buf + count);
> + if (ret < 0)
> + break;
>
> - return ret;
> + count += ret;
> + n -= ret;
> + to_read -= ret / datum_size;
> + } while (to_read > 0);
> +
> + if (count)
> + return count;
> + if (ret < 0)
> + return ret;
> +
> + return -EAGAIN;
> }
>
> /**
> @@ -96,9 +121,8 @@ unsigned int iio_buffer_poll(struct file *filp,
> return -ENODEV;
>
> poll_wait(filp, &rb->pollq, wait);
> - if (iio_buffer_data_available(rb))
> + if (iio_buffer_data_available(rb) >= rb->low_watermark)
> return POLLIN | POLLRDNORM;
> - /* need a way of knowing if there may be enough data... */
> return 0;
> }
>
> @@ -123,6 +147,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
> INIT_LIST_HEAD(&buffer->buffer_list);
> init_waitqueue_head(&buffer->pollq);
> kref_init(&buffer->ref);
> + buffer->low_watermark = 1;
> }
> EXPORT_SYMBOL(iio_buffer_init);
>
> @@ -418,7 +443,16 @@ static ssize_t iio_buffer_write_length(struct device *dev,
> }
> mutex_unlock(&indio_dev->mlock);
>
> - return ret ? ret : len;
> + if (ret)
> + return ret;
> +
> + if (buffer->length)
> + val = buffer->length;
> +
> + if (val < buffer->low_watermark)
> + buffer->low_watermark = val;
> +
> + return len;
> }
>
> static ssize_t iio_buffer_show_enable(struct device *dev,
> @@ -472,6 +506,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
> static void iio_buffer_deactivate(struct iio_buffer *buffer)
> {
> list_del_init(&buffer->buffer_list);
> + wake_up_interruptible(&buffer->pollq);
> iio_buffer_put(buffer);
> }
>
> @@ -754,16 +789,59 @@ done:
>
> static const char * const iio_scan_elements_group_name = "scan_elements";
>
> +static ssize_t iio_buffer_show_watermark(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_buffer *buffer = indio_dev->buffer;
> +
> + return sprintf(buf, "%u\n", buffer->low_watermark);
> +}
> +
> +static ssize_t iio_buffer_store_watermark(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t len)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_buffer *buffer = indio_dev->buffer;
> + unsigned int val;
> + int ret;
> +
> + ret = kstrtouint(buf, 10, &val);
> + if (ret)
> + return ret;
> +
> + if (val > buffer->length)
> + return -EINVAL;
> +
> + mutex_lock(&indio_dev->mlock);
> + if (iio_buffer_is_active(indio_dev->buffer)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> + buffer->low_watermark = val;
> + ret = 0;
> +out:
> + mutex_unlock(&indio_dev->mlock);
> + return ret ? ret : len;
> +}
> +
> static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
> iio_buffer_write_length);
> static struct device_attribute dev_attr_length_ro = __ATTR(length,
> S_IRUGO, iio_buffer_read_length, NULL);
> static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
> iio_buffer_show_enable, iio_buffer_store_enable);
> +static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
> + iio_buffer_show_watermark, iio_buffer_store_watermark);
>
> static struct attribute *iio_buffer_attrs[] = {
> &dev_attr_length.attr,
> &dev_attr_enable.attr,
> + &dev_attr_low_watermark.attr,
> };
>
> int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> @@ -944,8 +1022,18 @@ static const void *iio_demux(struct iio_buffer *buffer,
> static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data)
> {
> const void *dataout = iio_demux(buffer, data);
> + int ret;
> +
> + ret = buffer->access->store_to(buffer, dataout);
> + if (ret)
> + return ret;
>
> - return buffer->access->store_to(buffer, dataout);
> + /*
> + * We can't just test for watermark to decide if we wake the poll queue
> + * because read may request less samples than the watermark.
> + */
> + wake_up_interruptible(&buffer->pollq);
> + return 0;
> }
>
> static void iio_buffer_demux_free(struct iio_buffer *buffer)
> diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
> index b2beea0..847ca56 100644
> --- a/drivers/iio/kfifo_buf.c
> +++ b/drivers/iio/kfifo_buf.c
> @@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
> ret = kfifo_in(&kf->kf, data, 1);
> if (ret != 1)
> return -EBUSY;
> -
> - wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
> -
> return 0;
> }
>
> @@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
> return copied;
> }
>
> -static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
> +static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
> {
> struct iio_kfifo *kf = iio_to_kfifo(r);
> - bool empty;
> + size_t samples;
>
> mutex_lock(&kf->user_lock);
> - empty = kfifo_is_empty(&kf->kf);
> + samples = kfifo_len(&kf->kf);
> mutex_unlock(&kf->user_lock);
>
> - return !empty;
> + return samples;
> }
>
> static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
> diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
> index f76a268..1e65dea 100644
> --- a/drivers/staging/iio/accel/sca3000_ring.c
> +++ b/drivers/staging/iio/accel/sca3000_ring.c
> @@ -129,9 +129,9 @@ error_ret:
> return ret ? ret : num_read;
> }
>
> -static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
> +static size_t sca3000_ring_buf_data_available(struct iio_buffer *r)
> {
> - return r->stufftoread;
> + return r->stufftoread ? r->low_watermark : 0;
> }
>
> /**
> diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
> index b65850a..4459e01 100644
> --- a/include/linux/iio/buffer.h
> +++ b/include/linux/iio/buffer.h
> @@ -21,8 +21,8 @@ struct iio_buffer;
> * struct iio_buffer_access_funcs - access functions for buffers.
> * @store_to: actually store stuff to the buffer
> * @read_first_n: try to get a specified number of bytes (must exist)
> - * @data_available: indicates whether data for reading from the buffer is
> - * available.
> + * @data_available: indicates how much data is available for reading from
> + * the buffer.
> * @request_update: if a parameter change has been marked, update underlying
> * storage.
> * @set_bytes_per_datum:set number of bytes per datum
> @@ -43,7 +43,7 @@ struct iio_buffer_access_funcs {
> int (*read_first_n)(struct iio_buffer *buffer,
> size_t n,
> char __user *buf);
> - bool (*data_available)(struct iio_buffer *buffer);
> + size_t (*data_available)(struct iio_buffer *buffer);
>
> int (*request_update)(struct iio_buffer *buffer);
>
> @@ -72,6 +72,7 @@ struct iio_buffer_access_funcs {
> * @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
> * @buffer_list: [INTERN] entry in the devices list of current buffers.
> * @ref: [INTERN] reference count of the buffer.
> + * @low_watermark: [INTERN] number of datums to wait for poll/read.
> */
> struct iio_buffer {
> int length;
> @@ -90,6 +91,7 @@ struct iio_buffer {
> void *demux_bounce;
> struct list_head buffer_list;
> struct kref ref;
> + unsigned int low_watermark;
> };
>
> /**
>
next prev parent reply other threads:[~2015-02-04 18:49 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-30 23:59 [PATCH v3 0/9] iio: add support for hardware fifo Octavian Purdila
2015-01-31 0:00 ` [PATCH v3 1/9] iio: buffer: refactor buffer attributes setup Octavian Purdila
2015-02-04 18:47 ` Jonathan Cameron
2015-01-31 0:00 ` [PATCH v3 2/9] iio: add watermark logic to iio read and poll Octavian Purdila
2015-02-04 18:49 ` Jonathan Cameron [this message]
2015-02-04 19:29 ` Octavian Purdila
2015-01-31 0:00 ` [PATCH v3 3/9] iio: add support for hardware fifo Octavian Purdila
2015-02-08 10:33 ` Jonathan Cameron
2015-01-31 0:00 ` [PATCH v3 4/9] iio: bmc150: refactor slope duration and threshold update Octavian Purdila
2015-02-05 17:02 ` Srinivas Pandruvada
2015-02-08 10:37 ` Jonathan Cameron
2015-02-09 9:54 ` Octavian Purdila
2015-01-31 0:00 ` [PATCH v3 5/9] iio: bmc150: refactor interrupt enabling Octavian Purdila
2015-02-05 17:06 ` Srinivas Pandruvada
2015-02-08 10:39 ` Jonathan Cameron
2015-01-31 0:00 ` [PATCH v3 6/9] iio: bmc150: exit early if event / trigger state is not changed Octavian Purdila
2015-02-05 17:09 ` Srinivas Pandruvada
2015-02-08 10:40 ` Jonathan Cameron
2015-01-31 0:00 ` [PATCH v3 7/9] iio: bmc150: introduce bmc150_accel_interrupt Octavian Purdila
2015-02-08 11:01 ` Jonathan Cameron
2015-01-31 0:00 ` [PATCH v3 8/9] iio: bmc150: introduce bmc150_accel_trigger Octavian Purdila
2015-02-08 11:07 ` Jonathan Cameron
2015-02-14 0:03 ` Srinivas Pandruvada
2015-01-31 0:00 ` [PATCH v3 9/9] iio: bmc150: add support for hardware fifo Octavian Purdila
2015-02-08 11:26 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54D269B7.3070202@kernel.org \
--to=jic23@kernel.org \
--cc=josselin.costanzi@mobile-devices.fr \
--cc=linux-iio@vger.kernel.org \
--cc=octavian.purdila@intel.com \
--cc=srinivas.pandruvada@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox