📄 mpparse_64.c
字号:
/* * 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/delay.h>#include <linux/bootmem.h>#include <linux/kernel_stat.h>#include <linux/mc146818rtc.h>#include <linux/acpi.h>#include <linux/module.h>#include <asm/smp.h>#include <asm/mtrr.h>#include <asm/mpspec.h>#include <asm/pgalloc.h>#include <asm/io_apic.h>#include <asm/proto.h>#include <asm/acpi.h>/* Have we found an MP table */int smp_found_config;/* * Various Linux-internal data structures created from the * MP-table. */DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };static int mp_current_pci_id = 0;/* 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;unsigned long mp_lapic_addr = 0;/* Processor that is doing the boot up */unsigned int boot_cpu_id = -1U;EXPORT_SYMBOL(boot_cpu_id);/* Internal processor count */unsigned int num_processors __cpuinitdata = 0;unsigned disabled_cpus __cpuinitdata;/* Bitmask of physically existing CPUs */physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE;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;}static void __cpuinit MP_processor_info(struct mpc_config_processor *m){ int cpu; cpumask_t tmp_map; char *bootup_cpu = ""; if (!(m->mpc_cpuflag & CPU_ENABLED)) { disabled_cpus++; return; } if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { bootup_cpu = " (Bootup-CPU)"; boot_cpu_id = m->mpc_apicid; } printk(KERN_INFO "Processor #%d%s\n", m->mpc_apicid, bootup_cpu); if (num_processors >= NR_CPUS) { printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." " Processor ignored.\n", NR_CPUS); return; } num_processors++; cpus_complement(tmp_map, cpu_present_map); cpu = first_cpu(tmp_map); physid_set(m->mpc_apicid, phys_cpu_present_map); if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { /* * bios_cpu_apicid is required to have processors listed * in same order as logical cpu numbers. Hence the first * entry is BSP, and so on. */ cpu = 0; } bios_cpu_apicid[cpu] = m->mpc_apicid; /* * We get called early in the the start_kernel initialization * process when the per_cpu data area is not yet setup, so we * use a static array that is removed after the per_cpu data * area is created. */ if (x86_cpu_to_apicid_ptr) { u8 *x86_cpu_to_apicid = (u8 *)x86_cpu_to_apicid_ptr; x86_cpu_to_apicid[cpu] = m->mpc_apicid; } else { per_cpu(x86_cpu_to_apicid, cpu) = m->mpc_apicid; } cpu_set(cpu, cpu_possible_map); cpu_set(cpu, cpu_present_map);}static void __init MP_bus_info (struct mpc_config_bus *m){ char str[7]; memcpy(str, m->mpc_bustype, 6); str[6] = 0; Dprintk("Bus #%d is %s\n", m->mpc_busid, str); if (strncmp(str, "ISA", 3) == 0) { set_bit(m->mpc_busid, mp_bus_not_pci); } else if (strncmp(str, "PCI", 3) == 0) { clear_bit(m->mpc_busid, mp_bus_not_pci); mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; mp_current_pci_id++; } else { printk(KERN_ERR "Unknown bustype %s\n", str); }}static int bad_ioapic(unsigned long address){ if (nr_ioapics >= MAX_IO_APICS) { printk(KERN_ERR "ERROR: 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 (!address) { printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" " found in table, skipping!\n"); return 1; } return 0;}static void __init MP_ioapic_info (struct mpc_config_ioapic *m){ if (!(m->mpc_flags & MPC_APIC_USABLE)) return; printk("I/O APIC #%d at 0x%X.\n", m->mpc_apicid, m->mpc_apicaddr); if (bad_ioapic(m->mpc_apicaddr)) 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);}/* * Read/parse the MPC */static int __init smp_read_mpc(struct mp_config_table *mpc){ char str[16]; int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { printk("MPTABLE: bad signature [%c%c%c%c]!\n", mpc->mpc_signature[0], mpc->mpc_signature[1], mpc->mpc_signature[2], mpc->mpc_signature[3]); return 0; } if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) { printk("MPTABLE: checksum error!\n"); return 0; } if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { printk(KERN_ERR "MPTABLE: bad table version (%d)!!\n", mpc->mpc_spec); return 0; } if (!mpc->mpc_lapic) { printk(KERN_ERR "MPTABLE: null local APIC address!\n"); return 0; } memcpy(str,mpc->mpc_oem,8); str[8] = 0; printk(KERN_INFO "MPTABLE: OEM ID: %s ",str); memcpy(str,mpc->mpc_productid,12); str[12] = 0; printk("MPTABLE: Product ID: %s ",str); printk("MPTABLE: APIC at: 0x%X\n",mpc->mpc_lapic); /* save the local APIC address, it might be non-default */ if (!acpi_lapic) mp_lapic_addr = mpc->mpc_lapic; /* * Now process the configuration blocks. */ while (count < mpc->mpc_length) { switch(*mpt) { case MP_PROCESSOR: { struct mpc_config_processor *m= (struct mpc_config_processor *)mpt; 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; } } } setup_apic_routing(); if (!num_processors) printk(KERN_ERR "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_ERR "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){ struct mpc_config_processor processor; struct mpc_config_bus bus; struct mpc_config_ioapic ioapic; struct mpc_config_lintsrc lintsrc; int linttypes[2] = { mp_ExtINT, mp_NMI }; int i; /* * local APIC has default address */ mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; /* * 2 CPUs, numbered 0 & 1. */ processor.mpc_type = MP_PROCESSOR; processor.mpc_apicver = 0; processor.mpc_cpuflag = CPU_ENABLED; processor.mpc_cpufeature = 0; processor.mpc_featureflag = 0; processor.mpc_reserved[0] = 0; processor.mpc_reserved[1] = 0; for (i = 0; i < 2; i++) { processor.mpc_apicid = i; MP_processor_info(&processor); } bus.mpc_type = MP_BUS; bus.mpc_busid = 0; switch (mpc_default_type) { default: printk(KERN_ERR "???\nUnknown standard configuration %d\n", mpc_default_type); /* fall through */ case 1: case 5: memcpy(bus.mpc_bustype, "ISA ", 6); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -