Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: buffer: introduce support for attaching more IIO buffers

With this change, calling iio_device_attach_buffer() will actually attach
more buffers.
Right now this doesn't do any validation of whether a buffer is attached
twice; maybe that can be added later (if needed). Attaching a buffer more
than once should yield noticeably bad results.

The first buffer is the legacy buffer, so a reference is kept to it.

At this point, accessing the data for the extra buffers (that are added
after the first one) isn't possible yet.

The iio_device_attach_buffer() is also changed to return an error code,
which for now is -ENOMEM if the array could not be realloc-ed for more
buffers.
To adapt to this new change iio_device_attach_buffer() is called last in
all place where it's called. The realloc failure is a bit difficult to
handle during un-managed calls when unwinding, so it's better to have this
as the last error in the setup_buffer calls.

At this point, no driver should call iio_device_attach_buffer() directly,
it should call one of the {devm_}iio_triggered_buffer_setup() or
devm_iio_kfifo_buffer_setup() or devm_iio_dmaengine_buffer_setup()
functions. This makes iio_device_attach_buffer() a bit easier to handle.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Link: https://lore.kernel.org/r/20210215104043.91251-20-alexandru.ardelean@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Alexandru Ardelean and committed by
Jonathan Cameron
ee708e6b 738f6ba1

+111 -40
+1 -3
drivers/iio/buffer/industrialio-buffer-dmaengine.c
··· 290 290 291 291 indio_dev->modes |= INDIO_BUFFER_HARDWARE; 292 292 293 - iio_device_attach_buffer(indio_dev, buffer); 294 - 295 - return 0; 293 + return iio_device_attach_buffer(indio_dev, buffer); 296 294 } 297 295 EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); 298 296
+7 -3
drivers/iio/buffer/industrialio-triggered-buffer.c
··· 50 50 goto error_ret; 51 51 } 52 52 53 - iio_device_attach_buffer(indio_dev, buffer); 54 - 55 53 indio_dev->pollfunc = iio_alloc_pollfunc(h, 56 54 thread, 57 55 IRQF_ONESHOT, ··· 70 72 71 73 buffer->attrs = buffer_attrs; 72 74 75 + ret = iio_device_attach_buffer(indio_dev, buffer); 76 + if (ret < 0) 77 + goto error_dealloc_pollfunc; 78 + 73 79 return 0; 74 80 81 + error_dealloc_pollfunc: 82 + iio_dealloc_pollfunc(indio_dev->pollfunc); 75 83 error_kfifo_free: 76 - iio_kfifo_free(indio_dev->buffer); 84 + iio_kfifo_free(buffer); 77 85 error_ret: 78 86 return ret; 79 87 }
+1 -3
drivers/iio/buffer/kfifo_buf.c
··· 235 235 if (!buffer) 236 236 return -ENOMEM; 237 237 238 - iio_device_attach_buffer(indio_dev, buffer); 239 - 240 238 indio_dev->modes |= mode_flags; 241 239 indio_dev->setup_ops = setup_ops; 242 240 243 - return 0; 241 + return iio_device_attach_buffer(indio_dev, buffer); 244 242 } 245 243 EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup); 246 244
+6 -4
drivers/iio/iio_core.h
··· 69 69 ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf, 70 70 size_t n, loff_t *f_ps); 71 71 72 - int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev); 73 - void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev); 72 + int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev); 73 + void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev); 74 74 75 75 #define iio_buffer_poll_addr (&iio_buffer_poll) 76 76 #define iio_buffer_read_outer_addr (&iio_buffer_read_outer) 77 77 78 78 void iio_disable_all_buffers(struct iio_dev *indio_dev); 79 79 void iio_buffer_wakeup_poll(struct iio_dev *indio_dev); 80 + void iio_buffers_put(struct iio_dev *indio_dev); 80 81 81 82 #else 82 83 83 84 #define iio_buffer_poll_addr NULL 84 85 #define iio_buffer_read_outer_addr NULL 85 86 86 - static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) 87 + static inline int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) 87 88 { 88 89 return 0; 89 90 } 90 91 91 - static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {} 92 + static inline void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) {} 92 93 93 94 static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {} 94 95 static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {} 96 + static inline void iio_buffers_put(struct iio_dev *indio_dev) {} 95 97 96 98 #endif 97 99
+81 -19
drivers/iio/industrialio-buffer.c
··· 193 193 */ 194 194 void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) 195 195 { 196 - struct iio_buffer *buffer = indio_dev->buffer; 196 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 197 + struct iio_buffer *buffer; 198 + unsigned int i; 197 199 198 - if (!buffer) 199 - return; 200 - 201 - wake_up(&buffer->pollq); 200 + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { 201 + buffer = iio_dev_opaque->attached_buffers[i]; 202 + wake_up(&buffer->pollq); 203 + } 202 204 } 203 205 204 206 void iio_buffer_init(struct iio_buffer *buffer) ··· 213 211 buffer->watermark = 1; 214 212 } 215 213 EXPORT_SYMBOL(iio_buffer_init); 214 + 215 + void iio_buffers_put(struct iio_dev *indio_dev) 216 + { 217 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 218 + struct iio_buffer *buffer; 219 + unsigned int i; 220 + 221 + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { 222 + buffer = iio_dev_opaque->attached_buffers[i]; 223 + iio_buffer_put(buffer); 224 + } 225 + } 216 226 217 227 static ssize_t iio_show_scan_index(struct device *dev, 218 228 struct device_attribute *attr, ··· 1466 1452 iio_free_chan_devattr_list(&buffer->buffer_attr_list); 1467 1453 } 1468 1454 1469 - int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) 1455 + int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) 1470 1456 { 1471 - struct iio_buffer *buffer = indio_dev->buffer; 1457 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 1472 1458 const struct iio_chan_spec *channels; 1473 - int i; 1459 + struct iio_buffer *buffer; 1460 + int unwind_idx; 1461 + int ret, i; 1474 1462 1475 1463 channels = indio_dev->channels; 1476 1464 if (channels) { ··· 1483 1467 indio_dev->masklength = ml; 1484 1468 } 1485 1469 1486 - if (!buffer) 1470 + if (!iio_dev_opaque->attached_buffers_cnt) 1487 1471 return 0; 1488 1472 1489 - return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, 0); 1473 + for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) { 1474 + buffer = iio_dev_opaque->attached_buffers[i]; 1475 + ret = __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, i); 1476 + if (ret) { 1477 + unwind_idx = i; 1478 + goto error_unwind_sysfs_and_mask; 1479 + } 1480 + } 1481 + 1482 + return 0; 1483 + 1484 + error_unwind_sysfs_and_mask: 1485 + for (; unwind_idx >= 0; unwind_idx--) { 1486 + buffer = iio_dev_opaque->attached_buffers[unwind_idx]; 1487 + __iio_buffer_free_sysfs_and_mask(buffer); 1488 + } 1489 + kfree(iio_dev_opaque->attached_buffers); 1490 + return ret; 1490 1491 } 1491 1492 1492 - void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) 1493 + void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) 1493 1494 { 1494 - struct iio_buffer *buffer = indio_dev->buffer; 1495 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 1496 + struct iio_buffer *buffer; 1497 + int i; 1495 1498 1496 - if (!buffer) 1499 + if (!iio_dev_opaque->attached_buffers_cnt) 1497 1500 return; 1498 1501 1499 1502 iio_buffer_unregister_legacy_sysfs_groups(indio_dev); 1500 1503 1501 - __iio_buffer_free_sysfs_and_mask(buffer); 1504 + for (i = iio_dev_opaque->attached_buffers_cnt - 1; i >= 0; i--) { 1505 + buffer = iio_dev_opaque->attached_buffers[i]; 1506 + __iio_buffer_free_sysfs_and_mask(buffer); 1507 + } 1508 + 1509 + kfree(iio_dev_opaque->attached_buffers); 1502 1510 } 1503 1511 1504 1512 /** ··· 1640 1600 * @indio_dev: The device the buffer should be attached to 1641 1601 * @buffer: The buffer to attach to the device 1642 1602 * 1603 + * Return 0 if successful, negative if error. 1604 + * 1643 1605 * This function attaches a buffer to a IIO device. The buffer stays attached to 1644 - * the device until the device is freed. The function should only be called at 1645 - * most once per device. 1606 + * the device until the device is freed. For legacy reasons, the first attached 1607 + * buffer will also be assigned to 'indio_dev->buffer'. 1646 1608 */ 1647 - void iio_device_attach_buffer(struct iio_dev *indio_dev, 1648 - struct iio_buffer *buffer) 1609 + int iio_device_attach_buffer(struct iio_dev *indio_dev, 1610 + struct iio_buffer *buffer) 1649 1611 { 1650 - indio_dev->buffer = iio_buffer_get(buffer); 1612 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 1613 + struct iio_buffer **new, **old = iio_dev_opaque->attached_buffers; 1614 + unsigned int cnt = iio_dev_opaque->attached_buffers_cnt; 1615 + 1616 + cnt++; 1617 + 1618 + new = krealloc(old, sizeof(*new) * cnt, GFP_KERNEL); 1619 + if (!new) 1620 + return -ENOMEM; 1621 + iio_dev_opaque->attached_buffers = new; 1622 + 1623 + buffer = iio_buffer_get(buffer); 1624 + 1625 + /* first buffer is legacy; attach it to the IIO device directly */ 1626 + if (!indio_dev->buffer) 1627 + indio_dev->buffer = buffer; 1628 + 1629 + iio_dev_opaque->attached_buffers[cnt - 1] = buffer; 1630 + iio_dev_opaque->attached_buffers_cnt = cnt; 1631 + 1632 + return 0; 1651 1633 } 1652 1634 EXPORT_SYMBOL_GPL(iio_device_attach_buffer);
+6 -6
drivers/iio/industrialio-core.c
··· 1585 1585 iio_device_unregister_eventset(indio_dev); 1586 1586 iio_device_unregister_sysfs(indio_dev); 1587 1587 1588 - iio_buffer_put(indio_dev->buffer); 1588 + iio_buffers_put(indio_dev); 1589 1589 1590 1590 ida_simple_remove(&iio_ida, indio_dev->id); 1591 1591 kfree(iio_dev_opaque); ··· 1862 1862 1863 1863 iio_device_register_debugfs(indio_dev); 1864 1864 1865 - ret = iio_buffer_alloc_sysfs_and_mask(indio_dev); 1865 + ret = iio_buffers_alloc_sysfs_and_mask(indio_dev); 1866 1866 if (ret) { 1867 1867 dev_err(indio_dev->dev.parent, 1868 1868 "Failed to create buffer sysfs interfaces\n"); ··· 1888 1888 indio_dev->setup_ops == NULL) 1889 1889 indio_dev->setup_ops = &noop_ring_setup_ops; 1890 1890 1891 - if (indio_dev->buffer) 1891 + if (iio_dev_opaque->attached_buffers_cnt) 1892 1892 cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); 1893 1893 else if (iio_dev_opaque->event_interface) 1894 1894 cdev_init(&indio_dev->chrdev, &iio_event_fileops); 1895 1895 1896 - if (indio_dev->buffer || iio_dev_opaque->event_interface) { 1896 + if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) { 1897 1897 indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); 1898 1898 indio_dev->chrdev.owner = this_mod; 1899 1899 } ··· 1912 1912 error_free_sysfs: 1913 1913 iio_device_unregister_sysfs(indio_dev); 1914 1914 error_buffer_free_sysfs: 1915 - iio_buffer_free_sysfs_and_mask(indio_dev); 1915 + iio_buffers_free_sysfs_and_mask(indio_dev); 1916 1916 error_unreg_debugfs: 1917 1917 iio_device_unregister_debugfs(indio_dev); 1918 1918 return ret; ··· 1946 1946 1947 1947 mutex_unlock(&indio_dev->info_exist_lock); 1948 1948 1949 - iio_buffer_free_sysfs_and_mask(indio_dev); 1949 + iio_buffers_free_sysfs_and_mask(indio_dev); 1950 1950 } 1951 1951 EXPORT_SYMBOL(iio_device_unregister); 1952 1952
+2 -2
include/linux/iio/buffer.h
··· 41 41 bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, 42 42 const unsigned long *mask); 43 43 44 - void iio_device_attach_buffer(struct iio_dev *indio_dev, 45 - struct iio_buffer *buffer); 44 + int iio_device_attach_buffer(struct iio_dev *indio_dev, 45 + struct iio_buffer *buffer); 46 46 47 47 #endif /* _IIO_BUFFER_GENERIC_H_ */
+3
include/linux/iio/buffer_impl.h
··· 112 112 /* @demux_bounce: Buffer for doing gather from incoming scan. */ 113 113 void *demux_bounce; 114 114 115 + /* @attached_entry: Entry in the devices list of buffers attached by the driver. */ 116 + struct list_head attached_entry; 117 + 115 118 /* @buffer_list: Entry in the devices list of current buffers. */ 116 119 struct list_head buffer_list; 117 120
+4
include/linux/iio/iio-opaque.h
··· 7 7 * struct iio_dev_opaque - industrial I/O device opaque information 8 8 * @indio_dev: public industrial I/O device information 9 9 * @event_interface: event chrdevs associated with interrupt lines 10 + * @attached_buffers: array of buffers statically attached by the driver 11 + * @attached_buffers_cnt: number of buffers in the array of statically attached buffers 10 12 * @buffer_list: list of all buffers currently attached 11 13 * @channel_attr_list: keep track of automatically created channel 12 14 * attributes ··· 26 24 struct iio_dev_opaque { 27 25 struct iio_dev indio_dev; 28 26 struct iio_event_interface *event_interface; 27 + struct iio_buffer **attached_buffers; 28 + unsigned int attached_buffers_cnt; 29 29 struct list_head buffer_list; 30 30 struct list_head channel_attr_list; 31 31 struct attribute_group chan_attr_group;