Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp1339910ybp; Thu, 17 Oct 2019 11:17:44 -0700 (PDT) X-Google-Smtp-Source: APXvYqwbaAdmjR+eag9QydSGm9EBEloY+GuaqrCfxeZudLN8bL159JCCDRBiXVKrM9tHDlfU8Kfw X-Received: by 2002:a50:f296:: with SMTP id f22mr5307084edm.69.1571336264036; Thu, 17 Oct 2019 11:17:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571336264; cv=none; d=google.com; s=arc-20160816; b=a4GnXongHtpT0FuuFwnei2hqqAIftUE5d5yvBrF38sgmIe9y3CiNxpPyPiyeB/YCBC HWwbLconiA9STMwk7oZr15oDzyneBerJZBRCTPsLZBK7Hj7Q9hNjxUt1UYkvs7mQ9BcI y5NyIGzHUjB3jvoCAO64EKvdgSXVitLfWiITy8C0E79jAQy5lxENqrD/tixENLMuokYK jqTXTXuUI2oByNg6ywZAvWX0q+T01hTRAdDZ9Aw8wd/aAbV0pJcRCifsyQsYknmjmreV GLOCiLUUoBbC/0eg17m2PnMQfqMoDAXZ/i27/pxctMkx0hqOOXm2J/3Y/hBM4EbjupKS ukKQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=T2zy+tHQSJ1TPouL1pC+9LT/6obqLLwAeGj2ISBbj3Q=; b=wmTHSRQQYWW8qNAX1D4LY0yO2hxUK6sod011kKfLe24cv6N9sbdjcDd1p5boy+Vyey ugyOABH8UTuQ1qLe5KckCRSo7B2srhVaOZ8l66pY9zK0Z19DOgO+lQNswsXJq+tyE/HW ywKm0tey5wLD3eoGqZ3u9ApXhbzIdtxuObTd0Alwazn/uC0lFCzfdBnNOLlsStb5L2ZL TIZih/VTBxXG1Rh/cErCGGFYsAeCcR5sVZV86ODugUdFM/15wrXKpy1HqUDO0z5kG5qN RquVxFcExNMNWyRFQCT+usRjD+veJYpO/Spir8epQRaukto3iM8m6p7kVlVi4mvIc0aF nUBQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=MLpYjnpw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e47si2180498ede.325.2019.10.17.11.17.20; Thu, 17 Oct 2019 11:17:44 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=MLpYjnpw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2438661AbfJPV77 (ORCPT + 99 others); Wed, 16 Oct 2019 17:59:59 -0400 Received: from mail.kernel.org ([198.145.29.99]:52864 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2438308AbfJPV6y (ORCPT ); Wed, 16 Oct 2019 17:58:54 -0400 Received: from localhost (unknown [192.55.54.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id D2009218DE; Wed, 16 Oct 2019 21:58:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571263133; bh=qP0ijBtTQLShNqh8GncS285yfnnd8elSdMGa/+Fej2w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MLpYjnpwOHqdO/F2TccqCy2mm56YBCpfYo7+QB1DnuBfpx7AVVu9CBH0E+f7c0DD1 BVTSrzw9d4MnJa0H2OcLw0Bb6TPM+MhBXwNtsOcrbb1ufD8brysy0oPj59ipLxcUVe hzxnjkYs76SjCNVTk0UvHkT60hYiAGsMXy6uXUsw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Fabrice Gasnier , Stable@vger.kernel.org, Jonathan Cameron Subject: [PATCH 5.3 056/112] iio: adc: stm32-adc: fix a race when using several adcs with dma and irq Date: Wed, 16 Oct 2019 14:50:48 -0700 Message-Id: <20191016214859.219922248@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191016214844.038848564@linuxfoundation.org> References: <20191016214844.038848564@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Fabrice Gasnier commit dcb10920179ab74caf88a6f2afadecfc2743b910 upstream. 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 Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/stm32-adc-core.c | 43 ++++++++++++++++++++++++++++++++++++--- drivers/iio/adc/stm32-adc-core.h | 1 2 files changed, 41 insertions(+), 3 deletions(-) --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -31,6 +31,8 @@ * @eoc1: adc1 end of conversion flag in @csr * @eoc2: adc2 end of conversion flag in @csr * @eoc3: adc3 end of conversion flag in @csr + * @ier: interrupt enable register offset for each adc + * @eocie_msk: end of conversion interrupt enable mask in @ier */ struct stm32_adc_common_regs { u32 csr; @@ -38,6 +40,8 @@ struct stm32_adc_common_regs { u32 eoc1_msk; u32 eoc2_msk; u32 eoc3_msk; + u32 ier; + u32 eocie_msk; }; struct stm32_adc_priv; @@ -251,6 +255,8 @@ static const struct stm32_adc_common_reg .eoc1_msk = STM32F4_EOC1, .eoc2_msk = STM32F4_EOC2, .eoc3_msk = STM32F4_EOC3, + .ier = STM32F4_ADC_CR1, + .eocie_msk = STM32F4_EOCIE, }; /* STM32H7 common registers definitions */ @@ -259,8 +265,24 @@ static const struct stm32_adc_common_reg .ccr = STM32H7_ADC_CCR, .eoc1_msk = STM32H7_EOC_MST, .eoc2_msk = STM32H7_EOC_SLV, + .ier = STM32H7_ADC_IER, + .eocie_msk = STM32H7_EOCIE, }; +static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = { + 0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2, +}; + +static unsigned int stm32_adc_eoc_enabled(struct stm32_adc_priv *priv, + unsigned int adc) +{ + u32 ier, offset = stm32_adc_offset[adc]; + + ier = readl_relaxed(priv->common.base + offset + priv->cfg->regs->ier); + + return ier & priv->cfg->regs->eocie_msk; +} + /* ADC common interrupt for all instances */ static void stm32_adc_irq_handler(struct irq_desc *desc) { @@ -271,13 +293,28 @@ static void stm32_adc_irq_handler(struct chained_irq_enter(chip, desc); status = readl_relaxed(priv->common.base + priv->cfg->regs->csr); - if (status & priv->cfg->regs->eoc1_msk) + /* + * End of conversion may be handled by using IRQ or DMA. There may be a + * race here when two conversions complete at the same time on several + * ADCs. EOC may be read 'set' for several ADCs, with: + * - an ADC configured to use DMA (EOC triggers the DMA request, and + * is then automatically cleared by DR read in hardware) + * - an ADC configured to use IRQs (EOCIE bit is set. The handler must + * be called in this case) + * 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). + */ + if (status & priv->cfg->regs->eoc1_msk && + stm32_adc_eoc_enabled(priv, 0)) generic_handle_irq(irq_find_mapping(priv->domain, 0)); - if (status & priv->cfg->regs->eoc2_msk) + if (status & priv->cfg->regs->eoc2_msk && + stm32_adc_eoc_enabled(priv, 1)) generic_handle_irq(irq_find_mapping(priv->domain, 1)); - if (status & priv->cfg->regs->eoc3_msk) + if (status & priv->cfg->regs->eoc3_msk && + stm32_adc_eoc_enabled(priv, 2)) generic_handle_irq(irq_find_mapping(priv->domain, 2)); chained_irq_exit(chip, desc); --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -25,6 +25,7 @@ * -------------------------------------------------------- */ #define STM32_ADC_MAX_ADCS 3 +#define STM32_ADC_OFFSET 0x100 #define STM32_ADCX_COMN_OFFSET 0x300 /* STM32F4 - Registers for each ADC instance */