[PATCH v2 2/6] genirq: Allow an interrupt to be marked as 'raw'

Todd Kjos tkjos at google.com
Wed Jun 23 10:28:26 PDT 2021


On Tue, Nov 24, 2020 at 6:15 AM Marc Zyngier <maz at kernel.org> wrote:
>
> Some interrupts (such as the rescheduling IPI) rely on not going through
> the irq_enter()/irq_exit() calls. To distinguish such interrupts, add
> a new IRQ flag that allows the low-level handling code to sidestep the
> enter()/exit() calls.
>
> Only the architecture code is expected to use this. It will do the wrong
> thing on normal interrupts. Note that this is a band-aid until we can
> move to some more correct infrastructure (such as kernel/entry/common.c).
>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  include/linux/irq.h   |  2 ++
>  kernel/irq/Kconfig    |  3 +++
>  kernel/irq/debugfs.c  |  1 +
>  kernel/irq/irqdesc.c  | 17 ++++++++++++-----
>  kernel/irq/settings.h | 15 +++++++++++++++
>  5 files changed, 33 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/irq.h b/include/linux/irq.h
> index c55f218d5b61..605ba5949255 100644
> --- a/include/linux/irq.h
> +++ b/include/linux/irq.h
> @@ -72,6 +72,7 @@ enum irqchip_irq_state;
>   *                               mechanism and from core side polling.
>   * IRQ_DISABLE_UNLAZY          - Disable lazy irq disable
>   * IRQ_HIDDEN                  - Don't show up in /proc/interrupts
> + * IRQ_RAW                     - Skip tick management and irqtime accounting
>   */
>  enum {
>         IRQ_TYPE_NONE           = 0x00000000,
> @@ -99,6 +100,7 @@ enum {
>         IRQ_IS_POLLED           = (1 << 18),
>         IRQ_DISABLE_UNLAZY      = (1 << 19),
>         IRQ_HIDDEN              = (1 << 20),
> +       IRQ_RAW                 = (1 << 21),
>  };
>
>  #define IRQF_MODIFY_MASK       \
> diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
> index 164a031cfdb6..ae9b13d5ee91 100644
> --- a/kernel/irq/Kconfig
> +++ b/kernel/irq/Kconfig
> @@ -109,6 +109,9 @@ config GENERIC_IRQ_MATRIX_ALLOCATOR
>  config GENERIC_IRQ_RESERVATION_MODE
>         bool
>
> +config ARCH_WANTS_IRQ_RAW
> +       bool
> +
>  # Support forced irq threading
>  config IRQ_FORCED_THREADING
>         bool
> diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
> index e4cff358b437..f53475d88072 100644
> --- a/kernel/irq/debugfs.c
> +++ b/kernel/irq/debugfs.c
> @@ -140,6 +140,7 @@ static const struct irq_bit_descr irqdesc_states[] = {
>         BIT_MASK_DESCR(_IRQ_IS_POLLED),
>         BIT_MASK_DESCR(_IRQ_DISABLE_UNLAZY),
>         BIT_MASK_DESCR(_IRQ_HIDDEN),
> +       BIT_MASK_DESCR(_IRQ_RAW),
>  };
>
>  static const struct irq_bit_descr irqdesc_istates[] = {
> diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
> index 1a7723604399..f5beee546a6f 100644
> --- a/kernel/irq/irqdesc.c
> +++ b/kernel/irq/irqdesc.c
> @@ -667,10 +667,9 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
>  {
>         struct pt_regs *old_regs = set_irq_regs(regs);
>         unsigned int irq = hwirq;
> +       struct irq_desc *desc;
>         int ret = 0;
>
> -       irq_enter();
> -
>  #ifdef CONFIG_IRQ_DOMAIN
>         if (lookup)
>                 irq = irq_find_mapping(domain, hwirq);
> @@ -680,14 +679,22 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
>          * Some hardware gives randomly wrong interrupts.  Rather
>          * than crashing, do something sensible.
>          */
> -       if (unlikely(!irq || irq >= nr_irqs)) {
> +       if (unlikely(!irq || irq >= nr_irqs || !(desc = irq_to_desc(irq)))) {

I see a checkpatch error here:

ERROR:ASSIGN_IN_IF: do not use assignment in if condition
#96: FILE: kernel/irq/irqdesc.c:682:

>                 ack_bad_irq(irq);
>                 ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       if (IS_ENABLED(CONFIG_ARCH_WANTS_IRQ_RAW) &&
> +           unlikely(irq_settings_is_raw(desc))) {
> +               generic_handle_irq_desc(desc);
>         } else {
> -               generic_handle_irq(irq);
> +               irq_enter();
> +               generic_handle_irq_desc(desc);
> +               irq_exit();
>         }
>
> -       irq_exit();
> +out:
>         set_irq_regs(old_regs);
>         return ret;
>  }
> diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
> index 51acdf43eadc..0033d459fdac 100644
> --- a/kernel/irq/settings.h
> +++ b/kernel/irq/settings.h
> @@ -18,6 +18,7 @@ enum {
>         _IRQ_IS_POLLED          = IRQ_IS_POLLED,
>         _IRQ_DISABLE_UNLAZY     = IRQ_DISABLE_UNLAZY,
>         _IRQ_HIDDEN             = IRQ_HIDDEN,
> +       _IRQ_RAW                = IRQ_RAW,
>         _IRQF_MODIFY_MASK       = IRQF_MODIFY_MASK,
>  };
>
> @@ -33,6 +34,7 @@ enum {
>  #define IRQ_IS_POLLED          GOT_YOU_MORON
>  #define IRQ_DISABLE_UNLAZY     GOT_YOU_MORON
>  #define IRQ_HIDDEN             GOT_YOU_MORON
> +#define IRQ_RAW                        GOT_YOU_MORON
>  #undef IRQF_MODIFY_MASK
>  #define IRQF_MODIFY_MASK       GOT_YOU_MORON
>
> @@ -180,3 +182,16 @@ static inline bool irq_settings_is_hidden(struct irq_desc *desc)
>  {
>         return desc->status_use_accessors & _IRQ_HIDDEN;
>  }
> +
> +static inline bool irq_settings_is_raw(struct irq_desc *desc)
> +{
> +       if (IS_ENABLED(CONFIG_ARCH_WANTS_IRQ_RAW))
> +               return desc->status_use_accessors & _IRQ_RAW;
> +
> +       /*
> +        * Using IRQ_RAW on architectures that don't expect it is
> +        * likely to be wrong.
> +        */
> +       WARN_ON_ONCE(1);
> +       return false;
> +}
> --
> 2.28.0
>
> --
> To unsubscribe from this group and stop receiving emails from it, send an email to kernel-team+unsubscribe at android.com.
>



More information about the linux-arm-kernel mailing list