/* * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and * 0x9X0 for the local motherboard interrupts.. * * 0x660 - NMI * * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer) * 0x810 - IRQ1 line printer (duh..) * 0x860 - IRQ6 floppy disk * 0x8E0 - IRQ14 SCSI controller * * 0x900 - COM1 * 0x920 - COM2 * 0x980 - keyboard * 0x990 - mouse * * PCI-based systems are more sane: they don't have the local * interrupts at all, and have only normal PCI interrupts from * devices. Happily it's easy enough to do a sane mapping from the * Jensen.. Note that this means that we may have to do a hardware * "ack" to a different interrupt than we report to the rest of the * world. */ static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq, ack; unsigned long flags; save_flags(flags); cli(); ack = irq = (vector - 0x800) >> 4; #ifdef CONFIG_ALPHA_JENSEN switch (vector) { case 0x660: handle_nmi(regs); return; /* local device interrupts: */ case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */ case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */ case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */ case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */ default: if (vector > 0x900) { printk("Unknown local interrupt %lx\n", vector); } } /* irq1 is supposed to be the keyboard, silly Jensen (is this really needed??) */ if (irq == 1) irq = 7; #endif /* CONFIG_ALPHA_JENSEN */ device_interrupt(irq, ack, regs); restore_flags(flags) ; }
asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, struct pt_regs *regs) { struct pt_regs *old_regs; switch (type) { case 0: #ifdef CONFIG_SMP handle_ipi(regs); return; #else irq_err_count++; printk(KERN_CRIT "Interprocessor interrupt? " "You must be kidding!\n"); #endif break; case 1: old_regs = set_irq_regs(regs); #ifdef CONFIG_SMP { long cpu; local_irq_disable(); smp_percpu_timer_interrupt(regs); cpu = smp_processor_id(); if (cpu != boot_cpuid) { kstat_incr_irqs_this_cpu(RTC_IRQ, irq_to_desc(RTC_IRQ)); } else { handle_irq(RTC_IRQ); } } #else handle_irq(RTC_IRQ); #endif set_irq_regs(old_regs); return; case 2: old_regs = set_irq_regs(regs); alpha_mv.machine_check(vector, la_ptr); set_irq_regs(old_regs); return; case 3: old_regs = set_irq_regs(regs); alpha_mv.device_interrupt(vector); set_irq_regs(old_regs); return; case 4: perf_irq(la_ptr, regs); return; default: printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n", type, vector); } printk(KERN_CRIT "PC = %016lx PS=%04lx\n", regs->pc, regs->ps); }
static inline void dispatch_multiple_rtc_irq() { rtc_reg_map *regs = RTC->regs; uint32 dsr = regs->CRH & regs->CRL; void (**hs)(void) = RTC->handlers; uint32 handled = 0; handle_irq(dsr, RTC_CRL_SECF, hs, RTC_SECONDS_INTERRUPT, handled); handle_irq(dsr, RTC_CRL_ALRF, hs, RTC_ALARM_GLOBAL_INTERRUPT, handled); handle_irq(dsr, RTC_CRL_OWF, hs, RTC_OVERFLOW_INTERRUPT, handled); regs->CRL &= ~handled; }
static inline void dispatch_adv_cc(timer_dev *dev) { uint32_t dsr = dev->regs->DIER & dev->regs->SR; void (**hs)(void) = dev->handlers; uint32_t handled = 0; handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); dev->regs->SR &= ~handled; }
static inline void dispatch_adv_trg_com(timer_dev *dev) { uint32_t dsr = dev->regs->DIER & dev->regs->SR; void (**hs)(void) = dev->handlers; uint32_t handled = 0; /* Logical OR of SR interrupt flags we end up * handling. We clear these. User handlers * must clear overcapture flags, to avoid * wasting time in output mode. */ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled); dev->regs->SR &= ~handled; }
static void mikasa_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; /* Read the interrupt summary registers */ pld = (((~inw(0x534) & 0x0000ffffUL) << 16) | (((unsigned long) inb(0xa0)) << 8) | inb(0x20)); /* * Now for every possible bit set, work through them and call * the appropriate interrupt handler. */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i < 16) { isa_device_interrupt(vector); } else { handle_irq(i); } } }
/* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; unsigned irq; irq_enter(); exit_idle(); irq = __this_cpu_read(vector_irq[vector]); if (!handle_irq(irq, regs)) { ack_APIC_irq(); if (irq != VECTOR_RETRIGGERED) { pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n", __func__, smp_processor_id(), vector, irq); } else { __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED); } } irq_exit(); set_irq_regs(old_regs); return 1; }
/* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; unsigned irq; irq_enter(); exit_idle(); irq = __this_cpu_read(vector_irq[vector]); if (!handle_irq(irq, regs)) { ack_APIC_irq(); if (printk_ratelimit()) pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n", __func__, smp_processor_id(), vector, irq); } irq_exit(); set_irq_regs(old_regs); return 1; }
static void miata_srm_device_interrupt(unsigned long vector) { int irq; irq = (vector - 0x800) >> 4; /* * I really hate to do this, but the MIATA SRM console ignores the * low 8 bits in the interrupt summary register, and reports the * vector 0x80 *lower* than I expected from the bit numbering in * the documentation. * This was done because the low 8 summary bits really aren't used * for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't * used for this purpose, as PIC interrupts are delivered as the * vectors 0x800-0x8f0). * But I really don't want to change the fixup code for allocation * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which * look nice and clean now. * So, here's this grotty hack... :-( */ if (irq >= 16) irq = irq + 8; handle_irq(irq); }
static void jensen_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq; switch (vector) { case 0x660: printk("Whee.. NMI received. Probable hardware error\n"); printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); return; /* local device interrupts: */ case 0x900: irq = 4; break; /* com1 -> irq 4 */ case 0x920: irq = 3; break; /* com2 -> irq 3 */ case 0x980: irq = 1; break; /* kbd -> irq 1 */ case 0x990: irq = 9; break; /* mouse -> irq 9 */ default: if (vector > 0x900) { printk("Unknown local interrupt %lx\n", vector); return; } irq = (vector - 0x800) >> 4; if (irq == 1) irq = 7; break; } handle_irq(irq, regs); }
/* Check if the pending bit for an IRQ line is set; if so, call the handler * function. */ static void check_irq_pending(uchar irq_num) { bool handle = FALSE; /* Check the appropriate hardware register, depending on the IRQ number. */ if (irq_num >= 64) { if (regs->IRQ_basic_pending & (1 << (irq_num - 64))) { handle = TRUE; } } else if (irq_num >= 32) { if (regs->IRQ_pending_2 & (1 << (irq_num - 32))) { handle = TRUE; } } else { if (regs->IRQ_pending_1 & (1 << irq_num)) { handle = TRUE; } } if (handle) { handle_irq(irq_num); /* The pending bit should have been cleared in a device-specific way by * the handler function. As far as we can tell, it cannot be cleared * directly through the interrupt controller. */ } }
static void rx164_device_interrupt(unsigned long vector) { unsigned long pld; volatile unsigned int *dirr; long i; /* Read the interrupt summary register. On Polaris, this is the DIRR register in PCI config space (offset 0x84). */ dirr = (void *)(POLARIS_DENSE_CONFIG_BASE + 0x84); pld = *dirr; /* * Now for every possible bit set, work through them and call * the appropriate interrupt handler. */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 20) { isa_no_iack_sc_device_interrupt(vector); } else { handle_irq(16+i); } } }
static void dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) { #if 1 printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n"); #else unsigned long pld; unsigned int i; /* Read the interrupt summary register of TSUNAMI */ pld = TSUNAMI_cchip->dir0.csr; /* * Now for every possible bit set, work through them and call * the appropriate interrupt handler. */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 55) isa_device_interrupt(vector, regs); else handle_irq(16 + i, 16 + i, regs); #if 0 TSUNAMI_cchip->dir0.csr = 1UL << i; mb(); tmp = TSUNAMI_cchip->dir0.csr; #endif } #endif }
static void miata_srm_device_interrupt(unsigned long vector) { int irq; irq = (vector - 0x800) >> 4; /* */ if (irq >= 16) irq = irq + 8; handle_irq(irq); }
static void rawhide_srm_device_interrupt(unsigned long vector) { int irq; irq = (vector - 0x800) >> 4; /* * The RAWHIDE SRM console reports PCI interrupts with a vector * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have * it line up with the actual bit numbers from the REQ registers, * which is how we manage the interrupts/mask. Sigh... * * Also, PCI #1 interrupts are offset some more... :-( */ if (irq == 52) { /* SCSI on PCI1 is special. */ irq = 72; } /* Adjust by which hose it is from. */ irq -= ((irq + 16) >> 2) & 0x38; handle_irq(irq); }
/* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { // 取得原来的寄存器 struct pt_regs *old_regs = set_irq_regs(regs); // 取得中断向量号 /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; unsigned irq; // 退出idle进程 exit_idle(); // 进入中断。使表示中断处理程序嵌套数量的计数器递增。 // 计数器是指当前进程thread_info结构的preempt_count字段 irq_enter(); // 中断线号与设备的中断号之间对应关系,有系统分配 // 分配表是一个per-cpu变量的vector_irq irq = __get_cpu_var(vector_irq)[vector]; if (!handle_irq(irq, regs)) { ack_APIC_irq(); if (printk_ratelimit()) pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n", __func__, smp_processor_id(), vector, irq); } // 结束中断 irq_exit(); set_irq_regs(old_regs); return 1; }
static void titan_srm_device_interrupt(unsigned long vector) { int irq; irq = (vector - 0x800) >> 4; handle_irq(irq); }
void irq_entry(regs *r) { ASSERT(!are_interrupts_enabled()); DEBUG_VALIDATE_STACK_PTR(); ASSERT(get_curr_task() != NULL); DEBUG_check_not_same_interrupt_nested(regs_intnum(r)); handle_irq(r); }
static void wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq; irq = (vector - 0x800) >> 4; /* * bits 10-8: source QBB ID * bits 7-6: PCA * bits 5-0: irq in PCA */ handle_irq(irq, regs); return; }
asmregparm unsigned int do_IRQ(struct pt_regs *regs) { /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; unsigned irq; irq_enter(); irq = vector_irq[vector]; if (!handle_irq(irq, regs)) { ack_APIC_irq(); } irq_exit(); /* Give scheduler a chance to run */ if (irq == 0) kt_sched_tick(); return 1; }
/* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); struct irq_desc * desc; /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; /* * NB: Unlike exception entries, IRQ entries do not reliably * handle context tracking in the low-level entry code. This is * because syscall entries execute briefly with IRQs on before * updating context tracking state, so we can take an IRQ from * kernel mode with CONTEXT_USER. The low-level entry code only * updates the context if we came from user mode, so we won't * switch to CONTEXT_KERNEL. We'll fix that once the syscall * code is cleaned up enough that we can cleanly defer enabling * IRQs. */ entering_irq(); /* entering_irq() tells RCU that we're not quiescent. Check it. */ RCU_LOCKDEP_WARN(!rcu_is_watching(), "IRQ failed to wake up RCU"); desc = __this_cpu_read(vector_irq[vector]); if (!handle_irq(desc, regs)) { ack_APIC_irq(); if (desc != VECTOR_RETRIGGERED) { pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n", __func__, smp_processor_id(), vector); } else { __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); } } exiting_irq(); set_irq_regs(old_regs); return 1; }
void irq_handler (unsigned int port_number) { system_call_thread_name_set ("IRQ handler"); if (system_call_irq_register (serial_port[port_number].irq, "Serial (UART)") != STORM_RETURN_SUCCESS) { log_print_formatted (&log_structure, LOG_URGENCY_EMERGENCY, "Could not allocate IRQ %d.", serial_port[port_number].irq); return; } while (TRUE) { system_call_irq_wait (serial_port[port_number].irq); handle_irq (port_number); system_call_irq_acknowledge (serial_port[port_number].irq); } }
/* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { /* 将栈顶地址保存到全局变量__irq_regs中,old_regs用于保存现在的__irq_regs值 */ struct pt_regs *old_regs = set_irq_regs(regs); /* 获取中断向量号,因为中断向量号是以取反方式保存的,这里再次取反 */ unsigned vector = ~regs->orig_ax; /* 中断向量号 */ unsigned irq; /* 硬中断计数器增加,硬中断计数器保存在preempt_count */ irq_enter(); /* 这里开始禁止调度,因为preempt_count不为0 */ /* 退出idle进程(如果当前进程是idle进程的情况下) */ exit_idle(); /* 根据中断向量号获取中断号 */ irq = __this_cpu_read(vector_irq[vector]); /* 主要函数是handle_irq,进行中断服务例程的处理 */ if (!handle_irq(irq, regs)) { /* EIO模式的应答 */ ack_APIC_irq(); /* 该中断号并没有发生过多次触发 */ if (irq != VECTOR_RETRIGGERED) { pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n", __func__, smp_processor_id(), vector, irq); } else { /* 将此中断向量号对应的vector_irq设置为未定义 */ __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED); } } /* 硬中断计数器减少,并检查是否有软中断需要执行,如果有,会设置CPU在开中断的状态下执行软中断处理 */ irq_exit(); /* 这里开始允许调度 */ /* 恢复原来的__irq_regs值 */ set_irq_regs(old_regs); return 1; }
static void clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq; irq = (vector - 0x800) >> 4; /* * The SRM console reports PCI interrupts with a vector calculated by: * * 0x900 + (0x10 * DRIR-bit) * * So bit 16 shows up as IRQ 32, etc. * * CLIPPER uses bits 8-47 for PCI interrupts, so we do not need * to scale down the vector reported, we just use it. * * Eg IRQ 24 is DRIR bit 8, etc, etc */ handle_irq(irq, regs); }
static void dp264_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; /* Read the interrupt summary register of TSUNAMI */ pld = TSUNAMI_cchip->dir0.csr; /* * Now for every possible bit set, work through them and call * the appropriate interrupt handler. */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 55) isa_device_interrupt(vector); else handle_irq(16 + i); } }
static void alcor_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; /* Read the interrupt summary register of the GRU */ pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS; /* * Now for every possible bit set, work through them and call * the appropriate interrupt handler. */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 31) { isa_device_interrupt(vector); } else { handle_irq(16 + i); } } }
static void alcor_device_interrupt(unsigned long vector) { unsigned long pld; unsigned int i; /* */ pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS; /* */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* */ if (i == 31) { isa_device_interrupt(vector); } else { handle_irq(16 + i); } } }
static void cabriolet_device_interrupt(unsigned long v) { unsigned long pld; unsigned int i; /* */ pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16); /* */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* */ if (i == 4) { isa_device_interrupt(v); } else { handle_irq(16 + i); } } }
static void cabriolet_device_interrupt(unsigned long v, struct pt_regs *r) { unsigned long pld; unsigned int i; /* Read the interrupt summary registers */ pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16); /* * Now for every possible bit set, work through them and call * the appropriate interrupt handler. */ while (pld) { i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 4) { isa_device_interrupt(v, r); } else { handle_irq(16 + i, r); } } }
static void dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq; irq = (vector - 0x800) >> 4; /* * The SRM console reports PCI interrupts with a vector calculated by: * * 0x900 + (0x10 * DRIR-bit) * * So bit 16 shows up as IRQ 32, etc. * * On DP264/BRICK/MONET, we adjust it down by 16 because at least * that many of the low order bits of the DRIR are not used, and * so we don't count them. */ if (irq >= 32) irq -= 16; handle_irq(irq, regs); }