x86/mce/amd: Fix threshold limit reset
authorYazen Ghannam <yazen.ghannam@amd.com>
Tue, 24 Jun 2025 14:15:59 +0000 (14:15 +0000)
committerBorislav Petkov (AMD) <bp@alien8.de>
Fri, 27 Jun 2025 11:16:23 +0000 (13:16 +0200)
The MCA threshold limit must be reset after servicing the interrupt.

Currently, the restart function doesn't have an explicit check for this.  It
makes some assumptions based on the current limit and what's in the registers.
These assumptions don't always hold, so the limit won't be reset in some
cases.

Make the reset condition explicit. Either an interrupt/overflow has occurred
or the bank is being initialized.

Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/20250624-wip-mca-updates-v4-4-236dd74f645f@amd.com
arch/x86/kernel/cpu/mce/amd.c

index 6820ebce5d46d7858b9c19414fdfb8c6883ba9d5..5c4eb28c3ac93026d7ea696707bc8a1eed9598e9 100644 (file)
@@ -350,7 +350,6 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
 
 struct thresh_restart {
        struct threshold_block  *b;
-       int                     reset;
        int                     set_lvt_off;
        int                     lvt_off;
        u16                     old_limit;
@@ -432,13 +431,13 @@ static void threshold_restart_bank(void *_tr)
 
        rdmsr(tr->b->address, lo, hi);
 
-       if (tr->b->threshold_limit < (hi & THRESHOLD_MAX))
-               tr->reset = 1;  /* limit cannot be lower than err count */
-
-       if (tr->reset) {                /* reset err count and overflow bit */
-               hi =
-                   (hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) |
-                   (THRESHOLD_MAX - tr->b->threshold_limit);
+       /*
+        * Reset error count and overflow bit.
+        * This is done during init or after handling an interrupt.
+        */
+       if (hi & MASK_OVERFLOW_HI || tr->set_lvt_off) {
+               hi &= ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI);
+               hi |= THRESHOLD_MAX - tr->b->threshold_limit;
        } else if (tr->old_limit) {     /* change limit w/o reset */
                int new_count = (hi & THRESHOLD_MAX) +
                    (tr->old_limit - tr->b->threshold_limit);