aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2012-03-30 09:14:25 +0100
committerKeir Fraser <keir@xen.org>2012-03-30 09:14:25 +0100
commitbdc31d56d83d9de76dd501d33b90d59cf583b630 (patch)
tree315b3748d94f9fbb40749b0c89a81b63dc19d63d /xen/arch
parent33c4b1044d00866e9b6d9362048fb194e76afb77 (diff)
downloadxen-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.c8
-rw-r--r--xen/arch/x86/cpu/mcheck/mce_intel.c80
-rw-r--r--xen/arch/x86/irq.c15
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;