Octavian Purdila schrieb am 29.01.2015 um 12:38: > On Thu, Jan 29, 2015 at 1:46 AM, Hartmut Knaack <knaack.h@xxxxxx> wrote: >> >> Octavian Purdila schrieb am 21.12.2014 um 01:42: >>> 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 allowing the >>> drivers to register operations for flushing the hadware fifo and >>> setting the watermark level. >>> >>> A driver implementing hardware fifo support must also provide a >>> watermark trigger which must contain "watermark" in its name. >>> >> >> A few comments inline, also addressed to the other IIO maintainers. >> > > Thanks for the review Hartmut. What do you think about the watermark > trigger approach? Looks good to me, so far. But keep in mind, that I am still pretty new to the IIO area, so people like Jonathan have a better understanding where the core development started out and where it should be heading. I will have a look at your other patches during the next days, as time permits. > > Also, after the discussion with Jonathan I am thinking of exposing a > dedicated watermark level for the hardware FIFO. That way userspace > can set a large value for the software buffer watermark and it also > give control to userspace over the hardware watermark. I think that > control is very important to achieve a good power/latency balance. > >>> Signed-off-by: Octavian Purdila <octavian.purdila@xxxxxxxxx> >>> --- >>> Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++ >>> drivers/iio/industrialio-buffer.c | 44 ++++++++++++++++++++++++++++----- >>> include/linux/iio/iio.h | 17 +++++++++++++ >>> 3 files changed, 77 insertions(+), 6 deletions(-) >>> >>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio >>> index 7260f1f..6bb67ac 100644 >>> --- a/Documentation/ABI/testing/sysfs-bus-iio >>> +++ b/Documentation/ABI/testing/sysfs-bus-iio >>> @@ -1152,3 +1152,25 @@ Description: >>> 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. >>> + If the device has a hardware fifo this value is going to be used >>> + for the hardware fifo watermark as well. >>> + >>> +What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length >>> +KernelVersion: 3.20 >>> +Contact: linux-iio@xxxxxxxxxxxxxxx >>> +Description: >>> + A single positive integer specifying the maximum number of >>> + samples that the hardware fifo has. If the device does not >>> + support hardware fifo this is zero. >>> + When a device supports hardware fifo it will expose a trigger >>> + with the name that contains "watermark" >>> + (e.g. i2c-BMC150A:00-watermark-dev0). >>> + To use the hardware fifo the user must set an appropriate value >>> + in the buffer/length and buffer/low_watermark entries and select >>> + the watermark trigger. At that poin the hardware fifo will be >>> + enabled and the samples will be collected in a hardware buffer. >>> + When the number of samples in the hardware fifo reaches the >>> + watermark level the watermark trigger is issued and data is >>> + flushed to the devices buffer. >>> + A hardware buffer flush will also be triggered when reading from >>> + the device buffer and there is not enough data available. >>> \ No newline at end of file >>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c >>> index 7f74c7f..3da6d07 100644 >>> --- a/drivers/iio/industrialio-buffer.c >>> +++ b/drivers/iio/industrialio-buffer.c >>> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf) >>> return !list_empty(&buf->buffer_list); >>> } >>> >>> -static size_t iio_buffer_data_available(struct iio_buffer *buf) >>> +static bool iio_buffer_data_available(struct iio_dev *indio_dev, >>> + struct iio_buffer *buf, size_t required) >>> { >>> - return buf->access->data_available(buf); >>> + size_t avail = buf->access->data_available(buf); >>> + >>> + if (avail < required && indio_dev->hwfifo) { >>> + indio_dev->hwfifo->flush(indio_dev); >>> + avail = buf->access->data_available(buf); >>> + } >>> + >>> + return avail >= required; >>> } >>> >>> /** >>> @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, >>> >>> do { >>> if (filp->f_flags & O_NONBLOCK) { >>> - if (!iio_buffer_data_available(rb)) { >>> + if (!iio_buffer_data_available(indio_dev, rb, 1)) { >>> ret = -EAGAIN; >>> break; >>> } >>> } else { >>> ret = wait_event_interruptible(rb->pollq, >>> - iio_buffer_data_available(rb) >= to_read || >>> + iio_buffer_data_available(indio_dev, rb, to_read) || >>> indio_dev->info == NULL); >>> if (ret) >>> return ret; >>> @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp, >>> return -ENODEV; >>> >>> poll_wait(filp, &rb->pollq, wait); >>> - if (iio_buffer_data_available(rb) >= rb->low_watermark) >>> + if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark)) >>> return POLLIN | POLLRDNORM; >>> return 0; >>> } >>> @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev, >>> if (buffer->length) >>> val = buffer->length; >>> >>> - if (val < buffer->low_watermark) >>> + if (val < buffer->low_watermark) { >>> + if (indio_dev->hwfifo) { >>> + ret = indio_dev->hwfifo->set_watermark(indio_dev, val); >>> + if (ret) >>> + return ret; >>> + } >>> buffer->low_watermark = val; >>> + } >>> >>> return len; >>> } >>> @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev, >>> goto out; >>> } >>> >>> + if (indio_dev->hwfifo) { >>> + ret = indio_dev->hwfifo->set_watermark(indio_dev, val); >>> + if (ret) >>> + goto out; >>> + } >>> + >>> buffer->low_watermark = val; >>> ret = 0; >>> out: >>> @@ -818,6 +838,16 @@ out: >>> return ret ? ret : len; >>> } >>> >>> +ssize_t iio_buffer_hwfifo_read_length(struct device *dev, >>> + struct device_attribute *attr, >>> + char *buf) >>> +{ >>> + struct iio_dev *indio_dev = dev_to_iio_dev(dev); >>> + const struct iio_hwfifo *hwfifo = indio_dev->hwfifo; >>> + >>> + return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0); >>> +} >>> + >>> 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, >>> @@ -826,11 +856,13 @@ 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 DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL); >>> >>> static struct attribute *iio_buffer_attrs[] = { >>> &dev_attr_length.attr, >>> &dev_attr_enable.attr, >>> &dev_attr_low_watermark.attr, >>> + &dev_attr_hwfifo_length.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 878d861..f64a05f 100644 >>> --- a/include/linux/iio/iio.h >>> +++ b/include/linux/iio/iio.h >>> @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops { >>> }; >>> >>> /** >>> + * struct iio_buffer_hwfifo_ops - hardware fifo operations >>> + * >>> + * @length: [DRIVER] the hardware fifo length >>> + * @set_watermark: [DRIVER] setups the watermark level >> Maybe use "sets" instead of "setups". >> > > Ok, sensible suggestion, I'll do that in the next version. > >> Also, and this is more a general question, as it was quite annoying when getting into >> the topic: I would prefer to place some information about the expected return values of >> these functions into these descriptions. What do you guys think about that? >> >>> + * @flush: [DRIVER] copies data from the hardware buffer to the >>> + * device buffer >>> + * @watermark_trig: [DRIVER] an allocated and registered trigger containing >>> + * "watermark" in its name >>> + */ >>> +struct iio_hwfifo { >>> + int length; >>> + int (*set_watermark)(struct iio_dev *, unsigned int); >>> + int (*flush)(struct iio_dev *); >>> +}; >>> + >>> +/** >>> * struct iio_dev - industrial I/O device >>> * @id: [INTERN] used to identify device internally >>> * @modes: [DRIVER] operating modes supported by device >>> @@ -491,6 +507,7 @@ struct iio_dev { >>> int groupcounter; >>> >>> unsigned long flags; >>> + const struct iio_hwfifo *hwfifo; >> This new entry should be added to the description of the iio_dev struct, as well. > > Sure. > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html