diff options
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_amd.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 80c482382d5c..f438318ee800 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c | |||
@@ -59,12 +59,6 @@ struct threshold_block { | |||
59 | struct list_head miscj; | 59 | struct list_head miscj; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* defaults used early on boot */ | ||
63 | static struct threshold_block threshold_defaults = { | ||
64 | .interrupt_enable = 0, | ||
65 | .threshold_limit = THRESHOLD_MAX, | ||
66 | }; | ||
67 | |||
68 | struct threshold_bank { | 62 | struct threshold_bank { |
69 | struct kobject *kobj; | 63 | struct kobject *kobj; |
70 | struct threshold_block *blocks; | 64 | struct threshold_block *blocks; |
@@ -89,6 +83,8 @@ static void amd_threshold_interrupt(void); | |||
89 | struct thresh_restart { | 83 | struct thresh_restart { |
90 | struct threshold_block *b; | 84 | struct threshold_block *b; |
91 | int reset; | 85 | int reset; |
86 | int set_lvt_off; | ||
87 | int lvt_off; | ||
92 | u16 old_limit; | 88 | u16 old_limit; |
93 | }; | 89 | }; |
94 | 90 | ||
@@ -116,6 +112,12 @@ static void threshold_restart_bank(void *_tr) | |||
116 | (new_count & THRESHOLD_MAX); | 112 | (new_count & THRESHOLD_MAX); |
117 | } | 113 | } |
118 | 114 | ||
115 | if (tr->set_lvt_off) { | ||
116 | /* set new lvt offset */ | ||
117 | mci_misc_hi &= ~MASK_LVTOFF_HI; | ||
118 | mci_misc_hi |= tr->lvt_off << 20; | ||
119 | } | ||
120 | |||
119 | tr->b->interrupt_enable ? | 121 | tr->b->interrupt_enable ? |
120 | (mci_misc_hi = (mci_misc_hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : | 122 | (mci_misc_hi = (mci_misc_hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) : |
121 | (mci_misc_hi &= ~MASK_INT_TYPE_HI); | 123 | (mci_misc_hi &= ~MASK_INT_TYPE_HI); |
@@ -124,13 +126,25 @@ static void threshold_restart_bank(void *_tr) | |||
124 | wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi); | 126 | wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi); |
125 | } | 127 | } |
126 | 128 | ||
129 | static void mce_threshold_block_init(struct threshold_block *b, int offset) | ||
130 | { | ||
131 | struct thresh_restart tr = { | ||
132 | .b = b, | ||
133 | .set_lvt_off = 1, | ||
134 | .lvt_off = offset, | ||
135 | }; | ||
136 | |||
137 | b->threshold_limit = THRESHOLD_MAX; | ||
138 | threshold_restart_bank(&tr); | ||
139 | }; | ||
140 | |||
127 | /* cpu init entry point, called from mce.c with preempt off */ | 141 | /* cpu init entry point, called from mce.c with preempt off */ |
128 | void mce_amd_feature_init(struct cpuinfo_x86 *c) | 142 | void mce_amd_feature_init(struct cpuinfo_x86 *c) |
129 | { | 143 | { |
144 | struct threshold_block b; | ||
130 | unsigned int cpu = smp_processor_id(); | 145 | unsigned int cpu = smp_processor_id(); |
131 | u32 low = 0, high = 0, address = 0; | 146 | u32 low = 0, high = 0, address = 0; |
132 | unsigned int bank, block; | 147 | unsigned int bank, block; |
133 | struct thresh_restart tr; | ||
134 | int lvt_off = -1; | 148 | int lvt_off = -1; |
135 | u8 offset; | 149 | u8 offset; |
136 | 150 | ||
@@ -186,16 +200,13 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) | |||
186 | continue; | 200 | continue; |
187 | } | 201 | } |
188 | 202 | ||
189 | high &= ~MASK_LVTOFF_HI; | 203 | memset(&b, 0, sizeof(b)); |
190 | high |= lvt_off << 20; | 204 | b.cpu = cpu; |
191 | wrmsr(address, low, high); | 205 | b.bank = bank; |
192 | 206 | b.block = block; | |
193 | threshold_defaults.address = address; | 207 | b.address = address; |
194 | tr.b = &threshold_defaults; | ||
195 | tr.reset = 0; | ||
196 | tr.old_limit = 0; | ||
197 | threshold_restart_bank(&tr); | ||
198 | 208 | ||
209 | mce_threshold_block_init(&b, offset); | ||
199 | mce_threshold_vector = amd_threshold_interrupt; | 210 | mce_threshold_vector = amd_threshold_interrupt; |
200 | } | 211 | } |
201 | } | 212 | } |
@@ -298,9 +309,8 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size) | |||
298 | 309 | ||
299 | b->interrupt_enable = !!new; | 310 | b->interrupt_enable = !!new; |
300 | 311 | ||
312 | memset(&tr, 0, sizeof(tr)); | ||
301 | tr.b = b; | 313 | tr.b = b; |
302 | tr.reset = 0; | ||
303 | tr.old_limit = 0; | ||
304 | 314 | ||
305 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); | 315 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); |
306 | 316 | ||
@@ -321,10 +331,10 @@ store_threshold_limit(struct threshold_block *b, const char *buf, size_t size) | |||
321 | if (new < 1) | 331 | if (new < 1) |
322 | new = 1; | 332 | new = 1; |
323 | 333 | ||
334 | memset(&tr, 0, sizeof(tr)); | ||
324 | tr.old_limit = b->threshold_limit; | 335 | tr.old_limit = b->threshold_limit; |
325 | b->threshold_limit = new; | 336 | b->threshold_limit = new; |
326 | tr.b = b; | 337 | tr.b = b; |
327 | tr.reset = 0; | ||
328 | 338 | ||
329 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); | 339 | smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); |
330 | 340 | ||