提交 f227d430 编写于 作者: B Borislav Petkov

x86, MCE, AMD: Make APIC LVT thresholding interrupt optional

Currently, the APIC LVT interrupt for error thresholding is implicitly
enabled. However, there are models in the F15h range which do not enable
it. Make the code machinery which sets up the APIC interrupt support
an optional setting and add an ->interrupt_capable member to the bank
representation mirroring that capability and enable the interrupt offset
programming only if it is true.

Simplify code and fixup comment style while at it.
Signed-off-by: NBorislav Petkov <borislav.petkov@amd.com>
上级 69964ea4
...@@ -51,6 +51,7 @@ struct threshold_block { ...@@ -51,6 +51,7 @@ struct threshold_block {
unsigned int cpu; unsigned int cpu;
u32 address; u32 address;
u16 interrupt_enable; u16 interrupt_enable;
bool interrupt_capable;
u16 threshold_limit; u16 threshold_limit;
struct kobject kobj; struct kobject kobj;
struct list_head miscj; struct list_head miscj;
...@@ -83,6 +84,21 @@ struct thresh_restart { ...@@ -83,6 +84,21 @@ struct thresh_restart {
u16 old_limit; u16 old_limit;
}; };
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
*/
return msr_high_bits & BIT(28);
}
static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
{ {
int msr = (hi & MASK_LVTOFF_HI) >> 20; int msr = (hi & MASK_LVTOFF_HI) >> 20;
...@@ -104,8 +120,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) ...@@ -104,8 +120,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
return 1; return 1;
}; };
/* must be called with correct cpu affinity */ /*
/* Called via smp_call_function_single() */ * Called via smp_call_function_single(), must be called with correct
* cpu affinity.
*/
static void threshold_restart_bank(void *_tr) static void threshold_restart_bank(void *_tr)
{ {
struct thresh_restart *tr = _tr; struct thresh_restart *tr = _tr;
...@@ -128,6 +146,12 @@ static void threshold_restart_bank(void *_tr) ...@@ -128,6 +146,12 @@ static void threshold_restart_bank(void *_tr)
(new_count & THRESHOLD_MAX); (new_count & THRESHOLD_MAX);
} }
/* clear IntType */
hi &= ~MASK_INT_TYPE_HI;
if (!tr->b->interrupt_capable)
goto done;
if (tr->set_lvt_off) { if (tr->set_lvt_off) {
if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) { if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
/* set new lvt offset */ /* set new lvt offset */
...@@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr) ...@@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr)
} }
} }
tr->b->interrupt_enable ? if (tr->b->interrupt_enable)
(hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : hi |= INT_TYPE_APIC;
(hi &= ~MASK_INT_TYPE_HI);
done:
hi |= MASK_COUNT_EN_HI; hi |= MASK_COUNT_EN_HI;
wrmsr(tr->b->address, lo, hi); wrmsr(tr->b->address, lo, hi);
...@@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) ...@@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
if (shared_bank[bank] && c->cpu_core_id) if (shared_bank[bank] && c->cpu_core_id)
break; break;
offset = setup_APIC_mce(offset,
(high & MASK_LVTOFF_HI) >> 20);
memset(&b, 0, sizeof(b)); memset(&b, 0, sizeof(b));
b.cpu = cpu; b.cpu = cpu;
b.bank = bank; b.bank = bank;
b.block = block; b.block = block;
b.address = address; b.address = address;
b.interrupt_capable = lvt_interrupt_supported(bank, high);
if (b.interrupt_capable) {
int new = (high & MASK_LVTOFF_HI) >> 20;
offset = setup_APIC_mce(offset, new);
}
mce_threshold_block_init(&b, offset); mce_threshold_block_init(&b, offset);
mce_threshold_vector = amd_threshold_interrupt; mce_threshold_vector = amd_threshold_interrupt;
...@@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size) ...@@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
struct thresh_restart tr; struct thresh_restart tr;
unsigned long new; unsigned long new;
if (!b->interrupt_capable)
return -EINVAL;
if (strict_strtoul(buf, 0, &new) < 0) if (strict_strtoul(buf, 0, &new) < 0)
return -EINVAL; return -EINVAL;
...@@ -467,6 +498,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, ...@@ -467,6 +498,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
b->cpu = cpu; b->cpu = cpu;
b->address = address; b->address = address;
b->interrupt_enable = 0; b->interrupt_enable = 0;
b->interrupt_capable = lvt_interrupt_supported(bank, high);
b->threshold_limit = THRESHOLD_MAX; b->threshold_limit = THRESHOLD_MAX;
INIT_LIST_HEAD(&b->miscj); INIT_LIST_HEAD(&b->miscj);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册