Skip to content

Commit f575822

Browse files
Fabrice GasnierADESTM
authored andcommitted
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 in 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: 2763ea0 ("iio: adc: stm32: add optional dma support") Change-Id: I148ca98184bf6b63d2bd0e3bfc0c1f423c16ba68 Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com> Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/linux-stm32/+/141381 Reviewed-by: CITOOLS <smet-aci-reviews@lists.codex.cro.st.com> Reviewed-by: CIBUILD <smet-aci-builds@lists.codex.cro.st.com>
1 parent ad9ff10 commit f575822

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

drivers/iio/adc/stm32-adc-core.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@
102102
* @jeoc1: adc1 end of injected conversion flag in @csr
103103
* @jeoc2: adc2 end of injected conversion flag in @csr
104104
* @jeoc3: adc3 end of injected conversion flag in @csr
105+
* @ier: interrupt enable register offset for each adc
106+
* @eocie_msk: end of conversion interrupt enable mask in @ier
105107
*/
106108
struct stm32_adc_common_regs {
107109
u32 csr;
@@ -112,6 +114,8 @@ struct stm32_adc_common_regs {
112114
u32 jeoc1_msk;
113115
u32 jeoc2_msk;
114116
u32 jeoc3_msk;
117+
u32 ier;
118+
u32 eocie_msk;
115119
};
116120

117121
struct stm32_adc_priv;
@@ -354,6 +358,8 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
354358
.jeoc1_msk = STM32F4_JEOC_MASK1,
355359
.jeoc2_msk = STM32F4_JEOC_MASK2,
356360
.jeoc3_msk = STM32F4_JEOC_MASK3,
361+
.ier = STM32F4_ADC_CR1,
362+
.eocie_msk = STM32F4_EOCIE,
357363
};
358364

359365
/* STM32H7 common registers definitions */
@@ -364,8 +370,24 @@ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
364370
.eoc2_msk = STM32H7_EOC_MASK2,
365371
.jeoc1_msk = STM32H7_JEOC_MASK1,
366372
.jeoc2_msk = STM32H7_JEOC_MASK2,
373+
.ier = STM32H7_ADC_IER,
374+
.eocie_msk = STM32H7_EOCIE,
367375
};
368376

377+
static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
378+
0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2,
379+
};
380+
381+
static unsigned int stm32_adc_eoc_enabled(struct stm32_adc_priv *priv,
382+
unsigned int adc)
383+
{
384+
u32 ier, offset = stm32_adc_offset[adc];
385+
386+
ier = readl_relaxed(priv->common.base + offset + priv->cfg->regs->ier);
387+
388+
return ier & priv->cfg->regs->eocie_msk;
389+
}
390+
369391
/* ADC common interrupt for all instances */
370392
static void stm32_adc_irq_handler(struct irq_desc *desc)
371393
{
@@ -376,13 +398,28 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
376398
chained_irq_enter(chip, desc);
377399
status = readl_relaxed(priv->common.base + priv->cfg->regs->csr);
378400

379-
if (status & priv->cfg->regs->eoc1_msk)
401+
/*
402+
* End of conversion may be handled by using IRQ or DMA. There may be a
403+
* race here when two conversions complete at the same time on several
404+
* ADCs. EOC may be read 'set' for several ADCs, with:
405+
* - an ADC configured to use DMA (EOC triggers the DMA request, and
406+
* is then automatically cleared by DR read in hardware)
407+
* - an ADC configured to use IRQs (EOCIE bit is set. The handler must
408+
* be called in this case)
409+
* So both EOC status bit in CSR and EOCIE control bit must be checked
410+
* before invoking the interrupt handler (e.g. call ISR only for
411+
* IRQ-enabled ADCs).
412+
*/
413+
if (status & priv->cfg->regs->eoc1_msk &&
414+
stm32_adc_eoc_enabled(priv, 0))
380415
generic_handle_irq(irq_find_mapping(priv->domain, 0));
381416

382-
if (status & priv->cfg->regs->eoc2_msk)
417+
if (status & priv->cfg->regs->eoc2_msk &&
418+
stm32_adc_eoc_enabled(priv, 1))
383419
generic_handle_irq(irq_find_mapping(priv->domain, 1));
384420

385-
if (status & priv->cfg->regs->eoc3_msk)
421+
if (status & priv->cfg->regs->eoc3_msk &&
422+
stm32_adc_eoc_enabled(priv, 2))
386423
generic_handle_irq(irq_find_mapping(priv->domain, 2));
387424

388425
if (status & priv->cfg->regs->jeoc1_msk)

drivers/iio/adc/stm32-adc-core.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,24 @@ struct stm32_adc_calib {
4545
bool calibrated;
4646
};
4747

48+
/* STM32F4 - registers for each ADC instance */
49+
#define STM32F4_ADC_CR1 0x04
50+
51+
/* STM32F4_ADC_CR1 - bit fields */
52+
#define STM32F4_EOCIE BIT(5)
53+
4854
/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */
4955
#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
5056

5157
/* STM32F4_ADC_CCR - bit fields */
5258
#define STM32F4_ADC_TSVREFE BIT(23)
5359

60+
/* STM32H7 - registers for each instance */
61+
#define STM32H7_ADC_IER 0x04
62+
63+
/* STM32H7_ADC_IER - bit fields */
64+
#define STM32H7_EOCIE BIT(2)
65+
5466
/* STM32H7 - common registers for all ADC instances */
5567
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
5668

drivers/iio/adc/stm32-adc.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232

3333
/* STM32F4 - Registers for each ADC instance */
3434
#define STM32F4_ADC_SR 0x00
35-
#define STM32F4_ADC_CR1 0x04
3635
#define STM32F4_ADC_CR2 0x08
3736
#define STM32F4_ADC_SMPR1 0x0C
3837
#define STM32F4_ADC_SMPR2 0x10
@@ -66,7 +65,6 @@
6665
#define STM32F4_SCAN BIT(8)
6766
#define STM32F4_JEOCIE BIT(7)
6867
#define STM32F4_AWDIE BIT(6)
69-
#define STM32F4_EOCIE BIT(5)
7068
#define STM32F4_AWDCH_SHIFT 0
7169
#define STM32F4_AWDCH_MASK GENMASK(4, 0)
7270

@@ -88,7 +86,6 @@
8886

8987
/* STM32H7 - Registers for each ADC instance */
9088
#define STM32H7_ADC_ISR 0x00
91-
#define STM32H7_ADC_IER 0x04
9289
#define STM32H7_ADC_CR 0x08
9390
#define STM32H7_ADC_CFGR 0x0C
9491
#define STM32H7_ADC_SMPR1 0x14
@@ -132,7 +129,6 @@
132129
#define STM32H7_AWD1IE STM32H7_AWD1
133130
#define STM32H7_JEOSIE STM32H7_JEOS
134131
#define STM32H7_OVRIE STM32H7_OVR
135-
#define STM32H7_EOCIE STM32H7_EOC
136132

137133
/* STM32H7_ADC_CR - bit fields */
138134
#define STM32H7_ADCAL BIT(31)

0 commit comments

Comments
 (0)