/* Needs to be called during startup. It records the state the BIOS * leaves the local APIC so we can undo upon kexec. */ void __init record_boot_APIC_mode(void) { /* Sanity check - we should only ever run once, but could possibly * be called several times */ if ( APIC_MODE_INVALID != apic_boot_mode ) return; apic_boot_mode = current_local_apic_mode(); apic_printk(APIC_DEBUG, "APIC boot state is '%s'\n", apic_mode_to_str(apic_boot_mode)); }
void disable_local_APIC(void) { clear_local_APIC(); /* * Disable APIC (implies clearing of registers * for 82489DX!). */ apic_write_around(APIC_SPIV, apic_read(APIC_SPIV) & ~APIC_SPIV_APIC_ENABLED); if (enabled_via_apicbase) { uint64_t msr_content; rdmsrl(MSR_IA32_APICBASE, msr_content); wrmsrl(MSR_IA32_APICBASE, msr_content & ~(MSR_IA32_APICBASE_ENABLE|MSR_IA32_APICBASE_EXTD)); } if ( kexecing && (current_local_apic_mode() != apic_boot_mode) ) { uint64_t msr_content; rdmsrl(MSR_IA32_APICBASE, msr_content); msr_content &= ~(MSR_IA32_APICBASE_ENABLE|MSR_IA32_APICBASE_EXTD); wrmsrl(MSR_IA32_APICBASE, msr_content); switch ( apic_boot_mode ) { case APIC_MODE_DISABLED: break; /* Nothing to do - we did this above */ case APIC_MODE_XAPIC: msr_content |= MSR_IA32_APICBASE_ENABLE; wrmsrl(MSR_IA32_APICBASE, msr_content); break; case APIC_MODE_X2APIC: msr_content |= MSR_IA32_APICBASE_ENABLE; wrmsrl(MSR_IA32_APICBASE, msr_content); msr_content |= MSR_IA32_APICBASE_EXTD; wrmsrl(MSR_IA32_APICBASE, msr_content); break; default: printk("Default case when reverting #%d lapic to boot state\n", smp_processor_id()); break; } } }
static void nmi_shootdown_cpus(void) { unsigned long msecs; local_irq_disable(); if ( hpet_broadcast_is_available() ) hpet_disable_legacy_broadcast(); crashing_cpu = smp_processor_id(); local_irq_count(crashing_cpu) = 0; atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); /* Would it be better to replace the trap vector here? */ set_nmi_callback(crash_nmi_callback); /* Ensure the new callback function is set before sending out the NMI. */ wmb(); smp_send_nmi_allbutself(); msecs = 1000; /* Wait at most a second for the other cpus to stop */ while ( (atomic_read(&waiting_for_crash_ipi) > 0) && msecs ) { mdelay(1); msecs--; } /* Crash shutdown any IOMMU functionality as the crashdump kernel is not * happy when booting if interrupt/dma remapping is still enabled */ iommu_crash_shutdown(); __stop_this_cpu(); /* This is a bit of a hack due to the problems with the x2apic_enabled * variable, but we can't do any better without a significant refactoring * of the APIC code */ x2apic_enabled = (current_local_apic_mode() == APIC_MODE_X2APIC); disable_IO_APIC(); hpet_disable(); }