From 21add34f66a10b14df51d208ed7a66f72a932df6 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 8 Oct 2003 01:55:24 -0700 Subject: [PATCH] [PATCH] APIC fixes for x86-64 Various APIC/ACPI fixes for x86-64. This brings us closer to working out of the box on the now popular VIA and NVidia Nforce3 based Athlon64 and Opteron boards. To be really good we would need more ACPI changes (still waiting for that to be all merged through the usual channels). With this we mostly work with acpi=off at least. Also it syncs us up with bugfixes done in 2.4. - Disable IO-APIC by default on non SMP VIA/NVidia boards. This is a bit of a hack, but needed to work around ACPI bugs. Can be overwriten with "apic". - Add acpi=ht, meaning run ACPI boot setup, but do not enable the interpreter. Same as i386. - Stop MADT parsing early when local APIC or IO-APIC are disabled - Add more option parsing early enough to actually change the boot process - Update documentation for command line options --- Documentation/x86_64/boot-options.txt | 23 +++++---- arch/x86_64/kernel/acpi/boot.c | 11 ++--- arch/x86_64/kernel/apic.c | 3 ++ arch/x86_64/kernel/io_apic.c | 69 ++++++++++++++++++++++++++- arch/x86_64/kernel/setup.c | 25 +++++++++- include/asm-x86_64/proto.h | 8 +++- 6 files changed, 119 insertions(+), 20 deletions(-) diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index b1c0e82005112..d1e4b1b333c6a 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -20,18 +20,15 @@ Machine check APICs - nolocalapic Don't use a local or IO-APIC. This should only - be needed if you have a buggy BIOS. The newer - kernels already turn it off by default if the - BIOS didn't enable the local APIC, so it will - be hopefully not needed. - Note this code path is not very well tested, you are on - your own. - apic Use IO-APIC. Default + Unless you have an NVidia or VIA/Uniprocessor board. + Then it defaults to off. noapic Don't use the IO-APIC. - Also only lightly tested. + + disableapic Don't use the local APIC + + nolapic Don't use the local APIC (alias for i386 compatibility) pirq=... See Documentation/i386/IO-APIC.txt @@ -60,13 +57,16 @@ Timing Report when timer interrupts are lost because some code turned off interrupts for too long. - nmi_watchdog=NUMBER + nmi_watchdog=NUMBER[,panic] NUMBER can be: 0 don't use an NMI watchdog 1 use the IO-APIC timer for the NMI watchdog 2 use the local APIC for the NMI watchdog using a performance counter. Note This will use one performance counter and the local APIC's performance vector. + When panic is specified panic when an NMI watchdog timeout occurs. + This is useful when you use a panic=... timeout and need the box + quickly up again. Idle loop @@ -127,6 +127,9 @@ NUMA ACPI acpi=off Don't enable ACPI + acpi=ht Use ACPI boot table parsing, but don't enable ACPI + interpreter + acpi=force Force ACPI on (currently not needed) PCI diff --git a/arch/x86_64/kernel/acpi/boot.c b/arch/x86_64/kernel/acpi/boot.c index b70eb8739913b..56aaf7859b645 100644 --- a/arch/x86_64/kernel/acpi/boot.c +++ b/arch/x86_64/kernel/acpi/boot.c @@ -46,10 +46,8 @@ #include #include -extern int acpi_disabled; int acpi_lapic = 0; int acpi_ioapic = 0; -extern int disable_apic; #define PREFIX "ACPI: " @@ -316,7 +314,7 @@ acpi_boot_init (void) { int result = 0; - if (acpi_disabled) + if (acpi_disabled && !acpi_ht) return 1; /* @@ -339,9 +337,10 @@ acpi_boot_init (void) return result; } - extern int disable_apic; - if (disable_apic) + if (disable_apic) { + printk(KERN_INFO PREFIX "Skipping MADT probe because local APIC is disabled\n"); return 0; + } #ifdef CONFIG_X86_LOCAL_APIC @@ -423,7 +422,7 @@ acpi_boot_init (void) /* * if "noapic" boot option, don't look for IO-APICs */ - if (disable_apic) { + if (skip_ioapic_setup) { printk(KERN_INFO PREFIX "Skipping IOAPIC probe " "due to 'noapic' option.\n"); return 1; diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index d7496edab8b2a..2610e64be2598 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -1023,8 +1023,11 @@ static __init int setup_noapictimer(char *str) return 0; } +/* dummy parsing: see setup.c */ + __setup("disableapic", setup_disableapic); __setup("nolapic", setup_nolapic); /* same as disableapic, for compatibility */ + __setup("noapictimer", setup_noapictimer); /* no "lapic" flag - we only use the lapic when the BIOS tells us so. */ diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 57c2cb01d4b08..65c7acadef464 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -176,14 +176,79 @@ static void clear_IO_APIC (void) int pirq_entries [MAX_PIRQS]; int pirqs_enabled; int skip_ioapic_setup; +int ioapic_force; -static int __init ioapic_setup(char *str) +/* dummy parsing: see setup.c */ + +static int __init disable_ioapic_setup(char *str) { skip_ioapic_setup = 1; return 1; } -__setup("noapic", ioapic_setup); +static int __init enable_ioapic_setup(char *str) +{ + ioapic_force = 1; + skip_ioapic_setup = 0; + return 1; +} + +__setup("noapic", disable_ioapic_setup); +__setup("apic", enable_ioapic_setup); + +#ifndef CONFIG_SMP +#include +#include +#include + +/* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC + off. Check for an Nvidia or VIA PCI bridge and turn it off. + Use pci direct infrastructure because this runs before the PCI subsystem. + + Can be overwritten with "apic" */ +void __init check_ioapic(void) +{ + int num,slot,func; + if (ioapic_force) + return; + + /* Poor man's PCI discovery */ + for (num = 0; num < 32; num++) { + for (slot = 0; slot < 32; slot++) { + for (func = 0; func < 8; func++) { + u32 class; + u32 vendor; + class = read_pci_config(num,slot,func, + PCI_CLASS_REVISION); + if (class == 0xffffffff) + break; + + if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) + continue; + + vendor = read_pci_config(num, slot, func, + PCI_VENDOR_ID); + vendor &= 0xffff; + switch (vendor) { + case PCI_VENDOR_ID_NVIDIA: + case PCI_VENDOR_ID_VIA: + printk(KERN_INFO + "PCI bridge %02x:%02x from %x found. Setting \"noapic\". Overwrite with \"apic\"\n", + num,slot,vendor); + skip_ioapic_setup = 1; + return; + } + + /* No multi-function device? */ + u8 type = read_pci_config_byte(num,slot,func, + PCI_HEADER_TYPE); + if (!(type & 0x80)) + break; + } + } + } +} +#endif static int __init ioapic_pirq_setup(char *str) { diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 2f9d157a4ac9a..2a5f5515d3ef9 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -65,6 +65,7 @@ unsigned long mmu_cr4_features; EXPORT_SYMBOL_GPL(mmu_cr4_features); int acpi_disabled = 0; +int acpi_ht = 0; /* For PCI or other memory-mapped resources */ unsigned long pci_mem_start = 0x10000000; @@ -204,9 +205,24 @@ static __init void parse_cmdline_early (char ** cmdline_p) acpi_disabled = 0; } - if (!memcmp(from, "disableapic", 11)) + /* acpi=ht just means: do ACPI MADT parsing + at bootup, but don't enable the full ACPI interpreter */ + if (!memcmp(from, "acpi=ht", 7)) { + acpi_ht = 1; + } + + if (!memcmp(from, "nolapic", 7) || + !memcmp(from, "disableapic", 11)) disable_apic = 1; + if (!memcmp(from, "noapic", 6)) + skip_ioapic_setup = 1; + + if (!memcmp(from, "apic", 6)) { + skip_ioapic_setup = 0; + ioapic_force = 1; + } + if (!memcmp(from, "mem=", 4)) parse_memopt(from+4, &from); @@ -417,6 +433,13 @@ void __init setup_arch(char **cmdline_p) #endif paging_init(); + +#ifndef CONFIG_SMP + /* Temporary hack: disable the IO-APIC for UP Nvidia and + This is until we sort out the ACPI problems. */ + if (!acpi_disabled) + check_ioapic(); +#endif #ifdef CONFIG_ACPI_BOOT /* * Initialize the ACPI boot-time table parser (gets the RSDP and SDT). diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index 5e176402f5c1f..87861e8ff4f92 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -70,7 +70,9 @@ extern void show_regs(struct pt_regs * regs); extern int map_syscall32(struct mm_struct *mm, unsigned long address); extern char *syscall32_page; -void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); +extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); + +extern void check_ioapic(void); extern unsigned long max_mapnr; extern unsigned long end_pfn; @@ -81,6 +83,10 @@ extern int force_iommu, no_iommu; extern int using_apic_timer; extern int disable_apic; extern unsigned cpu_khz; +extern int ioapic_force; +extern int skip_ioapic_setup; +extern int acpi_ht; +extern int acpi_disabled; extern int fallback_aper_order; extern int fallback_aper_force; -- 2.53.0