//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));
}
阅读(3168) | 评论(0) | 转发(0) |