Merge branch 'linus' into perfcounters/core
Conflicts: arch/x86/kernel/irqinit.c arch/x86/kernel/irqinit_64.c arch/x86/kernel/traps.c arch/x86/mm/fault.c include/linux/sched.h kernel/exit.c
This commit is contained in:
@@ -100,6 +100,29 @@ early_param("lapic", parse_lapic);
|
||||
/* Local APIC was disabled by the BIOS and enabled by the kernel */
|
||||
static int enabled_via_apicbase;
|
||||
|
||||
/*
|
||||
* Handle interrupt mode configuration register (IMCR).
|
||||
* This register controls whether the interrupt signals
|
||||
* that reach the BSP come from the master PIC or from the
|
||||
* local APIC. Before entering Symmetric I/O Mode, either
|
||||
* the BIOS or the operating system must switch out of
|
||||
* PIC Mode by changing the IMCR.
|
||||
*/
|
||||
static inline void imcr_pic_to_apic(void)
|
||||
{
|
||||
/* select IMCR register */
|
||||
outb(0x70, 0x22);
|
||||
/* NMI and 8259 INTR go through APIC */
|
||||
outb(0x01, 0x23);
|
||||
}
|
||||
|
||||
static inline void imcr_apic_to_pic(void)
|
||||
{
|
||||
/* select IMCR register */
|
||||
outb(0x70, 0x22);
|
||||
/* NMI and 8259 INTR go directly to BSP */
|
||||
outb(0x00, 0x23);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
@@ -113,13 +136,19 @@ static __init int setup_apicpmtimer(char *s)
|
||||
__setup("apicpmtimer", setup_apicpmtimer);
|
||||
#endif
|
||||
|
||||
int x2apic_mode;
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
int x2apic;
|
||||
/* x2apic enabled before OS handover */
|
||||
static int x2apic_preenabled;
|
||||
static int disable_x2apic;
|
||||
static __init int setup_nox2apic(char *str)
|
||||
{
|
||||
if (x2apic_enabled()) {
|
||||
pr_warning("Bios already enabled x2apic, "
|
||||
"can't enforce nox2apic");
|
||||
return 0;
|
||||
}
|
||||
|
||||
disable_x2apic = 1;
|
||||
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
|
||||
return 0;
|
||||
@@ -211,6 +240,31 @@ static int modern_apic(void)
|
||||
return lapic_get_version() >= 0x14;
|
||||
}
|
||||
|
||||
/*
|
||||
* bare function to substitute write operation
|
||||
* and it's _that_ fast :)
|
||||
*/
|
||||
static void native_apic_write_dummy(u32 reg, u32 v)
|
||||
{
|
||||
WARN_ON_ONCE((cpu_has_apic || !disable_apic));
|
||||
}
|
||||
|
||||
static u32 native_apic_read_dummy(u32 reg)
|
||||
{
|
||||
WARN_ON_ONCE((cpu_has_apic && !disable_apic));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* right after this call apic->write/read doesn't do anything
|
||||
* note that there is no restore operation it works one way
|
||||
*/
|
||||
void apic_disable(void)
|
||||
{
|
||||
apic->read = native_apic_read_dummy;
|
||||
apic->write = native_apic_write_dummy;
|
||||
}
|
||||
|
||||
void native_apic_wait_icr_idle(void)
|
||||
{
|
||||
while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
|
||||
@@ -350,7 +404,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
|
||||
|
||||
static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
|
||||
{
|
||||
unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
|
||||
unsigned long reg = (lvt_off << 4) + APIC_EILVTn(0);
|
||||
unsigned int v = (mask << 16) | (msg_type << 8) | vector;
|
||||
|
||||
apic_write(reg, v);
|
||||
@@ -817,7 +871,7 @@ void clear_local_APIC(void)
|
||||
u32 v;
|
||||
|
||||
/* APIC hasn't been mapped yet */
|
||||
if (!x2apic && !apic_phys)
|
||||
if (!x2apic_mode && !apic_phys)
|
||||
return;
|
||||
|
||||
maxlvt = lapic_get_maxlvt();
|
||||
@@ -1290,7 +1344,7 @@ void check_x2apic(void)
|
||||
{
|
||||
if (x2apic_enabled()) {
|
||||
pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
|
||||
x2apic_preenabled = x2apic = 1;
|
||||
x2apic_preenabled = x2apic_mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1298,7 +1352,7 @@ void enable_x2apic(void)
|
||||
{
|
||||
int msr, msr2;
|
||||
|
||||
if (!x2apic)
|
||||
if (!x2apic_mode)
|
||||
return;
|
||||
|
||||
rdmsr(MSR_IA32_APICBASE, msr, msr2);
|
||||
@@ -1307,6 +1361,7 @@ void enable_x2apic(void)
|
||||
wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_X86_X2APIC */
|
||||
|
||||
void __init enable_IR_x2apic(void)
|
||||
{
|
||||
@@ -1315,32 +1370,21 @@ void __init enable_IR_x2apic(void)
|
||||
unsigned long flags;
|
||||
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
||||
|
||||
if (!cpu_has_x2apic)
|
||||
return;
|
||||
|
||||
if (!x2apic_preenabled && disable_x2apic) {
|
||||
pr_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) {
|
||||
pr_info("Skipped enabling x2apic and Interrupt-remapping "
|
||||
"because of skipping io-apic setup\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dmar_table_init();
|
||||
if (ret) {
|
||||
pr_info("dmar_table_init() failed with %d:\n", ret);
|
||||
pr_debug("dmar_table_init() failed with %d:\n", ret);
|
||||
goto ir_failed;
|
||||
}
|
||||
|
||||
if (x2apic_preenabled)
|
||||
panic("x2apic enabled by bios. But IR enabling failed");
|
||||
else
|
||||
pr_info("Not enabling x2apic,Intr-remapping\n");
|
||||
if (!intr_remapping_supported()) {
|
||||
pr_debug("intr-remapping not supported\n");
|
||||
goto ir_failed;
|
||||
}
|
||||
|
||||
|
||||
if (!x2apic_preenabled && skip_ioapic_setup) {
|
||||
pr_info("Skipped enabling intr-remap because of skipping "
|
||||
"io-apic setup\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1360,19 +1404,16 @@ void __init enable_IR_x2apic(void)
|
||||
mask_IO_APIC_setup(ioapic_entries);
|
||||
mask_8259A();
|
||||
|
||||
ret = enable_intr_remapping(EIM_32BIT_APIC_ID);
|
||||
|
||||
if (ret && x2apic_preenabled) {
|
||||
local_irq_restore(flags);
|
||||
panic("x2apic enabled by bios. But IR enabling failed");
|
||||
}
|
||||
|
||||
ret = enable_intr_remapping(x2apic_supported());
|
||||
if (ret)
|
||||
goto end_restore;
|
||||
|
||||
if (!x2apic) {
|
||||
x2apic = 1;
|
||||
pr_info("Enabled Interrupt-remapping\n");
|
||||
|
||||
if (x2apic_supported() && !x2apic_mode) {
|
||||
x2apic_mode = 1;
|
||||
enable_x2apic();
|
||||
pr_info("Enabled x2apic\n");
|
||||
}
|
||||
|
||||
end_restore:
|
||||
@@ -1381,37 +1422,34 @@ end_restore:
|
||||
* IR enabling failed
|
||||
*/
|
||||
restore_IO_APIC_setup(ioapic_entries);
|
||||
else
|
||||
reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);
|
||||
|
||||
unmask_8259A();
|
||||
local_irq_restore(flags);
|
||||
|
||||
end:
|
||||
if (!ret) {
|
||||
if (!x2apic_preenabled)
|
||||
pr_info("Enabled x2apic and interrupt-remapping\n");
|
||||
else
|
||||
pr_info("Enabled Interrupt-remapping\n");
|
||||
} else
|
||||
pr_err("Failed to enable Interrupt-remapping and x2apic\n");
|
||||
if (ioapic_entries)
|
||||
free_ioapic_entries(ioapic_entries);
|
||||
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
ir_failed:
|
||||
if (x2apic_preenabled)
|
||||
panic("x2apic enabled by bios. But IR enabling failed");
|
||||
else if (cpu_has_x2apic)
|
||||
pr_info("Not enabling x2apic,Intr-remapping\n");
|
||||
#else
|
||||
if (!cpu_has_x2apic)
|
||||
return;
|
||||
|
||||
if (x2apic_preenabled)
|
||||
panic("x2apic enabled prior OS handover,"
|
||||
" enable CONFIG_INTR_REMAP");
|
||||
|
||||
pr_info("Enable CONFIG_INTR_REMAP for enabling intr-remapping "
|
||||
" and x2apic\n");
|
||||
" enable CONFIG_X86_X2APIC, CONFIG_INTR_REMAP");
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_X86_X2APIC */
|
||||
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
@@ -1428,7 +1466,6 @@ static int __init detect_init_APIC(void)
|
||||
}
|
||||
|
||||
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
|
||||
boot_cpu_physical_apicid = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@@ -1542,32 +1579,49 @@ void __init early_init_lapic_mapping(void)
|
||||
*/
|
||||
void __init init_apic_mappings(void)
|
||||
{
|
||||
if (x2apic) {
|
||||
unsigned int new_apicid;
|
||||
|
||||
if (x2apic_mode) {
|
||||
boot_cpu_physical_apicid = 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
|
||||
* one for the IO-APIC.
|
||||
*/
|
||||
/* If no local APIC can be found return early */
|
||||
if (!smp_found_config && detect_init_APIC()) {
|
||||
apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
|
||||
apic_phys = __pa(apic_phys);
|
||||
} else
|
||||
/* lets NOP'ify apic operations */
|
||||
pr_info("APIC: disable apic facility\n");
|
||||
apic_disable();
|
||||
} else {
|
||||
apic_phys = mp_lapic_addr;
|
||||
|
||||
set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
|
||||
apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n",
|
||||
APIC_BASE, apic_phys);
|
||||
/*
|
||||
* acpi lapic path already maps that address in
|
||||
* acpi_register_lapic_address()
|
||||
*/
|
||||
if (!acpi_lapic)
|
||||
set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
|
||||
|
||||
apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n",
|
||||
APIC_BASE, apic_phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the APIC ID of the BSP in case we have a
|
||||
* default configuration (or the MP table is broken).
|
||||
*/
|
||||
if (boot_cpu_physical_apicid == -1U)
|
||||
boot_cpu_physical_apicid = read_apic_id();
|
||||
new_apicid = read_apic_id();
|
||||
if (boot_cpu_physical_apicid != new_apicid) {
|
||||
boot_cpu_physical_apicid = new_apicid;
|
||||
/*
|
||||
* yeah -- we lie about apic_version
|
||||
* in case if apic was disabled via boot option
|
||||
* but it's not a problem for SMP compiled kernel
|
||||
* since smp_sanity_check is prepared for such a case
|
||||
* and disable smp mode
|
||||
*/
|
||||
apic_version[new_apicid] =
|
||||
GET_APIC_VERSION(apic_read(APIC_LVR));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1736,8 +1790,7 @@ void __init connect_bsp_APIC(void)
|
||||
*/
|
||||
apic_printk(APIC_VERBOSE, "leaving PIC mode, "
|
||||
"enabling APIC mode.\n");
|
||||
outb(0x70, 0x22);
|
||||
outb(0x01, 0x23);
|
||||
imcr_pic_to_apic();
|
||||
}
|
||||
#endif
|
||||
if (apic->enable_apic_mode)
|
||||
@@ -1765,8 +1818,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
|
||||
*/
|
||||
apic_printk(APIC_VERBOSE, "disabling APIC mode, "
|
||||
"entering PIC mode.\n");
|
||||
outb(0x70, 0x22);
|
||||
outb(0x00, 0x23);
|
||||
imcr_apic_to_pic();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1972,10 +2024,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
|
||||
|
||||
local_irq_save(flags);
|
||||
disable_local_APIC();
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
|
||||
if (intr_remapping_enabled)
|
||||
disable_intr_remapping();
|
||||
#endif
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
@@ -1985,42 +2037,34 @@ static int lapic_resume(struct sys_device *dev)
|
||||
unsigned int l, h;
|
||||
unsigned long flags;
|
||||
int maxlvt;
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
||||
|
||||
if (!apic_pm_state.active)
|
||||
return 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (x2apic) {
|
||||
if (intr_remapping_enabled) {
|
||||
ioapic_entries = alloc_ioapic_entries();
|
||||
if (!ioapic_entries) {
|
||||
WARN(1, "Alloc ioapic_entries in lapic resume failed.");
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto restore;
|
||||
}
|
||||
|
||||
ret = save_IO_APIC_setup(ioapic_entries);
|
||||
if (ret) {
|
||||
WARN(1, "Saving IO-APIC state failed: %d\n", ret);
|
||||
free_ioapic_entries(ioapic_entries);
|
||||
return ret;
|
||||
goto restore;
|
||||
}
|
||||
|
||||
mask_IO_APIC_setup(ioapic_entries);
|
||||
mask_8259A();
|
||||
enable_x2apic();
|
||||
}
|
||||
#else
|
||||
if (!apic_pm_state.active)
|
||||
return 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (x2apic)
|
||||
if (x2apic_mode)
|
||||
enable_x2apic();
|
||||
#endif
|
||||
|
||||
else {
|
||||
/*
|
||||
* Make sure the APICBASE points to the right address
|
||||
@@ -2058,21 +2102,16 @@ static int lapic_resume(struct sys_device *dev)
|
||||
apic_write(APIC_ESR, 0);
|
||||
apic_read(APIC_ESR);
|
||||
|
||||
#ifdef CONFIG_INTR_REMAP
|
||||
if (intr_remapping_enabled)
|
||||
reenable_intr_remapping(EIM_32BIT_APIC_ID);
|
||||
|
||||
if (x2apic) {
|
||||
if (intr_remapping_enabled) {
|
||||
reenable_intr_remapping(x2apic_mode);
|
||||
unmask_8259A();
|
||||
restore_IO_APIC_setup(ioapic_entries);
|
||||
free_ioapic_entries(ioapic_entries);
|
||||
}
|
||||
#endif
|
||||
|
||||
restore:
|
||||
local_irq_restore(flags);
|
||||
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2120,31 +2159,14 @@ static void apic_pm_activate(void) { }
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* apic_is_clustered_box() -- Check if we can expect good TSC
|
||||
*
|
||||
* Thus far, the major user of this is IBM's Summit2 series:
|
||||
*
|
||||
* Clustered boxes may have unsynced TSC problems if they are
|
||||
* multi-chassis. Use available data to take a good guess.
|
||||
* If in doubt, go HPET.
|
||||
*/
|
||||
__cpuinit int apic_is_clustered_box(void)
|
||||
|
||||
static int __cpuinit apic_cluster_num(void)
|
||||
{
|
||||
int i, clusters, zeros;
|
||||
unsigned id;
|
||||
u16 *bios_cpu_apicid;
|
||||
DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
|
||||
|
||||
/*
|
||||
* there is not this kind of box with AMD CPU yet.
|
||||
* Some AMD box with quadcore cpu and 8 sockets apicid
|
||||
* will be [4, 0x23] or [8, 0x27] could be thought to
|
||||
* vsmp box still need checking...
|
||||
*/
|
||||
if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && !is_vsmp_box())
|
||||
return 0;
|
||||
|
||||
bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid);
|
||||
bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
|
||||
|
||||
@@ -2180,18 +2202,67 @@ __cpuinit int apic_is_clustered_box(void)
|
||||
++zeros;
|
||||
}
|
||||
|
||||
/* ScaleMP vSMPowered boxes have one cluster per board and TSCs are
|
||||
* not guaranteed to be synced between boards
|
||||
*/
|
||||
if (is_vsmp_box() && clusters > 1)
|
||||
return clusters;
|
||||
}
|
||||
|
||||
static int __cpuinitdata multi_checked;
|
||||
static int __cpuinitdata multi;
|
||||
|
||||
static int __cpuinit set_multi(const struct dmi_system_id *d)
|
||||
{
|
||||
if (multi)
|
||||
return 0;
|
||||
pr_info("APIC: %s detected, Multi Chassis\n", d->ident);
|
||||
multi = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const __cpuinitconst struct dmi_system_id multi_dmi_table[] = {
|
||||
{
|
||||
.callback = set_multi,
|
||||
.ident = "IBM System Summit2",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Summit2"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static void __cpuinit dmi_check_multi(void)
|
||||
{
|
||||
if (multi_checked)
|
||||
return;
|
||||
|
||||
dmi_check_system(multi_dmi_table);
|
||||
multi_checked = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* apic_is_clustered_box() -- Check if we can expect good TSC
|
||||
*
|
||||
* Thus far, the major user of this is IBM's Summit2 series:
|
||||
* Clustered boxes may have unsynced TSC problems if they are
|
||||
* multi-chassis.
|
||||
* Use DMI to check them
|
||||
*/
|
||||
__cpuinit int apic_is_clustered_box(void)
|
||||
{
|
||||
dmi_check_multi();
|
||||
if (multi)
|
||||
return 1;
|
||||
|
||||
if (!is_vsmp_box())
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If clusters > 2, then should be multi-chassis.
|
||||
* May have to revisit this when multi-core + hyperthreaded CPUs come
|
||||
* out, but AFAIK this will work even for them.
|
||||
* ScaleMP vSMPowered boxes have one cluster per board and TSCs are
|
||||
* not guaranteed to be synced between boards
|
||||
*/
|
||||
return (clusters > 2);
|
||||
if (apic_cluster_num() > 1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user