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