i82975x_edac.c

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

C
667
字号
/* * Intel 82975X Memory Controller kernel module * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com) * (C) 2007 jetzbroadband (http://jetzbroadband.com) * This file may be distributed under the terms of the * GNU General Public License. * * Written by Arvind R. *   Copied from i82875p_edac.c source: */#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/pci_ids.h>#include <linux/slab.h>#include "edac_core.h"#define I82975X_REVISION	" Ver: 1.0.0 " __DATE__#define EDAC_MOD_STR		"i82975x_edac"#define i82975x_printk(level, fmt, arg...) \	edac_printk(level, "i82975x", fmt, ##arg)#define i82975x_mc_printk(mci, level, fmt, arg...) \	edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg)#ifndef PCI_DEVICE_ID_INTEL_82975_0#define PCI_DEVICE_ID_INTEL_82975_0	0x277c#endif				/* PCI_DEVICE_ID_INTEL_82975_0 */#define I82975X_NR_CSROWS(nr_chans)		(8/(nr_chans))/* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */#define I82975X_EAP		0x58	/* Dram Error Address Pointer (32b)					 *					 * 31:7  128 byte cache-line address					 * 6:1   reserved					 * 0     0: CH0; 1: CH1					 */#define I82975X_DERRSYN		0x5c	/* Dram Error SYNdrome (8b)					 *					 *  7:0  DRAM ECC Syndrome					 */#define I82975X_DES		0x5d	/* Dram ERRor DeSTination (8b)					 * 0h:    Processor Memory Reads					 * 1h:7h  reserved					 * More - See Page 65 of Intel DocSheet.					 */#define I82975X_ERRSTS		0xc8	/* Error Status Register (16b)					 *					 * 15:12 reserved					 * 11    Thermal Sensor Event					 * 10    reserved					 *  9    non-DRAM lock error (ndlock)					 *  8    Refresh Timeout					 *  7:2  reserved					 *  1    ECC UE (multibit DRAM error)					 *  0    ECC CE (singlebit DRAM error)					 *//* Error Reporting is supported by 3 mechanisms:  1. DMI SERR generation  ( ERRCMD )  2. SMI DMI  generation  ( SMICMD )  3. SCI DMI  generation  ( SCICMD )NOTE: Only ONE of the three must be enabled*/#define I82975X_ERRCMD		0xca	/* Error Command (16b)					 *					 * 15:12 reserved					 * 11    Thermal Sensor Event					 * 10    reserved					 *  9    non-DRAM lock error (ndlock)					 *  8    Refresh Timeout					 *  7:2  reserved					 *  1    ECC UE (multibit DRAM error)					 *  0    ECC CE (singlebit DRAM error)					 */#define I82975X_SMICMD		0xcc	/* Error Command (16b)					 *					 * 15:2  reserved					 *  1    ECC UE (multibit DRAM error)					 *  0    ECC CE (singlebit DRAM error)					 */#define I82975X_SCICMD		0xce	/* Error Command (16b)					 *					 * 15:2  reserved					 *  1    ECC UE (multibit DRAM error)					 *  0    ECC CE (singlebit DRAM error)					 */#define I82975X_XEAP	0xfc	/* Extended Dram Error Address Pointer (8b)					 *					 * 7:1   reserved					 * 0     Bit32 of the Dram Error Address					 */#define I82975X_MCHBAR		0x44	/*					 *					 * 31:14 Base Addr of 16K memory-mapped					 *	configuration space					 * 13:1  reserverd					 *  0    mem-mapped config space enable					 *//* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) *//* Intel 82975x memory mapped register space */#define I82975X_DRB_SHIFT 25	/* fixed 32MiB grain */#define I82975X_DRB		0x100	/* DRAM Row Boundary (8b x 8)					 *					 * 7   set to 1 in highest DRB of					 *	channel if 4GB in ch.					 * 6:2 upper boundary of rank in					 *	32MB grains					 * 1:0 set to 0					 */#define I82975X_DRB_CH0R0		0x100#define I82975X_DRB_CH0R1		0x101#define I82975X_DRB_CH0R2		0x102#define I82975X_DRB_CH0R3		0x103#define I82975X_DRB_CH1R0		0x180#define I82975X_DRB_CH1R1		0x181#define I82975X_DRB_CH1R2		0x182#define I82975X_DRB_CH1R3		0x183#define I82975X_DRA		0x108	/* DRAM Row Attribute (4b x 8)					 *  defines the PAGE SIZE to be used					 *	for the rank					 *  7    reserved					 *  6:4  row attr of odd rank, i.e. 1					 *  3    reserved					 *  2:0  row attr of even rank, i.e. 0					 *					 * 000 = unpopulated					 * 001 = reserved					 * 010 = 4KiB					 * 011 = 8KiB					 * 100 = 16KiB					 * others = reserved					 */#define I82975X_DRA_CH0R01		0x108#define I82975X_DRA_CH0R23		0x109#define I82975X_DRA_CH1R01		0x188#define I82975X_DRA_CH1R23		0x189#define I82975X_BNKARC	0x10e /* Type of device in each rank - Bank Arch (16b)					 *					 * 15:8  reserved					 * 7:6  Rank 3 architecture					 * 5:4  Rank 2 architecture					 * 3:2  Rank 1 architecture					 * 1:0  Rank 0 architecture					 *					 * 00 => x16 devices; i.e 4 banks					 * 01 => x8  devices; i.e 8 banks					 */#define I82975X_C0BNKARC	0x10e#define I82975X_C1BNKARC	0x18e#define I82975X_DRC		0x120 /* DRAM Controller Mode0 (32b)					 *					 * 31:30 reserved					 * 29    init complete					 * 28:11 reserved, according to Intel					 *    22:21 number of channels					 *		00=1 01=2 in 82875					 *		seems to be ECC mode					 *		bits in 82975 in Asus					 *		P5W					 *	 19:18 Data Integ Mode					 *		00=none 01=ECC in 82875					 * 10:8  refresh mode					 *  7    reserved					 *  6:4  mode select					 *  3:2  reserved					 *  1:0  DRAM type 10=Second Revision					 *		DDR2 SDRAM					 *         00, 01, 11 reserved					 */#define I82975X_DRC_CH0M0		0x120#define I82975X_DRC_CH1M0		0x1A0#define I82975X_DRC_M1	0x124 /* DRAM Controller Mode1 (32b)					 * 31	0=Standard Address Map					 *	1=Enhanced Address Map					 * 30:0	reserved					 */#define I82975X_DRC_CH0M1		0x124#define I82975X_DRC_CH1M1		0x1A4enum i82975x_chips {	I82975X = 0,};struct i82975x_pvt {	void __iomem *mch_window;};struct i82975x_dev_info {	const char *ctl_name;};struct i82975x_error_info {	u16 errsts;	u32 eap;	u8 des;	u8 derrsyn;	u16 errsts2;	u8 chan;		/* the channel is bit 0 of EAP */	u8 xeap;		/* extended eap bit */};static const struct i82975x_dev_info i82975x_devs[] = {	[I82975X] = {		.ctl_name = "i82975x"	},};static struct pci_dev *mci_pdev;	/* init dev: in case that AGP code has					 * already registered driver					 */static int i82975x_registered = 1;static void i82975x_get_error_info(struct mem_ctl_info *mci,		struct i82975x_error_info *info){	struct pci_dev *pdev;	pdev = to_pci_dev(mci->dev);	/*	 * This is a mess because there is no atomic way to read all the	 * registers at once and the registers can transition from CE being	 * overwritten by UE.	 */	pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts);	pci_read_config_dword(pdev, I82975X_EAP, &info->eap);	pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);	pci_read_config_byte(pdev, I82975X_DES, &info->des);	pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn);	pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2);	pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003);	/*	 * If the error is the same then we can for both reads then	 * the first set of reads is valid.  If there is a change then	 * there is a CE no info and the second set of reads is valid	 * and should be UE info.	 */	if (!(info->errsts2 & 0x0003))		return;	if ((info->errsts ^ info->errsts2) & 0x0003) {		pci_read_config_dword(pdev, I82975X_EAP, &info->eap);		pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);		pci_read_config_byte(pdev, I82975X_DES, &info->des);		pci_read_config_byte(pdev, I82975X_DERRSYN,				&info->derrsyn);	}}static int i82975x_process_error_info(struct mem_ctl_info *mci,		struct i82975x_error_info *info, int handle_errors){	int row, multi_chan, chan;	multi_chan = mci->csrows[0].nr_channels - 1;	if (!(info->errsts2 & 0x0003))		return 0;	if (!handle_errors)		return 1;	if ((info->errsts ^ info->errsts2) & 0x0003) {		edac_mc_handle_ce_no_info(mci, "UE overwrote CE");		info->errsts = info->errsts2;	}	chan = info->eap & 1;	info->eap >>= 1;	if (info->xeap )		info->eap |= 0x80000000;	info->eap >>= PAGE_SHIFT;	row = edac_mc_find_csrow_by_page(mci, info->eap);	if (info->errsts & 0x0002)		edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE");	else		edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,				multi_chan ? chan : 0,				"i82975x CE");	return 1;}static void i82975x_check(struct mem_ctl_info *mci){	struct i82975x_error_info info;	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);	i82975x_get_error_info(mci, &info);	i82975x_process_error_info(mci, &info, 1);}/* Return 1 if dual channel mode is active.  Else return 0. */static int dual_channel_active(void __iomem *mch_window){	/*	 * We treat interleaved-symmetric configuration as dual-channel - EAP's	 * bit-0 giving the channel of the error location.	 *	 * All other configurations are treated as single channel - the EAP's	 * bit-0 will resolve ok in symmetric area of mixed	 * (symmetric/asymmetric) configurations	 */	u8	drb[4][2];	int	row;

⌨️ 快捷键说明

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