mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	staging:iio:sysfs-trigger: Use irq_work to properly active trigger
Since iio_trigger_poll() calls generic_handle_irq() it need to be called from
hardirq context. The sysfs trigger is kicked from userspace, so it is obviously
not possible to fulfill this requirement by calling iio_trigger_poll directly.
As a workaround commit 1f785681 ("staging:iio:trigger sysfs userspace trigger
rework.") added iio_trigger_poll_chained() which uses handle_nested_irq instead
of generic_handle_irq. This in itself is a hack and only works by chance.
handle_nested_irq is intended to be called from the threaded interrupt handler
of the parent IRQ. Using handle_nested_irq is also problematic since it will
only call the threaded handler of the IRQ. But quite a few IIO drivers rely on
their hardirq handler being called or undefined behaviour will occur.
This patch uses the irq_work framework to schedule the call to
iio_trigger_poll() from hardirq context, which fixes the issues described above.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									ed5514c925
								
							
						
					
					
						commit
						f38bc926d0
					
				| @ -21,6 +21,8 @@ config IIO_GPIO_TRIGGER | ||||
| config IIO_SYSFS_TRIGGER | ||||
| 	tristate "SYSFS trigger" | ||||
| 	depends on SYSFS | ||||
| 	depends on HAVE_IRQ_WORK | ||||
| 	select IRQ_WORK | ||||
| 	help | ||||
| 	  Provides support for using SYSFS entry as IIO triggers. | ||||
| 	  If unsure, say N (but it's safe to say "Y"). | ||||
|  | ||||
| @ -10,12 +10,14 @@ | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/irq_work.h> | ||||
| 
 | ||||
| #include <linux/iio/iio.h> | ||||
| #include <linux/iio/trigger.h> | ||||
| 
 | ||||
| struct iio_sysfs_trig { | ||||
| 	struct iio_trigger *trig; | ||||
| 	struct irq_work work; | ||||
| 	int id; | ||||
| 	struct list_head l; | ||||
| }; | ||||
| @ -89,11 +91,21 @@ static struct device iio_sysfs_trig_dev = { | ||||
| 	.release = &iio_trigger_sysfs_release, | ||||
| }; | ||||
| 
 | ||||
| static void iio_sysfs_trigger_work(struct irq_work *work) | ||||
| { | ||||
| 	struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig, | ||||
| 							work); | ||||
| 
 | ||||
| 	iio_trigger_poll(trig->trig, 0); | ||||
| } | ||||
| 
 | ||||
| static ssize_t iio_sysfs_trigger_poll(struct device *dev, | ||||
| 		struct device_attribute *attr, const char *buf, size_t count) | ||||
| { | ||||
| 	struct iio_trigger *trig = to_iio_trigger(dev); | ||||
| 	iio_trigger_poll_chained(trig, 0); | ||||
| 	struct iio_sysfs_trig *sysfs_trig = trig->private_data; | ||||
| 
 | ||||
| 	irq_work_queue(&sysfs_trig->work); | ||||
| 
 | ||||
| 	return count; | ||||
| } | ||||
| @ -148,6 +160,9 @@ static int iio_sysfs_trigger_probe(int id) | ||||
| 	t->trig->dev.groups = iio_sysfs_trigger_attr_groups; | ||||
| 	t->trig->ops = &iio_sysfs_trigger_ops; | ||||
| 	t->trig->dev.parent = &iio_sysfs_trig_dev; | ||||
| 	t->trig->private_data = t; | ||||
| 
 | ||||
| 	init_irq_work(&t->work, iio_sysfs_trigger_work); | ||||
| 
 | ||||
| 	ret = iio_trigger_register(t->trig); | ||||
| 	if (ret) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Lars-Peter Clausen
						Lars-Peter Clausen