Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1595741
  • 博文数量: 204
  • 博客积分: 2215
  • 博客等级: 大尉
  • 技术积分: 4427
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-06 08:03
个人简介

气质,源于心灵的自信!

文章存档

2018年(1)

2017年(1)

2016年(1)

2015年(18)

2014年(20)

2013年(30)

2012年(119)

2011年(14)

分类: Android平台

2013-03-15 15:58:55

//分析的内容包括中断和软中断的处理,版本基于android2.3
asmlinkage void __init start_kernel(void)
{
    setup_arch(&command_line);//跟踪调用链(1)
    init_IRQ();//跟踪调用链(2)
    softirq_init();//跟踪调用链(3)
}

//跟踪调用链(1)
void __init setup_arch(char **cmdline_p)
{
    ............
    init_arch_irq = mdesc->init_irq;
    early_trap_init();//跟踪调用链(1)
}

//跟踪调用链(1),初始化整个中断处理向量,把中断向量拷贝到0xffff0000地方
void __init early_trap_init(void)
{
    unsigned long vectors = CONFIG_VECTORS_BASE;//#define CONFIG_VECTORS_BASE 0xffff0000
    extern char __stubs_start[], __stubs_end[];
    extern char __vectors_start[], __vectors_end[];
    /*
     * 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);//更复杂的代码
}

//异常向量代码和跳转代码
    .globl    __stubs_start
__stubs_start:
/*
 * Interrupt dispatcher
 */
    vector_stub    irq, IRQ_MODE, 4

    .long    __irq_usr            @  0  (USR_26 / USR_32)
    .long    __irq_invalid            @  1  (FIQ_26 / FIQ_32)
    .long    __irq_invalid            @  2  (IRQ_26 / IRQ_32)
    .long    __irq_svc            @  3  (SVC_26 / SVC_32)
    .long    __irq_invalid            @  4
    .long    __irq_invalid            @  5
    .long    __irq_invalid            @  6
    .long    __irq_invalid            @  7
    .long    __irq_invalid            @  8
    .long    __irq_invalid            @  9
    .long    __irq_invalid            @  a
    .long    __irq_invalid            @  b
    .long    __irq_invalid            @  c
    .long    __irq_invalid            @  d
    .long    __irq_invalid            @  e
    .long    __irq_invalid            @  f

    vector_stub    dabt, ABT_MODE, 8

    .long    __dabt_usr            @  0  (USR_26 / USR_32)
    .long    __dabt_invalid            @  1  (FIQ_26 / FIQ_32)
    .long    __dabt_invalid            @  2  (IRQ_26 / IRQ_32)
    .long    __dabt_svc            @  3  (SVC_26 / SVC_32)
    .long    __dabt_invalid            @  4
    .long    __dabt_invalid            @  5
    .long    __dabt_invalid            @  6
    .long    __dabt_invalid            @  7
    .long    __dabt_invalid            @  8
    .long    __dabt_invalid            @  9
    .long    __dabt_invalid            @  a
    .long    __dabt_invalid            @  b
    .long    __dabt_invalid            @  c
    .long    __dabt_invalid            @  d
    .long    __dabt_invalid            @  e
    .long    __dabt_invalid            @  f

    vector_stub    pabt, ABT_MODE, 4

    .long    __pabt_usr            @  0 (USR_26 / USR_32)
    .long    __pabt_invalid            @  1 (FIQ_26 / FIQ_32)
    .long    __pabt_invalid            @  2 (IRQ_26 / IRQ_32)
    .long    __pabt_svc            @  3 (SVC_26 / SVC_32)
    .long    __pabt_invalid            @  4
    .long    __pabt_invalid            @  5
    .long    __pabt_invalid            @  6
    .long    __pabt_invalid            @  7
    .long    __pabt_invalid            @  8
    .long    __pabt_invalid            @  9
    .long    __pabt_invalid            @  a
    .long    __pabt_invalid            @  b
    .long    __pabt_invalid            @  c
    .long    __pabt_invalid            @  d
    .long    __pabt_invalid            @  e
    .long    __pabt_invalid            @  f

    vector_stub    und, UND_MODE

    .long    __und_usr            @  0 (USR_26 / USR_32)
    .long    __und_invalid            @  1 (FIQ_26 / FIQ_32)
    .long    __und_invalid            @  2 (IRQ_26 / IRQ_32)
    .long    __und_svc            @  3 (SVC_26 / SVC_32)
    .long    __und_invalid            @  4
    .long    __und_invalid            @  5
    .long    __und_invalid            @  6
    .long    __und_invalid            @  7
    .long    __und_invalid            @  8
    .long    __und_invalid            @  9
    .long    __und_invalid            @  a
    .long    __und_invalid            @  b
    .long    __und_invalid            @  c
    .long    __und_invalid            @  d
    .long    __und_invalid            @  e
    .long    __und_invalid            @  f

    .align    5

vector_fiq:
    disable_fiq
    subs    pc, lr, #4

vector_addrexcptn:
    b    vector_addrexcptn

    .align    5

.LCvswi:
    .word    vector_swi

    .globl    __stubs_end
__stubs_end:
/*********************************************************************************/

.equ    stubs_offset, __vectors_start + 0x200 - __stubs_start

/*********************************************************************************/
__vectors_start:
 ARM(    swi    SYS_ERROR0    )
 THUMB(    svc    #0        )
 THUMB(    nop            )
    W(b)    vector_und + stubs_offset
    W(ldr)    pc, .LCvswi + stubs_offset
    W(b)    vector_pabt + stubs_offset
    W(b)    vector_dabt + stubs_offset
    W(b)    vector_addrexcptn + stubs_offset
    W(b)    vector_irq + stubs_offset
    W(b)    vector_fiq + stubs_offset

    .globl    __vectors_end
__vectors_end:
/*********************************************************************************/


////跟踪调用链(2),全局的irq数组
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();////跟踪调用链(2),执行架构的machine里的irq结构体
}

////跟踪调用链(2),板级定义的结构体
MACHINE_START(MSM8X60, "QCT MSM8X60")
#ifdef CONFIG_MSM_DEBUG_UART
    .phys_io = MSM_DEBUG_UART_PHYS,
    .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
#endif
    .map_io = msm8x60_map_io,
    .init_irq = msm8x60_init_irq,
    .timer = &msm_timer,
MACHINE_END

////跟踪调用链(2),对应8x60项目为.init_irq = msm8x60_init_irq,
void __init msm8x60_init_irq(void)
{
    for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {//为每一个中断安装入口函数
        if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
            set_irq_handler(i, handle_percpu_irq);//初始化该平台的irq处理的handler函数
    }
}

////跟踪调用链(2)
static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
    __set_irq_handler(irq, handle, 0, NULL);
}

////跟踪调用链(2),安装描述符的总处理函数
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);
    desc->handle_irq = handle;
}


//中断注册流程,以msm_otg里面的一个注册函数为例
ret = request_irq(dev->irq, msm_otg_irq, IRQF_SHARED,"msm_otg", dev);

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
{
    return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags,
             const char *devname, void *dev_id)
{
    struct irqaction *action;
    struct irq_desc *desc;
    int retval;

    /*
     * Sanity-check: shared interrupts must pass in a real dev-ID,
     * otherwise we'll have trouble later trying to figure out
     * which interrupt is which (messes up the interrupt freeing
     * logic etc).
     */
    if ((irqflags & IRQF_SHARED) && !dev_id)
        return -EINVAL;

    desc = irq_to_desc(irq);
    if (!desc)
        return -EINVAL;

    action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
    if (!action)
        return -ENOMEM;

    action->handler = handler;//中断处理函数
    action->thread_fn = thread_fn;
    action->flags = irqflags;//标志位,是否是共享中断?
    action->name = devname;
    action->dev_id = dev_id;//共享中断时用的区分标志

    chip_bus_lock(irq, desc);
    retval = __setup_irq(irq, desc, action);//把初始化好的action安装到desc的action链表中
    chip_bus_sync_unlock(irq, desc);

    if (retval)
        kfree(action);
    return retval;
}

static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
    struct irqaction *old, **old_ptr;
    old_ptr = &desc->action;
    old = *old_ptr;
    if (old) {//共享中断
        /*
         * Can't share interrupts unless both agree to and are
         * the same type (level, edge, polarity). So both flag
         * fields must have IRQF_SHARED set and the bits which
         * set the trigger type must match.
         */
        if (!((old->flags & new->flags) & IRQF_SHARED) ||
            ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
            old_name = old->name;
            goto mismatch;
        }

        /* add new interrupt at end of irq queue */
        do {
            old_ptr = &old->next;
            old = *old_ptr;
        } while (old);
        shared = 1;
    }

    if (!shared) {
    }
        
    /*把新节点加入链表*/
    new->irq = irq;
    *old_ptr = new;



//执行中断,中断处理流程,总入口,由汇编进入该函数
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);

    perf_mon_interrupt_in();
    irq_enter();

    /*
     * Some hardware gives randomly wrong interrupts.  Rather
     * than crashing, do something sensible.
     */
    if (unlikely(irq >= NR_IRQS)) {
        if (printk_ratelimit())
            printk(KERN_WARNING "Bad IRQ%u\n", irq);
        ack_bad_irq(irq);
    } else {
        generic_handle_irq(irq);//通用的处理函数,在这里面处理中断
    }

    /* AT91 specific workaround */
    irq_finish(irq);

    irq_exit();//在该函数中调用软中断处理函数
    set_irq_regs(old_regs);
    perf_mon_interrupt_out();
}

//跟踪上面的调用链
static inline void generic_handle_irq(unsigned int irq)
{
    generic_handle_irq_desc(irq, irq_to_desc(irq));
}

//跟踪上面的调用链
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
    desc->handle_irq(irq, desc);//handle_percpu_irq,调用在板级结构体初始化时的函数
#else
    if (likely(desc->handle_irq))
        desc->handle_irq(irq, desc);
    else
        __do_IRQ(irq);
#endif
}

//调用注册的回调函数
void handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
{
    action_ret = handle_IRQ_event(irq, desc->action);//处理IRQ
}

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
    irqreturn_t ret, retval = IRQ_NONE;
    unsigned int status = 0;

    do {//循环执行action链表里的handler函数,参数为irq号和注册时的最后一参数
        trace_irq_handler_entry(irq, action);
        ret = action->handler(irq, action->dev_id);
        trace_irq_handler_exit(irq, action, ret);

        switch (ret) {
        ...........
        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 irq_exit(void)
{
    if (!in_interrupt() && local_softirq_pending())//不在中断中,并且有软中断挂起
        invoke_softirq();//调用软中断处理
}

# define invoke_softirq()    __do_softirq()

asmlinkage void __do_softirq(void)
{
    struct softirq_action *h;
    __u32 pending;
    int max_restart = MAX_SOFTIRQ_RESTART;//#define MAX_SOFTIRQ_RESTART 10
    int cpu;

    pending = local_softirq_pending();//取出软中断挂起位标志变量
    account_system_vtime(current);

    __local_bh_disable((unsigned long)__builtin_return_address(0));
    lockdep_softirq_enter();

    cpu = smp_processor_id();
restart:
    /* Reset the pending bitmask before enabling irqs */
    set_softirq_pending(0);//清除挂起标志位

    local_irq_enable();//打开中断,这也是设计软中断的初衷

    h = softirq_vec;//软中断处理数组

    do {
        if (pending & 1) {//取出每一个pending位
            int prev_count = preempt_count();
            kstat_incr_softirqs_this_cpu(h - softirq_vec);

            trace_softirq_entry(h, softirq_vec);
            h->action(h);//执行该软中断的处理函数
            trace_softirq_exit(h, softirq_vec);
            rcu_bh_qs(cpu);
        }
        h++;
        pending >>= 1;
    } while (pending);

    local_irq_disable();

    pending = local_softirq_pending();//再次判断是否有软中断pending
    if (pending && --max_restart)//如果一直有,且达到最大次数,如果还有pending的话?
        goto restart;

    if (pending)//唤醒软中断处理进程帮忙处理
        wakeup_softirqd();

    lockdep_softirq_exit();

    account_system_vtime(current);
    _local_bh_enable();
}

//执行tasklet的软中断处理函数,在系统初始化时已经安装
static void tasklet_action(struct softirq_action *a)
{
    struct tasklet_struct *list;

    /*取出tasklet链表保存到局部变量,并清空tasklet_vec全局链表*/
    local_irq_disable();
    list = __get_cpu_var(tasklet_vec).head;
    __get_cpu_var(tasklet_vec).head = NULL;
    __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
    local_irq_enable();

    while (list) {//遍历该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))//清除TASKLET_STATE_SCHED
                    BUG();
                t->func(t->data);//执行tasklet处理函数
                tasklet_unlock(t);
                continue;
            }
            tasklet_unlock(t);
        }

        /*如果不满足条件的话,继续加入到全局tasklet_vec链表*/
        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();
    }
}

//驱动软中断的注册分析
enum
{
    TASKLET_STATE_SCHED,    /* Tasklet is scheduled for execution */
    TASKLET_STATE_RUN    /* Tasklet is running (SMP only) */
};

static inline void tasklet_schedule(struct tasklet_struct *t)
{
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))//如果为TASKLET_STATE_SCHED的话不允许再提交
        __tasklet_schedule(t);
}

//加入tasklet_vec链表,并置位相应的pending位
void __tasklet_schedule(struct tasklet_struct *t)
{
    unsigned long flags;

    local_irq_save(flags);
    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_restore(flags);
}


//管理软中断的结构体
/***************************************************************************************/
struct softirq_action
{
    void    (*action)(struct softirq_action *);
};

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

    NR_SOFTIRQS
};

//管理软中断的全局变量
static struct softirq_action softirq_vec[NR_SOFTIRQS]

//软中断进行初始化
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);//tasklet的执行函数
    open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

//安装对应软中断的处理函数
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
    softirq_vec[nr].action = action;
}
阅读(1774) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~