/* * Intel Multiprocessor Specification 1.1 and 1.4 * compliant MP-table parsing routines. * * (c) 1995 Alan Cox, Building #3 * (c) 1998, 1999, 2000 Ingo Molnar * * 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 #include #include #include #include #include #include #include #include /** * Points to the MP table, once and if it is found. * This gets initialized by find_mp_table(). */ static struct intel_mp_floating *mpf_found; /** * Physical CPU ID of the bootstrap CPU (the BP). */ unsigned int __initdata boot_phys_cpu_id = -1U; /** * The number of CPUs in the system. */ unsigned int __initdata num_cpus = 0; /** * Map of all CPUs present. * Bits set represent physical CPU IDs present. */ physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE; /** * Version information for every Local APIC in the system. * The array is indexed by APIC ID. */ unsigned char apic_version[MAX_APICS]; /** * MP Bus information */ static int mp_current_pci_id = 0; unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; /** * MP IO APIC information */ int nr_ioapics = 0; struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; /** * MP IRQ information */ int mp_irq_entries = 0; struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* TODO: move these */ int pic_mode; /** * Computes the checksum of an MP configuration block. */ static int __init mpf_checksum(unsigned char *mp, int len) { int sum = 0; while (len--) sum += *mp++; return sum & 0xFF; } /** * Parses an MP table CPU entry. */ static void __init MP_processor_info(struct mpc_config_processor *m) { int cpu; int is_bp; unsigned char ver; cpumask_t tmp_map; if (!(m->mpc_cpuflag & CPU_ENABLED)) panic("A disabled CPU was encountered\n"); /* Count the new CPU */ if (++num_cpus > NR_CPUS) panic("NR_CPUS limit of %i reached.\n", NR_CPUS); /* * Determine if this is the bootstrap processor... * the one responsible for booting the other CPUs. */ is_bp = (m->mpc_cpuflag & CPU_BOOTPROCESSOR); /* * Assign a logical CPU ID. * The bootstrap CPU is always assigned logical ID 0. * All other CPUs are assigned the lowest ID available. */ if (is_bp) { cpu = 0; } else { cpus_complement(tmp_map, cpu_present_map); cpu = first_cpu(tmp_map); } /* Validate APIC version, fixing up if necessary. */ ver = m->mpc_apicver; if (ver == 0x0) { printk(KERN_ERR "BIOS bug, APIC version is 0 for PhysCPU#%d! " "fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); ver = 0x10; } /* Remember the APIC's version */ apic_version[m->mpc_apicid] = ver; /* Add the CPU to the map of physical CPU IDs present. */ physid_set(m->mpc_apicid, phys_cpu_present_map); /* Remember the physical CPU ID of the bootstrap CPU. */ if (is_bp) boot_phys_cpu_id = m->mpc_apicid; /* Add the CPU to the map of logical CPU IDs present. */ cpu_set(cpu, cpu_present_map); /* Store ID information. */ cpu_info[cpu].logical_id = cpu; cpu_info[cpu].physical_id = m->mpc_apicid; cpu_info[cpu].arch.apic_id = m->mpc_apicid; printk(KERN_DEBUG "Physical CPU #%d -> Logical CPU #%d, %d:%d APIC version %d%s\n", m->mpc_apicid, cpu, (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, ver, is_bp ? " (Bootstrap CPU)" : ""); } /** * Parses an MP table BUS entry. */ static void __init MP_bus_info(struct mpc_config_bus *m) { char str[7]; memcpy(str, m->mpc_bustype, 6); str[6] = 0; printk(KERN_DEBUG "Bus #%d is %s\n", m->mpc_busid, str); if (strncmp(str, "ISA", 3) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; } else if (strncmp(str, "EISA", 4) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; } else if (strncmp(str, "PCI", 3) == 0) { 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, "MCA", 3) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; } else { printk(KERN_ERR "Unknown bustype %s\n", str); } } /** * Parses an MP table BUS entry. */ static void __init MP_ioapic_info(struct mpc_config_ioapic *m) { if (!(m->mpc_flags & MPC_APIC_USABLE)) { printk(KERN_DEBUG "Encountered unusable APIC, ignoring it.\n"); return; } printk(KERN_DEBUG "I/O APIC #%d Version %d at 0x%X\n", m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); if (nr_ioapics >= MAX_IO_APICS) { printk(KERN_ERR "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++; ioapic_id[ioapic_num] = m->mpc_apicid; ioapic_phys_addr[ioapic_num] = m->mpc_apicaddr; ioapic_num++; } /** * Parses an MP table IRQ source entry. */ static void __init MP_intsrc_info(struct mpc_config_intsrc *m) { mp_irqs [mp_irq_entries] = *m; printk(KERN_DEBUG "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"); } /** * Parses an MP table LINT entry. */ static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) { printk(KERN_DEBUG "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(); } /** * Parses the input MP table, storing various bits of information in global * variables as it goes. */ static int __init 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(KERN_ERR "SMP 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 -1; } if (mpf_checksum((unsigned char *)mpc, mpc->mpc_length)) { printk(KERN_ERR "SMP mptable: checksum error!\n"); return -1; } if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { printk(KERN_ERR "SMP mptable: bad table version (%d)!\n", mpc->mpc_spec); return -1; } if (!mpc->mpc_lapic) { printk(KERN_ERR "SMP mptable: null local APIC address!\n"); return -1; } memcpy(str, mpc->mpc_oem, 8); str[8]=0; printk(KERN_DEBUG " OEM ID: %s\n", str); memcpy(str, mpc->mpc_productid, 12); str[12]=0; printk(KERN_DEBUG " Product ID: %s\n", str); printk(KERN_DEBUG " APIC at: 0x%X\n", mpc->mpc_lapic); /* Save the local APIC address, it might be non-default. */ lapic_phys_addr = mpc->mpc_lapic; /* Now process all of the configuration blocks in the table. */ while (count < mpc->mpc_length) { switch(*mpt) { case MP_PROCESSOR: { struct mpc_config_processor *m= (struct mpc_config_processor *)mpt; 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; } } } //clustered_apic_check(); if (!num_cpus) printk(KERN_ERR "SMP mptable: no CPUs registered!\n"); return 0; } /** * Determines the multiprocessor configuration. * The configuration information is stored in global variables so nothing is * returned. find_mp_config() must be called before this function. */ void __init get_mp_config(void) { struct intel_mp_floating *mpf = mpf_found; if (!mpf) { printk(KERN_WARNING "Assuming 1 CPU.\n"); num_cpus = 1; /* Assign the only CPU logical=physical ID 0 */ cpu_set(0, cpu_present_map); physid_set(0, phys_cpu_present_map); cpu_info[0].logical_id = 0; cpu_info[0].physical_id = 0; cpu_info[0].arch.apic_id = 0; return; } printk(KERN_DEBUG "Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { printk(KERN_DEBUG " IMCR and PIC compatibility mode.\n"); pic_mode = 1; } else { printk(KERN_DEBUG " Virtual Wire compatibility mode.\n"); pic_mode = 0; } /* * We don't support the default MP configuration. * All supported multi-CPU systems must provide a full MP table. */ if (mpf->mpf_feature1 != 0) BUG(); if (!mpf->mpf_physptr) BUG(); /* * Set this early so we don't allocate CPU0 if the * MADT list doesn't list the bootstrap processor first. * The bootstrap processor has to be logical ID 0... which * we are reserving here. */ cpu_set(0, cpu_present_map); /* * Parse the MP configuration */ if (read_mpc(phys_to_virt(mpf->mpf_physptr))) panic("BIOS bug, MP table errors detected! (tell your hw vendor)\n"); } /** * Scans a region of memory for the MP table. */ static int __init scan(unsigned long base, unsigned long length) { unsigned int *bp = phys_to_virt(base); struct intel_mp_floating *mpf; printk(KERN_DEBUG "Scan for MP table from 0x%p for %ld bytes\n", bp, length); while (length > 0) { mpf = (struct intel_mp_floating *)bp; if ((*bp == SMP_MAGIC_IDENT) && (mpf->mpf_length == 1) && !mpf_checksum((unsigned char *)bp, 16) && ((mpf->mpf_specification == 1) || (mpf->mpf_specification == 4)) ) { reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); if (mpf->mpf_physptr) reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE); mpf_found = mpf; printk(KERN_DEBUG "Found MP table at: 0x%p\n", mpf); return 1; } bp += 4; length -= 16; } return 0; } /** * Locates the MP table, if there is one. * This does not parse the MP table... get_mp_config() does that. */ void __init find_mp_config(void) { /* * 1) Scan the bottom 1K for a signature * 2) Scan the top 1K of base RAM * 3) Scan the 64K of bios */ if (scan(0x0,0x400) || scan(639*0x400,0x400) || scan(0xF0000,0x10000)) return; /* * If it is an MP machine we should know now. * * If not, make a final effort and scan the * Extended BIOS Data Area. * * NOTE! There are Linux loaders that will corrupt the EBDA * area, and as such this kind of MP config may be less * trustworthy, simply because the MP table may have been * stomped on during early boot. These loaders are buggy and * should be fixed. */ if (scan(ebda_addr, 0x1000)) { printk(KERN_WARNING "MP table found in EBDA\n"); return; } /* If we have come this far, we did not find an MP table */ printk(KERN_DEBUG "No MP table found.\n"); }