mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-15 09:55:36 +00:00
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:
commit
442d1ba237
@ -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
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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. */
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user