diff options
author | Keir Fraser <keir@xen.org> | 2012-03-30 09:14:25 +0100 |
---|---|---|
committer | Keir Fraser <keir@xen.org> | 2012-03-30 09:14:25 +0100 |
commit | bdc31d56d83d9de76dd501d33b90d59cf583b630 (patch) | |
tree | 315b3748d94f9fbb40749b0c89a81b63dc19d63d /xen/arch | |
parent | 33c4b1044d00866e9b6d9362048fb194e76afb77 (diff) | |
download | xen-bdc31d56d83d9de76dd501d33b90d59cf583b630.tar.gz xen-bdc31d56d83d9de76dd501d33b90d59cf583b630.tar.bz2 xen-bdc31d56d83d9de76dd501d33b90d59cf583b630.zip |
x86: Allow direct vectored interrupts to be dynamically allocated.
Use this for Intel's CMCI and thermal interrupts.
Signed-off-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch')
-rw-r--r-- | xen/arch/x86/apic.c | 8 | ||||
-rw-r--r-- | xen/arch/x86/cpu/mcheck/mce_intel.c | 80 | ||||
-rw-r--r-- | xen/arch/x86/irq.c | 15 |
3 files changed, 48 insertions, 55 deletions
diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index cde3cd5dfc..e05dd82bb2 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -128,14 +128,6 @@ void __init apic_intr_init(void) /* Performance Counters Interrupt */ set_direct_apic_vector(PMU_APIC_VECTOR, pmu_apic_interrupt); - - /* CMCI Correctable Machine Check Interrupt */ - set_direct_apic_vector(CMCI_APIC_VECTOR, cmci_interrupt); - - /* thermal monitor LVT interrupt, for P4 and latest Intel CPU*/ -#ifdef CONFIG_X86_MCE_THERMAL - set_direct_apic_vector(THERMAL_APIC_VECTOR, thermal_interrupt); -#endif } /* Using APIC to generate smp_local_timer_interrupt? */ diff --git a/xen/arch/x86/cpu/mcheck/mce_intel.c b/xen/arch/x86/cpu/mcheck/mce_intel.c index e2eed836d5..2d6c2f5307 100644 --- a/xen/arch/x86/cpu/mcheck/mce_intel.c +++ b/xen/arch/x86/cpu/mcheck/mce_intel.c @@ -46,22 +46,15 @@ static int __read_mostly nr_intel_ext_msrs; #define INTEL_SRAR_DATA_LOAD 0x134 #define INTEL_SRAR_INSTR_FETCH 0x150 -/* Thermal Hanlding */ #ifdef CONFIG_X86_MCE_THERMAL -static void unexpected_thermal_interrupt(struct cpu_user_regs *regs) -{ - printk(KERN_ERR "Thermal: CPU%d: Unexpected LVT TMR interrupt!\n", - smp_processor_id()); - add_taint(TAINT_MACHINE_CHECK); -} - -/* P4/Xeon Thermal transition interrupt handler */ static void intel_thermal_interrupt(struct cpu_user_regs *regs) { uint64_t msr_content; unsigned int cpu = smp_processor_id(); static DEFINE_PER_CPU(s_time_t, next); + ack_APIC_irq(); + if (NOW() < per_cpu(next, cpu)) return; @@ -77,16 +70,6 @@ static void intel_thermal_interrupt(struct cpu_user_regs *regs) } } -/* Thermal interrupt handler for this CPU setup */ -static void (*__read_mostly vendor_thermal_interrupt)( - struct cpu_user_regs *regs) = unexpected_thermal_interrupt; - -void thermal_interrupt(struct cpu_user_regs *regs) -{ - ack_APIC_irq(); - vendor_thermal_interrupt(regs); -} - /* Thermal monitoring depends on APIC, ACPI and clock modulation */ static int intel_thermal_supported(struct cpuinfo_x86 *c) { @@ -117,6 +100,7 @@ static void intel_init_thermal(struct cpuinfo_x86 *c) uint32_t val; int tm2 = 0; unsigned int cpu = smp_processor_id(); + static uint8_t thermal_apic_vector; if (!intel_thermal_supported(c)) return; /* -ENODEV */ @@ -159,17 +143,16 @@ static void intel_init_thermal(struct cpuinfo_x86 *c) return; /* -EBUSY */ } + alloc_direct_apic_vector(&thermal_apic_vector, intel_thermal_interrupt); + /* The temperature transition interrupt handler setup */ - val = THERMAL_APIC_VECTOR; /* our delivery vector */ + val = thermal_apic_vector; /* our delivery vector */ val |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */ apic_write_around(APIC_LVTTHMR, val); rdmsrl(MSR_IA32_THERM_INTERRUPT, msr_content); wrmsrl(MSR_IA32_THERM_INTERRUPT, msr_content | 0x03); - /* ok we're good to go... */ - vendor_thermal_interrupt = intel_thermal_interrupt; - rdmsrl(MSR_IA32_MISC_ENABLE, msr_content); wrmsrl(MSR_IA32_MISC_ENABLE, msr_content | (1ULL<<3)); @@ -1154,10 +1137,34 @@ static void cpu_mcheck_disable(void) clear_cmci(); } +static void cmci_interrupt(struct cpu_user_regs *regs) +{ + mctelem_cookie_t mctc; + struct mca_summary bs; + + ack_APIC_irq(); + + mctc = mcheck_mca_logout( + MCA_CMCI_HANDLER, __get_cpu_var(mce_banks_owned), &bs, NULL); + + if (bs.errcnt && mctc != NULL) { + if (dom0_vmce_enabled()) { + mctelem_commit(mctc); + mce_printk(MCE_VERBOSE, "CMCI: send CMCI to DOM0 through virq\n"); + send_global_virq(VIRQ_MCA); + } else { + x86_mcinfo_dump(mctelem_dataptr(mctc)); + mctelem_dismiss(mctc); + } + } else if (mctc != NULL) + mctelem_dismiss(mctc); +} + static void intel_init_cmci(struct cpuinfo_x86 *c) { u32 l, apic; int cpu = smp_processor_id(); + static uint8_t cmci_apic_vector; if (!mce_available(c) || !cmci_support) { if (opt_cpu_info) @@ -1173,7 +1180,9 @@ static void intel_init_cmci(struct cpuinfo_x86 *c) return; } - apic = CMCI_APIC_VECTOR; + alloc_direct_apic_vector(&cmci_apic_vector, cmci_interrupt); + + apic = cmci_apic_vector; apic |= (APIC_DM_FIXED | APIC_LVT_MASKED); apic_write_around(APIC_CMCI, apic); @@ -1183,29 +1192,6 @@ static void intel_init_cmci(struct cpuinfo_x86 *c) mce_set_owner(); } -void cmci_interrupt(struct cpu_user_regs *regs) -{ - mctelem_cookie_t mctc; - struct mca_summary bs; - - ack_APIC_irq(); - - mctc = mcheck_mca_logout( - MCA_CMCI_HANDLER, __get_cpu_var(mce_banks_owned), &bs, NULL); - - if (bs.errcnt && mctc != NULL) { - if (dom0_vmce_enabled()) { - mctelem_commit(mctc); - mce_printk(MCE_VERBOSE, "CMCI: send CMCI to DOM0 through virq\n"); - send_global_virq(VIRQ_MCA); - } else { - x86_mcinfo_dump(mctelem_dataptr(mctc)); - mctelem_dismiss(mctc); - } - } else if (mctc != NULL) - mctelem_dismiss(mctc); -} - /* MCA */ static int mce_is_broadcast(struct cpuinfo_x86 *c) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index ab5fd15556..2e150bc05b 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -772,6 +772,21 @@ void set_direct_apic_vector( direct_apic_vector[vector] = handler; } +void alloc_direct_apic_vector( + uint8_t *vector, void (*handler)(struct cpu_user_regs *)) +{ + static uint8_t next = LAST_HIPRIORITY_VECTOR; + static DEFINE_SPINLOCK(lock); + + spin_lock(&lock); + if (*vector == 0) { + BUG_ON(next == FIRST_HIPRIORITY_VECTOR); + set_direct_apic_vector(next, handler); + *vector = next--; + } + spin_unlock(&lock); +} + void do_IRQ(struct cpu_user_regs *regs) { struct irqaction *action; |