diff options
author | jhb <jhb@FreeBSD.org> | 2010-06-15 18:51:41 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2010-06-15 18:51:41 +0000 |
commit | 3e2692fd422754febd92a4d1613d4c2d454b8adc (patch) | |
tree | d79d22ca750365c31e1642d7bfb41c3704ee18a3 | |
parent | c907b418fb8aa37b08afb920eb5d944466e1e0f6 (diff) | |
download | FreeBSD-src-3e2692fd422754febd92a4d1613d4c2d454b8adc.zip FreeBSD-src-3e2692fd422754febd92a4d1613d4c2d454b8adc.tar.gz |
Restore the machine check register banks on resume. For banks being
monitored via CMCI, reset the interrupt threshold to 1 on resume.
Reviewed by: jkim
MFC after: 2 weeks
-rw-r--r-- | sys/amd64/acpica/acpi_wakeup.c | 2 | ||||
-rw-r--r-- | sys/amd64/amd64/mp_machdep.c | 1 | ||||
-rw-r--r-- | sys/amd64/include/mca.h | 1 | ||||
-rw-r--r-- | sys/i386/acpica/acpi_wakeup.c | 2 | ||||
-rw-r--r-- | sys/i386/include/mca.h | 1 | ||||
-rw-r--r-- | sys/x86/x86/mca.c | 85 |
6 files changed, 73 insertions, 19 deletions
diff --git a/sys/amd64/acpica/acpi_wakeup.c b/sys/amd64/acpica/acpi_wakeup.c index af9c2b4..5c35593 100644 --- a/sys/amd64/acpica/acpi_wakeup.c +++ b/sys/amd64/acpica/acpi_wakeup.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <vm/pmap.h> #include <machine/intr_machdep.h> +#include <machine/mca.h> #include <machine/pcb.h> #include <machine/pmap.h> #include <machine/specialreg.h> @@ -300,6 +301,7 @@ out: #endif load_cr3(cr3); + mca_resume(); intr_resume(); intr_restore(rf); diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index df02255..1bd7200 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -1264,6 +1264,7 @@ cpususpend_handler(void) /* Restore CR3 and enable interrupts */ load_cr3(cr3); + mca_resume(); lapic_setup(0); intr_restore(rf); } diff --git a/sys/amd64/include/mca.h b/sys/amd64/include/mca.h index 951750f..dd6e69c 100644 --- a/sys/amd64/include/mca.h +++ b/sys/amd64/include/mca.h @@ -49,6 +49,7 @@ struct mca_record { void cmc_intr(void); void mca_init(void); int mca_intr(void); +void mca_resume(void); #endif diff --git a/sys/i386/acpica/acpi_wakeup.c b/sys/i386/acpica/acpi_wakeup.c index af8d4b2..60bc31f 100644 --- a/sys/i386/acpica/acpi_wakeup.c +++ b/sys/i386/acpica/acpi_wakeup.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/cpufunc.h> #include <machine/intr_machdep.h> +#include <machine/mca.h> #include <machine/segments.h> #include <contrib/dev/acpica/include/acpi.h> @@ -272,6 +273,7 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state) for (;;) ; } else { /* Execute Wakeup */ + mca_resume(); intr_resume(); if (bootverbose) { diff --git a/sys/i386/include/mca.h b/sys/i386/include/mca.h index 951750f..dd6e69c 100644 --- a/sys/i386/include/mca.h +++ b/sys/i386/include/mca.h @@ -49,6 +49,7 @@ struct mca_record { void cmc_intr(void); void mca_init(void); int mca_intr(void); +void mca_resume(void); #endif diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c index 089c65b..b062a01 100644 --- a/sys/x86/x86/mca.c +++ b/sys/x86/x86/mca.c @@ -659,6 +659,15 @@ static void mca_setup(uint64_t mcg_cap) { + /* + * On AMD Family 10h processors, unless logging of level one TLB + * parity (L1TP) errors is disabled, enable the recommended workaround + * for Erratum 383. + */ + if (cpu_vendor_id == CPU_VENDOR_AMD && + CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) + workaround_erratum383 = 1; + mtx_init(&mca_lock, "mca", NULL, MTX_SPIN); STAILQ_INIT(&mca_records); TASK_INIT(&mca_task, 0x8000, mca_scan_cpus, NULL); @@ -727,38 +736,56 @@ cmci_monitor(int i) /* Mark this bank as monitored. */ PCPU_SET(cmci_mask, PCPU_GET(cmci_mask) | 1 << i); } + +/* + * For resume, reset the threshold for any banks we monitor back to + * one and throw away the timestamp of the last interrupt. + */ +static void +cmci_resume(int i) +{ + struct cmc_state *cc; + uint64_t ctl; + + KASSERT(i < cmc_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); + + /* Ignore banks not monitored by this CPU. */ + if (!(PCPU_GET(cmci_mask) & 1 << i)) + return; + + cc = &cmc_state[PCPU_GET(cpuid)][i]; + cc->last_intr = -ticks; + ctl = rdmsr(MSR_MC_CTL2(i)); + ctl &= ~MC_CTL2_THRESHOLD; + ctl |= MC_CTL2_CMCI_EN | 1; + wrmsr(MSR_MC_CTL2(i), ctl); +} #endif -/* Must be executed on each CPU. */ -void -mca_init(void) +/* + * Initializes per-CPU machine check registers and enables corrected + * machine check interrupts. + */ +static void +_mca_init(int boot) { uint64_t mcg_cap; uint64_t ctl, mask; - int skip; - int i; + int i, skip; /* MCE is required. */ if (!mca_enabled || !(cpu_feature & CPUID_MCE)) return; - /* - * On AMD Family 10h processors, unless logging of level one TLB - * parity (L1TP) errors is disabled, enable the recommended workaround - * for Erratum 383. - */ - if (cpu_vendor_id == CPU_VENDOR_AMD && - CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) - workaround_erratum383 = 1; - if (cpu_feature & CPUID_MCA) { - PCPU_SET(cmci_mask, 0); + if (boot) + PCPU_SET(cmci_mask, 0); mcg_cap = rdmsr(MSR_MCG_CAP); if (mcg_cap & MCG_CAP_CTL_P) /* Enable MCA features. */ wrmsr(MSR_MCG_CTL, MCG_CTL_ENABLE); - if (PCPU_GET(cpuid) == 0) + if (PCPU_GET(cpuid) == 0 && boot) mca_setup(mcg_cap); /* @@ -797,8 +824,12 @@ mca_init(void) wrmsr(MSR_MC_CTL(i), ctl); #ifdef DEV_APIC - if (mcg_cap & MCG_CAP_CMCI_P) - cmci_monitor(i); + if (mcg_cap & MCG_CAP_CMCI_P) { + if (boot) + cmci_monitor(i); + else + cmci_resume(i); + } #endif /* Clear all errors. */ @@ -806,7 +837,7 @@ mca_init(void) } #ifdef DEV_APIC - if (PCPU_GET(cmci_mask) != 0) + if (PCPU_GET(cmci_mask) != 0 && boot) lapic_enable_cmc(); #endif } @@ -814,6 +845,22 @@ mca_init(void) load_cr4(rcr4() | CR4_MCE); } +/* Must be executed on each CPU during boot. */ +void +mca_init(void) +{ + + _mca_init(1); +} + +/* Must be executed on each CPU during resume. */ +void +mca_resume(void) +{ + + _mca_init(0); +} + /* * The machine check registers for the BSP cannot be initialized until * the local APIC is initialized. This happens at SI_SUB_CPU, |