Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1875434
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: 嵌入式

2013-03-22 15:05:31

//arch/powerpc/kernel/irq.c
void do_IRQ(struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);
    unsigned int irq;

    trace_irq_entry(regs);

    irq_enter();

    check_stack_overflow();

    irq = ppc_md.get_irq();//调用具体芯片的获取irq号,此时是p1010_rdb的mpic_get_irq

    if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
        handle_one_irq(irq);//调用
    else if (irq != NO_IRQ_IGNORE)
        __get_cpu_var(irq_stat).spurious_irqs++;

    irq_exit();
    set_irq_regs(old_regs);

#ifdef CONFIG_PPC_ISERIES
    if (firmware_has_feature(FW_FEATURE_ISERIES) &&
            get_lppaca()->int_dword.fields.decr_int) {
        get_lppaca()->int_dword.fields.decr_int = 0;
        /* Signal a fake decrementer interrupt */
        timer_interrupt(regs);
    }
#endif

    trace_irq_exit(regs);
}

define_machine(p1010_rdb) {
    .name            = "P1010 RDB",
    .probe            = p1010_rdb_probe,
    .setup_arch        = p1010_rdb_setup_arch,
    .init_IRQ        = p1010_rdb_pic_init,
#ifdef CONFIG_PCI
    .pcibios_fixup_bus    = fsl_pcibios_fixup_bus,
#endif
    .get_irq        = mpic_get_irq,
    .restart        = fsl_rstcr_restart,
    .calibrate_decr        = generic_calibrate_decr,
    .progress        = udbg_progress,
};


unsigned int mpic_get_irq(void)
{
    struct mpic *mpic = mpic_primary;

    BUG_ON(mpic == NULL);

    return mpic_get_one_irq(mpic);
}

unsigned int mpic_get_one_irq(struct mpic *mpic)
{
    return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK));
}

static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg)
{
    u32 src;

    src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK);//读取INT_ACK获取硬件中断号
#ifdef DEBUG_LOW
    DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src);
#endif
    if (unlikely(src == mpic->spurious_vec)) {
        if (mpic->flags & MPIC_SPV_EOI)
            mpic_eoi(mpic);
        return NO_IRQ;
    }
    if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
        if (printk_ratelimit())
            printk(KERN_WARNING "%s: Got protected source %d !\n",
                   mpic->name, (int)src);
        mpic_eoi(mpic);
        return NO_IRQ;
    }

    return irq_linear_revmap(mpic->irqhost, src);//把硬件中断后转换为逻辑中断号
}

unsigned int irq_linear_revmap(struct irq_host *host,
                   irq_hw_number_t hwirq)
{
    unsigned int *revmap;

    WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);

    /* Check revmap bounds */
    if (unlikely(hwirq >= host->revmap_data.linear.size))
        return irq_find_mapping(host, hwirq);

    /* Check if revmap was allocated */
    revmap = host->revmap_data.linear.revmap;
    if (unlikely(revmap == NULL))
        return irq_find_mapping(host, hwirq);

    /* Fill up revmap with slow path if no mapping found */
    if (unlikely(revmap[hwirq] == NO_IRQ))
        revmap[hwirq] = irq_find_mapping(host, hwirq);

    return revmap[hwirq];//把硬件中断后转换为逻辑中断号,实际上上相等
}

static inline void handle_one_irq(unsigned int irq)
{
    struct thread_info *curtp, *irqtp;
    unsigned long saved_sp_limit;
    struct irq_desc *desc;

    /* Switch to the irq stack to handle this */
    curtp = current_thread_info();
    irqtp = hardirq_ctx[smp_processor_id()];

    if (curtp == irqtp) {
        /* We're already on the irq stack, just handle it */
        generic_handle_irq(irq);
        return;
    }

    desc = irq_to_desc(irq);
    saved_sp_limit = current->thread.ksp_limit;

    irqtp->task = curtp->task;
    irqtp->flags = 0;

    /* Copy the softirq bits in preempt_count so that the
     * softirq checks work in the hardirq context. */
    irqtp->preempt_count = (irqtp->preempt_count & ~SOFTIRQ_MASK) |
                   (curtp->preempt_count & SOFTIRQ_MASK);

    current->thread.ksp_limit = (unsigned long)irqtp +
        _ALIGN_UP(sizeof(struct thread_info), 16);

    call_handle_irq(irq, desc, irqtp, desc->handle_irq);//此函数汇编实现,其实在气内部调用desc->handle_irq,既handle_fasteoi_irq
    current->thread.ksp_limit = saved_sp_limit;
    irqtp->task = NULL;

    /* Set any flag that may have been set on the
     * alternate stack
     */
    if (irqtp->flags)
        set_bits(irqtp->flags, &curtp->flags);
}

//kernel/irq/chip.c
void
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
{
    struct irqaction *action;
    irqreturn_t action_ret;

    raw_spin_lock(&desc->lock);

    if (unlikely(desc->status & IRQ_INPROGRESS))
        goto out;

    desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
    kstat_incr_irqs_this_cpu(irq, desc);

    /*
     * If its disabled or no action available
     * then mask it and get out of here:
     */
    action = desc->action;
    if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
        desc->status |= IRQ_PENDING;
        mask_irq(desc, irq);
        goto out;
    }

    desc->status |= IRQ_INPROGRESS;
    desc->status &= ~IRQ_PENDING;
    raw_spin_unlock(&desc->lock);

    action_ret = handle_IRQ_event(irq, action);
    if (!noirqdebug)
        note_interrupt(irq, desc, action_ret);

    raw_spin_lock(&desc->lock);
    desc->status &= ~IRQ_INPROGRESS;
out:
    desc->chip->eoi(irq);//调用具体芯片函数,其实就是mpic_end_irq

    raw_spin_unlock(&desc->lock);
}
//kernel/irq/handle.c
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
    irqreturn_t ret, retval = IRQ_NONE;
    unsigned int status = 0;

    do {
        trace_irq_handler_entry(irq, action);
        ret = action->handler(irq, action->dev_id);//调用注册的处理函数
        trace_irq_handler_exit(irq, action, ret);

        switch (ret) {
        case IRQ_WAKE_THREAD:
            /*
             * Set result to handled so the spurious check
             * does not trigger.
             */
            ret = IRQ_HANDLED;

            /*
             * Catch drivers which return WAKE_THREAD but
             * did not set up a thread function
             */
            if (unlikely(!action->thread_fn)) {
                warn_no_thread(irq, action);
                break;
            }

            /*
             * Wake up the handler thread for this
             * action. In case the thread crashed and was
             * killed we just pretend that we handled the
             * interrupt. The hardirq handler above has
             * disabled the device interrupt, so no irq
             * storm is lurking.
             */
            if (likely(!test_bit(IRQTF_DIED,
                         &action->thread_flags))) {
                set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
                wake_up_process(action->thread);
            }

            /* Fall through to add to randomness */
        case IRQ_HANDLED:
            status |= action->flags;
            break;

        default:
            break;
        }

        retval |= ret;
        action = action->next;
    } while (action);

    if (status & IRQF_SAMPLE_RANDOM)
        add_interrupt_randomness(irq);
    local_irq_disable();

    return retval;
}

void mpic_end_irq(unsigned int irq)
{
    struct mpic *mpic = mpic_from_irq(irq);

#ifdef DEBUG_IRQ
    DBG("%s: end_irq: %d\n", mpic->name, irq);
#endif
    /* We always EOI on end_irq() even for edge interrupts since that
     * should only lower the priority, the MPIC should have properly
     * latched another edge interrupt coming in anyway
     */

    mpic_eoi(mpic);
}

static inline void mpic_eoi(struct mpic *mpic)
{
    mpic_cpu_write(MPIC_INFO(CPU_EOI), 0);//发中断结束信号
    (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI));
}


阅读(3120) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~