lkml.org 
[lkml]   [2020]   [Nov]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 2/6] genirq: Allow an interrupt to be marked as 'raw'
    Date
    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@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)))) {
    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
    \
     
     \ /
      Last update: 2020-11-24 15:17    [W:4.938 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site