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

📄 irq.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * $Id: irq.c,v 1.113 1999/09/17 17:22:56 cort Exp $ * *  arch/ppc/kernel/irq.c * *  Derived from arch/i386/kernel/irq.c *    Copyright (C) 1992 Linus Torvalds *  Adapted from arch/i386 by Gary Thomas *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) *  Updated and modified by Cort Dougan (cort@cs.nmt.edu) *    Copyright (C) 1996 Cort Dougan *  Adapted for Power Macintosh by Paul Mackerras *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). *   * 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. * * The MPC8xx has an interrupt mask in the SIU.  If a bit is set, the * interrupt is _enabled_.  As expected, IRQ0 is bit 0 in the 32-bit * mask register (of which only 16 are defined), hence the weird shifting * and compliment of the cached_irq_mask.  I want to be able to stuff * this right into the SIU SMASK register. * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx * to reduce code space and undefined function references. */#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/threads.h>#include <linux/kernel_stat.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/timex.h>#include <linux/config.h>#include <linux/init.h>#include <linux/malloc.h>#include <linux/openpic.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/irq.h>#include <linux/proc_fs.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <asm/hydra.h>#include <asm/system.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/irq.h>#include <asm/gg2.h>#include <asm/cache.h>#include <asm/prom.h>#include <asm/amigaints.h>#include <asm/amigahw.h>#include <asm/amigappc.h>#include <asm/ptrace.h>#include "local_irq.h"extern volatile unsigned long ipi_count;void enable_irq(unsigned int irq_nr);void disable_irq(unsigned int irq_nr);volatile unsigned char *chrp_int_ack_special;#define MAXCOUNT 10000000irq_desc_t irq_desc[NR_IRQS];int ppc_spurious_interrupts = 0;struct irqaction *ppc_irq_action[NR_IRQS];unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];unsigned int ppc_lost_interrupts[NR_MASK_WORDS];atomic_t ppc_n_lost_interrupts;/* nasty hack for shared irq's since we need to do kmalloc calls but * can't very early in the boot when we need to do a request irq. * this needs to be removed. * -- Cort */#define IRQ_KMALLOC_ENTRIES 8static int cache_bitmask = 0;static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES];extern int mem_init_done;void *irq_kmalloc(size_t size, int pri){	unsigned int i;	if ( mem_init_done )		return kmalloc(size,pri);	for ( i = 0; i < IRQ_KMALLOC_ENTRIES ; i++ )		if ( ! ( cache_bitmask & (1<<i) ) )		{			cache_bitmask |= (1<<i);			return (void *)(&malloc_cache[i]);		}	return 0;}void irq_kfree(void *ptr){	unsigned int i;	for ( i = 0 ; i < IRQ_KMALLOC_ENTRIES ; i++ )		if ( ptr == &malloc_cache[i] )		{			cache_bitmask &= ~(1<<i);			return;		}	kfree(ptr);}#if (defined(CONFIG_8xx) || defined(CONFIG_8260))/* Name change so we can catch standard drivers that potentially mess up * the internal interrupt controller on 8xx and 8260.  Just bear with me, * I don't like this either and I am searching a better solution.  For * now, this is what I need. -- Dan */int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),#elif defined(CONFIG_APUS)int request_sysirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),#elseint request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),#endif	unsigned long irqflags, const char * devname, void *dev_id){	struct irqaction *old, **p, *action;	unsigned long flags;	if (irq >= NR_IRQS)		return -EINVAL;	if (!handler)	{		/* Free */		p = &irq_desc[irq].action;		while ((action = *p) != NULL && action->dev_id != dev_id)			p = &action->next;		if (action == NULL)			return -ENOENT;		/* Found it - now free it */		save_flags(flags);		cli();		*p = action->next;		if (irq_desc[irq].action == NULL)			disable_irq(irq);		restore_flags(flags);		irq_kfree(action);		return 0;	}		action = (struct irqaction *)		irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);	if (!action)		return -ENOMEM;		save_flags(flags);	cli();		action->handler = handler;	action->flags = irqflags;						action->mask = 0;	action->name = devname;	action->dev_id = dev_id;	action->next = NULL;	enable_irq(irq);		p = &irq_desc[irq].action;		if ((old = *p) != NULL) {		/* Can't share interrupts unless both agree to */		if (!(old->flags & action->flags & SA_SHIRQ))			return -EBUSY;		/* add new interrupt at end of irq queue */		do {			p = &old->next;			old = *p;		} while (old);	}	*p = action;	restore_flags(flags);		return 0;}#ifdef CONFIG_APUSvoid sys_free_irq(unsigned int irq, void *dev_id){	sys_request_irq(irq, NULL, 0, NULL, dev_id);}#elsevoid free_irq(unsigned int irq, void *dev_id){#if (defined(CONFIG_8xx) || defined(CONFIG_8260))	request_8xxirq(irq, NULL, 0, NULL, dev_id);#else	request_irq(irq, NULL, 0, NULL, dev_id);#endif}#endif/* XXX should implement irq disable depth like on intel */void disable_irq_nosync(unsigned int irq_nr){	mask_irq(irq_nr);}void disable_irq(unsigned int irq_nr){	mask_irq(irq_nr);	synchronize_irq();}void enable_irq(unsigned int irq_nr){	unmask_irq(irq_nr);}int get_irq_list(char *buf){#ifdef CONFIG_APUS	return apus_get_irq_list (buf);#else	int i, len = 0, j;	struct irqaction * action;	len += sprintf(buf+len, "           ");	for (j=0; j<smp_num_cpus; j++)		len += sprintf(buf+len, "CPU%d       ",j);	*(char *)(buf+len++) = '\n';	for (i = 0 ; i < NR_IRQS ; i++) {		action = irq_desc[i].action;		if ( !action || !action->handler )			continue;		len += sprintf(buf+len, "%3d: ", i);		#ifdef CONFIG_SMP		for (j = 0; j < smp_num_cpus; j++)			len += sprintf(buf+len, "%10u ",				kstat.irqs[cpu_logical_map(j)][i]);#else				len += sprintf(buf+len, "%10u ", kstat_irqs(i));#endif /* CONFIG_SMP */		if ( irq_desc[i].handler )					len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );		else			len += sprintf(buf+len, "  None      ");		len += sprintf(buf+len, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge  ");		len += sprintf(buf+len, "    %s",action->name);		for (action=action->next; action; action = action->next) {			len += sprintf(buf+len, ", %s", action->name);		}		len += sprintf(buf+len, "\n");	}#ifdef CONFIG_SMP	/* should this be per processor send/receive? */	len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);#endif			len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);	return len;#endif /* CONFIG_APUS */}/* * Eventually, this should take an array of interrupts and an array size * so it can dispatch multiple interrupts. */void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq){	int status;	struct irqaction *action;	int cpu = smp_processor_id();	mask_and_ack_irq(irq);	status = 0;	action = irq_desc[irq].action;	kstat.irqs[cpu][irq]++;	if (action && action->handler) {		if (!(action->flags & SA_INTERRUPT))			__sti();		do { 			status |= action->flags;			action->handler(irq, action->dev_id, regs);			action = action->next;		} while ( action );		__cli();		if (irq_desc[irq].handler) {			if (irq_desc[irq].handler->end)				irq_desc[irq].handler->end(irq);			else if (irq_desc[irq].handler->enable)				irq_desc[irq].handler->enable(irq);		}	} else {		ppc_spurious_interrupts++;		printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq);		disable_irq(irq);		if (irq_desc[irq].handler->end)			irq_desc[irq].handler->end(irq);	}}int do_IRQ(struct pt_regs *regs, int isfake){	int cpu = smp_processor_id();	int irq;        hardirq_enter( cpu );	/* every arch is required to have a get_irq -- Cort */	irq = ppc_md.get_irq( regs );	if ( irq < 0 )	{		/* -2 means ignore, already handled */		if (irq != -2)		{			printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",			       irq, regs->nip);			ppc_spurious_interrupts++;		}		goto out;	}	ppc_irq_dispatch_handler( regs, irq );	if (ppc_md.post_irq)		ppc_md.post_irq( regs, irq ); out:	        hardirq_exit( cpu );	return 1; /* lets ret_from_int know we can do checks */}unsigned long probe_irq_on (void){	return 0;}int probe_irq_off (unsigned long irqs){	return 0;}unsigned int probe_irq_mask(unsigned long irqs){	return 0;}void __init init_IRQ(void){	static int once = 0;	if ( once )		return;	else		once++;		ppc_md.init_IRQ();}#ifdef CONFIG_SMPunsigned char global_irq_holder = NO_PROC_ID;unsigned volatile int global_irq_lock;atomic_t global_irq_count;atomic_t global_bh_count;static void show(char * str){	int i;	unsigned long *stack;	int cpu = smp_processor_id();	printk("\n%s, CPU %d:\n", str, cpu);	printk("irq:  %d [%d %d]\n",	       atomic_read(&global_irq_count),	       local_irq_count(0),	       local_irq_count(1));	printk("bh:   %d [%d %d]\n",	       atomic_read(&global_bh_count),	       local_bh_count(0),	       local_bh_count(1));	stack = (unsigned long *) &str;	for (i = 40; i ; i--) {		unsigned long x = *++stack;		if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {			printk("<[%08lx]> ", x);		}	}}static inline void wait_on_bh(void){	int count = MAXCOUNT;	do {

⌨️ 快捷键说明

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