Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 312788
b: refs/heads/master
c: 019f34f
h: refs/heads/master
v: v3
  • Loading branch information
Borislav Petkov committed Jun 7, 2012
1 parent b61655d commit 9c197d7
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 26ab256eaac7af26ecd9ba893b5159a3b38c8a1c
refs/heads/master: 019f34fccfd5cf5ff1e722dafd9fe2bd54434e66
21 changes: 21 additions & 0 deletions trunk/arch/x86/include/asm/amd_nb.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,31 @@ struct amd_l3_cache {
u8 subcaches[4];
};

struct threshold_block {
unsigned int block;
unsigned int bank;
unsigned int cpu;
u32 address;
u16 interrupt_enable;
bool interrupt_capable;
u16 threshold_limit;
struct kobject kobj;
struct list_head miscj;
};

struct threshold_bank {
struct kobject *kobj;
struct threshold_block *blocks;

/* initialized to the number of CPUs on the node sharing this bank */
atomic_t cpus;
};

struct amd_northbridge {
struct pci_dev *misc;
struct pci_dev *link;
struct amd_l3_cache l3_cache;
struct threshold_bank *bank4;
};

struct amd_northbridge_info {
Expand Down
107 changes: 87 additions & 20 deletions trunk/arch/x86/kernel/cpu/mcheck/mce_amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/cpu.h>
#include <linux/smp.h>

#include <asm/amd_nb.h>
#include <asm/apic.h>
#include <asm/idle.h>
#include <asm/mce.h>
Expand All @@ -45,23 +46,6 @@
#define MASK_BLKPTR_LO 0xFF000000
#define MCG_XBLK_ADDR 0xC0000400

struct threshold_block {
unsigned int block;
unsigned int bank;
unsigned int cpu;
u32 address;
u16 interrupt_enable;
bool interrupt_capable;
u16 threshold_limit;
struct kobject kobj;
struct list_head miscj;
};

struct threshold_bank {
struct kobject *kobj;
struct threshold_block *blocks;
};

static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);

static unsigned char shared_bank[NR_BANKS] = {
Expand Down Expand Up @@ -546,15 +530,62 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
return err;
}

static __cpuinit int __threshold_add_blocks(struct threshold_bank *b)
{
struct list_head *head = &b->blocks->miscj;
struct threshold_block *pos = NULL;
struct threshold_block *tmp = NULL;
int err = 0;

err = kobject_add(&b->blocks->kobj, b->kobj, b->blocks->kobj.name);
if (err)
return err;

list_for_each_entry_safe(pos, tmp, head, miscj) {

err = kobject_add(&pos->kobj, b->kobj, pos->kobj.name);
if (err) {
list_for_each_entry_safe_reverse(pos, tmp, head, miscj)
kobject_del(&pos->kobj);

return err;
}
}
return err;
}

static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
{
struct device *dev = per_cpu(mce_device, cpu);
struct amd_northbridge *nb = NULL;
struct threshold_bank *b = NULL;
char name[32];
int err = 0;

sprintf(name, "threshold_bank%i", bank);

if (shared_bank[bank]) {

nb = node_to_amd_nb(amd_get_nb_id(cpu));
WARN_ON(!nb);

/* threshold descriptor already initialized on this node? */
if (nb->bank4) {
/* yes, use it */
b = nb->bank4;
err = kobject_add(b->kobj, &dev->kobj, name);
if (err)
goto out;

per_cpu(threshold_banks, cpu)[bank] = b;
atomic_inc(&b->cpus);

err = __threshold_add_blocks(b);

goto out;
}
}

b = kzalloc(sizeof(struct threshold_bank), GFP_KERNEL);
if (!b) {
err = -ENOMEM;
Expand All @@ -569,15 +600,23 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)

per_cpu(threshold_banks, cpu)[bank] = b;

if (shared_bank[bank]) {
atomic_set(&b->cpus, 1);

/* nb is already initialized, see above */
WARN_ON(nb->bank4);
nb->bank4 = b;
}

err = allocate_threshold_blocks(cpu, bank, 0,
MSR_IA32_MC0_MISC + bank * 4);
if (!err)
goto out;

out_free:
per_cpu(threshold_banks, cpu)[bank] = NULL;
out_free:
kfree(b);
out:

out:
return err;
}

Expand Down Expand Up @@ -618,16 +657,44 @@ static void deallocate_threshold_block(unsigned int cpu,
per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
}

static void __threshold_remove_blocks(struct threshold_bank *b)
{
struct threshold_block *pos = NULL;
struct threshold_block *tmp = NULL;

kobject_del(b->kobj);

list_for_each_entry_safe(pos, tmp, &b->blocks->miscj, miscj)
kobject_del(&pos->kobj);
}

static void threshold_remove_bank(unsigned int cpu, int bank)
{
struct amd_northbridge *nb;
struct threshold_bank *b;

b = per_cpu(threshold_banks, cpu)[bank];
if (!b)
return;

if (!b->blocks)
goto free_out;

if (shared_bank[bank]) {
if (!atomic_dec_and_test(&b->cpus)) {
__threshold_remove_blocks(b);
per_cpu(threshold_banks, cpu)[bank] = NULL;
return;
} else {
/*
* the last CPU on this node using the shared bank is
* going away, remove that bank now.
*/
nb = node_to_amd_nb(amd_get_nb_id(cpu));
nb->bank4 = NULL;
}
}

deallocate_threshold_block(cpu, bank);

free_out:
Expand Down

0 comments on commit 9c197d7

Please sign in to comment.