X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fedac%2Fedac_core.h;h=4e6bad15c4ba2c342fe0cb89f9a4520a3b15e5d6;hb=cc556c5c92a45763e23015a31efb27005a6132fa;hp=f34ebb609d55e872cb78d6f5777891c9fc11caf5;hpb=c4192705fec85219086231a1c0fa61e8776e2c3b;p=linux-2.6 diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index f34ebb609d..4b55ec607a 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -34,7 +34,6 @@ #include #include #include -#include #define EDAC_MC_LABEL_LEN 31 #define EDAC_DEVICE_NAME_LEN 31 @@ -60,6 +59,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" @@ -71,7 +74,7 @@ extern int edac_debug_level; #define edac_debug_printk(level, fmt, arg...) \ do { \ if (level <= edac_debug_level) \ - edac_printk(KERN_EMERG, EDAC_DEBUG, fmt, ##arg); \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ } while(0) #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) @@ -80,7 +83,7 @@ extern int edac_debug_level; #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) -#else /* !CONFIG_EDAC_DEBUG */ +#else /* !CONFIG_EDAC_DEBUG */ #define debugf0( ... ) #define debugf1( ... ) @@ -88,14 +91,12 @@ extern int edac_debug_level; #define debugf3( ... ) #define debugf4( ... ) -#endif /* !CONFIG_EDAC_DEBUG */ - -#define BIT(x) (1 << (x)) +#endif /* !CONFIG_EDAC_DEBUG */ #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ PCI_DEVICE_ID_ ## vend ## _ ## dev -#define dev_name(dev) (dev)->dev_name +#define edac_dev_name(dev) (dev)->dev_name /* memory devices */ enum dev_type { @@ -131,9 +132,10 @@ enum mem_type { MEM_DDR, /* Double data rate SDRAM */ MEM_RDDR, /* Registered Double data rate SDRAM */ MEM_RMBS, /* Rambus DRAM */ - MEM_DDR2, /* DDR2 RAM */ - MEM_FB_DDR2, /* fully buffered DDR2 */ - MEM_RDDR2, /* Registered DDR2 RAM */ + MEM_DDR2, /* DDR2 RAM */ + MEM_FB_DDR2, /* fully buffered DDR2 */ + MEM_RDDR2, /* Registered DDR2 RAM */ + MEM_XDR, /* Rambus XDR */ }; #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) @@ -150,6 +152,7 @@ enum mem_type { #define MEM_FLAG_DDR2 BIT(MEM_DDR2) #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) #define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) +#define MEM_FLAG_XDR BIT(MEM_XDR) /* chipset Error Detection and Correction capabilities and mode */ enum edac_type { @@ -200,7 +203,12 @@ enum scrub_type { /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ -extern char * edac_align_ptr(void *ptr, unsigned size); +/* 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 /* * There are several things to be aware of that aren't at all obvious: @@ -287,7 +295,7 @@ extern char * edac_align_ptr(void *ptr, unsigned size); struct channel_info { int chan_idx; /* channel index */ u32 ce_count; /* Correctable Errors for this CHANNEL */ - char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ + char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ struct csrow_info *csrow; /* the parent */ }; @@ -308,15 +316,29 @@ struct csrow_info { struct mem_ctl_info *mci; /* the parent */ struct kobject kobj; /* sysfs kobject for this csrow */ - struct completion kobj_complete; - /* FIXME the number of CHANNELs might need to become dynamic */ + /* channel information for this csrow */ u32 nr_channels; struct channel_info *channels; }; +/* mcidev_sysfs_attribute structure + * used for driver sysfs attributes and in mem_ctl_info + * sysfs top level entries + */ +struct mcidev_sysfs_attribute { + struct attribute attr; + ssize_t (*show)(struct mem_ctl_info *,char *); + ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); +}; + +/* MEMORY controller information structure + */ struct mem_ctl_info { - struct list_head link; /* for global list of mem_ctl_info structs */ + struct list_head link; /* for global list of mem_ctl_info structs */ + + struct module *owner; /* Module owner of this control struct */ + unsigned long mtype_cap; /* memory types supported by mc */ unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ unsigned long edac_cap; /* configuration capabilities - this is @@ -333,14 +355,15 @@ struct mem_ctl_info { /* Translates sdram memory scrub rate given in bytes/sec to the internal representation and configures whatever else needs to be configured. - */ - int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); + */ + int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw); /* Get the current sdram memory scrub rate from the internal representation and converts it to the closest matching bandwith in bytes/sec. - */ - int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); + */ + int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw); + /* pointer to edac checking routine */ void (*edac_check) (struct mem_ctl_info * mci); @@ -351,7 +374,7 @@ struct mem_ctl_info { */ /* FIXME - why not send the phys page to begin with? */ unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, - unsigned long page); + unsigned long page); int mc_idx; int nr_csrows; struct csrow_info *csrows; @@ -381,11 +404,28 @@ struct mem_ctl_info { /* edac sysfs device control */ struct kobject edac_mci_kobj; - struct completion kobj_complete; + + /* Additional top controller level attributes, but specified + * by the low level driver. + * + * Set by the low level driver to provide attributes at the + * controller level, same level as 'ue_count' and 'ce_count' above. + * An array of structures, NULL terminated + * + * If attributes are desired, then set to array of attributes + * If no attributes are desired, leave NULL + */ + struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; + + /* work struct for this MC */ + struct delayed_work work; + + /* the internal state of this controller instance */ + int op_state; }; /* - * The following are the structures to provide for a generice + * The following are the structures to provide for a generic * or abstract 'edac_device'. This set of structures and the * code that implements the APIs for the same, provide for * registering EDAC type devices which are NOT standard memory. @@ -424,54 +464,61 @@ struct mem_ctl_info { */ struct edac_device_counter { - u32 ue_count; - u32 ce_count; + u32 ue_count; + u32 ce_count; }; -#define INC_COUNTER(cnt) (cnt++) +/* forward reference */ +struct edac_device_ctl_info; +struct edac_device_block; -/* - * An array of these is passed to the alloc() function - * to specify attributes of the edac_block +/* edac_dev_sysfs_attribute structure + * used for driver sysfs attributes in mem_ctl_info + * for extra controls and attributes: + * like high level error Injection controls */ -struct edac_attrib_spec { - char name[EDAC_DEVICE_NAME_LEN + 1]; - - int type; -#define EDAC_ATTR_INT 0x01 -#define EDAC_ATTR_CHAR 0x02 +struct edac_dev_sysfs_attribute { + struct attribute attr; + ssize_t (*show)(struct edac_device_ctl_info *, char *); + ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t); }; - -/* Attribute control structure - * In this structure is a pointer to the driver's edac_attrib_spec - * The life of this pointer is inclusive in the life of the driver's - * life cycle. +/* edac_dev_sysfs_block_attribute structure + * + * used in leaf 'block' nodes for adding controls/attributes + * + * each block in each instance of the containing control structure + * can have an array of the following. The show and store functions + * will be filled in with the show/store function in the + * low level driver. + * + * The 'value' field will be the actual value field used for + * counting */ -struct edac_attrib { - struct edac_device_block *block; /* Up Pointer */ - - struct edac_attrib_spec *spec; /* ptr to module spec entry */ - - union { /* actual value */ - int edac_attrib_int_value; - char edac_attrib_char_value[EDAC_ATTRIB_VALUE_LEN + 1]; - } edac_attrib_value; +struct edac_dev_sysfs_block_attribute { + struct attribute attr; + ssize_t (*show)(struct kobject *, struct attribute *, char *); + ssize_t (*store)(struct kobject *, struct attribute *, + const char *, size_t); + struct edac_device_block *block; + + unsigned int value; }; /* device block control structure */ struct edac_device_block { struct edac_device_instance *instance; /* Up Pointer */ - char name[EDAC_DEVICE_NAME_LEN + 1]; + char name[EDAC_DEVICE_NAME_LEN + 1]; struct edac_device_counter counters; /* basic UE and CE counters */ - int nr_attribs; /* how many attributes */ - struct edac_attrib *attribs; /* this block's attributes */ + int nr_attribs; /* how many attributes */ + + /* this block's attributes, could be NULL */ + struct edac_dev_sysfs_block_attribute *block_attributes; /* edac sysfs device control */ struct kobject kobj; - struct completion kobj_complete; }; /* device instance control structure */ @@ -481,12 +528,11 @@ struct edac_device_instance { struct edac_device_counter counters; /* instance counters */ - u32 nr_blocks; /* how many blocks */ + u32 nr_blocks; /* how many blocks */ struct edac_device_block *blocks; /* block array */ /* edac sysfs device control */ struct kobject kobj; - struct completion kobj_complete; }; @@ -498,6 +544,8 @@ struct edac_device_ctl_info { /* for global list of edac_device_ctl_info structs */ struct list_head link; + struct module *owner; /* Module owner of this control struct */ + int dev_idx; /* Per instance controls for this edac_device */ @@ -507,27 +555,30 @@ struct edac_device_ctl_info { 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 */ + /* Additional top controller level attributes, but specified + * by the low level driver. + * + * Set by the low level driver to provide attributes at the + * controller level, same level as 'ue_count' and 'ce_count' above. + * An array of structures, NULL terminated + * + * If attributes are desired, then set to array of attributes + * If no attributes are desired, leave NULL + */ + struct edac_dev_sysfs_attribute *sysfs_attributes; + + /* pointer to main 'edac' class in sysfs */ + struct sysdev_class *edac_class; /* 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; -#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 + * 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_device_ctl_info * edac_dev); @@ -539,20 +590,20 @@ struct edac_device_ctl_info { void *pvt_info; /* pointer to 'private driver' info */ - unsigned long start_time;/* edac_device load start time (jiffies)*/ + unsigned long start_time; /* edac_device load start time (jiffies) */ /* these are for safe removal of mc devices from global list while * NMI handlers may be traversing list */ struct rcu_head rcu; - struct completion complete; + struct completion removal_complete; /* sysfs top name under 'edac' directory * and instance name: - * cpu/cpu0/... - * cpu/cpu1/... - * cpu/cpu2/... - * ... + * cpu/cpu0/... + * cpu/cpu1/... + * cpu/cpu2/... + * ... */ char name[EDAC_DEVICE_NAME_LEN + 1]; @@ -569,36 +620,28 @@ struct edac_device_ctl_info { * device this structure controls */ struct kobject kobj; - struct completion kobj_complete; }; /* To get from the instance's wq to the beginning of the ctl structure */ +#define to_edac_mem_ctl_work(w) \ + container_of(w, struct mem_ctl_info, work) + #define to_edac_device_ctl_work(w) \ container_of(w,struct edac_device_ctl_info,work) -/* Function to calc the number of delay jiffies from poll_msec */ -static inline void edac_device_calc_delay( - struct edac_device_ctl_info *edac_dev) -{ - /* convert from msec to jiffies */ - edac_dev->delay = edac_dev->poll_msec * HZ / 1000; -} - /* * The alloc() and free() functions for the 'edac_device' control info * structure. A MC driver will allocate one of these for each edac_device * it is going to control/register with the EDAC CORE. */ extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( - unsigned sizeof_private, - char *edac_device_name, - unsigned nr_instances, - char *edac_block_name, - unsigned nr_blocks, - unsigned offset_value, - struct edac_attrib_spec *attrib_spec, - unsigned nr_attribs -); + unsigned sizeof_private, + char *edac_device_name, unsigned nr_instances, + char *edac_block_name, unsigned nr_blocks, + unsigned offset_value, + struct edac_dev_sysfs_block_attribute *block_attributes, + unsigned nr_attribs, + int device_index); /* The offset value can be: * -1 indicating no offset value @@ -608,13 +651,80 @@ extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( */ #define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1) -extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info); +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; + + struct sysdev_class *edac_class; /* pointer to class */ + + /* the internal state of this controller instance */ + int op_state; + /* work struct for this instance */ + struct delayed_work work; + + /* 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) + u8 mask) { if (mask != 0xff) { u8 buf; @@ -630,7 +740,7 @@ static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, /* write all or some bits in a word-register*/ static inline void pci_write_bits16(struct pci_dev *pdev, int offset, - u16 value, u16 mask) + u16 value, u16 mask) { if (mask != 0xffff) { u16 buf; @@ -646,7 +756,7 @@ static inline void pci_write_bits16(struct pci_dev *pdev, int offset, /* write all or some bits in a dword-register*/ static inline void pci_write_bits32(struct pci_dev *pdev, int offset, - u32 value, u32 mask) + u32 value, u32 mask) { if (mask != 0xffff) { u32 buf; @@ -660,13 +770,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset, pci_write_config_dword(pdev, offset, value); } -#endif /* CONFIG_PCI */ +#endif /* CONFIG_PCI */ -extern struct mem_ctl_info * edac_mc_find(int idx); -extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx); -extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev); +extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, + unsigned nr_chans, int edac_index); +extern int edac_mc_add_mc(struct mem_ctl_info *mci); +extern void edac_mc_free(struct mem_ctl_info *mci); +extern struct mem_ctl_info *edac_mc_find(int idx); +extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, - unsigned long page); + unsigned long page); /* * The no info errors are used when error overflows are reported. @@ -679,38 +792,59 @@ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, * statement clutter and extra function arguments. */ extern void edac_mc_handle_ce(struct mem_ctl_info *mci, - unsigned long page_frame_number, unsigned long offset_in_page, - unsigned long syndrome, int row, int channel, - const char *msg); + unsigned long page_frame_number, + unsigned long offset_in_page, + unsigned long syndrome, int row, int channel, + const char *msg); extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, - const char *msg); + const char *msg); extern void edac_mc_handle_ue(struct mem_ctl_info *mci, - unsigned long page_frame_number, unsigned long offset_in_page, - int row, const char *msg); + unsigned long page_frame_number, + unsigned long offset_in_page, int row, + const char *msg); extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, - const char *msg); -extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, - unsigned int csrow, - unsigned int channel0, - unsigned int channel1, - char *msg); -extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, - unsigned int csrow, - unsigned int channel, - char *msg); + const char *msg); +extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow, + unsigned int channel0, unsigned int channel1, + char *msg); +extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow, + unsigned int channel, char *msg); /* * edac_device APIs */ -extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, - unsigned nr_chans); -extern void edac_mc_free(struct mem_ctl_info *mci); -extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx); -extern struct edac_device_ctl_info * edac_device_del_device(struct device *dev); +extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev); +extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev); extern void edac_device_handle_ue(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); 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_to_string(int op_state); #endif /* _EDAC_CORE_H_ */