aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-06-22 21:41:15 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-10 10:44:45 -0400
commita0c36a1f0fbab42590dab3c13c10fa7d20e6c2cd (patch)
tree1aba0a7bd6f50cf394e747d02c624f456a24fdb8
parent66f41d4c5c8a5deed66fdcc84509376c9a0bf9d8 (diff)
i7core_edac: Add an EDAC memory controller driver for Nehalem chipsets
This driver is meant to support i7 core/i7core extreme desktop processors and Xeon 35xx/55xx series with integrated memory controller. It is likely that it can be expanded in the future to work with other processor series based at the same Memory Controller design. For now, it has just a few MCH status reads. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/i7core_edac.c462
-rw-r--r--include/linux/pci_ids.h16
4 files changed, 486 insertions, 0 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 55c9c59b3f71..391ddbfb2a34 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -166,6 +166,13 @@ config EDAC_I5400
166 Support for error detection and correction the Intel 166 Support for error detection and correction the Intel
167 i5400 MCH chipset (Seaburg). 167 i5400 MCH chipset (Seaburg).
168 168
169config EDAC_I7CORE
170 tristate "Intel i7 Core (Nehalem) processors"
171 depends on EDAC_MM_EDAC && PCI && X86
172 help
173 Support for error detection and correction the Intel
174 i7 Core (Nehalem) Integrated Memory Controller
175
169config EDAC_I82860 176config EDAC_I82860
170 tristate "Intel 82860" 177 tristate "Intel 82860"
171 depends on EDAC_MM_EDAC && PCI && X86_32 178 depends on EDAC_MM_EDAC && PCI && X86_32
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index bc5dc232a0fb..b9996195b233 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
23obj-$(CONFIG_EDAC_I5000) += i5000_edac.o 23obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
24obj-$(CONFIG_EDAC_I5100) += i5100_edac.o 24obj-$(CONFIG_EDAC_I5100) += i5100_edac.o
25obj-$(CONFIG_EDAC_I5400) += i5400_edac.o 25obj-$(CONFIG_EDAC_I5400) += i5400_edac.o
26obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o
26obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o 27obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
27obj-$(CONFIG_EDAC_E752X) += e752x_edac.o 28obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
28obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o 29obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
new file mode 100644
index 000000000000..7ecf15e66a3f
--- /dev/null
+++ b/drivers/edac/i7core_edac.c
@@ -0,0 +1,462 @@
1/* Intel 7 core Memory Controller kernel module (Nehalem)
2 *
3 * This file may be distributed under the terms of the
4 * GNU General Public License version 2 only.
5 *
6 * Copyright (c) 2009 by:
7 * Mauro Carvalho Chehab <mchehab@redhat.com>
8 *
9 * Red Hat Inc. http://www.redhat.com
10 *
11 * Forked and adapted from the i5400_edac driver
12 *
13 * Based on the following public Intel datasheets:
14 * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor
15 * Datasheet, Volume 2:
16 * http://download.intel.com/design/processor/datashts/320835.pdf
17 * Intel Xeon Processor 5500 Series Datasheet Volume 2
18 * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
19 * also available at:
20 * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
21 */
22
23
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/pci.h>
27#include <linux/pci_ids.h>
28#include <linux/slab.h>
29#include <linux/edac.h>
30#include <linux/mmzone.h>
31
32#include "edac_core.h"
33
34
35/*
36 * Alter this version for the module when modifications are made
37 */
38#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
39#define EDAC_MOD_STR "i7core_edac"
40
41/* HACK: temporary, just to enable all logs, for now */
42#undef debugf0
43#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg)
44
45/*
46 * Debug macros
47 */
48#define i7core_printk(level, fmt, arg...) \
49 edac_printk(level, "i7core", fmt, ##arg)
50
51#define i7core_mc_printk(mci, level, fmt, arg...) \
52 edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
53
54/*
55 * i7core Memory Controller Registers
56 */
57
58 /* OFFSETS for Device 3 Function 0 */
59
60#define MC_CONTROL 0x48
61#define MC_STATUS 0x4c
62#define MC_MAX_DOD 0x64
63
64 /* OFFSETS for Devices 4,5 and 6 Function 0 */
65
66#define MC_CHANNEL_ADDR_MATCH 0xf0
67
68#define MC_MASK_DIMM (1 << 41)
69#define MC_MASK_RANK (1 << 40)
70#define MC_MASK_BANK (1 << 39)
71#define MC_MASK_PAGE (1 << 38)
72#define MC_MASK_COL (1 << 37)
73
74/*
75 * i7core structs
76 */
77
78#define NUM_CHANS 3
79#define NUM_FUNCS 1
80
81struct i7core_info {
82 u32 mc_control;
83 u32 mc_status;
84 u32 max_dod;
85};
86
87struct i7core_pvt {
88 struct pci_dev *pci_mcr; /* Dev 3:0 */
89 struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS];
90 struct i7core_info info;
91};
92
93/* Device name and register DID (Device ID) */
94struct i7core_dev_info {
95 const char *ctl_name; /* name for this device */
96 u16 fsb_mapping_errors; /* DID for the branchmap,control */
97};
98
99static int chan_pci_ids[NUM_CHANS] = {
100 PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */
101 PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */
102 PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */
103};
104
105/* Table of devices attributes supported by this driver */
106static const struct i7core_dev_info i7core_devs[] = {
107 {
108 .ctl_name = "i7 Core",
109 .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR,
110 },
111};
112
113static struct edac_pci_ctl_info *i7core_pci;
114
115/****************************************************************************
116 Anciliary status routines
117 ****************************************************************************/
118
119 /* MC_CONTROL bits */
120#define CH2_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 10)
121#define CH1_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 9)
122#define CH0_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 8)
123#define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1)
124
125 /* MC_STATUS bits */
126#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3)
127#define CH2_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 2)
128#define CH1_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 1)
129#define CH0_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 0)
130
131 /* MC_MAX_DOD read functions */
132static inline int maxnumdimms(struct i7core_pvt *pvt)
133{
134 return (pvt->info.max_dod & 0x3) + 1;
135}
136
137static inline int maxnumrank(struct i7core_pvt *pvt)
138{
139 static int ranks[4] = { 1, 2, 4, -EINVAL };
140
141 return ranks[(pvt->info.max_dod >> 2) & 0x3];
142}
143
144static inline int maxnumbank(struct i7core_pvt *pvt)
145{
146 static int banks[4] = { 4, 8, 16, -EINVAL };
147
148 return banks[(pvt->info.max_dod >> 4) & 0x3];
149}
150
151static inline int maxnumrow(struct i7core_pvt *pvt)
152{
153 static int rows[8] = {
154 1 << 12, 1 << 13, 1 << 14, 1 << 15,
155 1 << 16, -EINVAL, -EINVAL, -EINVAL,
156 };
157
158 return rows[((pvt->info.max_dod >> 6) & 0x7)];
159}
160
161static inline int maxnumcol(struct i7core_pvt *pvt)