|
@@ -98,6 +98,29 @@ early_param("lapic", parse_lapic);
|
|
/* Local APIC was disabled by the BIOS and enabled by the kernel */
|
|
/* Local APIC was disabled by the BIOS and enabled by the kernel */
|
|
static int enabled_via_apicbase;
|
|
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
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#ifdef CONFIG_X86_64
|
|
@@ -111,13 +134,19 @@ static __init int setup_apicpmtimer(char *s)
|
|
__setup("apicpmtimer", setup_apicpmtimer);
|
|
__setup("apicpmtimer", setup_apicpmtimer);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+int x2apic_mode;
|
|
#ifdef CONFIG_X86_X2APIC
|
|
#ifdef CONFIG_X86_X2APIC
|
|
-int x2apic;
|
|
|
|
/* x2apic enabled before OS handover */
|
|
/* x2apic enabled before OS handover */
|
|
static int x2apic_preenabled;
|
|
static int x2apic_preenabled;
|
|
static int disable_x2apic;
|
|
static int disable_x2apic;
|
|
static __init int setup_nox2apic(char *str)
|
|
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;
|
|
disable_x2apic = 1;
|
|
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
|
|
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
|
|
return 0;
|
|
return 0;
|
|
@@ -209,6 +238,31 @@ static int modern_apic(void)
|
|
return lapic_get_version() >= 0x14;
|
|
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)
|
|
void native_apic_wait_icr_idle(void)
|
|
{
|
|
{
|
|
while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
|
|
while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
|
|
@@ -348,7 +402,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)
|
|
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;
|
|
unsigned int v = (mask << 16) | (msg_type << 8) | vector;
|
|
|
|
|
|
apic_write(reg, v);
|
|
apic_write(reg, v);
|
|
@@ -815,7 +869,7 @@ void clear_local_APIC(void)
|
|
u32 v;
|
|
u32 v;
|
|
|
|
|
|
/* APIC hasn't been mapped yet */
|
|
/* APIC hasn't been mapped yet */
|
|
- if (!x2apic && !apic_phys)
|
|
|
|
|
|
+ if (!x2apic_mode && !apic_phys)
|
|
return;
|
|
return;
|
|
|
|
|
|
maxlvt = lapic_get_maxlvt();
|
|
maxlvt = lapic_get_maxlvt();
|
|
@@ -1287,7 +1341,7 @@ void check_x2apic(void)
|
|
{
|
|
{
|
|
if (x2apic_enabled()) {
|
|
if (x2apic_enabled()) {
|
|
pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
|
|
pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
|
|
- x2apic_preenabled = x2apic = 1;
|
|
|
|
|
|
+ x2apic_preenabled = x2apic_mode = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1295,7 +1349,7 @@ void enable_x2apic(void)
|
|
{
|
|
{
|
|
int msr, msr2;
|
|
int msr, msr2;
|
|
|
|
|
|
- if (!x2apic)
|
|
|
|
|
|
+ if (!x2apic_mode)
|
|
return;
|
|
return;
|
|
|
|
|
|
rdmsr(MSR_IA32_APICBASE, msr, msr2);
|
|
rdmsr(MSR_IA32_APICBASE, msr, msr2);
|
|
@@ -1304,6 +1358,7 @@ void enable_x2apic(void)
|
|
wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
|
|
wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+#endif /* CONFIG_X86_X2APIC */
|
|
|
|
|
|
void __init enable_IR_x2apic(void)
|
|
void __init enable_IR_x2apic(void)
|
|
{
|
|
{
|
|
@@ -1312,32 +1367,21 @@ void __init enable_IR_x2apic(void)
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
|
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;
|
|
|
|
|
|
+ ret = dmar_table_init();
|
|
|
|
+ if (ret) {
|
|
|
|
+ pr_debug("dmar_table_init() failed with %d:\n", ret);
|
|
|
|
+ goto ir_failed;
|
|
}
|
|
}
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
+ if (!intr_remapping_supported()) {
|
|
|
|
+ pr_debug("intr-remapping not supported\n");
|
|
|
|
+ goto ir_failed;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = dmar_table_init();
|
|
|
|
- if (ret) {
|
|
|
|
- pr_info("dmar_table_init() failed with %d:\n", ret);
|
|
|
|
|
|
|
|
- if (x2apic_preenabled)
|
|
|
|
- panic("x2apic enabled by bios. But IR enabling failed");
|
|
|
|
- else
|
|
|
|
- pr_info("Not enabling x2apic,Intr-remapping\n");
|
|
|
|
|
|
+ if (!x2apic_preenabled && skip_ioapic_setup) {
|
|
|
|
+ pr_info("Skipped enabling intr-remap because of skipping "
|
|
|
|
+ "io-apic setup\n");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1357,19 +1401,16 @@ void __init enable_IR_x2apic(void)
|
|
mask_IO_APIC_setup(ioapic_entries);
|
|
mask_IO_APIC_setup(ioapic_entries);
|
|
mask_8259A();
|
|
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)
|
|
if (ret)
|
|
goto end_restore;
|
|
goto end_restore;
|
|
|
|
|
|
- if (!x2apic) {
|
|
|
|
- x2apic = 1;
|
|
|
|
|
|
+ pr_info("Enabled Interrupt-remapping\n");
|
|
|
|
+
|
|
|
|
+ if (x2apic_supported() && !x2apic_mode) {
|
|
|
|
+ x2apic_mode = 1;
|
|
enable_x2apic();
|
|
enable_x2apic();
|
|
|
|
+ pr_info("Enabled x2apic\n");
|
|
}
|
|
}
|
|
|
|
|
|
end_restore:
|
|
end_restore:
|
|
@@ -1378,37 +1419,34 @@ end_restore:
|
|
* IR enabling failed
|
|
* IR enabling failed
|
|
*/
|
|
*/
|
|
restore_IO_APIC_setup(ioapic_entries);
|
|
restore_IO_APIC_setup(ioapic_entries);
|
|
- else
|
|
|
|
- reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);
|
|
|
|
|
|
|
|
unmask_8259A();
|
|
unmask_8259A();
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
|
|
|
|
end:
|
|
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)
|
|
if (ioapic_entries)
|
|
free_ioapic_entries(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
|
|
#else
|
|
if (!cpu_has_x2apic)
|
|
if (!cpu_has_x2apic)
|
|
return;
|
|
return;
|
|
|
|
|
|
if (x2apic_preenabled)
|
|
if (x2apic_preenabled)
|
|
panic("x2apic enabled prior OS handover,"
|
|
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
|
|
#endif
|
|
|
|
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
-#endif /* CONFIG_X86_X2APIC */
|
|
|
|
|
|
+
|
|
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#ifdef CONFIG_X86_64
|
|
/*
|
|
/*
|
|
@@ -1425,7 +1463,6 @@ static int __init detect_init_APIC(void)
|
|
}
|
|
}
|
|
|
|
|
|
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
|
|
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
|
|
- boot_cpu_physical_apicid = 0;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
@@ -1539,32 +1576,49 @@ void __init early_init_lapic_mapping(void)
|
|
*/
|
|
*/
|
|
void __init init_apic_mappings(void)
|
|
void __init init_apic_mappings(void)
|
|
{
|
|
{
|
|
- if (x2apic) {
|
|
|
|
|
|
+ unsigned int new_apicid;
|
|
|
|
+
|
|
|
|
+ if (x2apic_mode) {
|
|
boot_cpu_physical_apicid = read_apic_id();
|
|
boot_cpu_physical_apicid = read_apic_id();
|
|
return;
|
|
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()) {
|
|
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;
|
|
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
|
|
* Fetch the APIC ID of the BSP in case we have a
|
|
* default configuration (or the MP table is broken).
|
|
* 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));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1733,8 +1787,7 @@ void __init connect_bsp_APIC(void)
|
|
*/
|
|
*/
|
|
apic_printk(APIC_VERBOSE, "leaving PIC mode, "
|
|
apic_printk(APIC_VERBOSE, "leaving PIC mode, "
|
|
"enabling APIC mode.\n");
|
|
"enabling APIC mode.\n");
|
|
- outb(0x70, 0x22);
|
|
|
|
- outb(0x01, 0x23);
|
|
|
|
|
|
+ imcr_pic_to_apic();
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
if (apic->enable_apic_mode)
|
|
if (apic->enable_apic_mode)
|
|
@@ -1762,8 +1815,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
|
|
*/
|
|
*/
|
|
apic_printk(APIC_VERBOSE, "disabling APIC mode, "
|
|
apic_printk(APIC_VERBOSE, "disabling APIC mode, "
|
|
"entering PIC mode.\n");
|
|
"entering PIC mode.\n");
|
|
- outb(0x70, 0x22);
|
|
|
|
- outb(0x00, 0x23);
|
|
|
|
|
|
+ imcr_apic_to_pic();
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
@@ -1969,10 +2021,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
|
|
|
|
|
|
local_irq_save(flags);
|
|
local_irq_save(flags);
|
|
disable_local_APIC();
|
|
disable_local_APIC();
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
|
|
|
+
|
|
if (intr_remapping_enabled)
|
|
if (intr_remapping_enabled)
|
|
disable_intr_remapping();
|
|
disable_intr_remapping();
|
|
-#endif
|
|
|
|
|
|
+
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -1982,42 +2034,34 @@ static int lapic_resume(struct sys_device *dev)
|
|
unsigned int l, h;
|
|
unsigned int l, h;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
int maxlvt;
|
|
int maxlvt;
|
|
-
|
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
|
- int ret;
|
|
|
|
|
|
+ int ret = 0;
|
|
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
|
struct IO_APIC_route_entry **ioapic_entries = NULL;
|
|
|
|
|
|
if (!apic_pm_state.active)
|
|
if (!apic_pm_state.active)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
local_irq_save(flags);
|
|
local_irq_save(flags);
|
|
- if (x2apic) {
|
|
|
|
|
|
+ if (intr_remapping_enabled) {
|
|
ioapic_entries = alloc_ioapic_entries();
|
|
ioapic_entries = alloc_ioapic_entries();
|
|
if (!ioapic_entries) {
|
|
if (!ioapic_entries) {
|
|
WARN(1, "Alloc ioapic_entries in lapic resume failed.");
|
|
WARN(1, "Alloc ioapic_entries in lapic resume failed.");
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto restore;
|
|
}
|
|
}
|
|
|
|
|
|
ret = save_IO_APIC_setup(ioapic_entries);
|
|
ret = save_IO_APIC_setup(ioapic_entries);
|
|
if (ret) {
|
|
if (ret) {
|
|
WARN(1, "Saving IO-APIC state failed: %d\n", ret);
|
|
WARN(1, "Saving IO-APIC state failed: %d\n", ret);
|
|
free_ioapic_entries(ioapic_entries);
|
|
free_ioapic_entries(ioapic_entries);
|
|
- return ret;
|
|
|
|
|
|
+ goto restore;
|
|
}
|
|
}
|
|
|
|
|
|
mask_IO_APIC_setup(ioapic_entries);
|
|
mask_IO_APIC_setup(ioapic_entries);
|
|
mask_8259A();
|
|
mask_8259A();
|
|
- enable_x2apic();
|
|
|
|
}
|
|
}
|
|
-#else
|
|
|
|
- if (!apic_pm_state.active)
|
|
|
|
- return 0;
|
|
|
|
|
|
|
|
- local_irq_save(flags);
|
|
|
|
- if (x2apic)
|
|
|
|
|
|
+ if (x2apic_mode)
|
|
enable_x2apic();
|
|
enable_x2apic();
|
|
-#endif
|
|
|
|
-
|
|
|
|
else {
|
|
else {
|
|
/*
|
|
/*
|
|
* Make sure the APICBASE points to the right address
|
|
* Make sure the APICBASE points to the right address
|
|
@@ -2055,21 +2099,16 @@ static int lapic_resume(struct sys_device *dev)
|
|
apic_write(APIC_ESR, 0);
|
|
apic_write(APIC_ESR, 0);
|
|
apic_read(APIC_ESR);
|
|
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();
|
|
unmask_8259A();
|
|
restore_IO_APIC_setup(ioapic_entries);
|
|
restore_IO_APIC_setup(ioapic_entries);
|
|
free_ioapic_entries(ioapic_entries);
|
|
free_ioapic_entries(ioapic_entries);
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
-
|
|
|
|
|
|
+restore:
|
|
local_irq_restore(flags);
|
|
local_irq_restore(flags);
|
|
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2117,31 +2156,14 @@ static void apic_pm_activate(void) { }
|
|
#endif /* CONFIG_PM */
|
|
#endif /* CONFIG_PM */
|
|
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#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;
|
|
int i, clusters, zeros;
|
|
unsigned id;
|
|
unsigned id;
|
|
u16 *bios_cpu_apicid;
|
|
u16 *bios_cpu_apicid;
|
|
DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
|
|
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);
|
|
bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid);
|
|
bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
|
|
bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
|
|
|
|
|
|
@@ -2177,18 +2199,67 @@ __cpuinit int apic_is_clustered_box(void)
|
|
++zeros;
|
|
++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;
|
|
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
|
|
#endif
|
|
|
|
|