Commit 70311aaa authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull MCE updates from Ingo Molnar:
 "This tree updates/fixes MCE hardware support, it makes the APIC LVT
  thresholding interrupt optional because a subset of AMD F15h models
  don't support it."

* 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, MCE, AMD: Disable error thresholding bank 4 on some models
  x86, MCE, AMD: Hide interrupt_enable sysfs node
  x86, MCE, AMD: Make APIC LVT thresholding interrupt optional
parents ec0d7f18 239e7bad
...@@ -1431,6 +1431,43 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) ...@@ -1431,6 +1431,43 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
*/ */
if (c->x86 == 6 && banks > 0) if (c->x86 == 6 && banks > 0)
mce_banks[0].ctl = 0; mce_banks[0].ctl = 0;
/*
* Turn off MC4_MISC thresholding banks on those models since
* they're not supported there.
*/
if (c->x86 == 0x15 &&
(c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
int i;
u64 val, hwcr;
bool need_toggle;
u32 msrs[] = {
0x00000413, /* MC4_MISC0 */
0xc0000408, /* MC4_MISC1 */
};
rdmsrl(MSR_K7_HWCR, hwcr);
/* McStatusWrEn has to be set */
need_toggle = !(hwcr & BIT(18));
if (need_toggle)
wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
for (i = 0; i < ARRAY_SIZE(msrs); i++) {
rdmsrl(msrs[i], val);
/* CntP bit set? */
if (val & BIT(62)) {
val &= ~BIT(62);
wrmsrl(msrs[i], val);
}
}
/* restore old settings */
if (need_toggle)
wrmsrl(MSR_K7_HWCR, hwcr);
}
} }
if (c->x86_vendor == X86_VENDOR_INTEL) { if (c->x86_vendor == X86_VENDOR_INTEL) {
......
...@@ -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;
...@@ -390,10 +421,10 @@ RW_ATTR(threshold_limit); ...@@ -390,10 +421,10 @@ RW_ATTR(threshold_limit);
RW_ATTR(error_count); RW_ATTR(error_count);
static struct attribute *default_attrs[] = { static struct attribute *default_attrs[] = {
&interrupt_enable.attr,
&threshold_limit.attr, &threshold_limit.attr,
&error_count.attr, &error_count.attr,
NULL NULL, /* possibly interrupt_enable if supported, see below */
NULL,
}; };
#define to_block(k) container_of(k, struct threshold_block, kobj) #define to_block(k) container_of(k, struct threshold_block, kobj)
...@@ -467,8 +498,14 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, ...@@ -467,8 +498,14 @@ 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;
if (b->interrupt_capable)
threshold_ktype.default_attrs[2] = &interrupt_enable.attr;
else
threshold_ktype.default_attrs[2] = NULL;
INIT_LIST_HEAD(&b->miscj); INIT_LIST_HEAD(&b->miscj);
if (per_cpu(threshold_banks, cpu)[bank]->blocks) { if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment