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 + -
显示快捷键?