Re: [PATCH][RFC] iio: Move attach/detach of the poll func to the core

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

 



On 11/9/18 11:03 AM, Ardelean, Alexandru wrote:
> On Sat, 2018-11-03 at 18:19 +0000, Jonathan Cameron wrote:
>> On Fri, 22 Jun 2018 16:53:22 +0300
>> Alexandru Ardelean <alexandru.ardelean@xxxxxxxxxx> wrote:
> 
> Hey,
> 
> Thanks for taking the time for this, Jonathan.
> 
>>
>>> All devices using a triggered buffer need to attach and detach the
>>> trigger
>>> to the device in order to properly work. Instead of doing this in each
>>> and
>>> every driver by hand move this into the core.
>>>
>>> Signed-off-by: Lars-Peter Clausen <lars@xxxxxxxxxx>
>>> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@xxxxxxxxxx>
>>> ---
>>>
>>> Note: `Signed-off-by` is also Lars-Peter Clausen because he is the
>>> original author of this patch [on an older kernel].
>>> The patch has been updated since the original patch from Lars.
>>>
>>> There has been a (small) discussion about whether such a patch makes
>>> sense to implement (for reducing code duplication), or whether it's too
>>> risky to do it.
>>>
>>> The reason for the risky-ness is that there is no consistent way in
>>> which
>>> drivers attach/detach the poll function.
>>> i.e.
>>>    1. some drivers call `iio_triggered_buffer_postenable()` before
>>> doing HW
>>>       stuff, some after (for attaching the poll func)
>>>    2. similarly, for `iio_triggered_buffer_predisable()` some drivers
>>> do it
>>>       before HW stuff, some after (for detaching the poll func)
>>>
>>> Common sense would dictate that (in the case of
>>> `iio_triggered_buffer_postenable()`) there would normally be HW setup
>>> first
>>> and then attach the poll func.
>>> And the reverse done for `iio_triggered_buffer_predisable()`.
>>
>> I'm sure I once had the flow around this all well laid out, but I really
>> can't recall what it was and it was all tied around trying to do the
>> buffer enable as lockless as possible. Years ago Lars pointed out that
>> was impossible so a lot of the logic has been messed up since then.
>>
>> Anyhow, I've put this off long enough (sorry about that - just new it
>> was going to involve some head scratching!)  Crucially I have another
>> plan.  Figure out which drivers this actually makes a difference to
>> and thankfully in most cases the author is still active :)
>>
>>
>>>
>>> However, it's unclear whether this reasoning is completely sound for
>>> all
>>> drivers.
>>>
>>> Hence this RFC.
>>
>> I've culled the cases that are obvious.  Either just the defaults or
>> where we do the calls at the end of enable and start of disable.
>>
>> In those there is no ordering change.
>>
>> There are some odd ones
>> gp2ap020a00f does it under a lock. Which makes no difference.
>> isl29125 totally missbalanced so the preenable does things undone in the
>>    predisable.  I wonder if anyone has one to allow us to test cleaning
>>    that up. No flow change due to this patch though so fine.
>> tcs3414 is much the same as the isl29125.
>> lmp91000?? Is about all I can say on that.  It detaches a poll function
>> that
>> was never attached.
>>
>> Anyhow, so what's left (hopefully we haven't had any crazies since
>> you posted this patch. I'll check at somepoint)
>>
>>>  drivers/iio/adc/ad_sigma_delta.c              |  5 ----
>>
>> I'll assume you are fine with that one ;)
>>
>>>  drivers/iio/adc/dln2-adc.c                    |  4 +--
>>
>> + CC Jack Anderson (worst comes to the worst I have one of these and can
>>      run basic tests).
>>
>>>  drivers/iio/adc/stm32-adc.c                   | 11 --------
>>
>> + CC Fabrice

Hi Ardelean, Jonathan,

Thanks for CC'ing me. Please find my comments here here after.

>>
>>>  drivers/iio/adc/vf610_adc.c                   |  6 +----
>>
>> + CC Sanchayan who might still have access to one of these
>> + Bhuvanchanda who fixed a bug not so long ago...
>>
>>>  drivers/iio/chemical/atlas-ph-sensor.c        |  8 ------
>>
>> + CC Matt who is definitely still contactable as I met him last week ;)
>>
>>>  drivers/iio/potentiostat/lmp91000.c           |  1 -
>>
>> Another of Matt's.  On this one, I'm not sure who it attaches
>> the pollfunc in the first place.  I may be going crazy however, so
>> over to Matt to point out what I'm missing.
>>
>> So the actual change that matters is:
>>
>>> diff --git a/drivers/iio/industrialio-buffer.c
>>> b/drivers/iio/industrialio-buffer.c
>>> index cd5bfe39591b..d8eb534a9544 100644
>>> --- a/drivers/iio/industrialio-buffer.c
>>> +++ b/drivers/iio/industrialio-buffer.c
>>> @@ -24,6 +24,7 @@
>>>  
>>>  #include <linux/iio/iio.h>
>>>  #include "iio_core.h"
>>> +#include "iio_core_trigger.h"
>>>  #include <linux/iio/sysfs.h>
>>>  #include <linux/iio/buffer.h>
>>>  #include <linux/iio/buffer_impl.h>
>>> @@ -961,6 +962,13 @@ static int iio_enable_buffers(struct iio_dev
>>> *indio_dev,
>>>  		}
>>>  	}
>>>  
>>> +	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
>>> +		ret = iio_trigger_attach_poll_func(indio_dev->trig,
>>> +						   indio_dev->pollfunc);
>>> +		if (ret)
>>> +			goto err_disable_buffers;
>>> +	}
>>> +
>>
>> This is immediately after the postenable call.
>>
> 
> I'm vague here about your comment.
> Do I need to change something ?
> 

I have some concern about the ordering here as well, regarding
stm32-adc.c: I think this is same case as ad_sigma_delta.c (I haven't
checked the others).

With this patch, in stm32-adc case, the hardware gets started (e.g.
getting data with interrupts or dma) before the handler has been attached:
-> iio_triggered_buffer_postenable
 -> iio_trigger_attach_poll_func
  -> request_threaded_irq

I haven't tested it, but I think this is racy. I feel like
iio_trigger_attach_poll_func should happen before postenable call
(rather than after), see after stm32-adc.c.

>>>  	return 0;
>>>  
>>>  err_disable_buffers:
>>> @@ -987,6 +995,11 @@ static int iio_disable_buffers(struct iio_dev
>>> *indio_dev)
>>>  	if (list_empty(&indio_dev->buffer_list))
>>>  		return 0;
>>>  
>>
>> This is immediately before the predisable call.
> 
> Same here as above:
> ```
> I'm vague here about your comment.
> Do I need to change something ?
> ```
> 

Same here (at least for stm32-adc case): the handler gets unregistered
but the hardware is still running (e.g. getting data with interrupts or
dma).

I'd prefer the other way :-):
- upon enable: attach the poll func, then start the HW
- upon disable: stop the HW, detach the poll func

>>
>>> +	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
>>> +		iio_trigger_detach_poll_func(indio_dev->trig,
>>> +					     indio_dev->pollfunc);
>>> +	}
>>> +
>>>  	/*
>>>  	 * If things go wrong at some step in disable we still need to
>>> continue
>>>  	 * to perform the other steps, otherwise we leave the device in a
>>> diff --git a/drivers/iio/industrialio-trigger.c
>>> b/drivers/iio/industrialio-trigger.c
>>> index ce66699c7fcc..a4dacb638a72 100644
>>> --- a/drivers/iio/industrialio-trigger.c
>>> +++ b/drivers/iio/industrialio-trigger.c
>>> @@ -242,8 +242,8 @@ static void iio_trigger_put_irq(struct iio_trigger
>>> *trig, int irq)
>>>   * the relevant function is in there may be the best option.
>>>   */
>>>  /* Worth protecting against double additions? */
>>> -static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
>>> -					struct iio_poll_func *pf)
>>> +int iio_trigger_attach_poll_func(struct iio_trigger *trig,
>>> +				 struct iio_poll_func *pf)
>>>  {
>>>  	int ret = 0;
>>>  	bool notinuse
>>> @@ -290,8 +290,8 @@ static int iio_trigger_attach_poll_func(struct
>>> iio_trigger *trig,
>>>  	return ret;
>>>  }
>>>  
>>> -static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
>>> -					 struct iio_poll_func *pf)
>>> +int iio_trigger_detach_poll_func(struct iio_trigger *trig,
>>> +				 struct iio_poll_func *pf)
>>>  {
>>>  	int ret = 0;
>>>  	bool no_other_users
>>> @@ -758,17 +758,3 @@ void iio_device_unregister_trigger_consumer(struct
>>> iio_dev *indio_dev)
>>>  	if (indio_dev->trig)
>>>  		iio_trigger_put(indio_dev->trig);
>>>  }
>>> -
>>> -int iio_triggered_buffer_postenable(struct iio_dev *indio_dev)
>>> -{
>>> -	return iio_trigger_attach_poll_func(indio_dev->trig,
>>> -					    indio_dev->pollfunc);
>>> -}
>>> -EXPORT_SYMBOL(iio_triggered_buffer_postenable);
>>> -
>>> -int iio_triggered_buffer_predisable(struct iio_dev *indio_dev)
>>> -{
>>> -	return iio_trigger_detach_poll_func(indio_dev->trig,
>>> -					     indio_dev->pollfunc);
>>> -}
>>> -EXPORT_SYMBOL(iio_triggered_buffer_predisable);
>>
>>
>>
>>
>>> diff --git a/drivers/iio/adc/ad_sigma_delta.c
>>> b/drivers/iio/adc/ad_sigma_delta.c
>>> index cf1b048b0665..ef046277bf7b 100644
>>> --- a/drivers/iio/adc/ad_sigma_delta.c
>>> +++ b/drivers/iio/adc/ad_sigma_delta.c
>>> @@ -338,10 +338,6 @@ static int ad_sd_buffer_postenable(struct iio_dev
>>> *indio_dev)
>>>  	unsigned int channel;
>>>  	int ret;
>>>  
>>> -	ret = iio_triggered_buffer_postenable(indio_dev);
>>> -	if (ret < 0)
>>> -		return ret;
>>> -
>>
>> Here is one where the ordering actually changes. I'm going to hope you
>> concluded
>> this one was fine ;)
>>
> 
> Yep, this patch should be fine (for the ad_sigma_delta.c change).
> It's been in our tree for a while.
> 
>>>  	channel = find_first_bit(indio_dev->active_scan_mask,
>>>  				 indio_dev->masklength);
>>>  	ret = ad_sigma_delta_set_channel(sigma_delta,
>>> @@ -426,7 +422,6 @@ static irqreturn_t ad_sd_trigger_handler(int irq,
>>> void *p)
>>>  
>>>  static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
>>>  	.postenable = &ad_sd_buffer_postenable,
>>> -	.predisable = &iio_triggered_buffer_predisable,
>>>  	.postdisable = &ad_sd_buffer_postdisable,
>>>  	.validate_scan_mask = &iio_validate_scan_mask_onehot,
>>>  };
>>> diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
>>> index c64c6675cae6..51135e7c0d4f 100644
>>> --- a/drivers/iio/adc/dln2-adc.c
>>> +++ b/drivers/iio/adc/dln2-adc.c
>>> @@ -560,7 +560,7 @@ static int
>>> dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
>>>  		mutex_unlock(&dln2->mutex);
>>>  	}
>>>  
>>> -	return iio_triggered_buffer_postenable(indio_dev);
>>> +	return 0;
>>>  }
>>>  
>>>  static int dln2_adc_triggered_buffer_predisable(struct iio_dev
>>> *indio_dev)
>>> @@ -585,7 +585,7 @@ static int
>>> dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
>>>  		return ret;
>>>  	}
>>>  
>>> -	return iio_triggered_buffer_predisable(indio_dev);
>>
>> An unbalanced one.  Postenable is fine but presdisable.  Who knows..
>>
>>> +	return 0;
>>>  }
>>>  
>>> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
>>> index 378411853d75..ce0d17c03d7e 100644
>>> --- a/drivers/iio/adc/stm32-adc.c
>>> +++ b/drivers/iio/adc/stm32-adc.c
>>> @@ -1482,10 +1482,6 @@ static int stm32_adc_buffer_postenable(struct
>>> iio_dev *indio_dev)
>>>  		goto err_clr_trig;
>>>  	}
>>>  
>>> -	ret = iio_triggered_buffer_postenable(indio_dev);
>>> -	if (ret < 0)
>>> -		goto err_stop_dma;
>>> -

This is where the ordering changes.
I'd rather prefer to call "iio_trigger_attach_poll_func" before calling
the .postenable routine, and the reverse order when disabling.

Thanks,
Best regards,
Fabrice

>>>  	/* Reset adc buffer index */
>>>  	adc->bufi = 0;
>>>  
>>> @@ -1496,9 +1492,6 @@ static int stm32_adc_buffer_postenable(struct
>>> iio_dev *indio_dev)
>>>  
>>>  	return 0;
>>>  
>>> -err_stop_dma:
>>> -	if (adc->dma_chan)
>>> -		dmaengine_terminate_all(adc->dma_chan);
>>>  err_clr_trig:
>>>  	stm32_adc_set_trig(indio_dev, NULL);
>>>  err_unprepare:
>>> @@ -1517,10 +1510,6 @@ static int stm32_adc_buffer_predisable(struct
>>> iio_dev *indio_dev)
>>>  	if (!adc->dma_chan)
>>>  		stm32_adc_conv_irq_disable(adc);
>>>  
>>> -	ret = iio_triggered_buffer_predisable(indio_dev);
>>> -	if (ret < 0)
>>> -		dev_err(&indio_dev->dev, "predisable failed\n");
>>> -
>>>  	if (adc->dma_chan)
>>>  		dmaengine_terminate_all(adc->dma_chan);
>>>  
>>> diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
>>> index bbcb7a4d7edf..3a15b98cfd39 100644
>>> --- a/drivers/iio/adc/vf610_adc.c
>>> +++ b/drivers/iio/adc/vf610_adc.c
>>> @@ -740,10 +740,6 @@ static int vf610_adc_buffer_postenable(struct
>>> iio_dev *indio_dev)
>>>  	int ret;
>>>  	int val;
>>>  
>>> -	ret = iio_triggered_buffer_postenable(indio_dev);
>>> -	if (ret)
>>> -		return ret;
>>> -
>>>  	val = readl(info->regs + VF610_REG_ADC_GC);
>>>  	val |= VF610_ADC_ADCON;
>>>  	writel(val, info->regs + VF610_REG_ADC_GC);
>>> @@ -774,7 +770,7 @@ static int vf610_adc_buffer_predisable(struct
>>> iio_dev *indio_dev)
>>>  
>>>  	writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
>>>  
>>> -	return iio_triggered_buffer_predisable(indio_dev);
>>> +	return 0;
>>>  }
>>>  
>>>  static const struct iio_buffer_setup_ops
>>> iio_triggered_buffer_setup_ops = {
>>
>>
>>> diff --git a/drivers/iio/chemical/atlas-ph-sensor.c
>>> b/drivers/iio/chemical/atlas-ph-sensor.c
>>> index a406ad31b096..8fed75f9e95d 100644
>>> --- a/drivers/iio/chemical/atlas-ph-sensor.c
>>> +++ b/drivers/iio/chemical/atlas-ph-sensor.c
>>> @@ -305,10 +305,6 @@ static int atlas_buffer_postenable(struct iio_dev
>>> *indio_dev)
>>>  	struct atlas_data *data = iio_priv(indio_dev);
>>>  	int ret;
>>>  
>>> -	ret = iio_triggered_buffer_postenable(indio_dev);
>>> -	if (ret)
>>> -		return ret;
>>> -
>>>  	ret = pm_runtime_get_sync(&data->client->dev);
>>>  	if (ret < 0) {
>>>  		pm_runtime_put_noidle(&data->client->dev);
>>> @@ -323,10 +319,6 @@ static int atlas_buffer_predisable(struct iio_dev
>>> *indio_dev)
>>>  	struct atlas_data *data = iio_priv(indio_dev);
>>>  	int ret;
>>>  
>>> -	ret = iio_triggered_buffer_predisable(indio_dev);
>>> -	if (ret)
>>> -		return ret;
>>> -
>>>  	ret = atlas_set_interrupt(data, false);
>>>  	if (ret)
>>>  		return ret;
>>> diff --git a/drivers/iio/potentiostat/lmp91000.c
>>> b/drivers/iio/potentiostat/lmp91000.c
>>> index 85714055cc74..84f9105cbb37 100644
>>> --- a/drivers/iio/potentiostat/lmp91000.c
>>> +++ b/drivers/iio/potentiostat/lmp91000.c
>>> @@ -295,7 +295,6 @@ static int lmp91000_buffer_predisable(struct
>>> iio_dev *indio_dev)
>>>  
>>>  static const struct iio_buffer_setup_ops lmp91000_buffer_setup_ops = {
>>>  	.preenable = lmp91000_buffer_preenable,
>>> -	.postenable = iio_triggered_buffer_postenable,
>>
>> A resounding ??? 
>>>  	.predisable = lmp91000_buffer_predisable,
>>>  };
>>>  
>>
>>



[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