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