Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp3479563ybl; Mon, 27 Jan 2020 04:58:04 -0800 (PST) X-Google-Smtp-Source: APXvYqxHYKnMFsLsYMWe89vqOdNnjJI1zk+480Wv863FSZ6RIGPw/iQtNsLKOg5PM8Pohf/bEPyf X-Received: by 2002:a9d:7086:: with SMTP id l6mr5368207otj.294.1580129884315; Mon, 27 Jan 2020 04:58:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1580129884; cv=none; d=google.com; s=arc-20160816; b=nqZsL7V+XZW7vXbOcdN/FHtgnIuGukmLDRskmdBYgnzZ2sMQuNMyV1tZZibqmifO9S QKQ9AWLKjwvj5wl0j1tEjpMOAHcmjE7VrSQuCuqPrKx1LHaOl9B0wXZ/HWr09akmOW5h oKLIrz5xq0fUdGAfvHferNuc+HAX1LcpvPLqoAHCiO2rOOhDUM6J/41c5RNIXNg9/Oqu Lb8zMoL+v9fVmp7GCcgWiS25iI70AHESEZwhGvkCJ3y2y3YRJ53fB9vJ0qwGWmgYIVx0 75W8HOGXtt8Oe0uevSant8fo8dTuw4jPiaiV7nAGeY14eBrfqRGyllOZp6ReJCNDFTCO Pxkw== 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 :organization:references:in-reply-to:message-id:subject:cc:to:from :date; bh=mhNDAy+SPX7/iYZQ2+zKf43PjgHCEMa7xS6SjL96YFc=; b=lX3ZWG2W7sZdO4wx1E4hirW+7LANlTxAPGVbClf17M1yWXUHDaVxcLqdhwS8mTARAh KhMGlCmpbP3kXCNVcApuPJd9RDApM99gxD5rICa8Vs0LnJKpUZsFfBQcWIuuLvaRl6Hx JNUQrYGbneYMoRZtbYhOylA7IRXcLcUaSPH0rRNapG1X9s3qoyTi5IGk4kjiYmNFV2Hl wDdUz8IH3SxECUvPOkINhzdlylYoAVGG11NbXcBRwk8qo5VRrIE6Iv4dCTst2/cRdTaT mkQKS8PjFtQKoBCcchD3AmAmiT+7u1RtyVpWgg2JyKjmhAYuKm98ZYJHilFm5tHQHnVf Bdmw== ARC-Authentication-Results: i=1; mx.google.com; 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 n9si6590464ota.103.2020.01.27.04.57.52; Mon, 27 Jan 2020 04:58:04 -0800 (PST) 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; 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 S1730503AbgA0MNE (ORCPT + 99 others); Mon, 27 Jan 2020 07:13:04 -0500 Received: from lhrrgout.huawei.com ([185.176.76.210]:2298 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728733AbgA0MND (ORCPT ); Mon, 27 Jan 2020 07:13:03 -0500 Received: from lhreml706-cah.china.huawei.com (unknown [172.18.7.107]) by Forcepoint Email with ESMTP id E7EE9CF9B90E00A3F073; Mon, 27 Jan 2020 12:13:01 +0000 (GMT) Received: from lhreml710-chm.china.huawei.com (10.201.108.61) by lhreml706-cah.china.huawei.com (10.201.108.47) with Microsoft SMTP Server (TLS) id 14.3.408.0; Mon, 27 Jan 2020 12:13:01 +0000 Received: from localhost (10.202.226.57) by lhreml710-chm.china.huawei.com (10.201.108.61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Mon, 27 Jan 2020 12:13:01 +0000 Date: Mon, 27 Jan 2020 12:13:00 +0000 From: Jonathan Cameron To: CC: , , , , Subject: Re: [PATCH v2 2/3] iio: adc: at91-sama5d2_adc: handle unfinished conversions Message-ID: <20200127121300.00002a38@Huawei.com> In-Reply-To: References: <1578917098-9674-1-git-send-email-eugen.hristev@microchip.com> <1578917098-9674-3-git-send-email-eugen.hristev@microchip.com> <20200117173424.0000244f@Huawei.com> Organization: Huawei Technologies Research and Development (UK) Ltd. X-Mailer: Claws Mail 3.17.4 (GTK+ 2.24.32; i686-w64-mingw32) MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit X-Originating-IP: [10.202.226.57] X-ClientProxiedBy: lhreml737-chm.china.huawei.com (10.201.108.187) To lhreml710-chm.china.huawei.com (10.201.108.61) X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, 20 Jan 2020 07:27:00 +0000 wrote: > On 17.01.2020 19:34, Jonathan Cameron wrote: > > > On Mon, 13 Jan 2020 12:07:09 +0000 > > wrote: > > > >> From: Eugen Hristev > >> > >> It can happen that on IRQ trigger, not all conversions are done if > >> we are enabling multiple channels. > >> The IRQ is triggered on first EOC (end of channel), but it can happen > >> that not all channels are done. This leads into erroneous reports to > >> userspace (zero values or previous values). > >> To solve this, in trigger handler, check if the mask of done channels > >> is the same as the mask of active scan channels. > >> If it's the same, proceed and push to buffers. Otherwise, use usleep > >> to sleep until the conversion is done or we timeout. > >> Normally, it should happen that in a short time fashion, all channels are > >> ready, since the first IRQ triggered. > >> If a hardware fault happens (for example the clock suddently dissappears), > >> the handler will not be completed, in which case we do not report anything to > >> userspace anymore. > >> Also, change from using the EOC interrupts to DRDY interrupt. > >> This helps with the fact that not 'n' interrupt statuses are enabled, > >> each being able to trigger an interrupt, and instead only data ready > >> interrupt can wake up the CPU. Like this, when data is ready, check in > >> handler which and how many channels are done. While the DRDY is raised, > >> other IRQs cannot occur. Once the channel data is being read, we ack the > >> IRQ and finish the conversion. > >> > >> Signed-off-by: Eugen Hristev > >> --- > >> Changes in v2: > >> - move start of conversion to threaded irq, removed specific at91 pollfunc > >> - add timeout to channel mask readiness check in trigger handler > >> - use DRDY irq instead of EOC irqs. > >> - move enable irq after DRDY has been acked in reenable_trigger > >> > >> drivers/iio/adc/at91-sama5d2_adc.c | 62 ++++++++++++++++++++++++++++---------- > >> 1 file changed, 46 insertions(+), 16 deletions(-) > >> > >> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c > >> index 2a6950a..454a493 100644 > >> --- a/drivers/iio/adc/at91-sama5d2_adc.c > >> +++ b/drivers/iio/adc/at91-sama5d2_adc.c > >> @@ -8,6 +8,7 @@ > >> > >> #include > >> #include > >> +#include > >> #include > >> #include > >> #include > >> @@ -100,6 +101,8 @@ > >> #define AT91_SAMA5D2_IER_YRDY BIT(21) > >> /* Interrupt Enable Register - TS pressure measurement ready */ > >> #define AT91_SAMA5D2_IER_PRDY BIT(22) > >> +/* Interrupt Enable Register - Data ready */ > >> +#define AT91_SAMA5D2_IER_DRDY BIT(24) > >> /* Interrupt Enable Register - general overrun error */ > >> #define AT91_SAMA5D2_IER_GOVRE BIT(25) > >> /* Interrupt Enable Register - Pen detect */ > >> @@ -486,6 +489,21 @@ static inline int at91_adc_of_xlate(struct iio_dev *indio_dev, > >> return at91_adc_chan_xlate(indio_dev, iiospec->args[0]); > >> } > >> > >> +static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev) > >> +{ > >> + u32 mask = 0; > >> + u8 bit; > >> + > >> + for_each_set_bit(bit, indio_dev->active_scan_mask, > >> + indio_dev->num_channels) { > >> + struct iio_chan_spec const *chan = > >> + at91_adc_chan_get(indio_dev, bit); > >> + mask |= BIT(chan->channel); > >> + } > >> + > >> + return mask & GENMASK(11, 0); > >> +} > >> + > >> static void at91_adc_config_emr(struct at91_adc_state *st) > >> { > >> /* configure the extended mode register */ > >> @@ -746,24 +764,19 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) > >> at91_adc_writel(st, AT91_SAMA5D2_COR, cor); > >> } > >> > >> - if (state) { > >> + if (state) > >> at91_adc_writel(st, AT91_SAMA5D2_CHER, > >> BIT(chan->channel)); > >> - /* enable irq only if not using DMA */ > >> - if (!st->dma_st.dma_chan) { > >> - at91_adc_writel(st, AT91_SAMA5D2_IER, > >> - BIT(chan->channel)); > >> - } > >> - } else { > >> - /* disable irq only if not using DMA */ > >> - if (!st->dma_st.dma_chan) { > >> - at91_adc_writel(st, AT91_SAMA5D2_IDR, > >> - BIT(chan->channel)); > >> - } > >> + else > >> at91_adc_writel(st, AT91_SAMA5D2_CHDR, > >> BIT(chan->channel)); > >> - } > >> } > >> + /* enable irq only if not using DMA */ > >> + if (state && !st->dma_st.dma_chan) > >> + at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_DRDY); > >> + /* disable irq only if not using DMA */ > >> + if (!state && !st->dma_st.dma_chan) > >> + at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_DRDY); > > Hmm. Would have been nicer to avoid the refactor and just have the change to > > what was written. If you want to keep it, perhaps: > > > > /* Nothing to do if using DMA */ > > if (!st->dma_st.dma_chan) > > return 0; > > > > if (state) > > at91... > > else > > at91... > > > > Hi Jonathan, > > Ok I will rework it in next version > > >> > >> return 0; > >> } > >> @@ -777,10 +790,10 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig) > >> if (st->dma_st.dma_chan) > >> return 0; > >> > >> - enable_irq(st->irq); > >> - > >> /* Needed to ACK the DRDY interruption */ > >> at91_adc_readl(st, AT91_SAMA5D2_LCDR); > >> + > >> + enable_irq(st->irq); > > > > Why this change? I'm not totally following the description above. > > > > The ' reading of the LCDR register ' makes the DRDY bit in ISR > (interrupt status register) to be cleared. > So, reading that clears the IRQ, but, if we enable the IRQs before this > clearance, there is a race chance that we get the DRDY IRQ triggered again. > It is best to clear the DRDY first, and then re enable the IRQs. > > Does it make sense ? Why is it an issue if dataready is triggered again? That should only happen if there really is new data. In that case we want to call the interrupt handler again. Normally hardware will only generate a new interrupt after the status register is cleared. If that's not the case here than the hardware is racy whatever order we do it in. If not, the old order is correct as we don't want to potentially miss the interrupt. Chances are this is a level interrupt so it won't make any difference either way, we either trigger at or after the readl (original code) or it's still set when we hit the enable_irq and trigger then (with reordered code). So unless I'm missing something, original code order was more 'standard' but it may make not difference. Jonathan > > >> return 0; > >> } > >> > >> @@ -1015,6 +1028,22 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, > >> int i = 0; > >> int val; > >> u8 bit; > >> + u32 mask = at91_adc_active_scan_mask_to_reg(indio_dev); > >> + unsigned int timeout = 50; > >> + > >> + /* > >> + * Check if the conversion is ready. If not, wait a little bit, and > >> + * in case of timeout exit with an error. > >> + */ > >> + while ((at91_adc_readl(st, AT91_SAMA5D2_ISR) & mask) != mask && > >> + timeout) { > >> + usleep_range(50, 100); > >> + timeout--; > >> + } > >> + > >> + /* Cannot read data, not ready. Continue without reporting data */ > >> + if (!timeout) > >> + return; > >> > >> for_each_set_bit(bit, indio_dev->active_scan_mask, > >> indio_dev->num_channels) { > >> @@ -1281,7 +1310,8 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private) > >> status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR); > >> status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR); > >> status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR); > >> - } else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) { > >> + } else if (iio_buffer_enabled(indio) && > >> + (status & AT91_SAMA5D2_IER_DRDY)) { > >> /* triggered buffer without DMA */ > >> disable_irq_nosync(irq); > >> iio_trigger_poll(indio->trig); > > > > > >