mpparse.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,165 行 · 第 1/3 页
C
1,165 行
/* * 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;static 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; /* * 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++; /* * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y * but we need to work other dependencies like SMP_SUSPEND etc * before this can be done without some confusion. * if (CPU_HOTPLUG_ENABLED || num_processors > 8) * - Ashok Raj <ashok.raj@intel.com> */ if (num_processors > 8) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: if (!APIC_XAPIC(ver)) { def_to_bigsmp = 0; break; } /* If P4 and above fall through */ case X86_VENDOR_AMD: def_to_bigsmp = 1; } } 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 (m->mpc_busid >= MAX_MP_BUSSES) { printk(KERN_WARNING "MP table busid value (%d) for bustype %s " " is too large, max. supported is %d\n", m->mpc_busid, str, MAX_MP_BUSSES - 1); return; } 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];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?