diff mbox series

[09/13] mtd: rawnand: gpmi: poll the BCH interrupt bit in start_dma_with_bch_irq()

Message ID 20180426154134.8270-10-sam.lefebvre@essensium.com
State Changes Requested
Delegated to: Boris Brezillon
Headers show
Series [01/13] mtd: nand: gpmi: drop dma_ops_type | expand

Commit Message

Sam Lefebvre April 26, 2018, 3:41 p.m. UTC
To improve nand performance, the BCH interrupt bit must be polled
before waiting for occurence. This avoids an unnecessary context switch.

Signed-off-by: Sam Lefebvre <sam.lefebvre@essensium.com>
---
 drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

Comments

Boris Brezillon April 26, 2018, 4:49 p.m. UTC | #1
On Thu, 26 Apr 2018 17:41:30 +0200
Sam Lefebvre <sam.lefebvre@essensium.com> wrote:

> To improve nand performance, the BCH interrupt bit must be polled
> before waiting for occurence. This avoids an unnecessary context switch.
> 
> Signed-off-by: Sam Lefebvre <sam.lefebvre@essensium.com>
> ---
>  drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
> index 60bc1bac7741..28a2cf106ddc 100644
> --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
> +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
> @@ -503,18 +503,31 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this,
>   * Actually, we must wait for two interrupts :
>   *	[1] firstly the DMA interrupt and
>   *	[2] secondly the BCH interrupt.
> + *	To improve performance, we first poll for the BCH
> + *	interrupt.
>   */
>  int start_dma_with_bch_irq(struct gpmi_nand_data *this,
>  			struct dma_async_tx_descriptor *desc)
>  {
>  	struct completion *bch_c = &this->bch_done;
> +	struct resources *r = &this->resources;
>  	unsigned long timeout;
>  
> -	/* Prepare to receive an interrupt from the BCH block. */
> -	init_completion(bch_c);
> +	/* Disable interrupt */
> +	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, r->bch_regs + HW_BCH_CTRL_CLR);

I'd prefer to have it disabled in the probe function.

>  
>  	/* start the DMA */
>  	start_dma_without_bch_irq(this, desc);
> +	if (readl(r->bch_regs + HW_BCH_CTRL) & BM_BCH_CTRL_COMPLETE_IRQ) {
> +		writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
> +		return 0;
> +	}
> +
> +	/* Prepare to receive an interrupt from the BCH block. */
> +	init_completion(bch_c);
> +
> +	/* Re-enable interrupt */
> +	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, r->bch_regs + HW_BCH_CTRL_SET);
>  
>  	/* Wait for the interrupt from the BCH block. */
>  	timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));

And then you can disable it here, so that the interrupt is only active
when we need it.
diff mbox series

Patch

diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 60bc1bac7741..28a2cf106ddc 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -503,18 +503,31 @@  int start_dma_without_bch_irq(struct gpmi_nand_data *this,
  * Actually, we must wait for two interrupts :
  *	[1] firstly the DMA interrupt and
  *	[2] secondly the BCH interrupt.
+ *	To improve performance, we first poll for the BCH
+ *	interrupt.
  */
 int start_dma_with_bch_irq(struct gpmi_nand_data *this,
 			struct dma_async_tx_descriptor *desc)
 {
 	struct completion *bch_c = &this->bch_done;
+	struct resources *r = &this->resources;
 	unsigned long timeout;
 
-	/* Prepare to receive an interrupt from the BCH block. */
-	init_completion(bch_c);
+	/* Disable interrupt */
+	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, r->bch_regs + HW_BCH_CTRL_CLR);
 
 	/* start the DMA */
 	start_dma_without_bch_irq(this, desc);
+	if (readl(r->bch_regs + HW_BCH_CTRL) & BM_BCH_CTRL_COMPLETE_IRQ) {
+		writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
+		return 0;
+	}
+
+	/* Prepare to receive an interrupt from the BCH block. */
+	init_completion(bch_c);
+
+	/* Re-enable interrupt */
+	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, r->bch_regs + HW_BCH_CTRL_SET);
 
 	/* Wait for the interrupt from the BCH block. */
 	timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));