We setup APIC vectors for threshold errors if interrupt_capable.
However, we don't set interrupt_enable by default.
Re-working threshold_restart_bank() here so that the first time we
set up lvt_offset, we also set IntType to APIC.

If user wants to disable through sysfs, then that's fine too as
we will clear IntType if !tr->b->interrupt_enable

Also, we want to set IntType only if lvt_off_valid is true.
If not, then something is wrong (buggy BIOS maybe) and we'd rather
not have interrupts generated on overflow.

Misc other changes:
- lvt_interrupt_supported() says bank 4 supports APIC LVT always
  But, I looked at BKDG from K8 onwards and I am not seeing IntP
  bit(bit 60) set for any of them.
  - So, removing the bank = 4 check
  - msr_high_bits & BIT(28); will work anyway if bit is set

- We don't have to expose 'interrupt_enable' attribute if HW is
  not capable.
- Moving setting of b.threshold_limit to mce_amd_feature_init()
  - All other setup of struct threshold_block is done there anyway

- Fix comments/comment style issues

Testing details:
on Fam10h (does not have IntP set)
 - interrupt_enable attribute is not exposed.
on F15hM60h (IntP is set)
 - interrupt_enable is set by default
 - echo 0 > interrupt_enable clears IntType of respective register
 - Forcing error count to go over threshold_limit generates APIC
   interrupt and edac mce_amd catches it fine

Signed-off-by: Aravind Gopalakrishnan <[email protected]>
---
 arch/x86/kernel/cpu/mcheck/mce_amd.c | 43 +++++++++++++-----------------------
 1 file changed, 15 insertions(+), 28 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c 
b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index f1c3769..8b7dcc6 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -61,9 +61,7 @@ static DEFINE_PER_CPU(unsigned char, bank_map);       /* see 
which banks are on */
 
 static void amd_threshold_interrupt(void);
 
-/*
- * CPU Initialization
- */
+/* CPU Initialization */
 
 struct thresh_restart {
        struct threshold_block  *b;
@@ -102,12 +100,6 @@ static const char * const bank4_names(struct 
threshold_block *b)
 static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
 {
        /*
-        * bank 4 supports APIC LVT interrupts implicitly since forever.
-        */
-       if (bank == 4)
-               return true;
-
-       /*
         * IntP: interrupt present; if this bit is set, the thresholding
         * bank can generate APIC LVT interrupts
         */
@@ -161,23 +153,24 @@ static void threshold_restart_bank(void *_tr)
                    (new_count & THRESHOLD_MAX);
        }
 
-       /* clear IntType */
-       hi &= ~MASK_INT_TYPE_HI;
-
        if (!tr->b->interrupt_capable)
                goto done;
 
+       /* clear IntType */
+       if (!tr->b->interrupt_enable)
+               hi &= ~MASK_INT_TYPE_HI;
+
        if (tr->set_lvt_off) {
                if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
                        /* set new lvt offset */
                        hi &= ~MASK_LVTOFF_HI;
                        hi |= tr->lvt_off << 20;
+
+                       /* set IntType */
+                       hi |= INT_TYPE_APIC;
                }
        }
 
-       if (tr->b->interrupt_enable)
-               hi |= INT_TYPE_APIC;
-
  done:
 
        hi |= MASK_COUNT_EN_HI;
@@ -192,7 +185,6 @@ static void mce_threshold_block_init(struct threshold_block 
*b, int offset)
                .lvt_off                = offset,
        };
 
-       b->threshold_limit              = THRESHOLD_MAX;
        threshold_restart_bank(&tr);
 };
 
@@ -246,6 +238,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
                        b.block                 = block;
                        b.address               = address;
                        b.interrupt_capable     = lvt_interrupt_supported(bank, 
high);
+                       b.threshold_limit       = THRESHOLD_MAX;
 
                        if (!b.interrupt_capable)
                                goto init;
@@ -264,13 +257,9 @@ init:
 }
 
 /*
- * APIC Interrupt Handler
- */
-
-/*
- * threshold interrupt handler will service THRESHOLD_APIC_VECTOR.
+ * The threshold interrupt handler will service THRESHOLD_APIC_VECTOR.
  * the interrupt goes off when error_count reaches threshold_limit.
- * the handler will simply log mcelog w/ software defined bank number.
+ * the handler will simply call mcelog for error decoding
  */
 static void amd_threshold_interrupt(void)
 {
@@ -329,9 +318,7 @@ log:
        wrmsrl(MSR_IA32_MCx_STATUS(bank), 0);
 }
 
-/*
- * Sysfs Interface
- */
+/* Sysfs Interface */
 
 struct threshold_attr {
        struct attribute attr;
@@ -497,10 +484,10 @@ static int allocate_threshold_blocks(unsigned int cpu, 
unsigned int bank,
        b->interrupt_capable    = lvt_interrupt_supported(bank, high);
        b->threshold_limit      = THRESHOLD_MAX;
 
-       if (b->interrupt_capable)
+       if (b->interrupt_capable) {
                threshold_ktype.default_attrs[2] = &interrupt_enable.attr;
-       else
-               threshold_ktype.default_attrs[2] = NULL;
+               b->interrupt_enable = 1;
+       }
 
        INIT_LIST_HEAD(&b->miscj);
 
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to