Re: [RFC PATCH V2] iio:trigger: Experimental kthread tight loop trigger (thread only)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 06/03/16 20:02, Jonathan Cameron wrote:
> This patch is in response to that of
> Gregor Boirie <gregor.boirie@xxxxxxxxxx>
> who proposed using a tight kthread within a device driver (be it with the
> support factored out into a helper library) in order to basically spin as
> fast as possible.
> 
> It is meant as a talking point rather than a formal proposal of the code
> (though we are heading towards that I think).
> Also gives people some working code to mess around with.
> 
> I proposed that this could be done with a trigger with a few constraints
> and this is the proof (be it ugly) of that.
> 
> There are some constraints though, some of which we would want to relax
> if this were to move forward.
> 
> * Will only run the thread part of the registered pollfunc.  This is to
>   avoid the overhead of jumping in and out of interrupt context.  Is the
>   overhead significant?  Not certain but feels like it should be!
> 
> * This limitation precludes any device that 'must' do some work in
>   interrupt context.  However, that is true of few if any drivers and
>   I suspect that any that do will be restricted to using triggers they
>   provide themselves.  Usually we have a top half mainly to grab a
>   timestamp as soon after the dataready type signal as possible.
> 
> Signed-off-by: Jonathan Cameron <jic23@xxxxxxxxxx>
Any comments on this anyone?

Whilst we still haven't dealt with the question of neatly handling
the missing top halves (where relevant) I think it might be worth taking this
soonish as we have genuine use cases...

Would be easy enough to modify the pollfunc generic timestamp code to play
a few games to ensure it grabs a software timestamp in the threaded handler if needed
(inserting an appropriate access function into all users)..
say
iio_pollfunc_get_ts_best_effort() that uses the top half stored one if available
(also setting a 'new timestamp' available if from a hardware source) or if not
grabs one at call time in the threaded handler.


Jonathan
> ---
>  drivers/iio/trigger/Kconfig         |  12 +++
>  drivers/iio/trigger/Makefile        |   1 +
>  drivers/iio/trigger/iio-trig-loop.c | 143 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 156 insertions(+)
> 
> diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
> index 519e6772f6f5..9feabe95eeda 100644
> --- a/drivers/iio/trigger/Kconfig
> +++ b/drivers/iio/trigger/Kconfig
> @@ -24,6 +24,18 @@ config IIO_INTERRUPT_TRIGGER
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called iio-trig-interrupt.
>  
> +config IIO_TIGHTLOOP_TRIGGER
> +	tristate "A kthread based hammering loop trigger"
> +	depends on IIO_SW_TRIGGER
> +	help
> +	  An experimental trigger, used to allow sensors to be sampled as fast
> +	  as possible under the limitations of whatever else is going on.
> +	  Uses a tight loop in a kthread.  Will only work with lower half only
> +	  trigger consumers.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called iio-trig-loop.	  
> +
>  config IIO_SYSFS_TRIGGER
>  	tristate "SYSFS trigger"
>  	depends on SYSFS
> diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
> index fe06eb564367..aab4dc23303d 100644
> --- a/drivers/iio/trigger/Makefile
> +++ b/drivers/iio/trigger/Makefile
> @@ -7,3 +7,4 @@
>  obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
>  obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
>  obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
> +obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o
> diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c
> new file mode 100644
> index 000000000000..dc6be28f96fe
> --- /dev/null
> +++ b/drivers/iio/trigger/iio-trig-loop.c
> @@ -0,0 +1,143 @@
> +/*
> + * Copyright 2016 Jonathan Cameron <jic23@xxxxxxxxxx>
> + *
> + * Licensed under the GPL-2.
> + *
> + * Based on a mashup of the hrtimer trigger and continuous sampling proposal of
> + * Gregor Boirie <gregor.boirie@xxxxxxxxxx>
> + *
> + * Note this is still rather experimental and may eat babies.
> + *
> + * Todo
> + * * Protect against connection of devices that 'need' the top half
> + *   handler.
> + * * Work out how to run top half handlers in this context if it is
> + *   safe to do so (timestamp grabbing for example)
> + *
> + * Tested against a max1363. Used about 33% cpu for the thread and 20%
> + * for generic_buffer piping to /dev/null. Watermark set at 64 on a 128
> + * element kfifo buffer.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/irq_work.h>
> +#include <linux/kthread.h>
> +#include <linux/freezer.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/sw_trigger.h>
> +
> +struct iio_loop_info {
> +	struct iio_sw_trigger swt;
> +	struct task_struct *task;
> +};
> +
> +static struct config_item_type iio_loop_type = {
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static int iio_loop_thread(void *data)
> +{
> +	struct iio_trigger *trig = data;
> +
> +	set_freezable();
> +
> +	do {
> +		iio_trigger_poll_chained(trig);
> +	} while (likely(!kthread_freezable_should_stop(NULL)));
> +
> +	return 0;
> +}
> +
> +static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state)
> +{
> +	struct iio_loop_info *loop_trig = iio_trigger_get_drvdata(trig);
> +
> +	if (state) {
> +		loop_trig->task = kthread_run(iio_loop_thread,
> +					      trig, trig->name);
> +		if (unlikely(IS_ERR(loop_trig->task))) {
> +			dev_err(&trig->dev,
> +				"failed to create trigger loop thread\n");
> +			return PTR_ERR(loop_trig->task);
> +		}
> +	} else {
> +		kthread_stop(loop_trig->task);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct iio_trigger_ops iio_loop_trigger_ops = {
> +	.set_trigger_state = iio_loop_trigger_set_state,
> +	.owner = THIS_MODULE,
> +};
> +
> +static struct iio_sw_trigger *iio_trig_loop_probe(const char *name)
> +{
> +	struct iio_loop_info *trig_info;
> +	int ret;
> +
> +	trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
> +	if (!trig_info)
> +		return ERR_PTR(-ENOMEM);
> +
> +	trig_info->swt.trigger = iio_trigger_alloc("%s", name);
> +	if (!trig_info->swt.trigger) {
> +		ret = -ENOMEM;
> +		goto err_free_trig_info;
> +	}
> +
> +	iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
> +	trig_info->swt.trigger->ops = &iio_loop_trigger_ops;
> +
> +	ret = iio_trigger_register(trig_info->swt.trigger);
> +	if (ret)
> +		goto err_free_trigger;
> +
> +	iio_swt_group_init_type_name(&trig_info->swt, name, &iio_loop_type);
> +
> +	return &trig_info->swt;
> +
> +err_free_trigger:
> +	iio_trigger_free(trig_info->swt.trigger);
> +err_free_trig_info:
> +	kfree(trig_info);
> +
> +	return ERR_PTR(ret);
> +}
> +
> +static int iio_trig_loop_remove(struct iio_sw_trigger *swt)
> +{
> +	struct iio_loop_info *trig_info;
> +
> +	trig_info = iio_trigger_get_drvdata(swt->trigger);
> +
> +	iio_trigger_unregister(swt->trigger);
> +	iio_trigger_free(swt->trigger);
> +	kfree(trig_info);
> +
> +	return 0;
> +}
> +
> +static const struct iio_sw_trigger_ops iio_trig_loop_ops = {
> +	.probe = iio_trig_loop_probe,
> +	.remove = iio_trig_loop_remove,
> +};
> +
> +static struct iio_sw_trigger_type iio_trig_loop = {
> +	.name = "loop",
> +	.owner = THIS_MODULE,
> +	.ops = &iio_trig_loop_ops,
> +};
> +
> +module_iio_sw_trigger_driver(iio_trig_loop);
> +
> +MODULE_AUTHOR("Jonathan Cameron <jic23@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("Loop based trigger for the iio subsystem");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:iio-trig-loop");
> 

--
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



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux