e7xxx_edac.c

来自「linux 内核源代码」· C语言 代码 · 共 585 行 · 第 1/2 页

C
585
字号
/* * Intel e7xxx Memory Controller kernel module * (C) 2003 Linux Networx (http://lnxi.com) * This file may be distributed under the terms of the * GNU General Public License. * * See "enum e7xxx_chips" below for supported chipsets * * Written by Thayne Harbaugh * Based on work by Dan Hollis <goemon at anime dot net> and others. *	http://www.anime.net/~goemon/linux-ecc/ * * Contributors: *	Eric Biederman (Linux Networx) *	Tom Zimmerman (Linux Networx) *	Jim Garlick (Lawrence Livermore National Labs) *	Dave Peterson (Lawrence Livermore National Labs) *	That One Guy (Some other place) *	Wang Zhenyu (intel.com) * * $Id: edac_e7xxx.c,v 1.5.2.9 2005/10/05 00:43:44 dsp_llnl Exp $ * */#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/pci_ids.h>#include <linux/slab.h>#include <linux/edac.h>#include "edac_core.h"#define	E7XXX_REVISION " Ver: 2.0.2 " __DATE__#define	EDAC_MOD_STR	"e7xxx_edac"#define e7xxx_printk(level, fmt, arg...) \	edac_printk(level, "e7xxx", fmt, ##arg)#define e7xxx_mc_printk(mci, level, fmt, arg...) \	edac_mc_chipset_printk(mci, level, "e7xxx", fmt, ##arg)#ifndef PCI_DEVICE_ID_INTEL_7205_0#define PCI_DEVICE_ID_INTEL_7205_0	0x255d#endif				/* PCI_DEVICE_ID_INTEL_7205_0 */#ifndef PCI_DEVICE_ID_INTEL_7205_1_ERR#define PCI_DEVICE_ID_INTEL_7205_1_ERR	0x2551#endif				/* PCI_DEVICE_ID_INTEL_7205_1_ERR */#ifndef PCI_DEVICE_ID_INTEL_7500_0#define PCI_DEVICE_ID_INTEL_7500_0	0x2540#endif				/* PCI_DEVICE_ID_INTEL_7500_0 */#ifndef PCI_DEVICE_ID_INTEL_7500_1_ERR#define PCI_DEVICE_ID_INTEL_7500_1_ERR	0x2541#endif				/* PCI_DEVICE_ID_INTEL_7500_1_ERR */#ifndef PCI_DEVICE_ID_INTEL_7501_0#define PCI_DEVICE_ID_INTEL_7501_0	0x254c#endif				/* PCI_DEVICE_ID_INTEL_7501_0 */#ifndef PCI_DEVICE_ID_INTEL_7501_1_ERR#define PCI_DEVICE_ID_INTEL_7501_1_ERR	0x2541#endif				/* PCI_DEVICE_ID_INTEL_7501_1_ERR */#ifndef PCI_DEVICE_ID_INTEL_7505_0#define PCI_DEVICE_ID_INTEL_7505_0	0x2550#endif				/* PCI_DEVICE_ID_INTEL_7505_0 */#ifndef PCI_DEVICE_ID_INTEL_7505_1_ERR#define PCI_DEVICE_ID_INTEL_7505_1_ERR	0x2551#endif				/* PCI_DEVICE_ID_INTEL_7505_1_ERR */#define E7XXX_NR_CSROWS		8	/* number of csrows */#define E7XXX_NR_DIMMS		8	/* FIXME - is this correct? *//* E7XXX register addresses - device 0 function 0 */#define E7XXX_DRB		0x60	/* DRAM row boundary register (8b) */#define E7XXX_DRA		0x70	/* DRAM row attribute register (8b) */					/*					 * 31   Device width row 7 0=x8 1=x4					 * 27   Device width row 6					 * 23   Device width row 5					 * 19   Device width row 4					 * 15   Device width row 3					 * 11   Device width row 2					 *  7   Device width row 1					 *  3   Device width row 0					 */#define E7XXX_DRC		0x7C	/* DRAM controller mode reg (32b) */					/*					 * 22    Number channels 0=1,1=2					 * 19:18 DRB Granularity 32/64MB					 */#define E7XXX_TOLM		0xC4	/* DRAM top of low memory reg (16b) */#define E7XXX_REMAPBASE		0xC6	/* DRAM remap base address reg (16b) */#define E7XXX_REMAPLIMIT	0xC8	/* DRAM remap limit address reg (16b) *//* E7XXX register addresses - device 0 function 1 */#define E7XXX_DRAM_FERR		0x80	/* DRAM first error register (8b) */#define E7XXX_DRAM_NERR		0x82	/* DRAM next error register (8b) */#define E7XXX_DRAM_CELOG_ADD	0xA0	/* DRAM first correctable memory */					/*     error address register (32b) */					/*					 * 31:28 Reserved					 * 27:6  CE address (4k block 33:12)					 *  5:0  Reserved					 */#define E7XXX_DRAM_UELOG_ADD	0xB0	/* DRAM first uncorrectable memory */					/*     error address register (32b) */					/*					 * 31:28 Reserved					 * 27:6  CE address (4k block 33:12)					 *  5:0  Reserved					 */#define E7XXX_DRAM_CELOG_SYNDROME 0xD0	/* DRAM first correctable memory */					/*     error syndrome register (16b) */enum e7xxx_chips {	E7500 = 0,	E7501,	E7505,	E7205,};struct e7xxx_pvt {	struct pci_dev *bridge_ck;	u32 tolm;	u32 remapbase;	u32 remaplimit;	const struct e7xxx_dev_info *dev_info;};struct e7xxx_dev_info {	u16 err_dev;	const char *ctl_name;};struct e7xxx_error_info {	u8 dram_ferr;	u8 dram_nerr;	u32 dram_celog_add;	u16 dram_celog_syndrome;	u32 dram_uelog_add;};static struct edac_pci_ctl_info *e7xxx_pci;static const struct e7xxx_dev_info e7xxx_devs[] = {	[E7500] = {		.err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,		.ctl_name = "E7500"},	[E7501] = {		.err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,		.ctl_name = "E7501"},	[E7505] = {		.err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,		.ctl_name = "E7505"},	[E7205] = {		.err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,		.ctl_name = "E7205"},};/* FIXME - is this valid for both SECDED and S4ECD4ED? */static inline int e7xxx_find_channel(u16 syndrome){	debugf3("%s()\n", __func__);	if ((syndrome & 0xff00) == 0)		return 0;	if ((syndrome & 0x00ff) == 0)		return 1;	if ((syndrome & 0xf000) == 0 || (syndrome & 0x0f00) == 0)		return 0;	return 1;}static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,				unsigned long page){	u32 remap;	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;	debugf3("%s()\n", __func__);	if ((page < pvt->tolm) ||		((page >= 0x100000) && (page < pvt->remapbase)))		return page;	remap = (page - pvt->tolm) + pvt->remapbase;	if (remap < pvt->remaplimit)		return remap;	e7xxx_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);	return pvt->tolm - 1;}static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info){	u32 error_1b, page;	u16 syndrome;	int row;	int channel;	debugf3("%s()\n", __func__);	/* read the error address */	error_1b = info->dram_celog_add;	/* FIXME - should use PAGE_SHIFT */	page = error_1b >> 6;	/* convert the address to 4k page */	/* read the syndrome */	syndrome = info->dram_celog_syndrome;	/* FIXME - check for -1 */	row = edac_mc_find_csrow_by_page(mci, page);	/* convert syndrome to channel */	channel = e7xxx_find_channel(syndrome);	edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE");}static void process_ce_no_info(struct mem_ctl_info *mci){	debugf3("%s()\n", __func__);	edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");}static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info){	u32 error_2b, block_page;	int row;	debugf3("%s()\n", __func__);	/* read the error address */	error_2b = info->dram_uelog_add;	/* FIXME - should use PAGE_SHIFT */	block_page = error_2b >> 6;	/* convert to 4k address */	row = edac_mc_find_csrow_by_page(mci, block_page);	edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");}static void process_ue_no_info(struct mem_ctl_info *mci){	debugf3("%s()\n", __func__);	edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");}static void e7xxx_get_error_info(struct mem_ctl_info *mci,				 struct e7xxx_error_info *info){	struct e7xxx_pvt *pvt;	pvt = (struct e7xxx_pvt *)mci->pvt_info;	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, &info->dram_ferr);	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, &info->dram_nerr);	if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,				&info->dram_celog_add);		pci_read_config_word(pvt->bridge_ck,				E7XXX_DRAM_CELOG_SYNDROME,				&info->dram_celog_syndrome);	}	if ((info->dram_ferr & 2) || (info->dram_nerr & 2))		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD,				&info->dram_uelog_add);	if (info->dram_ferr & 3)		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);	if (info->dram_nerr & 3)		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);}static int e7xxx_process_error_info(struct mem_ctl_info *mci,				struct e7xxx_error_info *info,				int handle_errors){	int error_found;	error_found = 0;	/* decode and report errors */	if (info->dram_ferr & 1) {	/* check first error correctable */		error_found = 1;		if (handle_errors)			process_ce(mci, info);	}	if (info->dram_ferr & 2) {	/* check first error uncorrectable */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?