diff options
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
| -rw-r--r-- | arch/x86/kernel/apic/apic.c | 159 | 
1 files changed, 87 insertions, 72 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 06c196d7e59c..966673f44141 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -43,6 +43,7 @@  #include <asm/i8259.h>  #include <asm/proto.h>  #include <asm/apic.h> +#include <asm/io_apic.h>  #include <asm/desc.h>  #include <asm/hpet.h>  #include <asm/idle.h> @@ -78,12 +79,21 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);  EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid);  #ifdef CONFIG_X86_32 + +/* + * On x86_32, the mapping between cpu and logical apicid may vary + * depending on apic in use.  The following early percpu variable is + * used for the mapping.  This is where the behaviors of x86_64 and 32 + * actually diverge.  Let's keep it ugly for now. + */ +DEFINE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid, BAD_APICID); +  /*   * Knob to control our willingness to enable the local APIC.   *   * +1=force-enable   */ -static int force_enable_local_apic; +static int force_enable_local_apic __initdata;  /*   * APIC command line parameters   */ @@ -153,7 +163,7 @@ early_param("nox2apic", setup_nox2apic);  unsigned long mp_lapic_addr;  int disable_apic;  /* Disable local APIC timer from the kernel commandline or via dmi quirk */ -static int disable_apic_timer __cpuinitdata; +static int disable_apic_timer __initdata;  /* Local APIC timer works in C2 */  int local_apic_timer_c2_ok;  EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); @@ -177,29 +187,8 @@ static struct resource lapic_resource = {  static unsigned int calibration_result; -static int lapic_next_event(unsigned long delta, -			    struct clock_event_device *evt); -static void lapic_timer_setup(enum clock_event_mode mode, -			      struct clock_event_device *evt); -static void lapic_timer_broadcast(const struct cpumask *mask);  static void apic_pm_activate(void); -/* - * The local apic timer can be used for any function which is CPU local. - */ -static struct clock_event_device lapic_clockevent = { -	.name		= "lapic", -	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT -			| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, -	.shift		= 32, -	.set_mode	= lapic_timer_setup, -	.set_next_event	= lapic_next_event, -	.broadcast	= lapic_timer_broadcast, -	.rating		= 100, -	.irq		= -1, -}; -static DEFINE_PER_CPU(struct clock_event_device, lapic_events); -  static unsigned long apic_phys;  /* @@ -238,7 +227,7 @@ static int modern_apic(void)   * right after this call apic become NOOP driven   * so apic->write/read doesn't do anything   */ -void apic_disable(void) +static void __init apic_disable(void)  {  	pr_info("APIC: switched to apic NOOP\n");  	apic = &apic_noop; @@ -282,23 +271,6 @@ u64 native_apic_icr_read(void)  	return icr1 | ((u64)icr2 << 32);  } -/** - * enable_NMI_through_LVT0 - enable NMI through local vector table 0 - */ -void __cpuinit enable_NMI_through_LVT0(void) -{ -	unsigned int v; - -	/* unmask and set to NMI */ -	v = APIC_DM_NMI; - -	/* Level triggered for 82489DX (32bit mode) */ -	if (!lapic_is_integrated()) -		v |= APIC_LVT_LEVEL_TRIGGER; - -	apic_write(APIC_LVT0, v); -} -  #ifdef CONFIG_X86_32  /**   * get_physical_broadcast - Get number of physical broadcast IDs @@ -508,6 +480,23 @@ static void lapic_timer_broadcast(const struct cpumask *mask)  #endif  } + +/* + * The local apic timer can be used for any function which is CPU local. + */ +static struct clock_event_device lapic_clockevent = { +	.name		= "lapic", +	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT +			| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, +	.shift		= 32, +	.set_mode	= lapic_timer_setup, +	.set_next_event	= lapic_next_event, +	.broadcast	= lapic_timer_broadcast, +	.rating		= 100, +	.irq		= -1, +}; +static DEFINE_PER_CPU(struct clock_event_device, lapic_events); +  /*   * Setup the local APIC timer for this CPU. Copy the initialized values   * of the boot CPU and register the clock event in the framework. @@ -1209,7 +1198,7 @@ void __cpuinit setup_local_APIC(void)  		rdtscll(tsc);  	if (disable_apic) { -		arch_disable_smp_support(); +		disable_ioapic_support();  		return;  	} @@ -1237,6 +1226,19 @@ void __cpuinit setup_local_APIC(void)  	 */  	apic->init_apic_ldr(); +#ifdef CONFIG_X86_32 +	/* +	 * APIC LDR is initialized.  If logical_apicid mapping was +	 * initialized during get_smp_config(), make sure it matches the +	 * actual value. +	 */ +	i = early_per_cpu(x86_cpu_to_logical_apicid, cpu); +	WARN_ON(i != BAD_APICID && i != logical_smp_processor_id()); +	/* always use the value from LDR */ +	early_per_cpu(x86_cpu_to_logical_apicid, cpu) = +		logical_smp_processor_id(); +#endif +  	/*  	 * Set Task Priority to 'accept all'. We never change this  	 * later on. @@ -1381,12 +1383,17 @@ void __cpuinit end_local_APIC_setup(void)  #endif  	apic_pm_activate(); +} + +void __init bsp_end_local_APIC_setup(void) +{ +	end_local_APIC_setup();  	/*  	 * Now that local APIC setup is completed for BP, configure the fault  	 * handling for interrupt remapping.  	 */ -	if (!smp_processor_id() && intr_remapping_enabled) +	if (intr_remapping_enabled)  		enable_drhd_fault_handling();  } @@ -1443,7 +1450,7 @@ int __init enable_IR(void)  void __init enable_IR_x2apic(void)  {  	unsigned long flags; -	struct IO_APIC_route_entry **ioapic_entries = NULL; +	struct IO_APIC_route_entry **ioapic_entries;  	int ret, x2apic_enabled = 0;  	int dmar_table_init_ret; @@ -1532,7 +1539,7 @@ static int __init detect_init_APIC(void)  }  #else -static int apic_verify(void) +static int __init apic_verify(void)  {  	u32 features, h, l; @@ -1557,7 +1564,7 @@ static int apic_verify(void)  	return 0;  } -int apic_force_enable(void) +int __init apic_force_enable(unsigned long addr)  {  	u32 h, l; @@ -1573,7 +1580,7 @@ int apic_force_enable(void)  	if (!(l & MSR_IA32_APICBASE_ENABLE)) {  		pr_info("Local APIC disabled by BIOS -- reenabling.\n");  		l &= ~MSR_IA32_APICBASE_BASE; -		l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; +		l |= MSR_IA32_APICBASE_ENABLE | addr;  		wrmsr(MSR_IA32_APICBASE, l, h);  		enabled_via_apicbase = 1;  	} @@ -1614,7 +1621,7 @@ static int __init detect_init_APIC(void)  				"you can enable it with \"lapic\"\n");  			return -1;  		} -		if (apic_force_enable()) +		if (apic_force_enable(APIC_DEFAULT_PHYS_BASE))  			return -1;  	} else {  		if (apic_verify()) @@ -1756,7 +1763,7 @@ int __init APIC_init_uniprocessor(void)  		enable_IO_APIC();  #endif -	end_local_APIC_setup(); +	bsp_end_local_APIC_setup();  #ifdef CONFIG_X86_IO_APIC  	if (smp_found_config && !skip_ioapic_setup && nr_ioapics) @@ -1925,17 +1932,6 @@ void __cpuinit generic_processor_info(int apicid, int version)  {  	int cpu; -	/* -	 * Validate version -	 */ -	if (version == 0x0) { -		pr_warning("BIOS bug, APIC version is 0 for CPU#%d! " -			   "fixing up to 0x10. (tell your hw vendor)\n", -				version); -		version = 0x10; -	} -	apic_version[apicid] = version; -  	if (num_processors >= nr_cpu_ids) {  		int max = nr_cpu_ids;  		int thiscpu = max + disabled_cpus; @@ -1949,22 +1945,34 @@ void __cpuinit generic_processor_info(int apicid, int version)  	}  	num_processors++; -	cpu = cpumask_next_zero(-1, cpu_present_mask); - -	if (version != apic_version[boot_cpu_physical_apicid]) -		WARN_ONCE(1, -			"ACPI: apic version mismatch, bootcpu: %x cpu %d: %x\n", -			apic_version[boot_cpu_physical_apicid], cpu, version); - -	physid_set(apicid, phys_cpu_present_map);  	if (apicid == boot_cpu_physical_apicid) {  		/*  		 * x86_bios_cpu_apicid is required to have processors listed  		 * in same order as logical cpu numbers. Hence the first  		 * entry is BSP, and so on. +		 * boot_cpu_init() already hold bit 0 in cpu_present_mask +		 * for BSP.  		 */  		cpu = 0; +	} else +		cpu = cpumask_next_zero(-1, cpu_present_mask); + +	/* +	 * Validate version +	 */ +	if (version == 0x0) { +		pr_warning("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n", +			   cpu, apicid); +		version = 0x10;  	} +	apic_version[apicid] = version; + +	if (version != apic_version[boot_cpu_physical_apicid]) { +		pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", +			apic_version[boot_cpu_physical_apicid], cpu, version); +	} + +	physid_set(apicid, phys_cpu_present_map);  	if (apicid > max_physical_apicid)  		max_physical_apicid = apicid; @@ -1972,7 +1980,10 @@ void __cpuinit generic_processor_info(int apicid, int version)  	early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;  	early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid;  #endif - +#ifdef CONFIG_X86_32 +	early_per_cpu(x86_cpu_to_logical_apicid, cpu) = +		apic->x86_32_early_logical_apicid(cpu); +#endif  	set_cpu_possible(cpu, true);  	set_cpu_present(cpu, true);  } @@ -1993,10 +2004,14 @@ void default_init_apic_ldr(void)  }  #ifdef CONFIG_X86_32 -int default_apicid_to_node(int logical_apicid) +int default_x86_32_numa_cpu_node(int cpu)  { -#ifdef CONFIG_SMP -	return apicid_2_node[hard_smp_processor_id()]; +#ifdef CONFIG_NUMA +	int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); + +	if (apicid != BAD_APICID) +		return __apicid_to_node[apicid]; +	return NUMA_NO_NODE;  #else  	return 0;  #endif  | 
