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/

