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

📄 io_apic.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	Intel IO-APIC support for multi-Pentium hosts. * *	Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo * *	Many thanks to Stig Venaas for trying out countless experimental *	patches and reporting/debugging problems patiently! * *	(c) 1999, Multiple IO-APIC support, developed by *	Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and *      Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>, *	further tested and cleaned up by Zach Brown <zab@redhat.com> *	and Ingo Molnar <mingo@redhat.com> * *	Fixes *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs; *					thanks to Eric Gilmore *					and Rolf G. Tews *					for testing these extensively */#include <linux/mm.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/config.h>#include <linux/smp_lock.h>#include <linux/mc146818rtc.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/desc.h>#undef APIC_LOCKUP_DEBUG#define APIC_LOCKUP_DEBUGstatic spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;/* * # of IRQ routing registers */int nr_ioapic_registers[MAX_IO_APICS];/* * Rough estimation of how many shared IRQs there are, can * be changed anytime. */#define MAX_PLUS_SHARED_IRQS NR_IRQS#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)/* * This is performance-critical, we want to do it O(1) * * the indexing order of this array favors 1:1 mappings * between pins and IRQs. */static struct irq_pin_list {	int apic, pin, next;} irq_2_pin[PIN_MAP_SIZE];/* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */static void add_pin_to_irq(unsigned int irq, int apic, int pin){	static int first_free_entry = NR_IRQS;	struct irq_pin_list *entry = irq_2_pin + irq;	while (entry->next)		entry = irq_2_pin + entry->next;	if (entry->pin != -1) {		entry->next = first_free_entry;		entry = irq_2_pin + entry->next;		if (++first_free_entry >= PIN_MAP_SIZE)			panic("io_apic.c: whoops");	}	entry->apic = apic;	entry->pin = pin;}#define __DO_ACTION(R, ACTION, FINAL)					\									\{									\	int pin;							\	struct irq_pin_list *entry = irq_2_pin + irq;			\									\	for (;;) {							\		unsigned int reg;					\		pin = entry->pin;					\		if (pin == -1)						\			break;						\		reg = io_apic_read(entry->apic, 0x10 + R + pin*2);	\		reg ACTION;						\		io_apic_modify(entry->apic, reg);			\		if (!entry->next)					\			break;						\		entry = irq_2_pin + entry->next;			\	}								\	FINAL;								\}#define DO_ACTION(name,R,ACTION, FINAL)					\									\	static void name##_IO_APIC_irq (unsigned int irq)		\	__DO_ACTION(R, ACTION, FINAL)DO_ACTION( __mask,             0, |= 0x00010000, io_apic_sync(entry->apic) )						/* mask = 1 */DO_ACTION( __unmask,           0, &= 0xfffeffff, )						/* mask = 0 */DO_ACTION( __mask_and_edge,    0, = (reg & 0xffff7fff) | 0x00010000, )						/* mask = 1, trigger = 0 */DO_ACTION( __unmask_and_level, 0, = (reg & 0xfffeffff) | 0x00008000, )						/* mask = 0, trigger = 1 */static void mask_IO_APIC_irq (unsigned int irq){	unsigned long flags;	spin_lock_irqsave(&ioapic_lock, flags);	__mask_IO_APIC_irq(irq);	spin_unlock_irqrestore(&ioapic_lock, flags);}static void unmask_IO_APIC_irq (unsigned int irq){	unsigned long flags;	spin_lock_irqsave(&ioapic_lock, flags);	__unmask_IO_APIC_irq(irq);	spin_unlock_irqrestore(&ioapic_lock, flags);}void clear_IO_APIC_pin(unsigned int apic, unsigned int pin){	struct IO_APIC_route_entry entry;	unsigned long flags;	/*	 * Disable it in the IO-APIC irq-routing table:	 */	memset(&entry, 0, sizeof(entry));	entry.mask = 1;	spin_lock_irqsave(&ioapic_lock, flags);	io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));	spin_unlock_irqrestore(&ioapic_lock, flags);}static void clear_IO_APIC (void){	int apic, pin;	for (apic = 0; apic < nr_ioapics; apic++)		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)			clear_IO_APIC_pin(apic, pin);}/* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. */#define MAX_PIRQS 8int pirq_entries [MAX_PIRQS];int pirqs_enabled;int skip_ioapic_setup;static int __init ioapic_setup(char *str){	skip_ioapic_setup = 1;	return 1;}__setup("noapic", ioapic_setup);static int __init ioapic_pirq_setup(char *str){	int i, max;	int ints[MAX_PIRQS+1];	get_options(str, ARRAY_SIZE(ints), ints);	for (i = 0; i < MAX_PIRQS; i++)		pirq_entries[i] = -1;	pirqs_enabled = 1;	printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n");	max = MAX_PIRQS;	if (ints[0] < MAX_PIRQS)		max = ints[0];	for (i = 0; i < max; i++) {		printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);		/*		 * PIRQs are mapped upside down, usually.		 */		pirq_entries[MAX_PIRQS-i-1] = ints[i+1];	}	return 1;}__setup("pirq=", ioapic_pirq_setup);/* * Find the IRQ entry number of a certain pin. */static int __init find_irq_entry(int apic, int pin, int type){	int i;	for (i = 0; i < mp_irq_entries; i++)		if (mp_irqs[i].mpc_irqtype == type &&		    (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||		     mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&		    mp_irqs[i].mpc_dstirq == pin)			return i;	return -1;}/* * Find the pin to which IRQ[irq] (ISA) is connected */static int __init find_isa_irq_pin(int irq, int type){	int i;	for (i = 0; i < mp_irq_entries; i++) {		int lbus = mp_irqs[i].mpc_srcbus;		if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||		     mp_bus_id_to_type[lbus] == MP_BUS_EISA ||		     mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&		    (mp_irqs[i].mpc_irqtype == type) &&		    (mp_irqs[i].mpc_srcbusirq == irq))			return mp_irqs[i].mpc_dstirq;	}	return -1;}/* * Find a specific PCI IRQ entry. * Not an __init, possibly needed by modules */static int pin_2_irq(int idx, int apic, int pin);int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin){	int apic, i, best_guess = -1;	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",		bus, slot, pin);	if (mp_bus_id_to_pci_bus[bus] == -1) {		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);		return -1;	}	for (i = 0; i < mp_irq_entries; i++) {		int lbus = mp_irqs[i].mpc_srcbus;		for (apic = 0; apic < nr_ioapics; apic++)			if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||			    mp_irqs[i].mpc_dstapic == MP_APIC_ALL)				break;		if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&		    !mp_irqs[i].mpc_irqtype &&		    (bus == lbus) &&		    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {			int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);			if (!(apic || IO_APIC_IRQ(irq)))				continue;			if (pin == (mp_irqs[i].mpc_srcbusirq & 3))				return irq;			/*			 * Use the first all-but-pin matching entry as a			 * best-guess fuzzy result for broken mptables.			 */			if (best_guess < 0)				best_guess = irq;		}	}	return best_guess;}/* * EISA Edge/Level control register, ELCR */static int __init EISA_ELCR(unsigned int irq){	if (irq < 16) {		unsigned int port = 0x4d0 + (irq >> 3);		return (inb(port) >> (irq & 7)) & 1;	}	printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq);	return 0;}/* EISA interrupts are always polarity zero and can be edge or level * trigger depending on the ELCR value.  If an interrupt is listed as * EISA conforming in the MP table, that means its trigger type must * be read in from the ELCR */#define default_EISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))#define default_EISA_polarity(idx)	(0)/* ISA interrupts are always polarity zero edge triggered, * when listed as conforming in the MP table. */#define default_ISA_trigger(idx)	(0)#define default_ISA_polarity(idx)	(0)/* PCI interrupts are always polarity one level triggered, * when listed as conforming in the MP table. */#define default_PCI_trigger(idx)	(1)#define default_PCI_polarity(idx)	(1)/* MCA interrupts are always polarity zero level triggered, * when listed as conforming in the MP table. */#define default_MCA_trigger(idx)	(1)#define default_MCA_polarity(idx)	(0)static int __init MPBIOS_polarity(int idx){	int bus = mp_irqs[idx].mpc_srcbus;	int polarity;	/*	 * Determine IRQ line polarity (high active or low active):	 */	switch (mp_irqs[idx].mpc_irqflag & 3)	{		case 0: /* conforms, ie. bus-type dependent polarity */		{			switch (mp_bus_id_to_type[bus])			{				case MP_BUS_ISA: /* ISA pin */				{					polarity = default_ISA_polarity(idx);					break;				}				case MP_BUS_EISA: /* EISA pin */				{					polarity = default_EISA_polarity(idx);					break;				}				case MP_BUS_PCI: /* PCI pin */				{					polarity = default_PCI_polarity(idx);					break;				}				case MP_BUS_MCA: /* MCA pin */				{					polarity = default_MCA_polarity(idx);					break;				}				default:				{					printk(KERN_WARNING "broken BIOS!!\n");					polarity = 1;					break;				}			}			break;		}		case 1: /* high active */		{			polarity = 0;			break;		}		case 2: /* reserved */		{			printk(KERN_WARNING "broken BIOS!!\n");			polarity = 1;			break;		}		case 3: /* low active */		{			polarity = 1;			break;		}		default: /* invalid */		{			printk(KERN_WARNING "broken BIOS!!\n");			polarity = 1;			break;		}	}	return polarity;}static int __init MPBIOS_trigger(int idx){	int bus = mp_irqs[idx].mpc_srcbus;	int trigger;	/*	 * Determine IRQ trigger mode (edge or level sensitive):	 */	switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)	{		case 0: /* conforms, ie. bus-type dependent */		{			switch (mp_bus_id_to_type[bus])			{				case MP_BUS_ISA: /* ISA pin */				{					trigger = default_ISA_trigger(idx);					break;				}				case MP_BUS_EISA: /* EISA pin */				{					trigger = default_EISA_trigger(idx);					break;				}				case MP_BUS_PCI: /* PCI pin */				{					trigger = default_PCI_trigger(idx);					break;				}				case MP_BUS_MCA: /* MCA pin */				{					trigger = default_MCA_trigger(idx);					break;				}				default:				{					printk(KERN_WARNING "broken BIOS!!\n");					trigger = 1;					break;				}			}			break;		}		case 1: /* edge */		{			trigger = 0;			break;		}		case 2: /* reserved */		{			printk(KERN_WARNING "broken BIOS!!\n");			trigger = 1;			break;		}		case 3: /* level */		{			trigger = 1;			break;		}		default: /* invalid */		{			printk(KERN_WARNING "broken BIOS!!\n");			trigger = 0;			break;		}	}	return trigger;}static inline int irq_polarity(int idx){	return MPBIOS_polarity(idx);}static inline int irq_trigger(int idx){	return MPBIOS_trigger(idx);}static int pin_2_irq(int idx, int apic, int pin){	int irq, i;	int bus = mp_irqs[idx].mpc_srcbus;	/*	 * Debugging check, we are in big trouble if this message pops up!	 */	if (mp_irqs[idx].mpc_dstirq != pin)		printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");	switch (mp_bus_id_to_type[bus])	{		case MP_BUS_ISA: /* ISA pin */		case MP_BUS_EISA:		case MP_BUS_MCA:		{			irq = mp_irqs[idx].mpc_srcbusirq;			break;		}		case MP_BUS_PCI: /* PCI pin */		{			/*			 * PCI IRQs are mapped in order			 */			i = irq = 0;			while (i < apic)				irq += nr_ioapic_registers[i++];			irq += pin;			break;		}		default:		{			printk(KERN_ERR "unknown bus type %d.\n",bus); 			irq = 0;			break;		}	}	/*	 * PCI IRQ command line redirection. Yes, limits are hardcoded.	 */	if ((pin >= 16) && (pin <= 23)) {		if (pirq_entries[pin-16] != -1) {			if (!pirq_entries[pin-16]) {				printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16);			} else {				irq = pirq_entries[pin-16];				printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n",						pin-16, irq);			}		}	}	return irq;}static inline int IO_APIC_irq_trigger(int irq){

⌨️ 快捷键说明

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