Commit 91b99041 authored by Dave Jiang's avatar Dave Jiang Committed by Linus Torvalds

drivers/edac: updated PCI monitoring

Moving PCI to a per-instance device model

This should include the correct sysfs setup as well. Please review.
Signed-off-by: default avatarDave Jiang <djiang@mvista.com>
Signed-off-by: default avatarDouglas Thompson <dougthompson@xmission.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 81d87cb1
...@@ -11,9 +11,12 @@ obj-$(CONFIG_EDAC) := edac_stub.o ...@@ -11,9 +11,12 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.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_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
edac_core-objs += edac_module.o edac_device_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_AMD76X) += amd76x_edac.o
obj-$(CONFIG_EDAC_I5000) += i5000_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
static int force_function_unhide; static int force_function_unhide;
static struct edac_pci_ctl_info *e752x_pci;
#define e752x_printk(level, fmt, arg...) \ #define e752x_printk(level, fmt, arg...) \
edac_printk(level, "e752x", fmt, ##arg) edac_printk(level, "e752x", fmt, ##arg)
...@@ -1040,6 +1042,17 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) ...@@ -1040,6 +1042,17 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
e752x_init_error_reporting_regs(pvt); e752x_init_error_reporting_regs(pvt);
e752x_get_error_info(mci, &discard); /* clear other MCH errors */ 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 */ /* get this far and it's successful */
debugf3("%s(): success\n", __func__); debugf3("%s(): success\n", __func__);
return 0; return 0;
...@@ -1073,6 +1086,9 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev) ...@@ -1073,6 +1086,9 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__); debugf0("%s()\n", __func__);
if (e752x_pci)
edac_pci_release_generic_ctl(e752x_pci);
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return; return;
......
...@@ -60,6 +60,10 @@ ...@@ -60,6 +60,10 @@
#define edac_device_printk(ctl, level, fmt, arg...) \ #define edac_device_printk(ctl, level, fmt, arg...) \
printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##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() */ /* prefixes for edac_printk() and edac_mc_printk() */
#define EDAC_MC "MC" #define EDAC_MC "MC"
#define EDAC_PCI "PCI" #define EDAC_PCI "PCI"
...@@ -200,6 +204,13 @@ enum scrub_type { ...@@ -200,6 +204,13 @@ enum scrub_type {
/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ /* 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); extern char * edac_align_ptr(void *ptr, unsigned size);
/* /*
...@@ -520,12 +531,6 @@ struct edac_device_ctl_info { ...@@ -520,12 +531,6 @@ struct edac_device_ctl_info {
/* the internal state of this controller instance */ /* the internal state of this controller instance */
int op_state; 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 */ /* work struct for this instance */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
struct delayed_work work; struct delayed_work work;
...@@ -626,6 +631,84 @@ extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info); ...@@ -626,6 +631,84 @@ extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info);
#ifdef CONFIG_PCI #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*/ /* write all or some bits in a byte-register*/
static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
u8 mask) u8 mask)
...@@ -726,5 +809,30 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, ...@@ -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, extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
int inst_nr, int block_nr, const char *msg); 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_ */ #endif /* _EDAC_CORE_H_ */
...@@ -418,27 +418,6 @@ void edac_device_reset_delay_period( ...@@ -418,27 +418,6 @@ void edac_device_reset_delay_period(
unlock_device_list(); 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_add_device: Insert the 'edac_dev' structure into the
* edac_device global list and create sysfs entries associated with * edac_device global list and create sysfs entries associated with
...@@ -496,7 +475,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx) ...@@ -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->mod_name,
edac_dev->ctl_name, edac_dev->ctl_name,
dev_name(edac_dev), dev_name(edac_dev),
edac_op_state_toString(edac_dev) edac_op_state_toString(edac_dev->op_state)
); );
unlock_device_list(); unlock_device_list();
......
...@@ -34,6 +34,25 @@ static struct sysdev_class edac_class = { ...@@ -34,6 +34,25 @@ static struct sysdev_class edac_class = {
}; };
static int edac_class_valid = 0; 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() * edac_get_edac_class()
* *
...@@ -153,26 +172,16 @@ static int __init edac_init(void) ...@@ -153,26 +172,16 @@ static int __init edac_init(void)
goto error_sysfs; 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 */ /* Setup/Initialize the edac_device system */
err = edac_workqueue_setup(); err = edac_workqueue_setup();
if (err) { if (err) {
edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n"); edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
goto error_pci; goto error_mem;
} }
return 0; return 0;
/* Error teardown stack */ /* Error teardown stack */
error_pci:
edac_sysfs_pci_teardown();
error_mem: error_mem:
edac_sysfs_memctrl_teardown(); edac_sysfs_memctrl_teardown();
error_sysfs: error_sysfs:
...@@ -192,7 +201,6 @@ static void __exit edac_exit(void) ...@@ -192,7 +201,6 @@ static void __exit edac_exit(void)
/* tear down the various subsystems*/ /* tear down the various subsystems*/
edac_workqueue_teardown(); edac_workqueue_teardown();
edac_sysfs_memctrl_teardown(); edac_sysfs_memctrl_teardown();
edac_sysfs_pci_teardown();
edac_unregister_sysfs_edac_name(); edac_unregister_sysfs_edac_name();
} }
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment