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

📄 io_apic.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *	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 *	Paul Diefenbaugh	:	Added full ACPI support */#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 <linux/acpi.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/desc.h>#include <asm/proto.h>int sis_apic_bug; /* not actually supported, dummy for compile */#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 {	short apic, pin, next;} irq_2_pin[PIN_MAP_SIZE];int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};#ifdef CONFIG_PCI_MSI#define vector_to_irq(vector) 	\	(platform_legacy_irq(vector) ? vector : vector_irq[vector])#else#define vector_to_irq(vector)	(vector)#endif/* * 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 __init 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;	/* Check delivery_mode to be sure we're not clearing an SMI pin */	spin_lock_irqsave(&ioapic_lock, flags);	*(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);	*(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);	spin_unlock_irqrestore(&ioapic_lock, flags);	if (entry.delivery_mode == dest_SMI)		return;	/*	 * 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;int ioapic_force;/* dummy parsing: see setup.c */static int __init disable_ioapic_setup(char *str){	skip_ioapic_setup = 1;	return 1;}static int __init enable_ioapic_setup(char *str){	ioapic_force = 1;	skip_ioapic_setup = 0;	return 1;}__setup("noapic", disable_ioapic_setup);__setup("apic", enable_ioapic_setup);#include <asm/pci-direct.h>#include <linux/pci_ids.h>#include <linux/pci.h>/* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC   off. Check for an Nvidia or VIA PCI bridge and turn it off.   Use pci direct infrastructure because this runs before the PCI subsystem.    Can be overwritten with "apic"   And another hack to disable the IOMMU on VIA chipsets.   Kludge-O-Rama. */void __init check_ioapic(void) { 	int num,slot,func; 	if (ioapic_force) 		return; 	/* Poor man's PCI discovery */	for (num = 0; num < 32; num++) { 		for (slot = 0; slot < 32; slot++) { 			for (func = 0; func < 8; func++) { 				u32 class;				u32 vendor;				u8 type;				class = read_pci_config(num,slot,func,							PCI_CLASS_REVISION);				if (class == 0xffffffff)					break; 		       		if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)					continue; 				vendor = read_pci_config(num, slot, func, 							 PCI_VENDOR_ID);				vendor &= 0xffff;				switch (vendor) { 				case PCI_VENDOR_ID_VIA:#ifdef CONFIG_GART_IOMMU					if ((end_pfn >= (0xffffffff>>PAGE_SHIFT) ||					     force_iommu) &&					    !iommu_aperture_allowed) {						printk(KERN_INFO    "Looks like a VIA chipset. Disabling IOMMU. Overwrite with \"iommu=allowed\"\n");						iommu_aperture_disabled = 1;					}#endif					return;				case PCI_VENDOR_ID_NVIDIA:#ifndef CONFIG_SMP					printk(KERN_INFO      "PCI bridge %02x:%02x from %x found. Setting \"noapic\". Overwrite with \"apic\"\n",					       num,slot,vendor); 					skip_ioapic_setup = 1;#endif					return;				} 				/* No multi-function device? */				type = read_pci_config_byte(num,slot,func,							    PCI_HEADER_TYPE);				if (!(type & 0x80))					break;			} 		}	}} 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;		}

⌨️ 快捷键说明

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