Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 APIC updates from Ingo Molnar:
 "Continued fallout of the conversion of the x86 IRQ code to the
  hierarchical irqdomain framework: more cleanups, simplifications,
  memory allocation behavior enhancements, mainly in the interrupt
  remapping and APIC code"

* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits)
  x86, init: Fix UP boot regression on x86_64
  iommu/amd: Fix irq remapping detection logic
  x86/acpi: Make acpi_[un]register_gsi_ioapic() depend on CONFIG_X86_LOCAL_APIC
  x86: Consolidate boot cpu timer setup
  x86/apic: Reuse apic_bsp_setup() for UP APIC setup
  x86/smpboot: Sanitize uniprocessor init
  x86/smpboot: Move apic init code to apic.c
  init: Get rid of x86isms
  x86/apic: Move apic_init_uniprocessor code
  x86/smpboot: Cleanup ioapic handling
  x86/apic: Sanitize ioapic handling
  x86/ioapic: Add proper checks to setp/enable_IO_APIC()
  x86/ioapic: Provide stub functions for IOAPIC%3Dn
  x86/smpboot: Move smpboot inlines to code
  x86/x2apic: Use state information for disable
  x86/x2apic: Split enable and setup function
  x86/x2apic: Disable x2apic from nox2apic setup
  x86/x2apic: Add proper state tracking
  x86/x2apic: Clarify remapping mode for x2apic enablement
  x86/x2apic: Move code in conditional region
  ...
This commit is contained in:
Linus Torvalds 2015-02-09 16:57:56 -08:00
commit 9d43bade34
18 changed files with 445 additions and 510 deletions

View File

@ -856,6 +856,10 @@ config SCHED_MC
source "kernel/Kconfig.preempt"
config UP_LATE_INIT
def_bool y
depends on !SMP && X86_LOCAL_APIC
config X86_UP_APIC
bool "Local APIC support on uniprocessors"
depends on X86_32 && !SMP && !X86_32_NON_STANDARD

View File

@ -106,7 +106,14 @@ extern u32 native_safe_apic_wait_icr_idle(void);
extern void native_apic_icr_write(u32 low, u32 id);
extern u64 native_apic_icr_read(void);
extern int x2apic_mode;
static inline bool apic_is_x2apic_enabled(void)
{
u64 msr;
if (rdmsrl_safe(MSR_IA32_APICBASE, &msr))
return false;
return msr & X2APIC_ENABLE;
}
#ifdef CONFIG_X86_X2APIC
/*
@ -169,48 +176,23 @@ static inline u64 native_x2apic_icr_read(void)
return val;
}
extern int x2apic_mode;
extern int x2apic_phys;
extern int x2apic_preenabled;
extern void check_x2apic(void);
extern void enable_x2apic(void);
extern void __init check_x2apic(void);
extern void x2apic_setup(void);
static inline int x2apic_enabled(void)
{
u64 msr;
if (!cpu_has_x2apic)
return 0;
rdmsrl(MSR_IA32_APICBASE, msr);
if (msr & X2APIC_ENABLE)
return 1;
return 0;
return cpu_has_x2apic && apic_is_x2apic_enabled();
}
#define x2apic_supported() (cpu_has_x2apic)
static inline void x2apic_force_phys(void)
{
x2apic_phys = 1;
}
#else
static inline void disable_x2apic(void)
{
}
static inline void check_x2apic(void)
{
}
static inline void enable_x2apic(void)
{
}
static inline int x2apic_enabled(void)
{
return 0;
}
static inline void x2apic_force_phys(void)
{
}
static inline void check_x2apic(void) { }
static inline void x2apic_setup(void) { }
static inline int x2apic_enabled(void) { return 0; }
#define x2apic_preenabled 0
#define x2apic_supported() 0
#define x2apic_mode (0)
#define x2apic_supported() (0)
#endif
extern void enable_IR_x2apic(void);
@ -219,7 +201,6 @@ extern int get_physical_broadcast(void);
extern int lapic_get_maxlvt(void);
extern void clear_local_APIC(void);
extern void connect_bsp_APIC(void);
extern void disconnect_bsp_APIC(int virt_wire_setup);
extern void disable_local_APIC(void);
extern void lapic_shutdown(void);
@ -227,8 +208,6 @@ extern int verify_local_APIC(void);
extern void sync_Arb_IDs(void);
extern void init_bsp_APIC(void);
extern void setup_local_APIC(void);
extern void end_local_APIC_setup(void);
extern void bsp_end_local_APIC_setup(void);
extern void init_apic_mappings(void);
void register_lapic_address(unsigned long address);
extern void setup_boot_APIC_clock(void);
@ -236,6 +215,9 @@ extern void setup_secondary_APIC_clock(void);
extern int APIC_init_uniprocessor(void);
extern int apic_force_enable(unsigned long addr);
extern int apic_bsp_setup(bool upmode);
extern void apic_ap_setup(void);
/*
* On 32bit this is mach-xxx local
*/

View File

@ -279,6 +279,11 @@ static inline void disable_ioapic_support(void) { }
#define native_ioapic_set_affinity NULL
#define native_setup_ioapic_entry NULL
#define native_eoi_ioapic_pin NULL
static inline void setup_IO_APIC(void) { }
static inline void enable_IO_APIC(void) { }
static inline void setup_ioapic_dest(void) { }
#endif
#endif /* _ASM_X86_IO_APIC_H */

View File

@ -33,8 +33,6 @@ struct irq_cfg;
#ifdef CONFIG_IRQ_REMAP
extern void setup_irq_remapping_ops(void);
extern int irq_remapping_supported(void);
extern void set_irq_remapping_broken(void);
extern int irq_remapping_prepare(void);
extern int irq_remapping_enable(void);
@ -60,8 +58,6 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip);
#else /* CONFIG_IRQ_REMAP */
static inline void setup_irq_remapping_ops(void) { }
static inline int irq_remapping_supported(void) { return 0; }
static inline void set_irq_remapping_broken(void) { }
static inline int irq_remapping_prepare(void) { return -ENODEV; }
static inline int irq_remapping_enable(void) { return -ENODEV; }

View File

@ -1,68 +0,0 @@
/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws
* which needs to alter them. */
static inline void smpboot_clear_io_apic_irqs(void)
{
#ifdef CONFIG_X86_IO_APIC
io_apic_irqs = 0;
#endif
}
static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
{
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
CMOS_WRITE(0xa, 0xf);
spin_unlock_irqrestore(&rtc_lock, flags);
local_flush_tlb();
pr_debug("1.\n");
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
start_eip >> 4;
pr_debug("2.\n");
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
start_eip & 0xf;
pr_debug("3.\n");
}
static inline void smpboot_restore_warm_reset_vector(void)
{
unsigned long flags;
/*
* Install writable page 0 entry to set BIOS data area.
*/
local_flush_tlb();
/*
* Paranoid: Set warm reset code and vector here back
* to default values.
*/
spin_lock_irqsave(&rtc_lock, flags);
CMOS_WRITE(0, 0xf);
spin_unlock_irqrestore(&rtc_lock, flags);
*((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0;
}
static inline void __init smpboot_setup_io_apic(void)
{
#ifdef CONFIG_X86_IO_APIC
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
* go and set it up:
*/
if (!skip_ioapic_setup && nr_ioapics)
setup_IO_APIC();
else {
nr_ioapics = 0;
}
#endif
}
static inline void smpboot_clear_io_apic(void)
{
#ifdef CONFIG_X86_IO_APIC
nr_ioapics = 0;
#endif
}

View File

@ -653,6 +653,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
return gsi;
}
#ifdef CONFIG_X86_LOCAL_APIC
static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
int trigger, int polarity)
{
@ -675,6 +676,7 @@ static void acpi_unregister_gsi_ioapic(u32 gsi)
mutex_unlock(&acpi_ioapic_lock);
#endif
}
#endif
int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
int trigger, int polarity) = acpi_register_gsi_pic;

View File

@ -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,184 @@ 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);
pr_info("Disabling x2apic\n");
__disable_x2apic(msr);
if (nox2apic) {
clear_cpu_cap(&cpu_data(0), X86_FEATURE_X2APIC);
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
}
x2apic_disabled = 1;
x2apic_mode = 0;
register_lapic_address(mp_lapic_addr);
}
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");
}
void check_x2apic(void)
static inline void __x2apic_enable(void)
{
u64 msr;
rdmsrl(MSR_IA32_APICBASE, msr);
if (msr & X2APIC_ENABLE)
return;
wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE);
printk_once(KERN_INFO "x2apic enabled\n");
}
static int __init setup_nox2apic(char *str)
{
if (x2apic_enabled()) {
pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
x2apic_preenabled = x2apic_mode = 1;
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.\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 enable_x2apic(void)
/* Called from cpu_init() to enable x2apic on (secondary) cpus */
void x2apic_setup(void)
{
u64 msr;
rdmsrl(MSR_IA32_APICBASE, msr);
if (x2apic_disabled) {
__disable_x2apic(msr);
/*
* If x2apic is not in ON state, disable it if already enabled
* from BIOS.
*/
if (x2apic_state != X2APIC_ON) {
__x2apic_disable();
return;
}
__x2apic_enable();
}
if (!x2apic_mode)
static __init void x2apic_disable(void)
{
u32 x2apic_id;
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 (!(msr & X2APIC_ENABLE)) {
printk_once(KERN_INFO "Enabling x2apic\n");
wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE);
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 (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 ||
(IS_ENABLED(CONFIG_HYPERVISOR_GUEST) &&
!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();
}
void __init check_x2apic(void)
{
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;
}
}
#endif /* CONFIG_X86_X2APIC */
int __init enable_IR(void)
#else /* CONFIG_X86_X2APIC */
static int __init validate_x2apic(void)
{
#ifdef CONFIG_IRQ_REMAP
if (!irq_remapping_supported()) {
pr_debug("intr-remapping not supported\n");
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);
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;
}
if (!x2apic_preenabled && skip_ioapic_setup) {
pr_info("Skipped enabling intr-remap because of skipping "
"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;
int ret, ir_stat;
/* Make sure irq_remap_ops are initialized */
setup_irq_remapping_ops();
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 +1652,13 @@ void __init enable_IR_x2apic(void)
legacy_pic->mask_all();
mask_ioapic_entries();
if (x2apic_preenabled && nox2apic)
disable_x2apic();
/* 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 (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 (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 +1849,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 +1955,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 +2202,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 +2381,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
*

View File

@ -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");

View File

@ -1332,7 +1332,7 @@ void cpu_init(void)
barrier();
x86_configure_nx();
enable_x2apic();
x2apic_setup();
/*
* set up and load the per-CPU TSS

View File

@ -73,7 +73,6 @@
#include <asm/setup.h>
#include <asm/uv/uv.h>
#include <linux/mc146818rtc.h>
#include <asm/smpboot_hooks.h>
#include <asm/i8259.h>
#include <asm/realmode.h>
#include <asm/misc.h>
@ -104,6 +103,43 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
atomic_t init_deasserted;
static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
{
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
CMOS_WRITE(0xa, 0xf);
spin_unlock_irqrestore(&rtc_lock, flags);
local_flush_tlb();
pr_debug("1.\n");
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
start_eip >> 4;
pr_debug("2.\n");
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
start_eip & 0xf;
pr_debug("3.\n");
}
static inline void smpboot_restore_warm_reset_vector(void)
{
unsigned long flags;
/*
* Install writable page 0 entry to set BIOS data area.
*/
local_flush_tlb();
/*
* Paranoid: Set warm reset code and vector here back
* to default values.
*/
spin_lock_irqsave(&rtc_lock, flags);
CMOS_WRITE(0, 0xf);
spin_unlock_irqrestore(&rtc_lock, flags);
*((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0;
}
/*
* Report back to the Boot Processor during boot time or to the caller processor
* during CPU online.
@ -136,8 +172,7 @@ static void smp_callin(void)
* CPU, first the APIC. (this is probably redundant on most
* boards)
*/
setup_local_APIC();
end_local_APIC_setup();
apic_ap_setup();
/*
* Need to setup vector mappings before we enable interrupts.
@ -955,9 +990,12 @@ void arch_disable_smp_support(void)
*/
static __init void disable_smp(void)
{
pr_info("SMP disabled\n");
disable_ioapic_support();
init_cpu_present(cpumask_of(0));
init_cpu_possible(cpumask_of(0));
smpboot_clear_io_apic_irqs();
if (smp_found_config)
physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
@ -967,6 +1005,13 @@ static __init void disable_smp(void)
cpumask_set_cpu(0, cpu_core_mask(0));
}
enum {
SMP_OK,
SMP_NO_CONFIG,
SMP_NO_APIC,
SMP_FORCE_UP,
};
/*
* Various sanity checks.
*/
@ -1014,10 +1059,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
if (!smp_found_config && !acpi_lapic) {
preempt_enable();
pr_notice("SMP motherboard not detected\n");
disable_smp();
if (APIC_init_uniprocessor())
pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
return -1;
return SMP_NO_CONFIG;
}
/*
@ -1041,9 +1083,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
boot_cpu_physical_apicid);
pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
}
smpboot_clear_io_apic();
disable_ioapic_support();
return -1;
return SMP_NO_APIC;
}
verify_local_APIC();
@ -1053,15 +1093,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
*/
if (!max_cpus) {
pr_info("SMP mode deactivated\n");
smpboot_clear_io_apic();
connect_bsp_APIC();
setup_local_APIC();
bsp_end_local_APIC_setup();
return -1;
return SMP_FORCE_UP;
}
return 0;
return SMP_OK;
}
static void __init smp_cpu_index_default(void)
@ -1101,10 +1136,21 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
}
set_cpu_sibling_map(0);
if (smp_sanity_check(max_cpus) < 0) {
pr_info("SMP disabled\n");
switch (smp_sanity_check(max_cpus)) {
case SMP_NO_CONFIG:
disable_smp();
if (APIC_init_uniprocessor())
pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
return;
case SMP_NO_APIC:
disable_smp();
return;
case SMP_FORCE_UP:
disable_smp();
apic_bsp_setup(false);
return;
case SMP_OK:
break;
}
default_setup_apic_routing();
@ -1115,33 +1161,10 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
/* Or can we switch back to PIC here? */
}
connect_bsp_APIC();
/*
* Switch from PIC to APIC mode.
*/
setup_local_APIC();
if (x2apic_mode)
cpu0_logical_apicid = apic_read(APIC_LDR);
else
cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
/*
* Enable IO APIC before setting up error vector
*/
if (!skip_ioapic_setup && nr_ioapics)
enable_IO_APIC();
bsp_end_local_APIC_setup();
smpboot_setup_io_apic();
/*
* Set up local APIC timer on boot CPU.
*/
cpu0_logical_apicid = apic_bsp_setup(false);
pr_info("CPU%d: ", 0);
print_cpu_info(&cpu_data(0));
x86_init.timers.setup_percpu_clockev();
if (is_uv_system())
uv_system_init();
@ -1177,9 +1200,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
nmi_selftest();
impress_friends();
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
#endif
mtrr_aps_init();
}

View File

@ -4284,7 +4284,6 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)
}
struct irq_remap_ops amd_iommu_irq_ops = {
.supported = amd_iommu_supported,
.prepare = amd_iommu_prepare,
.enable = amd_iommu_enable,
.disable = amd_iommu_disable,

View File

@ -2014,9 +2014,6 @@ static bool detect_ivrs(void)
/* Make sure ACS will be enabled during PCI probe */
pci_request_acs();
if (!disable_irq_remap)
amd_iommu_irq_remap = true;
return true;
}
@ -2123,12 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state)
#ifdef CONFIG_IRQ_REMAP
int __init amd_iommu_prepare(void)
{
return iommu_go_to_state(IOMMU_ACPI_FINISHED);
}
int ret;
int __init amd_iommu_supported(void)
{
return amd_iommu_irq_remap ? 1 : 0;
amd_iommu_irq_remap = true;
ret = iommu_go_to_state(IOMMU_ACPI_FINISHED);
if (ret)
return ret;
return amd_iommu_irq_remap ? 0 : -ENODEV;
}
int __init amd_iommu_enable(void)

View File

@ -33,7 +33,6 @@ extern void amd_iommu_init_notifier(void);
extern void amd_iommu_init_api(void);
/* Needed for interrupt remapping */
extern int amd_iommu_supported(void);
extern int amd_iommu_prepare(void);
extern int amd_iommu_enable(void);
extern void amd_iommu_disable(void);

View File

@ -32,8 +32,9 @@ struct hpet_scope {
};
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
#define IRTE_DEST(dest) ((eim_mode) ? dest : dest << 8)
static int __read_mostly eim_mode;
static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
static struct hpet_scope ir_hpet[MAX_HPET_TBS];
@ -481,11 +482,11 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
if (iommu->ir_table)
return 0;
ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC);
ir_table = kzalloc(sizeof(struct ir_table), GFP_KERNEL);
if (!ir_table)
return -ENOMEM;
pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO,
pages = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO,
INTR_REMAP_PAGE_ORDER);
if (!pages) {
@ -566,13 +567,27 @@ static int __init dmar_x2apic_optout(void)
return dmar->flags & DMAR_X2APIC_OPT_OUT;
}
static int __init intel_irq_remapping_supported(void)
static void __init intel_cleanup_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
for_each_iommu(iommu, drhd) {
if (ecap_ir_support(iommu->ecap)) {
iommu_disable_irq_remapping(iommu);
intel_teardown_irq_remapping(iommu);
}
}
if (x2apic_supported())
pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
}
static int __init intel_prepare_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
if (disable_irq_remap)
return 0;
if (irq_remap_broken) {
printk(KERN_WARNING
"This system BIOS has enabled interrupt remapping\n"
@ -581,38 +596,45 @@ static int __init intel_irq_remapping_supported(void)
"interrupt remapping is being disabled. Please\n"
"contact your BIOS vendor for an update\n");
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
disable_irq_remap = 1;
return 0;
return -ENODEV;
}
if (!dmar_ir_support())
return 0;
if (dmar_table_init() < 0)
return -ENODEV;
if (!dmar_ir_support())
return -ENODEV;
if (parse_ioapics_under_ir() != 1) {
printk(KERN_INFO "Not enabling interrupt remapping\n");
goto error;
}
/* First make sure all IOMMUs support IRQ remapping */
for_each_iommu(iommu, drhd)
if (!ecap_ir_support(iommu->ecap))
return 0;
goto error;
return 1;
/* Do the allocations early */
for_each_iommu(iommu, drhd)
if (intel_setup_irq_remapping(iommu))
goto error;
return 0;
error:
intel_cleanup_irq_remapping();
return -ENODEV;
}
static int __init intel_enable_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
bool x2apic_present;
int setup = 0;
int eim = 0;
x2apic_present = x2apic_supported();
if (parse_ioapics_under_ir() != 1) {
printk(KERN_INFO "Not enable interrupt remapping\n");
goto error;
}
if (x2apic_present) {
pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
if (x2apic_supported()) {
eim = !dmar_x2apic_optout();
if (!eim)
printk(KERN_WARNING
@ -646,16 +668,15 @@ static int __init intel_enable_irq_remapping(void)
/*
* check for the Interrupt-remapping support
*/
for_each_iommu(iommu, drhd) {
if (!ecap_ir_support(iommu->ecap))
continue;
for_each_iommu(iommu, drhd)
if (eim && !ecap_eim_support(iommu->ecap)) {
printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
" ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
goto error;
eim = 0;
}
}
eim_mode = eim;
if (eim)
pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
/*
* Enable queued invalidation for all the DRHD's.
@ -675,12 +696,6 @@ static int __init intel_enable_irq_remapping(void)
* Setup Interrupt-remapping for all the DRHD's now.
*/
for_each_iommu(iommu, drhd) {
if (!ecap_ir_support(iommu->ecap))
continue;
if (intel_setup_irq_remapping(iommu))
goto error;
iommu_set_irq_remapping(iommu, eim);
setup = 1;
}
@ -702,15 +717,7 @@ static int __init intel_enable_irq_remapping(void)
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
error:
for_each_iommu(iommu, drhd)
if (ecap_ir_support(iommu->ecap)) {
iommu_disable_irq_remapping(iommu);
intel_teardown_irq_remapping(iommu);
}
if (x2apic_present)
pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
intel_cleanup_irq_remapping();
return -1;
}
@ -1199,8 +1206,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
}
struct irq_remap_ops intel_irq_remap_ops = {
.supported = intel_irq_remapping_supported,
.prepare = dmar_table_init,
.prepare = intel_prepare_irq_remapping,
.enable = intel_enable_irq_remapping,
.disable = disable_irq_remapping,
.reenable = reenable_irq_remapping,

View File

@ -17,12 +17,11 @@
#include "irq_remapping.h"
int irq_remapping_enabled;
int disable_irq_remap;
int irq_remap_broken;
int disable_sourceid_checking;
int no_x2apic_optout;
static int disable_irq_remap;
static struct irq_remap_ops *remap_ops;
static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
@ -194,45 +193,32 @@ static __init int setup_irqremap(char *str)
}
early_param("intremap", setup_irqremap);
void __init setup_irq_remapping_ops(void)
{
remap_ops = &intel_irq_remap_ops;
#ifdef CONFIG_AMD_IOMMU
if (amd_iommu_irq_ops.prepare() == 0)
remap_ops = &amd_iommu_irq_ops;
#endif
}
void set_irq_remapping_broken(void)
{
irq_remap_broken = 1;
}
int irq_remapping_supported(void)
{
if (disable_irq_remap)
return 0;
if (!remap_ops || !remap_ops->supported)
return 0;
return remap_ops->supported();
}
int __init irq_remapping_prepare(void)
{
if (!remap_ops || !remap_ops->prepare)
return -ENODEV;
if (disable_irq_remap)
return -ENOSYS;
return remap_ops->prepare();
if (intel_irq_remap_ops.prepare() == 0)
remap_ops = &intel_irq_remap_ops;
else if (IS_ENABLED(CONFIG_AMD_IOMMU) &&
amd_iommu_irq_ops.prepare() == 0)
remap_ops = &amd_iommu_irq_ops;
else
return -ENOSYS;
return 0;
}
int __init irq_remapping_enable(void)
{
int ret;
if (!remap_ops || !remap_ops->enable)
if (!remap_ops->enable)
return -ENODEV;
ret = remap_ops->enable();
@ -245,22 +231,16 @@ int __init irq_remapping_enable(void)
void irq_remapping_disable(void)
{
if (!irq_remapping_enabled ||
!remap_ops ||
!remap_ops->disable)
return;
remap_ops->disable();
if (irq_remapping_enabled && remap_ops->disable)
remap_ops->disable();
}
int irq_remapping_reenable(int mode)
{
if (!irq_remapping_enabled ||
!remap_ops ||
!remap_ops->reenable)
return 0;
if (irq_remapping_enabled && remap_ops->reenable)
return remap_ops->reenable(mode);
return remap_ops->reenable(mode);
return 0;
}
int __init irq_remap_enable_fault_handling(void)
@ -268,7 +248,7 @@ int __init irq_remap_enable_fault_handling(void)
if (!irq_remapping_enabled)
return 0;
if (!remap_ops || !remap_ops->enable_faulting)
if (!remap_ops->enable_faulting)
return -ENODEV;
return remap_ops->enable_faulting();
@ -279,7 +259,7 @@ int setup_ioapic_remapped_entry(int irq,
unsigned int destination, int vector,
struct io_apic_irq_attr *attr)
{
if (!remap_ops || !remap_ops->setup_ioapic_entry)
if (!remap_ops->setup_ioapic_entry)
return -ENODEV;
return remap_ops->setup_ioapic_entry(irq, entry, destination,
@ -289,8 +269,7 @@ int setup_ioapic_remapped_entry(int irq,
static int set_remapped_irq_affinity(struct irq_data *data,
const struct cpumask *mask, bool force)
{
if (!config_enabled(CONFIG_SMP) || !remap_ops ||
!remap_ops->set_affinity)
if (!config_enabled(CONFIG_SMP) || !remap_ops->set_affinity)
return 0;
return remap_ops->set_affinity(data, mask, force);
@ -300,10 +279,7 @@ void free_remapped_irq(int irq)
{
struct irq_cfg *cfg = irq_cfg(irq);
if (!remap_ops || !remap_ops->free_irq)
return;
if (irq_remapped(cfg))
if (irq_remapped(cfg) && remap_ops->free_irq)
remap_ops->free_irq(irq);
}
@ -315,13 +291,13 @@ void compose_remapped_msi_msg(struct pci_dev *pdev,
if (!irq_remapped(cfg))
native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
else if (remap_ops && remap_ops->compose_msi_msg)
else if (remap_ops->compose_msi_msg)
remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
}
static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
{
if (!remap_ops || !remap_ops->msi_alloc_irq)
if (!remap_ops->msi_alloc_irq)
return -ENODEV;
return remap_ops->msi_alloc_irq(pdev, irq, nvec);
@ -330,7 +306,7 @@ static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
int index, int sub_handle)
{
if (!remap_ops || !remap_ops->msi_setup_irq)
if (!remap_ops->msi_setup_irq)
return -ENODEV;
return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
@ -340,7 +316,7 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{
int ret;
if (!remap_ops || !remap_ops->alloc_hpet_msi)
if (!remap_ops->alloc_hpet_msi)
return -ENODEV;
ret = remap_ops->alloc_hpet_msi(irq, id);

View File

@ -31,16 +31,12 @@ struct cpumask;
struct pci_dev;
struct msi_msg;
extern int disable_irq_remap;
extern int irq_remap_broken;
extern int disable_sourceid_checking;
extern int no_x2apic_optout;
extern int irq_remapping_enabled;
struct irq_remap_ops {
/* Check whether Interrupt Remapping is supported */
int (*supported)(void);
/* Initializes hardware and makes it ready for remapping interrupts */
int (*prepare)(void);
@ -89,7 +85,6 @@ extern struct irq_remap_ops amd_iommu_irq_ops;
#else /* CONFIG_IRQ_REMAP */
#define irq_remapping_enabled 0
#define disable_irq_remap 1
#define irq_remap_broken 0
#endif /* CONFIG_IRQ_REMAP */

View File

@ -151,6 +151,13 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
static inline void kick_all_cpus_sync(void) { }
static inline void wake_up_all_idle_cpus(void) { }
#ifdef CONFIG_UP_LATE_INIT
extern void __init up_late_init(void);
static inline void smp_init(void) { up_late_init(); }
#else
static inline void smp_init(void) { }
#endif
#endif /* !SMP */
/*

View File

@ -87,10 +87,6 @@
#include <asm/sections.h>
#include <asm/cacheflush.h>
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h>
#endif
static int kernel_init(void *);
extern void init_IRQ(void);
@ -351,15 +347,6 @@ __setup("rdinit=", rdinit_setup);
#ifndef CONFIG_SMP
static const unsigned int setup_max_cpus = NR_CPUS;
#ifdef CONFIG_X86_LOCAL_APIC
static void __init smp_init(void)
{
APIC_init_uniprocessor();
}
#else
#define smp_init() do { } while (0)
#endif
static inline void setup_nr_cpu_ids(void) { }
static inline void smp_prepare_cpus(unsigned int maxcpus) { }
#endif