Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: st_sensors: harden interrupt handling

Leonard Crestez observed the following phenomenon: when using
hard interrupt triggers (the DRDY line coming out of an ST
sensor) sometimes a new value would arrive while reading the
previous value, due to latencies in the system.

We discovered that the ST hardware as far as can be observed
is designed for level interrupts: the DRDY line will be held
asserted as long as there are new values coming. The interrupt
handler should be re-entered until we're out of values to
handle from the sensor.

If interrupts were handled as occurring on the edges (usually
low-to-high) new values could appear and the line be held
asserted after that, and these values would be missed, the
interrupt handler would also lock up as new data was
available, but as no new edges occurs on the DRDY signal,
nothing happens: the edge detector only detects edges.

To counter this, do the following:

- Accept interrupt lines to be flagged as level interrupts
using IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW. If the line
is marked like this (in the device tree node or ACPI
table or similar) it will be utilized as a level IRQ.
We mark the line with IRQF_ONESHOT and mask the IRQ
while processing a sample, then the top half will be
entered again if new values are available.

- If we are flagged as using edge interrupts with
IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING: remove
IRQF_ONESHOT so that the interrupt line is not
masked while running the thread part of the interrupt.
This way we will never miss an interrupt, then introduce
a loop that polls the data ready registers repeatedly
until no new samples are available, then exit the
interrupt handler. This way we know no new values are
available when the interrupt handler exits and
new (edge) interrupts will be triggered when data arrives.
Take some extra care to update the timestamp in the poll
loop if this happens. The timestamp will not be 100%
perfect, but it will at least be closer to the actual
events. Usually the extra poll loop will handle the new
samples, but once in a blue moon, we get a new IRQ
while exiting the loop, before returning from the
thread IRQ bottom half with IRQ_HANDLED. On these rare
occasions, the removal of IRQF_ONESHOT means the
interrupt will immediately fire again.

- If no interrupt type is indicated from the DT/ACPI,
choose IRQF_TRIGGER_RISING as default, as this is necessary
for legacy boards.

Tested successfully on the LIS331DL and L3G4200D by setting
sampling frequency to 400Hz/800Hz and stressing the system:
extra reads in the threaded interrupt handler occurs.

Cc: Giuseppe Barba <giuseppe.barba@st.com>
Cc: Denis Ciocca <denis.ciocca@st.com>
Tested-by: Crestez Dan Leonard <cdleonard@gmail.com>
Reported-by: Crestez Dan Leonard <cdleonard@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Linus Walleij and committed by
Jonathan Cameron
90efe055 cde4cb5d

+118 -47
+6 -1
drivers/iio/common/st_sensors/st_sensors_buffer.c
··· 58 58 struct st_sensor_data *sdata = iio_priv(indio_dev); 59 59 s64 timestamp; 60 60 61 - /* If we do timetamping here, do it before reading the values */ 61 + /* 62 + * If we do timetamping here, do it before reading the values, because 63 + * once we've read the values, new interrupts can occur (when using 64 + * the hardware trigger) and the hw_timestamp may get updated. 65 + * By storing it in a local variable first, we are safe. 66 + */ 62 67 if (sdata->hw_irq_trigger) 63 68 timestamp = sdata->hw_timestamp; 64 69 else
+110 -46
drivers/iio/common/st_sensors/st_sensors_trigger.c
··· 18 18 #include "st_sensors_core.h" 19 19 20 20 /** 21 + * st_sensors_new_samples_available() - check if more samples came in 22 + * returns: 23 + * 0 - no new samples available 24 + * 1 - new samples available 25 + * negative - error or unknown 26 + */ 27 + static int st_sensors_new_samples_available(struct iio_dev *indio_dev, 28 + struct st_sensor_data *sdata) 29 + { 30 + u8 status; 31 + int ret; 32 + 33 + /* How would I know if I can't check it? */ 34 + if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy) 35 + return -EINVAL; 36 + 37 + /* No scan mask, no interrupt */ 38 + if (!indio_dev->active_scan_mask) 39 + return 0; 40 + 41 + ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, 42 + sdata->sensor_settings->drdy_irq.addr_stat_drdy, 43 + &status); 44 + if (ret < 0) { 45 + dev_err(sdata->dev, 46 + "error checking samples available\n"); 47 + return ret; 48 + } 49 + /* 50 + * the lower bits of .active_scan_mask[0] is directly mapped 51 + * to the channels on the sensor: either bit 0 for 52 + * one-dimensional sensors, or e.g. x,y,z for accelerometers, 53 + * gyroscopes or magnetometers. No sensor use more than 3 54 + * channels, so cut the other status bits here. 55 + */ 56 + status &= 0x07; 57 + 58 + if (status & (u8)indio_dev->active_scan_mask[0]) 59 + return 1; 60 + 61 + return 0; 62 + } 63 + 64 + /** 21 65 * st_sensors_irq_handler() - top half of the IRQ-based triggers 22 66 * @irq: irq number 23 67 * @p: private handler data ··· 87 43 struct iio_trigger *trig = p; 88 44 struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 89 45 struct st_sensor_data *sdata = iio_priv(indio_dev); 90 - int ret; 91 46 92 47 /* 93 48 * If this trigger is backed by a hardware interrupt and we have a 94 - * status register, check if this IRQ came from us 49 + * status register, check if this IRQ came from us. Notice that 50 + * we will process also if st_sensors_new_samples_available() 51 + * returns negative: if we can't check status, then poll 52 + * unconditionally. 95 53 */ 96 - if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) { 97 - u8 status; 98 - 99 - ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, 100 - sdata->sensor_settings->drdy_irq.addr_stat_drdy, 101 - &status); 102 - if (ret < 0) { 103 - dev_err(sdata->dev, "could not read channel status\n"); 104 - goto out_poll; 105 - } 106 - /* 107 - * the lower bits of .active_scan_mask[0] is directly mapped 108 - * to the channels on the sensor: either bit 0 for 109 - * one-dimensional sensors, or e.g. x,y,z for accelerometers, 110 - * gyroscopes or magnetometers. No sensor use more than 3 111 - * channels, so cut the other status bits here. 112 - */ 113 - status &= 0x07; 114 - 115 - /* 116 - * If this was not caused by any channels on this sensor, 117 - * return IRQ_NONE 118 - */ 119 - if (!indio_dev->active_scan_mask) 120 - return IRQ_NONE; 121 - if (!(status & (u8)indio_dev->active_scan_mask[0])) 122 - return IRQ_NONE; 54 + if (sdata->hw_irq_trigger && 55 + st_sensors_new_samples_available(indio_dev, sdata)) { 56 + iio_trigger_poll_chained(p); 57 + } else { 58 + dev_dbg(sdata->dev, "spurious IRQ\n"); 59 + return IRQ_NONE; 123 60 } 124 61 125 - out_poll: 126 - /* It's our IRQ: proceed to handle the register polling */ 127 - iio_trigger_poll_chained(p); 62 + /* 63 + * If we have proper level IRQs the handler will be re-entered if 64 + * the line is still active, so return here and come back in through 65 + * the top half if need be. 66 + */ 67 + if (!sdata->edge_irq) 68 + return IRQ_HANDLED; 69 + 70 + /* 71 + * If we are using egde IRQs, new samples arrived while processing 72 + * the IRQ and those may be missed unless we pick them here, so poll 73 + * again. If the sensor delivery frequency is very high, this thread 74 + * turns into a polled loop handler. 75 + */ 76 + while (sdata->hw_irq_trigger && 77 + st_sensors_new_samples_available(indio_dev, sdata)) { 78 + dev_dbg(sdata->dev, "more samples came in during polling\n"); 79 + sdata->hw_timestamp = iio_get_time_ns(indio_dev); 80 + iio_trigger_poll_chained(p); 81 + } 82 + 128 83 return IRQ_HANDLED; 129 84 } 130 85 ··· 150 107 * If the IRQ is triggered on falling edge, we need to mark the 151 108 * interrupt as active low, if the hardware supports this. 152 109 */ 153 - if (irq_trig == IRQF_TRIGGER_FALLING) { 110 + switch(irq_trig) { 111 + case IRQF_TRIGGER_FALLING: 112 + case IRQF_TRIGGER_LOW: 154 113 if (!sdata->sensor_settings->drdy_irq.addr_ihl) { 155 114 dev_err(&indio_dev->dev, 156 - "falling edge specified for IRQ but hardware " 157 - "only support rising edge, will request " 158 - "rising edge\n"); 159 - irq_trig = IRQF_TRIGGER_RISING; 115 + "falling/low specified for IRQ " 116 + "but hardware only support rising/high: " 117 + "will request rising/high\n"); 118 + if (irq_trig == IRQF_TRIGGER_FALLING) 119 + irq_trig = IRQF_TRIGGER_RISING; 120 + if (irq_trig == IRQF_TRIGGER_LOW) 121 + irq_trig = IRQF_TRIGGER_HIGH; 160 122 } else { 161 123 /* Set up INT active low i.e. falling edge */ 162 124 err = st_sensors_write_data_with_mask(indio_dev, ··· 170 122 if (err < 0) 171 123 goto iio_trigger_free; 172 124 dev_info(&indio_dev->dev, 173 - "interrupts on the falling edge\n"); 125 + "interrupts on the falling edge or " 126 + "active low level\n"); 174 127 } 175 - } else if (irq_trig == IRQF_TRIGGER_RISING) { 128 + break; 129 + case IRQF_TRIGGER_RISING: 176 130 dev_info(&indio_dev->dev, 177 131 "interrupts on the rising edge\n"); 178 - 179 - } else { 132 + break; 133 + case IRQF_TRIGGER_HIGH: 134 + dev_info(&indio_dev->dev, 135 + "interrupts active high level\n"); 136 + break; 137 + default: 138 + /* This is the most preferred mode, if possible */ 180 139 dev_err(&indio_dev->dev, 181 - "unsupported IRQ trigger specified (%lx), only " 182 - "rising and falling edges supported, enforce " 140 + "unsupported IRQ trigger specified (%lx), enforce " 183 141 "rising edge\n", irq_trig); 184 142 irq_trig = IRQF_TRIGGER_RISING; 185 143 } 144 + 145 + /* Tell the interrupt handler that we're dealing with edges */ 146 + if (irq_trig == IRQF_TRIGGER_FALLING || 147 + irq_trig == IRQF_TRIGGER_RISING) 148 + sdata->edge_irq = true; 149 + else 150 + /* 151 + * If we're not using edges (i.e. level interrupts) we 152 + * just mask off the IRQ, handle one interrupt, then 153 + * if the line is still low, we return to the 154 + * interrupt handler top half again and start over. 155 + */ 156 + irq_trig |= IRQF_ONESHOT; 186 157 187 158 /* 188 159 * If the interrupt pin is Open Drain, by definition this ··· 214 147 if (sdata->int_pin_open_drain && 215 148 sdata->sensor_settings->drdy_irq.addr_stat_drdy) 216 149 irq_trig |= IRQF_SHARED; 217 - 218 - /* Let's create an interrupt thread masking the hard IRQ here */ 219 - irq_trig |= IRQF_ONESHOT; 220 150 221 151 err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), 222 152 st_sensors_irq_handler,
+2
include/linux/iio/common/st_sensors.h
··· 223 223 * @get_irq_data_ready: Function to get the IRQ used for data ready signal. 224 224 * @tf: Transfer function structure used by I/O operations. 225 225 * @tb: Transfer buffers and mutex used by I/O operations. 226 + * @edge_irq: the IRQ triggers on edges and need special handling. 226 227 * @hw_irq_trigger: if we're using the hardware interrupt on the sensor. 227 228 * @hw_timestamp: Latest timestamp from the interrupt handler, when in use. 228 229 */ ··· 251 250 const struct st_sensor_transfer_function *tf; 252 251 struct st_sensor_transfer_buffer tb; 253 252 253 + bool edge_irq; 254 254 bool hw_irq_trigger; 255 255 s64 hw_timestamp; 256 256 };