mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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>
This commit is contained in:
1 parent
33c4b1044d
commit
bdc31d56d8
5 files changed
+59
-68
No files matched your search
@@ -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? */
|
||||
|
||||
@@ -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,36 +1137,7 @@ static void cpu_mcheck_disable(void)
|
||||
clear_cmci();
|
||||
}
|
||||
|
||||
static void intel_init_cmci(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 l, apic;
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (!mce_available(c) || !cmci_support) {
|
||||
if (opt_cpu_info)
|
||||
mce_printk(MCE_QUIET, "CMCI: CPU%d has no CMCI support\n", cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
apic = apic_read(APIC_CMCI);
|
||||
if ( apic & APIC_VECTOR_MASK )
|
||||
{
|
||||
mce_printk(MCE_QUIET, "CPU%d CMCI LVT vector (%#x) already installed\n",
|
||||
cpu, ( apic & APIC_VECTOR_MASK ));
|
||||
return;
|
||||
}
|
||||
|
||||
apic = CMCI_APIC_VECTOR;
|
||||
apic |= (APIC_DM_FIXED | APIC_LVT_MASKED);
|
||||
apic_write_around(APIC_CMCI, apic);
|
||||
|
||||
l = apic_read(APIC_CMCI);
|
||||
apic_write_around(APIC_CMCI, l & ~APIC_LVT_MASKED);
|
||||
|
||||
mce_set_owner();
|
||||
}
|
||||
|
||||
void cmci_interrupt(struct cpu_user_regs *regs)
|
||||
static void cmci_interrupt(struct cpu_user_regs *regs)
|
||||
{
|
||||
mctelem_cookie_t mctc;
|
||||
struct mca_summary bs;
|
||||
@@ -1206,6 +1160,38 @@ void cmci_interrupt(struct cpu_user_regs *regs)
|
||||
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)
|
||||
mce_printk(MCE_QUIET, "CMCI: CPU%d has no CMCI support\n", cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
apic = apic_read(APIC_CMCI);
|
||||
if ( apic & APIC_VECTOR_MASK )
|
||||
{
|
||||
mce_printk(MCE_QUIET, "CPU%d CMCI LVT vector (%#x) already installed\n",
|
||||
cpu, ( apic & APIC_VECTOR_MASK ));
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
l = apic_read(APIC_CMCI);
|
||||
apic_write_around(APIC_CMCI, l & ~APIC_LVT_MASKED);
|
||||
|
||||
mce_set_owner();
|
||||
}
|
||||
|
||||
/* MCA */
|
||||
|
||||
static int mce_is_broadcast(struct cpuinfo_x86 *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;
|
||||
|
||||
@@ -86,12 +86,12 @@ void apic_timer_interrupt(struct cpu_user_regs *regs);
|
||||
void error_interrupt(struct cpu_user_regs *regs);
|
||||
void pmu_apic_interrupt(struct cpu_user_regs *regs);
|
||||
void spurious_interrupt(struct cpu_user_regs *regs);
|
||||
void thermal_interrupt(struct cpu_user_regs *regs);
|
||||
void cmci_interrupt(struct cpu_user_regs *regs);
|
||||
void irq_move_cleanup_interrupt(struct cpu_user_regs *regs);
|
||||
|
||||
void set_direct_apic_vector(
|
||||
uint8_t vector, void (*handler)(struct cpu_user_regs *));
|
||||
void alloc_direct_apic_vector(
|
||||
uint8_t *vector, void (*handler)(struct cpu_user_regs *));
|
||||
|
||||
void do_IRQ(struct cpu_user_regs *regs);
|
||||
|
||||
|
||||
@@ -7,16 +7,14 @@
|
||||
#define INVALIDATE_TLB_VECTOR 0xfd
|
||||
#define EVENT_CHECK_VECTOR 0xfc
|
||||
#define CALL_FUNCTION_VECTOR 0xfb
|
||||
#define THERMAL_APIC_VECTOR 0xfa
|
||||
#define LOCAL_TIMER_VECTOR 0xf9
|
||||
#define PMU_APIC_VECTOR 0xf8
|
||||
#define CMCI_APIC_VECTOR 0xf7
|
||||
#define LOCAL_TIMER_VECTOR 0xfa
|
||||
#define PMU_APIC_VECTOR 0xf9
|
||||
/*
|
||||
* High-priority dynamically-allocated vectors. For interrupts that
|
||||
* must be higher priority than any guest-bound interrupt.
|
||||
*/
|
||||
#define FIRST_HIPRIORITY_VECTOR 0xf0
|
||||
#define LAST_HIPRIORITY_VECTOR 0xf6
|
||||
#define LAST_HIPRIORITY_VECTOR 0xf8
|
||||
|
||||
/* Legacy PIC uses vectors 0xe0-0xef. */
|
||||
#define FIRST_LEGACY_VECTOR 0xe0
|
||||
|
||||