[1/3] genirq: Simplify cond_unmask_eoi_irq()

Message ID 20221126234134.32660-2-samuel@sholland.org
State New
Headers
Series genirq: oneshot-safe threaded EOIs |

Commit Message

Samuel Holland Nov. 26, 2022, 11:41 p.m. UTC
  This function calls .irq_eoi in three places, making the logic hard to
follow. Rearrange the function so that .irq_eoi is called only once.

The only time .irq_eoi is not called is when all three if checks fail,
so return early in that case. threads_oneshot can only be nonzero if
IRQS_ONESHOT is set, so the IRQS_ONESHOT check can be omitted there.

The IRQS_ONESHOT condition from the first if statement must then be
copied to the unmask_irq() condition.

Furthermore, if IRQS_ONESHOT is set, mask_irq() must have been called
in the parent function, so the irqd_irq_masked() check is redundant.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---

 kernel/irq/chip.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
  

Comments

Thomas Gleixner Nov. 30, 2022, 2:48 p.m. UTC | #1
Samuel!

On Sat, Nov 26 2022 at 17:41, Samuel Holland wrote:

> This function calls .irq_eoi in three places, making the logic hard to
> follow. Rearrange the function so that .irq_eoi is called only once.
>
> The only time .irq_eoi is not called is when all three if checks fail,
> so return early in that case. threads_oneshot can only be nonzero if
> IRQS_ONESHOT is set, so the IRQS_ONESHOT check can be omitted there.
>
> The IRQS_ONESHOT condition from the first if statement must then be
> copied to the unmask_irq() condition.
>
> Furthermore, if IRQS_ONESHOT is set, mask_irq() must have been called
> in the parent function, so the irqd_irq_masked() check is redundant.

Not really convinced that all this is functionaly equivalent.

>  static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
>  {
> -	if (!(desc->istate & IRQS_ONESHOT)) {
> -		chip->irq_eoi(&desc->irq_data);
> +	/*
> +	 * Do not send an EOI if the thread will do it later in
> +	 * unmask_threaded_irq().
> +	 */
> +	if ((chip->flags & IRQCHIP_EOI_THREADED) && desc->threads_oneshot)
>  		return;
> -	}
> +
> +	chip->irq_eoi(&desc->irq_data);

This now issues EOI when the interrupt is in disabled state, which was
not done before. That's probably a non-issue, but clearly a undocumented
change.

> +
>  	/*
>  	 * We need to unmask in the following cases:
>  	 * - Oneshot irq which did not wake the thread (caused by a
> @@ -669,12 +674,8 @@ static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
>  	 *   completely).
>  	 */
>  	if (!irqd_irq_disabled(&desc->irq_data) &&
> -	    irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
> -		chip->irq_eoi(&desc->irq_data);
> +	    (desc->istate & IRQS_ONESHOT) && !desc->threads_oneshot)
>  		unmask_irq(desc);

This breaks the mask logic of handle_fasteoi_mask_irq() for an interrupt
which does not have IRQS_ONESHOT set.

So no, it's not the same and it even breaks stuff.

Thanks,

        tglx
  
Thomas Gleixner Nov. 30, 2022, 3:29 p.m. UTC | #2
On Wed, Nov 30 2022 at 15:48, Thomas Gleixner wrote:
> On Sat, Nov 26 2022 at 17:41, Samuel Holland wrote:
>> +	    (desc->istate & IRQS_ONESHOT) && !desc->threads_oneshot)
>>  		unmask_irq(desc);
>
> This breaks the mask logic of handle_fasteoi_mask_irq() for an interrupt
> which does not have IRQS_ONESHOT set.

Ignore this one. That handler is broken by design.
  

Patch

diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 8ac37e8e738a..672bad021a1f 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -658,10 +658,15 @@  EXPORT_SYMBOL_GPL(handle_level_irq);
 
 static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
 {
-	if (!(desc->istate & IRQS_ONESHOT)) {
-		chip->irq_eoi(&desc->irq_data);
+	/*
+	 * Do not send an EOI if the thread will do it later in
+	 * unmask_threaded_irq().
+	 */
+	if ((chip->flags & IRQCHIP_EOI_THREADED) && desc->threads_oneshot)
 		return;
-	}
+
+	chip->irq_eoi(&desc->irq_data);
+
 	/*
 	 * We need to unmask in the following cases:
 	 * - Oneshot irq which did not wake the thread (caused by a
@@ -669,12 +674,8 @@  static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
 	 *   completely).
 	 */
 	if (!irqd_irq_disabled(&desc->irq_data) &&
-	    irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
-		chip->irq_eoi(&desc->irq_data);
+	    (desc->istate & IRQS_ONESHOT) && !desc->threads_oneshot)
 		unmask_irq(desc);
-	} else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
-		chip->irq_eoi(&desc->irq_data);
-	}
 }
 
 /**