#define DECREMENTER_EXCEPTION \
START_EXCEPTION(Decrementer) \
NORMAL_EXCEPTION_PROLOG; \
lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \
mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \
addi r3,r1,STACK_FRAME_OVERHEAD; \
EXC_XFER_LITE(0x0900, timer_interrupt)
void timer_interrupt(struct pt_regs * regs)
=>int cpu = smp_processor_id();
=>if (atomic_read(&ppc_n_lost_interrupts) != 0)//如果还有未处理的外部中断处理函数,则处理
do_IRQ(regs);
=>old_regs = set_irq_regs(regs);//保存寄存器现场,注意old_regs是指针,指向现场全局寄存器的指针
=>struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs);//保存在__irq_regs全局变量里面,每个核一个
old_regs = *pp_regs;
*pp_regs = new_regs;
return old_regs
=>irq_enter();//中断计数加一,进入中断上下文
=>while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu))) >= tb_ticks_per_jiffy)
per_cpu(last_jiffy, cpu) += tb_ticks_per_jiffy;
account_process_time(regs);//#define account_process_time(regs) update_process_times(user_mode(regs))
=>scheduler_tick();//选择合适的进程,用于时钟中断返回继续调度
=>curr->sched_class->task_tick(rq, curr);//.task_tick = task_tick_fair
=>struct sched_entity *se = &curr->se;
=>for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
entity_tick(cfs_rq, se);
=>update_curr(cfs_rq);
=>if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT))
check_preempt_tick(cfs_rq, curr);
=>ideal_runtime = sched_slice(cfs_rq, curr);//计算理想调度时间
=>delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
=>if (delta_exec > ideal_runtime) {//实际时间大于理想时间,则调度
resched_task(rq_of(cfs_rq)->curr);
/*
* The current task ran long enough, ensure it doesn't get
* re-elected due to buddy favours.
*/
clear_buddies(cfs_rq, curr);
return;
}
}
if (cpu != boot_cpuid)
continue;
tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
tb_last_jiffy = tb_next_jiffy;
do_timer(1);
timer_recalc_offset(tb_last_jiffy);
timer_check_rtc();
}
=>next_dec = tb_ticks_per_jiffy - ticks;
=>set_dec(next_dec);//设置DEC寄存器,用于触发下一次的时钟中断
=>irq_exit();
=>set_irq_regs(old_regs);
void timer_interrupt(struct pt_regs * regs)
=>struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
=>set_dec(DECREMENTER_MAX);//重新设置最大值
=>mtspr(SPRN_DEC, val);
=>__get_cpu_var(irq_stat).timer_irqs++;
=>old_regs = set_irq_regs(regs);//保存寄存器现场,注意old_regs是指针,指向现场全局寄存器的指针
=>struct pt_regs *old_regs;
old_regs = __this_cpu_read(__irq_regs);//保存在__irq_regs全局变量里面,每个核一个
__this_cpu_write(__irq_regs, new_regs);
return old_regs;
=>irq_enter();//中断计数加一,进入中断上下文
desc->handle_irq = handle_level_irq;//Mpc8xx_pic.c (c:\linux\linux-2.6.23\arch\powerpc\sysdev):
=>desc->chip->ack(irq);/* Start handling the irq */
=>desc->status |= IRQ_INPROGRESS;/* Mark the IRQ currently in progress.*/
=>do//可能好几个中断都上报
desc->status &= ~IRQ_PENDING;
action_ret = handle_IRQ_event(irq, action);
=>do//依次查看是否共享中断
ret = action->handler(irq, action->dev_id);
retval |= ret;
action = action->next;
=>while (action);
=>while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);