From: Jonathan Cameron <jic23@kernel.org>
To: Octavian Purdila <octavian.purdila@intel.com>, linux-iio@vger.kernel.org
Cc: srinivas.pandruvada@linux.intel.com
Subject: Re: [PATCH v5 2/3] iio: add support for hardware fifo
Date: Sat, 14 Mar 2015 18:16:32 +0000 [thread overview]
Message-ID: <55047B00.9000800@kernel.org> (raw)
In-Reply-To: <1425491773-28499-3-git-send-email-octavian.purdila@intel.com>
On 04/03/15 17:56, Octavian Purdila wrote:
> Some devices have hardware buffers that can store a number of samples
> for later consumption. Hardware usually provides interrupts to notify
> the processor when the fifo is full or when it has reached a certain
> threshold. This helps with reducing the number of interrupts to the
> host processor and thus it helps decreasing the power consumption.
>
> This patch adds support for hardware fifo to IIO by adding drivers
> operations for flushing the hadware fifo and setting and getting the
> watermark level.
>
> Since a driver may support hardware fifo only when not in triggered
> buffer mode (due to different samantics of hardware fifo sampling and
> triggered sampling) this patch changes the IIO core code to allow
> falling back to non-triggered buffered mode if no trigger is enabled.
>
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Bits and bobs inline
Typo's and a comment on weird hardware possibilities..
Also I'm not keen on some of the error handling.
Sorry it too me so very long to look at this. I keep thinking
it'll be fiddly and hence doing the easier stuff first only
to come to this and see that actually its very straight forward!.
Jonathan
> ---
> Documentation/ABI/testing/sysfs-bus-iio | 25 ++++++++++++
> drivers/iio/industrialio-buffer.c | 69 +++++++++++++++++++++++++++------
> include/linux/iio/iio.h | 26 +++++++++++++
> 3 files changed, 108 insertions(+), 12 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index 1283ca7..143ddf2d 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1264,3 +1264,28 @@ Description:
> allows the application to block on poll with a timeout and read
> the available samples after the timeout expires and thus have a
> maximum delay guarantee.
> +
> +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark
> +KernelVersion: 3.21
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Read-only entry that contains a single integer specifying the
> + current level for the hardware fifo watermark level. If this
> + value is negative it means that the device does not support a
> + hardware fifo. If this value is 0 it means that the hardware fifo
> + is currently disabled.
I wonder if we should indicate lack of hardware support by just not exporting
this attribute in the first place?
> + If this value is strictly positive it signals that the hardware
> + fifo of the device is active and that samples are stored in an
> + internal hardware buffer. When the level of the hardware fifo
> + reaches the watermark level the device will flush its internal
> + buffer to the device buffer. Because of this a trigger is not
> + needed to use the device in buffer mode.
> + The hardware watermark level is set by the driver based on the
> + value set by the user in buffer/watermark but taking into account
> + the limitations of the hardware (e.g. most hardware buffers are
> + limited to 32-64 samples).
> + Because the sematics of triggers and hardware fifo may be
> + different (e.g. the hadware fifo may record samples according to
hardware fifo
> + the sample rate while an any-motion trigger generates samples
> + based on the set rate of change) setting a trigger may disable
> + the hardware fifo.
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index a4f4f07..b6f1bd4 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -42,18 +42,47 @@ static size_t iio_buffer_data_available(struct iio_buffer *buf)
> return buf->access->data_available(buf);
> }
>
> +static int iio_buffer_flush_hwfifo(struct iio_dev *indio_dev,
> + struct iio_buffer *buf, size_t required)
> +{
> + if (!indio_dev->info->hwfifo_flush)
> + return -ENODEV;
> +
> + return indio_dev->info->hwfifo_flush(indio_dev, required);
> +}
> +
> static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
> - size_t to_wait)
> + size_t to_wait, bool try_flush)
> {
> + size_t avail;
> + int flushed = 0;
> +
> /* wakeup if the device was unregistered */
> if (!indio_dev->info)
> return true;
>
> /* drain the buffer if it was disabled */
> - if (!iio_buffer_is_active(buf))
> + if (!iio_buffer_is_active(buf)) {
> to_wait = min_t(size_t, to_wait, 1);
> + try_flush = false;
> + }
> +
> + avail = iio_buffer_data_available(buf);
>
> - if (iio_buffer_data_available(buf) >= to_wait)
> + if (avail >= to_wait) {
I'm not really following what this is for.
If to_wait = 0 and avail = 0 and we have requested a flush
then try to read 1 element?
I think this only occurs on a non blocking read when nothing is
available? What I don't understand is why we'd only try to read 1
sample. Surely asking for as many as requested is more intuitive?
> + /* force a flush for non-blocking reads */
> + if (!to_wait && !avail && try_flush)
> + iio_buffer_flush_hwfifo(indio_dev, buf, 1);
> + return true;
> + }
> +
> + if (try_flush)
> + flushed = iio_buffer_flush_hwfifo(indio_dev, buf,
> + to_wait - avail);
> + if (flushed <= 0)
> + return false;
> +
> + if (avail + flushed >= to_wait)
> return true;
>
> return false;
> @@ -92,7 +121,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>
> do {
> ret = wait_event_interruptible(rb->pollq,
> - iio_buffer_ready(indio_dev, rb, to_wait));
> + iio_buffer_ready(indio_dev, rb, to_wait, true));
> if (ret)
> return ret;
>
> @@ -120,7 +149,7 @@ unsigned int iio_buffer_poll(struct file *filp,
> return -ENODEV;
>
> poll_wait(filp, &rb->pollq, wait);
> - if (iio_buffer_ready(indio_dev, rb, rb->watermark))
> + if (iio_buffer_ready(indio_dev, rb, rb->watermark, false))
> return POLLIN | POLLRDNORM;
> return 0;
> }
> @@ -659,19 +688,16 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
> }
> }
> /* Definitely possible for devices to support both of these. */
> - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
> - if (!indio_dev->trig) {
> - printk(KERN_INFO "Buffer not started: no trigger\n");
> - ret = -EINVAL;
> - /* Can only occur on first buffer */
> - goto error_run_postdisable;
> - }
> + if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
> indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
> } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
> indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
> } else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
> indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
> } else { /* Should never be reached */
> + /* Can only occur on first buffer */
> + if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
> + pr_info("Buffer not started: no trigger\n");
> ret = -EINVAL;
> goto error_run_postdisable;
> }
> @@ -823,12 +849,28 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
> }
>
> buffer->watermark = val;
> +
> + if (indio_dev->info->hwfifo_set_watermark)
> + indio_dev->info->hwfifo_set_watermark(indio_dev, val);
> out:
> mutex_unlock(&indio_dev->mlock);
>
> return ret ? ret : len;
> }
>
> +static ssize_t iio_buffer_show_hwfifo_watermark(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + int ret = -1;
> +
> + if (indio_dev->info->hwfifo_get_watermark)
> + ret = indio_dev->info->hwfifo_get_watermark(indio_dev);
Any error code returned should be returned by this function to userspace.
Also, ret = -1 would be EPERM, a possible error code. Hence you need
to separate your handling of not supported from possible return values.
if (indio_dev->info->hwfifo_get_watermark) {
ret = indio_dev->info->hwfifo_get_watermark(indio_dev);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", ret);
} else {
return sprintf(buf, "-1\n");
seems the simplest way to me.
> +
> + return sprintf(buf, "%d\n", ret < -1 ? -1 : ret);
> +}
> +
> 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,
> @@ -837,11 +879,14 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
> iio_buffer_show_enable, iio_buffer_store_enable);
> static DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR,
> iio_buffer_show_watermark, iio_buffer_store_watermark);
> +static DEVICE_ATTR(hwfifo_watermark, S_IRUGO, iio_buffer_show_hwfifo_watermark,
> + NULL);
>
> static struct attribute *iio_buffer_attrs[] = {
> &dev_attr_length.attr,
> &dev_attr_enable.attr,
> &dev_attr_watermark.attr,
> + &dev_attr_hwfifo_watermark.attr,
> };
>
> int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 80d8550..1b1cd7d 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -338,6 +338,29 @@ struct iio_dev;
> * provide a custom of_xlate function that reads the
> * *args* and returns the appropriate index in registered
> * IIO channels array.
> + * @hwfifo_set_watermark: function pointer to set the current hardware fifo
> + * watermark level. It receives the desired watermark as a
> + * hint and the device driver may adjust it to take into
> + * account hardware limitations. Setting the watermark to a
> + * strictly positive value should enable the hardware fifo
> + * if not already enabled. When the hardware fifo is
> + * enabled and its level reaches the watermark level the
> + * device must flush the samples stored in the hardware
> + * fifo to the device buffer.
Hmm. This one is interesting. I wonder if we have devices with minimum
watermark levels. I know that devices with fixed levels exist (sca3000 IIRC)
but in that case if we are below the level we can fallback to the data ready
signal (watermark of 1 effectively). If the device provides no notification
that data capture is occuring until we reach a particular level (say 50% full)
then its not entirely clear whether we should turn the buffer on when a
watermark below that is set.
> Setting the watermark to 0
> + * should disable the hardware fifo. The device driver must
> + * disable the hardware fifo when a trigger with different
> + * sampling semantic (then the hardware fifo) is set
(than the...
> + * (e.g. when setting an any-motion trigger to a device
> + * that has its hardware fifo sample based on the set
> + * sample frequency).
> + * @hwfifo_get_watermark: function pointer to obtain the current hardware fifo
> + * watermark level
> + * @hwfifo_flush: function pointer to flush the samples stored in the
> + * hardware fifo to the device buffer. The driver should
> + * not flush more then count samples. The function must
more than count
> + * return the number of samples flushed, 0 if no samples
> + * were flushed or a negative integer if no samples were
> + * flushed and there was an error.
> **/
> struct iio_info {
> struct module *driver_module;
> @@ -399,6 +422,9 @@ struct iio_info {
> unsigned *readval);
> int (*of_xlate)(struct iio_dev *indio_dev,
> const struct of_phandle_args *iiospec);
> + int (*hwfifo_set_watermark)(struct iio_dev *indio_dev, unsigned val);
> + int (*hwfifo_get_watermark)(struct iio_dev *indio_dev);
> + int (*hwfifo_flush)(struct iio_dev *indio_dev, unsigned count);
> };
>
> /**
>
next prev parent reply other threads:[~2015-03-14 18:16 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-04 17:56 [PATCH v5 0/3] iio: add support for hardware fifos Octavian Purdila
2015-03-04 17:56 ` [PATCH v5 1/3] iio: add watermark logic to iio read and poll Octavian Purdila
2015-03-14 17:46 ` Jonathan Cameron
2015-03-18 9:19 ` Lars-Peter Clausen
2015-03-18 9:29 ` Octavian Purdila
2015-03-18 9:37 ` Lars-Peter Clausen
2015-03-19 15:43 ` Octavian Purdila
2015-03-19 15:46 ` Octavian Purdila
2015-03-04 17:56 ` [PATCH v5 2/3] iio: add support for hardware fifo Octavian Purdila
2015-03-14 18:16 ` Jonathan Cameron [this message]
2015-03-16 10:05 ` Octavian Purdila
2015-03-21 12:16 ` Jonathan Cameron
2015-03-18 11:55 ` Lars-Peter Clausen
2015-03-18 16:47 ` Octavian Purdila
2015-03-21 12:18 ` Jonathan Cameron
2015-03-04 17:56 ` [PATCH v5 3/3] iio: bmc150_accel: " Octavian Purdila
2015-03-14 18:32 ` 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=55047B00.9000800@kernel.org \
--to=jic23@kernel.org \
--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;
as well as URLs for NNTP newsgroup(s).