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

📄 mpparse.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Intel Multiprocessor Specification 1.1 and 1.4 *	compliant MP-table parsing routines. * *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com> *	(c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com> * *	Fixes *		Erich Boleyn	:	MP v1.4 and additional changes. *		Alan Cox	:	Added EBDA scanning *		Ingo Molnar	:	various cleanups and rewrites *		Maciej W. Rozycki:	Bits for default MP configurations *		Paul Diefenbaugh:	Added full ACPI support */#include <linux/mm.h>#include <linux/init.h>#include <linux/acpi.h>#include <linux/delay.h>#include <linux/config.h>#include <linux/bootmem.h>#include <linux/smp_lock.h>#include <linux/kernel_stat.h>#include <linux/mc146818rtc.h>#include <linux/bitops.h>#include <asm/smp.h>#include <asm/acpi.h>#include <asm/mtrr.h>#include <asm/mpspec.h>#include <asm/io_apic.h>#include <mach_apic.h>#include <mach_mpparse.h>#include <bios_ebda.h>/* Have we found an MP table */int smp_found_config;unsigned int __initdata maxcpus = NR_CPUS;/* * Various Linux-internal data structures created from the * MP-table. */int apic_version [MAX_APICS];int mp_bus_id_to_type [MAX_MP_BUSSES];int mp_bus_id_to_node [MAX_MP_BUSSES];int mp_bus_id_to_local [MAX_MP_BUSSES];int quad_local_to_mp_bus_id [NR_CPUS/4][4];int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };static int mp_current_pci_id;/* I/O APIC entries */struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];/* # of MP IRQ source entries */struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];/* MP IRQ source entries */int mp_irq_entries;int nr_ioapics;int pic_mode;unsigned long mp_lapic_addr;unsigned int def_to_bigsmp = 0;/* Processor that is doing the boot up */unsigned int boot_cpu_physical_apicid = -1U;/* Internal processor count */static unsigned int __devinitdata num_processors;/* Bitmask of physically existing CPUs */physid_mask_t phys_cpu_present_map;u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };/* * Intel MP BIOS table parsing routines: *//* * Checksum an MP configuration block. */static int __init mpf_checksum(unsigned char *mp, int len){	int sum = 0;	while (len--)		sum += *mp++;	return sum & 0xFF;}/* * Have to match translation table entries to main table entries by counter * hence the mpc_record variable .... can't see a less disgusting way of * doing this .... */static int mpc_record; static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata;#ifdef CONFIG_X86_NUMAQstatic int MP_valid_apicid(int apicid, int version){	return hweight_long(apicid & 0xf) == 1 && (apicid >> 4) != 0xf;}#elsestatic int MP_valid_apicid(int apicid, int version){	if (version >= 0x14)		return apicid < 0xff;	else		return apicid < 0xf;}#endifstatic void __devinit MP_processor_info (struct mpc_config_processor *m){ 	int ver, apicid;	physid_mask_t phys_cpu; 		if (!(m->mpc_cpuflag & CPU_ENABLED))		return;	apicid = mpc_apic_id(m, translation_table[mpc_record]);	if (m->mpc_featureflag&(1<<0))		Dprintk("    Floating point unit present.\n");	if (m->mpc_featureflag&(1<<7))		Dprintk("    Machine Exception supported.\n");	if (m->mpc_featureflag&(1<<8))		Dprintk("    64 bit compare & exchange supported.\n");	if (m->mpc_featureflag&(1<<9))		Dprintk("    Internal APIC present.\n");	if (m->mpc_featureflag&(1<<11))		Dprintk("    SEP present.\n");	if (m->mpc_featureflag&(1<<12))		Dprintk("    MTRR  present.\n");	if (m->mpc_featureflag&(1<<13))		Dprintk("    PGE  present.\n");	if (m->mpc_featureflag&(1<<14))		Dprintk("    MCA  present.\n");	if (m->mpc_featureflag&(1<<15))		Dprintk("    CMOV  present.\n");	if (m->mpc_featureflag&(1<<16))		Dprintk("    PAT  present.\n");	if (m->mpc_featureflag&(1<<17))		Dprintk("    PSE  present.\n");	if (m->mpc_featureflag&(1<<18))		Dprintk("    PSN  present.\n");	if (m->mpc_featureflag&(1<<19))		Dprintk("    Cache Line Flush Instruction present.\n");	/* 20 Reserved */	if (m->mpc_featureflag&(1<<21))		Dprintk("    Debug Trace and EMON Store present.\n");	if (m->mpc_featureflag&(1<<22))		Dprintk("    ACPI Thermal Throttle Registers  present.\n");	if (m->mpc_featureflag&(1<<23))		Dprintk("    MMX  present.\n");	if (m->mpc_featureflag&(1<<24))		Dprintk("    FXSR  present.\n");	if (m->mpc_featureflag&(1<<25))		Dprintk("    XMM  present.\n");	if (m->mpc_featureflag&(1<<26))		Dprintk("    Willamette New Instructions  present.\n");	if (m->mpc_featureflag&(1<<27))		Dprintk("    Self Snoop  present.\n");	if (m->mpc_featureflag&(1<<28))		Dprintk("    HT  present.\n");	if (m->mpc_featureflag&(1<<29))		Dprintk("    Thermal Monitor present.\n");	/* 30, 31 Reserved */	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {		Dprintk("    Bootup CPU\n");		boot_cpu_physical_apicid = m->mpc_apicid;	}	ver = m->mpc_apicver;	if (!MP_valid_apicid(apicid, ver)) {		printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n",			m->mpc_apicid, MAX_APICS);		return;	}	/*	 * Validate version	 */	if (ver == 0x0) {		printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! "				"fixing up to 0x10. (tell your hw vendor)\n",				m->mpc_apicid);		ver = 0x10;	}	apic_version[m->mpc_apicid] = ver;	phys_cpu = apicid_to_cpu_present(apicid);	physids_or(phys_cpu_present_map, phys_cpu_present_map, phys_cpu);	if (num_processors >= NR_CPUS) {		printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."			"  Processor ignored.\n", NR_CPUS);		return;	}	if (num_processors >= maxcpus) {		printk(KERN_WARNING "WARNING: maxcpus limit of %i reached."			" Processor ignored.\n", maxcpus);		return;	}	cpu_set(num_processors, cpu_possible_map);	num_processors++;	if ((num_processors > 8) &&	    ((APIC_XAPIC(ver) &&	     (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)) ||	     (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)))		def_to_bigsmp = 1;	else		def_to_bigsmp = 0;	bios_cpu_apicid[num_processors - 1] = m->mpc_apicid;}static void __init MP_bus_info (struct mpc_config_bus *m){	char str[7];	memcpy(str, m->mpc_bustype, 6);	str[6] = 0;	mpc_oem_bus_info(m, str, translation_table[mpc_record]);	if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;	} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;	} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {		mpc_oem_pci_bus(m, translation_table[mpc_record]);		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;		mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;		mp_current_pci_id++;	} else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;	} else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) {		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98;	} else {		printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);	}}static void __init MP_ioapic_info (struct mpc_config_ioapic *m){	if (!(m->mpc_flags & MPC_APIC_USABLE))		return;	printk(KERN_INFO "I/O APIC #%d Version %d at 0x%lX.\n",		m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);	if (nr_ioapics >= MAX_IO_APICS) {		printk(KERN_CRIT "Max # of I/O APICs (%d) exceeded (found %d).\n",			MAX_IO_APICS, nr_ioapics);		panic("Recompile kernel with bigger MAX_IO_APICS!.\n");	}	if (!m->mpc_apicaddr) {		printk(KERN_ERR "WARNING: bogus zero I/O APIC address"			" found in MP table, skipping!\n");		return;	}	mp_ioapics[nr_ioapics] = *m;	nr_ioapics++;}static void __init MP_intsrc_info (struct mpc_config_intsrc *m){	mp_irqs [mp_irq_entries] = *m;	Dprintk("Int: type %d, pol %d, trig %d, bus %d,"		" IRQ %02x, APIC ID %x, APIC INT %02x\n",			m->mpc_irqtype, m->mpc_irqflag & 3,			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);	if (++mp_irq_entries == MAX_IRQ_SOURCES)		panic("Max # of irq sources exceeded!!\n");}static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m){	Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"		" IRQ %02x, APIC ID %x, APIC LINT %02x\n",			m->mpc_irqtype, m->mpc_irqflag & 3,			(m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,			m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);	/*	 * Well it seems all SMP boards in existence	 * use ExtINT/LVT1 == LINT0 and	 * NMI/LVT2 == LINT1 - the following check	 * will show us if this assumptions is false.	 * Until then we do not have to add baggage.	 */	if ((m->mpc_irqtype == mp_ExtINT) &&		(m->mpc_destapiclint != 0))			BUG();	if ((m->mpc_irqtype == mp_NMI) &&		(m->mpc_destapiclint != 1))			BUG();}#ifdef CONFIG_X86_NUMAQstatic void __init MP_translation_info (struct mpc_config_translation *m){	printk(KERN_INFO "Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);	if (mpc_record >= MAX_MPC_ENTRY) 		printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n");	else		translation_table[mpc_record] = m; /* stash this for later */	if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad))		node_set_online(m->trans_quad);}/* * Read/parse the MPC oem tables */static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \	unsigned short oemsize){	int count = sizeof (*oemtable); /* the header size */	unsigned char *oemptr = ((unsigned char *)oemtable)+count;		mpc_record = 0;	printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", oemtable);	if (memcmp(oemtable->oem_signature,MPC_OEM_SIGNATURE,4))	{		printk(KERN_WARNING "SMP mpc oemtable: bad signature [%c%c%c%c]!\n",			oemtable->oem_signature[0],			oemtable->oem_signature[1],			oemtable->oem_signature[2],			oemtable->oem_signature[3]);		return;	}	if (mpf_checksum((unsigned char *)oemtable,oemtable->oem_length))	{		printk(KERN_WARNING "SMP oem mptable: checksum error!\n");		return;	}	while (count < oemtable->oem_length) {		switch (*oemptr) {			case MP_TRANSLATION:			{				struct mpc_config_translation *m=					(struct mpc_config_translation *)oemptr;				MP_translation_info(m);				oemptr += sizeof(*m);				count += sizeof(*m);				++mpc_record;				break;			}			default:			{				printk(KERN_WARNING "Unrecognised OEM table entry type! - %d\n", (int) *oemptr);				return;			}		}       }}static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,		char *productid){	if (strncmp(oem, "IBM NUMA", 8))		printk("Warning!  May not be a NUMA-Q system!\n");	if (mpc->mpc_oemptr)		smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr,				mpc->mpc_oemsize);}#endif	/* CONFIG_X86_NUMAQ *//* * Read/parse the MPC */static int __init smp_read_mpc(struct mp_config_table *mpc){	char str[16];	char oem[10];	int count=sizeof(*mpc);	unsigned char *mpt=((unsigned char *)mpc)+count;	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {		printk(KERN_ERR "SMP mptable: bad signature [0x%x]!\n",			*(u32 *)mpc->mpc_signature);		return 0;	}	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {		printk(KERN_ERR "SMP mptable: checksum error!\n");		return 0;	}	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {		printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",			mpc->mpc_spec);		return 0;	}	if (!mpc->mpc_lapic) {		printk(KERN_ERR "SMP mptable: null local APIC address!\n");		return 0;	}	memcpy(oem,mpc->mpc_oem,8);	oem[8]=0;	printk(KERN_INFO "OEM ID: %s ",oem);	memcpy(str,mpc->mpc_productid,12);	str[12]=0;	printk("Product ID: %s ",str);	mps_oem_check(mpc, oem, str);	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);	/* 	 * Save the local APIC address (it might be non-default) -- but only	 * if we're not using ACPI.	 */	if (!acpi_lapic)		mp_lapic_addr = mpc->mpc_lapic;	/*	 *	Now process the configuration blocks.	 */	mpc_record = 0;	while (count < mpc->mpc_length) {		switch(*mpt) {			case MP_PROCESSOR:			{				struct mpc_config_processor *m=					(struct mpc_config_processor *)mpt;				/* ACPI may have already provided this data */				if (!acpi_lapic)					MP_processor_info(m);				mpt += sizeof(*m);				count += sizeof(*m);				break;			}			case MP_BUS:			{				struct mpc_config_bus *m=					(struct mpc_config_bus *)mpt;				MP_bus_info(m);				mpt += sizeof(*m);				count += sizeof(*m);				break;			}			case MP_IOAPIC:			{				struct mpc_config_ioapic *m=					(struct mpc_config_ioapic *)mpt;				MP_ioapic_info(m);				mpt+=sizeof(*m);				count+=sizeof(*m);				break;			}			case MP_INTSRC:			{				struct mpc_config_intsrc *m=					(struct mpc_config_intsrc *)mpt;				MP_intsrc_info(m);				mpt+=sizeof(*m);				count+=sizeof(*m);				break;			}			case MP_LINTSRC:			{				struct mpc_config_lintsrc *m=					(struct mpc_config_lintsrc *)mpt;				MP_lintsrc_info(m);				mpt+=sizeof(*m);				count+=sizeof(*m);				break;			}			default:			{				count = mpc->mpc_length;				break;			}		}		++mpc_record;	}	clustered_apic_check();	if (!num_processors)		printk(KERN_ERR "SMP mptable: no processors registered!\n");	return num_processors;}static int __init ELCR_trigger(unsigned int irq){	unsigned int port;	port = 0x4d0 + (irq >> 3);	return (inb(port) >> (irq & 7)) & 1;}static void __init construct_default_ioirq_mptable(int mpc_default_type){	struct mpc_config_intsrc intsrc;	int i;	int ELCR_fallback = 0;	intsrc.mpc_type = MP_INTSRC;	intsrc.mpc_irqflag = 0;			/* conforming */	intsrc.mpc_srcbus = 0;	intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;	intsrc.mpc_irqtype = mp_INT;	/*	 *  If true, we have an ISA/PCI system with no IRQ entries	 *  in the MP table. To prevent the PCI interrupts from being set up	 *  incorrectly, we try to use the ELCR. The sanity check to see if	 *  there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can	 *  never be level sensitive, so we simply see if the ELCR agrees.	 *  If it does, we assume it's valid.	 */	if (mpc_default_type == 5) {		printk(KERN_INFO "ISA/PCI bus type with no IRQ information... falling back to ELCR\n");		if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13))			printk(KERN_WARNING "ELCR contains invalid data... not using ELCR\n");		else {			printk(KERN_INFO "Using ELCR to identify PCI interrupts\n");			ELCR_fallback = 1;		}	}	for (i = 0; i < 16; i++) {		switch (mpc_default_type) {		case 2:			if (i == 0 || i == 13)				continue;	/* IRQ0 & IRQ13 not connected */			/* fall through */		default:			if (i == 2)				continue;	/* IRQ2 is never connected */		}		if (ELCR_fallback) {			/*			 *  If the ELCR indicates a level-sensitive interrupt, we			 *  copy that information over to the MP table in the			 *  irqflag field (level sensitive, active high polarity).			 */			if (ELCR_trigger(i))				intsrc.mpc_irqflag = 13;			else				intsrc.mpc_irqflag = 0;		}		intsrc.mpc_srcbusirq = i;		intsrc.mpc_dstirq = i ? i : 2;		/* IRQ0 to INTIN2 */		MP_intsrc_info(&intsrc);	}	intsrc.mpc_irqtype = mp_ExtINT;	intsrc.mpc_srcbusirq = 0;	intsrc.mpc_dstirq = 0;				/* 8259A to INTIN0 */	MP_intsrc_info(&intsrc);}static inline void __init construct_default_ISA_mptable(int mpc_default_type)

⌨️ 快捷键说明

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