Merge branch 'edac-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp

* 'edac-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  amd64_edac: Disable DRAM ECC injection on K8
  EDAC: Fixup scrubrate manipulation
  amd64_edac: Remove two-stage initialization
  amd64_edac: Check ECC capabilities initially
  amd64_edac: Carve out ECC-related hw settings
  amd64_edac: Remove PCI ECS enabling functions
  amd64_edac: Remove explicit Kconfig PCI dependency
  amd64_edac: Allocate driver instances dynamically
  amd64_edac: Rework printk macros
  amd64_edac: Rename CPU PCI devices
  amd64_edac: Concentrate per-family init even more
  amd64_edac: Cleanup the CPU PCI device reservation
  amd64_edac: Simplify CPU family detection
  amd64_edac: Add per-family init function
  amd64_edac: Use cached extended CPU model
  amd64_edac: Remove F11h support
This commit is contained in:
Linus Torvalds 2011-01-07 14:53:42 -08:00
commit 442d1ba237
10 changed files with 437 additions and 599 deletions

View File

@ -75,11 +75,11 @@ config EDAC_MCE
bool
config EDAC_AMD64
tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
depends on EDAC_MM_EDAC && AMD_NB && X86_64 && PCI && EDAC_DECODE_MCE
tristate "AMD64 (Opteron, Athlon64) K8, F10h"
depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE
help
Support for error detection and correction on the AMD 64
Families of Memory Controllers (K8, F10h and F11h)
Support for error detection and correction of DRAM ECC errors on
the AMD64 families of memory controllers (K8 and F10h)
config EDAC_AMD64_ERROR_INJECTION
bool "Sysfs HW Error injection facilities"

File diff suppressed because it is too large Load Diff

View File

@ -74,11 +74,26 @@
#include "edac_core.h"
#include "mce_amd.h"
#define amd64_printk(level, fmt, arg...) \
edac_printk(level, "amd64", fmt, ##arg)
#define amd64_debug(fmt, arg...) \
edac_printk(KERN_DEBUG, "amd64", fmt, ##arg)
#define amd64_mc_printk(mci, level, fmt, arg...) \
edac_mc_chipset_printk(mci, level, "amd64", fmt, ##arg)
#define amd64_info(fmt, arg...) \
edac_printk(KERN_INFO, "amd64", fmt, ##arg)
#define amd64_notice(fmt, arg...) \
edac_printk(KERN_NOTICE, "amd64", fmt, ##arg)
#define amd64_warn(fmt, arg...) \
edac_printk(KERN_WARNING, "amd64", fmt, ##arg)
#define amd64_err(fmt, arg...) \
edac_printk(KERN_ERR, "amd64", fmt, ##arg)
#define amd64_mc_warn(mci, fmt, arg...) \
edac_mc_chipset_printk(mci, KERN_WARNING, "amd64", fmt, ##arg)
#define amd64_mc_err(mci, fmt, arg...) \
edac_mc_chipset_printk(mci, KERN_ERR, "amd64", fmt, ##arg)
/*
* Throughout the comments in this code, the following terms are used:
@ -129,11 +144,9 @@
* sections 3.5.4 and 3.5.5 for more information.
*/
#define EDAC_AMD64_VERSION " Ver: 3.3.0 " __DATE__
#define EDAC_AMD64_VERSION "v3.3.0"
#define EDAC_MOD_STR "amd64_edac"
#define EDAC_MAX_NUMNODES 8
/* Extended Model from CPUID, for CPU Revision numbers */
#define K8_REV_D 1
#define K8_REV_E 2
@ -322,9 +335,6 @@
#define K8_SCRCTRL 0x58
#define F10_NB_CFG_LOW 0x88
#define F10_NB_CFG_LOW_ENABLE_EXT_CFG BIT(14)
#define F10_NB_CFG_HIGH 0x8C
#define F10_ONLINE_SPARE 0xB0
#define F10_ONLINE_SPARE_SWAPDONE0(x) ((x) & BIT(1))
@ -373,7 +383,6 @@ static inline int get_node_id(struct pci_dev *pdev)
enum amd64_chipset_families {
K8_CPUS = 0,
F10_CPUS,
F11_CPUS,
};
/* Error injection control structure */
@ -384,16 +393,13 @@ struct error_injection {
};
struct amd64_pvt {
struct low_ops *ops;
/* pci_device handles which we utilize */
struct pci_dev *addr_f1_ctl;
struct pci_dev *dram_f2_ctl;
struct pci_dev *misc_f3_ctl;
struct pci_dev *F1, *F2, *F3;
int mc_node_id; /* MC index of this MC node */
int ext_model; /* extended model value of this node */
struct low_ops *ops; /* pointer to per PCI Device ID func table */
int channel_count;
/* Raw registers */
@ -455,27 +461,27 @@ struct amd64_pvt {
/* place to store error injection parameters prior to issue */
struct error_injection injection;
/* Save old hw registers' values before we modified them */
u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */
/* DCT per-family scrubrate setting */
u32 min_scrubrate;
/* family name this instance is running on */
const char *ctl_name;
};
/*
* per-node ECC settings descriptor
*/
struct ecc_settings {
u32 old_nbctl;
bool nbctl_valid;
/* MC Type Index value: socket F vs Family 10h */
u32 mc_type_index;
/* misc settings */
struct flags {
unsigned long cf8_extcfg:1;
unsigned long nb_mce_enable:1;
unsigned long nb_ecc_prev:1;
} flags;
};
struct scrubrate {
u32 scrubval; /* bit pattern for scrub rate */
u32 bandwidth; /* bandwidth consumed (bytes/sec) */
};
extern struct scrubrate scrubrates[23];
extern const char *tt_msgs[4];
extern const char *ll_msgs[4];
extern const char *rrrr_msgs[16];
@ -517,23 +523,10 @@ struct low_ops {
struct amd64_family_type {
const char *ctl_name;
u16 addr_f1_ctl;
u16 misc_f3_ctl;
u16 f1_id, f3_id;
struct low_ops ops;
};
static struct amd64_family_type amd64_family_types[];
static inline const char *get_amd_family_name(int index)
{
return amd64_family_types[index].ctl_name;
}
static inline struct low_ops *family_ops(int index)
{
return &amd64_family_types[index].ops;
}
static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
u32 *val, const char *func)
{
@ -541,8 +534,8 @@ static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
err = pci_read_config_dword(pdev, offset, val);
if (err)
amd64_printk(KERN_WARNING, "%s: error reading F%dx%x.\n",
func, PCI_FUNC(pdev->devfn), offset);
amd64_warn("%s: error reading F%dx%x.\n",
func, PCI_FUNC(pdev->devfn), offset);
return err;
}
@ -556,7 +549,6 @@ static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
*/
#define K8_MIN_SCRUB_RATE_BITS 0x0
#define F10_MIN_SCRUB_RATE_BITS 0x5
#define F11_MIN_SCRUB_RATE_BITS 0x6
int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
u64 *hole_offset, u64 *hole_size);

View File

@ -23,9 +23,7 @@ static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
if (ret != -EINVAL) {
if (value > 3) {
amd64_printk(KERN_WARNING,
"%s: invalid section 0x%lx\n",
__func__, value);
amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
return -EINVAL;
}
@ -58,9 +56,7 @@ static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
if (ret != -EINVAL) {
if (value > 8) {
amd64_printk(KERN_WARNING,
"%s: invalid word 0x%lx\n",
__func__, value);
amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
return -EINVAL;
}
@ -92,9 +88,8 @@ static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
if (ret != -EINVAL) {
if (value & 0xFFFF0000) {
amd64_printk(KERN_WARNING,
"%s: invalid EccVector: 0x%lx\n",
__func__, value);
amd64_warn("%s: invalid EccVector: 0x%lx\n",
__func__, value);
return -EINVAL;
}
@ -122,15 +117,13 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM_ECC |
SET_NB_ARRAY_ADDRESS(pvt->injection.section);
pci_write_config_dword(pvt->misc_f3_ctl,
F10_NB_ARRAY_ADDR, section);
pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section);
word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
pvt->injection.bit_map);
/* Issue 'word' and 'bit' along with the READ request */
pci_write_config_dword(pvt->misc_f3_ctl,
F10_NB_ARRAY_DATA, word_bits);
pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
@ -157,15 +150,13 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM_ECC |
SET_NB_ARRAY_ADDRESS(pvt->injection.section);
pci_write_config_dword(pvt->misc_f3_ctl,
F10_NB_ARRAY_ADDR, section);
pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section);
word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
pvt->injection.bit_map);
/* Issue 'word' and 'bit' along with the READ request */
pci_write_config_dword(pvt->misc_f3_ctl,
F10_NB_ARRAY_DATA, word_bits);
pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);

View File

@ -818,9 +818,10 @@ static void cpc925_del_edac_devices(void)
}
/* Convert current back-ground scrub rate into byte/sec bandwith */
static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci)
{
struct cpc925_mc_pdata *pdata = mci->pvt_info;
int bw;
u32 mscr;
u8 si;
@ -832,11 +833,11 @@ static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) ||
(si == 0)) {
cpc925_mc_printk(mci, KERN_INFO, "Scrub mode not enabled\n");
*bw = 0;
bw = 0;
} else
*bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si;
bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si;
return 0;
return bw;
}
/* Return 0 for single channel; 1 for dual channel */

View File

@ -983,11 +983,11 @@ static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval);
return 0;
return scrubrates[i].bandwidth;
}
/* Convert current scrub rate value into byte/sec bandwidth */
static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
{
const struct scrubrate *scrubrates;
struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
@ -1013,10 +1013,8 @@ static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
"Invalid sdram scrub control value: 0x%x\n", scrubval);
return -1;
}
return scrubrates[i].bandwidth;
*bw = scrubrates[i].bandwidth;
return 0;
}
/* Return 1 if dual channel mode is active. Else return 0. */

View File

@ -68,9 +68,10 @@
#define EDAC_PCI "PCI"
#define EDAC_DEBUG "DEBUG"
extern const char *edac_mem_types[];
#ifdef CONFIG_EDAC_DEBUG
extern int edac_debug_level;
extern const char *edac_mem_types[];
#define edac_debug_printk(level, fmt, arg...) \
do { \
@ -386,7 +387,7 @@ struct mem_ctl_info {
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 */

View File

@ -76,6 +76,8 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci)
debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
}
#endif /* CONFIG_EDAC_DEBUG */
/*
* keep those in sync with the enum mem_type
*/
@ -100,8 +102,6 @@ const char *edac_mem_types[] = {
};
EXPORT_SYMBOL_GPL(edac_mem_types);
#endif /* CONFIG_EDAC_DEBUG */
/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
* Adjust 'ptr' so that its alignment is at least as stringent as what the
* compiler would provide for X and return the aligned result.

View File

@ -436,56 +436,55 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
return count;
}
/* memory scrubbing */
/* Memory scrubbing interface:
*
* A MC driver can limit the scrubbing bandwidth based on the CPU type.
* Therefore, ->set_sdram_scrub_rate should be made to return the actual
* bandwidth that is accepted or 0 when scrubbing is to be disabled.
*
* Negative value still means that an error has occurred while setting
* the scrub rate.
*/
static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
const char *data, size_t count)
{
unsigned long bandwidth = 0;
int err;
int new_bw = 0;
if (!mci->set_sdram_scrub_rate) {
edac_printk(KERN_WARNING, EDAC_MC,
"Memory scrub rate setting not implemented!\n");
if (!mci->set_sdram_scrub_rate)
return -EINVAL;
}
if (strict_strtoul(data, 10, &bandwidth) < 0)
return -EINVAL;
err = mci->set_sdram_scrub_rate(mci, (u32)bandwidth);
if (err) {
edac_printk(KERN_DEBUG, EDAC_MC,
"Failed setting scrub rate to %lu\n", bandwidth);
return -EINVAL;
}
else {
edac_printk(KERN_DEBUG, EDAC_MC,
"Scrub rate set to: %lu\n", bandwidth);
new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
if (new_bw >= 0) {
edac_printk(KERN_DEBUG, EDAC_MC, "Scrub rate set to %d\n", new_bw);
return count;
}
edac_printk(KERN_DEBUG, EDAC_MC, "Error setting scrub rate to: %lu\n", bandwidth);
return -EINVAL;
}
/*
* ->get_sdram_scrub_rate() return value semantics same as above.
*/
static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
{
u32 bandwidth = 0;
int err;
int bandwidth = 0;
if (!mci->get_sdram_scrub_rate) {
edac_printk(KERN_WARNING, EDAC_MC,
"Memory scrub rate reading not implemented\n");
if (!mci->get_sdram_scrub_rate)
return -EINVAL;
bandwidth = mci->get_sdram_scrub_rate(mci);
if (bandwidth < 0) {
edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
return bandwidth;
}
err = mci->get_sdram_scrub_rate(mci, &bandwidth);
if (err) {
edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
return err;
}
else {
edac_printk(KERN_DEBUG, EDAC_MC,
"Read scrub rate: %d\n", bandwidth);
return sprintf(data, "%d\n", bandwidth);
}
edac_printk(KERN_DEBUG, EDAC_MC, "Read scrub rate: %d\n", bandwidth);
return sprintf(data, "%d\n", bandwidth);
}
/* default attribute files for the MCI object */

View File

@ -611,20 +611,17 @@ static int i5100_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
bandwidth = 5900000 * i5100_mc_scrben(dw);
return 0;
return bandwidth;
}
static int i5100_get_scrub_rate(struct mem_ctl_info *mci,
u32 *bandwidth)
static int i5100_get_scrub_rate(struct mem_ctl_info *mci)
{
struct i5100_priv *priv = mci->pvt_info;
u32 dw;
pci_read_config_dword(priv->mc, I5100_MC, &dw);
*bandwidth = 5900000 * i5100_mc_scrben(dw);
return 0;
return 5900000 * i5100_mc_scrben(dw);
}
static struct pci_dev *pci_get_device_func(unsigned vendor,