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