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 + -
显示快捷键?