⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irq.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  $Id: irq.c,v 1.109 2000/08/31 10:00:39 anton Exp $ *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the *                            Sparc the IRQ's are basically 'cast in stone' *                            and you are supposed to probe the prom's device *                            node trees to find out who's got which IRQ. * *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) *  Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) */#include <linux/config.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/linkage.h>#include <linux/kernel_stat.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/malloc.h>#include <linux/random.h>#include <linux/init.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/delay.h>#include <linux/threads.h>#include <linux/spinlock.h>#include <asm/ptrace.h>#include <asm/processor.h>#include <asm/system.h>#include <asm/psr.h>#include <asm/smp.h>#include <asm/vaddrs.h>#include <asm/timer.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/traps.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/pgalloc.h>#include <asm/pgtable.h>#include <asm/hardirq.h>#include <asm/softirq.h>#include <asm/pcic.h>/* * Dave Redman (djhr@tadpole.co.uk) * * IRQ numbers.. These are no longer restricted to 15.. * * this is done to enable SBUS cards and onboard IO to be masked * correctly. using the interrupt level isn't good enough. * * For example: *   A device interrupting at sbus level6 and the Floppy both come in *   at IRQ11, but enabling and disabling them requires writing to *   different bits in the SLAVIO/SEC. * * As a result of these changes sun4m machines could now support * directed CPU interrupts using the existing enable/disable irq code * with tweaks. * */static void irq_panic(void){    extern char *cputypval;    prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval);    prom_halt();}void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =    (void (*)(void (*)(int, void *,struct pt_regs *))) irq_panic;/* * Dave Redman (djhr@tadpole.co.uk) * * There used to be extern calls and hard coded values here.. very sucky! * instead, because some of the devices attach very early, I do something * equally sucky but at least we'll never try to free statically allocated * space or call kmalloc before kmalloc_init :(. *  * In fact it's the timer10 that attaches first.. then timer14 * then kmalloc_init is called.. then the tty interrupts attach. * hmmm.... * */#define MAX_STATIC_ALLOC	4struct irqaction static_irqaction[MAX_STATIC_ALLOC];int static_irq_count = 0;struct irqaction *irq_action[NR_IRQS+1] = {	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL};int get_irq_list(char *buf){	int i, len = 0;	struct irqaction * action;#ifdef CONFIG_SMP	int j;#endif	if (sparc_cpu_model == sun4d) {		extern int sun4d_get_irq_list(char *);				return sun4d_get_irq_list(buf);	}	for (i = 0 ; i < (NR_IRQS+1) ; i++) {	        action = *(i + irq_action);		if (!action) 		        continue;		len += sprintf(buf+len, "%3d: ", i);#ifndef CONFIG_SMP		len += sprintf(buf+len, "%10u ", kstat_irqs(i));#else		for (j = 0; j < smp_num_cpus; j++)			len += sprintf(buf+len, "%10u ",				kstat.irqs[cpu_logical_map(j)][i]);#endif		len += sprintf(buf+len, " %c %s",			(action->flags & SA_INTERRUPT) ? '+' : ' ',			action->name);		for (action=action->next; action; action = action->next) {			len += sprintf(buf+len, ",%s %s",				(action->flags & SA_INTERRUPT) ? " +" : "",				action->name);		}		len += sprintf(buf+len, "\n");	}	return len;}void free_irq(unsigned int irq, void *dev_id){	struct irqaction * action;	struct irqaction * tmp = NULL;        unsigned long flags;	unsigned int cpu_irq;		if (sparc_cpu_model == sun4d) {		extern void sun4d_free_irq(unsigned int, void *);				return sun4d_free_irq(irq, dev_id);	}	cpu_irq = irq & NR_IRQS;	action = *(cpu_irq + irq_action);        if (cpu_irq > 14) {  /* 14 irq levels on the sparc */                printk("Trying to free bogus IRQ %d\n", irq);                return;        }	if (!action->handler) {		printk("Trying to free free IRQ%d\n",irq);		return;	}	if (dev_id) {		for (; action; action = action->next) {			if (action->dev_id == dev_id)				break;			tmp = action;		}		if (!action) {			printk("Trying to free free shared IRQ%d\n",irq);			return;		}	} else if (action->flags & SA_SHIRQ) {		printk("Trying to free shared IRQ%d with NULL device ID\n", irq);		return;	}	if (action->flags & SA_STATIC_ALLOC)	{	    /* This interrupt is marked as specially allocated	     * so it is a bad idea to free it.	     */	    printk("Attempt to free statically allocated IRQ%d (%s)\n",		   irq, action->name);	    return;	}	        save_and_cli(flags);	if (action && tmp)		tmp->next = action->next;	else		*(cpu_irq + irq_action) = action->next;	kfree(action);	if (!(*(cpu_irq + irq_action)))		disable_irq(irq);        restore_flags(flags);}#ifdef CONFIG_SMP/* Who has the global irq brlock */unsigned char global_irq_holder = NO_PROC_ID;void smp_show_backtrace_all_cpus(void);void show_backtrace(void);#define VERBOSE_DEBUG_IRQLOCK#define MAXCOUNT 100000000static void show(char * str){	int cpu = smp_processor_id();	int i;	printk("\n%s, CPU %d:\n", str, cpu);	printk("irq:  %d [ ", irqs_running());	for (i = 0; i < smp_num_cpus; i++)		printk("%u ", __brlock_array[i][BR_GLOBALIRQ_LOCK]);	printk("]\nbh:   %d [ ",	       (spin_is_locked(&global_bh_lock) ? 1 : 0));	for (i = 0; i < smp_num_cpus; i++)		printk("%u ", local_bh_count(i));	printk("]\n");#ifdef VERBOSE_DEBUG_IRQLOCK	smp_show_backtrace_all_cpus();#else	show_backtrace();#endif}/* * We have to allow irqs to arrive between __sti and __cli */#define SYNC_OTHER_CORES(x) barrier()/* * This is called when we want to synchronize with * interrupts. We may for example tell a device to * stop sending interrupts: but to make sure there * are no interrupts that are executing on another * CPU we need to call this function. */void synchronize_irq(void){	if (irqs_running()) {		cli();		sti();	}}static inline void get_irqlock(int cpu){	int count;	if ((unsigned char)cpu == global_irq_holder)		return;	count = MAXCOUNT;again:	br_write_lock(BR_GLOBALIRQ_LOCK);	for (;;) {		spinlock_t *lock;		if (!irqs_running() &&		    (local_bh_count(smp_processor_id()) || !spin_is_locked(&global_bh_lock)))			break;		br_write_unlock(BR_GLOBALIRQ_LOCK);		lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock;		while (irqs_running() ||		       spin_is_locked(lock) ||		       (!local_bh_count(smp_processor_id()) && spin_is_locked(&global_bh_lock))) {			if (!--count) {				show("get_irqlock");				count = (~0 >> 1);			}			__sti();			SYNC_OTHER_CORES(cpu);			__cli();		}		goto again;	}	global_irq_holder = cpu;}/* * A global "cli()" while in an interrupt context * turns into just a local cli(). Interrupts * should use spinlocks for the (very unlikely) * case that they ever want to protect against * each other. * * If we already have local interrupts disabled, * this will not turn a local disable into a * global one (problems with spinlocks: this makes * save_flags+cli+sti usable inside a spinlock). */void __global_cli(void){	unsigned long flags;	__save_flags(flags);	if ((flags & PSR_PIL) != PSR_PIL) {		int cpu = smp_processor_id();		__cli();		if (!local_irq_count(cpu))			get_irqlock(cpu);	}}void __global_sti(void){	int cpu = smp_processor_id();	if (!local_irq_count(cpu))		release_irqlock(cpu);	__sti();}/* * SMP flags value to restore to: * 0 - global cli * 1 - global sti * 2 - local cli * 3 - local sti */unsigned long __global_save_flags(void){	unsigned long flags, retval;	unsigned long local_enabled = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -