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
This commit is contained in:
parent
ecd5dd957d
commit
61d3f0bab2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=209212
@ -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 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
|
||||
#endif
|
||||
|
||||
load_cr3(cr3);
|
||||
mca_resume();
|
||||
intr_resume();
|
||||
intr_restore(rf);
|
||||
|
||||
|
@ -1264,6 +1264,7 @@ cpususpend_handler(void)
|
||||
|
||||
/* Restore CR3 and enable interrupts */
|
||||
load_cr3(cr3);
|
||||
mca_resume();
|
||||
lapic_setup(0);
|
||||
intr_restore(rf);
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ struct mca_record {
|
||||
void cmc_intr(void);
|
||||
void mca_init(void);
|
||||
int mca_intr(void);
|
||||
void mca_resume(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -49,6 +49,7 @@ struct mca_record {
|
||||
void cmc_intr(void);
|
||||
void mca_init(void);
|
||||
int mca_intr(void);
|
||||
void mca_resume(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user