#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/workqueue.h>
-#include <linux/version.h>
#define EDAC_MC_LABEL_LEN 31
#define EDAC_DEVICE_NAME_LEN 31
#define MC_PROC_NAME_MAX_LEN 7
#if PAGE_SHIFT < 20
-#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
+#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT))
+#define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
#else /* PAGE_SHIFT > 20 */
-#define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20))
+#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20))
#endif
#define edac_printk(level, prefix, fmt, arg...) \
#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
-/* edac_device printk */
#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)
#define EDAC_PCI "PCI"
#define EDAC_DEBUG "DEBUG"
+extern const char *edac_mem_types[];
+
#ifdef CONFIG_EDAC_DEBUG
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); \
- } while(0)
+#define edac_debug_printk(level, fmt, arg...) \
+ do { \
+ if (level <= edac_debug_level) \
+ edac_printk(KERN_DEBUG, EDAC_DEBUG, \
+ "%s: " fmt, __func__, ##arg); \
+ } while (0)
#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
#endif /* !CONFIG_EDAC_DEBUG */
-#define BIT(x) (1 << (x))
-
#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 {
MEM_DDR2, /* DDR2 RAM */
MEM_FB_DDR2, /* fully buffered DDR2 */
MEM_RDDR2, /* Registered DDR2 RAM */
+ MEM_XDR, /* Rambus XDR */
+ MEM_DDR3, /* DDR3 RAM */
+ MEM_RDDR3, /* Registered DDR3 RAM */
};
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
#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)
+#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
/* chipset Error Detection and Correction capabilities and mode */
enum edac_type {
* for single channel are 64 bits, for dual channel 128
* bits.
*
- * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memmory.
+ * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory.
* Motherboards commonly drive two chip-select pins to
* a memory stick. A single-ranked stick, will occupy
* only one of those rows. The other will be unused.
* is irrespective of the memory devices being mounted
* on both sides of the memory stick.
*
- * Socket set: All of the memory sticks that are required for for
+ * Socket set: All of the memory sticks that are required for
* a single memory access or all of the memory sticks
* spanned by a chip-select row. A single socket set
* has two chip-select rows and if double-sided sticks
struct channel_info *channels;
};
+struct mcidev_sysfs_group {
+ const char *name; /* group name */
+ const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
+};
+
+struct mcidev_sysfs_group_kobj {
+ struct list_head list; /* list for all instances within a mc */
+
+ struct kobject kobj; /* kobj for the group */
+
+ const struct mcidev_sysfs_group *grp; /* group description table */
+ struct mem_ctl_info *mci; /* the parent */
+};
+
/* 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;
+ /* It should use either attr or grp */
+ struct attribute attr;
+ const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
+
+ /* Ops for show/store values at the attribute - not used on group */
ssize_t (*show)(struct mem_ctl_info *,char *);
ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
};
*/
struct mem_ctl_info {
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
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);
/* pointer to edac checking routine */
/* edac sysfs device control */
struct kobject edac_mci_kobj;
+ /* list for all grp instances within a mc */
+ struct list_head grp_kobj_list;
+
/* Additional top controller level attributes, but specified
* by the low level driver.
*
* 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;
+ const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
/* work struct for this MC */
struct delayed_work work;
};
/* 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_dev_sysfs_block_attribute {
struct attribute attr;
const char *, size_t);
struct edac_device_block *block;
- /* low driver use */
- void *arg;
unsigned int value;
};
/* edac sysfs device control */
struct kobject kobj;
- struct completion kobj_complete;
};
/* device instance control structure */
/* edac sysfs device control */
struct kobject kobj;
- struct completion kobj_complete;
};
/* 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 */
* 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:
* 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 */
pci_write_config_word(pdev, offset, value);
}
-/* write all or some bits in a dword-register*/
+/*
+ * pci_write_bits32
+ *
+ * edac local routine to do pci_write_config_dword, but adds
+ * a mask parameter. If mask is all ones, ignore the mask.
+ * Otherwise utilize the mask to isolate specified bits
+ *
+ * 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)
{
- if (mask != 0xffff) {
+ if (mask != 0xffffffff) {
u32 buf;
pci_read_config_dword(pdev, offset, &buf);
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 *find_mci_by_dev(struct device *dev);
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);
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);
+extern int edac_device_alloc_index(void);
/*
* edac_pci APIs
extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
unsigned long value);
+extern int edac_pci_alloc_index(void);
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);