irq.c
来自「这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,」· C语言 代码 · 共 688 行 · 第 1/2 页
C
688 行
/* * linux/arch/arm/kernel/irq.c * * Copyright (C) 1992 Linus Torvalds * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This file contains the code used by various IRQ handling routines: * asking for different IRQ's should be done through these routines * instead of just grabbing them. Thus setups with different IRQ numbers * shouldn't result in any weird surprises, and installing new handlers * should be easier. * * IRQ's are in fact implemented a bit like signal handlers for the kernel. * Naturally it's not a 1:1 relation, but there are similarities. */#include <linux/config.h>#include <linux/ptrace.h>#include <linux/kernel_stat.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/random.h>#include <linux/smp.h>#include <linux/init.h>#include <asm/proc/cache.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/mach/irq.h>#include <asm/arch/irq.h> /* pick up fixup_irq definition *//* * Maximum IRQ count. Currently, this is arbitary. However, it should * not be set too low to prevent false triggering. Conversely, if it * is set too high, then you could miss a stuck IRQ. * * Maybe we ought to set a timer and re-enable the IRQ at a later time? */#define MAX_IRQ_CNT 100000static volatile unsigned long irq_err_count;static spinlock_t irq_controller_lock;struct irqdesc irq_desc[NR_IRQS];void (*init_arch_irq)(void) __initdata = NULL;/* * Dummy mask/unmask handler */static void dummy_mask_unmask_irq(unsigned int irq){}//XXXextern int *inside_irq;extern int last_irq;extern unsigned long jiffies_last_irq;extern unsigned long my_jiffies;extern unsigned long total_irqs;static int in_crash_report = 0;static void crash_report(char *s){ int _i_; int _inint[22]; int lic = local_irq_count(0); int lbc = local_bh_count(0); for(_i_=0;_i_<22;_i_++) _inint[_i_]=inside_irq[_i_]; if(in_crash_report > 0) return; in_crash_report++; printk("---------------------------------------------------------\n"); printk("**** CRASH REPORT ****\n"); printk("%s\n",s); printk("my_jiffies= %ld - total_irq = %ld\n",my_jiffies, total_irqs); printk("Scheduling in interrupt (irq = %d bh = %d)\n" "lastirq = %d, jiffies=%lu irq_jiffies=%lu\n", lic, lbc,last_irq, jiffies, jiffies_last_irq); printk("inside irqs:"); printk("%d ",_inint[31]); printk("\n"); panic("BUG\n");}/** * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * * Disable the selected interrupt line. * * This function may be called - with care - from IRQ context. */void disable_irq(unsigned int irq){ unsigned long flags; spin_lock_irqsave(&irq_controller_lock, flags); irq_desc[irq].enabled = 0; irq_desc[irq].mask(irq); spin_unlock_irqrestore(&irq_controller_lock, flags);}/** * enable_irq - enable interrupt handling on an irq * @irq: Interrupt to enable * * Re-enables the processing of interrupts on this IRQ line * * This function may be called from IRQ context. */void enable_irq(unsigned int irq){ unsigned long flags; spin_lock_irqsave(&irq_controller_lock, flags); irq_desc[irq].probing = 0; irq_desc[irq].triggered = 0; irq_desc[irq].enabled = 1; irq_desc[irq].unmask(irq); spin_unlock_irqrestore(&irq_controller_lock, flags);}#ifdef CONFIG_ARCH_QUASAR#include <asm/arch/quasar.h>#endifint get_irq_list(char *buf){ int i; struct irqaction * action; char *p = buf; for (i = 0 ; i < NR_IRQS ; i++) { action = irq_desc[i].action; if (!action) continue; p += sprintf(p, "%3d: %10u ", i, kstat_irqs(i)); p += sprintf(p, " %s", action->name); for (action = action->next; action; action = action->next) { p += sprintf(p, ", %s", action->name); } *p++ = '\n'; }#ifdef CONFIG_ARCH_ACORN p += get_fiq_list(p);#endif p += sprintf(p, "Err: %10lu\n", irq_err_count);#ifdef CONFIG_ARCH_QUASAR { static char *irqstat_str[] = { "IRQSTAT", "FIQSTAT", "INTTYPE", "INTPOLL", "INTEN " }; static int irqstat_reg[] = { INT_IRQSTAT, INT_FIQSTAT, INT_INTTYPE, INT_INTPOLL, INT_INTEN, -1 }; unsigned int irqstat; p += sprintf(p, "\nQUASAR IRQ Registers :\n"); irqstat = quasar_readl(QUASAR_LBC_INTERRUPT); p += sprintf(p, " QUASAR_LBC_INTERRUPT : %08x\n", irqstat); p += sprintf(p, "\nJASPER IRQ Registers :\n"); for (i = 0; irqstat_reg[i] >= 0; ++i) { irqstat = __raw_readl(JASPER_INT_CONTROLLER_BASE + irqstat_reg[i]); p += sprintf(p, " %08x (%s) : %08x\n", JASPER_INT_CONTROLLER_BASE + i, irqstat_str[i], irqstat); } }#endif return p - buf;}/* * IRQ lock detection. * * Hopefully, this should get us out of a few locked situations. * However, it may take a while for this to happen, since we need * a large number if IRQs to appear in the same jiffie with the * same instruction pointer (or within 2 instructions). */static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs){ unsigned long instr_ptr = instruction_pointer(regs); if (desc->lck_jif == jiffies && desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) { desc->lck_cnt += 1; if (desc->lck_cnt > MAX_IRQ_CNT) { printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); disable_irq(irq); } } else { desc->lck_cnt = 0; desc->lck_pc = instruction_pointer(regs); desc->lck_jif = jiffies; }}/* * do_IRQ handles all normal device IRQ's */int *inside_irq;int last_irq;unsigned long jiffies_last_irq;unsigned long my_jiffies=0;unsigned long total_irqs=0;asmlinkage void do_IRQ(int irq, struct pt_regs * regs){ struct irqdesc * desc; struct irqaction * action; int cpu;#ifdef CONFIG_ARCH_SAMSUNG CLEAR_PEND_INT(irq);#endif irq = fixup_irq(irq);//XXX if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_BEFORE_INC inside_irq != local_irq_count(0)"); /* * Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */ if (irq >= NR_IRQS) goto bad_irq;//XXX if(irq==0) my_jiffies++; total_irqs++; if(in_crash_report == 0) { inside_irq[31]++; last_irq=irq; jiffies_last_irq=jiffies; } desc = irq_desc + irq; spin_lock(&irq_controller_lock); desc->mask_ack(irq); spin_unlock(&irq_controller_lock); cpu = smp_processor_id(); irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; desc->triggered = 1; /* Return with this interrupt masked if no action */ action = desc->action;//XXX if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_AFTER_INC inside_irq != local_irq_count(0)"); if (action) { int status = 0; if (desc->nomask) { spin_lock(&irq_controller_lock); desc->unmask(irq); spin_unlock(&irq_controller_lock); }//XXX if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_BEFORE_STI inside_irq != local_irq_count(0)"); if (!(action->flags & SA_INTERRUPT)) {// XXX __sti(); } if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_AFTER_STI inside_irq != local_irq_count(0)"); do { status |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_BEFORE_CLI inside_irq != local_irq_count(0)"); __cli();// XXX if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_AFTER_CLI inside_irq != local_irq_count(0)"); if (!desc->nomask && desc->enabled) { spin_lock(&irq_controller_lock); desc->unmask(irq); spin_unlock(&irq_controller_lock); } }//XXX if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_BEFORE_DEC inside_irq != local_irq_count(0)"); /* * Debug measure - hopefully we can continue if an * IRQ lockup problem occurs... */ check_irq_lock(desc, irq, regs);//XXX if(in_crash_report == 0) inside_irq[31]--; irq_exit(cpu, irq); // barrier(); if(inside_irq[31]!=local_irq_count(0)) crash_report("IRQ_AFTER_DEC inside_irq != local_irq_count(0)");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?