aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2012-04-16 12:01:53 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-17 14:23:12 -0400
commit33b3689af55ddec6efd608bd82f09a83e4e4042c (patch)
treebd4403ec7ced8529a752c88d147ace76302ab37d /arch/x86/kernel
parente2b55892ceb923d9ff6c204e59be5f2b43a0009c (diff)
x86, MCE, AMD: Make APIC LVT thresholding interrupt optional
commit f227d4306cf30e1d5b6f231e8ef9006c34f3d186 upstream. 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: Borislav Petkov <borislav.petkov@amd.com> Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c55
1 files changed, 44 insertions, 11 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index bb0adad3514..dc4fb779a72 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -52,6 +52,7 @@ struct threshold_block {
52 unsigned int cpu; 52 unsigned int cpu;
53 u32 address; 53 u32 address;
54 u16 interrupt_enable; 54 u16 interrupt_enable;
55 bool interrupt_capable;
55 u16 threshold_limit; 56 u16 threshold_limit;
56 struct kobject kobj; 57 struct kobject kobj;
57 struct list_head miscj; 58 struct list_head miscj;
@@ -86,6 +87,21 @@ struct thresh_restart {
86 u16 old_limit; 87 u16 old_limit;
87}; 88};
88 89
90static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
91{
92 /*
93 * bank 4 supports APIC LVT interrupts implicitly since forever.
94 */
95 if (bank == 4)
96 return true;
97
98 /*
99 * IntP: interrupt present; if this bit is set, the thresholding
100 * bank can generate APIC LVT interrupts
101 */
102 return msr_high_bits & BIT(28);
103}
104
89static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) 105static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
90{ 106{
91 int msr = (hi & MASK_LVTOFF_HI) >> 20; 107 int msr = (hi & MASK_LVTOFF_HI) >> 20;
@@ -107,8 +123,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
107 return 1; 123 return 1;
108}; 124};
109 125
110/* must be called with correct cpu affinity */ 126/*
111/* Called via smp_call_function_single() */ 127 * Called via smp_call_function_single(), must be called with correct
128 * cpu affinity.
129 */
112static void threshold_restart_bank(void *_tr) 130static void threshold_restart_bank(void *_tr)
113{ 131{
114 struct thresh_restart *tr = _tr; 132 struct thresh_restart *tr = _tr;
@@ -131,6 +149,12 @@ static void threshold_restart_bank(void *_tr)
131 (new_count & THRESHOLD_MAX); 149 (new_count & THRESHOLD_MAX);
132 } 150 }
133 151
152 /* clear IntType */
153 hi &= ~MASK_INT_TYPE_HI;
154
155 if (!tr->b->interrupt_capable)
156 goto done;
157
134 if (tr->set_lvt_off) { 158 if (tr->set_lvt_off) {
135 if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) { 159 if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
136 /* set new lvt offset */ 160 /* set new lvt offset */
@@ -139,9 +163,10 @@ static void threshold_restart_bank(void *_tr)
139 } 163 }
140 } 164 }
141 165
142 tr->b->interrupt_enable ? 166 if (tr->b->interrupt_enable)
143 (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : 167 hi |= INT_TYPE_APIC;
144 (hi &= ~MASK_INT_TYPE_HI); 168
169 done:
145 170
146 hi |= MASK_COUNT_EN_HI; 171 hi |= MASK_COUNT_EN_HI;
147 wrmsr(tr->b->address, lo, hi); 172 wrmsr(tr->b->address, lo, hi);
@@ -206,14 +231,18 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
206 if (shared_bank[bank] && c->cpu_core_id) 231 if (shared_bank[bank] && c->cpu_core_id)
207 break; 232 break;
208#endif 233#endif
209 offset = setup_APIC_mce(offset,
210 (high & MASK_LVTOFF_HI) >> 20);
211 234
212 memset(&b, 0, sizeof(b)); 235 memset(&b, 0, sizeof(b));
213 b.cpu = cpu; 236 b.cpu = cpu;
214 b.bank = bank; 237 b.bank = bank;
215 b.block = block; 238 b.block = block;
216 b.address = address; 239 b.address = address;
240 b.interrupt_capable = lvt_interrupt_supported(bank, high);
241
242 if (b.interrupt_capable) {
243 int new = (high & MASK_LVTOFF_HI) >> 20;
244 offset = setup_APIC_mce(offset, new);
245 }
217 246
218 mce_threshold_block_init(&b, offset); 247 mce_threshold_block_init(&b, offset);
219 mce_threshold_vector = amd_threshold_interrupt; 248 mce_threshold_vector = amd_threshold_interrupt;
@@ -313,6 +342,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
313 struct thresh_restart tr; 342 struct thresh_restart tr;
314 unsigned long new; 343 unsigned long new;
315 344
345 if (!b->interrupt_capable)
346 return -EINVAL;
347
316 if (strict_strtoul(buf, 0, &new) < 0) 348 if (strict_strtoul(buf, 0, &new) < 0)
317 return -EINVAL; 349 return -EINVAL;
318 350
@@ -471,6 +503,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
471 b->cpu = cpu; 503 b->cpu = cpu;
472 b->address = address; 504 b->address = address;
473 b->interrupt_enable = 0; 505 b->interrupt_enable = 0;
506 b->interrupt_capable = lvt_interrupt_supported(bank, high);
474 b->threshold_limit = THRESHOLD_MAX; 507 b->threshold_limit = THRESHOLD_MAX;
475 508
476 INIT_LIST_HEAD(&b->miscj); 509 INIT_LIST_HEAD(&b->miscj);