mce, amd: Implement mce_threshold_block_init() helper function
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / x86 / kernel / cpu / mcheck / mce_amd.c
CommitLineData
89b831ef 1/*
95268664 2 * (c) 2005, 2006 Advanced Micro Devices, Inc.
89b831ef
JS
3 * Your use of this code is subject to the terms and conditions of the
4 * GNU general public license version 2. See "COPYING" or
5 * http://www.gnu.org/licenses/gpl.html
6 *
7 * Written by Jacob Shin - AMD, Inc.
8 *
9 * Support : jacob.shin@amd.com
10 *
95268664
JS
11 * April 2006
12 * - added support for AMD Family 0x10 processors
89b831ef 13 *
95268664 14 * All MC4_MISCi registers are shared between multi-cores
89b831ef 15 */
89b831ef 16#include <linux/interrupt.h>
89b831ef 17#include <linux/notifier.h>
1cb2a8e1 18#include <linux/kobject.h>
34fa1967 19#include <linux/percpu.h>
89b831ef 20#include <linux/sysdev.h>
1cb2a8e1
IM
21#include <linux/errno.h>
22#include <linux/sched.h>
89b831ef 23#include <linux/sysfs.h>
5a0e3ad6 24#include <linux/slab.h>
1cb2a8e1
IM
25#include <linux/init.h>
26#include <linux/cpu.h>
27#include <linux/smp.h>
28
89b831ef 29#include <asm/apic.h>
1cb2a8e1 30#include <asm/idle.h>
89b831ef
JS
31#include <asm/mce.h>
32#include <asm/msr.h>
89b831ef 33
2903ee85
JS
34#define PFX "mce_threshold: "
35#define VERSION "version 1.1.1"
36#define NR_BANKS 6
37#define NR_BLOCKS 9
38#define THRESHOLD_MAX 0xFFF
39#define INT_TYPE_APIC 0x00020000
40#define MASK_VALID_HI 0x80000000
24ce0e96
JB
41#define MASK_CNTP_HI 0x40000000
42#define MASK_LOCKED_HI 0x20000000
2903ee85
JS
43#define MASK_LVTOFF_HI 0x00F00000
44#define MASK_COUNT_EN_HI 0x00080000
45#define MASK_INT_TYPE_HI 0x00060000
46#define MASK_OVERFLOW_HI 0x00010000
89b831ef 47#define MASK_ERR_COUNT_HI 0x00000FFF
95268664
JS
48#define MASK_BLKPTR_LO 0xFF000000
49#define MCG_XBLK_ADDR 0xC0000400
89b831ef 50
95268664 51struct threshold_block {
1cb2a8e1
IM
52 unsigned int block;
53 unsigned int bank;
54 unsigned int cpu;
55 u32 address;
56 u16 interrupt_enable;
57 u16 threshold_limit;
58 struct kobject kobj;
59 struct list_head miscj;
89b831ef
JS
60};
61
95268664 62struct threshold_bank {
1cb2a8e1
IM
63 struct kobject *kobj;
64 struct threshold_block *blocks;
65 cpumask_var_t cpus;
95268664 66};
204fba4a 67static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);
95268664 68
89b831ef
JS
69#ifdef CONFIG_SMP
70static unsigned char shared_bank[NR_BANKS] = {
71 0, 0, 0, 0, 1
72};
73#endif
74
75static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */
76
b2762686
AK
77static void amd_threshold_interrupt(void);
78
89b831ef
JS
79/*
80 * CPU Initialization
81 */
82
4cd4601d 83struct thresh_restart {
1cb2a8e1
IM
84 struct threshold_block *b;
85 int reset;
9c37c9d8
RR
86 int set_lvt_off;
87 int lvt_off;
1cb2a8e1 88 u16 old_limit;
4cd4601d
MT
89};
90
89b831ef 91/* must be called with correct cpu affinity */
a6b6a14e
AM
92/* Called via smp_call_function_single() */
93static void threshold_restart_bank(void *_tr)
89b831ef 94{
4cd4601d 95 struct thresh_restart *tr = _tr;
89b831ef
JS
96 u32 mci_misc_hi, mci_misc_lo;
97
4cd4601d 98 rdmsr(tr->b->address, mci_misc_lo, mci_misc_hi);
89b831ef 99
4cd4601d
MT
100 if (tr->b->threshold_limit < (mci_misc_hi & THRESHOLD_MAX))
101 tr->reset = 1; /* limit cannot be lower than err count */
89b831ef 102
4cd4601d 103 if (tr->reset) { /* reset err count and overflow bit */
89b831ef
JS
104 mci_misc_hi =
105 (mci_misc_hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) |
4cd4601d
MT
106 (THRESHOLD_MAX - tr->b->threshold_limit);
107 } else if (tr->old_limit) { /* change limit w/o reset */
89b831ef 108 int new_count = (mci_misc_hi & THRESHOLD_MAX) +
4cd4601d 109 (tr->old_limit - tr->b->threshold_limit);
1cb2a8e1 110
89b831ef
JS
111 mci_misc_hi = (mci_misc_hi & ~MASK_ERR_COUNT_HI) |
112 (new_count & THRESHOLD_MAX);
113 }
114
9c37c9d8
RR
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
4cd4601d 121 tr->b->interrupt_enable ?
89b831ef
JS
122 (mci_misc_hi = (mci_misc_hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
123 (mci_misc_hi &= ~MASK_INT_TYPE_HI);
124
125 mci_misc_hi |= MASK_COUNT_EN_HI;
4cd4601d 126 wrmsr(tr->b->address, mci_misc_lo, mci_misc_hi);
89b831ef
JS
127}
128
9c37c9d8
RR
129static 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
95268664 141/* cpu init entry point, called from mce.c with preempt off */
cc3ca220 142void mce_amd_feature_init(struct cpuinfo_x86 *c)
89b831ef 143{
9c37c9d8 144 struct threshold_block b;
89b831ef 145 unsigned int cpu = smp_processor_id();
95268664 146 u32 low = 0, high = 0, address = 0;
1cb2a8e1 147 unsigned int bank, block;
27afdf20
RR
148 int lvt_off = -1;
149 u8 offset;
89b831ef
JS
150
151 for (bank = 0; bank < NR_BANKS; ++bank) {
95268664
JS
152 for (block = 0; block < NR_BLOCKS; ++block) {
153 if (block == 0)
154 address = MSR_IA32_MC0_MISC + bank * 4;
24ce0e96
JB
155 else if (block == 1) {
156 address = (low & MASK_BLKPTR_LO) >> 21;
157 if (!address)
158 break;
6dcbfe4f 159
24ce0e96 160 address += MCG_XBLK_ADDR;
1cb2a8e1 161 } else
95268664
JS
162 ++address;
163
164 if (rdmsr_safe(address, &low, &high))
24ce0e96 165 break;
95268664 166
6dcbfe4f
BP
167 if (!(high & MASK_VALID_HI))
168 continue;
95268664 169
24ce0e96
JB
170 if (!(high & MASK_CNTP_HI) ||
171 (high & MASK_LOCKED_HI))
95268664
JS
172 continue;
173
174 if (!block)
175 per_cpu(bank_map, cpu) |= (1 << bank);
89b831ef 176#ifdef CONFIG_SMP
95268664
JS
177 if (shared_bank[bank] && c->cpu_core_id)
178 break;
89b831ef 179#endif
27afdf20
RR
180 offset = (high & MASK_LVTOFF_HI) >> 20;
181 if (lvt_off < 0) {
182 if (setup_APIC_eilvt(offset,
183 THRESHOLD_APIC_VECTOR,
184 APIC_EILVT_MSG_FIX, 0)) {
185 pr_err(FW_BUG "cpu %d, failed to "
186 "setup threshold interrupt "
187 "for bank %d, block %d "
188 "(MSR%08X=0x%x%08x)",
189 smp_processor_id(), bank, block,
190 address, high, low);
191 continue;
192 }
193 lvt_off = offset;
194 } else if (lvt_off != offset) {
195 pr_err(FW_BUG "cpu %d, invalid threshold "
196 "interrupt offset %d for bank %d,"
197 "block %d (MSR%08X=0x%x%08x)",
198 smp_processor_id(), lvt_off, bank,
199 block, address, high, low);
200 continue;
201 }
7b83dae7 202
9c37c9d8
RR
203 memset(&b, 0, sizeof(b));
204 b.cpu = cpu;
205 b.bank = bank;
206 b.block = block;
207 b.address = address;
b2762686 208
9c37c9d8 209 mce_threshold_block_init(&b, offset);
b2762686 210 mce_threshold_vector = amd_threshold_interrupt;
95268664 211 }
89b831ef
JS
212 }
213}
214
215/*
216 * APIC Interrupt Handler
217 */
218
219/*
220 * threshold interrupt handler will service THRESHOLD_APIC_VECTOR.
221 * the interrupt goes off when error_count reaches threshold_limit.
222 * the handler will simply log mcelog w/ software defined bank number.
223 */
b2762686 224static void amd_threshold_interrupt(void)
89b831ef 225{
1cb2a8e1 226 u32 low = 0, high = 0, address = 0;
95268664 227 unsigned int bank, block;
89b831ef
JS
228 struct mce m;
229
b5f2fa4e 230 mce_setup(&m);
89b831ef
JS
231
232 /* assume first bank caused it */
233 for (bank = 0; bank < NR_BANKS; ++bank) {
24ce0e96
JB
234 if (!(per_cpu(bank_map, m.cpu) & (1 << bank)))
235 continue;
95268664 236 for (block = 0; block < NR_BLOCKS; ++block) {
1cb2a8e1 237 if (block == 0) {
95268664 238 address = MSR_IA32_MC0_MISC + bank * 4;
1cb2a8e1 239 } else if (block == 1) {
24ce0e96
JB
240 address = (low & MASK_BLKPTR_LO) >> 21;
241 if (!address)
242 break;
243 address += MCG_XBLK_ADDR;
1cb2a8e1 244 } else {
95268664 245 ++address;
1cb2a8e1 246 }
95268664
JS
247
248 if (rdmsr_safe(address, &low, &high))
24ce0e96 249 break;
95268664
JS
250
251 if (!(high & MASK_VALID_HI)) {
252 if (block)
253 continue;
254 else
255 break;
256 }
257
24ce0e96
JB
258 if (!(high & MASK_CNTP_HI) ||
259 (high & MASK_LOCKED_HI))
95268664
JS
260 continue;
261
1cb2a8e1
IM
262 /*
263 * Log the machine check that caused the threshold
264 * event.
265 */
ee031c31
AK
266 machine_check_poll(MCP_TIMESTAMP,
267 &__get_cpu_var(mce_poll_banks));
a98f0dd3 268
95268664
JS
269 if (high & MASK_OVERFLOW_HI) {
270 rdmsrl(address, m.misc);
271 rdmsrl(MSR_IA32_MC0_STATUS + bank * 4,
272 m.status);
273 m.bank = K8_MCE_THRESHOLD_BASE
274 + bank * NR_BLOCKS
275 + block;
276 mce_log(&m);
b2762686 277 return;
95268664 278 }
89b831ef
JS
279 }
280 }
89b831ef
JS
281}
282
283/*
284 * Sysfs Interface
285 */
286
89b831ef 287struct threshold_attr {
2903ee85 288 struct attribute attr;
1cb2a8e1
IM
289 ssize_t (*show) (struct threshold_block *, char *);
290 ssize_t (*store) (struct threshold_block *, const char *, size_t count);
89b831ef
JS
291};
292
1cb2a8e1
IM
293#define SHOW_FIELDS(name) \
294static ssize_t show_ ## name(struct threshold_block *b, char *buf) \
295{ \
296 return sprintf(buf, "%lx\n", (unsigned long) b->name); \
2903ee85 297}
89b831ef
JS
298SHOW_FIELDS(interrupt_enable)
299SHOW_FIELDS(threshold_limit)
300
1cb2a8e1 301static ssize_t
9319cec8 302store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
89b831ef 303{
4cd4601d 304 struct thresh_restart tr;
1cb2a8e1 305 unsigned long new;
1cb2a8e1 306
9319cec8 307 if (strict_strtoul(buf, 0, &new) < 0)
89b831ef 308 return -EINVAL;
1cb2a8e1 309
89b831ef
JS
310 b->interrupt_enable = !!new;
311
9c37c9d8 312 memset(&tr, 0, sizeof(tr));
1cb2a8e1 313 tr.b = b;
1cb2a8e1 314
a6b6a14e 315 smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
89b831ef 316
9319cec8 317 return size;
89b831ef
JS
318}
319
1cb2a8e1 320static ssize_t
9319cec8 321store_threshold_limit(struct threshold_block *b, const char *buf, size_t size)
89b831ef 322{
4cd4601d 323 struct thresh_restart tr;
1cb2a8e1 324 unsigned long new;
1cb2a8e1 325
9319cec8 326 if (strict_strtoul(buf, 0, &new) < 0)
89b831ef 327 return -EINVAL;
1cb2a8e1 328
89b831ef
JS
329 if (new > THRESHOLD_MAX)
330 new = THRESHOLD_MAX;
331 if (new < 1)
332 new = 1;
1cb2a8e1 333
9c37c9d8 334 memset(&tr, 0, sizeof(tr));
4cd4601d 335 tr.old_limit = b->threshold_limit;
89b831ef 336 b->threshold_limit = new;
4cd4601d 337 tr.b = b;
89b831ef 338
a6b6a14e 339 smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
89b831ef 340
9319cec8 341 return size;
89b831ef
JS
342}
343
a6b6a14e 344struct threshold_block_cross_cpu {
1cb2a8e1
IM
345 struct threshold_block *tb;
346 long retval;
a6b6a14e
AM
347};
348
349static void local_error_count_handler(void *_tbcc)
89b831ef 350{
a6b6a14e
AM
351 struct threshold_block_cross_cpu *tbcc = _tbcc;
352 struct threshold_block *b = tbcc->tb;
4cd4601d
MT
353 u32 low, high;
354
95268664 355 rdmsr(b->address, low, high);
a6b6a14e 356 tbcc->retval = (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit);
4cd4601d
MT
357}
358
359static ssize_t show_error_count(struct threshold_block *b, char *buf)
360{
a6b6a14e
AM
361 struct threshold_block_cross_cpu tbcc = { .tb = b, };
362
363 smp_call_function_single(b->cpu, local_error_count_handler, &tbcc, 1);
364 return sprintf(buf, "%lx\n", tbcc.retval);
89b831ef
JS
365}
366
95268664 367static ssize_t store_error_count(struct threshold_block *b,
89b831ef
JS
368 const char *buf, size_t count)
369{
4cd4601d
MT
370 struct thresh_restart tr = { .b = b, .reset = 1, .old_limit = 0 };
371
a6b6a14e 372 smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
89b831ef
JS
373 return 1;
374}
375
34fa1967
HS
376#define RW_ATTR(val) \
377static struct threshold_attr val = { \
378 .attr = {.name = __stringify(val), .mode = 0644 }, \
379 .show = show_## val, \
380 .store = store_## val, \
89b831ef
JS
381};
382
2903ee85
JS
383RW_ATTR(interrupt_enable);
384RW_ATTR(threshold_limit);
385RW_ATTR(error_count);
89b831ef
JS
386
387static struct attribute *default_attrs[] = {
388 &interrupt_enable.attr,
389 &threshold_limit.attr,
390 &error_count.attr,
391 NULL
392};
393
1cb2a8e1
IM
394#define to_block(k) container_of(k, struct threshold_block, kobj)
395#define to_attr(a) container_of(a, struct threshold_attr, attr)
89b831ef
JS
396
397static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
398{
95268664 399 struct threshold_block *b = to_block(kobj);
89b831ef
JS
400 struct threshold_attr *a = to_attr(attr);
401 ssize_t ret;
1cb2a8e1 402
89b831ef 403 ret = a->show ? a->show(b, buf) : -EIO;
1cb2a8e1 404
89b831ef
JS
405 return ret;
406}
407
408static ssize_t store(struct kobject *kobj, struct attribute *attr,
409 const char *buf, size_t count)
410{
95268664 411 struct threshold_block *b = to_block(kobj);
89b831ef
JS
412 struct threshold_attr *a = to_attr(attr);
413 ssize_t ret;
1cb2a8e1 414
89b831ef 415 ret = a->store ? a->store(b, buf, count) : -EIO;
1cb2a8e1 416
89b831ef
JS
417 return ret;
418}
419
52cf25d0 420static const struct sysfs_ops threshold_ops = {
1cb2a8e1
IM
421 .show = show,
422 .store = store,
89b831ef
JS
423};
424
425static struct kobj_type threshold_ktype = {
1cb2a8e1
IM
426 .sysfs_ops = &threshold_ops,
427 .default_attrs = default_attrs,
89b831ef
JS
428};
429
95268664
JS
430static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
431 unsigned int bank,
432 unsigned int block,
433 u32 address)
434{
95268664 435 struct threshold_block *b = NULL;
1cb2a8e1
IM
436 u32 low, high;
437 int err;
95268664
JS
438
439 if ((bank >= NR_BANKS) || (block >= NR_BLOCKS))
440 return 0;
441
a6b6a14e 442 if (rdmsr_safe_on_cpu(cpu, address, &low, &high))
24ce0e96 443 return 0;
95268664
JS
444
445 if (!(high & MASK_VALID_HI)) {
446 if (block)
447 goto recurse;
448 else
449 return 0;
450 }
451
24ce0e96
JB
452 if (!(high & MASK_CNTP_HI) ||
453 (high & MASK_LOCKED_HI))
95268664
JS
454 goto recurse;
455
456 b = kzalloc(sizeof(struct threshold_block), GFP_KERNEL);
457 if (!b)
458 return -ENOMEM;
95268664 459
1cb2a8e1
IM
460 b->block = block;
461 b->bank = bank;
462 b->cpu = cpu;
463 b->address = address;
464 b->interrupt_enable = 0;
465 b->threshold_limit = THRESHOLD_MAX;
95268664
JS
466
467 INIT_LIST_HEAD(&b->miscj);
468
1cb2a8e1 469 if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
95268664
JS
470 list_add(&b->miscj,
471 &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj);
1cb2a8e1 472 } else {
95268664 473 per_cpu(threshold_banks, cpu)[bank]->blocks = b;
1cb2a8e1 474 }
95268664 475
542eb75a
GKH
476 err = kobject_init_and_add(&b->kobj, &threshold_ktype,
477 per_cpu(threshold_banks, cpu)[bank]->kobj,
478 "misc%i", block);
95268664
JS
479 if (err)
480 goto out_free;
481recurse:
482 if (!block) {
483 address = (low & MASK_BLKPTR_LO) >> 21;
484 if (!address)
485 return 0;
486 address += MCG_XBLK_ADDR;
1cb2a8e1 487 } else {
95268664 488 ++address;
1cb2a8e1 489 }
95268664
JS
490
491 err = allocate_threshold_blocks(cpu, bank, ++block, address);
492 if (err)
493 goto out_free;
494
213eca7f
GKH
495 if (b)
496 kobject_uevent(&b->kobj, KOBJ_ADD);
542eb75a 497
95268664
JS
498 return err;
499
500out_free:
501 if (b) {
38a382ae 502 kobject_put(&b->kobj);
95268664
JS
503 kfree(b);
504 }
505 return err;
506}
507
a6b6a14e
AM
508static __cpuinit long
509local_allocate_threshold_blocks(int cpu, unsigned int bank)
4cd4601d 510{
a6b6a14e
AM
511 return allocate_threshold_blocks(cpu, bank, 0,
512 MSR_IA32_MC0_MISC + bank * 4);
4cd4601d
MT
513}
514
89b831ef 515/* symlinks sibling shared banks to first core. first core owns dir/files. */
95268664 516static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
89b831ef 517{
95268664 518 int i, err = 0;
68209407 519 struct threshold_bank *b = NULL;
95268664 520 char name[32];
a017421d 521#ifdef CONFIG_SMP
cb9805ab 522 struct cpuinfo_x86 *c = &cpu_data(cpu);
a017421d 523#endif
95268664
JS
524
525 sprintf(name, "threshold_bank%i", bank);
89b831ef
JS
526
527#ifdef CONFIG_SMP
92cb7612 528 if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) { /* symlink */
cb9805ab 529 i = cpumask_first(c->llc_shared_map);
95268664
JS
530
531 /* first core not up yet */
92cb7612 532 if (cpu_data(i).cpu_core_id)
95268664
JS
533 goto out;
534
535 /* already linked */
536 if (per_cpu(threshold_banks, cpu)[bank])
537 goto out;
538
539 b = per_cpu(threshold_banks, i)[bank];
89b831ef 540
89b831ef
JS
541 if (!b)
542 goto out;
95268664 543
cb491fca 544 err = sysfs_create_link(&per_cpu(mce_dev, cpu).kobj,
a521cf20 545 b->kobj, name);
89b831ef
JS
546 if (err)
547 goto out;
95268664 548
cb9805ab 549 cpumask_copy(b->cpus, c->llc_shared_map);
89b831ef 550 per_cpu(threshold_banks, cpu)[bank] = b;
1cb2a8e1 551
89b831ef
JS
552 goto out;
553 }
554#endif
555
95268664 556 b = kzalloc(sizeof(struct threshold_bank), GFP_KERNEL);
89b831ef
JS
557 if (!b) {
558 err = -ENOMEM;
559 goto out;
560 }
1389298f 561 if (!zalloc_cpumask_var(&b->cpus, GFP_KERNEL)) {
a1c33bbe
MT
562 kfree(b);
563 err = -ENOMEM;
564 goto out;
565 }
89b831ef 566
cb491fca 567 b->kobj = kobject_create_and_add(name, &per_cpu(mce_dev, cpu).kobj);
a521cf20
GKH
568 if (!b->kobj)
569 goto out_free;
570
95268664 571#ifndef CONFIG_SMP
a1c33bbe 572 cpumask_setall(b->cpus);
95268664 573#else
1389298f 574 cpumask_set_cpu(cpu, b->cpus);
95268664 575#endif
95268664 576
89b831ef 577 per_cpu(threshold_banks, cpu)[bank] = b;
95268664 578
a6b6a14e 579 err = local_allocate_threshold_blocks(cpu, bank);
95268664
JS
580 if (err)
581 goto out_free;
582
a1c33bbe 583 for_each_cpu(i, b->cpus) {
95268664
JS
584 if (i == cpu)
585 continue;
586
cb491fca 587 err = sysfs_create_link(&per_cpu(mce_dev, i).kobj,
a521cf20 588 b->kobj, name);
95268664
JS
589 if (err)
590 goto out;
591
592 per_cpu(threshold_banks, i)[bank] = b;
593 }
594
595 goto out;
596
597out_free:
598 per_cpu(threshold_banks, cpu)[bank] = NULL;
a1c33bbe 599 free_cpumask_var(b->cpus);
95268664 600 kfree(b);
2903ee85 601out:
89b831ef
JS
602 return err;
603}
604
605/* create dir/files for all valid threshold banks */
606static __cpuinit int threshold_create_device(unsigned int cpu)
607{
2903ee85 608 unsigned int bank;
89b831ef
JS
609 int err = 0;
610
89b831ef 611 for (bank = 0; bank < NR_BANKS; ++bank) {
5a96f4a5 612 if (!(per_cpu(bank_map, cpu) & (1 << bank)))
89b831ef
JS
613 continue;
614 err = threshold_create_bank(cpu, bank);
615 if (err)
616 goto out;
617 }
2903ee85 618out:
89b831ef
JS
619 return err;
620}
621
89b831ef
JS
622/*
623 * let's be hotplug friendly.
624 * in case of multiple core processors, the first core always takes ownership
625 * of shared sysfs dir/files, and rest of the cores will be symlinked to it.
626 */
627
be6b5a35 628static void deallocate_threshold_block(unsigned int cpu,
95268664
JS
629 unsigned int bank)
630{
631 struct threshold_block *pos = NULL;
632 struct threshold_block *tmp = NULL;
633 struct threshold_bank *head = per_cpu(threshold_banks, cpu)[bank];
634
635 if (!head)
636 return;
637
638 list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) {
38a382ae 639 kobject_put(&pos->kobj);
95268664
JS
640 list_del(&pos->miscj);
641 kfree(pos);
642 }
643
644 kfree(per_cpu(threshold_banks, cpu)[bank]->blocks);
645 per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
646}
647
be6b5a35 648static void threshold_remove_bank(unsigned int cpu, int bank)
89b831ef
JS
649{
650 struct threshold_bank *b;
95268664 651 char name[32];
1cb2a8e1 652 int i = 0;
89b831ef
JS
653
654 b = per_cpu(threshold_banks, cpu)[bank];
655 if (!b)
656 return;
95268664
JS
657 if (!b->blocks)
658 goto free_out;
659
660 sprintf(name, "threshold_bank%i", bank);
661
02316067 662#ifdef CONFIG_SMP
95268664
JS
663 /* sibling symlink */
664 if (shared_bank[bank] && b->blocks->cpu != cpu) {
cb491fca 665 sysfs_remove_link(&per_cpu(mce_dev, cpu).kobj, name);
0d2caebd 666 per_cpu(threshold_banks, cpu)[bank] = NULL;
1cb2a8e1 667
95268664 668 return;
89b831ef 669 }
02316067 670#endif
95268664
JS
671
672 /* remove all sibling symlinks before unregistering */
a1c33bbe 673 for_each_cpu(i, b->cpus) {
95268664
JS
674 if (i == cpu)
675 continue;
676
cb491fca 677 sysfs_remove_link(&per_cpu(mce_dev, i).kobj, name);
95268664
JS
678 per_cpu(threshold_banks, i)[bank] = NULL;
679 }
680
681 deallocate_threshold_block(cpu, bank);
682
683free_out:
8735728e 684 kobject_del(b->kobj);
38a382ae 685 kobject_put(b->kobj);
a1c33bbe 686 free_cpumask_var(b->cpus);
95268664
JS
687 kfree(b);
688 per_cpu(threshold_banks, cpu)[bank] = NULL;
89b831ef
JS
689}
690
be6b5a35 691static void threshold_remove_device(unsigned int cpu)
89b831ef 692{
2903ee85 693 unsigned int bank;
89b831ef
JS
694
695 for (bank = 0; bank < NR_BANKS; ++bank) {
5a96f4a5 696 if (!(per_cpu(bank_map, cpu) & (1 << bank)))
89b831ef
JS
697 continue;
698 threshold_remove_bank(cpu, bank);
699 }
89b831ef
JS
700}
701
89b831ef 702/* get notified when a cpu comes on/off */
1cb2a8e1
IM
703static void __cpuinit
704amd_64_threshold_cpu_callback(unsigned long action, unsigned int cpu)
89b831ef 705{
89b831ef
JS
706 switch (action) {
707 case CPU_ONLINE:
8bb78442 708 case CPU_ONLINE_FROZEN:
89b831ef 709 threshold_create_device(cpu);
89b831ef
JS
710 break;
711 case CPU_DEAD:
8bb78442 712 case CPU_DEAD_FROZEN:
89b831ef
JS
713 threshold_remove_device(cpu);
714 break;
715 default:
716 break;
717 }
89b831ef
JS
718}
719
89b831ef
JS
720static __init int threshold_init_device(void)
721{
2903ee85 722 unsigned lcpu = 0;
89b831ef 723
89b831ef
JS
724 /* to hit CPUs online before the notifier is up */
725 for_each_online_cpu(lcpu) {
fff2e89f 726 int err = threshold_create_device(lcpu);
1cb2a8e1 727
89b831ef 728 if (err)
fff2e89f 729 return err;
89b831ef 730 }
8735728e 731 threshold_cpu_callback = amd_64_threshold_cpu_callback;
1cb2a8e1 732
fff2e89f 733 return 0;
89b831ef 734}
89b831ef 735device_initcall(threshold_init_device);