Index: FreeBSD/sys/x86/x86/mca.c =================================================================== --- FreeBSD/sys/x86/x86/mca.c +++ FreeBSD/sys/x86/x86/mca.c @@ -116,10 +116,11 @@ static STAILQ_HEAD(, mca_internal) mca_freelist; static int mca_freecount; static STAILQ_HEAD(, mca_internal) mca_records; +static struct mca_internal *mca_lastrec = NULL; static struct callout mca_timer; static int mca_ticks = 3600; /* Check hourly by default. */ static struct taskqueue *mca_tq; -static struct task mca_refill_task, mca_scan_task; +static struct task mca_postscan_task, mca_scan_task; static struct mtx mca_lock; #ifdef DEV_APIC @@ -491,10 +492,40 @@ } static void -mca_refill(void *context, int pending) +mca_emit_logs(void) +{ + struct mca_internal *mca; + + mtx_lock_spin(&mca_lock); + if (mca_lastrec == NULL) + mca = STAILQ_FIRST(&mca_records); + else + mca = STAILQ_NEXT(mca_lastrec, link); + if (mca != NULL) { + STAILQ_FOREACH_FROM(mca, &mca_records, link) { + if (!mca->logged) { + mca->logged = 1; + mca_log(&mca->rec); + } + mca_lastrec = mca; + } + mca_lastrec = STAILQ_LAST(&mca_records, mca_internal, link); + } + mtx_unlock_spin(&mca_lock); +} + +/* + * Refill the free list and log any unlogged messages. This is + * intended to be called from a task queue and to handle work which + * does not need to be done (or cannot be done) in the hardware + * interrupt context. + */ +static void +mca_postscan(void *context __unused, int pending __unused) { mca_fill_freelist(); + mca_emit_logs(); } static void @@ -523,8 +554,6 @@ STAILQ_INSERT_TAIL(&mca_records, rec, link); mca_count++; mtx_unlock_spin(&mca_lock); - if (mode == CMCI && !cold) - taskqueue_enqueue(mca_tq, &mca_refill_task); } #ifdef DEV_APIC @@ -717,7 +746,6 @@ static void mca_scan_cpus(void *context, int pending) { - struct mca_internal *mca; struct thread *td; int count, cpu; @@ -733,16 +761,8 @@ sched_unbind(td); } thread_unlock(td); - if (count != 0) { - mtx_lock_spin(&mca_lock); - STAILQ_FOREACH(mca, &mca_records, link) { - if (!mca->logged) { - mca->logged = 1; - mca_log(&mca->rec); - } - } - mtx_unlock_spin(&mca_lock); - } + if (count != 0) + mca_emit_logs(); } static void @@ -786,6 +806,9 @@ mca_startup(void *dummy) { + /* Handle any events that might have been logged during startup. */ + mca_postscan(NULL, 0); + if (mca_banks <= 0) return; @@ -846,7 +869,7 @@ TASK_INIT(&mca_scan_task, 0, mca_scan_cpus, NULL); callout_init(&mca_timer, 1); STAILQ_INIT(&mca_freelist); - TASK_INIT(&mca_refill_task, 0, mca_refill, NULL); + TASK_INIT(&mca_postscan_task, 0, mca_postscan, NULL); mca_fill_freelist(); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "count", CTLFLAG_RD, (int *)(uintptr_t)&mca_count, 0, @@ -1183,6 +1206,10 @@ panic("Unrecoverable machine check exception"); } + /* Schedule post-processing to log the message(s). */ + if (!cold) + taskqueue_enqueue(mca_tq, &mca_postscan_task); + /* Clear MCIP. */ wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP); } @@ -1192,7 +1219,6 @@ void cmc_intr(void) { - struct mca_internal *mca; int count; /* @@ -1201,16 +1227,8 @@ */ count = mca_scan(CMCI, NULL); - /* If we found anything, log them to the console. */ - if (count != 0) { - mtx_lock_spin(&mca_lock); - STAILQ_FOREACH(mca, &mca_records, link) { - if (!mca->logged) { - mca->logged = 1; - mca_log(&mca->rec); - } - } - mtx_unlock_spin(&mca_lock); - } + /* If we found anything, do post-processing. */ + if (count > 0 && !cold) + taskqueue_enqueue(mca_tq, &mca_postscan_task); } #endif