summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabrice Gasnier <fabrice.gasnier@st.com>2019-09-17 08:38:16 -0400
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2019-10-09 14:11:26 -0400
commitdcb10920179ab74caf88a6f2afadecfc2743b910 (patch)
treeadae8a51062c3dbea4d81bf84ba1395b279323a1
parent31922f62bb527d749b99dbc776e514bcba29b7fe (diff)
iio: adc: stm32-adc: fix a race when using several adcs with dma and irq
End of conversion may be handled by using IRQ or DMA. There may be a race when two conversions complete at the same time on several ADCs. EOC can be read as 'set' for several ADCs, with: - an ADC configured to use IRQs. EOCIE bit is set. The handler is normally called in this case. - an ADC configured to use DMA. EOCIE bit isn't set. EOC triggers the DMA request instead. It's then automatically cleared by DMA read. But the handler gets called due to status bit is temporarily set (IRQ triggered by the other ADC). So both EOC status bit in CSR and EOCIE control bit must be checked before invoking the interrupt handler (e.g. call ISR only for IRQ-enabled ADCs). Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support") Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com> Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
-rw-r--r--drivers/iio/adc/stm32-adc-core.c43
-rw-r--r--drivers/iio/adc/stm32-adc-core.h1
2 files changed, 41 insertions, 3 deletions
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 84ac326bb714..93a096a91f8c 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -44,6 +44,8 @@
44 * @eoc1: adc1 end of conversion flag in @csr 44 * @eoc1: adc1 end of conversion flag in @csr
45 * @eoc2: adc2 end of conversion flag in @csr 45 * @eoc2: adc2 end of conversion flag in @csr
46 * @eoc3: adc3 end of conversion flag in @csr 46 * @eoc3: adc3 end of conversion flag in @csr
47 * @ier: interrupt enable register offset for each adc
48 * @eocie_msk: end of conversion interrupt enable mask in @ier
47 */ 49 */
48struct stm32_adc_common_regs { 50struct stm32_adc_common_regs {
49 u32 csr; 51 u32 csr;
@@ -51,6 +53,8 @@ struct stm32_adc_common_regs {
51 u32 eoc1_msk; 53 u32 eoc1_msk;
52 u32 eoc2_msk; 54 u32 eoc2_msk;
53 u32 eoc3_msk; 55 u32 eoc3_msk;
56 u32 ier;
57 u32 eocie_msk;
54}; 58};
55 59
56struct stm32_adc_priv; 60struct stm32_adc_priv;
@@ -276,6 +280,8 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
276 .eoc1_msk = STM32F4_EOC1, 280 .eoc1_msk = STM32F4_EOC1,
277 .eoc2_msk = STM32F4_EOC2, 281 .eoc2_msk = STM32F4_EOC2,
278 .eoc3_msk = STM32F4_EOC3, 282 .eoc3_msk = STM32F4_EOC3,
283 .ier = STM32F4_ADC_CR1,
284 .eocie_msk = STM32F4_EOCIE,
279}; 285};
280 286
281/* STM32H7 common registers definitions */ 287/* STM32H7 common registers definitions */
@@ -284,8 +290,24 @@ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
284 .ccr = STM32H7_ADC_CCR, 290 .ccr = STM32H7_ADC_CCR,
285 .eoc1_msk = STM32H7_EOC_MST, 291 .eoc1_msk = STM32H7_EOC_MST,
286 .eoc2_msk = STM32H7_EOC_SLV, 292 .eoc2_msk = STM32H7_EOC_SLV,
293 .ier = STM32H7_ADC_IER,
294 .eocie_msk = STM32H7_EOCIE,
287}; 295};
288 296
297static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
298 0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2,
299};
300
301static unsigned int stm32_adc_eoc_enabled(struct stm32_adc_priv *priv,
302 unsigned int adc)
303{
304 u32 ier, offset = stm32_adc_offset[adc];
305
306 ier = readl_relaxed(priv->common.base + offset + priv->cfg->regs->ier);
307
308 return ier & priv->cfg->regs->eocie_msk;
309}
310
289/* ADC common interrupt for all instances */ 311/* ADC common interrupt for all instances */
290static void stm32_adc_irq_handler(struct irq_desc *desc) 312static void stm32_adc_irq_handler(struct irq_desc *desc)
291{ 313{
@@ -296,13 +318,28 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
296 chained_irq_enter(chip, desc); 318 chained_irq_enter(chip, desc);
297 status = readl_relaxed(priv->common.base + priv->cfg->regs->csr); 319 status = readl_relaxed(priv->common.base + priv->cfg->regs->csr);
298 320
299 if (status & priv->cfg->regs->eoc1_msk) 321 /*
322 * End of conversion may be handled by using IRQ or DMA. There may be a
323 * race here when two conversions complete at the same time on several
324 * ADCs. EOC may be read 'set' for several ADCs, with:
325 * - an ADC configured to use DMA (EOC triggers the DMA request, and
326 * is then automatically cleared by DR read in hardware)
327 * - an ADC configured to use IRQs (EOCIE bit is set. The handler must
328 * be called in this case)
329 * So both EOC status bit in CSR and EOCIE control bit must be checked
330 * before invoking the interrupt handler (e.g. call ISR only for
331 * IRQ-enabled ADCs).
332 */
333 if (status & priv->cfg->regs->eoc1_msk &&
334 stm32_adc_eoc_enabled(priv, 0))
300 generic_handle_irq(irq_find_mapping(priv->domain, 0)); 335 generic_handle_irq(irq_find_mapping(priv->domain, 0));
301 336
302 if (status & priv->cfg->regs->eoc2_msk) 337 if (status & priv->cfg->regs->eoc2_msk &&
338 stm32_adc_eoc_enabled(priv, 1))
303 generic_handle_irq(irq_find_mapping(priv->domain, 1)); 339 generic_handle_irq(irq_find_mapping(priv->domain, 1));
304 340
305 if (status & priv->cfg->regs->eoc3_msk) 341 if (status & priv->cfg->regs->eoc3_msk &&
342 stm32_adc_eoc_enabled(priv, 2))
306 generic_handle_irq(irq_find_mapping(priv->domain, 2)); 343 generic_handle_irq(irq_find_mapping(priv->domain, 2));
307 344
308 chained_irq_exit(chip, desc); 345 chained_irq_exit(chip, desc);
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 94aa2d2577dc..2579d514c2a3 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -25,6 +25,7 @@
25 * -------------------------------------------------------- 25 * --------------------------------------------------------
26 */ 26 */
27#define STM32_ADC_MAX_ADCS 3 27#define STM32_ADC_MAX_ADCS 3
28#define STM32_ADC_OFFSET 0x100
28#define STM32_ADCX_COMN_OFFSET 0x300 29#define STM32_ADCX_COMN_OFFSET 0x300
29 30
30/* STM32F4 - Registers for each ADC instance */ 31/* STM32F4 - Registers for each ADC instance */