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

📄 ip27-irq.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ip27-irq.c: Highlevel interrupt handling for IP27 architecture. * * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */#include <linux/config.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/timex.h>#include <linux/malloc.h>#include <linux/random.h>#include <linux/smp_lock.h>#include <linux/kernel_stat.h>#include <linux/delay.h>#include <linux/irq.h>#include <asm/bitops.h>#include <asm/bootinfo.h>#include <asm/io.h>#include <asm/mipsregs.h>#include <asm/system.h>#include <asm/ptrace.h>#include <asm/processor.h>#include <asm/pci/bridge.h>#include <asm/sn/sn0/hub.h>#include <asm/sn/sn0/ip27.h>#include <asm/sn/arch.h>#include <asm/sn/intr.h>#include <asm/sn/intr_public.h>#undef DEBUG_IRQ#ifdef DEBUG_IRQ#define DBG(x...) printk(x)#else#define DBG(x...)#endif/* * Linux has a controller-independent x86 interrupt architecture. * every controller has a 'controller-template', that is used * by the main code to do the right thing. Each driver-visible * interrupt source is transparently wired to the apropriate * controller. Thus drivers need not be aware of the * interrupt-controller. * * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. * (IO-APICs assumed to be messaging to Pentium local-APICs) * * the code is designed to be easily extended with new/different * interrupt controllers, without having to do assembly magic. */extern asmlinkage void ip27_irq(void);extern int irq_to_bus[], irq_to_slot[], bus_to_cpu[];int intr_connect_level(int cpu, int bit);int intr_disconnect_level(int cpu, int bit);unsigned long spurious_count = 0;/* * we need to map irq's up to at least bit 7 of the INT_MASK0_A register * since bits 0-6 are pre-allocated for other purposes. */#define IRQ_TO_SWLEVEL(cpu, i)	i + 7#define SWLEVEL_TO_IRQ(cpu, s)	s - 7/* * use these macros to get the encoded nasid and widget id * from the irq value */#define IRQ_TO_BUS(i)			irq_to_bus[(i)]#define IRQ_TO_CPU(i)			bus_to_cpu[IRQ_TO_BUS(i)]#define NASID_FROM_PCI_IRQ(i)		bus_to_nid[IRQ_TO_BUS(i)]#define WID_FROM_PCI_IRQ(i)		bus_to_wid[IRQ_TO_BUS(i)]#define	SLOT_FROM_PCI_IRQ(i)		irq_to_slot[i]void disable_irq(unsigned int irq_nr){	panic("disable_irq() called ...");}void enable_irq(unsigned int irq_nr){	panic("enable_irq() called ...");}/* This is stupid for an Origin which can have thousands of IRQs ...  */static struct irqaction *irq_action[NR_IRQS];int get_irq_list(char *buf){	int i, len = 0;	struct irqaction * action;	for (i = 0 ; i < NR_IRQS ; i++) {		action = irq_action[i];		if (!action) 			continue;		len += sprintf(buf+len, "%2d: %8d %c %s", i, kstat.irqs[0][i],		               (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;}/* * do_IRQ handles all normal device IRQ's (the special SMP cross-CPU interrupts * have their own specific handlers). */static void do_IRQ(cpuid_t thiscpu, int irq, struct pt_regs * regs){	struct irqaction *action;	int do_random;	irq_enter(thiscpu, irq);	kstat.irqs[thiscpu][irq]++;	action = *(irq + irq_action);	if (action) {		if (!(action->flags & SA_INTERRUPT))			__sti();		do_random = 0;        	do {			do_random |= action->flags;			action->handler(irq, action->dev_id, regs);			action = action->next;        	} while (action);		if (do_random & SA_SAMPLE_RANDOM)			add_interrupt_randomness(irq);		__cli();	}	irq_exit(thiscpu, irq);	/* unmasking and bottom half handling is done magically for us. */}/* * Find first bit set */static int ms1bit(unsigned long x){	int	b;	if (x >> 32) 	b = 32, x >>= 32;	else		b  =  0;	if (x >> 16)	b += 16, x >>= 16;	if (x >>  8)	b +=  8, x >>=  8;	if (x >>  4)	b +=  4, x >>=  4;	if (x >>  2)	b +=  2, x >>=  2;	return b + (int) (x >> 1);}/* * This code is unnecessarily complex, because we do SA_INTERRUPT * intr enabling. Basically, once we grab the set of intrs we need * to service, we must mask _all_ these interrupts; firstly, to make * sure the same intr does not intr again, causing recursion that  * can lead to stack overflow. Secondly, we can not just mask the * one intr we are do_IRQing, because the non-masked intrs in the * first set might intr again, causing multiple servicings of the * same intr. This effect is mostly seen for intercpu intrs. * Kanoj 05.13.00 */void ip27_do_irq(struct pt_regs *regs){	int irq, swlevel;	hubreg_t pend0, mask0;	cpuid_t thiscpu = smp_processor_id();	int pi_int_mask0 = ((cputoslice(thiscpu) == 0) ?					PI_INT_MASK0_A : PI_INT_MASK0_B);	/* copied from Irix intpend0() */	while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) & 				(mask0 = LOCAL_HUB_L(pi_int_mask0))) != 0) {		pend0 &= mask0;		/* Pick intrs we should look at */		if (pend0) {			/* Prevent any of the picked intrs from recursing */			LOCAL_HUB_S(pi_int_mask0, mask0 & ~(pend0));			do {				swlevel = ms1bit(pend0);				LOCAL_HUB_CLR_INTR(swlevel);				/* "map" swlevel to irq */				irq = SWLEVEL_TO_IRQ(thiscpu, swlevel);				do_IRQ(thiscpu, irq, regs);				/* clear bit in pend0 */				pend0 ^= 1ULL << swlevel;			} while(pend0);			/* Now allow the set of serviced intrs again */			LOCAL_HUB_S(pi_int_mask0, mask0);			LOCAL_HUB_L(PI_INT_PEND0);		}	}}/* Startup one of the (PCI ...) IRQs routes over a bridge.  */static unsigned int bridge_startup(unsigned int irq){	bridgereg_t device;	bridge_t *bridge;	int pin, swlevel;	cpuid_t cpu;	nasid_t master = NASID_FROM_PCI_IRQ(irq);        bridge = (bridge_t *) NODE_SWIN_BASE(master, WID_FROM_PCI_IRQ(irq));	pin = SLOT_FROM_PCI_IRQ(irq);	cpu = IRQ_TO_CPU(irq);	DBG("bridge_startup(): irq= 0x%x  pin=%d\n", irq, pin);	/*	 * "map" irq to a swlevel greater than 6 since the first 6 bits	 * of INT_PEND0 are taken	 */	swlevel = IRQ_TO_SWLEVEL(cpu, irq);	intr_connect_level(cpu, swlevel);	bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (master << 8));	bridge->b_int_enable |= (1 << pin);	/* more stuff in int_enable reg */	bridge->b_int_enable |= 0x7ffffe00;	/*	 * XXX This only works if b_int_device is initialized to 0!	 * We program the bridge to have a 1:1 mapping between devices	 * (slots) and intr pins.	 */	device = bridge->b_int_device;	device |= (pin << (pin*3));	bridge->b_int_device = device;        bridge->b_widget.w_tflush;                      /* Flush */        return 0;       /* Never anything pending.  */}/* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */static unsigned int bridge_shutdown(unsigned int irq){	bridge_t *bridge;	int pin, swlevel;	bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq), 	                                     WID_FROM_PCI_IRQ(irq));	DBG("bridge_shutdown: irq 0x%x\n", irq);	pin = SLOT_FROM_PCI_IRQ(irq);	/*	 * map irq to a swlevel greater than 6 since the first 6 bits	 * of INT_PEND0 are taken	 */	swlevel = IRQ_TO_SWLEVEL(cpu, irq);	intr_disconnect_level(smp_processor_id(), swlevel);	bridge->b_int_enable &= ~(1 << pin);	bridge->b_widget.w_tflush;                      /* Flush */	return 0;       /* Never anything pending.  */}void irq_debug(void){	bridge_t *bridge = (bridge_t *) 0x9200000008000000;	printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status);	printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable);	printk("PI_INT_PEND0   = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0));	printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A));}int setup_irq(unsigned int irq, struct irqaction *new){	int shared = 0;	struct irqaction *old, **p;	unsigned long flags;	DBG("setup_irq: 0x%x\n", irq);	if (irq >= NR_IRQS) {		printk("IRQ array overflow %d\n", irq);		while(1);	}	if (new->flags & SA_SAMPLE_RANDOM)		rand_initialize_irq(irq);	save_and_cli(flags);	p = irq_action + irq;	if ((old = *p) != NULL) {		/* Can't share interrupts unless both agree to */		if (!(old->flags & new->flags & SA_SHIRQ)) {			restore_flags(flags);			return -EBUSY;		}		/* Add new interrupt at end of irq queue */		do {			p = &old->next;			old = *p;		} while (old);		shared = 1;	}	*p = new;	if ((!shared) && (irq >= BASE_PCI_IRQ)) {		bridge_startup(irq);	}	restore_flags(flags);	return 0;}int request_irq(unsigned int irq, 		void (*handler)(int, void *, struct pt_regs *),		unsigned long irqflags, const char * devname, void *dev_id){	int retval;	struct irqaction *action;	DBG("request_irq(): irq= 0x%x\n", irq);	if (!handler)		return -EINVAL;	action = (struct irqaction *)kmalloc(sizeof(*action), GFP_KERNEL);	if (!action)		return -ENOMEM;	action->handler = handler;	action->flags = irqflags;	action->mask = 0;	action->name = devname;	action->next = NULL;	action->dev_id = dev_id;	DBG("request_irq(): %s  devid= 0x%x\n", devname, dev_id);	retval = setup_irq(irq, action);	DBG("request_irq(): retval= %d\n", retval);	if (retval)		kfree(action);	return retval;

⌨️ 快捷键说明

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