Skip to content

Commit

Permalink
drivers/edac: updated PCI monitoring
Browse files Browse the repository at this point in the history
Moving PCI to a per-instance device model

This should include the correct sysfs setup as well. Please review.

Signed-off-by: Dave Jiang <djiang@mvista.com>
Signed-off-by: Douglas Thompson <dougthompson@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Dave Jiang authored and Linus Torvalds committed Jul 19, 2007
1 parent 81d87cb commit 91b9904
Show file tree
Hide file tree
Showing 7 changed files with 861 additions and 65 deletions.
5 changes: 4 additions & 1 deletion drivers/edac/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o

edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o

edac_core-objs += edac_module.o edac_device_sysfs.o

ifdef CONFIG_PCI
edac_core-objs += edac_pci.o edac_pci_sysfs.o
endif

obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
Expand Down
16 changes: 16 additions & 0 deletions drivers/edac/e752x_edac.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

static int force_function_unhide;

static struct edac_pci_ctl_info *e752x_pci;

#define e752x_printk(level, fmt, arg...) \
edac_printk(level, "e752x", fmt, ##arg)

Expand Down Expand Up @@ -1040,6 +1042,17 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
e752x_init_error_reporting_regs(pvt);
e752x_get_error_info(mci, &discard); /* clear other MCH errors */

/* allocating generic PCI control info */
e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
if (!e752x_pci) {
printk(KERN_WARNING
"%s(): Unable to create PCI control\n",
__func__);
printk(KERN_WARNING
"%s(): PCI error report via EDAC not setup\n",
__func__);
}

/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
Expand Down Expand Up @@ -1073,6 +1086,9 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)

debugf0("%s()\n", __func__);

if (e752x_pci)
edac_pci_release_generic_ctl(e752x_pci);

if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;

Expand Down
120 changes: 114 additions & 6 deletions drivers/edac/edac_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
#define edac_device_printk(ctl, level, fmt, arg...) \
printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)

/* edac_pci printk */
#define edac_pci_printk(ctl, level, fmt, arg...) \
printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)

/* prefixes for edac_printk() and edac_mc_printk() */
#define EDAC_MC "MC"
#define EDAC_PCI "PCI"
Expand Down Expand Up @@ -200,6 +204,13 @@ enum scrub_type {

/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */

/* EDAC internal operation states */
#define OP_ALLOC 0x100
#define OP_RUNNING_POLL 0x201
#define OP_RUNNING_INTERRUPT 0x202
#define OP_RUNNING_POLL_INTR 0x203
#define OP_OFFLINE 0x300

extern char * edac_align_ptr(void *ptr, unsigned size);

/*
Expand Down Expand Up @@ -520,12 +531,6 @@ struct edac_device_ctl_info {

/* the internal state of this controller instance */
int op_state;
#define OP_ALLOC 0x100
#define OP_RUNNING_POLL 0x201
#define OP_RUNNING_INTERRUPT 0x202
#define OP_RUNNING_POLL_INTR 0x203
#define OP_OFFLINE 0x300

/* work struct for this instance */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
struct delayed_work work;
Expand Down Expand Up @@ -626,6 +631,84 @@ extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info);

#ifdef CONFIG_PCI

struct edac_pci_counter {
atomic_t pe_count;
atomic_t npe_count;
};

/*
* Abstract edac_pci control info structure
*
*/
struct edac_pci_ctl_info {
/* for global list of edac_pci_ctl_info structs */
struct list_head link;

int pci_idx;

/* Per instance controls for this edac_device */
int check_parity_error; /* boolean for checking parity errs */
int log_parity_error; /* boolean for logging parity errs */
int panic_on_pe; /* boolean for panic'ing on a PE */
unsigned poll_msec; /* number of milliseconds to poll interval */
unsigned long delay; /* number of jiffies for poll_msec */

struct sysdev_class *edac_class; /* pointer to class */

/* the internal state of this controller instance */
int op_state;
/* work struct for this instance */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
struct delayed_work work;
#else
struct work_struct work;
#endif

/* pointer to edac polling checking routine:
* If NOT NULL: points to polling check routine
* If NULL: Then assumes INTERRUPT operation, where
* MC driver will receive events
*/
void (*edac_check) (struct edac_pci_ctl_info * edac_dev);

struct device *dev; /* pointer to device structure */

const char *mod_name; /* module name */
const char *ctl_name; /* edac controller name */
const char *dev_name; /* pci/platform/etc... name */

void *pvt_info; /* pointer to 'private driver' info */

unsigned long start_time;/* edac_pci load start time (jiffies)*/

/* these are for safe removal of devices from global list while
* NMI handlers may be traversing list
*/
struct rcu_head rcu;
struct completion complete;

/* sysfs top name under 'edac' directory
* and instance name:
* cpu/cpu0/...
* cpu/cpu1/...
* cpu/cpu2/...
* ...
*/
char name[EDAC_DEVICE_NAME_LEN + 1];

/* Event counters for the this whole EDAC Device */
struct edac_pci_counter counters;

/* edac sysfs device control for the 'name'
* device this structure controls
*/
struct kobject kobj;
struct completion kobj_complete;
};

#define to_edac_pci_ctl_work(w) \
container_of(w, struct edac_pci_ctl_info,work)

/* write all or some bits in a byte-register*/
static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
u8 mask)
Expand Down Expand Up @@ -726,5 +809,30 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
int inst_nr, int block_nr, const char *msg);

/*
* edac_pci APIs
*/
extern struct edac_pci_ctl_info *
edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name);

extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);

extern void
edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, unsigned long value);

extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
extern struct edac_pci_ctl_info * edac_pci_del_device(struct device *dev);

extern struct edac_pci_ctl_info *
edac_pci_create_generic_ctl(struct device *dev, const char *mod_name);

extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);

/*
* edac misc APIs
*/
extern char * edac_op_state_toString(int op_state);

#endif /* _EDAC_CORE_H_ */
23 changes: 1 addition & 22 deletions drivers/edac/edac_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,27 +418,6 @@ void edac_device_reset_delay_period(
unlock_device_list();
}

/*
* edac_op_state_toString(edac_dev)
*/
static char *edac_op_state_toString(struct edac_device_ctl_info *edac_dev)
{
int opstate = edac_dev->op_state;

if (opstate == OP_RUNNING_POLL)
return "POLLED";
else if (opstate == OP_RUNNING_INTERRUPT)
return "INTERRUPT";
else if (opstate == OP_RUNNING_POLL_INTR)
return "POLL-INTR";
else if (opstate == OP_ALLOC)
return "ALLOC";
else if (opstate == OP_OFFLINE)
return "OFFLINE";

return "UNKNOWN";
}

/**
* edac_device_add_device: Insert the 'edac_dev' structure into the
* edac_device global list and create sysfs entries associated with
Expand Down Expand Up @@ -496,7 +475,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx)
edac_dev->mod_name,
edac_dev->ctl_name,
dev_name(edac_dev),
edac_op_state_toString(edac_dev)
edac_op_state_toString(edac_dev->op_state)
);

unlock_device_list();
Expand Down
32 changes: 20 additions & 12 deletions drivers/edac/edac_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ static struct sysdev_class edac_class = {
};
static int edac_class_valid = 0;

/*
* edac_op_state_toString()
*/
char * edac_op_state_toString(int opstate)
{
if (opstate == OP_RUNNING_POLL)
return "POLLED";
else if (opstate == OP_RUNNING_INTERRUPT)
return "INTERRUPT";
else if (opstate == OP_RUNNING_POLL_INTR)
return "POLL-INTR";
else if (opstate == OP_ALLOC)
return "ALLOC";
else if (opstate == OP_OFFLINE)
return "OFFLINE";

return "UNKNOWN";
}

/*
* edac_get_edac_class()
*
Expand Down Expand Up @@ -153,26 +172,16 @@ static int __init edac_init(void)
goto error_sysfs;
}

/* Create the PCI parity sysfs entries */
if (edac_sysfs_pci_setup()) {
edac_printk(KERN_ERR, EDAC_MC,
"PCI: Error initializing sysfs code\n");
err = -ENODEV;
goto error_mem;
}

/* Setup/Initialize the edac_device system */
err = edac_workqueue_setup();
if (err) {
edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
goto error_pci;
goto error_mem;
}

return 0;

/* Error teardown stack */
error_pci:
edac_sysfs_pci_teardown();
error_mem:
edac_sysfs_memctrl_teardown();
error_sysfs:
Expand All @@ -192,7 +201,6 @@ static void __exit edac_exit(void)
/* tear down the various subsystems*/
edac_workqueue_teardown();
edac_sysfs_memctrl_teardown();
edac_sysfs_pci_teardown();
edac_unregister_sysfs_edac_name();
}

Expand Down
Loading

0 comments on commit 91b9904

Please sign in to comment.