硬中断--asm_do_IRQ

liaocj 2024-12-03 09:02:56
Categories: Tags:
/*
 * handle_IRQ handles all hardware IRQ's.  Decoded IRQs should
 * not come via this function.  Instead, they should provide their
 * own 'handler'.  Used by platform code implementing C-based 1st
 * level decoding.
 */
void handle_IRQ(unsigned int irq, struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);
    struct irq_desc *desc;

    irq_enter(); //irq_enter函数中的preempt_count_add相对应HARDIRQ_OFFSET,用来标识进入硬中断

    /*
     * Some hardware gives randomly wrong interrupts.  Rather
     * than crashing, do something sensible.
     */
    if (unlikely(!irq || irq >= nr_irqs))
        desc = NULL;
    else
        desc = irq_to_desc(irq);

    if (likely(desc))
        handle_irq_desc(desc);
    else
        ack_bad_irq(irq);

    irq_exit(); //irq_exit函数首先将preempt_count_sub计数器减去HARDIRQ_OFFSET,用来标识退出硬中断
    set_irq_regs(old_regs);
}

/*
 * asm_do_IRQ is the interface to be used from assembly code.
 */
asmlinkage void __exception_irq_entry
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
    handle_IRQ(irq, regs);
}
/**
 * irq_enter - Enter an interrupt context including RCU update
 * softirq.c
 */
void irq_enter(void)
{
    rcu_irq_enter();
    irq_enter_rcu();
}

/**
 * irq_enter_rcu - Enter an interrupt context with RCU watching
 */
void irq_enter_rcu(void)
{
    __irq_enter_raw();

    if (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))
        tick_irq_enter();

    account_hardirq_enter(current);
}

/*
 * Like __irq_enter() without time accounting for fast
 * interrupts, e.g. reschedule IPI where time accounting
 * is more expensive than the actual interrupt.
 */
#define __irq_enter_raw()				\
    do {						\
        preempt_count_add(HARDIRQ_OFFSET);	\
        lockdep_hardirq_enter();		\
    } while (0)