diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 0b6f0abf3370..6bf79072179f 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1295,3 +1295,72 @@ 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_enabled +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A read-only boolean value that indicates if the hardware fifo is + currently enabled or disabled. If the device does not have a + hardware fifo this entry is not present. + The hardware fifo is enabled when the buffer is enabled if the + current hardware fifo watermark level is set and other current + device settings allows it (e.g. if a trigger is set that samples + data differently that the hardware fifo does then hardware fifo + will not enabled). + If the hardware fifo is enabled and the level of the hardware + fifo reaches the hardware fifo watermark level the device will + flush its hardware fifo to the device buffer. Doing a non + blocking read on the device when no samples are present in the + device buffer will also force a flush. + When the hardware fifo is enabled there is no need to use a + trigger to use buffer mode since the watermark settings + guarantees that the hardware fifo is flushed to the device + buffer. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + Read-only entry that contains a single integer specifying the + current watermark level for the hardware fifo. If the device + does not have a hardware fifo this entry is not present. + The watermark level for the hardware fifo is set by the driver + based on the value set by the user in buffer/watermark but + taking into account hardware limitations (e.g. most hardware + buffers are limited to 32-64 samples, some hardware buffers + watermarks are fixed or have minimum levels). A value of 0 + means that the hardware watermark is unset. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_min +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A single positive integer specifying the minimum watermark level + for the hardware fifo of this device. If the device does not + have a hardware fifo this entry is not present. + If the user sets buffer/watermark to a value less than this one, + then the hardware watermark will remain unset. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_max +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A single positive integer specifying the maximum watermark level + for the hardware fifo of this device. If the device does not + have a hardware fifo this entry is not present. + If the user sets buffer/watermark to a value greater than this + one, then the hardware watermark will be capped at this value. + +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_available +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + A list of positive integers specifying the available watermark + levels for the hardware fifo. This entry is optional and if it + is not present it means that all the values between + hwfifo_watermark_min and hwfifo_watermark_max are supported. + If the user sets buffer/watermark to a value greater than + hwfifo_watermak_min but not equal to any of the values in this + list, the driver will chose an appropriate value for the + hardware fifo watermark level. diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index a24b2e005eb3..df919f44d513 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 bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, - size_t to_wait) +static int iio_buffer_flush_hwfifo(struct iio_dev *indio_dev, + struct iio_buffer *buf, size_t required) { + if (!indio_dev->info->hwfifo_flush_to_buffer) + return -ENODEV; + + return indio_dev->info->hwfifo_flush_to_buffer(indio_dev, required); +} + +static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, + size_t to_wait, int to_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); + to_flush = 0; + } - if (iio_buffer_data_available(buf) >= to_wait) + avail = iio_buffer_data_available(buf); + + if (avail >= to_wait) { + /* force a flush for non-blocking reads */ + if (!to_wait && !avail && to_flush) + iio_buffer_flush_hwfifo(indio_dev, buf, to_flush); + return true; + } + + if (to_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; @@ -72,6 +101,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, struct iio_buffer *rb = indio_dev->buffer; size_t datum_size; size_t to_wait = 0; + size_t to_read; int ret; if (!indio_dev->info) @@ -89,12 +119,14 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, if (!datum_size) return 0; + to_read = min_t(size_t, n / datum_size, rb->watermark); + if (!(filp->f_flags & O_NONBLOCK)) - to_wait = min_t(size_t, n / datum_size, rb->watermark); + to_wait = to_read; do { ret = wait_event_interruptible(rb->pollq, - iio_buffer_ready(indio_dev, rb, to_wait)); + iio_buffer_ready(indio_dev, rb, to_wait, to_read)); if (ret) return ret; @@ -122,7 +154,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, 0)) return POLLIN | POLLRDNORM; return 0; } @@ -661,19 +693,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; } @@ -825,6 +854,9 @@ 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); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 80d855061064..d86b753e9b30 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -338,6 +338,16 @@ 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; see hwfifo_* entries in + * Documentation/ABI/testing/sysfs-bus-iio for details on + * how the hardware fifo operates + * @hwfifo_flush_to_buffer: function pointer to flush the samples stored + * in the hardware fifo to the device buffer. The driver + * should not flush more than count samples. The function + * must 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 +409,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_flush_to_buffer)(struct iio_dev *indio_dev, + unsigned count); }; /**