// SPDX-License-Identifier: GPL-2.0/* * Intel Multiprocessor Specification 1.1 and 1.4 * compliant MP-table parsing routines. * * (c) 1995 Alan Cox, Building #3 <alan@lxorguk.ukuu.org.uk> * (c) 1998, 1999, 2000, 2009 Ingo Molnar <mingo@redhat.com> * (c) 2008 Alexey Starikovskiy <astarikovskiy@suse.de> */ #include <linux/mm.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/memblock.h>#include <linux/kernel_stat.h>#include <linux/mc146818rtc.h>#include <linux/bitops.h>#include <linux/acpi.h>#include <linux/smp.h>#include <linux/pci.h> #include <asm/i8259.h>#include <asm/io_apic.h>#include <asm/acpi.h>#include <asm/irqdomain.h>#include <asm/mtrr.h>#include <asm/mpspec.h>#include <asm/proto.h>#include <asm/bios_ebda.h>#include <asm/e820/api.h>#include <asm/setup.h>#include <asm/smp.h> #include <asm/apic.h>/* * Checksum an MP configuration block. */ static unsigned int num_procs __initdata; static int __init mpf_checksum(unsigned char *mp, int len){ int sum = 0; while (len--) sum += *mp++; return sum & 0xFF;} static void __init MP_processor_info(struct mpc_cpu *m){ char *bootup_cpu = ""; topology_register_apic(m->apicid, CPU_ACPIID_INVALID, m->cpuflag & CPU_ENABLED); if (!(m->cpuflag & CPU_ENABLED)) return; if (m->cpuflag & CPU_BOOTPROCESSOR) bootup_cpu = " (Bootup-CPU)"; pr_info("Processor #%d%s\n", m->apicid, bootup_cpu); num_procs++;} #ifdef CONFIG_X86_IO_APICstatic void __init mpc_oem_bus_info(struct mpc_bus *m, char *str){ memcpy(str, m->bustype, 6); str[6] = 0; apic_pr_verbose("Bus #%d is %s\n", m->busid, str);} static void __init MP_bus_info(struct mpc_bus *m){ char str[7]; mpc_oem_bus_info(m, str); #if MAX_MP_BUSSES < 256 if (m->busid >= MAX_MP_BUSSES) { pr_warn("MP table busid value (%d) for bustype %s is too large, max. supported is %d\n", m->busid, str, MAX_MP_BUSSES - 1); return; }#endif set_bit(m->busid, mp_bus_not_pci); if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {#ifdef CONFIG_EISA mp_bus_id_to_type[m->busid] = MP_BUS_ISA;#endif } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) { clear_bit(m->busid, mp_bus_not_pci);#ifdef CONFIG_EISA mp_bus_id_to_type[m->busid] = MP_BUS_PCI; } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) { mp_bus_id_to_type[m->busid] = MP_BUS_EISA;#endif } else pr_warn("Unknown bustype %s - ignoring\n", str);} static void __init MP_ioapic_info(struct mpc_ioapic *m){ struct ioapic_domain_cfg cfg = { .type = IOAPIC_DOMAIN_LEGACY, .ops = &mp_ioapic_irqdomain_ops, }; if (m->flags & MPC_APIC_USABLE) mp_register_ioapic(m->apicid, m->apicaddr, gsi_top, &cfg);} static void __init print_mp_irq_info(struct mpc_intsrc *mp_irq){ apic_printk(APIC_VERBOSE, "Int: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC INT %02x\n", mp_irq->irqtype, mp_irq->irqflag & 3, (mp_irq->irqflag >> 2) & 3, mp_irq->srcbus, mp_irq->srcbusirq, mp_irq->dstapic, mp_irq->dstirq);} #else /* CONFIG_X86_IO_APIC */static inline void __init MP_bus_info(struct mpc_bus *m) {}static inline void __init MP_ioapic_info(struct mpc_ioapic *m) {}#endif /* CONFIG_X86_IO_APIC */ static void __init MP_lintsrc_info(struct mpc_lintsrc *m){ apic_printk(APIC_VERBOSE, "Lint: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC LINT %02x\n", m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbusid, m->srcbusirq, m->destapic, m->destapiclint);} /* * Read/parse the MPC */static int __init smp_check_mpc(struct mpc_table *mpc, char *oem, char *str){ if (memcmp(mpc->signature, MPC_SIGNATURE, 4)) { pr_err("MPTABLE: bad signature [%c%c%c%c]!\n", mpc->signature[0], mpc->signature[1], mpc->signature[2], mpc->signature[3]); return 0; } if (mpf_checksum((unsigned char *)mpc, mpc->length)) { pr_err("MPTABLE: checksum error!\n"); return 0; } if (mpc->spec != 0x01 && mpc->spec != 0x04) { pr_err("MPTABLE: bad table version (%d)!!\n", mpc->spec); return 0; } if (!mpc->lapic) { pr_err("MPTABLE: null local APIC address!\n"); return 0; } memcpy(oem, mpc->oem, 8); oem[8] = 0; pr_info("MPTABLE: OEM ID: %s\n", oem); memcpy(str, mpc->productid, 12); str[12] = 0; pr_info("MPTABLE: Product ID: %s\n", str); pr_info("MPTABLE: APIC at: 0x%X\n", mpc->lapic); return 1;} static void skip_entry(unsigned char **ptr, int *count, int size){ *ptr += size; *count += size;} static void __init smp_dump_mptable(struct mpc_table *mpc, unsigned char *mpt){ pr_err("Your mptable is wrong, contact your HW vendor!\n"); pr_cont("type %x\n", *mpt); print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_ADDRESS, 16, 1, mpc, mpc->length, 1);} static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early){ char str[16]; char oem[10]; int count = sizeof(*mpc); unsigned char *mpt = ((unsigned char *)mpc) + count; if (!smp_check_mpc(mpc, oem, str)) return 0; if (early) { /* Initialize the lapic mapping */ if (!acpi_lapic) register_lapic_address(mpc->lapic); return 1; } /* Now process the configuration blocks. */ while (count < mpc->length) { switch (*mpt) { case MP_PROCESSOR: /* ACPI may have already provided this data */ if (!acpi_lapic) MP_processor_info((struct mpc_cpu *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_cpu)); break; case MP_BUS: MP_bus_info((struct mpc_bus *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_bus)); break; case MP_IOAPIC: MP_ioapic_info((struct mpc_ioapic *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_ioapic)); break; case MP_INTSRC: mp_save_irq((struct mpc_intsrc *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_intsrc)); break; case MP_LINTSRC: MP_lintsrc_info((struct mpc_lintsrc *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_lintsrc)); break; default: /* wrong mptable */ smp_dump_mptable(mpc, mpt); count = mpc->length; break; } } if (!num_procs && !acpi_lapic) pr_err("MPTABLE: no processors registered!\n"); return num_procs || acpi_lapic;} #ifdef CONFIG_X86_IO_APIC static int __init ELCR_trigger(unsigned int irq){ unsigned int port; port = PIC_ELCR1 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1;} static void __init construct_default_ioirq_mptable(int mpc_default_type){ struct mpc_intsrc intsrc; int i; int ELCR_fallback = 0; intsrc.type = MP_INTSRC; intsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT; intsrc.srcbus = 0; intsrc.dstapic = mpc_ioapic_id(0); intsrc.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) { pr_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)) pr_err("ELCR contains invalid data... not using ELCR\n"); else { pr_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 */ fallthrough; 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.irqflag = MP_IRQTRIG_LEVEL | MP_IRQPOL_ACTIVE_HIGH; } else { intsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT; } } intsrc.srcbusirq = i; intsrc.dstirq = i ? i : 2; /* IRQ0 to INTIN2 */ mp_save_irq(&intsrc); } intsrc.irqtype = mp_ExtINT; intsrc.srcbusirq = 0; intsrc.dstirq = 0; /* 8259A to INTIN0 */ mp_save_irq(&intsrc);} static void __init construct_ioapic_table(int mpc_default_type){ struct mpc_ioapic ioapic; struct mpc_bus bus; bus.type = MP_BUS; bus.busid = 0; switch (mpc_default_type) { default: pr_err("???\nUnknown standard configuration %d\n", mpc_default_type); fallthrough; case 1: case 5: memcpy(bus.bustype, "ISA ", 6); break; case 2: case 6: case 3: memcpy(bus.bustype, "EISA ", 6); break; } MP_bus_info(&bus); if (mpc_default_type > 4) { bus.busid = 1; memcpy(bus.bustype, "PCI ", 6); MP_bus_info(&bus); } ioapic.type = MP_IOAPIC; ioapic.apicid = 2; ioapic.apicver = mpc_default_type > 4 ? 0x10 : 0x01; ioapic.flags = MPC_APIC_USABLE; ioapic.apicaddr = IO_APIC_DEFAULT_PHYS_BASE; MP_ioapic_info(&ioapic); /* * We set up most of the low 16 IO-APIC pins according to MPS rules. */ construct_default_ioirq_mptable(mpc_default_type);}#elsestatic inline void __init construct_ioapic_table(int mpc_default_type) { }#endif static inline void __init construct_default_ISA_mptable(int mpc_default_type){ struct mpc_cpu processor; struct mpc_lintsrc lintsrc; int linttypes[2] = { mp_ExtINT, mp_NMI }; int i; /* * 2 CPUs, numbered 0 & 1. */ processor.type = MP_PROCESSOR; /* Either an integrated APIC or a discrete 82489DX. */ processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01; processor.cpuflag = CPU_ENABLED; processor.cpufeature = (boot_cpu_data.x86 << 8) | (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping; processor.featureflag = boot_cpu_data.x86_capability[CPUID_1_EDX]; processor.reserved[0] = 0; processor.reserved[1] = 0; for (i = 0; i < 2; i++) { processor.apicid = i; MP_processor_info(&processor); } construct_ioapic_table(mpc_default_type); lintsrc.type = MP_LINTSRC; lintsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT; lintsrc.srcbusid = 0; lintsrc.srcbusirq = 0; lintsrc.destapic = MP_APIC_ALL; for (i = 0; i < 2; i++) { lintsrc.irqtype = linttypes[i]; lintsrc.destapiclint = i; MP_lintsrc_info(&lintsrc); }} static unsigned long mpf_base;static bool mpf_found; static unsigned long __init get_mpc_size(unsigned long physptr){ struct mpc_table *mpc; unsigned long size; mpc = early_memremap(physptr, PAGE_SIZE); size = mpc->length; early_memunmap(mpc, PAGE_SIZE); apic_pr_verbose(" mpc: %lx-%lx\n", physptr, physptr + size); return size;} static int __init check_physptr(struct mpf_intel *mpf, unsigned int early){ struct mpc_table *mpc; unsigned long size; size = get_mpc_size(mpf->physptr); mpc = early_memremap(mpf->physptr, size); /* * Read the physical hardware table. Anything here will * override the defaults. */ if (!smp_read_mpc(mpc, early)) {#ifdef CONFIG_X86_LOCAL_APIC smp_found_config = 0;#endif pr_err("BIOS bug, MP table errors detected!...\n"); pr_cont("... disabling SMP support. (tell your hw vendor)\n"); early_memunmap(mpc, size); return -1; } early_memunmap(mpc, size); if (early) return -1; #ifdef CONFIG_X86_IO_APIC /* * If there are no explicit MP IRQ entries, then we are * broken. We set up most of the low 16 IO-APIC pins to * ISA defaults and hope it will work. */ if (!mp_irq_entries) { struct mpc_bus bus; pr_err("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); bus.type = MP_BUS; bus.busid = 0; memcpy(bus.bustype, "ISA ", 6); MP_bus_info(&bus); construct_default_ioirq_mptable(0); }#endif return 0;} /* * Scan the memory blocks for an SMP configuration block. */static __init void mpparse_get_smp_config(unsigned int early){ struct mpf_intel *mpf; if (!smp_found_config) return; if (!mpf_found) return; if (acpi_lapic && early) return; /* * MPS doesn't support hyperthreading, aka only have * thread 0 apic id in MPS table */ if (acpi_lapic && acpi_ioapic) return; mpf = early_memremap(mpf_base, sizeof(*mpf)); if (!mpf) { pr_err("MPTABLE: error mapping MP table\n"); return;Lines 1–500 of 943. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Intel Multiprocessor Specification 1.1 and 1.4 * compliant MP-table parsing routines. * * (c) 1995 Alan Cox, Building #3 <alan@lxorguk.ukuu.org.uk> * (c) 1998, 1999, 2000, 2009 Ingo Molnar <mingo@redhat.com> * (c) 2008 Alexey Starikovskiy <astarikovskiy@suse.de> */ #include <linux/mm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/memblock.h> #include <linux/kernel_stat.h> #include <linux/mc146818rtc.h> #include <linux/bitops.h> #include <linux/acpi.h> #include <linux/smp.h> #include <linux/pci.h> #include <asm/i8259.h> #include <asm/io_apic.h> #include <asm/acpi.h> #include <asm/irqdomain.h> #include <asm/mtrr.h> #include <asm/mpspec.h> #include <asm/proto.h> #include <asm/bios_ebda.h> #include <asm/e820/api.h> #include <asm/setup.h> #include <asm/smp.h> #include <asm/apic.h> /* * Checksum an MP configuration block. */ static unsigned int num_procs __initdata; static int __init mpf_checksum(unsigned char *mp, int len) { int sum = 0; while (len--) sum += *mp++; return sum & 0xFF; } static void __init MP_processor_info(struct mpc_cpu *m) { char *bootup_cpu = ""; topology_register_apic(m->apicid, CPU_ACPIID_INVALID, m->cpuflag & CPU_ENABLED); if (!(m->cpuflag & CPU_ENABLED)) return; if (m->cpuflag & CPU_BOOTPROCESSOR) bootup_cpu = " (Bootup-CPU)"; pr_info("Processor #%d%s\n", m->apicid, bootup_cpu); num_procs++; } #ifdef CONFIG_X86_IO_APIC static void __init mpc_oem_bus_info(struct mpc_bus *m, char *str) { memcpy(str, m->bustype, 6); str[6] = 0; apic_pr_verbose("Bus #%d is %s\n", m->busid, str); } static void __init MP_bus_info(struct mpc_bus *m) { char str[7]; mpc_oem_bus_info(m, str); #if MAX_MP_BUSSES < 256 if (m->busid >= MAX_MP_BUSSES) { pr_warn("MP table busid value (%d) for bustype %s is too large, max. supported is %d\n", m->busid, str, MAX_MP_BUSSES - 1); return; } #endif set_bit(m->busid, mp_bus_not_pci); if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) { #ifdef CONFIG_EISA mp_bus_id_to_type[m->busid] = MP_BUS_ISA; #endif } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) { clear_bit(m->busid, mp_bus_not_pci); #ifdef CONFIG_EISA mp_bus_id_to_type[m->busid] = MP_BUS_PCI; } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) { mp_bus_id_to_type[m->busid] = MP_BUS_EISA; #endif } else pr_warn("Unknown bustype %s - ignoring\n", str); } static void __init MP_ioapic_info(struct mpc_ioapic *m) { struct ioapic_domain_cfg cfg = { .type = IOAPIC_DOMAIN_LEGACY, .ops = &mp_ioapic_irqdomain_ops, }; if (m->flags & MPC_APIC_USABLE) mp_register_ioapic(m->apicid, m->apicaddr, gsi_top, &cfg); } static void __init print_mp_irq_info(struct mpc_intsrc *mp_irq) { apic_printk(APIC_VERBOSE, "Int: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC INT %02x\n", mp_irq->irqtype, mp_irq->irqflag & 3, (mp_irq->irqflag >> 2) & 3, mp_irq->srcbus, mp_irq->srcbusirq, mp_irq->dstapic, mp_irq->dstirq); } #else /* CONFIG_X86_IO_APIC */ static inline void __init MP_bus_info(struct mpc_bus *m) {} static inline void __init MP_ioapic_info(struct mpc_ioapic *m) {} #endif /* CONFIG_X86_IO_APIC */ static void __init MP_lintsrc_info(struct mpc_lintsrc *m) { apic_printk(APIC_VERBOSE, "Lint: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC LINT %02x\n", m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbusid, m->srcbusirq, m->destapic, m->destapiclint); } /* * Read/parse the MPC */ static int __init smp_check_mpc(struct mpc_table *mpc, char *oem, char *str) { if (memcmp(mpc->signature, MPC_SIGNATURE, 4)) { pr_err("MPTABLE: bad signature [%c%c%c%c]!\n", mpc->signature[0], mpc->signature[1], mpc->signature[2], mpc->signature[3]); return 0; } if (mpf_checksum((unsigned char *)mpc, mpc->length)) { pr_err("MPTABLE: checksum error!\n"); return 0; } if (mpc->spec != 0x01 && mpc->spec != 0x04) { pr_err("MPTABLE: bad table version (%d)!!\n", mpc->spec); return 0; } if (!mpc->lapic) { pr_err("MPTABLE: null local APIC address!\n"); return 0; } memcpy(oem, mpc->oem, 8); oem[8] = 0; pr_info("MPTABLE: OEM ID: %s\n", oem); memcpy(str, mpc->productid, 12); str[12] = 0; pr_info("MPTABLE: Product ID: %s\n", str); pr_info("MPTABLE: APIC at: 0x%X\n", mpc->lapic); return 1; } static void skip_entry(unsigned char **ptr, int *count, int size) { *ptr += size; *count += size; } static void __init smp_dump_mptable(struct mpc_table *mpc, unsigned char *mpt) { pr_err("Your mptable is wrong, contact your HW vendor!\n"); pr_cont("type %x\n", *mpt); print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_ADDRESS, 16, 1, mpc, mpc->length, 1); } static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early) { char str[16]; char oem[10]; int count = sizeof(*mpc); unsigned char *mpt = ((unsigned char *)mpc) + count; if (!smp_check_mpc(mpc, oem, str)) return 0; if (early) { /* Initialize the lapic mapping */ if (!acpi_lapic) register_lapic_address(mpc->lapic); return 1; } /* Now process the configuration blocks. */ while (count < mpc->length) { switch (*mpt) { case MP_PROCESSOR: /* ACPI may have already provided this data */ if (!acpi_lapic) MP_processor_info((struct mpc_cpu *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_cpu)); break; case MP_BUS: MP_bus_info((struct mpc_bus *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_bus)); break; case MP_IOAPIC: MP_ioapic_info((struct mpc_ioapic *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_ioapic)); break; case MP_INTSRC: mp_save_irq((struct mpc_intsrc *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_intsrc)); break; case MP_LINTSRC: MP_lintsrc_info((struct mpc_lintsrc *)mpt); skip_entry(&mpt, &count, sizeof(struct mpc_lintsrc)); break; default: /* wrong mptable */ smp_dump_mptable(mpc, mpt); count = mpc->length; break; } } if (!num_procs && !acpi_lapic) pr_err("MPTABLE: no processors registered!\n"); return num_procs || acpi_lapic; } #ifdef CONFIG_X86_IO_APIC static int __init ELCR_trigger(unsigned int irq) { unsigned int port; port = PIC_ELCR1 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } static void __init construct_default_ioirq_mptable(int mpc_default_type) { struct mpc_intsrc intsrc; int i; int ELCR_fallback = 0; intsrc.type = MP_INTSRC; intsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT; intsrc.srcbus = 0; intsrc.dstapic = mpc_ioapic_id(0); intsrc.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) { pr_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)) pr_err("ELCR contains invalid data... not using ELCR\n"); else { pr_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 */ fallthrough; 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.irqflag = MP_IRQTRIG_LEVEL | MP_IRQPOL_ACTIVE_HIGH; } else { intsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT; } } intsrc.srcbusirq = i; intsrc.dstirq = i ? i : 2; /* IRQ0 to INTIN2 */ mp_save_irq(&intsrc); } intsrc.irqtype = mp_ExtINT; intsrc.srcbusirq = 0; intsrc.dstirq = 0; /* 8259A to INTIN0 */ mp_save_irq(&intsrc); } static void __init construct_ioapic_table(int mpc_default_type) { struct mpc_ioapic ioapic; struct mpc_bus bus; bus.type = MP_BUS; bus.busid = 0; switch (mpc_default_type) { default: pr_err("???\nUnknown standard configuration %d\n", mpc_default_type); fallthrough; case 1: case 5: memcpy(bus.bustype, "ISA ", 6); break; case 2: case 6: case 3: memcpy(bus.bustype, "EISA ", 6); break; } MP_bus_info(&bus); if (mpc_default_type > 4) { bus.busid = 1; memcpy(bus.bustype, "PCI ", 6); MP_bus_info(&bus); } ioapic.type = MP_IOAPIC; ioapic.apicid = 2; ioapic.apicver = mpc_default_type > 4 ? 0x10 : 0x01; ioapic.flags = MPC_APIC_USABLE; ioapic.apicaddr = IO_APIC_DEFAULT_PHYS_BASE; MP_ioapic_info(&ioapic); /* * We set up most of the low 16 IO-APIC pins according to MPS rules. */ construct_default_ioirq_mptable(mpc_default_type); } #else static inline void __init construct_ioapic_table(int mpc_default_type) { } #endif static inline void __init construct_default_ISA_mptable(int mpc_default_type) { struct mpc_cpu processor; struct mpc_lintsrc lintsrc; int linttypes[2] = { mp_ExtINT, mp_NMI }; int i; /* * 2 CPUs, numbered 0 & 1. */ processor.type = MP_PROCESSOR; /* Either an integrated APIC or a discrete 82489DX. */ processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01; processor.cpuflag = CPU_ENABLED; processor.cpufeature = (boot_cpu_data.x86 << 8) | (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping; processor.featureflag = boot_cpu_data.x86_capability[CPUID_1_EDX]; processor.reserved[0] = 0; processor.reserved[1] = 0; for (i = 0; i < 2; i++) { processor.apicid = i; MP_processor_info(&processor); } construct_ioapic_table(mpc_default_type); lintsrc.type = MP_LINTSRC; lintsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT; lintsrc.srcbusid = 0; lintsrc.srcbusirq = 0; lintsrc.destapic = MP_APIC_ALL; for (i = 0; i < 2; i++) { lintsrc.irqtype = linttypes[i]; lintsrc.destapiclint = i; MP_lintsrc_info(&lintsrc); } } static unsigned long mpf_base; static bool mpf_found; static unsigned long __init get_mpc_size(unsigned long physptr) { struct mpc_table *mpc; unsigned long size; mpc = early_memremap(physptr, PAGE_SIZE); size = mpc->length; early_memunmap(mpc, PAGE_SIZE); apic_pr_verbose(" mpc: %lx-%lx\n", physptr, physptr + size); return size; } static int __init check_physptr(struct mpf_intel *mpf, unsigned int early) { struct mpc_table *mpc; unsigned long size; size = get_mpc_size(mpf->physptr); mpc = early_memremap(mpf->physptr, size); /* * Read the physical hardware table. Anything here will * override the defaults. */ if (!smp_read_mpc(mpc, early)) { #ifdef CONFIG_X86_LOCAL_APIC smp_found_config = 0; #endif pr_err("BIOS bug, MP table errors detected!...\n"); pr_cont("... disabling SMP support. (tell your hw vendor)\n"); early_memunmap(mpc, size); return -1; } early_memunmap(mpc, size); if (early) return -1; #ifdef CONFIG_X86_IO_APIC /* * If there are no explicit MP IRQ entries, then we are * broken. We set up most of the low 16 IO-APIC pins to * ISA defaults and hope it will work. */ if (!mp_irq_entries) { struct mpc_bus bus; pr_err("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); bus.type = MP_BUS; bus.busid = 0; memcpy(bus.bustype, "ISA ", 6); MP_bus_info(&bus); construct_default_ioirq_mptable(0); } #endif return 0; } /* * Scan the memory blocks for an SMP configuration block. */ static __init void mpparse_get_smp_config(unsigned int early) { struct mpf_intel *mpf; if (!smp_found_config) return; if (!mpf_found) return; if (acpi_lapic && early) return; /* * MPS doesn't support hyperthreading, aka only have * thread 0 apic id in MPS table */ if (acpi_lapic && acpi_ioapic) return; mpf = early_memremap(mpf_base, sizeof(*mpf)); if (!mpf) { pr_err("MPTABLE: error mapping MP table\n"); return;