diff mbox series

[RFC] iio:st_magn: enable device after trigger

Message ID 20181015015336.21066-1-martin@martingkelly.com (mailing list archive)
State New, archived
Headers show
Series [RFC] iio:st_magn: enable device after trigger | expand

Commit Message

Martin Kelly Oct. 15, 2018, 1:53 a.m. UTC
From: Martin Kelly <martin@martingkelly.com>

I'd like to get others' opinions on this patch before I submit it. It fixes
an issue I've seen with a driver I'm working on (LSM9DS1 magnetometer
driver, waiting on this before I send a patch). However, I have a few
concerns about the generality of this approach:

(1) Possible data races between st_sensors_set_enable and IRQ handlers,
    since both could run concurrently. Although we can protect this with a
    lock, we'd need to touch each driver, which will be tricky to test.
    Alternatively, we could audit each driver and see if there are any real
    races. The only property touched by st_sensors_set_enable appears to be
    the "enabled" property, which is unlikely to be read/written by any IRQ
    handlers. That said, the fact that the race exists makes me concerned
    about potential mistakes in the future.
(2) If this is a good approach to solve the issue, then we should make the
    same change to the ST accelerometer, gyroscope, and pressure drivers.
    But again, we'd need to re-test every driver, which is tricky.

I'd be happy to hear opinions or suggested alternative approaches. Thanks!

Patch:
--------------------------------------------------------------------------
Currently, we enable the device before we enable the device trigger. At
high frequencies, this can cause interrupts that don't yet have a poll
function associated with them and are thus treated as spurious. At high
frequencies with level interrupts, this can even cause an interrupt storm
of repeated spurious interrupts (~100,000 on my Beagleboard with the
LSM9DS1 magnetometer). If these repeat too much, the interrupt will get
disabled and the device will stop functioning.

To prevent these problems, enable the device prior to enabling the device
trigger, and disable the divec prior to disabling the trigger. This means
there's no window of time during which the device creates interrupts but we
have no trigger to answer them.

Signed-off-by: Martin Kelly <martin@martingkelly.com>
---
 drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

--
2.11.0

Comments

Lorenzo Bianconi Oct. 15, 2018, 7:19 a.m. UTC | #1
> Currently, we enable the device before we enable the device trigger. At
> high frequencies, this can cause interrupts that don't yet have a poll
> function associated with them and are thus treated as spurious. At high
> frequencies with level interrupts, this can even cause an interrupt storm
> of repeated spurious interrupts (~100,000 on my Beagleboard with the
> LSM9DS1 magnetometer). If these repeat too much, the interrupt will get
> disabled and the device will stop functioning.
>
> To prevent these problems, enable the device prior to enabling the device
> trigger, and disable the divec prior to disabling the trigger. This means
> there's no window of time during which the device creates interrupts but we
> have no trigger to answer them.
>

I have just reviewed the code (not carried out any tests) and I guess this patch
is correct. Moreover if the memory allocation in st_magn_buffer_postenable fails
we will end up with a device generating interrupts without any buffer
to collect data.
I guess there is the same issue in st_magn_buffer_predisable(), if
st_sensors_set_enable
or iio_triggered_buffer_predisable fails, should we remove the data
buffer? Maybe we
just skip return code from st_sensors_set_enable.
@Denis: any hints?

Regards,
Lorenzo

> Signed-off-by: Martin Kelly <martin@martingkelly.com>
> ---
>  drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
>  1 file changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
> index 0a9e8fadfa9d..37ab30566464 100644
> --- a/drivers/iio/magnetometer/st_magn_buffer.c
> +++ b/drivers/iio/magnetometer/st_magn_buffer.c
> @@ -30,11 +30,6 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
>         return st_sensors_set_dataready_irq(indio_dev, state);
>  }
>
> -static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
> -{
> -       return st_sensors_set_enable(indio_dev, true);
> -}
> -
>  static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>  {
>         int err;
> @@ -50,7 +45,7 @@ static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>         if (err < 0)
>                 goto st_magn_buffer_postenable_error;
>
> -       return err;
> +       return st_sensors_set_enable(indio_dev, true);
>
>  st_magn_buffer_postenable_error:
>         kfree(mdata->buffer_data);
> @@ -63,11 +58,11 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>         int err;
>         struct st_sensor_data *mdata = iio_priv(indio_dev);
>
> -       err = iio_triggered_buffer_predisable(indio_dev);
> +       err = st_sensors_set_enable(indio_dev, false);
>         if (err < 0)
>                 goto st_magn_buffer_predisable_error;
>
> -       err = st_sensors_set_enable(indio_dev, false);
> +       err = iio_triggered_buffer_predisable(indio_dev);
>
>  st_magn_buffer_predisable_error:
>         kfree(mdata->buffer_data);
> @@ -75,7 +70,6 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>  }
>
>  static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
> -       .preenable = &st_magn_buffer_preenable,
>         .postenable = &st_magn_buffer_postenable,
>         .predisable = &st_magn_buffer_predisable,
>  };
> --
> 2.11.0
>
Martin Kelly Oct. 20, 2018, 4:08 a.m. UTC | #2
On 10/15/18 12:19 AM, Lorenzo Bianconi wrote:
>> Currently, we enable the device before we enable the device trigger. At
>> high frequencies, this can cause interrupts that don't yet have a poll
>> function associated with them and are thus treated as spurious. At high
>> frequencies with level interrupts, this can even cause an interrupt storm
>> of repeated spurious interrupts (~100,000 on my Beagleboard with the
>> LSM9DS1 magnetometer). If these repeat too much, the interrupt will get
>> disabled and the device will stop functioning.
>>
>> To prevent these problems, enable the device prior to enabling the device
>> trigger, and disable the divec prior to disabling the trigger. This means
>> there's no window of time during which the device creates interrupts but we
>> have no trigger to answer them.
>>
> 
> I have just reviewed the code (not carried out any tests) and I guess this patch
> is correct. Moreover if the memory allocation in st_magn_buffer_postenable fails
> we will end up with a device generating interrupts without any buffer
> to collect data.
> I guess there is the same issue in st_magn_buffer_predisable(), if
> st_sensors_set_enable
> or iio_triggered_buffer_predisable fails, should we remove the data
> buffer? Maybe we
> just skip return code from st_sensors_set_enable.
> @Denis: any hints?
> 
> Regards,
> Lorenzo
> 

Dennis, any opinion?

>> Signed-off-by: Martin Kelly <martin@martingkelly.com>
>> ---
>>   drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
>>   1 file changed, 3 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
>> index 0a9e8fadfa9d..37ab30566464 100644
>> --- a/drivers/iio/magnetometer/st_magn_buffer.c
>> +++ b/drivers/iio/magnetometer/st_magn_buffer.c
>> @@ -30,11 +30,6 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
>>          return st_sensors_set_dataready_irq(indio_dev, state);
>>   }
>>
>> -static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
>> -{
>> -       return st_sensors_set_enable(indio_dev, true);
>> -}
>> -
>>   static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>   {
>>          int err;
>> @@ -50,7 +45,7 @@ static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>          if (err < 0)
>>                  goto st_magn_buffer_postenable_error;
>>
>> -       return err;
>> +       return st_sensors_set_enable(indio_dev, true);
>>
>>   st_magn_buffer_postenable_error:
>>          kfree(mdata->buffer_data);
>> @@ -63,11 +58,11 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>          int err;
>>          struct st_sensor_data *mdata = iio_priv(indio_dev);
>>
>> -       err = iio_triggered_buffer_predisable(indio_dev);
>> +       err = st_sensors_set_enable(indio_dev, false);
>>          if (err < 0)
>>                  goto st_magn_buffer_predisable_error;
>>
>> -       err = st_sensors_set_enable(indio_dev, false);
>> +       err = iio_triggered_buffer_predisable(indio_dev);
>>
>>   st_magn_buffer_predisable_error:
>>          kfree(mdata->buffer_data);
>> @@ -75,7 +70,6 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>   }
>>
>>   static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
>> -       .preenable = &st_magn_buffer_preenable,
>>          .postenable = &st_magn_buffer_postenable,
>>          .predisable = &st_magn_buffer_predisable,
>>   };
>> --
>> 2.11.0
>>
Martin Kelly Oct. 20, 2018, 4:08 a.m. UTC | #3
On 10/15/18 12:19 AM, Lorenzo Bianconi wrote:
>> Currently, we enable the device before we enable the device trigger. At
>> high frequencies, this can cause interrupts that don't yet have a poll
>> function associated with them and are thus treated as spurious. At high
>> frequencies with level interrupts, this can even cause an interrupt storm
>> of repeated spurious interrupts (~100,000 on my Beagleboard with the
>> LSM9DS1 magnetometer). If these repeat too much, the interrupt will get
>> disabled and the device will stop functioning.
>>
>> To prevent these problems, enable the device prior to enabling the device
>> trigger, and disable the divec prior to disabling the trigger. This means
>> there's no window of time during which the device creates interrupts but we
>> have no trigger to answer them.
>>
> 
> I have just reviewed the code (not carried out any tests) and I guess this patch
> is correct. Moreover if the memory allocation in st_magn_buffer_postenable fails
> we will end up with a device generating interrupts without any buffer
> to collect data.
> I guess there is the same issue in st_magn_buffer_predisable(), if
> st_sensors_set_enable
> or iio_triggered_buffer_predisable fails, should we remove the data
> buffer? Maybe we
> just skip return code from st_sensors_set_enable.
> @Denis: any hints?
> 
> Regards,
> Lorenzo
> 

Denis, any opinion?

>> Signed-off-by: Martin Kelly <martin@martingkelly.com>
>> ---
>>   drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
>>   1 file changed, 3 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
>> index 0a9e8fadfa9d..37ab30566464 100644
>> --- a/drivers/iio/magnetometer/st_magn_buffer.c
>> +++ b/drivers/iio/magnetometer/st_magn_buffer.c
>> @@ -30,11 +30,6 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
>>          return st_sensors_set_dataready_irq(indio_dev, state);
>>   }
>>
>> -static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
>> -{
>> -       return st_sensors_set_enable(indio_dev, true);
>> -}
>> -
>>   static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>   {
>>          int err;
>> @@ -50,7 +45,7 @@ static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>          if (err < 0)
>>                  goto st_magn_buffer_postenable_error;
>>
>> -       return err;
>> +       return st_sensors_set_enable(indio_dev, true);
>>
>>   st_magn_buffer_postenable_error:
>>          kfree(mdata->buffer_data);
>> @@ -63,11 +58,11 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>          int err;
>>          struct st_sensor_data *mdata = iio_priv(indio_dev);
>>
>> -       err = iio_triggered_buffer_predisable(indio_dev);
>> +       err = st_sensors_set_enable(indio_dev, false);
>>          if (err < 0)
>>                  goto st_magn_buffer_predisable_error;
>>
>> -       err = st_sensors_set_enable(indio_dev, false);
>> +       err = iio_triggered_buffer_predisable(indio_dev);
>>
>>   st_magn_buffer_predisable_error:
>>          kfree(mdata->buffer_data);
>> @@ -75,7 +70,6 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>   }
>>
>>   static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
>> -       .preenable = &st_magn_buffer_preenable,
>>          .postenable = &st_magn_buffer_postenable,
>>          .predisable = &st_magn_buffer_predisable,
>>   };
>> --
>> 2.11.0
>>
Denis CIOCCA Oct. 20, 2018, 11:22 p.m. UTC | #4
Hi Martin,

I am performing few tests. I'll give you a feedback tomorrow!

Thanks,
Denis


-----Original Message-----
From: Martin Kelly <martin@martingkelly.com> 
Sent: Friday, October 19, 2018 9:08 PM
To: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Cc: linux-iio@vger.kernel.org; Jonathan Cameron <jic23@kernel.org>; Hartmut Knaack <knaack.h@gmx.de>; Lars-Peter Clausen <lars@metafoo.de>; Peter Meerwald-Stadler <pmeerw@pmeerw.net>; Denis CIOCCA <denis.ciocca@st.com>
Subject: Re: [RFC][PATCH] iio:st_magn: enable device after trigger

On 10/15/18 12:19 AM, Lorenzo Bianconi wrote:
>> Currently, we enable the device before we enable the device trigger. 
>> At high frequencies, this can cause interrupts that don't yet have a 
>> poll function associated with them and are thus treated as spurious. 
>> At high frequencies with level interrupts, this can even cause an 
>> interrupt storm of repeated spurious interrupts (~100,000 on my 
>> Beagleboard with the
>> LSM9DS1 magnetometer). If these repeat too much, the interrupt will 
>> get disabled and the device will stop functioning.
>>
>> To prevent these problems, enable the device prior to enabling the 
>> device trigger, and disable the divec prior to disabling the trigger. 
>> This means there's no window of time during which the device creates 
>> interrupts but we have no trigger to answer them.
>>
> 
> I have just reviewed the code (not carried out any tests) and I guess 
> this patch is correct. Moreover if the memory allocation in 
> st_magn_buffer_postenable fails we will end up with a device 
> generating interrupts without any buffer to collect data.
> I guess there is the same issue in st_magn_buffer_predisable(), if 
> st_sensors_set_enable or iio_triggered_buffer_predisable fails, should 
> we remove the data buffer? Maybe we just skip return code from 
> st_sensors_set_enable.
> @Denis: any hints?
> 
> Regards,
> Lorenzo
> 

Denis, any opinion?

>> Signed-off-by: Martin Kelly <martin@martingkelly.com>
>> ---
>>   drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
>>   1 file changed, 3 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/iio/magnetometer/st_magn_buffer.c 
>> b/drivers/iio/magnetometer/st_magn_buffer.c
>> index 0a9e8fadfa9d..37ab30566464 100644
>> --- a/drivers/iio/magnetometer/st_magn_buffer.c
>> +++ b/drivers/iio/magnetometer/st_magn_buffer.c
>> @@ -30,11 +30,6 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
>>          return st_sensors_set_dataready_irq(indio_dev, state);
>>   }
>>
>> -static int st_magn_buffer_preenable(struct iio_dev *indio_dev) -{
>> -       return st_sensors_set_enable(indio_dev, true);
>> -}
>> -
>>   static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>   {
>>          int err;
>> @@ -50,7 +45,7 @@ static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>          if (err < 0)
>>                  goto st_magn_buffer_postenable_error;
>>
>> -       return err;
>> +       return st_sensors_set_enable(indio_dev, true);
>>
>>   st_magn_buffer_postenable_error:
>>          kfree(mdata->buffer_data);
>> @@ -63,11 +58,11 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>          int err;
>>          struct st_sensor_data *mdata = iio_priv(indio_dev);
>>
>> -       err = iio_triggered_buffer_predisable(indio_dev);
>> +       err = st_sensors_set_enable(indio_dev, false);
>>          if (err < 0)
>>                  goto st_magn_buffer_predisable_error;
>>
>> -       err = st_sensors_set_enable(indio_dev, false);
>> +       err = iio_triggered_buffer_predisable(indio_dev);
>>
>>   st_magn_buffer_predisable_error:
>>          kfree(mdata->buffer_data);
>> @@ -75,7 +70,6 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>   }
>>
>>   static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
>> -       .preenable = &st_magn_buffer_preenable,
>>          .postenable = &st_magn_buffer_postenable,
>>          .predisable = &st_magn_buffer_predisable,
>>   };
>> --
>> 2.11.0
>>
Denis CIOCCA Oct. 22, 2018, 3:56 a.m. UTC | #5
Hi Martin,

I performed few tests today.

Here is my thoughts:

1. Interrupts SHOULD be used in level. 99% of our devices set interrupt level when new data are generated and reset the status of the pad after an i2c read of the output registers is performed. If i2c read fails or sensor disable fails, interrupt is kept set. That's why interrupts should always be treated in level mode. There are instead other devices (such as lsm6dsm) where pads can be configured to generate pulsed interrupts of 75us width, in this case interrupts are continually generated independently from output reads. This latest case should be treated instead in edge mode.
LSM9DS1 magn is compatible with LIS3MDL, that is working as described in the first case.

2. From logical point of view driver should be ready to receive irqs before enabling the sensor itself. Your suggestion is 'logically' a better implementation. 

3. About spurious / storm interrupts. From my tests with the  oscillope, with high odrs (80Hz), interrupts in fact are generated before irq is requested. This is generally not an issue. Introduction of 

iio: st_sensors: harden interrupt handling
90efe05562921768d34e44c0292703ea3168ba8d

has generated a problem though.

Irq_thread function is checking the status of hw_irq_trigger variable that is set executing st_magn_trig_set_state function.
So, if between request_irq and st_magn_trig_set_state interrupts are received, irq_thread treats those as IRQ_NONE. Many of those (because of level) cause disabling of the IRQ.

To summarize, your patch (with few modifications) are valid to me, even for other sensors but is not covering all cases. For example if sensor fails the disable interrupts are still generated and new enable could cause the same issue.

I've modified the patch you propose because is not covering failures, I'll try to send the patch tomorrow since I am having problems with git-send-email through company proxy :(

Feedback are very welcome!

Best Regards,
Denis


-----Original Message-----
From: Denis CIOCCA 
Sent: Saturday, October 20, 2018 4:22 PM
To: 'Martin Kelly' <martin@martingkelly.com>
Cc: linux-iio@vger.kernel.org; Jonathan Cameron <jic23@kernel.org>; Hartmut Knaack <knaack.h@gmx.de>; Lars-Peter Clausen <lars@metafoo.de>; Peter Meerwald-Stadler <pmeerw@pmeerw.net>; Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Subject: RE: [RFC][PATCH] iio:st_magn: enable device after trigger

Hi Martin,

I am performing few tests. I'll give you a feedback tomorrow!

Thanks,
Denis


-----Original Message-----
From: Martin Kelly <martin@martingkelly.com>
Sent: Friday, October 19, 2018 9:08 PM
To: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Cc: linux-iio@vger.kernel.org; Jonathan Cameron <jic23@kernel.org>; Hartmut Knaack <knaack.h@gmx.de>; Lars-Peter Clausen <lars@metafoo.de>; Peter Meerwald-Stadler <pmeerw@pmeerw.net>; Denis CIOCCA <denis.ciocca@st.com>
Subject: Re: [RFC][PATCH] iio:st_magn: enable device after trigger

On 10/15/18 12:19 AM, Lorenzo Bianconi wrote:
>> Currently, we enable the device before we enable the device trigger. 
>> At high frequencies, this can cause interrupts that don't yet have a 
>> poll function associated with them and are thus treated as spurious.
>> At high frequencies with level interrupts, this can even cause an 
>> interrupt storm of repeated spurious interrupts (~100,000 on my 
>> Beagleboard with the
>> LSM9DS1 magnetometer). If these repeat too much, the interrupt will 
>> get disabled and the device will stop functioning.
>>
>> To prevent these problems, enable the device prior to enabling the 
>> device trigger, and disable the divec prior to disabling the trigger.
>> This means there's no window of time during which the device creates 
>> interrupts but we have no trigger to answer them.
>>
> 
> I have just reviewed the code (not carried out any tests) and I guess 
> this patch is correct. Moreover if the memory allocation in 
> st_magn_buffer_postenable fails we will end up with a device 
> generating interrupts without any buffer to collect data.
> I guess there is the same issue in st_magn_buffer_predisable(), if 
> st_sensors_set_enable or iio_triggered_buffer_predisable fails, should 
> we remove the data buffer? Maybe we just skip return code from 
> st_sensors_set_enable.
> @Denis: any hints?
> 
> Regards,
> Lorenzo
> 

Denis, any opinion?

>> Signed-off-by: Martin Kelly <martin@martingkelly.com>
>> ---
>>   drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
>>   1 file changed, 3 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/iio/magnetometer/st_magn_buffer.c
>> b/drivers/iio/magnetometer/st_magn_buffer.c
>> index 0a9e8fadfa9d..37ab30566464 100644
>> --- a/drivers/iio/magnetometer/st_magn_buffer.c
>> +++ b/drivers/iio/magnetometer/st_magn_buffer.c
>> @@ -30,11 +30,6 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
>>          return st_sensors_set_dataready_irq(indio_dev, state);
>>   }
>>
>> -static int st_magn_buffer_preenable(struct iio_dev *indio_dev) -{
>> -       return st_sensors_set_enable(indio_dev, true);
>> -}
>> -
>>   static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>   {
>>          int err;
>> @@ -50,7 +45,7 @@ static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>          if (err < 0)
>>                  goto st_magn_buffer_postenable_error;
>>
>> -       return err;
>> +       return st_sensors_set_enable(indio_dev, true);
>>
>>   st_magn_buffer_postenable_error:
>>          kfree(mdata->buffer_data);
>> @@ -63,11 +58,11 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>          int err;
>>          struct st_sensor_data *mdata = iio_priv(indio_dev);
>>
>> -       err = iio_triggered_buffer_predisable(indio_dev);
>> +       err = st_sensors_set_enable(indio_dev, false);
>>          if (err < 0)
>>                  goto st_magn_buffer_predisable_error;
>>
>> -       err = st_sensors_set_enable(indio_dev, false);
>> +       err = iio_triggered_buffer_predisable(indio_dev);
>>
>>   st_magn_buffer_predisable_error:
>>          kfree(mdata->buffer_data);
>> @@ -75,7 +70,6 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>   }
>>
>>   static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
>> -       .preenable = &st_magn_buffer_preenable,
>>          .postenable = &st_magn_buffer_postenable,
>>          .predisable = &st_magn_buffer_predisable,
>>   };
>> --
>> 2.11.0
>>
Martin Kelly Oct. 23, 2018, 2:35 a.m. UTC | #6
On 10/21/18 8:56 PM, Denis CIOCCA wrote:
> Hi Martin,
> 
> I performed few tests today.
> 
> Here is my thoughts:
> 
> 1. Interrupts SHOULD be used in level. 99% of our devices set interrupt level when new data are generated and reset the status of the pad after an i2c read of the output registers is performed. If i2c read fails or sensor disable fails, interrupt is kept set. That's why interrupts should always be treated in level mode. There are instead other devices (such as lsm6dsm) where pads can be configured to generate pulsed interrupts of 75us width, in this case interrupts are continually generated independently from output reads. This latest case should be treated instead in edge mode.
> LSM9DS1 magn is compatible with LIS3MDL, that is working as described in the first case.
> 
> 2. From logical point of view driver should be ready to receive irqs before enabling the sensor itself. Your suggestion is 'logically' a better implementation.
> 
> 3. About spurious / storm interrupts. From my tests with the  oscillope, with high odrs (80Hz), interrupts in fact are generated before irq is requested. This is generally not an issue. Introduction of
> 
> iio: st_sensors: harden interrupt handling
> 90efe05562921768d34e44c0292703ea3168ba8d
> 
> has generated a problem though.
> 
> Irq_thread function is checking the status of hw_irq_trigger variable that is set executing st_magn_trig_set_state function.
> So, if between request_irq and st_magn_trig_set_state interrupts are received, irq_thread treats those as IRQ_NONE. Many of those (because of level) cause disabling of the IRQ.
> 
> To summarize, your patch (with few modifications) are valid to me, even for other sensors but is not covering all cases. For example if sensor fails the disable interrupts are still generated and new enable could cause the same issue.
> 
> I've modified the patch you propose because is not covering failures, I'll try to send the patch tomorrow since I am having problems with git-send-email through company proxy :(
> 

Thank you for the very thorough analysis. It sounds like you observed 
the same behavior that I did (CPU spike and interrupts running as fast 
as possible, returning IRQ_NONE). It's especially noticeable with high 
ODRs but occurs all the time.

I look forward to your patch!

> Feedback are very welcome!
> 
> Best Regards,
> Denis
> 
> 
> -----Original Message-----
> From: Denis CIOCCA
> Sent: Saturday, October 20, 2018 4:22 PM
> To: 'Martin Kelly' <martin@martingkelly.com>
> Cc: linux-iio@vger.kernel.org; Jonathan Cameron <jic23@kernel.org>; Hartmut Knaack <knaack.h@gmx.de>; Lars-Peter Clausen <lars@metafoo.de>; Peter Meerwald-Stadler <pmeerw@pmeerw.net>; Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
> Subject: RE: [RFC][PATCH] iio:st_magn: enable device after trigger
> 
> Hi Martin,
> 
> I am performing few tests. I'll give you a feedback tomorrow!
> 
> Thanks,
> Denis
> 
> 
> -----Original Message-----
> From: Martin Kelly <martin@martingkelly.com>
> Sent: Friday, October 19, 2018 9:08 PM
> To: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
> Cc: linux-iio@vger.kernel.org; Jonathan Cameron <jic23@kernel.org>; Hartmut Knaack <knaack.h@gmx.de>; Lars-Peter Clausen <lars@metafoo.de>; Peter Meerwald-Stadler <pmeerw@pmeerw.net>; Denis CIOCCA <denis.ciocca@st.com>
> Subject: Re: [RFC][PATCH] iio:st_magn: enable device after trigger
> 
> On 10/15/18 12:19 AM, Lorenzo Bianconi wrote:
>>> Currently, we enable the device before we enable the device trigger.
>>> At high frequencies, this can cause interrupts that don't yet have a
>>> poll function associated with them and are thus treated as spurious.
>>> At high frequencies with level interrupts, this can even cause an
>>> interrupt storm of repeated spurious interrupts (~100,000 on my
>>> Beagleboard with the
>>> LSM9DS1 magnetometer). If these repeat too much, the interrupt will
>>> get disabled and the device will stop functioning.
>>>
>>> To prevent these problems, enable the device prior to enabling the
>>> device trigger, and disable the divec prior to disabling the trigger.
>>> This means there's no window of time during which the device creates
>>> interrupts but we have no trigger to answer them.
>>>
>>
>> I have just reviewed the code (not carried out any tests) and I guess
>> this patch is correct. Moreover if the memory allocation in
>> st_magn_buffer_postenable fails we will end up with a device
>> generating interrupts without any buffer to collect data.
>> I guess there is the same issue in st_magn_buffer_predisable(), if
>> st_sensors_set_enable or iio_triggered_buffer_predisable fails, should
>> we remove the data buffer? Maybe we just skip return code from
>> st_sensors_set_enable.
>> @Denis: any hints?
>>
>> Regards,
>> Lorenzo
>>
> 
> Denis, any opinion?
> 
>>> Signed-off-by: Martin Kelly <martin@martingkelly.com>
>>> ---
>>>    drivers/iio/magnetometer/st_magn_buffer.c | 12 +++---------
>>>    1 file changed, 3 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/iio/magnetometer/st_magn_buffer.c
>>> b/drivers/iio/magnetometer/st_magn_buffer.c
>>> index 0a9e8fadfa9d..37ab30566464 100644
>>> --- a/drivers/iio/magnetometer/st_magn_buffer.c
>>> +++ b/drivers/iio/magnetometer/st_magn_buffer.c
>>> @@ -30,11 +30,6 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
>>>           return st_sensors_set_dataready_irq(indio_dev, state);
>>>    }
>>>
>>> -static int st_magn_buffer_preenable(struct iio_dev *indio_dev) -{
>>> -       return st_sensors_set_enable(indio_dev, true);
>>> -}
>>> -
>>>    static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>>    {
>>>           int err;
>>> @@ -50,7 +45,7 @@ static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
>>>           if (err < 0)
>>>                   goto st_magn_buffer_postenable_error;
>>>
>>> -       return err;
>>> +       return st_sensors_set_enable(indio_dev, true);
>>>
>>>    st_magn_buffer_postenable_error:
>>>           kfree(mdata->buffer_data);
>>> @@ -63,11 +58,11 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>>           int err;
>>>           struct st_sensor_data *mdata = iio_priv(indio_dev);
>>>
>>> -       err = iio_triggered_buffer_predisable(indio_dev);
>>> +       err = st_sensors_set_enable(indio_dev, false);
>>>           if (err < 0)
>>>                   goto st_magn_buffer_predisable_error;
>>>
>>> -       err = st_sensors_set_enable(indio_dev, false);
>>> +       err = iio_triggered_buffer_predisable(indio_dev);
>>>
>>>    st_magn_buffer_predisable_error:
>>>           kfree(mdata->buffer_data);
>>> @@ -75,7 +70,6 @@ static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
>>>    }
>>>
>>>    static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
>>> -       .preenable = &st_magn_buffer_preenable,
>>>           .postenable = &st_magn_buffer_postenable,
>>>           .predisable = &st_magn_buffer_predisable,
>>>    };
>>> --
>>> 2.11.0
>>>
>
diff mbox series

Patch

diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
index 0a9e8fadfa9d..37ab30566464 100644
--- a/drivers/iio/magnetometer/st_magn_buffer.c
+++ b/drivers/iio/magnetometer/st_magn_buffer.c
@@ -30,11 +30,6 @@  int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
 	return st_sensors_set_dataready_irq(indio_dev, state);
 }

-static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
-{
-	return st_sensors_set_enable(indio_dev, true);
-}
-
 static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
 {
 	int err;
@@ -50,7 +45,7 @@  static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
 	if (err < 0)
 		goto st_magn_buffer_postenable_error;

-	return err;
+	return st_sensors_set_enable(indio_dev, true);

 st_magn_buffer_postenable_error:
 	kfree(mdata->buffer_data);
@@ -63,11 +58,11 @@  static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
 	int err;
 	struct st_sensor_data *mdata = iio_priv(indio_dev);

-	err = iio_triggered_buffer_predisable(indio_dev);
+	err = st_sensors_set_enable(indio_dev, false);
 	if (err < 0)
 		goto st_magn_buffer_predisable_error;

-	err = st_sensors_set_enable(indio_dev, false);
+	err = iio_triggered_buffer_predisable(indio_dev);

 st_magn_buffer_predisable_error:
 	kfree(mdata->buffer_data);
@@ -75,7 +70,6 @@  static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
 }

 static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
-	.preenable = &st_magn_buffer_preenable,
 	.postenable = &st_magn_buffer_postenable,
 	.predisable = &st_magn_buffer_predisable,
 };