中断二

依然从start_kernel开始,里面调用了四个涉及中断的函数,如下:

1、trap_init();

2、early_trap_init();

3、init_IRQ();

4、softirq_init();

下面来一个一个分析

1、trap_init()

arch/arm/kernel/trap.c

void __init trap_init(void)
{
        return;
}

貌似在arm的架构下没什么好说的

2、early_irq_init();

arch/arm/kernel/trap.c

void __init early_trap_init(void)
{
        unsigned long vectors = CONFIG_VECTORS_BASE;
        extern char __stubs_start[], __stubs_end[];
        extern char __vectors_start[], __vectors_end[];
        extern char __kuser_helper_start[], __kuser_helper_end[];
        int kuser_sz = __kuser_helper_end - __kuser_helper_start;

        /*
         * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
         * into the vector page, mapped at 0xffff0000, and ensure these
         * are visible to the instruction stream.
         */
        memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
        memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
        memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

        /*
         * Copy signal return handlers into the vector page, and
         * set sigreturn to be a pointer to these.

         */
        memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
               sizeof(sigreturn_codes));

        flush_icache_range(vectors, vectors + PAGE_SIZE);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}

 3、init_IRQ();

arch/arm/kernel/irq.c

void __init init_IRQ(void)
{
        int irq;

        for (irq = 0; irq < NR_IRQS; irq++)
                irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;

        init_arch_irq();     //分析到处,他妈的又差点把我给骗了此处在start_kernel中的setup_arch里将machine start里的init_irq传递到此的,此为函数指针
}

MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
        /* Maintainer: Freescale Semiconductor, Inc. */
        .phys_io = AIPS1_BASE_ADDR,
        .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .fixup = fixup_mxc_board,
        .map_io = mx5_map_io,
        .init_irq = mx5_init_irq,
        .init_machine = mxc_board_init,
        .timer = &mxc_timer,
MACHINE_END

arch/arm/mach-mx5/device.c

void __init mx5_init_irq(void)
{
        unsigned long tzic_addr;

        if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0)
                tzic_addr = MX51_TZIC_BASE_ADDR_T01;
        else if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0)
                tzic_addr = MX51_TZIC_BASE_ADDR;
        else /* mx53 and mx50 */
                tzic_addr = MX53_TZIC_BASE_ADDR;

        mxc_tzic_init_irq(tzic_addr);
}

arch/arm/plat-mxc/tzic.c

void __init mxc_tzic_init_irq(unsigned long base)
{
        int i;

        tzic_base = ioremap(base, SZ_4K);

        /* put the TZIC into the reset value with
         * all interrupts disabled
         */
        i = __raw_readl(TZIC_INTCNTL);

        __raw_writel(0x80010001, TZIC_INTCNTL);
        i = __raw_readl(TZIC_INTCNTL);
        __raw_writel(0x1f, TZIC_PRIOMASK);
        i = __raw_readl(TZIC_PRIOMASK);
        __raw_writel(0x02, TZIC_SYNCCTRL);
        i = __raw_readl(TZIC_SYNCCTRL);
        for (i = 0; i < 4; i++) {
                __raw_writel(0xFFFFFFFF, TZIC_INTSEC0 + i * 4);
        }
        /* disable all interrupts */
        for (i = 0; i < 4; i++) {

                __raw_writel(0xFFFFFFFF, TZIC_ENCLEAR0 + i * 4);
        }

        /* all IRQ no FIQ Warning :: No selection */

        for (i = 0; i < TZIC_NUM_IRQS; i++) {
                set_irq_chip(i, &mxc_tzic_chip);
                set_irq_handler(i, handle_level_irq);
                set_irq_flags(i, IRQF_VALID);
        }

        printk(KERN_INFO "MXC IRQ initialized\n");
}

kernel/irq/chip.c

int set_irq_chip(unsigned int irq, struct irq_chip *chip)
{
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;

        if (!desc) {
                WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
                return -EINVAL;
        }

        if (!chip)
  
              chip = &no_irq_chip;

        spin_lock_irqsave(&desc->lock, flags);
        irq_chip_set_defaults(chip);
        desc->chip = chip;
        spin_unlock_irqrestore(&desc->lock, flags);

        return 0;
}

kernel/irq/handle.c

struct irq_chip no_irq_chip = {
        .name           = "none",
        .startup        = noop_ret,
        .shutdown       = noop,
        .enable         = noop,
        .disable        = noop,
        .ack            = ack_bad,
        .end            = noop,
};
/include/linux/irq.h

static inline void
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
        __set_irq_handler(irq, handle, 0, NULL);
}

/kernel/irq/chip.c

void
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                  const char *name)
{
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;

        if (!desc) {
                printk(KERN_ERR
                       "Trying to install type control for IRQ%d\n", irq);
                return;
        }

        if (!handle)
                handle = handle_bad_irq;
        else if (desc->chip == &no_irq_chip) {
                printk(KERN_WARNING "Trying to install %sinterrupt handler "
                       "for IRQ%d\n", is_chained ? "chained " : "", irq);
                /*
                 * Some ARM implementations install a handler for really dumb
                 * interrupt hardware without setting an irq_chip. This worked
                 * with the ARM no_irq_chip but the check in setup_irq would

                 * prevent us to setup the interrupt at all. Switch it to
                 * dummy_irq_chip for easy transition.
                 */
                desc->chip = &dummy_irq_chip;
        }

        spin_lock_irqsave(&desc->lock, flags);

        /* Uninstall? */
        if (handle == handle_bad_irq) {
                if (desc->chip != &no_irq_chip)
                        mask_ack_irq(desc, irq);
                desc->status |= IRQ_DISABLED;
                desc->depth = 1;
        }
        desc->handle_irq = handle;
        desc->name = name;

        if (handle != handle_bad_irq && is_chained) {
                desc->status &= ~IRQ_DISABLED;
                desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;

                 desc->depth = 0;
                desc->chip->startup(irq);
        }
        spin_unlock_irqrestore(&desc->lock, flags);
}

至此,貌似中断以初始化完毕

 再看一下softirq_init();

kernel/softirq.c

void __init softirq_init(void)
{
        int cpu;

        for_each_possible_cpu(cpu) {
                int i;

                per_cpu(tasklet_vec, cpu).tail =
                        &per_cpu(tasklet_vec, cpu).head;
                per_cpu(tasklet_hi_vec, cpu).tail =
                        &per_cpu(tasklet_hi_vec, cpu).head;
                for (i = 0; i < NR_SOFTIRQS; i++)
                        INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
        }

        register_hotcpu_notifier(&remote_softirq_cpu_notifier);

        open_softirq(TASKLET_SOFTIRQ, tasklet_action);
        open_softirq(HI_SOFTIRQ, tasklet_hi_action);

}

/include/linux/interrupt.h

struct tasklet_struct
{
        struct tasklet_struct *next;
        unsigned long state;
        atomic_t count;
        void (*func)(unsigned long);
        unsigned long data;
};
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data};

#define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }

enum  //软中断类型
{
        HI_SOFTIRQ=0,
        TIMER_SOFTIRQ,
        NET_TX_SOFTIRQ,
        NET_RX_SOFTIRQ,
        BLOCK_SOFTIRQ,
        TASKLET_SOFTIRQ,
        SCHED_SOFTIRQ,
        HRTIMER_SOFTIRQ,
        RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

        NR_SOFTIRQS
};

static void tasklet_action(struct softirq_action *a)
{
        struct tasklet_struct *list;

        local_irq_disable();
        list = __get_cpu_var(tasklet_vec).head;////////kernel/softirq.c:static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
        __get_cpu_var(tasklet_vec).head = NULL;
        __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
        local_irq_enable();  

        while (list) {
                struct tasklet_struct *t = list;

                list = list->next;

                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
                                if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                                        BUG();
                                t->func(t->data);
                                tasklet_unlock(t);

                                continue;
                        }
                        tasklet_unlock(t);
                }

                local_irq_disable();
                t->next = NULL;
                *__get_cpu_var(tasklet_vec).tail = t;
                __get_cpu_var(tasklet_vec).tail = &(t->next);
                __raise_softirq_irqoff(TASKLET_SOFTIRQ);
                local_irq_enable();
        }
}

void tasklet_init(struct tasklet_struct *t,
                  void (*func)(unsigned long), unsigned long data)
{
        t->next = NULL;
        t->state = 0;
        atomic_set(&t->count, 0);
        t->func = func;
        t->data = data;
}

/include/linux/interrupt.h

static inline void tasklet_disable(struct tasklet_struct *t)
{
        tasklet_disable_nosync(t);
        tasklet_unlock_wait(t);
        smp_mb();
}

static inline void tasklet_enable(struct tasklet_struct *t)
{
        smp_mb__before_atomic_dec();
        atomic_dec(&t->count);
}

static inline void tasklet_schedule(struct tasklet_struct *t)
{
        if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
                __tasklet_schedule(t);  //此功能就是将本tasklet_struct 添加到那个链表上去,然后判断是否在中断中,如果不是,唤醒ksoftirqd,准备执行软中断,还有就是每次硬件中断执行完,可能调用软中断
}

 



 


 


 

 

 


 


 


 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(中断二)