Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 112658
b: refs/heads/master
c: 6e1cb38
h: refs/heads/master
v: v3
  • Loading branch information
Suresh Siddha authored and Ingo Molnar committed Jul 12, 2008
1 parent 63d3931 commit e7b72c9
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 75c46fa61bc5b4ccd20a168ff325c58771248fcd
refs/heads/master: 6e1cb38a2aef7680975e71f23de187859ee8b158
2 changes: 2 additions & 0 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,8 @@ and is between 256 and 4096 characters. It is defined in the file

nolapic_timer [X86-32,APIC] Do not use the local APIC timer.

nox2apic [X86-64,APIC] Do not enable x2APIC mode.

noltlbs [PPC] Do not use large page/tlb entries for kernel
lowmem mapping on PPC40x.

Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/x86/kernel/acpi/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,9 @@ static void __init acpi_process_madt(void)
acpi_ioapic = 1;

smp_found_config = 1;
#ifdef CONFIG_X86_32
setup_apic_routing();
#endif
}
}
if (error == -EINVAL) {
Expand Down
154 changes: 150 additions & 4 deletions trunk/arch/x86/kernel/apic_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/clockchips.h>
#include <linux/acpi_pmtmr.h>
#include <linux/module.h>
#include <linux/dmar.h>

#include <asm/atomic.h>
#include <asm/smp.h>
Expand All @@ -39,15 +40,20 @@
#include <asm/proto.h>
#include <asm/timex.h>
#include <asm/apic.h>
#include <asm/i8259.h>

#include <mach_ipi.h>
#include <mach_apic.h>

static int disable_apic_timer __cpuinitdata;
static int apic_calibrate_pmtmr __initdata;
int disable_apic;
int disable_x2apic;
int x2apic;

/* x2apic enabled before OS handover */
int x2apic_preenabled;

/* Local APIC timer works in C2 */
int local_apic_timer_c2_ok;
EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
Expand Down Expand Up @@ -896,6 +902,125 @@ void __cpuinit end_local_APIC_setup(void)
apic_pm_activate();
}

void check_x2apic(void)
{
int msr, msr2;

rdmsr(MSR_IA32_APICBASE, msr, msr2);

if (msr & X2APIC_ENABLE) {
printk("x2apic enabled by BIOS, switching to x2apic ops\n");
x2apic_preenabled = x2apic = 1;
apic_ops = &x2apic_ops;
}
}

void enable_x2apic(void)
{
int msr, msr2;

rdmsr(MSR_IA32_APICBASE, msr, msr2);
if (!(msr & X2APIC_ENABLE)) {
printk("Enabling x2apic\n");
wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
}
}

void enable_IR_x2apic(void)
{
#ifdef CONFIG_INTR_REMAP
int ret;
unsigned long flags;

if (!cpu_has_x2apic)
return;

if (!x2apic_preenabled && disable_x2apic) {
printk(KERN_INFO
"Skipped enabling x2apic and Interrupt-remapping "
"because of nox2apic\n");
return;
}

if (x2apic_preenabled && disable_x2apic)
panic("Bios already enabled x2apic, can't enforce nox2apic");

if (!x2apic_preenabled && skip_ioapic_setup) {
printk(KERN_INFO
"Skipped enabling x2apic and Interrupt-remapping "
"because of skipping io-apic setup\n");
return;
}

ret = dmar_table_init();
if (ret) {
printk(KERN_INFO
"dmar_table_init() failed with %d:\n", ret);

if (x2apic_preenabled)
panic("x2apic enabled by bios. But IR enabling failed");
else
printk(KERN_INFO
"Not enabling x2apic,Intr-remapping\n");
return;
}

local_irq_save(flags);
mask_8259A();
save_mask_IO_APIC_setup();

ret = enable_intr_remapping(1);

if (ret && x2apic_preenabled) {
local_irq_restore(flags);
panic("x2apic enabled by bios. But IR enabling failed");
}

if (ret)
goto end;

if (!x2apic) {
x2apic = 1;
apic_ops = &x2apic_ops;
enable_x2apic();
}
end:
if (ret)
/*
* IR enabling failed
*/
restore_IO_APIC_setup();
else
reinit_intr_remapped_IO_APIC(x2apic_preenabled);

unmask_8259A();
local_irq_restore(flags);

if (!ret) {
if (!x2apic_preenabled)
printk(KERN_INFO
"Enabled x2apic and interrupt-remapping\n");
else
printk(KERN_INFO
"Enabled Interrupt-remapping\n");
} else
printk(KERN_ERR
"Failed to enable Interrupt-remapping and x2apic\n");
#else
if (!cpu_has_x2apic)
return;

if (x2apic_preenabled)
panic("x2apic enabled prior OS handover,"
" enable CONFIG_INTR_REMAP");

printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
" and x2apic\n");
#endif

return;
}

/*
* Detect and enable local APICs on non-SMP boards.
* Original code written by Keir Fraser.
Expand Down Expand Up @@ -943,6 +1068,11 @@ void __init early_init_lapic_mapping(void)
*/
void __init init_apic_mappings(void)
{
if (x2apic) {
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
return;
}

/*
* If no local APIC can be found then set up a fake all
* zeroes page to simulate the local APIC and another
Expand Down Expand Up @@ -981,6 +1111,9 @@ int __init APIC_init_uniprocessor(void)
return -1;
}

enable_IR_x2apic();
setup_apic_routing();

verify_local_APIC();

connect_bsp_APIC();
Expand Down Expand Up @@ -1238,10 +1371,14 @@ static int lapic_resume(struct sys_device *dev)
maxlvt = lapic_get_maxlvt();

local_irq_save(flags);
rdmsr(MSR_IA32_APICBASE, l, h);
l &= ~MSR_IA32_APICBASE_BASE;
l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
wrmsr(MSR_IA32_APICBASE, l, h);
if (!x2apic) {
rdmsr(MSR_IA32_APICBASE, l, h);
l &= ~MSR_IA32_APICBASE_BASE;
l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
wrmsr(MSR_IA32_APICBASE, l, h);
} else
enable_x2apic();

apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
apic_write(APIC_ID, apic_pm_state.apic_id);
apic_write(APIC_DFR, apic_pm_state.apic_dfr);
Expand Down Expand Up @@ -1381,6 +1518,15 @@ __cpuinit int apic_is_clustered_box(void)
return (clusters > 2);
}

static __init int setup_nox2apic(char *str)
{
disable_x2apic = 1;
clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC);
return 0;
}
early_param("nox2apic", setup_nox2apic);


/*
* APIC command line parameters
*/
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/x86/kernel/cpu/common_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ void __cpuinit cpu_init(void)
barrier();

check_efer();
if (cpu != 0 && x2apic)
enable_x2apic();

/*
* set up and load the per-CPU TSS
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/x86/kernel/genapic_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/hardirq.h>
#include <linux/dmar.h>

#include <asm/smp.h>
#include <asm/ipi.h>
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/x86/kernel/mpparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
generic_bigsmp_probe();
#endif

#ifdef CONFIG_X86_32
setup_apic_routing();
#endif
if (!num_processors)
printk(KERN_ERR "MPTABLE: no processors registered!\n");
return num_processors;
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/x86/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,8 @@ void __init setup_arch(char **cmdline_p)
num_physpages = max_pfn;

check_efer();
if (cpu_has_x2apic)
check_x2apic();

/* How many end-of-memory variables you have, grandma! */
/* need this before calling reserve_initrd */
Expand Down
5 changes: 5 additions & 0 deletions trunk/arch/x86/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
current_thread_info()->cpu = 0; /* needed? */
set_cpu_sibling_map(0);

#ifdef CONFIG_X86_64
enable_IR_x2apic();
setup_apic_routing();
#endif

if (smp_sanity_check(max_cpus) < 0) {
printk(KERN_INFO "SMP disabled\n");
disable_smp();
Expand Down
5 changes: 5 additions & 0 deletions trunk/include/asm-x86/apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ extern void apic_wait_icr_idle(void);
extern u32 safe_apic_wait_icr_idle(void);
extern void apic_icr_write(u32 low, u32 id);
#else
extern int x2apic, x2apic_preenabled;
extern void check_x2apic(void);
extern void enable_x2apic(void);
extern void enable_IR_x2apic(void);
extern void x2apic_icr_write(u32 low, u32 id);

struct apic_ops {
u32 (*read)(u32 reg);
Expand Down

0 comments on commit e7b72c9

Please sign in to comment.