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 Sun, May 29, 2016 at 10:19 PM, Jonathan Cameron <jic23@xxxxxxxxxx> wrote:
> On 22/05/16 22:30, Jonathan Cameron wrote:
>> 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
>
> This needs a review from someone!..  Daniel, it uses your configfs stuff so could
> you take a look if no one else does?
>

Sure, will look on this tomorrow.
> Thanks,
>
> 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
>>
>
> --
> 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



[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