blob: 795fcd1eec1c88c49303f443b66f16fd16a7f500 [file] [log] [blame]
Alan Cox806c35f2006-01-18 17:44:08 -08001/*
2 * Intel e752x Memory Controller kernel module
3 * (C) 2004 Linux Networx (http://lnxi.com)
4 * This file may be distributed under the terms of the
5 * GNU General Public License.
6 *
7 * See "enum e752x_chips" below for supported chipsets
8 *
9 * Written by Tom Zimmerman
10 *
11 * Contributors:
12 * Thayne Harbaugh at realmsys.com (?)
13 * Wang Zhenyu at intel.com
14 * Dave Jiang at mvista.com
15 *
Alan Coxda9bb1d2006-01-18 17:44:13 -080016 * $Id: edac_e752x.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $
Alan Cox806c35f2006-01-18 17:44:08 -080017 *
18 */
19
Alan Cox806c35f2006-01-18 17:44:08 -080020#include <linux/module.h>
21#include <linux/init.h>
Alan Cox806c35f2006-01-18 17:44:08 -080022#include <linux/pci.h>
23#include <linux/pci_ids.h>
Alan Cox806c35f2006-01-18 17:44:08 -080024#include <linux/slab.h>
Dave Jiangc0d12172007-07-19 01:49:46 -070025#include <linux/edac.h>
Douglas Thompson20bcb7a2007-07-19 01:49:47 -070026#include "edac_core.h"
Alan Cox806c35f2006-01-18 17:44:08 -080027
Douglas Thompson20bcb7a2007-07-19 01:49:47 -070028#define E752X_REVISION " Ver: 2.0.2 " __DATE__
Doug Thompson929a40e2006-07-01 04:35:45 -070029#define EDAC_MOD_STR "e752x_edac"
Doug Thompson37f04582006-06-30 01:56:07 -070030
Doug Thompson10d33e92008-07-25 01:49:12 -070031static int report_non_memory_errors;
mark gross96941022006-05-03 19:55:07 -070032static int force_function_unhide;
Peter Tyser94ee1cf2008-04-29 01:03:15 -070033static int sysbus_parity = -1;
mark gross96941022006-05-03 19:55:07 -070034
Dave Jiang91b99042007-07-19 01:49:52 -070035static struct edac_pci_ctl_info *e752x_pci;
36
Dave Peterson537fba22006-03-26 01:38:40 -080037#define e752x_printk(level, fmt, arg...) \
Dave Petersone7ecd892006-03-26 01:38:52 -080038 edac_printk(level, "e752x", fmt, ##arg)
Dave Peterson537fba22006-03-26 01:38:40 -080039
40#define e752x_mc_printk(mci, level, fmt, arg...) \
Dave Petersone7ecd892006-03-26 01:38:52 -080041 edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg)
Dave Peterson537fba22006-03-26 01:38:40 -080042
Alan Cox806c35f2006-01-18 17:44:08 -080043#ifndef PCI_DEVICE_ID_INTEL_7520_0
44#define PCI_DEVICE_ID_INTEL_7520_0 0x3590
45#endif /* PCI_DEVICE_ID_INTEL_7520_0 */
46
47#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR
48#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591
49#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */
50
51#ifndef PCI_DEVICE_ID_INTEL_7525_0
52#define PCI_DEVICE_ID_INTEL_7525_0 0x359E
53#endif /* PCI_DEVICE_ID_INTEL_7525_0 */
54
55#ifndef PCI_DEVICE_ID_INTEL_7525_1_ERR
56#define PCI_DEVICE_ID_INTEL_7525_1_ERR 0x3593
57#endif /* PCI_DEVICE_ID_INTEL_7525_1_ERR */
58
59#ifndef PCI_DEVICE_ID_INTEL_7320_0
60#define PCI_DEVICE_ID_INTEL_7320_0 0x3592
61#endif /* PCI_DEVICE_ID_INTEL_7320_0 */
62
63#ifndef PCI_DEVICE_ID_INTEL_7320_1_ERR
64#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593
65#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */
66
Andrei Konovalov5135b792008-04-29 01:03:13 -070067#ifndef PCI_DEVICE_ID_INTEL_3100_0
68#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0
69#endif /* PCI_DEVICE_ID_INTEL_3100_0 */
70
71#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR
72#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1
73#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */
74
Alan Cox806c35f2006-01-18 17:44:08 -080075#define E752X_NR_CSROWS 8 /* number of csrows */
76
Alan Cox806c35f2006-01-18 17:44:08 -080077/* E752X register addresses - device 0 function 0 */
78#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */
79#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */
80 /*
81 * 31:30 Device width row 7
82 * 01=x8 10=x4 11=x8 DDR2
83 * 27:26 Device width row 6
84 * 23:22 Device width row 5
85 * 19:20 Device width row 4
86 * 15:14 Device width row 3
87 * 11:10 Device width row 2
88 * 7:6 Device width row 1
89 * 3:2 Device width row 0
90 */
91#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */
92 /* FIXME:IS THIS RIGHT? */
93 /*
94 * 22 Number channels 0=1,1=2
95 * 19:18 DRB Granularity 32/64MB
96 */
97#define E752X_DRM 0x80 /* Dimm mapping register */
98#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */
99 /*
100 * 14:12 1 single A, 2 single B, 3 dual
101 */
102#define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */
103#define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */
104#define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */
105#define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */
106
107/* E752X register addresses - device 0 function 1 */
108#define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b) */
109#define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */
110#define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b) */
111#define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b) */
112#define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b) */
113#define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b) */
114#define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b) */
115#define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b) */
116#define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */
117#define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */
118#define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b) */
119#define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b) */
120#define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b) */
Doug Thompson10d33e92008-07-25 01:49:12 -0700121#define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI cmd reg (8b) */
Alan Cox806c35f2006-01-18 17:44:08 -0800122#define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */
123#define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */
124#define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */
125#define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */
126#define E752X_DRAM_RETR_ADD 0xAC /* DRAM Retry address register (32b) */
127#define E752X_DRAM_SEC1_ADD 0xA0 /* DRAM first correctable memory */
128 /* error address register (32b) */
129 /*
130 * 31 Reserved
Doug Thompson10d33e92008-07-25 01:49:12 -0700131 * 30:2 CE address (64 byte block 34:6
Alan Cox806c35f2006-01-18 17:44:08 -0800132 * 1 Reserved
133 * 0 HiLoCS
134 */
135#define E752X_DRAM_SEC2_ADD 0xC8 /* DRAM first correctable memory */
136 /* error address register (32b) */
137 /*
138 * 31 Reserved
139 * 30:2 CE address (64 byte block 34:6)
140 * 1 Reserved
141 * 0 HiLoCS
142 */
143#define E752X_DRAM_DED_ADD 0xA4 /* DRAM first uncorrectable memory */
144 /* error address register (32b) */
145 /*
146 * 31 Reserved
147 * 30:2 CE address (64 byte block 34:6)
148 * 1 Reserved
149 * 0 HiLoCS
150 */
Doug Thompson10d33e92008-07-25 01:49:12 -0700151#define E752X_DRAM_SCRB_ADD 0xA8 /* DRAM 1st uncorrectable scrub mem */
Alan Cox806c35f2006-01-18 17:44:08 -0800152 /* error address register (32b) */
153 /*
154 * 31 Reserved
Doug Thompson10d33e92008-07-25 01:49:12 -0700155 * 30:2 CE address (64 byte block 34:6
Alan Cox806c35f2006-01-18 17:44:08 -0800156 * 1 Reserved
157 * 0 HiLoCS
158 */
159#define E752X_DRAM_SEC1_SYNDROME 0xC4 /* DRAM first correctable memory */
160 /* error syndrome register (16b) */
161#define E752X_DRAM_SEC2_SYNDROME 0xC6 /* DRAM second correctable memory */
162 /* error syndrome register (16b) */
163#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */
164
Andrei Konovalov5135b792008-04-29 01:03:13 -0700165/* 3100 IMCH specific register addresses - device 0 function 1 */
166#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */
167#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */
168#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */
169#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */
170
Alan Cox806c35f2006-01-18 17:44:08 -0800171/* ICH5R register addresses - device 30 function 0 */
172#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */
173#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */
174#define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */
175
176enum e752x_chips {
177 E7520 = 0,
178 E7525 = 1,
Andrei Konovalov5135b792008-04-29 01:03:13 -0700179 E7320 = 2,
180 I3100 = 3
Alan Cox806c35f2006-01-18 17:44:08 -0800181};
182
Alan Cox806c35f2006-01-18 17:44:08 -0800183struct e752x_pvt {
184 struct pci_dev *bridge_ck;
185 struct pci_dev *dev_d0f0;
186 struct pci_dev *dev_d0f1;
187 u32 tolm;
188 u32 remapbase;
189 u32 remaplimit;
190 int mc_symmetric;
191 u8 map[8];
192 int map_type;
193 const struct e752x_dev_info *dev_info;
194};
195
Alan Cox806c35f2006-01-18 17:44:08 -0800196struct e752x_dev_info {
197 u16 err_dev;
Dave Peterson3847bcc2006-03-26 01:38:42 -0800198 u16 ctl_dev;
Alan Cox806c35f2006-01-18 17:44:08 -0800199 const char *ctl_name;
200};
201
202struct e752x_error_info {
203 u32 ferr_global;
204 u32 nerr_global;
Andrei Konovalov5135b792008-04-29 01:03:13 -0700205 u32 nsi_ferr; /* 3100 only */
206 u32 nsi_nerr; /* 3100 only */
207 u8 hi_ferr; /* all but 3100 */
208 u8 hi_nerr; /* all but 3100 */
Alan Cox806c35f2006-01-18 17:44:08 -0800209 u16 sysbus_ferr;
210 u16 sysbus_nerr;
211 u8 buf_ferr;
212 u8 buf_nerr;
213 u16 dram_ferr;
214 u16 dram_nerr;
215 u32 dram_sec1_add;
216 u32 dram_sec2_add;
217 u16 dram_sec1_syndrome;
218 u16 dram_sec2_syndrome;
219 u32 dram_ded_add;
220 u32 dram_scrb_add;
221 u32 dram_retr_add;
222};
223
224static const struct e752x_dev_info e752x_devs[] = {
225 [E7520] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -0700226 .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
227 .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
228 .ctl_name = "E7520"},
Alan Cox806c35f2006-01-18 17:44:08 -0800229 [E7525] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -0700230 .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
231 .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
232 .ctl_name = "E7525"},
Alan Cox806c35f2006-01-18 17:44:08 -0800233 [E7320] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -0700234 .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
235 .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
236 .ctl_name = "E7320"},
Andrei Konovalov5135b792008-04-29 01:03:13 -0700237 [I3100] = {
238 .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR,
239 .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0,
240 .ctl_name = "3100"},
Alan Cox806c35f2006-01-18 17:44:08 -0800241};
242
Alan Cox806c35f2006-01-18 17:44:08 -0800243static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700244 unsigned long page)
Alan Cox806c35f2006-01-18 17:44:08 -0800245{
246 u32 remap;
Dave Jiang203333c2007-07-19 01:50:06 -0700247 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800248
Dave Peterson537fba22006-03-26 01:38:40 -0800249 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800250
251 if (page < pvt->tolm)
252 return page;
Dave Petersone7ecd892006-03-26 01:38:52 -0800253
Alan Cox806c35f2006-01-18 17:44:08 -0800254 if ((page >= 0x100000) && (page < pvt->remapbase))
255 return page;
Dave Petersone7ecd892006-03-26 01:38:52 -0800256
Alan Cox806c35f2006-01-18 17:44:08 -0800257 remap = (page - pvt->tolm) + pvt->remapbase;
Dave Petersone7ecd892006-03-26 01:38:52 -0800258
Alan Cox806c35f2006-01-18 17:44:08 -0800259 if (remap < pvt->remaplimit)
260 return remap;
Dave Petersone7ecd892006-03-26 01:38:52 -0800261
Dave Peterson537fba22006-03-26 01:38:40 -0800262 e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);
Alan Cox806c35f2006-01-18 17:44:08 -0800263 return pvt->tolm - 1;
264}
265
266static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700267 u32 sec1_add, u16 sec1_syndrome)
Alan Cox806c35f2006-01-18 17:44:08 -0800268{
269 u32 page;
270 int row;
271 int channel;
272 int i;
Dave Jiang203333c2007-07-19 01:50:06 -0700273 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800274
Dave Peterson537fba22006-03-26 01:38:40 -0800275 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800276
277 /* convert the addr to 4k page */
278 page = sec1_add >> (PAGE_SHIFT - 4);
279
280 /* FIXME - check for -1 */
281 if (pvt->mc_symmetric) {
282 /* chip select are bits 14 & 13 */
283 row = ((page >> 1) & 3);
Dave Peterson537fba22006-03-26 01:38:40 -0800284 e752x_printk(KERN_WARNING,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700285 "Test row %d Table %d %d %d %d %d %d %d %d\n", row,
286 pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
287 pvt->map[4], pvt->map[5], pvt->map[6],
288 pvt->map[7]);
Alan Cox806c35f2006-01-18 17:44:08 -0800289
290 /* test for channel remapping */
291 for (i = 0; i < 8; i++) {
292 if (pvt->map[i] == row)
293 break;
294 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800295
Dave Peterson537fba22006-03-26 01:38:40 -0800296 e752x_printk(KERN_WARNING, "Test computed row %d\n", i);
Dave Petersone7ecd892006-03-26 01:38:52 -0800297
Alan Cox806c35f2006-01-18 17:44:08 -0800298 if (i < 8)
299 row = i;
300 else
Dave Peterson537fba22006-03-26 01:38:40 -0800301 e752x_mc_printk(mci, KERN_WARNING,
Dave Jiang203333c2007-07-19 01:50:06 -0700302 "row %d not found in remap table\n",
303 row);
Alan Cox806c35f2006-01-18 17:44:08 -0800304 } else
305 row = edac_mc_find_csrow_by_page(mci, page);
Dave Petersone7ecd892006-03-26 01:38:52 -0800306
Alan Cox806c35f2006-01-18 17:44:08 -0800307 /* 0 = channel A, 1 = channel B */
308 channel = !(error_one & 1);
309
Mike Chan84db0032007-02-12 00:53:06 -0800310 /* e752x mc reads 34:6 of the DRAM linear address */
311 edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
Douglas Thompson052dfb42007-07-19 01:50:13 -0700312 sec1_syndrome, row, channel, "e752x CE");
Dave Petersone7ecd892006-03-26 01:38:52 -0800313}
Alan Cox806c35f2006-01-18 17:44:08 -0800314
315static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700316 u32 sec1_add, u16 sec1_syndrome, int *error_found,
317 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800318{
319 *error_found = 1;
320
321 if (handle_error)
322 do_process_ce(mci, error_one, sec1_add, sec1_syndrome);
323}
324
Dave Petersone7ecd892006-03-26 01:38:52 -0800325static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700326 u32 ded_add, u32 scrb_add)
Alan Cox806c35f2006-01-18 17:44:08 -0800327{
328 u32 error_2b, block_page;
329 int row;
Dave Jiang203333c2007-07-19 01:50:06 -0700330 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800331
Dave Peterson537fba22006-03-26 01:38:40 -0800332 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800333
334 if (error_one & 0x0202) {
335 error_2b = ded_add;
Dave Petersone7ecd892006-03-26 01:38:52 -0800336
Alan Cox806c35f2006-01-18 17:44:08 -0800337 /* convert to 4k address */
338 block_page = error_2b >> (PAGE_SHIFT - 4);
Dave Petersone7ecd892006-03-26 01:38:52 -0800339
Alan Cox806c35f2006-01-18 17:44:08 -0800340 row = pvt->mc_symmetric ?
Douglas Thompson052dfb42007-07-19 01:50:13 -0700341 /* chip select are bits 14 & 13 */
342 ((block_page >> 1) & 3) :
343 edac_mc_find_csrow_by_page(mci, block_page);
Dave Petersone7ecd892006-03-26 01:38:52 -0800344
Mike Chan84db0032007-02-12 00:53:06 -0800345 /* e752x mc reads 34:6 of the DRAM linear address */
346 edac_mc_handle_ue(mci, block_page,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700347 offset_in_page(error_2b << 4),
348 row, "e752x UE from Read");
Alan Cox806c35f2006-01-18 17:44:08 -0800349 }
350 if (error_one & 0x0404) {
351 error_2b = scrb_add;
Dave Petersone7ecd892006-03-26 01:38:52 -0800352
Alan Cox806c35f2006-01-18 17:44:08 -0800353 /* convert to 4k address */
354 block_page = error_2b >> (PAGE_SHIFT - 4);
Dave Petersone7ecd892006-03-26 01:38:52 -0800355
Alan Cox806c35f2006-01-18 17:44:08 -0800356 row = pvt->mc_symmetric ?
Douglas Thompson052dfb42007-07-19 01:50:13 -0700357 /* chip select are bits 14 & 13 */
358 ((block_page >> 1) & 3) :
359 edac_mc_find_csrow_by_page(mci, block_page);
Dave Petersone7ecd892006-03-26 01:38:52 -0800360
Mike Chan84db0032007-02-12 00:53:06 -0800361 /* e752x mc reads 34:6 of the DRAM linear address */
362 edac_mc_handle_ue(mci, block_page,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700363 offset_in_page(error_2b << 4),
364 row, "e752x UE from Scruber");
Alan Cox806c35f2006-01-18 17:44:08 -0800365 }
366}
367
368static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700369 u32 ded_add, u32 scrb_add, int *error_found,
370 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800371{
372 *error_found = 1;
373
374 if (handle_error)
375 do_process_ue(mci, error_one, ded_add, scrb_add);
376}
377
378static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
Dave Jiang203333c2007-07-19 01:50:06 -0700379 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800380{
381 *error_found = 1;
382
383 if (!handle_error)
384 return;
385
Dave Peterson537fba22006-03-26 01:38:40 -0800386 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800387 edac_mc_handle_ue_no_info(mci, "e752x UE log memory write");
388}
389
390static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
Dave Jiang203333c2007-07-19 01:50:06 -0700391 u32 retry_add)
Alan Cox806c35f2006-01-18 17:44:08 -0800392{
393 u32 error_1b, page;
394 int row;
Dave Jiang203333c2007-07-19 01:50:06 -0700395 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800396
397 error_1b = retry_add;
Doug Thompson10d33e92008-07-25 01:49:12 -0700398 page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
399
400 /* chip select are bits 14 & 13 */
401 row = pvt->mc_symmetric ? ((page >> 1) & 3) :
Douglas Thompson052dfb42007-07-19 01:50:13 -0700402 edac_mc_find_csrow_by_page(mci, page);
Doug Thompson10d33e92008-07-25 01:49:12 -0700403
Dave Peterson537fba22006-03-26 01:38:40 -0800404 e752x_mc_printk(mci, KERN_WARNING,
Dave Jiang203333c2007-07-19 01:50:06 -0700405 "CE page 0x%lx, row %d : Memory read retry\n",
406 (long unsigned int)page, row);
Alan Cox806c35f2006-01-18 17:44:08 -0800407}
408
409static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700410 u32 retry_add, int *error_found,
411 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800412{
413 *error_found = 1;
414
415 if (handle_error)
416 do_process_ded_retry(mci, error, retry_add);
417}
418
419static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
Dave Jiang203333c2007-07-19 01:50:06 -0700420 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800421{
422 *error_found = 1;
423
424 if (handle_error)
Dave Peterson537fba22006-03-26 01:38:40 -0800425 e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n");
Alan Cox806c35f2006-01-18 17:44:08 -0800426}
427
Alan Coxda9bb1d2006-01-18 17:44:13 -0800428static char *global_message[11] = {
Doug Thompson10d33e92008-07-25 01:49:12 -0700429 "PCI Express C1",
430 "PCI Express C",
431 "PCI Express B1",
432 "PCI Express B",
433 "PCI Express A1",
434 "PCI Express A",
435 "DMA Controller",
436 "HUB or NS Interface",
437 "System Bus",
438 "DRAM Controller", /* 9th entry */
439 "Internal Buffer"
Alan Cox806c35f2006-01-18 17:44:08 -0800440};
441
Doug Thompson10d33e92008-07-25 01:49:12 -0700442#define DRAM_ENTRY 9
443
Alan Coxda9bb1d2006-01-18 17:44:13 -0800444static char *fatal_message[2] = { "Non-Fatal ", "Fatal " };
Alan Cox806c35f2006-01-18 17:44:08 -0800445
446static void do_global_error(int fatal, u32 errors)
447{
448 int i;
449
450 for (i = 0; i < 11; i++) {
Doug Thompson10d33e92008-07-25 01:49:12 -0700451 if (errors & (1 << i)) {
452 /* If the error is from DRAM Controller OR
453 * we are to report ALL errors, then
454 * report the error
455 */
456 if ((i == DRAM_ENTRY) || report_non_memory_errors)
457 e752x_printk(KERN_WARNING, "%sError %s\n",
458 fatal_message[fatal],
459 global_message[i]);
460 }
Alan Cox806c35f2006-01-18 17:44:08 -0800461 }
462}
463
464static inline void global_error(int fatal, u32 errors, int *error_found,
Dave Jiang203333c2007-07-19 01:50:06 -0700465 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800466{
467 *error_found = 1;
468
469 if (handle_error)
470 do_global_error(fatal, errors);
471}
472
Alan Coxda9bb1d2006-01-18 17:44:13 -0800473static char *hub_message[7] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800474 "HI Address or Command Parity", "HI Illegal Access",
475 "HI Internal Parity", "Out of Range Access",
476 "HI Data Parity", "Enhanced Config Access",
477 "Hub Interface Target Abort"
478};
479
480static void do_hub_error(int fatal, u8 errors)
481{
482 int i;
483
484 for (i = 0; i < 7; i++) {
485 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800486 e752x_printk(KERN_WARNING, "%sError %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700487 fatal_message[fatal], hub_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800488 }
489}
490
491static inline void hub_error(int fatal, u8 errors, int *error_found,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700492 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800493{
494 *error_found = 1;
495
496 if (handle_error)
497 do_hub_error(fatal, errors);
498}
499
Andrei Konovalov5135b792008-04-29 01:03:13 -0700500#define NSI_FATAL_MASK 0x0c080081
501#define NSI_NON_FATAL_MASK 0x23a0ba64
502#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK)
503
504static char *nsi_message[30] = {
505 "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */
506 "", /* reserved */
507 "NSI Parity Error", /* bit 2, non-fatal */
508 "", /* reserved */
509 "", /* reserved */
510 "Correctable Error Message", /* bit 5, non-fatal */
511 "Non-Fatal Error Message", /* bit 6, non-fatal */
512 "Fatal Error Message", /* bit 7, fatal */
513 "", /* reserved */
514 "Receiver Error", /* bit 9, non-fatal */
515 "", /* reserved */
516 "Bad TLP", /* bit 11, non-fatal */
517 "Bad DLLP", /* bit 12, non-fatal */
518 "REPLAY_NUM Rollover", /* bit 13, non-fatal */
519 "", /* reserved */
520 "Replay Timer Timeout", /* bit 15, non-fatal */
521 "", /* reserved */
522 "", /* reserved */
523 "", /* reserved */
524 "Data Link Protocol Error", /* bit 19, fatal */
525 "", /* reserved */
526 "Poisoned TLP", /* bit 21, non-fatal */
527 "", /* reserved */
528 "Completion Timeout", /* bit 23, non-fatal */
529 "Completer Abort", /* bit 24, non-fatal */
530 "Unexpected Completion", /* bit 25, non-fatal */
531 "Receiver Overflow", /* bit 26, fatal */
532 "Malformed TLP", /* bit 27, fatal */
533 "", /* reserved */
534 "Unsupported Request" /* bit 29, non-fatal */
535};
536
537static void do_nsi_error(int fatal, u32 errors)
538{
539 int i;
540
541 for (i = 0; i < 30; i++) {
542 if (errors & (1 << i))
543 printk(KERN_WARNING "%sError %s\n",
544 fatal_message[fatal], nsi_message[i]);
545 }
546}
547
548static inline void nsi_error(int fatal, u32 errors, int *error_found,
549 int handle_error)
550{
551 *error_found = 1;
552
553 if (handle_error)
554 do_nsi_error(fatal, errors);
555}
556
Alan Coxda9bb1d2006-01-18 17:44:13 -0800557static char *membuf_message[4] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800558 "Internal PMWB to DRAM parity",
559 "Internal PMWB to System Bus Parity",
560 "Internal System Bus or IO to PMWB Parity",
561 "Internal DRAM to PMWB Parity"
562};
563
564static void do_membuf_error(u8 errors)
565{
566 int i;
567
568 for (i = 0; i < 4; i++) {
569 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800570 e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700571 membuf_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800572 }
573}
574
575static inline void membuf_error(u8 errors, int *error_found, int handle_error)
576{
577 *error_found = 1;
578
579 if (handle_error)
580 do_membuf_error(errors);
581}
582
Dave Petersone0093562006-03-26 01:38:54 -0800583static char *sysbus_message[10] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800584 "Addr or Request Parity",
585 "Data Strobe Glitch",
586 "Addr Strobe Glitch",
587 "Data Parity",
588 "Addr Above TOM",
589 "Non DRAM Lock Error",
590 "MCERR", "BINIT",
591 "Memory Parity",
592 "IO Subsystem Parity"
593};
594
595static void do_sysbus_error(int fatal, u32 errors)
596{
597 int i;
598
599 for (i = 0; i < 10; i++) {
600 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800601 e752x_printk(KERN_WARNING, "%sError System Bus %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700602 fatal_message[fatal], sysbus_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800603 }
604}
605
606static inline void sysbus_error(int fatal, u32 errors, int *error_found,
Dave Jiang203333c2007-07-19 01:50:06 -0700607 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800608{
609 *error_found = 1;
610
611 if (handle_error)
612 do_sysbus_error(fatal, errors);
613}
614
Dave Petersone7ecd892006-03-26 01:38:52 -0800615static void e752x_check_hub_interface(struct e752x_error_info *info,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700616 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800617{
618 u8 stat8;
619
620 //pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
Dave Petersone7ecd892006-03-26 01:38:52 -0800621
Alan Cox806c35f2006-01-18 17:44:08 -0800622 stat8 = info->hi_ferr;
Dave Petersone7ecd892006-03-26 01:38:52 -0800623
Dave Jiang203333c2007-07-19 01:50:06 -0700624 if (stat8 & 0x7f) { /* Error, so process */
Alan Cox806c35f2006-01-18 17:44:08 -0800625 stat8 &= 0x7f;
Dave Petersone7ecd892006-03-26 01:38:52 -0800626
Alan Cox806c35f2006-01-18 17:44:08 -0800627 if (stat8 & 0x2b)
628 hub_error(1, stat8 & 0x2b, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800629
Dave Jiang203333c2007-07-19 01:50:06 -0700630 if (stat8 & 0x54)
631 hub_error(0, stat8 & 0x54, error_found, handle_error);
632 }
633 //pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
634
635 stat8 = info->hi_nerr;
636
637 if (stat8 & 0x7f) { /* Error, so process */
638 stat8 &= 0x7f;
639
640 if (stat8 & 0x2b)
641 hub_error(1, stat8 & 0x2b, error_found, handle_error);
642
643 if (stat8 & 0x54)
Alan Cox806c35f2006-01-18 17:44:08 -0800644 hub_error(0, stat8 & 0x54, error_found, handle_error);
645 }
646}
647
Andrei Konovalov5135b792008-04-29 01:03:13 -0700648static void e752x_check_ns_interface(struct e752x_error_info *info,
649 int *error_found, int handle_error)
650{
651 u32 stat32;
652
653 stat32 = info->nsi_ferr;
654 if (stat32 & NSI_ERR_MASK) { /* Error, so process */
655 if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */
656 nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
657 handle_error);
658 if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */
659 nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
660 handle_error);
661 }
662 stat32 = info->nsi_nerr;
663 if (stat32 & NSI_ERR_MASK) {
664 if (stat32 & NSI_FATAL_MASK)
665 nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
666 handle_error);
667 if (stat32 & NSI_NON_FATAL_MASK)
668 nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
669 handle_error);
670 }
671}
672
Dave Petersone7ecd892006-03-26 01:38:52 -0800673static void e752x_check_sysbus(struct e752x_error_info *info,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700674 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800675{
676 u32 stat32, error32;
677
678 //pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
679 stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
680
681 if (stat32 == 0)
Dave Jiang203333c2007-07-19 01:50:06 -0700682 return; /* no errors */
Alan Cox806c35f2006-01-18 17:44:08 -0800683
684 error32 = (stat32 >> 16) & 0x3ff;
685 stat32 = stat32 & 0x3ff;
Dave Petersone7ecd892006-03-26 01:38:52 -0800686
Dave Jiang203333c2007-07-19 01:50:06 -0700687 if (stat32 & 0x087)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800688 sysbus_error(1, stat32 & 0x087, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800689
Dave Jiang203333c2007-07-19 01:50:06 -0700690 if (stat32 & 0x378)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800691 sysbus_error(0, stat32 & 0x378, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800692
Dave Jiang203333c2007-07-19 01:50:06 -0700693 if (error32 & 0x087)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800694 sysbus_error(1, error32 & 0x087, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800695
Dave Jiang203333c2007-07-19 01:50:06 -0700696 if (error32 & 0x378)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800697 sysbus_error(0, error32 & 0x378, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800698}
699
Dave Jiang203333c2007-07-19 01:50:06 -0700700static void e752x_check_membuf(struct e752x_error_info *info,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700701 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800702{
703 u8 stat8;
704
705 stat8 = info->buf_ferr;
Dave Petersone7ecd892006-03-26 01:38:52 -0800706
Dave Jiang203333c2007-07-19 01:50:06 -0700707 if (stat8 & 0x0f) { /* Error, so process */
Alan Cox806c35f2006-01-18 17:44:08 -0800708 stat8 &= 0x0f;
709 membuf_error(stat8, error_found, handle_error);
710 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800711
Alan Cox806c35f2006-01-18 17:44:08 -0800712 stat8 = info->buf_nerr;
Dave Petersone7ecd892006-03-26 01:38:52 -0800713
Dave Jiang203333c2007-07-19 01:50:06 -0700714 if (stat8 & 0x0f) { /* Error, so process */
Alan Cox806c35f2006-01-18 17:44:08 -0800715 stat8 &= 0x0f;
716 membuf_error(stat8, error_found, handle_error);
717 }
718}
719
Dave Jiang203333c2007-07-19 01:50:06 -0700720static void e752x_check_dram(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700721 struct e752x_error_info *info, int *error_found,
722 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800723{
724 u16 error_one, error_next;
725
726 error_one = info->dram_ferr;
727 error_next = info->dram_nerr;
728
729 /* decode and report errors */
Dave Jiang203333c2007-07-19 01:50:06 -0700730 if (error_one & 0x0101) /* check first error correctable */
Alan Cox806c35f2006-01-18 17:44:08 -0800731 process_ce(mci, error_one, info->dram_sec1_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700732 info->dram_sec1_syndrome, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800733
Dave Jiang203333c2007-07-19 01:50:06 -0700734 if (error_next & 0x0101) /* check next error correctable */
Alan Cox806c35f2006-01-18 17:44:08 -0800735 process_ce(mci, error_next, info->dram_sec2_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700736 info->dram_sec2_syndrome, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800737
Dave Jiang203333c2007-07-19 01:50:06 -0700738 if (error_one & 0x4040)
Alan Cox806c35f2006-01-18 17:44:08 -0800739 process_ue_no_info_wr(mci, error_found, handle_error);
740
Dave Jiang203333c2007-07-19 01:50:06 -0700741 if (error_next & 0x4040)
Alan Cox806c35f2006-01-18 17:44:08 -0800742 process_ue_no_info_wr(mci, error_found, handle_error);
743
Dave Jiang203333c2007-07-19 01:50:06 -0700744 if (error_one & 0x2020)
Alan Cox806c35f2006-01-18 17:44:08 -0800745 process_ded_retry(mci, error_one, info->dram_retr_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700746 error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800747
Dave Jiang203333c2007-07-19 01:50:06 -0700748 if (error_next & 0x2020)
Alan Cox806c35f2006-01-18 17:44:08 -0800749 process_ded_retry(mci, error_next, info->dram_retr_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700750 error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800751
Dave Jiang203333c2007-07-19 01:50:06 -0700752 if (error_one & 0x0808)
753 process_threshold_ce(mci, error_one, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800754
Dave Jiang203333c2007-07-19 01:50:06 -0700755 if (error_next & 0x0808)
Alan Cox806c35f2006-01-18 17:44:08 -0800756 process_threshold_ce(mci, error_next, error_found,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700757 handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800758
Dave Jiang203333c2007-07-19 01:50:06 -0700759 if (error_one & 0x0606)
Alan Cox806c35f2006-01-18 17:44:08 -0800760 process_ue(mci, error_one, info->dram_ded_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700761 info->dram_scrb_add, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800762
Dave Jiang203333c2007-07-19 01:50:06 -0700763 if (error_next & 0x0606)
Alan Cox806c35f2006-01-18 17:44:08 -0800764 process_ue(mci, error_next, info->dram_ded_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700765 info->dram_scrb_add, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800766}
767
Dave Jiang203333c2007-07-19 01:50:06 -0700768static void e752x_get_error_info(struct mem_ctl_info *mci,
769 struct e752x_error_info *info)
Alan Cox806c35f2006-01-18 17:44:08 -0800770{
771 struct pci_dev *dev;
772 struct e752x_pvt *pvt;
773
774 memset(info, 0, sizeof(*info));
Dave Jiang203333c2007-07-19 01:50:06 -0700775 pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800776 dev = pvt->dev_d0f1;
Alan Cox806c35f2006-01-18 17:44:08 -0800777 pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
778
779 if (info->ferr_global) {
Andrei Konovalov5135b792008-04-29 01:03:13 -0700780 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
781 pci_read_config_dword(dev, I3100_NSI_FERR,
782 &info->nsi_ferr);
783 info->hi_ferr = 0;
784 } else {
785 pci_read_config_byte(dev, E752X_HI_FERR,
786 &info->hi_ferr);
787 info->nsi_ferr = 0;
788 }
Alan Cox806c35f2006-01-18 17:44:08 -0800789 pci_read_config_word(dev, E752X_SYSBUS_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700790 &info->sysbus_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800791 pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
Dave Jiang203333c2007-07-19 01:50:06 -0700792 pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800793 pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700794 &info->dram_sec1_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800795 pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700796 &info->dram_sec1_syndrome);
Alan Cox806c35f2006-01-18 17:44:08 -0800797 pci_read_config_dword(dev, E752X_DRAM_DED_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700798 &info->dram_ded_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800799 pci_read_config_dword(dev, E752X_DRAM_SCRB_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700800 &info->dram_scrb_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800801 pci_read_config_dword(dev, E752X_DRAM_RETR_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700802 &info->dram_retr_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800803
Andrei Konovalov5135b792008-04-29 01:03:13 -0700804 /* ignore the reserved bits just in case */
Alan Cox806c35f2006-01-18 17:44:08 -0800805 if (info->hi_ferr & 0x7f)
806 pci_write_config_byte(dev, E752X_HI_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700807 info->hi_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800808
Andrei Konovalov5135b792008-04-29 01:03:13 -0700809 if (info->nsi_ferr & NSI_ERR_MASK)
810 pci_write_config_dword(dev, I3100_NSI_FERR,
811 info->nsi_ferr);
812
Alan Cox806c35f2006-01-18 17:44:08 -0800813 if (info->sysbus_ferr)
814 pci_write_config_word(dev, E752X_SYSBUS_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700815 info->sysbus_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800816
817 if (info->buf_ferr & 0x0f)
818 pci_write_config_byte(dev, E752X_BUF_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700819 info->buf_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800820
821 if (info->dram_ferr)
822 pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
Dave Jiang203333c2007-07-19 01:50:06 -0700823 info->dram_ferr, info->dram_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800824
825 pci_write_config_dword(dev, E752X_FERR_GLOBAL,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700826 info->ferr_global);
Alan Cox806c35f2006-01-18 17:44:08 -0800827 }
828
829 pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global);
830
831 if (info->nerr_global) {
Andrei Konovalov5135b792008-04-29 01:03:13 -0700832 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
833 pci_read_config_dword(dev, I3100_NSI_NERR,
834 &info->nsi_nerr);
835 info->hi_nerr = 0;
836 } else {
837 pci_read_config_byte(dev, E752X_HI_NERR,
838 &info->hi_nerr);
839 info->nsi_nerr = 0;
840 }
Alan Cox806c35f2006-01-18 17:44:08 -0800841 pci_read_config_word(dev, E752X_SYSBUS_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700842 &info->sysbus_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800843 pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
Dave Jiang203333c2007-07-19 01:50:06 -0700844 pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800845 pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700846 &info->dram_sec2_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800847 pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700848 &info->dram_sec2_syndrome);
Alan Cox806c35f2006-01-18 17:44:08 -0800849
850 if (info->hi_nerr & 0x7f)
851 pci_write_config_byte(dev, E752X_HI_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700852 info->hi_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800853
Andrei Konovalov5135b792008-04-29 01:03:13 -0700854 if (info->nsi_nerr & NSI_ERR_MASK)
855 pci_write_config_dword(dev, I3100_NSI_NERR,
856 info->nsi_nerr);
857
Alan Cox806c35f2006-01-18 17:44:08 -0800858 if (info->sysbus_nerr)
859 pci_write_config_word(dev, E752X_SYSBUS_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700860 info->sysbus_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800861
862 if (info->buf_nerr & 0x0f)
863 pci_write_config_byte(dev, E752X_BUF_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700864 info->buf_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800865
866 if (info->dram_nerr)
867 pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
Dave Jiang203333c2007-07-19 01:50:06 -0700868 info->dram_nerr, info->dram_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800869
870 pci_write_config_dword(dev, E752X_NERR_GLOBAL,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700871 info->nerr_global);
Alan Cox806c35f2006-01-18 17:44:08 -0800872 }
873}
874
Dave Jiang203333c2007-07-19 01:50:06 -0700875static int e752x_process_error_info(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700876 struct e752x_error_info *info,
877 int handle_errors)
Alan Cox806c35f2006-01-18 17:44:08 -0800878{
879 u32 error32, stat32;
880 int error_found;
881
882 error_found = 0;
883 error32 = (info->ferr_global >> 18) & 0x3ff;
884 stat32 = (info->ferr_global >> 4) & 0x7ff;
885
886 if (error32)
887 global_error(1, error32, &error_found, handle_errors);
888
889 if (stat32)
890 global_error(0, stat32, &error_found, handle_errors);
891
892 error32 = (info->nerr_global >> 18) & 0x3ff;
893 stat32 = (info->nerr_global >> 4) & 0x7ff;
894
895 if (error32)
896 global_error(1, error32, &error_found, handle_errors);
897
898 if (stat32)
899 global_error(0, stat32, &error_found, handle_errors);
900
901 e752x_check_hub_interface(info, &error_found, handle_errors);
Andrei Konovalov5135b792008-04-29 01:03:13 -0700902 e752x_check_ns_interface(info, &error_found, handle_errors);
Alan Cox806c35f2006-01-18 17:44:08 -0800903 e752x_check_sysbus(info, &error_found, handle_errors);
904 e752x_check_membuf(info, &error_found, handle_errors);
905 e752x_check_dram(mci, info, &error_found, handle_errors);
906 return error_found;
907}
908
909static void e752x_check(struct mem_ctl_info *mci)
910{
911 struct e752x_error_info info;
Dave Petersone7ecd892006-03-26 01:38:52 -0800912
Dave Peterson537fba22006-03-26 01:38:40 -0800913 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800914 e752x_get_error_info(mci, &info);
915 e752x_process_error_info(mci, &info, 1);
916}
917
Doug Thompson13189522006-06-30 01:56:08 -0700918/* Return 1 if dual channel mode is active. Else return 0. */
919static inline int dual_channel_active(u16 ddrcsr)
Alan Cox806c35f2006-01-18 17:44:08 -0800920{
Doug Thompson13189522006-06-30 01:56:08 -0700921 return (((ddrcsr >> 12) & 3) == 3);
922}
923
Mark Grondona7297c262007-07-19 01:50:23 -0700924/* Remap csrow index numbers if map_type is "reverse"
925 */
926static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
927{
928 struct e752x_pvt *pvt = mci->pvt_info;
929
930 if (!pvt->map_type)
931 return (7 - index);
932
933 return (index);
934}
935
Doug Thompson13189522006-06-30 01:56:08 -0700936static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700937 u16 ddrcsr)
Doug Thompson13189522006-06-30 01:56:08 -0700938{
939 struct csrow_info *csrow;
Alan Cox806c35f2006-01-18 17:44:08 -0800940 unsigned long last_cumul_size;
Doug Thompson13189522006-06-30 01:56:08 -0700941 int index, mem_dev, drc_chan;
Dave Jiang203333c2007-07-19 01:50:06 -0700942 int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
943 int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
Doug Thompson13189522006-06-30 01:56:08 -0700944 u8 value;
945 u32 dra, drc, cumul_size;
Alan Cox806c35f2006-01-18 17:44:08 -0800946
Brian Pomerantz9962fd02007-02-12 00:53:05 -0800947 dra = 0;
Dave Jiang203333c2007-07-19 01:50:06 -0700948 for (index = 0; index < 4; index++) {
Brian Pomerantz9962fd02007-02-12 00:53:05 -0800949 u8 dra_reg;
Dave Jiang203333c2007-07-19 01:50:06 -0700950 pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
Brian Pomerantz9962fd02007-02-12 00:53:05 -0800951 dra |= dra_reg << (index * 8);
952 }
Alan Cox806c35f2006-01-18 17:44:08 -0800953 pci_read_config_dword(pdev, E752X_DRC, &drc);
Doug Thompson13189522006-06-30 01:56:08 -0700954 drc_chan = dual_channel_active(ddrcsr);
Dave Jiang203333c2007-07-19 01:50:06 -0700955 drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
Alan Cox806c35f2006-01-18 17:44:08 -0800956 drc_ddim = (drc >> 20) & 0x3;
957
Doug Thompson13189522006-06-30 01:56:08 -0700958 /* The dram row boundary (DRB) reg values are boundary address for
Alan Cox806c35f2006-01-18 17:44:08 -0800959 * each DRAM row with a granularity of 64 or 128MB (single/dual
960 * channel operation). DRB regs are cumulative; therefore DRB7 will
961 * contain the total memory contained in all eight rows.
962 */
963 for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
Alan Cox806c35f2006-01-18 17:44:08 -0800964 /* mem_dev 0=x8, 1=x4 */
Doug Thompson13189522006-06-30 01:56:08 -0700965 mem_dev = (dra >> (index * 4 + 2)) & 0x3;
Mark Grondona7297c262007-07-19 01:50:23 -0700966 csrow = &mci->csrows[remap_csrow_index(mci, index)];
Alan Cox806c35f2006-01-18 17:44:08 -0800967
968 mem_dev = (mem_dev == 2);
Doug Thompson37f04582006-06-30 01:56:07 -0700969 pci_read_config_byte(pdev, E752X_DRB + index, &value);
Alan Cox806c35f2006-01-18 17:44:08 -0800970 /* convert a 128 or 64 MiB DRB to a page size. */
971 cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
Dave Peterson537fba22006-03-26 01:38:40 -0800972 debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
973 cumul_size);
Alan Cox806c35f2006-01-18 17:44:08 -0800974 if (cumul_size == last_cumul_size)
Doug Thompson13189522006-06-30 01:56:08 -0700975 continue; /* not populated */
Alan Cox806c35f2006-01-18 17:44:08 -0800976
977 csrow->first_page = last_cumul_size;
978 csrow->last_page = cumul_size - 1;
979 csrow->nr_pages = cumul_size - last_cumul_size;
980 last_cumul_size = cumul_size;
Doug Thompson13189522006-06-30 01:56:08 -0700981 csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
982 csrow->mtype = MEM_RDDR; /* only one type supported */
Alan Cox806c35f2006-01-18 17:44:08 -0800983 csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
984
985 /*
986 * if single channel or x8 devices then SECDED
987 * if dual channel and x4 then S4ECD4ED
988 */
989 if (drc_ddim) {
990 if (drc_chan && mem_dev) {
991 csrow->edac_mode = EDAC_S4ECD4ED;
992 mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
993 } else {
994 csrow->edac_mode = EDAC_SECDED;
995 mci->edac_cap |= EDAC_FLAG_SECDED;
996 }
997 } else
998 csrow->edac_mode = EDAC_NONE;
999 }
Doug Thompson13189522006-06-30 01:56:08 -07001000}
Alan Cox806c35f2006-01-18 17:44:08 -08001001
Doug Thompson13189522006-06-30 01:56:08 -07001002static void e752x_init_mem_map_table(struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001003 struct e752x_pvt *pvt)
Doug Thompson13189522006-06-30 01:56:08 -07001004{
1005 int index;
Mark Grondona7297c262007-07-19 01:50:23 -07001006 u8 value, last, row;
Alan Cox806c35f2006-01-18 17:44:08 -08001007
Doug Thompson13189522006-06-30 01:56:08 -07001008 last = 0;
1009 row = 0;
Dave Petersone7ecd892006-03-26 01:38:52 -08001010
Doug Thompson13189522006-06-30 01:56:08 -07001011 for (index = 0; index < 8; index += 2) {
1012 pci_read_config_byte(pdev, E752X_DRB + index, &value);
1013 /* test if there is a dimm in this slot */
1014 if (value == last) {
1015 /* no dimm in the slot, so flag it as empty */
1016 pvt->map[index] = 0xff;
1017 pvt->map[index + 1] = 0xff;
Dave Jiang203333c2007-07-19 01:50:06 -07001018 } else { /* there is a dimm in the slot */
Doug Thompson13189522006-06-30 01:56:08 -07001019 pvt->map[index] = row;
1020 row++;
1021 last = value;
1022 /* test the next value to see if the dimm is double
1023 * sided
1024 */
1025 pci_read_config_byte(pdev, E752X_DRB + index + 1,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001026 &value);
1027
1028 /* the dimm is single sided, so flag as empty */
1029 /* this is a double sided dimm to save the next row #*/
1030 pvt->map[index + 1] = (value == last) ? 0xff : row;
Doug Thompson13189522006-06-30 01:56:08 -07001031 row++;
1032 last = value;
Alan Cox806c35f2006-01-18 17:44:08 -08001033 }
1034 }
Doug Thompson13189522006-06-30 01:56:08 -07001035}
1036
1037/* Return 0 on success or 1 on failure. */
1038static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001039 struct e752x_pvt *pvt)
Doug Thompson13189522006-06-30 01:56:08 -07001040{
1041 struct pci_dev *dev;
1042
1043 pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
Doug Thompson10d33e92008-07-25 01:49:12 -07001044 pvt->dev_info->err_dev, pvt->bridge_ck);
Doug Thompson13189522006-06-30 01:56:08 -07001045
1046 if (pvt->bridge_ck == NULL)
1047 pvt->bridge_ck = pci_scan_single_device(pdev->bus,
1048 PCI_DEVFN(0, 1));
1049
1050 if (pvt->bridge_ck == NULL) {
1051 e752x_printk(KERN_ERR, "error reporting device not found:"
Douglas Thompson052dfb42007-07-19 01:50:13 -07001052 "vendor %x device 0x%x (broken BIOS?)\n",
1053 PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
Doug Thompson13189522006-06-30 01:56:08 -07001054 return 1;
1055 }
1056
Doug Thompson10d33e92008-07-25 01:49:12 -07001057 dev = pci_get_device(PCI_VENDOR_ID_INTEL,
1058 e752x_devs[dev_idx].ctl_dev,
1059 NULL);
Doug Thompson13189522006-06-30 01:56:08 -07001060
1061 if (dev == NULL)
1062 goto fail;
1063
1064 pvt->dev_d0f0 = dev;
1065 pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
1066
1067 return 0;
1068
Douglas Thompson052dfb42007-07-19 01:50:13 -07001069fail:
Doug Thompson13189522006-06-30 01:56:08 -07001070 pci_dev_put(pvt->bridge_ck);
1071 return 1;
1072}
1073
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001074/* Setup system bus parity mask register.
1075 * Sysbus parity supported on:
Konstantin Olifer8de5c1a2010-03-10 15:23:14 -08001076 * e7320/e7520/e7525 + Xeon
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001077 */
1078static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
1079{
1080 char *cpu_id = cpu_data(0).x86_model_id;
1081 struct pci_dev *dev = pvt->dev_d0f1;
1082 int enable = 1;
1083
Martin Olsson98a17082009-04-22 18:21:29 +02001084 /* Allow module parameter override, else see if CPU supports parity */
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001085 if (sysbus_parity != -1) {
1086 enable = sysbus_parity;
Konstantin Olifer8de5c1a2010-03-10 15:23:14 -08001087 } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) {
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001088 e752x_printk(KERN_INFO, "System Bus Parity not "
1089 "supported by CPU, disabling\n");
1090 enable = 0;
1091 }
1092
1093 if (enable)
1094 pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000);
1095 else
1096 pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309);
1097}
1098
Doug Thompson13189522006-06-30 01:56:08 -07001099static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
1100{
1101 struct pci_dev *dev;
1102
1103 dev = pvt->dev_d0f1;
1104 /* Turn off error disable & SMI in case the BIOS turned it on */
Andrei Konovalov5135b792008-04-29 01:03:13 -07001105 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
1106 pci_write_config_dword(dev, I3100_NSI_EMASK, 0);
1107 pci_write_config_dword(dev, I3100_NSI_SMICMD, 0);
1108 } else {
1109 pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
1110 pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
1111 }
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001112
1113 e752x_init_sysbus_parity_mask(pvt);
1114
Doug Thompson13189522006-06-30 01:56:08 -07001115 pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
1116 pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
1117 pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
1118 pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
1119 pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
1120}
1121
1122static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
1123{
1124 u16 pci_data;
1125 u8 stat8;
1126 struct mem_ctl_info *mci;
1127 struct e752x_pvt *pvt;
1128 u16 ddrcsr;
Dave Jiang203333c2007-07-19 01:50:06 -07001129 int drc_chan; /* Number of channels 0=1chan,1=2chan */
Doug Thompson13189522006-06-30 01:56:08 -07001130 struct e752x_error_info discard;
1131
1132 debugf0("%s(): mci\n", __func__);
1133 debugf0("Starting Probe1\n");
1134
1135 /* check to see if device 0 function 1 is enabled; if it isn't, we
1136 * assume the BIOS has reserved it for a reason and is expecting
1137 * exclusive access, we take care not to violate that assumption and
1138 * fail the probe. */
1139 pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
1140 if (!force_function_unhide && !(stat8 & (1 << 5))) {
1141 printk(KERN_INFO "Contact your BIOS vendor to see if the "
Douglas Thompson052dfb42007-07-19 01:50:13 -07001142 "E752x error registers can be safely un-hidden\n");
Aristeu Rozanskif9b5a5d2007-09-11 15:23:32 -07001143 return -ENODEV;
Doug Thompson13189522006-06-30 01:56:08 -07001144 }
1145 stat8 |= (1 << 5);
1146 pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
1147
1148 pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
1149 /* FIXME: should check >>12 or 0xf, true for all? */
1150 /* Dual channel = 1, Single channel = 0 */
1151 drc_chan = dual_channel_active(ddrcsr);
1152
Doug Thompsonb8f6f972007-07-19 01:50:26 -07001153 mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
Doug Thompson13189522006-06-30 01:56:08 -07001154
1155 if (mci == NULL) {
1156 return -ENOMEM;
1157 }
1158
1159 debugf3("%s(): init mci\n", __func__);
1160 mci->mtype_cap = MEM_FLAG_RDDR;
Andrei Konovalov5135b792008-04-29 01:03:13 -07001161 /* 3100 IMCH supports SECDEC only */
1162 mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
1163 (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED);
Doug Thompson13189522006-06-30 01:56:08 -07001164 /* FIXME - what if different memory types are in different csrows? */
1165 mci->mod_name = EDAC_MOD_STR;
1166 mci->mod_ver = E752X_REVISION;
1167 mci->dev = &pdev->dev;
1168
1169 debugf3("%s(): init pvt\n", __func__);
Dave Jiang203333c2007-07-19 01:50:06 -07001170 pvt = (struct e752x_pvt *)mci->pvt_info;
Doug Thompson13189522006-06-30 01:56:08 -07001171 pvt->dev_info = &e752x_devs[dev_idx];
1172 pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
1173
1174 if (e752x_get_devs(pdev, dev_idx, pvt)) {
1175 edac_mc_free(mci);
1176 return -ENODEV;
1177 }
1178
1179 debugf3("%s(): more mci init\n", __func__);
1180 mci->ctl_name = pvt->dev_info->ctl_name;
Dave Jiangc4192702007-07-19 01:49:47 -07001181 mci->dev_name = pci_name(pdev);
Doug Thompson13189522006-06-30 01:56:08 -07001182 mci->edac_check = e752x_check;
1183 mci->ctl_page_to_phys = ctl_page_to_phys;
1184
Mark Grondona7297c262007-07-19 01:50:23 -07001185 /* set the map type. 1 = normal, 0 = reversed
1186 * Must be set before e752x_init_csrows in case csrow mapping
1187 * is reversed.
1188 */
Doug Thompson13189522006-06-30 01:56:08 -07001189 pci_read_config_byte(pdev, E752X_DRM, &stat8);
1190 pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
Alan Cox806c35f2006-01-18 17:44:08 -08001191
Mark Grondona7297c262007-07-19 01:50:23 -07001192 e752x_init_csrows(mci, pdev, ddrcsr);
1193 e752x_init_mem_map_table(pdev, pvt);
1194
Andrei Konovalov5135b792008-04-29 01:03:13 -07001195 if (dev_idx == I3100)
1196 mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
1197 else
1198 mci->edac_cap |= EDAC_FLAG_NONE;
Dave Peterson537fba22006-03-26 01:38:40 -08001199 debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
Dave Petersone7ecd892006-03-26 01:38:52 -08001200
Alan Cox806c35f2006-01-18 17:44:08 -08001201 /* load the top of low memory, remap base, and remap limit vars */
Doug Thompson37f04582006-06-30 01:56:07 -07001202 pci_read_config_word(pdev, E752X_TOLM, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001203 pvt->tolm = ((u32) pci_data) << 4;
Doug Thompson37f04582006-06-30 01:56:07 -07001204 pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001205 pvt->remapbase = ((u32) pci_data) << 14;
Doug Thompson37f04582006-06-30 01:56:07 -07001206 pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001207 pvt->remaplimit = ((u32) pci_data) << 14;
Dave Peterson537fba22006-03-26 01:38:40 -08001208 e752x_printk(KERN_INFO,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001209 "tolm = %x, remapbase = %x, remaplimit = %x\n",
1210 pvt->tolm, pvt->remapbase, pvt->remaplimit);
Alan Cox806c35f2006-01-18 17:44:08 -08001211
Doug Thompson2d7bbb92006-06-30 01:56:08 -07001212 /* Here we assume that we will never see multiple instances of this
1213 * type of memory controller. The ID is therefore hardcoded to 0.
1214 */
Doug Thompsonb8f6f972007-07-19 01:50:26 -07001215 if (edac_mc_add_mc(mci)) {
Dave Peterson537fba22006-03-26 01:38:40 -08001216 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001217 goto fail;
1218 }
1219
Doug Thompson13189522006-06-30 01:56:08 -07001220 e752x_init_error_reporting_regs(pvt);
Dave Jiang203333c2007-07-19 01:50:06 -07001221 e752x_get_error_info(mci, &discard); /* clear other MCH errors */
Alan Cox806c35f2006-01-18 17:44:08 -08001222
Dave Jiang91b99042007-07-19 01:49:52 -07001223 /* allocating generic PCI control info */
1224 e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
1225 if (!e752x_pci) {
1226 printk(KERN_WARNING
Douglas Thompson052dfb42007-07-19 01:50:13 -07001227 "%s(): Unable to create PCI control\n", __func__);
Dave Jiang91b99042007-07-19 01:49:52 -07001228 printk(KERN_WARNING
Douglas Thompson052dfb42007-07-19 01:50:13 -07001229 "%s(): PCI error report via EDAC not setup\n",
1230 __func__);
Dave Jiang91b99042007-07-19 01:49:52 -07001231 }
1232
Alan Cox806c35f2006-01-18 17:44:08 -08001233 /* get this far and it's successful */
Dave Peterson537fba22006-03-26 01:38:40 -08001234 debugf3("%s(): success\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001235 return 0;
1236
Douglas Thompson052dfb42007-07-19 01:50:13 -07001237fail:
Doug Thompson13189522006-06-30 01:56:08 -07001238 pci_dev_put(pvt->dev_d0f0);
1239 pci_dev_put(pvt->dev_d0f1);
1240 pci_dev_put(pvt->bridge_ck);
1241 edac_mc_free(mci);
Dave Petersone7ecd892006-03-26 01:38:52 -08001242
Doug Thompson13189522006-06-30 01:56:08 -07001243 return -ENODEV;
Alan Cox806c35f2006-01-18 17:44:08 -08001244}
1245
1246/* returns count (>= 0), or negative on error */
1247static int __devinit e752x_init_one(struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001248 const struct pci_device_id *ent)
Alan Cox806c35f2006-01-18 17:44:08 -08001249{
Dave Peterson537fba22006-03-26 01:38:40 -08001250 debugf0("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001251
1252 /* wake up and enable device */
Dave Jiang203333c2007-07-19 01:50:06 -07001253 if (pci_enable_device(pdev) < 0)
Alan Cox806c35f2006-01-18 17:44:08 -08001254 return -EIO;
Dave Petersone7ecd892006-03-26 01:38:52 -08001255
Alan Cox806c35f2006-01-18 17:44:08 -08001256 return e752x_probe1(pdev, ent->driver_data);
1257}
1258
Alan Cox806c35f2006-01-18 17:44:08 -08001259static void __devexit e752x_remove_one(struct pci_dev *pdev)
1260{
1261 struct mem_ctl_info *mci;
1262 struct e752x_pvt *pvt;
1263
Dave Peterson537fba22006-03-26 01:38:40 -08001264 debugf0("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001265
Dave Jiang91b99042007-07-19 01:49:52 -07001266 if (e752x_pci)
1267 edac_pci_release_generic_ctl(e752x_pci);
1268
Doug Thompson37f04582006-06-30 01:56:07 -07001269 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
Alan Cox806c35f2006-01-18 17:44:08 -08001270 return;
1271
Dave Jiang203333c2007-07-19 01:50:06 -07001272 pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -08001273 pci_dev_put(pvt->dev_d0f0);
1274 pci_dev_put(pvt->dev_d0f1);
1275 pci_dev_put(pvt->bridge_ck);
1276 edac_mc_free(mci);
1277}
1278
Alan Cox806c35f2006-01-18 17:44:08 -08001279static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
Dave Petersone7ecd892006-03-26 01:38:52 -08001280 {
Dave Jiang203333c2007-07-19 01:50:06 -07001281 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1282 E7520},
Dave Petersone7ecd892006-03-26 01:38:52 -08001283 {
Dave Jiang203333c2007-07-19 01:50:06 -07001284 PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1285 E7525},
Dave Petersone7ecd892006-03-26 01:38:52 -08001286 {
Dave Jiang203333c2007-07-19 01:50:06 -07001287 PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1288 E7320},
Dave Petersone7ecd892006-03-26 01:38:52 -08001289 {
Andrei Konovalov5135b792008-04-29 01:03:13 -07001290 PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1291 I3100},
1292 {
Dave Jiang203333c2007-07-19 01:50:06 -07001293 0,
1294 } /* 0 terminated list. */
Alan Cox806c35f2006-01-18 17:44:08 -08001295};
1296
1297MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
1298
Alan Cox806c35f2006-01-18 17:44:08 -08001299static struct pci_driver e752x_driver = {
Dave Peterson680cbbb2006-03-26 01:38:41 -08001300 .name = EDAC_MOD_STR,
Randy Dunlap0d38b042006-02-03 03:04:24 -08001301 .probe = e752x_init_one,
1302 .remove = __devexit_p(e752x_remove_one),
1303 .id_table = e752x_pci_tbl,
Alan Cox806c35f2006-01-18 17:44:08 -08001304};
1305
Alan Coxda9bb1d2006-01-18 17:44:13 -08001306static int __init e752x_init(void)
Alan Cox806c35f2006-01-18 17:44:08 -08001307{
1308 int pci_rc;
1309
Dave Peterson537fba22006-03-26 01:38:40 -08001310 debugf3("%s()\n", __func__);
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -07001311
1312 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
1313 opstate_init();
1314
Alan Cox806c35f2006-01-18 17:44:08 -08001315 pci_rc = pci_register_driver(&e752x_driver);
1316 return (pci_rc < 0) ? pci_rc : 0;
1317}
1318
Alan Cox806c35f2006-01-18 17:44:08 -08001319static void __exit e752x_exit(void)
1320{
Dave Peterson537fba22006-03-26 01:38:40 -08001321 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001322 pci_unregister_driver(&e752x_driver);
1323}
1324
Alan Cox806c35f2006-01-18 17:44:08 -08001325module_init(e752x_init);
1326module_exit(e752x_exit);
1327
1328MODULE_LICENSE("GPL");
1329MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
Andrei Konovalov5135b792008-04-29 01:03:13 -07001330MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers");
mark gross96941022006-05-03 19:55:07 -07001331
1332module_param(force_function_unhide, int, 0444);
1333MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
Doug Thompson10d33e92008-07-25 01:49:12 -07001334 " 1=force unhide and hope BIOS doesn't fight driver for "
1335 "Dev0:Fun1 access");
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -07001336
Dave Jiangc0d12172007-07-19 01:49:46 -07001337module_param(edac_op_state, int, 0444);
1338MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001339
1340module_param(sysbus_parity, int, 0444);
1341MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking,"
1342 " 1=enable system bus parity checking, default=auto-detect");
Doug Thompson10d33e92008-07-25 01:49:12 -07001343module_param(report_non_memory_errors, int, 0644);
1344MODULE_PARM_DESC(report_non_memory_errors, "0=disable non-memory error "
1345 "reporting, 1=enable non-memory error reporting");