Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'irq-urgent-2024-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fixes from Thomas Gleixner:
"A series of fixes for the Renesas RZG21 interrupt chip driver to
prevent spurious and misrouted interrupts.

- Ensure that posted writes are flushed in the eoi() callback

- Ensure that interrupts are masked at the chip level when the
trigger type is changed

- Clear the interrupt status register when setting up edge type
trigger modes

- Ensure that the trigger type and routing information is set before
the interrupt is enabled"

* tag 'irq-urgent-2024-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
irqchip/renesas-rzg2l: Do not set TIEN and TINT source at the same time
irqchip/renesas-rzg2l: Prevent spurious interrupts when setting trigger type
irqchip/renesas-rzg2l: Rename rzg2l_irq_eoi()
irqchip/renesas-rzg2l: Rename rzg2l_tint_eoi()
irqchip/renesas-rzg2l: Flush posted write in irq_eoi()

+54 -18
+54 -18
drivers/irqchip/irq-renesas-rzg2l.c
··· 85 85 return data->domain->host_data; 86 86 } 87 87 88 - static void rzg2l_irq_eoi(struct irq_data *d) 88 + static void rzg2l_clear_irq_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq) 89 89 { 90 - unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START; 91 - struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 90 + unsigned int hw_irq = hwirq - IRQC_IRQ_START; 92 91 u32 bit = BIT(hw_irq); 93 92 u32 iitsr, iscr; 94 93 ··· 98 99 * ISCR can only be cleared if the type is falling-edge, rising-edge or 99 100 * falling/rising-edge. 100 101 */ 101 - if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq))) 102 + if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq))) { 102 103 writel_relaxed(iscr & ~bit, priv->base + ISCR); 104 + /* 105 + * Enforce that the posted write is flushed to prevent that the 106 + * just handled interrupt is raised again. 107 + */ 108 + readl_relaxed(priv->base + ISCR); 109 + } 103 110 } 104 111 105 - static void rzg2l_tint_eoi(struct irq_data *d) 112 + static void rzg2l_clear_tint_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq) 106 113 { 107 - unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_TINT_START; 108 - struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 109 - u32 bit = BIT(hw_irq); 114 + u32 bit = BIT(hwirq - IRQC_TINT_START); 110 115 u32 reg; 111 116 112 117 reg = readl_relaxed(priv->base + TSCR); 113 - if (reg & bit) 118 + if (reg & bit) { 114 119 writel_relaxed(reg & ~bit, priv->base + TSCR); 120 + /* 121 + * Enforce that the posted write is flushed to prevent that the 122 + * just handled interrupt is raised again. 123 + */ 124 + readl_relaxed(priv->base + TSCR); 125 + } 115 126 } 116 127 117 128 static void rzg2l_irqc_eoi(struct irq_data *d) ··· 131 122 132 123 raw_spin_lock(&priv->lock); 133 124 if (hw_irq >= IRQC_IRQ_START && hw_irq <= IRQC_IRQ_COUNT) 134 - rzg2l_irq_eoi(d); 125 + rzg2l_clear_irq_int(priv, hw_irq); 135 126 else if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) 136 - rzg2l_tint_eoi(d); 127 + rzg2l_clear_tint_int(priv, hw_irq); 137 128 raw_spin_unlock(&priv->lock); 138 129 irq_chip_eoi_parent(d); 139 130 } ··· 151 142 152 143 raw_spin_lock(&priv->lock); 153 144 reg = readl_relaxed(priv->base + TSSR(tssr_index)); 154 - reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset)); 145 + reg &= ~(TIEN << TSSEL_SHIFT(tssr_offset)); 155 146 writel_relaxed(reg, priv->base + TSSR(tssr_index)); 156 147 raw_spin_unlock(&priv->lock); 157 148 } ··· 163 154 unsigned int hw_irq = irqd_to_hwirq(d); 164 155 165 156 if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) { 166 - unsigned long tint = (uintptr_t)irq_data_get_irq_chip_data(d); 167 157 struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 168 158 u32 offset = hw_irq - IRQC_TINT_START; 169 159 u32 tssr_offset = TSSR_OFFSET(offset); ··· 171 163 172 164 raw_spin_lock(&priv->lock); 173 165 reg = readl_relaxed(priv->base + TSSR(tssr_index)); 174 - reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset); 166 + reg |= TIEN << TSSEL_SHIFT(tssr_offset); 175 167 writel_relaxed(reg, priv->base + TSSR(tssr_index)); 176 168 raw_spin_unlock(&priv->lock); 177 169 } ··· 180 172 181 173 static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type) 182 174 { 183 - unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START; 184 175 struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 176 + unsigned int hwirq = irqd_to_hwirq(d); 177 + u32 iitseln = hwirq - IRQC_IRQ_START; 178 + bool clear_irq_int = false; 185 179 u16 sense, tmp; 186 180 187 181 switch (type & IRQ_TYPE_SENSE_MASK) { ··· 193 183 194 184 case IRQ_TYPE_EDGE_FALLING: 195 185 sense = IITSR_IITSEL_EDGE_FALLING; 186 + clear_irq_int = true; 196 187 break; 197 188 198 189 case IRQ_TYPE_EDGE_RISING: 199 190 sense = IITSR_IITSEL_EDGE_RISING; 191 + clear_irq_int = true; 200 192 break; 201 193 202 194 case IRQ_TYPE_EDGE_BOTH: 203 195 sense = IITSR_IITSEL_EDGE_BOTH; 196 + clear_irq_int = true; 204 197 break; 205 198 206 199 default: ··· 212 199 213 200 raw_spin_lock(&priv->lock); 214 201 tmp = readl_relaxed(priv->base + IITSR); 215 - tmp &= ~IITSR_IITSEL_MASK(hw_irq); 216 - tmp |= IITSR_IITSEL(hw_irq, sense); 202 + tmp &= ~IITSR_IITSEL_MASK(iitseln); 203 + tmp |= IITSR_IITSEL(iitseln, sense); 204 + if (clear_irq_int) 205 + rzg2l_clear_irq_int(priv, hwirq); 217 206 writel_relaxed(tmp, priv->base + IITSR); 218 207 raw_spin_unlock(&priv->lock); 219 208 220 209 return 0; 210 + } 211 + 212 + static u32 rzg2l_disable_tint_and_set_tint_source(struct irq_data *d, struct rzg2l_irqc_priv *priv, 213 + u32 reg, u32 tssr_offset, u8 tssr_index) 214 + { 215 + u32 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d); 216 + u32 tien = reg & (TIEN << TSSEL_SHIFT(tssr_offset)); 217 + 218 + /* Clear the relevant byte in reg */ 219 + reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset)); 220 + /* Set TINT and leave TIEN clear */ 221 + reg |= tint << TSSEL_SHIFT(tssr_offset); 222 + writel_relaxed(reg, priv->base + TSSR(tssr_index)); 223 + 224 + return reg | tien; 221 225 } 222 226 223 227 static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type) ··· 242 212 struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 243 213 unsigned int hwirq = irqd_to_hwirq(d); 244 214 u32 titseln = hwirq - IRQC_TINT_START; 215 + u32 tssr_offset = TSSR_OFFSET(titseln); 216 + u8 tssr_index = TSSR_INDEX(titseln); 245 217 u8 index, sense; 246 - u32 reg; 218 + u32 reg, tssr; 247 219 248 220 switch (type & IRQ_TYPE_SENSE_MASK) { 249 221 case IRQ_TYPE_EDGE_RISING: ··· 267 235 } 268 236 269 237 raw_spin_lock(&priv->lock); 238 + tssr = readl_relaxed(priv->base + TSSR(tssr_index)); 239 + tssr = rzg2l_disable_tint_and_set_tint_source(d, priv, tssr, tssr_offset, tssr_index); 270 240 reg = readl_relaxed(priv->base + TITSR(index)); 271 241 reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH)); 272 242 reg |= sense << (titseln * TITSEL_WIDTH); 273 243 writel_relaxed(reg, priv->base + TITSR(index)); 244 + rzg2l_clear_tint_int(priv, hwirq); 245 + writel_relaxed(tssr, priv->base + TSSR(tssr_index)); 274 246 raw_spin_unlock(&priv->lock); 275 247 276 248 return 0;