Commit 21add34f authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[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
parent ffdbfd52
...@@ -20,18 +20,15 @@ Machine check ...@@ -20,18 +20,15 @@ Machine check
APICs 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 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. 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 pirq=... See Documentation/i386/IO-APIC.txt
...@@ -60,13 +57,16 @@ Timing ...@@ -60,13 +57,16 @@ Timing
Report when timer interrupts are lost because some code turned off Report when timer interrupts are lost because some code turned off
interrupts for too long. interrupts for too long.
nmi_watchdog=NUMBER nmi_watchdog=NUMBER[,panic]
NUMBER can be: NUMBER can be:
0 don't use an NMI watchdog 0 don't use an NMI watchdog
1 use the IO-APIC timer for the 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 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 This will use one performance counter and the local APIC's performance
vector. 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 Idle loop
...@@ -127,6 +127,9 @@ NUMA ...@@ -127,6 +127,9 @@ NUMA
ACPI ACPI
acpi=off Don't enable 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 PCI
......
...@@ -46,10 +46,8 @@ ...@@ -46,10 +46,8 @@
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
extern int acpi_disabled;
int acpi_lapic = 0; int acpi_lapic = 0;
int acpi_ioapic = 0; int acpi_ioapic = 0;
extern int disable_apic;
#define PREFIX "ACPI: " #define PREFIX "ACPI: "
...@@ -316,7 +314,7 @@ acpi_boot_init (void) ...@@ -316,7 +314,7 @@ acpi_boot_init (void)
{ {
int result = 0; int result = 0;
if (acpi_disabled) if (acpi_disabled && !acpi_ht)
return 1; return 1;
/* /*
...@@ -339,9 +337,10 @@ acpi_boot_init (void) ...@@ -339,9 +337,10 @@ acpi_boot_init (void)
return result; 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; return 0;
}
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
...@@ -423,7 +422,7 @@ acpi_boot_init (void) ...@@ -423,7 +422,7 @@ acpi_boot_init (void)
/* /*
* if "noapic" boot option, don't look for IO-APICs * if "noapic" boot option, don't look for IO-APICs
*/ */
if (disable_apic) { if (skip_ioapic_setup) {
printk(KERN_INFO PREFIX "Skipping IOAPIC probe " printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
"due to 'noapic' option.\n"); "due to 'noapic' option.\n");
return 1; return 1;
......
...@@ -1023,8 +1023,11 @@ static __init int setup_noapictimer(char *str) ...@@ -1023,8 +1023,11 @@ static __init int setup_noapictimer(char *str)
return 0; return 0;
} }
/* dummy parsing: see setup.c */
__setup("disableapic", setup_disableapic); __setup("disableapic", setup_disableapic);
__setup("nolapic", setup_nolapic); /* same as disableapic, for compatibility */ __setup("nolapic", setup_nolapic); /* same as disableapic, for compatibility */
__setup("noapictimer", setup_noapictimer); __setup("noapictimer", setup_noapictimer);
/* no "lapic" flag - we only use the lapic when the BIOS tells us so. */ /* no "lapic" flag - we only use the lapic when the BIOS tells us so. */
...@@ -176,14 +176,79 @@ static void clear_IO_APIC (void) ...@@ -176,14 +176,79 @@ static void clear_IO_APIC (void)
int pirq_entries [MAX_PIRQS]; int pirq_entries [MAX_PIRQS];
int pirqs_enabled; int pirqs_enabled;
int skip_ioapic_setup; 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; skip_ioapic_setup = 1;
return 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 <asm/pci-direct.h>
#include <linux/pci_ids.h>
#include <linux/pci.h>
/* 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) static int __init ioapic_pirq_setup(char *str)
{ {
......
...@@ -65,6 +65,7 @@ unsigned long mmu_cr4_features; ...@@ -65,6 +65,7 @@ unsigned long mmu_cr4_features;
EXPORT_SYMBOL_GPL(mmu_cr4_features); EXPORT_SYMBOL_GPL(mmu_cr4_features);
int acpi_disabled = 0; int acpi_disabled = 0;
int acpi_ht = 0;
/* For PCI or other memory-mapped resources */ /* For PCI or other memory-mapped resources */
unsigned long pci_mem_start = 0x10000000; unsigned long pci_mem_start = 0x10000000;
...@@ -204,9 +205,24 @@ static __init void parse_cmdline_early (char ** cmdline_p) ...@@ -204,9 +205,24 @@ static __init void parse_cmdline_early (char ** cmdline_p)
acpi_disabled = 0; 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; 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)) if (!memcmp(from, "mem=", 4))
parse_memopt(from+4, &from); parse_memopt(from+4, &from);
...@@ -417,6 +433,13 @@ void __init setup_arch(char **cmdline_p) ...@@ -417,6 +433,13 @@ void __init setup_arch(char **cmdline_p)
#endif #endif
paging_init(); 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 #ifdef CONFIG_ACPI_BOOT
/* /*
* Initialize the ACPI boot-time table parser (gets the RSDP and SDT). * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
......
...@@ -70,7 +70,9 @@ extern void show_regs(struct pt_regs * regs); ...@@ -70,7 +70,9 @@ extern void show_regs(struct pt_regs * regs);
extern int map_syscall32(struct mm_struct *mm, unsigned long address); extern int map_syscall32(struct mm_struct *mm, unsigned long address);
extern char *syscall32_page; 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 max_mapnr;
extern unsigned long end_pfn; extern unsigned long end_pfn;
...@@ -81,6 +83,10 @@ extern int force_iommu, no_iommu; ...@@ -81,6 +83,10 @@ extern int force_iommu, no_iommu;
extern int using_apic_timer; extern int using_apic_timer;
extern int disable_apic; extern int disable_apic;
extern unsigned cpu_khz; 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_order;
extern int fallback_aper_force; extern int fallback_aper_force;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment