aboutsummaryrefslogtreecommitdiff
path: root/sys/x86/x86/local_apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/x86/x86/local_apic.c')
-rw-r--r--sys/x86/x86/local_apic.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index f40026bb3037..7fec4f6cd69a 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/apicvar.h>
+#include <machine/mca.h>
#include <machine/md_var.h>
#include <machine/smp.h>
#include <machine/specialreg.h>
@@ -130,6 +131,7 @@ static struct lvt lvts[LVT_MAX + 1] = {
{ 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 */
+ { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_CMC_INT }, /* CMCI */
};
static inthand_t *ioint_handlers[] = {
@@ -235,6 +237,9 @@ lapic_init(vm_paddr_t addr)
setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_APIC, SEL_KPL, GSEL_APIC);
/* XXX: Thermal interrupt */
+
+ /* Local APIC CMCI. */
+ setidt(APIC_CMC_INT, IDTVEC(cmcint), SDT_APICT, SEL_KPL, GSEL_APIC);
}
/*
@@ -260,7 +265,7 @@ lapic_create(u_int apic_id, int boot_cpu)
*/
lapics[apic_id].la_present = 1;
lapics[apic_id].la_id = apic_id;
- for (i = 0; i < LVT_MAX; i++) {
+ for (i = 0; i <= LVT_MAX; i++) {
lapics[apic_id].la_lvts[i] = lvts[i];
lapics[apic_id].la_lvts[i].lvt_active = 0;
}
@@ -290,6 +295,7 @@ lapic_dump(const char* str)
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);
+ printf(" cmci: 0x%08x\n", lapic->lvt_cmci);
}
void
@@ -341,6 +347,10 @@ lapic_setup(int boot)
/* XXX: Thermal LVT */
+ /* Program the CMCI LVT entry if present. */
+ if (maxlvt >= LVT_CMCI)
+ lapic->lvt_cmci = lvt_mode(la, LVT_CMCI, lapic->lvt_cmci);
+
intr_restore(eflags);
}
@@ -838,6 +848,34 @@ lapic_timer_enable_intr(void)
}
void
+lapic_handle_cmc(void)
+{
+
+ lapic_eoi();
+ cmc_intr();
+}
+
+/*
+ * Called from the mca_init() to activate the CMC interrupt if this CPU is
+ * responsible for monitoring any MC banks for CMC events. Since mca_init()
+ * is called prior to lapic_setup() during boot, this just needs to unmask
+ * this CPU's LVT_CMCI entry.
+ */
+void
+lapic_enable_cmc(void)
+{
+ u_int apic_id;
+
+ apic_id = PCPU_GET(apic_id);
+ KASSERT(lapics[apic_id].la_present,
+ ("%s: missing APIC %u", __func__, apic_id));
+ lapics[apic_id].la_lvts[LVT_CMCI].lvt_masked = 0;
+ lapics[apic_id].la_lvts[LVT_CMCI].lvt_active = 1;
+ if (bootverbose)
+ printf("lapic%u: CMCI unmasked\n", apic_id);
+}
+
+void
lapic_handle_error(void)
{
u_int32_t esr;