All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: Eliav Farber <farbere@amazon.com>
Cc: <catalin.marinas@arm.com>, <will@kernel.org>,
	<akpm@linux-foundation.org>, <bhe@redhat.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>, <jonnyc@amazon.com>
Subject: Re: [PATCH] arm64: kexec: Check if IRQ is already masked before masking
Date: Tue, 26 Nov 2024 18:23:34 +0000	[thread overview]
Message-ID: <86cyihvopl.wl-maz@kernel.org> (raw)
In-Reply-To: <20241126050509.4426-1-farbere@amazon.com>

Thanks Catalin for pointing me to this patch.

On Tue, 26 Nov 2024 05:05:09 +0000,
Eliav Farber <farbere@amazon.com> wrote:
> 
> During machine kexec, the function machine_kexec_mask_interrupts() is
> responsible for masking all interrupts. However, the current
> implementation unconditionally calls the irq_mask() function for each
> interrupt descriptor, even if the interrupt is already masked.
> 
> This commit adds a check to verify if the interrupt is not already
> masked before calling the irq_mask() function. This change avoids
> redundant masking operations and potential issues that might arise from
> attempting to mask an already masked interrupt.
> 
> A specific issue was observed in the crash kernel flow after unbinding a
> device (prior to kexec) that used a GPIO as an IRQ source. The warning
> was triggered by the gpiochip_disable_irq() function, which attempted to
> clear the FLAG_IRQ_IS_ENABLED flag when FLAG_USED_AS_IRQ was not set:
> 
> ```
> void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset)
> {
> 	struct gpio_desc *desc = gpiochip_get_desc(gc, offset);
> 
> 	if (!IS_ERR(desc) &&
> 	    !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags)))
> 		clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
> }
> ```
> 
> This issue began after commit a8173820f441 ("gpio: gpiolib: Allow GPIO
> IRQs to lazy disable"), which replaced IRQ disable/enable hooks with
> mask/unmask hooks in some cases. The irq_disable hook was protected
> against disabling an already disabled IRQ, but the irq_mask hook in
> machine_kexec_mask_interrupts() was not.
> 
> When a driver that uses a GPIO-irq is unbound, the corresponding IRQ is
> released, invoking __irq_disable() and irq_state_set_masked().
> Subsequently, machine_kexec_mask_interrupts() attempts to call the
> chip->irq_mask() function again. This invokes gpiochip_irq_mask() and
> gpiochip_disable_irq(), and since FLAG_USED_AS_IRQ has already been
> cleared, this results in a warning being printed.
> 
> Signed-off-by: Eliav Farber <farbere@amazon.com>
> ---
>  arch/arm64/kernel/machine_kexec.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
> index 82e2203d86a3..6f56ec676844 100644
> --- a/arch/arm64/kernel/machine_kexec.c
> +++ b/arch/arm64/kernel/machine_kexec.c
> @@ -230,7 +230,7 @@ static void machine_kexec_mask_interrupts(void)
>  		    chip->irq_eoi)
>  			chip->irq_eoi(&desc->irq_data);
>  
> -		if (chip->irq_mask)
> +		if (chip->irq_mask && !irqd_irq_masked(&desc->irq_data))
>  			chip->irq_mask(&desc->irq_data);

Maybe a slightly better approach would be to simplify this code for
something that actually uses the kernel infrastructure:

diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index 82e2203d86a31..9b48d952df3ec 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -230,11 +230,8 @@ static void machine_kexec_mask_interrupts(void)
 		    chip->irq_eoi)
 			chip->irq_eoi(&desc->irq_data);
 
-		if (chip->irq_mask)
-			chip->irq_mask(&desc->irq_data);
-
-		if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data))
-			chip->irq_disable(&desc->irq_data);
+		irq_set_status_flags(i, IRQ_DISABLE_UNLAZY);
+		irq_disable(desc);
 	}
 }
 
This is of course untested.

But a *much* better approach would be to have a way to turn the
irqchip off altogether and stop this silly "walk 1000s of interrupts
for no purpose". Unfortunately, we don't have a good way to do this
today.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.


  reply	other threads:[~2024-11-26 18:24 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-26  5:05 [PATCH] arm64: kexec: Check if IRQ is already masked before masking Eliav Farber
2024-11-26 18:23 ` Marc Zyngier [this message]
2024-11-27 14:58   ` Farber, Eliav
  -- strict thread matches above, loose matches on Subject: below --
2024-11-27 15:18 Farber, Eliav

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=86cyihvopl.wl-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=bhe@redhat.com \
    --cc=catalin.marinas@arm.com \
    --cc=farbere@amazon.com \
    --cc=jonnyc@amazon.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.