@@ -47,7 +47,6 @@ void intel_init_cmci(void);
void intel_init_lmce(void);
void intel_clear_lmce(void);
bool intel_filter_mce(struct mce *m);
-void track_cmci_storm(int bank, u64 status);
#else
static inline void mce_intel_handle_storm(int bank, bool on) { }
static inline void cmci_disable_bank(int bank) { }
@@ -55,11 +54,28 @@ static inline void intel_init_cmci(void) { }
static inline void intel_init_lmce(void) { }
static inline void intel_clear_lmce(void) { }
static inline bool intel_filter_mce(struct mce *m) { return false; }
-static inline void track_cmci_storm(int bank, u64 status) { }
#endif
void mce_timer_kick(bool storm);
void mce_handle_storm(int bank, bool on);
+void cmci_storm_begin(int bank);
+void cmci_storm_end(int bank);
+
+DECLARE_PER_CPU(int, stormy_bank_count);
+DECLARE_PER_CPU(u64 [MAX_NR_BANKS], bank_history);
+DECLARE_PER_CPU(bool [MAX_NR_BANKS], bank_storm);
+DECLARE_PER_CPU(unsigned long [MAX_NR_BANKS], bank_time_stamp);
+
+/*
+ * How many errors within the history buffer mark the start of a storm
+ */
+#define STORM_BEGIN_THRESHOLD 5
+
+/*
+ * How many polls of machine check bank without an error before declaring
+ * the storm is over
+ */
+#define STORM_END_POLL_THRESHOLD 30
#ifdef CONFIG_ACPI_APEI
int apei_write_mce(struct mce *m);
@@ -607,6 +607,87 @@ static struct notifier_block mce_default_nb = {
.priority = MCE_PRIO_LOWEST,
};
+/*
+ * CMCI storm tracking state
+ * stormy_bank_count: per-cpu count of MC banks in storm state
+ * bank_history: bitmask tracking of corrected errors seen in each bank
+ * bank_time_stamp: last time (in jiffies) that each bank was polled
+ */
+DEFINE_PER_CPU(int, stormy_bank_count);
+DEFINE_PER_CPU(u64 [MAX_NR_BANKS], bank_history);
+DEFINE_PER_CPU(bool [MAX_NR_BANKS], bank_storm);
+DEFINE_PER_CPU(unsigned long [MAX_NR_BANKS], bank_time_stamp);
+
+void cmci_storm_begin(int bank)
+{
+ __set_bit(bank, this_cpu_ptr(mce_poll_banks));
+ this_cpu_write(bank_storm[bank], true);
+
+ /*
+ * If this is the first bank on this CPU to enter storm mode
+ * start polling
+ */
+ if (this_cpu_inc_return(stormy_bank_count) == 1)
+ mce_timer_kick(true);
+}
+
+void cmci_storm_end(int bank)
+{
+ __clear_bit(bank, this_cpu_ptr(mce_poll_banks));
+ this_cpu_write(bank_history[bank], 0ull);
+ this_cpu_write(bank_storm[bank], false);
+
+ /* If no banks left in storm mode, stop polling */
+ if (!this_cpu_dec_return(stormy_bank_count))
+ mce_timer_kick(false);
+}
+
+void track_cmci_storm(int bank, u64 status)
+{
+ unsigned long now = jiffies, delta;
+ unsigned int shift = 1;
+ u64 history;
+
+ /*
+ * When a bank is in storm mode it is polled once per second and
+ * the history mask will record about the last minute of poll results.
+ * If it is not in storm mode, then the bank is only checked when
+ * there is a CMCI interrupt. Check how long it has been since
+ * this bank was last checked, and adjust the amount of "shift"
+ * to apply to history.
+ */
+ if (!this_cpu_read(bank_storm[bank])) {
+ delta = now - this_cpu_read(bank_time_stamp[bank]);
+ shift = (delta + HZ) / HZ;
+ }
+
+ /* If has been a long time since the last poll, clear history */
+ if (shift >= 64)
+ history = 0;
+ else
+ history = this_cpu_read(bank_history[bank]) << shift;
+ this_cpu_write(bank_time_stamp[bank], now);
+
+ /* History keeps track of corrected errors. VAL=1 && UC=0 */
+ if ((status & (MCI_STATUS_VAL | MCI_STATUS_UC)) == MCI_STATUS_VAL)
+ history |= 1;
+ this_cpu_write(bank_history[bank], history);
+
+ if (this_cpu_read(bank_storm[bank])) {
+ if (history & GENMASK_ULL(STORM_END_POLL_THRESHOLD - 1, 0))
+ return;
+ pr_notice("CPU%d BANK%d CMCI storm subsided\n", smp_processor_id(), bank);
+ mce_handle_storm(bank, false);
+ cmci_storm_end(bank);
+ } else {
+ if (hweight64(history) < STORM_BEGIN_THRESHOLD)
+ return;
+ pr_notice("CPU%d BANK%d CMCI storm detected\n", smp_processor_id(), bank);
+ mce_handle_storm(bank, true);
+ cmci_storm_begin(bank);
+ }
+}
+
/*
* Read ADDR and MISC registers.
*/
@@ -47,17 +47,7 @@ static DEFINE_PER_CPU(mce_banks_t, mce_banks_owned);
*/
static DEFINE_RAW_SPINLOCK(cmci_discover_lock);
-/*
- * CMCI storm tracking state
- * stormy_bank_count: per-cpu count of MC banks in storm state
- * bank_history: bitmask tracking of corrected errors seen in each bank
- * bank_time_stamp: last time (in jiffies) that each bank was polled
- * cmci_threshold: MCi_CTL2 threshold for each bank when there is no storm
- */
-static DEFINE_PER_CPU(int, stormy_bank_count);
-static DEFINE_PER_CPU(u64 [MAX_NR_BANKS], bank_history);
-static DEFINE_PER_CPU(bool [MAX_NR_BANKS], bank_storm);
-static DEFINE_PER_CPU(unsigned long [MAX_NR_BANKS], bank_time_stamp);
+/* MCi_CTL2 threshold for each bank when there is no storm */
static int cmci_threshold[MAX_NR_BANKS];
/* Linux non-storm CMCI threshold (may be overridden by BIOS */
@@ -70,17 +60,6 @@ static int cmci_threshold[MAX_NR_BANKS];
*/
#define CMCI_STORM_THRESHOLD 32749
-/*
- * How many errors within the history buffer mark the start of a storm
- */
-#define STORM_BEGIN_THRESHOLD 5
-
-/*
- * How many polls of machine check bank without an error before declaring
- * the storm is over
- */
-#define STORM_END_POLL_THRESHOLD 30
-
static int cmci_supported(int *banks)
{
u64 cap;
@@ -160,76 +139,6 @@ void mce_intel_handle_storm(int bank, bool on)
cmci_set_threshold(bank, cmci_threshold[bank]);
}
-static void cmci_storm_begin(int bank)
-{
- __set_bit(bank, this_cpu_ptr(mce_poll_banks));
- this_cpu_write(bank_storm[bank], true);
-
- /*
- * If this is the first bank on this CPU to enter storm mode
- * start polling
- */
- if (this_cpu_inc_return(stormy_bank_count) == 1)
- mce_timer_kick(true);
-}
-
-static void cmci_storm_end(int bank)
-{
- __clear_bit(bank, this_cpu_ptr(mce_poll_banks));
- this_cpu_write(bank_history[bank], 0ull);
- this_cpu_write(bank_storm[bank], false);
-
- /* If no banks left in storm mode, stop polling */
- if (!this_cpu_dec_return(stormy_bank_count))
- mce_timer_kick(false);
-}
-
-void track_cmci_storm(int bank, u64 status)
-{
- unsigned long now = jiffies, delta;
- unsigned int shift = 1;
- u64 history;
-
- /*
- * When a bank is in storm mode it is polled once per second and
- * the history mask will record about the last minute of poll results.
- * If it is not in storm mode, then the bank is only checked when
- * there is a CMCI interrupt. Check how long it has been since
- * this bank was last checked, and adjust the amount of "shift"
- * to apply to history.
- */
- if (!this_cpu_read(bank_storm[bank])) {
- delta = now - this_cpu_read(bank_time_stamp[bank]);
- shift = (delta + HZ) / HZ;
- }
-
- /* If has been a long time since the last poll, clear history */
- if (shift >= 64)
- history = 0;
- else
- history = this_cpu_read(bank_history[bank]) << shift;
- this_cpu_write(bank_time_stamp[bank], now);
-
- /* History keeps track of corrected errors. VAL=1 && UC=0 */
- if ((status & (MCI_STATUS_VAL | MCI_STATUS_UC)) == MCI_STATUS_VAL)
- history |= 1;
- this_cpu_write(bank_history[bank], history);
-
- if (this_cpu_read(bank_storm[bank])) {
- if (history & GENMASK_ULL(STORM_END_POLL_THRESHOLD - 1, 0))
- return;
- pr_notice("CPU%d BANK%d CMCI storm subsided\n", smp_processor_id(), bank);
- mce_handle_storm(bank, false);
- cmci_storm_end(bank);
- } else {
- if (hweight64(history) < STORM_BEGIN_THRESHOLD)
- return;
- pr_notice("CPU%d BANK%d CMCI storm detected\n", smp_processor_id(), bank);
- mce_handle_storm(bank, true);
- cmci_storm_begin(bank);
- }
-}
-
/*
* The interrupt handler. This is called on every event.
* Just call the poller directly to log any events.