diff mbox series

[v2,5/5] irqchip/renesas-rzg2l: Use TIEN for enable/disable

Message ID 20240305183922.138727-6-biju.das.jz@bp.renesas.com (mailing list archive)
State Superseded
Delegated to: Geert Uytterhoeven
Headers show
Series Fix spurious TINT IRQ and enhancements | expand

Commit Message

Biju Das March 5, 2024, 6:39 p.m. UTC
Currently hardware settings for TINT detection is not in sync with
TINT source as the enable/disable overrides source setting value leading
to hardware inconsistent state. For eg: consider the case GPIOINT0 is used
as TINT interrupt and configuring GPIOINT5 as edgetype. During disable the
clearing of the entire bytes of TINT source selection for GPIOINT5 is same
as GPIOINT0 with TIEN disabled. Other than this during enabling, the
setting of GPIOINT5 with TIEN results in spurious IRQ as due to a HW race,
it is possible that IP can use the TIEN with previous source value
(GPIOINT0).

So, it is better to just use TIEN for enable/disable and avoid modifying
TINT source selection register.This will make the consistent hardware
settings for detection method tied with TINT source and allows to simplify
the code.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v1->v2:
 * Merged patch#4 and #5 and updated commit description.
---
 drivers/irqchip/irq-renesas-rzg2l.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

Comments

Thomas Gleixner March 13, 2024, 3:40 p.m. UTC | #1
On Tue, Mar 05 2024 at 18:39, Biju Das wrote:
> Currently hardware settings for TINT detection is not in sync with
> TINT source as the enable/disable overrides source setting value leading
> to hardware inconsistent state. For eg: consider the case GPIOINT0 is used
> as TINT interrupt and configuring GPIOINT5 as edgetype. During disable the
> clearing of the entire bytes of TINT source selection for GPIOINT5 is same
> as GPIOINT0 with TIEN disabled. Other than this during enabling, the
> setting of GPIOINT5 with TIEN results in spurious IRQ as due to a HW race,
> it is possible that IP can use the TIEN with previous source value
> (GPIOINT0).
>
> So, it is better to just use TIEN for enable/disable and avoid modifying
> TINT source selection register.This will make the consistent hardware
> settings for detection method tied with TINT source and allows to simplify
> the code.

I have no idea how the subject and change log is related to what the
patch is doing.

The patch just consolidates the almost identical functionality of
rzg2l_irqc_irq_disable() and rzg2l_irqc_irq_enable() into a helper
function which is invoked from both places. The existing code already
uses TIEN for disable and enable, so what's the change?

IOW, it's zero functional change and completely unrelated to the above
blurb.

Thanks,

        tglx
Biju Das March 13, 2024, 3:59 p.m. UTC | #2
Hi Thomas,

> -----Original Message-----
> From: Thomas Gleixner <tglx@linutronix.de>
> Sent: Wednesday, March 13, 2024 3:40 PM
> Subject: Re: [PATCH v2 5/5] irqchip/renesas-rzg2l: Use TIEN for enable/disable
> 
> On Tue, Mar 05 2024 at 18:39, Biju Das wrote:
> > Currently hardware settings for TINT detection is not in sync with
> > TINT source as the enable/disable overrides source setting value
> > leading to hardware inconsistent state. For eg: consider the case
> > GPIOINT0 is used as TINT interrupt and configuring GPIOINT5 as
> > edgetype. During disable the clearing of the entire bytes of TINT
> > source selection for GPIOINT5 is same as GPIOINT0 with TIEN disabled.
> > Other than this during enabling, the setting of GPIOINT5 with TIEN
> > results in spurious IRQ as due to a HW race, it is possible that IP
> > can use the TIEN with previous source value (GPIOINT0).
> >
> > So, it is better to just use TIEN for enable/disable and avoid
> > modifying TINT source selection register.This will make the consistent
> > hardware settings for detection method tied with TINT source and
> > allows to simplify the code.
> 
> I have no idea how the subject and change log is related to what the patch is doing.
> 
> The patch just consolidates the almost identical functionality of
> rzg2l_irqc_irq_disable() and rzg2l_irqc_irq_enable() into a helper function which is invoked from both
> places. The existing code already uses TIEN for disable and enable, so what's the change?
> 
> IOW, it's zero functional change and completely unrelated to the above blurb.

There is functional change. During disable, TINT source and TIEN cleared together

reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));

During Enable, TINT source and TIEN set together

reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);

This patch avoids modifying TINT source register which avoids hw race
as mentioned by hardware team. According to them we should not
set TINT source and TIEN together.

I can update the change log.

Cheers,
Biju
Thomas Gleixner March 14, 2024, 8:59 a.m. UTC | #3
On Wed, Mar 13 2024 at 15:59, Biju Das wrote:
>> From: Thomas Gleixner <tglx@linutronix.de>
>> IOW, it's zero functional change and completely unrelated to the above blurb.
>
> There is functional change. During disable, TINT source and TIEN cleared together
>
> reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
>
> During Enable, TINT source and TIEN set together
>
> reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);
>
> This patch avoids modifying TINT source register which avoids hw race
> as mentioned by hardware team. According to them we should not
> set TINT source and TIEN together.

Can you please split this into two pieces?

    1) The fix itself at both places

    2) The consolidation

That way it's obvious what this is doing. I really missed that subtle
change.

Thanks,

        tglx
Biju Das March 14, 2024, 9:07 a.m. UTC | #4
Hi Thomas,

> -----Original Message-----
> From: Thomas Gleixner <tglx@linutronix.de>
> Sent: Thursday, March 14, 2024 8:59 AM
> Subject: RE: [PATCH v2 5/5] irqchip/renesas-rzg2l: Use TIEN for enable/disable
> 
> On Wed, Mar 13 2024 at 15:59, Biju Das wrote:
> >> From: Thomas Gleixner <tglx@linutronix.de> IOW, it's zero functional
> >> change and completely unrelated to the above blurb.
> >
> > There is functional change. During disable, TINT source and TIEN
> > cleared together
> >
> > reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
> >
> > During Enable, TINT source and TIEN set together
> >
> > reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);
> >
> > This patch avoids modifying TINT source register which avoids hw race
> > as mentioned by hardware team. According to them we should not set
> > TINT source and TIEN together.
> 
> Can you please split this into two pieces?
> 
>     1) The fix itself at both places
> 
>     2) The consolidation
> 
> That way it's obvious what this is doing. I really missed that subtle change.

OK, will split this patch into two.

Thanks,
Biju
diff mbox series

Patch

diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c
index e793b8f07dac..a7d47dbf7627 100644
--- a/drivers/irqchip/irq-renesas-rzg2l.c
+++ b/drivers/irqchip/irq-renesas-rzg2l.c
@@ -138,7 +138,7 @@  static void rzg2l_irqc_eoi(struct irq_data *d)
 	irq_chip_eoi_parent(d);
 }
 
-static void rzg2l_irqc_irq_disable(struct irq_data *d)
+static void rzg2l_tint_irq_endisable(struct irq_data *d, bool enable)
 {
 	unsigned int hw_irq = irqd_to_hwirq(d);
 
@@ -151,31 +151,24 @@  static void rzg2l_irqc_irq_disable(struct irq_data *d)
 
 		raw_spin_lock(&priv->lock);
 		reg = readl_relaxed(priv->base + TSSR(tssr_index));
-		reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
+		if (enable)
+			reg |= TIEN << TSSEL_SHIFT(tssr_offset);
+		else
+			reg &= ~(TIEN << TSSEL_SHIFT(tssr_offset));
 		writel_relaxed(reg, priv->base + TSSR(tssr_index));
 		raw_spin_unlock(&priv->lock);
 	}
+}
+
+static void rzg2l_irqc_irq_disable(struct irq_data *d)
+{
+	rzg2l_tint_irq_endisable(d, false);
 	irq_chip_disable_parent(d);
 }
 
 static void rzg2l_irqc_irq_enable(struct irq_data *d)
 {
-	unsigned int hw_irq = irqd_to_hwirq(d);
-
-	if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
-		unsigned long tint = (uintptr_t)irq_data_get_irq_chip_data(d);
-		struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
-		u32 offset = hw_irq - IRQC_TINT_START;
-		u32 tssr_offset = TSSR_OFFSET(offset);
-		u8 tssr_index = TSSR_INDEX(offset);
-		u32 reg;
-
-		raw_spin_lock(&priv->lock);
-		reg = readl_relaxed(priv->base + TSSR(tssr_index));
-		reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);
-		writel_relaxed(reg, priv->base + TSSR(tssr_index));
-		raw_spin_unlock(&priv->lock);
-	}
+	rzg2l_tint_irq_endisable(d, true);
 	irq_chip_enable_parent(d);
 }