Skip to content

Commit 853a603

Browse files
bijudasKAGA-KOKO
authored andcommitted
irqchip/renesas-rzg2l: Prevent spurious interrupts when setting trigger type
RZ/G2L interrupt chips require that the interrupt is masked before changing the NMI, IRQ, TINT interrupt settings. Aside of that, after setting an edge trigger type it is required to clear the interrupt status register in order to avoid spurious interrupts. The current implementation fails to do either of that and therefore is prone to generate spurious interrupts when setting the trigger type. Address this by: - Ensuring that the interrupt is masked at the chip level across the update for the TINT chip - Clearing the interrupt status register after updating the trigger mode for edge type interrupts [ tglx: Massaged changelog and reverted the spin_lock_irqsave() change as the set_type() callback is always called with interrupts disabled. ] Fixes: 3fed095 ("irqchip: Add RZ/G2L IA55 Interrupt Controller driver") Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1 parent b4b5cd6 commit 853a603

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

drivers/irqchip/irq-renesas-rzg2l.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,10 @@ static void rzg2l_irqc_irq_enable(struct irq_data *d)
181181

182182
static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
183183
{
184-
unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
185184
struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
185+
unsigned int hwirq = irqd_to_hwirq(d);
186+
u32 iitseln = hwirq - IRQC_IRQ_START;
187+
bool clear_irq_int = false;
186188
u16 sense, tmp;
187189

188190
switch (type & IRQ_TYPE_SENSE_MASK) {
@@ -192,14 +194,17 @@ static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
192194

193195
case IRQ_TYPE_EDGE_FALLING:
194196
sense = IITSR_IITSEL_EDGE_FALLING;
197+
clear_irq_int = true;
195198
break;
196199

197200
case IRQ_TYPE_EDGE_RISING:
198201
sense = IITSR_IITSEL_EDGE_RISING;
202+
clear_irq_int = true;
199203
break;
200204

201205
case IRQ_TYPE_EDGE_BOTH:
202206
sense = IITSR_IITSEL_EDGE_BOTH;
207+
clear_irq_int = true;
203208
break;
204209

205210
default:
@@ -208,21 +213,40 @@ static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
208213

209214
raw_spin_lock(&priv->lock);
210215
tmp = readl_relaxed(priv->base + IITSR);
211-
tmp &= ~IITSR_IITSEL_MASK(hw_irq);
212-
tmp |= IITSR_IITSEL(hw_irq, sense);
216+
tmp &= ~IITSR_IITSEL_MASK(iitseln);
217+
tmp |= IITSR_IITSEL(iitseln, sense);
218+
if (clear_irq_int)
219+
rzg2l_clear_irq_int(priv, hwirq);
213220
writel_relaxed(tmp, priv->base + IITSR);
214221
raw_spin_unlock(&priv->lock);
215222

216223
return 0;
217224
}
218225

226+
static u32 rzg2l_disable_tint_and_set_tint_source(struct irq_data *d, struct rzg2l_irqc_priv *priv,
227+
u32 reg, u32 tssr_offset, u8 tssr_index)
228+
{
229+
u32 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d);
230+
u32 tien = reg & (TIEN << TSSEL_SHIFT(tssr_offset));
231+
232+
/* Clear the relevant byte in reg */
233+
reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
234+
/* Set TINT and leave TIEN clear */
235+
reg |= tint << TSSEL_SHIFT(tssr_offset);
236+
writel_relaxed(reg, priv->base + TSSR(tssr_index));
237+
238+
return reg | tien;
239+
}
240+
219241
static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
220242
{
221243
struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
222244
unsigned int hwirq = irqd_to_hwirq(d);
223245
u32 titseln = hwirq - IRQC_TINT_START;
246+
u32 tssr_offset = TSSR_OFFSET(titseln);
247+
u8 tssr_index = TSSR_INDEX(titseln);
224248
u8 index, sense;
225-
u32 reg;
249+
u32 reg, tssr;
226250

227251
switch (type & IRQ_TYPE_SENSE_MASK) {
228252
case IRQ_TYPE_EDGE_RISING:
@@ -244,10 +268,14 @@ static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
244268
}
245269

246270
raw_spin_lock(&priv->lock);
271+
tssr = readl_relaxed(priv->base + TSSR(tssr_index));
272+
tssr = rzg2l_disable_tint_and_set_tint_source(d, priv, tssr, tssr_offset, tssr_index);
247273
reg = readl_relaxed(priv->base + TITSR(index));
248274
reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH));
249275
reg |= sense << (titseln * TITSEL_WIDTH);
250276
writel_relaxed(reg, priv->base + TITSR(index));
277+
rzg2l_clear_tint_int(priv, hwirq);
278+
writel_relaxed(tssr, priv->base + TSSR(tssr_index));
251279
raw_spin_unlock(&priv->lock);
252280

253281
return 0;

0 commit comments

Comments
 (0)