summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2010-03-29 19:13:34 +0000
committerjhb <jhb@FreeBSD.org>2010-03-29 19:13:34 +0000
commitf3f4fff664d11e6372ad59b8fc307ab0244a8f71 (patch)
tree6f6f6806b0f1caeb147f69e12a3fa672cec7b4b5 /sys/i386
parent78907598c04661c36428e3f5b02ee6a80af4aac5 (diff)
downloadFreeBSD-src-f3f4fff664d11e6372ad59b8fc307ab0244a8f71.zip
FreeBSD-src-f3f4fff664d11e6372ad59b8fc307ab0244a8f71.tar.gz
Add a handler for the local APIC error interrupt. For now it just prints
out the current value of the local APIC error register when the interrupt fires. MFC after: 1 week
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/apic_vector.s13
-rw-r--r--sys/i386/i386/local_apic.c48
-rw-r--r--sys/i386/include/apicvar.h5
3 files changed, 46 insertions, 20 deletions
diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s
index d4dd90b..c4c5b01 100644
--- a/sys/i386/i386/apic_vector.s
+++ b/sys/i386/i386/apic_vector.s
@@ -110,6 +110,19 @@ IDTVEC(timerint)
MEXITCOUNT
jmp doreti
+/*
+ * Local APIC error interrupt handler.
+ */
+ .text
+ SUPERALIGN_TEXT
+IDTVEC(errorint)
+ PUSH_FRAME
+ SET_KERNEL_SREGS
+ FAKE_MCOUNT(TF_EIP(%esp))
+ call lapic_handle_error
+ MEXITCOUNT
+ jmp doreti
+
#ifdef SMP
/*
* Global address space TLB shootdown.
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c
index 6c62200..302535f 100644
--- a/sys/i386/i386/local_apic.c
+++ b/sys/i386/i386/local_apic.c
@@ -116,14 +116,12 @@ struct lapic {
int la_ioint_irqs[APIC_NUM_IOINTS + 1];
} static lapics[MAX_APIC_ID + 1];
-/* XXX: should thermal be an NMI? */
-
/* Global defaults for local APIC LVT entries. */
static struct lvt lvts[LVT_MAX + 1] = {
{ 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 }, /* LINT0: masked ExtINT */
{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */
- { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
+ { 1, 1, 0, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
{ 1, 1, 1, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */
};
@@ -228,7 +226,11 @@ lapic_init(vm_paddr_t addr)
setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
- /* XXX: error/thermal interrupts */
+ /* Local APIC error interrupt. */
+ setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_SYS386IGT, SEL_KPL,
+ GSEL(GCODE_SEL, SEL_KPL));
+
+ /* XXX: Thermal interrupt */
}
/*
@@ -281,7 +283,7 @@ lapic_dump(const char* str)
lapic->id, lapic->version, lapic->ldr, lapic->dfr);
printf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
- printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pcm: 0x%08x\n",
+ printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pmc: 0x%08x\n",
lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error,
lapic->lvt_pcint);
}
@@ -329,7 +331,11 @@ lapic_setup(int boot)
lapic_timer_enable_intr();
}
- /* XXX: Error and thermal LVTs */
+ /* Program error LVT and clear any existing errors. */
+ lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
+ lapic->esr = 0;
+
+ /* XXX: Thermal LVT */
intr_restore(eflags);
}
@@ -725,18 +731,6 @@ lapic_eoi(void)
lapic->eoi = 0;
}
-/*
- * Read the contents of the error status register. We have to write
- * to the register first before reading from it.
- */
-u_int
-lapic_error(void)
-{
-
- lapic->esr = 0;
- return (lapic->esr);
-}
-
void
lapic_handle_intr(int vector, struct trapframe *frame)
{
@@ -863,6 +857,24 @@ lapic_timer_enable_intr(void)
lapic->lvt_timer = value;
}
+void
+lapic_handle_error(void)
+{
+ u_int32_t esr;
+
+ /*
+ * Read the contents of the error status register. Write to
+ * the register first before reading from it to force the APIC
+ * to update its value to indicate any errors that have
+ * occurred since the previous write to the register.
+ */
+ lapic->esr = 0;
+ esr = lapic->esr;
+
+ printf("CPU%d: local APIC error 0x%x\n", PCPU_GET(cpuid), esr);
+ lapic_eoi();
+}
+
u_int
apic_cpuid(u_int apic_id)
{
diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h
index 208ffb5..bcb84a0 100644
--- a/sys/i386/include/apicvar.h
+++ b/sys/i386/include/apicvar.h
@@ -208,7 +208,8 @@ struct apic_enumerator {
inthand_t
IDTVEC(apic_isr1), IDTVEC(apic_isr2), IDTVEC(apic_isr3),
IDTVEC(apic_isr4), IDTVEC(apic_isr5), IDTVEC(apic_isr6),
- IDTVEC(apic_isr7), IDTVEC(spuriousint), IDTVEC(timerint);
+ IDTVEC(apic_isr7), IDTVEC(errorint), IDTVEC(spuriousint),
+ IDTVEC(timerint);
extern vm_paddr_t lapic_paddr;
extern int apic_cpuids[];
@@ -240,13 +241,13 @@ void lapic_disable_pmc(void);
void lapic_dump(const char *str);
int lapic_enable_pmc(void);
void lapic_eoi(void);
-u_int lapic_error(void);
int lapic_id(void);
void lapic_init(vm_paddr_t addr);
int lapic_intr_pending(u_int vector);
void lapic_ipi_raw(register_t icrlo, u_int dest);
void lapic_ipi_vectored(u_int vector, int dest);
int lapic_ipi_wait(int delay);
+void lapic_handle_error(void);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
void lapic_reenable_pmc(void);
OpenPOWER on IntegriCloud