diff options
Diffstat (limited to 'arch/x86/kernel/apic')
| -rw-r--r-- | arch/x86/kernel/apic/apic.c | 455 | ||||
| -rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 13 | 
2 files changed, 246 insertions, 222 deletions
| diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 29b5b18afa27..ad3639ae1b9b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -134,9 +134,6 @@ static inline void imcr_apic_to_pic(void)   */  static int force_enable_local_apic __initdata; -/* Control whether x2APIC mode is enabled or not */ -static bool nox2apic __initdata; -  /*   * APIC command line parameters   */ @@ -161,33 +158,6 @@ static __init int setup_apicpmtimer(char *s)  __setup("apicpmtimer", setup_apicpmtimer);  #endif -int x2apic_mode; -#ifdef CONFIG_X86_X2APIC -/* x2apic enabled before OS handover */ -int x2apic_preenabled; -static int x2apic_disabled; -static int __init setup_nox2apic(char *str) -{ -	if (x2apic_enabled()) { -		int apicid = native_apic_msr_read(APIC_ID); - -		if (apicid >= 255) { -			pr_warning("Apicid: %08x, cannot enforce nox2apic\n", -				   apicid); -			return 0; -		} - -		pr_warning("x2apic already enabled. will disable it\n"); -	} else -		setup_clear_cpu_cap(X86_FEATURE_X2APIC); - -	nox2apic = true; - -	return 0; -} -early_param("nox2apic", setup_nox2apic); -#endif -  unsigned long mp_lapic_addr;  int disable_apic;  /* Disable local APIC timer from the kernel commandline or via dmi quirk */ @@ -1475,7 +1445,7 @@ void setup_local_APIC(void)  #endif  } -void end_local_APIC_setup(void) +static void end_local_APIC_setup(void)  {  	lapic_setup_esr(); @@ -1492,116 +1462,183 @@ void end_local_APIC_setup(void)  	apic_pm_activate();  } -void __init bsp_end_local_APIC_setup(void) +/* + * APIC setup function for application processors. Called from smpboot.c + */ +void apic_ap_setup(void)  { +	setup_local_APIC();  	end_local_APIC_setup(); - -	/* -	 * Now that local APIC setup is completed for BP, configure the fault -	 * handling for interrupt remapping. -	 */ -	irq_remap_enable_fault_handling(); -  }  #ifdef CONFIG_X86_X2APIC -/* - * Need to disable xapic and x2apic at the same time and then enable xapic mode - */ -static inline void __disable_x2apic(u64 msr) -{ -	wrmsrl(MSR_IA32_APICBASE, -	       msr & ~(X2APIC_ENABLE | XAPIC_ENABLE)); -	wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE); -} +int x2apic_mode; -static __init void disable_x2apic(void) +enum { +	X2APIC_OFF, +	X2APIC_ON, +	X2APIC_DISABLED, +}; +static int x2apic_state; + +static inline void __x2apic_disable(void)  {  	u64 msr; -	if (!cpu_has_x2apic) +	if (cpu_has_apic)  		return;  	rdmsrl(MSR_IA32_APICBASE, msr); -	if (msr & X2APIC_ENABLE) { -		u32 x2apic_id = read_apic_id(); - -		if (x2apic_id >= 255) -			panic("Cannot disable x2apic, id: %08x\n", x2apic_id); +	if (!(msr & X2APIC_ENABLE)) +		return; +	/* Disable xapic and x2apic first and then reenable xapic mode */ +	wrmsrl(MSR_IA32_APICBASE, msr & ~(X2APIC_ENABLE | XAPIC_ENABLE)); +	wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE); +	printk_once(KERN_INFO "x2apic disabled\n"); +} -		pr_info("Disabling x2apic\n"); -		__disable_x2apic(msr); +static inline void __x2apic_enable(void) +{ +	u64 msr; -		if (nox2apic) { -			clear_cpu_cap(&cpu_data(0), X86_FEATURE_X2APIC); -			setup_clear_cpu_cap(X86_FEATURE_X2APIC); -		} +	rdmsrl(MSR_IA32_APICBASE, msr); +	if (msr & X2APIC_ENABLE) +		return; +	wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); +	printk_once(KERN_INFO "x2apic enabled\n"); +} -		x2apic_disabled = 1; -		x2apic_mode = 0; +static int __init setup_nox2apic(char *str) +{ +	if (x2apic_enabled()) { +		int apicid = native_apic_msr_read(APIC_ID); -		register_lapic_address(mp_lapic_addr); +		if (apicid >= 255) { +			pr_warning("Apicid: %08x, cannot enforce nox2apic\n", +				   apicid); +			return 0; +		} +		pr_warning("x2apic already enabled.\n"); +		__x2apic_disable();  	} +	setup_clear_cpu_cap(X86_FEATURE_X2APIC); +	x2apic_state = X2APIC_DISABLED; +	x2apic_mode = 0; +	return 0;  } +early_param("nox2apic", setup_nox2apic); -void check_x2apic(void) +/* Called from cpu_init() to enable x2apic on (secondary) cpus */ +void x2apic_setup(void)  { -	if (x2apic_enabled()) { -		pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); -		x2apic_preenabled = x2apic_mode = 1; +	/* +	 * If x2apic is not in ON state, disable it if already enabled +	 * from BIOS. +	 */ +	if (x2apic_state != X2APIC_ON) { +		__x2apic_disable(); +		return;  	} +	__x2apic_enable();  } -void enable_x2apic(void) +static __init void x2apic_disable(void)  { -	u64 msr; +	u32 x2apic_id; -	rdmsrl(MSR_IA32_APICBASE, msr); -	if (x2apic_disabled) { -		__disable_x2apic(msr); +	if (x2apic_state != X2APIC_ON) +		goto out; + +	x2apic_id = read_apic_id(); +	if (x2apic_id >= 255) +		panic("Cannot disable x2apic, id: %08x\n", x2apic_id); + +	__x2apic_disable(); +	register_lapic_address(mp_lapic_addr); +out: +	x2apic_state = X2APIC_DISABLED; +	x2apic_mode = 0; +} + +static __init void x2apic_enable(void) +{ +	if (x2apic_state != X2APIC_OFF)  		return; -	} -	if (!x2apic_mode) +	x2apic_mode = 1; +	x2apic_state = X2APIC_ON; +	__x2apic_enable(); +} + +static __init void try_to_enable_x2apic(int remap_mode) +{ +	if (x2apic_state == X2APIC_DISABLED)  		return; -	if (!(msr & X2APIC_ENABLE)) { -		printk_once(KERN_INFO "Enabling x2apic\n"); -		wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); +	if (remap_mode != IRQ_REMAP_X2APIC_MODE) { +		/* IR is required if there is APIC ID > 255 even when running +		 * under KVM +		 */ +		if (max_physical_apicid > 255 || +		    !hypervisor_x2apic_available()) { +			pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); +			x2apic_disable(); +			return; +		} + +		/* +		 * without IR all CPUs can be addressed by IOAPIC/MSI +		 * only in physical mode +		 */ +		x2apic_phys = 1;  	} +	x2apic_enable();  } -#endif /* CONFIG_X86_X2APIC */ -int __init enable_IR(void) +void __init check_x2apic(void)  { -#ifdef CONFIG_IRQ_REMAP -	if (!irq_remapping_supported()) { -		pr_debug("intr-remapping not supported\n"); -		return -1; +	if (x2apic_enabled()) { +		pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n"); +		x2apic_mode = 1; +		x2apic_state = X2APIC_ON; +	} else if (!cpu_has_x2apic) { +		x2apic_state = X2APIC_DISABLED;  	} +} +#else /* CONFIG_X86_X2APIC */ +static int __init validate_x2apic(void) +{ +	if (!apic_is_x2apic_enabled()) +		return 0; +	/* +	 * Checkme: Can we simply turn off x2apic here instead of panic? +	 */ +	panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); +} +early_initcall(validate_x2apic); -	if (!x2apic_preenabled && skip_ioapic_setup) { -		pr_info("Skipped enabling intr-remap because of skipping " -			"io-apic setup\n"); +static inline void try_to_enable_x2apic(int remap_mode) { } +static inline void __x2apic_enable(void) { } +#endif /* !CONFIG_X86_X2APIC */ + +static int __init try_to_enable_IR(void) +{ +#ifdef CONFIG_X86_IO_APIC +	if (!x2apic_enabled() && skip_ioapic_setup) { +		pr_info("Not enabling interrupt remapping due to skipped IO-APIC setup\n");  		return -1;  	} - -	return irq_remapping_enable();  #endif -	return -1; +	return irq_remapping_enable();  }  void __init enable_IR_x2apic(void)  {  	unsigned long flags; -	int ret, x2apic_enabled = 0; -	int hardware_init_ret; - -	/* Make sure irq_remap_ops are initialized */ -	setup_irq_remapping_ops(); +	int ret, ir_stat; -	hardware_init_ret = irq_remapping_prepare(); -	if (hardware_init_ret && !x2apic_supported()) +	ir_stat = irq_remapping_prepare(); +	if (ir_stat < 0 && !x2apic_supported())  		return;  	ret = save_ioapic_entries(); @@ -1614,49 +1651,13 @@ void __init enable_IR_x2apic(void)  	legacy_pic->mask_all();  	mask_ioapic_entries(); -	if (x2apic_preenabled && nox2apic) -		disable_x2apic(); - -	if (hardware_init_ret) -		ret = -1; -	else -		ret = enable_IR(); - -	if (!x2apic_supported()) -		goto skip_x2apic; - -	if (ret < 0) { -		/* IR is required if there is APIC ID > 255 even when running -		 * under KVM -		 */ -		if (max_physical_apicid > 255 || -		    !hypervisor_x2apic_available()) { -			if (x2apic_preenabled) -				disable_x2apic(); -			goto skip_x2apic; -		} -		/* -		 * without IR all CPUs can be addressed by IOAPIC/MSI -		 * only in physical mode -		 */ -		x2apic_force_phys(); -	} +	/* If irq_remapping_prepare() succeded, try to enable it */ +	if (ir_stat >= 0) +		ir_stat = try_to_enable_IR(); +	/* ir_stat contains the remap mode or an error code */ +	try_to_enable_x2apic(ir_stat); -	if (ret == IRQ_REMAP_XAPIC_MODE) { -		pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); -		goto skip_x2apic; -	} - -	x2apic_enabled = 1; - -	if (x2apic_supported() && !x2apic_mode) { -		x2apic_mode = 1; -		enable_x2apic(); -		pr_info("Enabled x2apic\n"); -	} - -skip_x2apic: -	if (ret < 0) /* IR enabling failed */ +	if (ir_stat < 0)  		restore_ioapic_entries();  	legacy_pic->restore_mask();  	local_irq_restore(flags); @@ -1847,82 +1848,8 @@ void __init register_lapic_address(unsigned long address)  	}  } -/* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. - */  int apic_version[MAX_LOCAL_APIC]; -int __init APIC_init_uniprocessor(void) -{ -	if (disable_apic) { -		pr_info("Apic disabled\n"); -		return -1; -	} -#ifdef CONFIG_X86_64 -	if (!cpu_has_apic) { -		disable_apic = 1; -		pr_info("Apic disabled by BIOS\n"); -		return -1; -	} -#else -	if (!smp_found_config && !cpu_has_apic) -		return -1; - -	/* -	 * Complain if the BIOS pretends there is one. -	 */ -	if (!cpu_has_apic && -	    APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { -		pr_err("BIOS bug, local APIC 0x%x not detected!...\n", -			boot_cpu_physical_apicid); -		return -1; -	} -#endif - -	default_setup_apic_routing(); - -	verify_local_APIC(); -	connect_bsp_APIC(); - -#ifdef CONFIG_X86_64 -	apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); -#else -	/* -	 * Hack: In case of kdump, after a crash, kernel might be booting -	 * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid -	 * might be zero if read from MP tables. Get it from LAPIC. -	 */ -# ifdef CONFIG_CRASH_DUMP -	boot_cpu_physical_apicid = read_apic_id(); -# endif -#endif -	physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); -	setup_local_APIC(); - -#ifdef CONFIG_X86_IO_APIC -	/* -	 * Now enable IO-APICs, actually call clear_IO_APIC -	 * We need clear_IO_APIC before enabling error vector -	 */ -	if (!skip_ioapic_setup && nr_ioapics) -		enable_IO_APIC(); -#endif - -	bsp_end_local_APIC_setup(); - -#ifdef CONFIG_X86_IO_APIC -	if (smp_found_config && !skip_ioapic_setup && nr_ioapics) -		setup_IO_APIC(); -	else { -		nr_ioapics = 0; -	} -#endif - -	x86_init.timers.setup_percpu_clockev(); -	return 0; -} -  /*   * Local APIC interrupts   */ @@ -2027,7 +1954,7 @@ __visible void smp_trace_error_interrupt(struct pt_regs *regs)  /**   * connect_bsp_APIC - attach the APIC to the interrupt system   */ -void __init connect_bsp_APIC(void) +static void __init connect_bsp_APIC(void)  {  #ifdef CONFIG_X86_32  	if (pic_mode) { @@ -2274,6 +2201,100 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v))  	}  } +static void __init apic_bsp_up_setup(void) +{ +#ifdef CONFIG_X86_64 +	apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); +#else +	/* +	 * Hack: In case of kdump, after a crash, kernel might be booting +	 * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid +	 * might be zero if read from MP tables. Get it from LAPIC. +	 */ +# ifdef CONFIG_CRASH_DUMP +	boot_cpu_physical_apicid = read_apic_id(); +# endif +#endif +	physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); +} + +/** + * apic_bsp_setup - Setup function for local apic and io-apic + * @upmode:		Force UP mode (for APIC_init_uniprocessor) + * + * Returns: + * apic_id of BSP APIC + */ +int __init apic_bsp_setup(bool upmode) +{ +	int id; + +	connect_bsp_APIC(); +	if (upmode) +		apic_bsp_up_setup(); +	setup_local_APIC(); + +	if (x2apic_mode) +		id = apic_read(APIC_LDR); +	else +		id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); + +	enable_IO_APIC(); +	end_local_APIC_setup(); +	irq_remap_enable_fault_handling(); +	setup_IO_APIC(); +	/* Setup local timer */ +	x86_init.timers.setup_percpu_clockev(); +	return id; +} + +/* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +int __init APIC_init_uniprocessor(void) +{ +	if (disable_apic) { +		pr_info("Apic disabled\n"); +		return -1; +	} +#ifdef CONFIG_X86_64 +	if (!cpu_has_apic) { +		disable_apic = 1; +		pr_info("Apic disabled by BIOS\n"); +		return -1; +	} +#else +	if (!smp_found_config && !cpu_has_apic) +		return -1; + +	/* +	 * Complain if the BIOS pretends there is one. +	 */ +	if (!cpu_has_apic && +	    APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { +		pr_err("BIOS bug, local APIC 0x%x not detected!...\n", +			boot_cpu_physical_apicid); +		return -1; +	} +#endif + +	if (!smp_found_config) +		disable_ioapic_support(); + +	default_setup_apic_routing(); +	verify_local_APIC(); +	apic_bsp_setup(true); +	return 0; +} + +#ifdef CONFIG_UP_LATE_INIT +void __init up_late_init(void) +{ +	APIC_init_uniprocessor(); +} +#endif +  /*   * Power management   */ @@ -2359,9 +2380,9 @@ static void lapic_resume(void)  	mask_ioapic_entries();  	legacy_pic->mask_all(); -	if (x2apic_mode) -		enable_x2apic(); -	else { +	if (x2apic_mode) { +		__x2apic_enable(); +	} else {  		/*  		 * Make sure the APICBASE points to the right address  		 * diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 3f5f60406ab1..f4dc2462a1ac 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1507,7 +1507,10 @@ void __init enable_IO_APIC(void)  	int i8259_apic, i8259_pin;  	int apic, pin; -	if (!nr_legacy_irqs()) +	if (skip_ioapic_setup) +		nr_ioapics = 0; + +	if (!nr_legacy_irqs() || !nr_ioapics)  		return;  	for_each_ioapic_pin(apic, pin) { @@ -2295,7 +2298,7 @@ static inline void __init check_timer(void)  	}  	local_irq_disable();  	apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n"); -	if (x2apic_preenabled) +	if (apic_is_x2apic_enabled())  		apic_printk(APIC_QUIET, KERN_INFO  			    "Perhaps problem with the pre-enabled x2apic mode\n"  			    "Try booting with x2apic and interrupt-remapping disabled in the bios.\n"); @@ -2373,9 +2376,9 @@ void __init setup_IO_APIC(void)  {  	int ioapic; -	/* -	 * calling enable_IO_APIC() is moved to setup_local_APIC for BP -	 */ +	if (skip_ioapic_setup || !nr_ioapics) +		return; +  	io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL;  	apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); |