i5000_edac.c

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

C
1,506
字号
/* * Intel 5000(P/V/X) class Memory Controllers kernel module * * This file may be distributed under the terms of the * GNU General Public License. * * Written by Douglas Thompson Linux Networx (http://lnxi.com) *	norsk5@xmission.com * * This module is based on the following document: * * Intel 5000X Chipset Memory Controller Hub (MCH) - Datasheet * 	http://developer.intel.com/design/chipsets/datashts/313070.htm * */#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 <asm/mmzone.h>#include "edac_core.h"/* * Alter this version for the I5000 module when modifications are made */#define I5000_REVISION    " Ver: 2.0.12 " __DATE__#define EDAC_MOD_STR      "i5000_edac"#define i5000_printk(level, fmt, arg...) \        edac_printk(level, "i5000", fmt, ##arg)#define i5000_mc_printk(mci, level, fmt, arg...) \        edac_mc_chipset_printk(mci, level, "i5000", fmt, ##arg)#ifndef PCI_DEVICE_ID_INTEL_FBD_0#define PCI_DEVICE_ID_INTEL_FBD_0	0x25F5#endif#ifndef PCI_DEVICE_ID_INTEL_FBD_1#define PCI_DEVICE_ID_INTEL_FBD_1	0x25F6#endif/* Device 16, * Function 0: System Address * Function 1: Memory Branch Map, Control, Errors Register * Function 2: FSB Error Registers * * All 3 functions of Device 16 (0,1,2) share the SAME DID */#define	PCI_DEVICE_ID_INTEL_I5000_DEV16	0x25F0/* OFFSETS for Function 0 *//* OFFSETS for Function 1 */#define		AMBASE			0x48#define		MAXCH			0x56#define		MAXDIMMPERCH		0x57#define		TOLM			0x6C#define		REDMEMB			0x7C#define			RED_ECC_LOCATOR(x)	((x) & 0x3FFFF)#define			REC_ECC_LOCATOR_EVEN(x)	((x) & 0x001FF)#define			REC_ECC_LOCATOR_ODD(x)	((x) & 0x3FE00)#define		MIR0			0x80#define		MIR1			0x84#define		MIR2			0x88#define		AMIR0			0x8C#define		AMIR1			0x90#define		AMIR2			0x94#define		FERR_FAT_FBD		0x98#define		NERR_FAT_FBD		0x9C#define			EXTRACT_FBDCHAN_INDX(x)	(((x)>>28) & 0x3)#define			FERR_FAT_FBDCHAN 0x30000000#define			FERR_FAT_M3ERR	0x00000004#define			FERR_FAT_M2ERR	0x00000002#define			FERR_FAT_M1ERR	0x00000001#define			FERR_FAT_MASK	(FERR_FAT_M1ERR | \						FERR_FAT_M2ERR | \						FERR_FAT_M3ERR)#define		FERR_NF_FBD		0xA0/* Thermal and SPD or BFD errors */#define			FERR_NF_M28ERR	0x01000000#define			FERR_NF_M27ERR	0x00800000#define			FERR_NF_M26ERR	0x00400000#define			FERR_NF_M25ERR	0x00200000#define			FERR_NF_M24ERR	0x00100000#define			FERR_NF_M23ERR	0x00080000#define			FERR_NF_M22ERR	0x00040000#define			FERR_NF_M21ERR	0x00020000/* Correctable errors */#define			FERR_NF_M20ERR	0x00010000#define			FERR_NF_M19ERR	0x00008000#define			FERR_NF_M18ERR	0x00004000#define			FERR_NF_M17ERR	0x00002000/* Non-Retry or redundant Retry errors */#define			FERR_NF_M16ERR	0x00001000#define			FERR_NF_M15ERR	0x00000800#define			FERR_NF_M14ERR	0x00000400#define			FERR_NF_M13ERR	0x00000200/* Uncorrectable errors */#define			FERR_NF_M12ERR	0x00000100#define			FERR_NF_M11ERR	0x00000080#define			FERR_NF_M10ERR	0x00000040#define			FERR_NF_M9ERR	0x00000020#define			FERR_NF_M8ERR	0x00000010#define			FERR_NF_M7ERR	0x00000008#define			FERR_NF_M6ERR	0x00000004#define			FERR_NF_M5ERR	0x00000002#define			FERR_NF_M4ERR	0x00000001#define			FERR_NF_UNCORRECTABLE	(FERR_NF_M12ERR | \							FERR_NF_M11ERR | \							FERR_NF_M10ERR | \							FERR_NF_M8ERR | \							FERR_NF_M7ERR | \							FERR_NF_M6ERR | \							FERR_NF_M5ERR | \							FERR_NF_M4ERR)#define			FERR_NF_CORRECTABLE	(FERR_NF_M20ERR | \							FERR_NF_M19ERR | \							FERR_NF_M18ERR | \							FERR_NF_M17ERR)#define			FERR_NF_DIMM_SPARE	(FERR_NF_M27ERR | \							FERR_NF_M28ERR)#define			FERR_NF_THERMAL		(FERR_NF_M26ERR | \							FERR_NF_M25ERR | \							FERR_NF_M24ERR | \							FERR_NF_M23ERR)#define			FERR_NF_SPD_PROTOCOL	(FERR_NF_M22ERR)#define			FERR_NF_NORTH_CRC	(FERR_NF_M21ERR)#define			FERR_NF_NON_RETRY	(FERR_NF_M13ERR | \							FERR_NF_M14ERR | \							FERR_NF_M15ERR)#define		NERR_NF_FBD		0xA4#define			FERR_NF_MASK		(FERR_NF_UNCORRECTABLE | \							FERR_NF_CORRECTABLE | \							FERR_NF_DIMM_SPARE | \							FERR_NF_THERMAL | \							FERR_NF_SPD_PROTOCOL | \							FERR_NF_NORTH_CRC | \							FERR_NF_NON_RETRY)#define		EMASK_FBD		0xA8#define			EMASK_FBD_M28ERR	0x08000000#define			EMASK_FBD_M27ERR	0x04000000#define			EMASK_FBD_M26ERR	0x02000000#define			EMASK_FBD_M25ERR	0x01000000#define			EMASK_FBD_M24ERR	0x00800000#define			EMASK_FBD_M23ERR	0x00400000#define			EMASK_FBD_M22ERR	0x00200000#define			EMASK_FBD_M21ERR	0x00100000#define			EMASK_FBD_M20ERR	0x00080000#define			EMASK_FBD_M19ERR	0x00040000#define			EMASK_FBD_M18ERR	0x00020000#define			EMASK_FBD_M17ERR	0x00010000#define			EMASK_FBD_M15ERR	0x00004000#define			EMASK_FBD_M14ERR	0x00002000#define			EMASK_FBD_M13ERR	0x00001000#define			EMASK_FBD_M12ERR	0x00000800#define			EMASK_FBD_M11ERR	0x00000400#define			EMASK_FBD_M10ERR	0x00000200#define			EMASK_FBD_M9ERR		0x00000100#define			EMASK_FBD_M8ERR		0x00000080#define			EMASK_FBD_M7ERR		0x00000040#define			EMASK_FBD_M6ERR		0x00000020#define			EMASK_FBD_M5ERR		0x00000010#define			EMASK_FBD_M4ERR		0x00000008#define			EMASK_FBD_M3ERR		0x00000004#define			EMASK_FBD_M2ERR		0x00000002#define			EMASK_FBD_M1ERR		0x00000001#define			ENABLE_EMASK_FBD_FATAL_ERRORS	(EMASK_FBD_M1ERR | \							EMASK_FBD_M2ERR | \							EMASK_FBD_M3ERR)#define 		ENABLE_EMASK_FBD_UNCORRECTABLE	(EMASK_FBD_M4ERR | \							EMASK_FBD_M5ERR | \							EMASK_FBD_M6ERR | \							EMASK_FBD_M7ERR | \							EMASK_FBD_M8ERR | \							EMASK_FBD_M9ERR | \							EMASK_FBD_M10ERR | \							EMASK_FBD_M11ERR | \							EMASK_FBD_M12ERR)#define 		ENABLE_EMASK_FBD_CORRECTABLE	(EMASK_FBD_M17ERR | \							EMASK_FBD_M18ERR | \							EMASK_FBD_M19ERR | \							EMASK_FBD_M20ERR)#define			ENABLE_EMASK_FBD_DIMM_SPARE	(EMASK_FBD_M27ERR | \							EMASK_FBD_M28ERR)#define			ENABLE_EMASK_FBD_THERMALS	(EMASK_FBD_M26ERR | \							EMASK_FBD_M25ERR | \							EMASK_FBD_M24ERR | \							EMASK_FBD_M23ERR)#define			ENABLE_EMASK_FBD_SPD_PROTOCOL	(EMASK_FBD_M22ERR)#define			ENABLE_EMASK_FBD_NORTH_CRC	(EMASK_FBD_M21ERR)#define			ENABLE_EMASK_FBD_NON_RETRY	(EMASK_FBD_M15ERR | \							EMASK_FBD_M14ERR | \							EMASK_FBD_M13ERR)#define		ENABLE_EMASK_ALL	(ENABLE_EMASK_FBD_NON_RETRY | \					ENABLE_EMASK_FBD_NORTH_CRC | \					ENABLE_EMASK_FBD_SPD_PROTOCOL | \					ENABLE_EMASK_FBD_THERMALS | \					ENABLE_EMASK_FBD_DIMM_SPARE | \					ENABLE_EMASK_FBD_FATAL_ERRORS | \					ENABLE_EMASK_FBD_CORRECTABLE | \					ENABLE_EMASK_FBD_UNCORRECTABLE)#define		ERR0_FBD		0xAC#define		ERR1_FBD		0xB0#define		ERR2_FBD		0xB4#define		MCERR_FBD		0xB8#define		NRECMEMA		0xBE#define			NREC_BANK(x)		(((x)>>12) & 0x7)#define			NREC_RDWR(x)		(((x)>>11) & 1)#define			NREC_RANK(x)		(((x)>>8) & 0x7)#define		NRECMEMB		0xC0#define			NREC_CAS(x)		(((x)>>16) & 0xFFFFFF)#define			NREC_RAS(x)		((x) & 0x7FFF)#define		NRECFGLOG		0xC4#define		NREEECFBDA		0xC8#define		NREEECFBDB		0xCC#define		NREEECFBDC		0xD0#define		NREEECFBDD		0xD4#define		NREEECFBDE		0xD8#define		REDMEMA			0xDC#define		RECMEMA			0xE2#define			REC_BANK(x)		(((x)>>12) & 0x7)#define			REC_RDWR(x)		(((x)>>11) & 1)#define			REC_RANK(x)		(((x)>>8) & 0x7)#define		RECMEMB			0xE4#define			REC_CAS(x)		(((x)>>16) & 0xFFFFFF)#define			REC_RAS(x)		((x) & 0x7FFF)#define		RECFGLOG		0xE8#define		RECFBDA			0xEC#define		RECFBDB			0xF0#define		RECFBDC			0xF4#define		RECFBDD			0xF8#define		RECFBDE			0xFC/* OFFSETS for Function 2 *//* * Device 21, * Function 0: Memory Map Branch 0 * * Device 22, * Function 0: Memory Map Branch 1 */#define PCI_DEVICE_ID_I5000_BRANCH_0	0x25F5#define PCI_DEVICE_ID_I5000_BRANCH_1	0x25F6#define AMB_PRESENT_0	0x64#define AMB_PRESENT_1	0x66#define MTR0		0x80#define MTR1		0x84#define MTR2		0x88#define MTR3		0x8C#define NUM_MTRS		4#define CHANNELS_PER_BRANCH	(2)/* Defines to extract the vaious fields from the *	MTRx - Memory Technology Registers */#define MTR_DIMMS_PRESENT(mtr)		((mtr) & (0x1 << 8))#define MTR_DRAM_WIDTH(mtr)		((((mtr) >> 6) & 0x1) ? 8 : 4)#define MTR_DRAM_BANKS(mtr)		((((mtr) >> 5) & 0x1) ? 8 : 4)#define MTR_DRAM_BANKS_ADDR_BITS(mtr)	((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2)#define MTR_DIMM_RANK(mtr)		(((mtr) >> 4) & 0x1)#define MTR_DIMM_RANK_ADDR_BITS(mtr)	(MTR_DIMM_RANK(mtr) ? 2 : 1)#define MTR_DIMM_ROWS(mtr)		(((mtr) >> 2) & 0x3)#define MTR_DIMM_ROWS_ADDR_BITS(mtr)	(MTR_DIMM_ROWS(mtr) + 13)#define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)#define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)#ifdef CONFIG_EDAC_DEBUGstatic char *numrow_toString[] = {	"8,192 - 13 rows",	"16,384 - 14 rows",	"32,768 - 15 rows",	"reserved"};static char *numcol_toString[] = {	"1,024 - 10 columns",	"2,048 - 11 columns",	"4,096 - 12 columns",	"reserved"};#endif/* Enumeration of supported devices */enum i5000_chips {	I5000P = 0,	I5000V = 1,		/* future */	I5000X = 2		/* future */};/* Device name and register DID (Device ID) */struct i5000_dev_info {	const char *ctl_name;	/* name for this device */	u16 fsb_mapping_errors;	/* DID for the branchmap,control */};/* Table of devices attributes supported by this driver */static const struct i5000_dev_info i5000_devs[] = {	[I5000P] = {		.ctl_name = "I5000",		.fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I5000_DEV16,	},};struct i5000_dimm_info {	int megabytes;		/* size, 0 means not present  */	int dual_rank;};#define	MAX_CHANNELS	6	/* max possible channels */#define MAX_CSROWS	(8*2)	/* max possible csrows per channel *//* driver private data structure */struct i5000_pvt {	struct pci_dev *system_address;	/* 16.0 */	struct pci_dev *branchmap_werrors;	/* 16.1 */	struct pci_dev *fsb_error_regs;	/* 16.2 */	struct pci_dev *branch_0;	/* 21.0 */	struct pci_dev *branch_1;	/* 22.0 */	u16 tolm;		/* top of low memory */	u64 ambase;		/* AMB BAR */	u16 mir0, mir1, mir2;	u16 b0_mtr[NUM_MTRS];	/* Memory Technlogy Reg */	u16 b0_ambpresent0;	/* Branch 0, Channel 0 */	u16 b0_ambpresent1;	/* Brnach 0, Channel 1 */	u16 b1_mtr[NUM_MTRS];	/* Memory Technlogy Reg */	u16 b1_ambpresent0;	/* Branch 1, Channel 8 */	u16 b1_ambpresent1;	/* Branch 1, Channel 1 */	/* DIMM infomation matrix, allocating architecture maximums */	struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];	/* Actual values for this controller */	int maxch;		/* Max channels */	int maxdimmperch;	/* Max DIMMs per channel */};/* I5000 MCH error information retrieved from Hardware */struct i5000_error_info {	/* These registers are always read from the MC */	u32 ferr_fat_fbd;	/* First Errors Fatal */	u32 nerr_fat_fbd;	/* Next Errors Fatal */	u32 ferr_nf_fbd;	/* First Errors Non-Fatal */	u32 nerr_nf_fbd;	/* Next Errors Non-Fatal */	/* These registers are input ONLY if there was a Recoverable  Error */	u32 redmemb;		/* Recoverable Mem Data Error log B */	u16 recmema;		/* Recoverable Mem Error log A */	u32 recmemb;		/* Recoverable Mem Error log B */	/* These registers are input ONLY if there was a	 * Non-Recoverable Error */	u16 nrecmema;		/* Non-Recoverable Mem log A */	u16 nrecmemb;		/* Non-Recoverable Mem log B */};static struct edac_pci_ctl_info *i5000_pci;/* *	i5000_get_error_info	Retrieve the hardware error information from *				the hardware and cache it in the 'info' *				structure */static void i5000_get_error_info(struct mem_ctl_info *mci,				 struct i5000_error_info *info){	struct i5000_pvt *pvt;	u32 value;	pvt = mci->pvt_info;	/* read in the 1st FATAL error register */	pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value);	/* Mask only the bits that the doc says are valid	 */	value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK);	/* If there is an error, then read in the */	/* NEXT FATAL error register and the Memory Error Log Register A */	if (value & FERR_FAT_MASK) {		info->ferr_fat_fbd = value;		/* harvest the various error data we need */		pci_read_config_dword(pvt->branchmap_werrors,				NERR_FAT_FBD, &info->nerr_fat_fbd);		pci_read_config_word(pvt->branchmap_werrors,				NRECMEMA, &info->nrecmema);		pci_read_config_word(pvt->branchmap_werrors,				NRECMEMB, &info->nrecmemb);		/* Clear the error bits, by writing them back */		pci_write_config_dword(pvt->branchmap_werrors,				FERR_FAT_FBD, value);	} else {		info->ferr_fat_fbd = 0;		info->nerr_fat_fbd = 0;		info->nrecmema = 0;		info->nrecmemb = 0;	}	/* read in the 1st NON-FATAL error register */	pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value);	/* If there is an error, then read in the 1st NON-FATAL error	 * register as well */	if (value & FERR_NF_MASK) {		info->ferr_nf_fbd = value;		/* harvest the various error data we need */		pci_read_config_dword(pvt->branchmap_werrors,				NERR_NF_FBD, &info->nerr_nf_fbd);		pci_read_config_word(pvt->branchmap_werrors,				RECMEMA, &info->recmema);		pci_read_config_dword(pvt->branchmap_werrors,				RECMEMB, &info->recmemb);		pci_read_config_dword(pvt->branchmap_werrors,				REDMEMB, &info->redmemb);		/* Clear the error bits, by writing them back */		pci_write_config_dword(pvt->branchmap_werrors,				FERR_NF_FBD, value);	} else {		info->ferr_nf_fbd = 0;		info->nerr_nf_fbd = 0;		info->recmema = 0;		info->recmemb = 0;		info->redmemb = 0;	}}/* * i5000_process_fatal_error_info(struct mem_ctl_info *mci, * 					struct i5000_error_info *info, * 					int handle_errors); * *	handle the Intel FATAL errors, if any */static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,					struct i5000_error_info *info,					int handle_errors){	char msg[EDAC_MC_LABEL_LEN + 1 + 90];	u32 allErrors;	int branch;	int channel;	int bank;	int rank;	int rdwr;	int ras, cas;	/* mask off the Error bits that are possible */	allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK);	if (!allErrors)		return;		/* if no error, return now */	/* ONLY ONE of the possible error bits will be set, as per the docs */	i5000_mc_printk(mci, KERN_ERR,			"FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",			allErrors);	branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);	channel = branch;	/* Use the NON-Recoverable macros to extract data */	bank = NREC_BANK(info->nrecmema);	rank = NREC_RANK(info->nrecmema);	rdwr = NREC_RDWR(info->nrecmema);	ras = NREC_RAS(info->nrecmemb);	cas = NREC_CAS(info->nrecmemb);	debugf0("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "		"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",		rank, channel, channel + 1, branch >> 1, bank,		rdwr ? "Write" : "Read", ras, cas);

⌨️ 快捷键说明

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