forked from luck/tmp_suning_uos_patched
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
This commit is contained in:
commit
70311aaa8a
@ -1431,6 +1431,43 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
|
||||
*/
|
||||
if (c->x86 == 6 && banks > 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) {
|
||||
|
@ -51,6 +51,7 @@ struct threshold_block {
|
||||
unsigned int cpu;
|
||||
u32 address;
|
||||
u16 interrupt_enable;
|
||||
bool interrupt_capable;
|
||||
u16 threshold_limit;
|
||||
struct kobject kobj;
|
||||
struct list_head miscj;
|
||||
@ -83,6 +84,21 @@ struct thresh_restart {
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct thresh_restart *tr = _tr;
|
||||
@ -128,6 +146,12 @@ 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;
|
||||
|
||||
if (tr->set_lvt_off) {
|
||||
if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
|
||||
/* set new lvt offset */
|
||||
@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr)
|
||||
}
|
||||
}
|
||||
|
||||
tr->b->interrupt_enable ?
|
||||
(hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
|
||||
(hi &= ~MASK_INT_TYPE_HI);
|
||||
if (tr->b->interrupt_enable)
|
||||
hi |= INT_TYPE_APIC;
|
||||
|
||||
done:
|
||||
|
||||
hi |= MASK_COUNT_EN_HI;
|
||||
wrmsr(tr->b->address, lo, hi);
|
||||
@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
|
||||
if (shared_bank[bank] && c->cpu_core_id)
|
||||
break;
|
||||
|
||||
offset = setup_APIC_mce(offset,
|
||||
(high & MASK_LVTOFF_HI) >> 20);
|
||||
|
||||
memset(&b, 0, sizeof(b));
|
||||
b.cpu = cpu;
|
||||
b.bank = bank;
|
||||
b.block = block;
|
||||
b.address = address;
|
||||
b.cpu = cpu;
|
||||
b.bank = bank;
|
||||
b.block = block;
|
||||
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_vector = amd_threshold_interrupt;
|
||||
@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
|
||||
struct thresh_restart tr;
|
||||
unsigned long new;
|
||||
|
||||
if (!b->interrupt_capable)
|
||||
return -EINVAL;
|
||||
|
||||
if (strict_strtoul(buf, 0, &new) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -390,10 +421,10 @@ RW_ATTR(threshold_limit);
|
||||
RW_ATTR(error_count);
|
||||
|
||||
static struct attribute *default_attrs[] = {
|
||||
&interrupt_enable.attr,
|
||||
&threshold_limit.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)
|
||||
@ -467,8 +498,14 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
|
||||
b->cpu = cpu;
|
||||
b->address = address;
|
||||
b->interrupt_enable = 0;
|
||||
b->interrupt_capable = lvt_interrupt_supported(bank, high);
|
||||
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);
|
||||
|
||||
if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
|
||||
|
Loading…
Reference in New Issue
Block a user